fix(js-analyzer): repair JS/TS analyzer inventory, call-graph, schema and functionId bugs#70
Conversation
… and functionId bugs
Fixes a cluster of defects in the JavaScript/TypeScript analysis pipeline,
grouped into five areas plus a local functionId parse fix. All root causes are in
the JS parser files; the c/ruby call_graph_builder.py siblings are correct parity
references and are not edited.
J1 call-edge extraction:
- extractCallsFromFunction passed funcNode.getKind() to getDescendantsOfKind
instead of ts.SyntaxKind.CallExpression, so every out-edge list was empty.
J2 AST inventory gaps (extractFunctionsFromFile now visits these shapes):
- module.exports = class {} (ClassExpression)
- anon export default function, Foo.prototype.bar=fn, this.method=fn,
Object.assign(proto, ...)
- this.x=function(){} assigned in a constructor body
- class get/set accessors were dropped because ts-morph getMethods() excludes
GetAccessor/SetAccessor. Now also iterate getGetAccessors()+getSetAccessors() at
all three class-member sites (inventory builder, callGraph builder, and the
single-member lookup), so `get x()`/`set x(v)` emit as Class.x functions WITH
callGraph companions.
- Object.defineProperty(X.prototype,"n",{value:fn})
- bare top-level CallExpression modules
- HOC const-initializers (memo/forwardRef/styled)
- barrel re-export object-literal property values
J3 Pattern-A companion:
- buildCallGraphForFile now visits the same 5 emit paths as
extractFunctionsFromFile so callGraph keeps pace with functions.
J4 call-edge content:
- walk getArguments() to record callback identifiers
- normalize callee name to an identifier (JS-native)
- bucket unresolved/dynamic calls into indirect_calls
J5 schema and framework classification:
- emit snake_case reverse_call_graph, repository, and per-function parameters
- route-handler coverage now spans Koa/Fastify on BOTH axes -- the param-shape
classifier (_hasRouteHandlerSignature) and the route-REGISTRATION walker.
Added the `route` verb to EXPRESS_VERBS and the `fastify`/`koa` receiver stems
to EXPRESS_RECEIVER_STEMS / _isPlausibleExpressReceiver (additive; existing
Express detection unchanged) so `fastify.get('/x', handler)` and `koa.get(...)`
synthesise route_handler entry-point units. Also fixed the React
(request,response) false-positive.
functionId parse:
- unit_generator.js and test_pipeline.py split the "<filePath>:<functionName>"
id on the last colon, mangling multi-colon Express ids. Switched to first-colon
split to match the dependency_resolver contract. The id format is unchanged
(backward-compatible). The dependency_resolver.js half is deferred.
Tests: RED-first tests under tests/parsers/javascript/ drive the Node analyzer /
UnitGenerator on inline fixtures, including class get/set accessors and
Fastify/Koa route registration. Suite: 245 passed, 22 skipped, 0 failed. ruff
clean; node --check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for this — meaty, well-targeted, and the test coverage is genuinely strong: one fixture per AST shape, all gated on Node/npm availability so CI stays green cross-platform. I verified the three contract claims against the consumers on
The headline catch — No blockers; I'd take this as-is. Two non-blocking precision/recall trade-offs for your call — flagged because reachability gates the paid LLM stages, so graph noise translates to cost (traced through 🟡 Medium — precision → cost · Every bare Safe direction (over-approximation only adds noise/$, never drops a real vuln), so non-blocking — but it does tax the cost-reduction goal. Worth considering: only record an identifier arg as an edge when it resolves to a known function id (the 🟡 Medium — entry-point recall · Dropping the bare Blast radius is small in practice (the route-registration walker plus the Python Low (no action needed):
Nice work overall — the contract-citing comments throughout made this fast to verify. |
|
Closing as already resolved on current master. This fix's behavior shipped via the parser-fix-stack release (#133/#134); confirmed by independent reproduction — the original bug (reconstructed from its bug-pipeline investigation) no longer manifests on master, not merely by line-presence. Part of a full validated sweep of the open-PR corpus. |
Fixes a cluster of defects in the JavaScript/TypeScript analysis pipeline,
grouped into five areas plus a local functionId parse fix. All root causes are in
the JS parser files; the c/ruby call_graph_builder.py siblings are correct parity
references and are not edited.
J1 call-edge extraction:
instead of ts.SyntaxKind.CallExpression, so every out-edge list was empty.
J2 AST inventory gaps (extractFunctionsFromFile now visits these shapes):
Object.assign(proto, ...)
GetAccessor/SetAccessor. Now also iterate getGetAccessors()+getSetAccessors() at
all three class-member sites (inventory builder, callGraph builder, and the
single-member lookup), so
get x()/set x(v)emit as Class.x functions WITHcallGraph companions.
J3 Pattern-A companion:
extractFunctionsFromFile so callGraph keeps pace with functions.
J4 call-edge content:
J5 schema and framework classification:
classifier (_hasRouteHandlerSignature) and the route-REGISTRATION walker.
Added the
routeverb to EXPRESS_VERBS and thefastify/koareceiver stemsto EXPRESS_RECEIVER_STEMS / _isPlausibleExpressReceiver (additive; existing
Express detection unchanged) so
fastify.get('/x', handler)andkoa.get(...)synthesise route_handler entry-point units. Also fixed the React
(request,response) false-positive.
functionId parse:
id on the last colon, mangling multi-colon Express ids. Switched to first-colon
split to match the dependency_resolver contract. The id format is unchanged
(backward-compatible). The dependency_resolver.js half is deferred.
Tests: RED-first tests under tests/parsers/javascript/ drive the Node analyzer /
UnitGenerator on inline fixtures, including class get/set accessors and
Fastify/Koa route registration. Suite: 245 passed, 22 skipped, 0 failed. ruff
clean; node --check clean.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com