Make TypeScript extraction see through barrels, aliases, and typed receivers - #27
Merged
Merged
Conversation
…ceivers TypeRef identity: a type reference now keys on the file where the type is declared and its declared name, not the referencing file and local alias. Two files importing the same interface, directly, renamed, or through a barrel, converge on one TypeRef node, so cross-file USES_TYPE, HAS_PARAM, and RETURNS aggregation works for the first time. Receiver-typed calls: a per-file binding table tracks const x = new Service() and typed declarations, so s.work() produces a CALLS edge to the right class's method. Edges are class-qualified through HAS_METHOD in the graph so two classes sharing a method name in one file cannot cross-contaminate, and ambiguous bindings are dropped, never guessed. Fixed a latent ordering bug this exposed: all three write paths created CALLS edges before HAS_METHOD edges existed. Barrels: export-star and named re-exports are now extracted, and a pipeline resolution pass follows chains to the origin with alias rewriting at every hop, a local-declaration base case so mixed barrels resolve their own exports, and per-path cycle guards with a global attempt bound. Multi-star barrels try every star in declaration order instead of only the first. The indexer builds the barrel index in a pre-pass whose hint regex tolerates comments, and collects local exports for every TypeScript file since chains can land anywhere. File-to-File IMPORTS edges still point at the barrel, which is the truthful import relationship. Three adversarial review rounds drove eleven defects out of this work before merge, verified by live-index attacks kept in the review scripts, including a diamond-shaped barrel graph and a 47-file star fan-out that terminates in 60ms. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
CodeQL flagged the comment-tolerant hint regex with two high-severity ReDoS alerts, and they were real: the old pattern hung past a 5-second kill on 'export' followed by 50k comment markers, and it ran against the full content of every indexed TypeScript file. The hint is now a hand-rolled forward-only scanner with identical semantics (whitespace, line comments, and block comments allowed between export and the star or brace) and the two attack shapes are pinned as timing tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This branch was previously deployed
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.
What this fixes
Batch three, wave one of the pre-launch audit: TypeScript extraction fidelity. Three structural blind spots that made the graph miss or misattribute relationships in ordinary code.
TypeRef identity
A type reference was keyed on the file that mentioned it, so every importing file created its own disconnected TypeRef node and cross-file type aggregation was structurally impossible. Identity is now the declaring file plus the declared name: direct imports, renamed imports (import { User as U }), type-only imports, and imports routed through barrels all converge on one node.
Receiver-typed calls
const s = new Service(); s.work() produced no CALLS edge because resolution only understood bare identifiers. A per-file binding table now tracks constructor assignments and typed declarations, and method edges are class-qualified through HAS_METHOD so two classes sharing a method name cannot cross-contaminate. Ambiguous bindings are dropped rather than guessed. This also exposed and fixed a latent ordering bug: all three graph write paths created CALLS edges before the HAS_METHOD edges they need existed.
Barrel files
Re-exports (export * from, export { y } from) were never parsed, so importing through an index.ts barrel silently dropped call edges. The pipeline now follows re-export chains to the origin with alias rewriting at every hop, a local-declaration base case (a barrel's own exported functions resolve to the barrel), correct handling of multiple export-star statements in one file, and per-path cycle guards with a global attempt bound so adversarial barrel graphs terminate instead of hanging. File-to-File IMPORTS edges still point at the barrel, which is the truthful import relationship.
Review process
Three adversarial review rounds ran live-index attacks against ephemeral databases. Round one found five blockers in code that passed CI; round two confirmed them fixed and found a sixth (multi-star barrels only following the first star); round three verified the fix plus stress probes: a diamond-shaped barrel graph and a 47-file star fan-out with the target buried in the last leaf, resolved correctly in 60ms.
Verification
Known gaps deliberately not in this PR (ledger)
🤖 Generated with Claude Code