test: the orphan guard covers every package, and reads its own entry points (#548) - #768
Merged
divshekhar merged 4 commits intoSep 6, 2026
Conversation
…points (reticlehq#548) Three packages had a hand-written orphan ledger and four had none. The three were identical apart from their allowlists, and all three carried the same bug: entry points were the literal set {'index.ts'}. That is wrong for any package publishing a subpath export. @reticlehq/react publishes './store', and docs/usage.md and docs/packages/react.mdx both tell users to import useReticleStore from '@reticlehq/react/store' - so a guard copied to that package would have reported a documented, published hook as dead code on its first run. The scan moves to scripts/orphan-scan.mjs, which derives entry points from each package's own exports map (plus main/module/types/bin), so the guard and the manifest cannot disagree. Only build outputs are mapped back to source: a manifest also points at things that never had any - './package.json', JSON schema assets - and turning those into .ts candidates would silently excuse a real source file that happened to share the name. Guards now cover server, browser, core, react, vite-plugin and eslint-plugin. babel-plugin is left out: it is one module, that module is the entry point, and its tsconfig is CommonJS so importing an ESM helper needs a dynamic import for no coverage in return. Both directions are still reported from one scan - undeclared orphans and declarations that have gone stale - because stopping at the first failure hides half the work. Signed-off-by: Vaibhav Srivastava <vaibhavsri1712@gmail.com>
…ers-every-package
…ers-every-package
…ers-every-package
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.
Closes #548.
What I found first
The issue asks to port
orphan-modules.test.tstopackages/browserandpackages/core. Both of those have since landed, and the two orphan files it names (observers/subresources.ts,dom/blind-spots.ts) are already deleted — so I looked at what the guard does and does not cover now.Three packages have a ledger (
server,browser,core); four do not. The three are identical apart from their allowlists, and all three share one bug:That is wrong for any package that publishes a subpath export.
@reticlehq/reactpublishes./store, and bothdocs/usage.md:969anddocs/packages/react.mdx:75tell users to write:store.tshas no importer insidepackages/react/src— its only importer is its own spec. So porting the guard toreactwith the hardcoded set would have reported a documented, published hook as dead code on the very first run, and the natural fix would have been to delete it.What this does
One scan, in
scripts/orphan-scan.mjs, so every package asks the same question the same way. Entry points come from each package's ownexportsmap (plusmain,module,types,bin), so the guard and the manifest cannot disagree.Only build outputs are mapped back to source. A manifest also names things that never had any —
"./package.json": "./package.json", JSON schema assets — and turning those into.tscandidates would silently excuse a real source file that happened to share the name.Coverage is now
server,browser,core,react,vite-plugin,eslint-plugin. Every existing allowlist and its prose is preserved verbatim; no entry added or removed.babel-pluginis deliberately left out: it is one module, that module is the entry point, and its tsconfig is CommonJS, so importing an ESM helper would need a dynamic import for no coverage in return. Say the word if you would rather it had one anyway.Verification
pnpm --filter @reticlehq/<pkg> exec vitest run src/orphan-modules.test.ts— 2 passed eachpackages/react/src/deliberately-orphaned-probe.tsfails withexpected [ 'deliberately-orphaned-probe.ts' ] to deeply equal [], and passes again once removednode scripts/check-boundaries.mjs— OK, 10 packagesprettier --checkclean;tsc --noEmitclean on every touched package for the files this PR adds (packages/reacthas a pre-existingsourceOwnererror from a stale@reticlehq/browserdist, present onmaintoo)scripts/orphan-scan.d.mtscarries the types so each package's TypeScript test imports it without an implicitany.