Problem
TypeScript has no entrypoint detection. grep -rniE "entry_?point" src/ returns one hit, and it
is a bundler comment in src/dataflow/pool.ts. The fields were de-advertised in #60 precisely
because nothing populated them; this issue is the work that earns them back.
Without it the analyzer emits a call graph with no distinguished roots, so a consumer cannot ask
what is reachable from outside the application — the first question any taint or attack-surface
query asks.
codeanalyzer-python shipped this as its #27: a codeanalyzer/entrypoints/ package (5 files), 73
source references, PyEntrypoint/PyEntrypointReport, is_entrypoint and entrypoint_frameworks
on two Neo4j labels, and --entrypoint-rules.
Design: docs/design/specs/entrypoint-detection.md.
Scope boundary
This issue is a rules ENGINE plus a shipped ruleset, not a pair of framework finders. Its
previous title ("entrypoint finders (Express/Angular routes)") named two frameworks and no engine;
built that way it would produce hardcoded detectors with no rules file, no confidence grading, no
coverage report and no user extensibility, then need rewriting to reach parity.
The other half of #60 is already done and is NOT in scope. Top-level invocation roots are in the
call graph: module-scope calls are attributed to the MODULE (src/semantic_analysis/callGraph.ts:161,
python #131 parity). Verified — a module-scope boot() now yields can://…/app.ts -> can://…/app.ts/boot
with prov: ["tsc"].
Not in scope: taint or reachability queries over the entrypoints (those are frontend SDK concerns).
Goals
Per the spec's decomposition; each becomes its own PR, filed just-in-time.
Caveats and known risks
Python's engine cannot be ported as-is. It has two matchers, decorators and base classes, which
cover its ecosystem. TypeScript needs three more with no python analog:
| framework |
declared how |
matcher |
| NestJS, Angular |
decorators |
python has it |
| Express, Koa, Fastify |
app.get('/p', h) — a call |
call-site |
| Next.js, Remix, SvelteKit |
app/**/route.ts, +server.ts |
file convention |
| AWS Lambda |
exported handler |
export name |
| CLI tools, packages |
bin/main in package.json |
manifest |
The rules format must be designed for those from the start, not copied from python's rules.yml.
- Under-approximation is the designed failure mode and is invisible without the report. Ship
TSEntrypointReport in the same change as detection, never after — a framework the ruleset misses
looks identical to a project with no entrypoints.
- False positives are worse than misses. A locally defined
Controller decorator in a non-NestJS
project must not register. The stage-0 gate is what prevents that, so it is not an optimisation.
- The call-site matcher is the weakest link; it should ship at
confidence: heuristic. Express
handlers registered through a variable (const r = express.Router()) or a helper will be missed,
and that belongs in the report's unresolved counts.
- Two decisions are open in the spec: whether a file-convention entrypoint may hang off a module
(python has no module-level entrypoints, so this diverges from the shared vocabulary and should go
to the siblings first), and how call-site matching stays level-free — the spec recommends a
syntactic L1 match at heuristic rather than gating Express to -a >= 2, which would break
"identical at every -a".
- File-convention rules are framework-version-sensitive — Next.js moved
pages/api to
app/**/route.ts across a major. Rules must express both without a code change or the ruleset rots.
Definition of done
- A NestJS or Angular project gets correct, gated, reported entrypoints — not "some entrypoints were
found"
SCHEMA_VERSION unmoved; the change is provably additive (existing fields and relationships
unchanged)
- Detection never aborts an analysis: rule loading is a hard error before analysis starts, detection
itself is best-effort
- Entrypoints are identical at every
-a, and a test asserts it
- A project that does NOT use a framework registers zero of its entrypoints (the gate is tested, not
assumed)
TSEntrypointReport is populated in the same release as the detection it reports on
- Validated against real projects, not only fixtures — python's ruleset was tuned that way, and
"it found entrypoints on vscode" is not validation
Problem
TypeScript has no entrypoint detection.
grep -rniE "entry_?point" src/returns one hit, and itis a bundler comment in
src/dataflow/pool.ts. The fields were de-advertised in #60 preciselybecause nothing populated them; this issue is the work that earns them back.
Without it the analyzer emits a call graph with no distinguished roots, so a consumer cannot ask
what is reachable from outside the application — the first question any taint or attack-surface
query asks.
codeanalyzer-python shipped this as its #27: a
codeanalyzer/entrypoints/package (5 files), 73source references,
PyEntrypoint/PyEntrypointReport,is_entrypointandentrypoint_frameworkson two Neo4j labels, and
--entrypoint-rules.Design:
docs/design/specs/entrypoint-detection.md.Scope boundary
This issue is a rules ENGINE plus a shipped ruleset, not a pair of framework finders. Its
previous title ("entrypoint finders (Express/Angular routes)") named two frameworks and no engine;
built that way it would produce hardcoded detectors with no rules file, no confidence grading, no
coverage report and no user extensibility, then need rewriting to reach parity.
The other half of #60 is already done and is NOT in scope. Top-level invocation roots are in the
call graph: module-scope calls are attributed to the MODULE (
src/semantic_analysis/callGraph.ts:161,python #131 parity). Verified — a module-scope
boot()now yieldscan://…/app.ts -> can://…/app.ts/bootwith
prov: ["tsc"].Not in scope: taint or reachability queries over the entrypoints (those are frontend SDK concerns).
Goals
Per the spec's decomposition; each becomes its own PR, filed just-in-time.
TSEntrypoint/TSEntrypointReportschema, Neo4jis_entrypoint/entrypoint_frameworks, andthe level-free L1 post-pass skeleton emitting an empty report
TSImport∪TSDependency, populatingframeworks_detected--entrypoint-rules, and the decorator matcher (ships NestJS +Angular)
extends_ids/implements_ids, withdispatch:andvia:Caveats and known risks
Python's engine cannot be ported as-is. It has two matchers, decorators and base classes, which
cover its ecosystem. TypeScript needs three more with no python analog:
app.get('/p', h)— a callapp/**/route.ts,+server.tshandlerbin/mainin package.jsonThe rules format must be designed for those from the start, not copied from python's
rules.yml.TSEntrypointReportin the same change as detection, never after — a framework the ruleset misseslooks identical to a project with no entrypoints.
Controllerdecorator in a non-NestJSproject must not register. The stage-0 gate is what prevents that, so it is not an optimisation.
confidence: heuristic. Expresshandlers registered through a variable (
const r = express.Router()) or a helper will be missed,and that belongs in the report's
unresolvedcounts.(python has no module-level entrypoints, so this diverges from the shared vocabulary and should go
to the siblings first), and how call-site matching stays level-free — the spec recommends a
syntactic L1 match at
heuristicrather than gating Express to-a >= 2, which would break"identical at every
-a".pages/apitoapp/**/route.tsacross a major. Rules must express both without a code change or the ruleset rots.Definition of done
found"
SCHEMA_VERSIONunmoved; the change is provably additive (existing fields and relationshipsunchanged)
itself is best-effort
-a, and a test asserts itassumed)
TSEntrypointReportis populated in the same release as the detection it reports on"it found entrypoints on vscode" is not validation