fix(debarrel): Respect exports boundaries and preserve non-static consumers - #37
Open
alexbit-codemod wants to merge 4 commits into
Open
fix(debarrel): Respect exports boundaries and preserve non-static consumers#37alexbit-codemod wants to merge 4 commits into
alexbit-codemod wants to merge 4 commits into
Conversation
Capture package exports boundaries, re-export rewrites, dynamic imports, namespace re-exports, and single-pass completeness so fixes can be driven by failing tests. Also bump workspace catalog deps for the local toolchain. Co-authored-by: Cursor <cursoragent@cursor.com>
…sumers Stop deepening past package.json exports, rewrite re-export edges, walk named re-export chains in one pass, and keep barrels used by dynamic imports or namespace re-exports. Co-authored-by: Cursor <cursoragent@cursor.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Improves the codemods/debarrel codemod’s correctness around package "exports" boundaries and non-static barrel consumers, and adds regression fixtures to cover these scenarios.
Changes:
- Add regression fixtures covering
"exports"subpath boundaries, type-only alias imports at export boundaries, transitive single-pass barrel chains, parent re-export updates, namespace re-exports, dynamicimport()consumers, mixed default+named imports, and CRLF line endings. - Update debarrel rewriting logic to (a) avoid rewriting past public
"exports"subpaths, (b) rewriteexport { … } from "…"edges, (c) follow transitive named re-export chains in one pass, and (d) preserve barrels required by namespace re-exports or dynamic imports. - Bump workspace catalog dependency versions (including TypeScript).
Reviewed changes
Copilot reviewed 105 out of 106 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pnpm-workspace.yaml | Bumps catalog dependency versions (incl. TypeScript). |
| pnpm-lock.yaml | Updates lockfile to reflect catalog dependency bumps. |
| codemods/debarrel/scripts/codemod.ts | Adds re-export edge rewriting and preserves barrels with non-static consumers. |
| codemods/debarrel/scripts/utils/specifiers.ts | Adds "exports" boundary guard for candidate rewrites and follows re-export chains. |
| codemods/debarrel/scripts/utils/paths.ts | Adds helpers to detect package "exports" subpaths and preserve export boundaries. |
| codemods/debarrel/scripts/utils/exportStar.ts | Adds transitive named re-export walking and broader barrel preservation checks. |
| codemods/debarrel/scripts/utils/barrel.ts | Tightens namespace re-export parsing to only match the intended namespace binding. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/input/tsconfig.json | Fixture: tsconfig paths alias for export-boundary scenario. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/input/packages/ui/package.json | Fixture: package "exports" map defining a public subpath. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/input/packages/ui/components/form/index.ts | Fixture: type re-export through an export boundary. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/input/packages/ui/components/form/fields/MultiSelect.ts | Fixture: leaf type definition. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/input/packages/app/src/App.ts | Fixture: type-only import using alias at export boundary. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/input/packages/app/package.json | Fixture: workspace consumer package setup. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/expected/tsconfig.json | Expected output for export-boundary type-only alias case. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/expected/packages/ui/package.json | Expected output (unchanged) for package "exports". |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/expected/packages/ui/components/form/index.ts | Expected output (unchanged) for type re-export. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/expected/packages/ui/components/form/fields/MultiSelect.ts | Expected output (unchanged) for leaf type. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/expected/packages/app/src/App.ts | Expected output (unchanged) for boundary-preserving import. |
| codemods/debarrel/tests/type-import-alias-at-export-boundary/expected/packages/app/package.json | Expected output (unchanged) for consumer package. |
| codemods/debarrel/tests/transitive-barrel-single-pass/metrics.json | New metrics baseline for transitive single-pass scenario. |
| codemods/debarrel/tests/transitive-barrel-single-pass/input/tsconfig.json | Fixture: basic project config for transitive barrels. |
| codemods/debarrel/tests/transitive-barrel-single-pass/input/src/utils/index.ts | Fixture: top-level barrel re-exporting a nested barrel. |
| codemods/debarrel/tests/transitive-barrel-single-pass/input/src/utils/helpers/index.ts | Fixture: nested barrel re-exporting a leaf module. |
| codemods/debarrel/tests/transitive-barrel-single-pass/input/src/utils/helpers/format.ts | Fixture: leaf implementation. |
| codemods/debarrel/tests/transitive-barrel-single-pass/input/src/metrics.json | Fixture: metrics input. |
| codemods/debarrel/tests/transitive-barrel-single-pass/input/src/App.ts | Fixture: consumer importing from top-level barrel. |
| codemods/debarrel/tests/transitive-barrel-single-pass/expected/tsconfig.json | Expected output config. |
| codemods/debarrel/tests/transitive-barrel-single-pass/expected/src/utils/index.barrel.bak.ts | Expected: renamed barrel with rewritten re-export edge. |
| codemods/debarrel/tests/transitive-barrel-single-pass/expected/src/utils/helpers/index.barrel.bak.ts | Expected: renamed nested barrel preserved as backup. |
| codemods/debarrel/tests/transitive-barrel-single-pass/expected/src/utils/helpers/format.ts | Expected: leaf module unchanged. |
| codemods/debarrel/tests/transitive-barrel-single-pass/expected/src/metrics.json | Expected metrics output. |
| codemods/debarrel/tests/transitive-barrel-single-pass/expected/src/App.ts | Expected: consumer import debarreled to the leaf module. |
| codemods/debarrel/tests/parent-barrel-reexport-update/metrics.json | New metrics baseline for parent re-export updates. |
| codemods/debarrel/tests/parent-barrel-reexport-update/input/tsconfig.json | Fixture config. |
| codemods/debarrel/tests/parent-barrel-reexport-update/input/src/metrics.json | Fixture metrics input. |
| codemods/debarrel/tests/parent-barrel-reexport-update/input/src/form/index.ts | Fixture: parent barrel with mixed exports. |
| codemods/debarrel/tests/parent-barrel-reexport-update/input/src/form/checkbox/index.ts | Fixture: nested barrel. |
| codemods/debarrel/tests/parent-barrel-reexport-update/input/src/form/checkbox/Checkbox.ts | Fixture: leaf implementation. |
| codemods/debarrel/tests/parent-barrel-reexport-update/input/src/App.ts | Fixture: consumer import from parent barrel. |
| codemods/debarrel/tests/parent-barrel-reexport-update/expected/tsconfig.json | Expected config. |
| codemods/debarrel/tests/parent-barrel-reexport-update/expected/src/metrics.json | Expected metrics output. |
| codemods/debarrel/tests/parent-barrel-reexport-update/expected/src/form/index.ts | Expected: parent re-export edge rewritten to direct leaf module. |
| codemods/debarrel/tests/parent-barrel-reexport-update/expected/src/form/checkbox/index.barrel.bak.ts | Expected: nested barrel renamed to backup. |
| codemods/debarrel/tests/parent-barrel-reexport-update/expected/src/form/checkbox/Checkbox.ts | Expected: leaf unchanged. |
| codemods/debarrel/tests/parent-barrel-reexport-update/expected/src/App.ts | Expected: consumer partially debarreled while preserving remaining imports. |
| codemods/debarrel/tests/package-exports-subpath-boundary/input/tsconfig.json | Fixture: tsconfig paths for package export subpath boundary. |
| codemods/debarrel/tests/package-exports-subpath-boundary/input/packages/ui/package.json | Fixture: package "exports" subpath declaration. |
| codemods/debarrel/tests/package-exports-subpath-boundary/input/packages/ui/components/button/index.ts | Fixture: barrel at an exported subpath. |
| codemods/debarrel/tests/package-exports-subpath-boundary/input/packages/ui/components/button/Button.ts | Fixture: leaf implementation. |
| codemods/debarrel/tests/package-exports-subpath-boundary/input/packages/app/src/App.ts | Fixture: consumer importing the public export subpath. |
| codemods/debarrel/tests/package-exports-subpath-boundary/input/packages/app/package.json | Fixture: workspace consumer package. |
| codemods/debarrel/tests/package-exports-subpath-boundary/expected/tsconfig.json | Expected config. |
| codemods/debarrel/tests/package-exports-subpath-boundary/expected/packages/ui/package.json | Expected output (unchanged) for "exports" boundary. |
| codemods/debarrel/tests/package-exports-subpath-boundary/expected/packages/ui/components/button/index.ts | Expected output (unchanged) for exported subpath barrel. |
| codemods/debarrel/tests/package-exports-subpath-boundary/expected/packages/ui/components/button/Button.ts | Expected output (unchanged) for leaf. |
| codemods/debarrel/tests/package-exports-subpath-boundary/expected/packages/app/src/App.ts | Expected output (unchanged) for boundary-preserving import. |
| codemods/debarrel/tests/package-exports-subpath-boundary/expected/packages/app/package.json | Expected output (unchanged) for consumer package. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/metrics.json | New metrics baseline for namespace re-export scenario. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/input/tsconfig.json | Fixture config. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/input/src/plugin/metadata.ts | Fixture: direct export used by consumer. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/input/src/plugin/index.ts | Fixture: barrel with namespace re-export (export * as …). |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/input/src/plugin/api/index.ts | Fixture: nested barrel behind namespace re-export. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/input/src/plugin/api/handler.ts | Fixture: leaf implementation. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/input/src/metrics.json | Fixture metrics input. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/input/src/App.ts | Fixture: consumer importing from barrel. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/expected/tsconfig.json | Expected config. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/expected/src/plugin/metadata.ts | Expected output (unchanged) for metadata module. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/expected/src/plugin/index.ts | Expected output: barrel preserved due to namespace re-export. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/expected/src/plugin/api/index.ts | Expected output (unchanged) for nested barrel. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/expected/src/plugin/api/handler.ts | Expected output (unchanged) for leaf. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/expected/src/metrics.json | Expected metrics output. |
| codemods/debarrel/tests/namespace-reexport-nested-barrel/expected/src/App.ts | Expected: consumer import rewritten to direct metadata module. |
| codemods/debarrel/tests/mixed-default-named-import/metrics.json | New metrics baseline for mixed default+named import case. |
| codemods/debarrel/tests/mixed-default-named-import/input/tsconfig.json | Fixture: tsconfig paths alias. |
| codemods/debarrel/tests/mixed-default-named-import/input/src/widgets/Widget.ts | Fixture: default export leaf. |
| codemods/debarrel/tests/mixed-default-named-import/input/src/widgets/index.ts | Fixture: barrel re-exporting default + named symbols. |
| codemods/debarrel/tests/mixed-default-named-import/input/src/widgets/helpers.ts | Fixture: named export leaf. |
| codemods/debarrel/tests/mixed-default-named-import/input/src/metrics.json | Fixture metrics input. |
| codemods/debarrel/tests/mixed-default-named-import/input/src/App.ts | Fixture: mixed default+named import from barrel. |
| codemods/debarrel/tests/mixed-default-named-import/input/package.json | Fixture package definition. |
| codemods/debarrel/tests/mixed-default-named-import/expected/tsconfig.json | Expected config. |
| codemods/debarrel/tests/mixed-default-named-import/expected/src/widgets/Widget.ts | Expected output (unchanged) for leaf default export. |
| codemods/debarrel/tests/mixed-default-named-import/expected/src/widgets/index.barrel.bak.ts | Expected: barrel renamed to backup. |
| codemods/debarrel/tests/mixed-default-named-import/expected/src/widgets/helpers.ts | Expected output (unchanged) for helper leaf. |
| codemods/debarrel/tests/mixed-default-named-import/expected/src/metrics.json | Expected metrics output. |
| codemods/debarrel/tests/mixed-default-named-import/expected/src/App.ts | Expected: mixed import split into direct default + named imports. |
| codemods/debarrel/tests/mixed-default-named-import/expected/package.json | Expected package definition unchanged. |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/input/tsconfig.json | Fixture: config for dynamic import preservation case. |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/input/src/registry.ts | Fixture: dynamic import() consumer of a barrel path. |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/input/src/plugin/api/index.ts | Fixture: barrel that must be preserved for dynamic import. |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/input/src/plugin/api/handler.ts | Fixture: leaf implementation. |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/expected/tsconfig.json | Expected config. |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/expected/src/registry.ts | Expected output (unchanged) for dynamic import consumer. |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/expected/src/plugin/api/index.ts | Expected output: barrel preserved (not renamed). |
| codemods/debarrel/tests/dynamic-import-barrel-consumer/expected/src/plugin/api/handler.ts | Expected output (unchanged) for leaf. |
| codemods/debarrel/tests/crlf-line-endings/metrics.json | New metrics baseline for CRLF handling. |
| codemods/debarrel/tests/crlf-line-endings/input/tsconfig.json | Fixture config. |
| codemods/debarrel/tests/crlf-line-endings/input/src/metrics.json | Fixture metrics input. |
| codemods/debarrel/tests/crlf-line-endings/input/src/components/index.ts | Fixture: barrel file (CRLF-related regression). |
| codemods/debarrel/tests/crlf-line-endings/input/src/components/Button.ts | Fixture: leaf implementation. |
| codemods/debarrel/tests/crlf-line-endings/input/src/App.ts | Fixture: consumer import from barrel. |
| codemods/debarrel/tests/crlf-line-endings/expected/tsconfig.json | Expected config. |
| codemods/debarrel/tests/crlf-line-endings/expected/src/metrics.json | Expected metrics output. |
| codemods/debarrel/tests/crlf-line-endings/expected/src/components/index.barrel.bak.ts | Expected: barrel renamed to backup. |
| codemods/debarrel/tests/crlf-line-endings/expected/src/components/Button.ts | Expected output (unchanged) for leaf. |
| codemods/debarrel/tests/crlf-line-endings/expected/src/App.ts | Expected: consumer import rewritten to direct leaf module. |
Files not reviewed (1)
- pnpm-lock.yaml: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
255
to
+257
| export function barrelHasNamespaceImporters(barrelFile: string): boolean { | ||
| return barrelMustBePreserved(barrelFile); | ||
| } |
Resolve local import-then-reexport barrels (including import aliases), rewrite parent exports to `default as` when the leaf is default-only, normalize consumer imports against actual export shapes, and update factory vi.mock/jest.mock plus dynamic import() paths. Allow barrel rename when dynamic imports are co-located with rewritable static imports. Adds four regression fixtures covering Cal.com-style gaps. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds a dependency-free shell harness to measure build and test wall-clock time on a target repo before and after running debarrel. Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Summary
Hardens the debarrel codemod against real-world monorepo gaps found while applying it to Cal.com (404 files). This PR adds regression fixtures and fixes across export-shape handling, aliased re-exports, test mocks, and barrel rename safety.
"exports"boundaries, re-export rewrites, dynamicimport()consumers, namespace re-exports, and single-pass transitive barrel chains.export { … } from "…"edges, walk named re-export chains in one pass, and preserve barrels required by namespace re-exports or dynamic imports.import { cache as unstable_cache }; export { unstable_cache }).default as Foowhen the leaf module is default-only.vi.mock/jest.mockand dynamicimport()paths when imports are fully debarreled to a single direct module.codemods/debarrel/benchmark/) to measure build/test wall-clock time on a target repo before and after debarreling.New fixtures
aliased-import-then-reexport— import alias + local re-export barrelparent-barrel-default-only-leaf— parentexport { Foo }where leaf isexport defaultnamed-import-default-only-barrel—import { Cal }fromexport { default as Cal }update-test-mocks-factory-path— factory mock + dynamic import path rewritesBenchmark harness
codemods/debarrel/benchmark/bench.shruns repeatable build and test timing on any target repo (defaults:yarn build --force,yarn test). Intended workflow:bench-results/outputSee
codemods/debarrel/benchmark/README.mdfor flags and examples (e.g. Cal.com).Test plan
pnpm testincodemods/debarrel(283 passed)pnpm check-typesincodemods/debarrelvalidate_codemod_packagereportsready: truecodemods/debarrel/tests/codemods/debarrel/benchmark/bench.shon Cal.com before/after debarrel