Skip to content

refactor: split src/map/extract.ts into cohesive modules (no behaviour change) - #127

Merged
patchstackdave merged 1 commit into
mainfrom
refactor/split-map-extract
Aug 13, 2026
Merged

refactor: split src/map/extract.ts into cohesive modules (no behaviour change)#127
patchstackdave merged 1 commit into
mainfrom
refactor/split-map-extract

Conversation

@patchstackdave

Copy link
Copy Markdown
Contributor

Pure, behaviour-preserving split of src/map/extract.ts (1,626 → 123 lines) into ten focused modules. No logic, comment semantics, control flow or public API changed.

Why

The file had grown to 1,626 lines and become the single hardest thing in the repo to review — and the site of several subtle bugs (a global replace once made a helper call itself, causing infinite recursion; another silently no-op'd on a mismatched anchor; leaf-vs-path matching hid inside a 90-line function). The seams were already implicit: helpers had to be exported purely so tests could reach them, and tests/map/* is already one file per concern.

Layout

Module Lines
ast.ts 148
bindings.ts 140
routes.ts 105
sources.ts 92
coordinates.ts 46
inputs.ts 194
sinks.ts 247
module-graph.ts 102
flows.ts 330
entries.ts 162
extract.ts 123 (orchestrator + re-exports)

Dependency graph verified acyclic: types → ast → bindings/routes → sources/coordinates → inputs/sinks → module-graph/flows → entries → extract.

Proof it changed nothing

  • 845 tests passing across 79 files — the same counts as main.
  • git diff --stat -- tests is empty: not one test was modified. extract.ts re-exports runtimeCoordinate, functionNameFromPath, routeFromFilePath (plus the WalkStats / ModuleGraph types), so every existing import still resolves.
  • typecheck clean, build clean.
  • Independent check beyond the suite: running the built map CLI against the real reference app on main and on this branch produces byte-identical JSON (9,693 bytes both).
  • Modules were assembled by copying exact line ranges from a pristine snapshot, then mechanically verified: the copied ranges cover every non-blank original line with zero duplicates, and a line-multiset diff contains only new import lines, added export prefixes, and two comment lines. Every security-reasoning comment travelled with its code intact.

Three deliberate deviations from the obvious layout

  1. ROUTE_REGISTER_NAMES lives in routes.ts, not entries.ts — its comment requires one list to drive both the AST recognizer and the textual pre-filter; putting it in entries.ts would have forced an upward sources → entries edge.
  2. The ModuleGraph interface lives in sinks.tssinksFrom needs the type while createModuleGraph needs collectLocalSinks; moving the interface down breaks the cycle one-way.
  3. methodFromObjectArg went to ast.ts — dependency-free, and it shares a section heading with unwindChain.

Latent issues found, deliberately NOT fixed here

Reported so they aren't lost; each needs its own PR because each is a behaviour change:

  1. Renamed destructuring loses the request namespace. ({ query }) => query.id correctly yields get.id, but ({ query: q }) => q.id falls through to bodypost.id. Worse for params: an aliased route-param read would receive a runtime coordinate where the resolver exposes none. The alias is recorded but compared against the literal 'query'/'params', so the binding key is discarded.
  2. escapeRe is dead code.
  3. pathFromTainted strips a leading namespace segment only when segs.length > 1, so a bare req.body read keeps body in its path — harmless today, inconsistent with the rule above it.

`src/map/extract.ts` had grown to ~1.6k lines covering the whole
extraction pipeline. Split it, moving code verbatim, into modules that
follow the pipeline's own layering:

  ast          dependency-free AST helpers
  bindings     per-file module bindings (identifier -> npm package)
  routes       file-path/route-shape derivation + the route-register list
  sources      project walk, pre-filter, framework detection
  coordinates  input -> runtime rule parameter
  inputs       validator schemas + request reads
  sinks        sink recognizers, argument roles, candidate families
  module-graph one-hop cross-file helper tracing
  flows        input -> sink linking, limitations
  entries      entry-point recognizers
  extract      the orchestrator only, plus re-exports

No behaviour change: every moved line is byte-identical, and
`extract.ts` re-exports what consumers and tests import from it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@coderbuds

coderbuds Bot commented Aug 13, 2026

Copy link
Copy Markdown

Refactored large extract.ts into focused, cohesive modules improving clarity.

🎯 Quality: 76% Good · 📦 Size: Oversized — strongly consider breaking this down

🛡️ Standards: no pre-flight fit check ran for this change — wire assess-change-fit into your coding agents to catch size before opening.

📈 This month: Your 58th PR — above team average · Averaging Good

See how your team is trending →

@patchstackdave

Copy link
Copy Markdown
Contributor Author

/review

@patchstackdave
patchstackdave merged commit 409f358 into main Aug 13, 2026
5 checks passed
@patchstackdave
patchstackdave deleted the refactor/split-map-extract branch August 13, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants