Skip to content

feat(parser): extract call-registration HTTP endpoints for JS/TS and Go - #956

Open
geeknik wants to merge 4 commits into
tirth8205:mainfrom
geeknik:feat/call-registration-endpoints
Open

feat(parser): extract call-registration HTTP endpoints for JS/TS and Go#956
geeknik wants to merge 4 commits into
tirth8205:mainfrom
geeknik:feat/call-registration-endpoints

Conversation

@geeknik

@geeknik geeknik commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

What

Extract HTTP endpoints from call-registration web frameworks so their handlers become addressable like decorator/annotation routes:

  • JS/TS — Express/Koa/Fastify app.get('/x', handler), router.post('/x', handler)
  • Go — net/http http.HandleFunc('/x', handler), gin/echo/chi r.GET('/x', handler)

Each emits an Endpoint node and a HANDLES edge (handler → endpoint), mirroring the existing _emit_spring_webflux_endpoint. The existing handlers_of / endpoints_for queries work with zero changes, so Spring MVC, Spring WebFlux, Express, Koa, Fastify, and Go are all handled uniformly.

Why

Decorator/annotation routes (FastAPI @app.get, Spring @GetMapping) are already captured, but call-registration routes were not, so their handlers were invisible as HTTP entrypoints. flows.detect_entry_points even carries (app|router)\.(get|post|...) patterns, but they only fire on a stamped decorator string, which call-registration never produces.

How

  • New _call_registration_arguments + _emit_call_registration_endpoint next to the WebFlux emitter.
  • Wired into _extract_calls at the JS member_call branch and the Go typed-call branch.
  • Constants _JS_ROUTE_VERBS / _GO_ROUTE_VERBS.

Scope / follow-up

Named identifier handlers defined in the file. Inline/anonymous handlers (app.get('/x', (req,res)=>{...})) are a documented follow-up: they are not their own graph nodes today and need synthetic node creation in the same emitter.

Safety

No schema change, no migration — Endpoint/HANDLES already exist and node/edge kinds are free-form TEXT. Detection requires a literal path starting with / plus an identifier handler, so non-route calls like cache.get('key') are ignored.

Tests

Adds tests/test_call_registration_endpoints.py (Express, Go net/http, gin, handlers_of/endpoints_for round-trip, negative cases). Existing parser/graph/flows suites pass unchanged locally (774 + 4).

Route handlers registered by a call — Express/Koa/Fastify
`app.get('/x', handler)` and Go net/http `http.HandleFunc('/x', handler)`
plus gin/echo/chi `r.GET('/x', handler)` — now emit an `Endpoint` node
and a `HANDLES` edge from the handler to the endpoint, mirroring the
existing Spring WebFlux emitter (`_emit_spring_webflux_endpoint`). This
makes call-registration handlers addressable by the existing
`handlers_of` / `endpoints_for` queries, uniformly with Spring MVC and
WebFlux.

Scope: named identifier handlers defined in the same file. Inline and
anonymous function handlers are left for a follow-up because they are not
their own graph nodes today. No schema change or migration — `Endpoint`
and `HANDLES` already exist and node/edge kinds are free-form TEXT.

Adds tests/test_call_registration_endpoints.py (Express, Go net/http,
gin, query round-trip, and non-route negative cases).

Claude-Session: https://claude.ai/code/session_01LjH35hKtHPMtzpJGzFN2Zp
Signed-off-by: geeknik <geeknik@protonmail.ch>
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

code-review-graph review

Overall risk: 0.55 (MEDIUM) — 17 changed function(s)/class(es), 0 affected flow(s), 6 test gap(s)

Risk-scored changes

Risk Level Symbol Location Tested
0.55 medium code_review_graph/parser.py::CodeParser._python_route_signature code_review_graph/parser.py:9635 no
0.35 low code_review_graph/parser.py::CodeParser._call_registration_arguments code_review_graph/parser.py:9653 no
0.30 low code_review_graph/parser.py::CodeParser._string_literal_value code_review_graph/parser.py:9605 no
0.25 low code_review_graph/parser.py::CodeParser._route_from_argument code_review_graph/parser.py:9616 no
0.15 low code_review_graph/parser.py::CodeParser code_review_graph/parser.py:2416 yes
0.15 low code_review_graph/parser.py::CodeParser._emit_call_registration_endpoint code_review_graph/parser.py:9694 no
0.15 low code_review_graph/parser.py::CodeParser._extract_calls code_review_graph/parser.py:10850 no
0.05 low tests/test_call_registration_endpoints.py::test_express_routes_link_endpoints_to_handlers tests/test_call_registration_endpoints.py:48 (test)
0.05 low tests/test_call_registration_endpoints.py::test_go_call_registration_routes tests/test_call_registration_endpoints.py:64 (test)
0.05 low tests/test_call_registration_endpoints.py::test_endpoint_queries_use_addressable_nodes tests/test_call_registration_endpoints.py:73 (test)

Test gaps

  • code_review_graph/parser.py::CodeParser._string_literal_value (code_review_graph/parser.py:9605)
  • code_review_graph/parser.py::CodeParser._route_from_argument (code_review_graph/parser.py:9616)
  • code_review_graph/parser.py::CodeParser._python_route_signature (code_review_graph/parser.py:9635)
  • code_review_graph/parser.py::CodeParser._call_registration_arguments (code_review_graph/parser.py:9653)
  • code_review_graph/parser.py::CodeParser._emit_call_registration_endpoint (code_review_graph/parser.py:9694)
  • ...and 1 more without direct tests

Token savings: this graph-backed report used ~165,473 fewer tokens (~98%) than reading every changed file in full (estimated, chars/4 approximation).


Powered by code-review-graph — local-first analysis; no code leaves the CI runner.

Anonymous/inline function handlers passed to a call-registration route,
`app.post('/x', (req, res) => {...})` or Go
`http.HandleFunc('/x', func(...){})`, are now emitted as a synthetic
`Function` node spanning the inline body and used as the `HANDLES`
source. This makes anonymous route handlers, the Express majority,
addressable and analyzable uniformly with named handlers.

Extends tests/test_call_registration_endpoints.py with inline JS and Go
cases.
…hon)

Extends the call-registration extractor beyond Express/Go to more
frameworks:

- Object/dict route config (Hapi, Kibana, Fastify):
  router.get({ path: '/x' }, handler)
- Django URLConf: path('x/', view), re_path(r'...', view), url(...)
- aiohttp / Flask: app.router.add_get('/x', h),
  app.add_url_rule('/x', name, h)

The route path comes from a string literal or the path/url/route key of
an object/dict config; Django routes need no leading slash (require_slash
is off for those framework-specific callees). Handlers resolve for
same-file named/dotted references and inline functions.

Cross-file handler resolution (Django views in a separate module) and
class-based `.as_view()` handlers are follow-ups.
`mux.HandleFunc("GET /info", handler)` (Go 1.22 http.ServeMux) embeds
the HTTP method in the route pattern. The method is now split out of the
pattern and the path validated, so these register as GET/POST/... rather
than being rejected for lacking a leading slash. Bare "/legacy" patterns
still register as ANY.
@tirth8205

Copy link
Copy Markdown
Owner

Changes required: method names alone create false HTTP endpoints and inline handler identities collide. Parse const cache = new Map(); const data = cache.get('/key', () => fallback()); using CodeParser(repo_root).parse_file(path) and this PR emits an HTTP endpoint; parsing app.get('/a', () => first()); app.get('/b', () => second()); on one line assigns both routes the same handler identity and leaves body calls attached to the file. Require framework evidence, unique handler identities and correct call attribution.

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