Files
zeekay 5095f79659 0.5.17 — a CommonJS consumer can require the package
The package is `type: module` and its exports map offered only `import`, so
every `.js` it ships is ESM and a `require()` reaches a syntax error inside
`dist/index.js` rather than a module. Plain Node hides that now that
`require(esm)` works; jest loads a dependency as CommonJS and does not, so a
jsdom test importing anything downstream of this package failed on our line.

A second `tsc` pass emits CommonJS to `dist-cjs`, `scripts/cjs.mjs` retargets
the sibling specifiers and folds it into `dist` as `.cjs`, and the exports map
names it under `require`. Same two-pass shape @hanzo/ui already builds with.
`main` follows, since that field is read by the resolvers that predate
`exports` and those are the CommonJS ones.

The dist check now loads BOTH artifacts and compares their export names to
each other, so the two formats cannot drift and neither can go missing.
Tokens, CSS and the ESM entry are untouched — all 23 exports are identical to
0.5.16.
2026-08-21 07:58:06 -07:00

44 lines
1.8 KiB
JavaScript

/**
* Fold the CommonJS pass into `dist` as `.cjs`.
*
* `tsc` emits one module format per outDir, so the CJS build lands in
* `dist-cjs` beside the ESM one. Both halves ship from `dist`, distinguished by
* extension — `.cjs` is CommonJS whatever the package `type` says, which is the
* only way an ESM-typed package can hand a `require()` consumer real CJS.
*
* Specifiers are rewritten on the way in. The sources name siblings with an
* explicit `./x.js`, which `tsc` copies through verbatim, so an unrewritten
* `dist/index.cjs` would `require('./tokens.gen.js')` — the ESM copy sitting
* right next to it. That either throws or loads a SECOND instance of every
* token, so the extension has to travel with the file.
*/
import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs'
import { dirname, join, relative } from 'node:path'
import { fileURLToPath } from 'node:url'
const root = join(dirname(fileURLToPath(import.meta.url)), '..')
const dist = join(root, 'dist')
const cjs = join(root, 'dist-cjs')
const files = (dir, out = []) => {
for (const name of readdirSync(dir)) {
const p = join(dir, name)
statSync(p).isDirectory() ? files(p, out) : out.push(p)
}
return out
}
// `from './x.js'`, `import './x.js'`, `import('./x.js')`, `require('./x.js')`
const SPECIFIER = /(\bfrom\s*|\bimport\s*\(?\s*|\brequire\s*\(\s*)(['"])(\.[^'"]*)\.js\2/g
for (const f of files(cjs)) {
if (!f.endsWith('.js')) continue
const src = readFileSync(f, 'utf8')
const out = src.replace(SPECIFIER, (_, head, q, spec) => `${head}${q}${spec}.cjs${q}`)
const dest = join(dist, relative(cjs, f)).replace(/\.js$/, '.cjs')
mkdirSync(dirname(dest), { recursive: true })
writeFileSync(dest, out)
}
rmSync(cjs, { recursive: true, force: true })