You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The headline is entrypoint detection, at parity with codeanalyzer-python: a rules engine, a shipped ruleset for web and non-web TypeScript, an honest coverage report, and the Neo4j projection to go with it. Alongside it: the L4 dataflow graph is finally connected across call boundaries on both legs, every body node and parameter carries its id in analysis.json, and a program selector for analysing very large repositories one program at a time.
This release carries one breaking change even though the version bump is minor. If you depend on ^1.2.0 you will pick it up automatically, so please read the first section.
⚠️ Breaking change
_module is gone from the Neo4j graph; every destructive statement is scoped on the can:// id prefix (#166)
The per-module purge used to match nodes on a _module property — the owning file key. That is true across languages and false across applications: two TypeScript projects in one database that share a file path deleted each other's nodes for it. And the --eager purge, scoped on the bare application id, never reached a can://javascript/ node at all.
Now the node is matched by equality and its descendants by id + '/', once per language namespace this analyzer emits. _module is removed from the projection, the schema catalog and its index. Two marker labels, TSCanNode and JSCanNode, ride every node keyed by a can://<lang>/ id, as index anchors for the prefix predicate. The graph contract stays 2.0.0.
Migration:
Anything that queried _module (MATCH (n {_module: $key})) should match on the id instead: MATCH (n:TSCanNode) WHERE n.id = $moduleId OR n.id STARTS WITH $moduleId + '/'.
Databases written by 1.2.0 keep a stale _module property on old nodes. One push with --eager repopulates the application cleanly; nothing else is required.
The Application node now also carries the TSCanNode marker.
Also visible, not breaking (#152): TSDecorator.qualified_name was documented as checker-resolved and never was. It is now the import-table resolution (@nestjs/common.Get) or absent when the decorator's head is not an imported binding; name is the decorator exactly as written, so a dotted decorator's name gains its prefix (http.route, not route). The :TSDecorator node merges on the corrected key, so a local @Get and NestJS's @Get are no longer one node.
Entrypoint detection
Every callable and class carries entrypoints[] and is_entrypoint, and the application carries an entrypoint_report. Level-free: identical at every -a, cold or from a warm cache.
A declarative ruleset, not hardcoded detectors.--entrypoint-rules <file.yml> (repeatable) merges your rules with the shipped set and can disable: shipped rules by id. A malformed file is a hard error before analysis starts — never load-clean-and-do-nothing. (#170)
A framework gate. A framework's rules run only if first-party source imports it or the manifest names it, so a locally defined Controller in a non-NestJS project cannot register. (#156)
Five matcher kinds, because TypeScript declares entrypoints in more ways than python does: decorators (NestJS, Angular), base classes with transitive heritage and dispatch (#160), call sites (app.get('/p', handler) — the record attaches to the handler), file conventions (Next.js app/**/route.ts and pages/api, SvelteKit +server.ts), and package.jsonmain/bin (#163).
Two tiers. Framework rules match the import-table-resolved name at certain; a framework-independent heuristic tier matches the written spelling at heuristic, runs last, and never doubles a node a framework rule claimed. Every record carries confidence, rule, ruleset, evidence, and where it applies route, http_methods, via.
Non-web apps are covered (#168): Electron (app.on, ipcMain.handle), commander (.action), worker_threads (parentPort.on), process.on, and the manifest's main/bin.
The report makes silence visible.frameworks_detected, rulesets, unresolved (every decorator or base spelling nothing could name, every call a rule matched but could not attach), errors. In Neo4j: is_entrypoint / entrypoint_frameworks on :TSClass and :TSCallable, and the report on :TSApplication.
Highlights
L4 dataflow crosses calls on both legs (#169) — the SDG's port vertices were connected across callables but not into the statement-level ddg: a caller's definition never reached actual_in, a return value never reached the statement that used it, and a walk entering a callee through param_in dead-ended at formal_in. All four binding classes are emitted now (prov: ["reaching-defs"]). Measured on the dataflow fixture: formal_in → use 0 → 31, def → actual_in 0 → 5, actual_out → callsite 0 → 17.
Body nodes and parameters carry their id (#165) — body[<local>].id is the same string the graph merges the node on, and parameters[i].id names the formal_in vertex that carries the parameter, at every level. A JSON consumer can name a statement without recomposing the join key.
Analyse one program at a time (#149) — --list-programs enumerates a repository's tsconfig scopes; --program <scope> restricts a run to one, with can:// ids byte-identical to a whole-repository run so shards union by id. --no-repo-sections skips the repository-wide artifact inventory on a shard; --emit-ir persists the shard's graph IR for a later cross-shard stitch. This is the first half of the sharded two-wave L4 design (spec) for repositories that no longer fit in one process.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
codeanalyzer-typescript v1.3.0
The headline is entrypoint detection, at parity with codeanalyzer-python: a rules engine, a shipped ruleset for web and non-web TypeScript, an honest coverage report, and the Neo4j projection to go with it. Alongside it: the L4 dataflow graph is finally connected across call boundaries on both legs, every body node and parameter carries its id in
analysis.json, and a program selector for analysing very large repositories one program at a time.This release carries one breaking change even though the version bump is minor. If you depend on
^1.2.0you will pick it up automatically, so please read the first section._moduleis gone from the Neo4j graph; every destructive statement is scoped on thecan://id prefix (#166)The per-module purge used to match nodes on a
_moduleproperty — the owning file key. That is true across languages and false across applications: two TypeScript projects in one database that share a file path deleted each other's nodes for it. And the--eagerpurge, scoped on the bare application id, never reached acan://javascript/node at all.Now the node is matched by equality and its descendants by
id + '/', once per language namespace this analyzer emits._moduleis removed from the projection, the schema catalog and its index. Two marker labels,TSCanNodeandJSCanNode, ride every node keyed by acan://<lang>/id, as index anchors for the prefix predicate. The graph contract stays2.0.0.Migration:
_module(MATCH (n {_module: $key})) should match on the id instead:MATCH (n:TSCanNode) WHERE n.id = $moduleId OR n.id STARTS WITH $moduleId + '/'._moduleproperty on old nodes. One push with--eagerrepopulates the application cleanly; nothing else is required.Applicationnode now also carries theTSCanNodemarker.Also visible, not breaking (#152):
TSDecorator.qualified_namewas documented as checker-resolved and never was. It is now the import-table resolution (@nestjs/common.Get) or absent when the decorator's head is not an imported binding;nameis the decorator exactly as written, so a dotted decorator'snamegains its prefix (http.route, notroute). The:TSDecoratornode merges on the corrected key, so a local@Getand NestJS's@Getare no longer one node.Entrypoint detection
Every callable and class carries
entrypoints[]andis_entrypoint, and the application carries anentrypoint_report. Level-free: identical at every-a, cold or from a warm cache.--entrypoint-rules <file.yml>(repeatable) merges your rules with the shipped set and candisable:shipped rules by id. A malformed file is a hard error before analysis starts — never load-clean-and-do-nothing. (#170)Controllerin a non-NestJS project cannot register. (#156)app.get('/p', handler)— the record attaches to the handler), file conventions (Next.jsapp/**/route.tsandpages/api, SvelteKit+server.ts), andpackage.jsonmain/bin(#163).certain; a framework-independent heuristic tier matches the written spelling atheuristic, runs last, and never doubles a node a framework rule claimed. Every record carriesconfidence,rule,ruleset,evidence, and where it appliesroute,http_methods,via.app.on,ipcMain.handle), commander (.action),worker_threads(parentPort.on),process.on, and the manifest'smain/bin.frameworks_detected,rulesets,unresolved(every decorator or base spelling nothing could name, every call a rule matched but could not attach),errors. In Neo4j:is_entrypoint/entrypoint_frameworkson:TSClassand:TSCallable, and the report on:TSApplication.Highlights
L4 dataflow crosses calls on both legs (#169) — the SDG's port vertices were connected across callables but not into the statement-level ddg: a caller's definition never reached
actual_in, a return value never reached the statement that used it, and a walk entering a callee throughparam_indead-ended atformal_in. All four binding classes are emitted now (prov: ["reaching-defs"]). Measured on the dataflow fixture:formal_in → use0 → 31,def → actual_in0 → 5,actual_out → callsite0 → 17.Body nodes and parameters carry their id (#165) —
body[<local>].idis the same string the graph merges the node on, andparameters[i].idnames theformal_invertex that carries the parameter, at every level. A JSON consumer can name a statement without recomposing the join key.Analyse one program at a time (#149) —
--list-programsenumerates a repository's tsconfig scopes;--program <scope>restricts a run to one, withcan://ids byte-identical to a whole-repository run so shards union by id.--no-repo-sectionsskips the repository-wide artifact inventory on a shard;--emit-irpersists the shard's graph IR for a later cross-shard stitch. This is the first half of the sharded two-wave L4 design (spec) for repositories that no longer fit in one process.Upgrade
A warm
.codeanalyzercache from 1.2.0 is invalidated automatically (the tree shape changed).Links
All reactions