diff --git a/package.json b/package.json index 098ca497..55f8e3e5 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "scripts": { "start": "firebase emulators:exec --project=rxfire-525a3 \"vitest --ui\"", "build": "tsc && vite build && npm run build:types-cjs && npm run docs", - "build:types-cjs": "node -e \"require('fs').copyFileSync('dist/index.d.ts','dist/index.d.cts')\"", + "build:types-cjs": "node scripts/emit-cjs-types.mjs", "test": "firebase emulators:exec --project=rxfire-525a3 \"vitest\"", "test:firestore": "firebase emulators:exec --only firestore --ui --project=rxfire-525a3 \"vitest firestore\"", "test:database": "firebase emulators:exec --only database --project=rxfire-525a3 \"vitest database\"", diff --git a/scripts/emit-cjs-types.mjs b/scripts/emit-cjs-types.mjs new file mode 100644 index 00000000..cbfe1cc4 --- /dev/null +++ b/scripts/emit-cjs-types.mjs @@ -0,0 +1,20 @@ +// Writes a CommonJS declaration file (`.d.cts`) next to every `dist/*.d.ts`, for the `require` export condition. +// A copy of `index.d.ts` is not enough: its relative imports resolve to `.d.ts` files, which TypeScript reads +// as ESM in this `"type": "module"` package, so CommonJS consumers get TS1479 on each import (#850). +// Rewriting `./x.js` to `./x.cjs` points each import at the matching `.d.cts` instead. +import { readdirSync, readFileSync, writeFileSync } from 'node:fs'; +import { join } from 'node:path'; + +const dir = 'dist'; +const relativeSpecifier = /(\bfrom\s*|\bimport\s*\(\s*)(['"])(\.{1,2}\/[^'"]*)\2/g; + +for (const file of readdirSync(dir).filter((f) => f.endsWith('.d.ts'))) { + const source = readFileSync(join(dir, file), 'utf8'); + const cjs = source.replace(relativeSpecifier, (_, keyword, quote, specifier) => { + if (!specifier.endsWith('.js')) { + throw new Error(`${file}: relative import without a .js extension: ${specifier}`); + } + return `${keyword}${quote}${specifier.slice(0, -'.js'.length)}.cjs${quote}`; + }); + writeFileSync(join(dir, file.replace(/\.d\.ts$/, '.d.cts')), cjs); +}