create Babel-based AST parser for CommonJS sources#3162
Merged
Conversation
Member
Author
🦋 Changeset detectedLatest commit: d74629e The changes in this PR will be included in the next version bump. This PR includes changesets to release 9 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
3666b32 to
f4ccfb3
Compare
This was referenced Apr 5, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an opt-in Babel-AST-based CommonJS parsing/analysis path (via @endo/module-source) and wires dynamic import() bridging for CJS execution in compartment-mapper, alongside extensive test coverage and fixtures.
Changes:
- Introduce
CjsModuleSource+ CJS visitor passes / functor builder in@endo/module-source. - Add
parse-cjs-babelandparserForLanguageWithCjsBabelopt-in parser in@endo/compartment-mapper. - Add integration/compat tests and fixtures for CJS/ESM dynamic
import()and CJS analyzer compatibility.
Reviewed changes
Copilot reviewed 20 out of 25 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/module-source/test/cjs-visitor-passes.test.js | New tests for CJS Babel visitor passes + transform behavior (incl import() rewrite). |
| packages/module-source/test/cjs-module-source.test.js | New unit tests for CjsModuleSource record shape, freezing, shebang handling, and import() support. |
| packages/module-source/test/cjs-compat.test.js | Large compat suite ported from lexer analyzer tests, targeting CjsModuleSource. |
| packages/module-source/src/visitor-passes.js | Add createCjsModuleSourcePasses() alongside existing ESM passes. |
| packages/module-source/src/types/visitor-passes.ts | Add CJS analysis/passes types and buildRecord() return type. |
| packages/module-source/src/types/module-source.ts | Add CJS record/state types; reorganize/extend source map hook types. |
| packages/module-source/src/source-options.js | Add createCjsSourceOptions() state bag factory for CJS plugin. |
| packages/module-source/src/cjs-transform-analyze.js | New parse/traverse/generate pipeline to produce frozen CjsModuleSourceRecord. |
| packages/module-source/src/cjs-module-source.js | New CjsModuleSource constructor wrapper around the analyzer. |
| packages/module-source/src/cjs-functor.js | Build CJS functor source and assemble frozen CJS module record. |
| packages/module-source/src/cjs-babel-plugin.js | New Babel plugin for CJS analysis (require/exports/reexports/import()) + transform (import() rewrite + hidden-id guard). |
| packages/module-source/README.md | Document CJS variant and tweak XS heading. |
| packages/module-source/index.js | Export CjsModuleSource + createCjsModuleSourcePasses. |
| packages/compartment-mapper/test/fixtures-dynamic-import-esm/node_modules/app/package.json | Add ESM dynamic import fixture package metadata. |
| packages/compartment-mapper/test/fixtures-dynamic-import-esm/node_modules/app/index.js | Fixture: ESM module that uses dynamic import(). |
| packages/compartment-mapper/test/fixtures-dynamic-import-esm/node_modules/app/foo.js | Fixture: ESM dependency providing default export. |
| packages/compartment-mapper/test/fixtures-cjs-compat/node_modules/dynamic-import/package.json | Add CJS dynamic import fixture package metadata. |
| packages/compartment-mapper/test/fixtures-cjs-compat/node_modules/dynamic-import/index.js | Fixture: CJS module exporting async fn that calls import(). |
| packages/compartment-mapper/test/dynamic-import-esm.test.js | Integration test for ESM dynamic import() via scaffold. |
| packages/compartment-mapper/test/cjs-compat.test.js | Run compat suite with both default lexer parser and new Babel CJS parser; add dynamic-import CJS test. |
| packages/compartment-mapper/src/types/external.ts | Minor import ordering adjustment (SourceMapObject import). |
| packages/compartment-mapper/src/parse-cjs-shared-export-wrapper.js | Add importFn that bridges to compartment.import() for CJS functors. |
| packages/compartment-mapper/src/parse-cjs-babel.js | New opt-in CJS parser using CjsModuleSource and importFn injection when needed. |
| packages/compartment-mapper/src/import-parsers.js | Add parserForLanguageWithCjsBabel helper alongside default parsers. |
| packages/compartment-mapper/import-parsers.js | Re-export parserForLanguageWithCjsBabel from package entrypoint. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
93e7e2c to
656bc39
Compare
f4ccfb3 to
3b30f06
Compare
656bc39 to
7594c39
Compare
3b30f06 to
d3334bc
Compare
7594c39 to
84dd4ee
Compare
8265794 to
526cf25
Compare
b1c50eb to
59ff80d
Compare
60d7132 to
7c3888c
Compare
59ff80d to
9d57d5e
Compare
8a0a4c9 to
9766810
Compare
9d57d5e to
a7fa619
Compare
ee18142 to
b77700f
Compare
cbb007c to
6472705
Compare
b77700f to
aae2670
Compare
47a33d5 to
e77ae52
Compare
6d15d60 to
5750f33
Compare
e77ae52 to
2fd4ab2
Compare
5750f33 to
1fd899f
Compare
2fd4ab2 to
252b91c
Compare
1fd899f to
f50448a
Compare
252b91c to
145cb97
Compare
f50448a to
65e196f
Compare
145cb97 to
8d92961
Compare
65e196f to
aefe20a
Compare
8d92961 to
0c30403
Compare
aefe20a to
3073d30
Compare
0c30403 to
ae1c9eb
Compare
3073d30 to
c130a92
Compare
ae1c9eb to
564f98d
Compare
c130a92 to
2f6e9e5
Compare
564f98d to
d74629e
Compare
- Fixes `CompartmentDescriptor` so that it is generic on the `PackagePolicy`; externally-defined `ParseFn`s can now refer to the specific contents of a custom `PackagePolicy` present in a `CompartmentDescriptor`. - Introduces `ParseSourceMapHook`; differentiated from `@endo/module-source`'s `SourceMapHook`. - Fixes type of `PolicyItem`; eliminates confusion between `void` (no extra union members) and `any` (`SomePackagePolicy`).
Exposes AST-based parser for CJS, as well as an `analyzeCjs` function from the `analyzer.js` subpath export. `CjsModuleSource` is also exported from the main entry point.
…port support Expose Babel-based CJS parser, `parse-cjs-babel`. Expose shared functionality for wrapping CJS functors with `__dirname`, `__filename`, etc. Add support for dynamic `import()` (`parse-cjs-babel` only).
2f6e9e5 to
eb2e3c0
Compare
d74629e to
edbf51e
Compare
Base automatically changed from
boneskull/module-source-pipeline
to
boneskull/ast-service
April 30, 2026 01:37
This was referenced Apr 30, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
feat(compartment-mapper): add Babel-based CJS parser with import() support
Adds
parse-cjs-babel.js, a new opt-in CJS parser that usesCjsModuleSourcefrom@endo/module-sourceinstead of the character-level lexer. Consumers swap it in viaparserForLanguage:Also adds
import()support for CJS modules:parse-cjs-shared-export-wrapper.jsnow provides animportFnthat invokescompartment.import(), bridging dynamic imports in CJS onto the SES module loader$h͏_importas a parameter whenimport()calls are detected, matching the ESM evasion patternThe existing
parse-cjs.js(lexer-based) remains the default; nothing breaks for current consumers.Includes integration tests and test fixtures covering both the new parser and dynamic
import()in CJS.May supersede #3154.
feat(module-source): add CJS Babel AST analysis, transformation, and CjsModuleSource
Replaces the character-level lexer approach to CJS module analysis with Babel AST visitors, enabling
@endo/parser-pipelineto share a single parse across CJS analysis, transformation, evasive-transform, and other consumers.New exports:
CjsModuleSource: constructor that parses, analyzes, transforms CJS source and produces a frozen record withimports,exports,reexports,cjsFunctor, and__needsImport__createCjsModuleSourcePasses(): paired analyzer/transform visitor passes for use with@endo/parser-pipeline, includingbuildRecordThe CJS Babel plugin detects all patterns the lexer handles:
require(),exports.*,module.exports,Object.defineProperty, Babel/TS reexport helpers, esbuild hints, spread reexports, andimport()calls. The transform rewritesimport()to the SES hidden identifier ($h͏_import) for compartment evasion.Includes 77 new tests: unit tests for both APIs plus a full compat suite ported from
@endo/cjs-module-analyzer's test cases.This is probably a better solution than #3154 for adding
import()support to CommonJS. We may want to do both... unsure.There could be a performance penalty to using the new parser over the lexer, but I'm hoping that leveraging
@endo/parser-pipeline(#3158) in LavaMoat will mitigate that.