praisonai-ts publishes both CJS and ESM outputs from a single TypeScript source, and a build shim called esm-shim.js post-processes the emitted ESM files so anything that still relies on require(...), __dirname, __filename, or module.exports keeps working at runtime under Node ESM.
How The Build Runs
The dual build is driven by twotsc passes wired through npm scripts in src/praisonai-ts/package.json.
esm-shim.js step runs after tsc emits the ESM build into dist/esm/. It walks every .js file, fixes relative import specifiers, repoints internal require(...) calls at the CJS twin, and prepends the createRequire banner only where genuinely needed. Source files are never touched, and the CJS build in dist/ is unaffected.
What The Shim Does
The shim lives atsrc/praisonai-ts/scripts/esm-shim.js and exports four helpers.
When a file needs the banner,
applyBanner prepends CJS_BANNER, which imports createRequire from module, fileURLToPath from url, and dirname from path, then re-creates require, __filename, and __dirname at module scope (plus a module stub so require.main === module evaluates to false).
A shebang line (
#!...) is preserved: the banner is inserted after it so the file stays executable.Why Detection Is Non-Trivial
Detection has to avoid two opposite failure modes.How stripStringsAndComments Works
needsCjsBanner first calls stripStringsAndComments, which blanks literal text and comments while keeping ${...} interpolations intact, then runs regex detectors on the cleaned code.
Blanking preserves offsets and newlines β each token is replaced with same-length whitespace β so error messages and source-map-friendly positions still line up. Inside a ${...} interpolation the shim honors nested braces, nested strings and templates, regex literals (with } inside a character class), and line/block comments, so a stray } cannot close the interpolation early.
The regex detectors then match real CJS usage:
What Does And Does Not Get Bannered
Use this table as the quick reference for expected behavior.Regression Tests
The detector is guarded bysrc/praisonai-ts/tests/unit/packaging/esm-shim-banner.test.ts, split into two directions plus an end-to-end emit check.
Run them from the TypeScript SDK folder:
When To Update This Page
Whenever a contributor changesneedsCjsBanner, stripStringsAndComments, or the CJS_BANNER string, they should:
1
Add a matching test
Add a case to
src/praisonai-ts/tests/unit/packaging/esm-shim-banner.test.ts in the matching describe block.2
Update the behavior table
Update the βWhat Does And Does Not Get Banneredβ table on this page if the observable behavior changes.
Related
Scripts & Automation
Includes a TypeScript SDK scripts section
Development Setup
Setting up the dev environment

