Skip to content

fix: resolve URL-builder helper calls to Route/HTTP_CALLS#1010

Open
CharlesQueiroz wants to merge 3 commits into
DeusData:mainfrom
CharlesQueiroz:fix/url-builder-routes
Open

fix: resolve URL-builder helper calls to Route/HTTP_CALLS#1010
CharlesQueiroz wants to merge 3 commits into
DeusData:mainfrom
CharlesQueiroz:fix/url-builder-routes

Conversation

@CharlesQueiroz

Copy link
Copy Markdown

Fixes #1009. Stacked on #1008 (includes its commit; rebases cleanly once #1008 lands).

Root cause

URL-shaped literals returned from small builder functions never reach a call argument, so client(buildPath(id)) had no first_string_arg: no HTTP_CALLS edge, no Route node, static and template literals alike. lookup_string_constant only covers module-level consts.

Fix

  • handle_url_builders() (extract_unified.c, runs in the unified walk): when a return statement (or an arrow-function expression body) yields a URL-shaped literal, records builderName -> url in the same per-file constant map used for module-level consts. Ambiguous builders (two different URLs for one name) are tombstoned so lookups miss instead of guessing.
  • extract_url_or_topic_arg() (extract_calls.c): a call_expression argument whose callee is a plain identifier resolves through that map, giving the call its first_string_arg; the existing pipeline then mints the Route node and the HTTP_CALLS edge from the real HTTP caller (the hook), not from the builder.
  • Composed builders: the builder-body template flatten is map-aware: a ${...} substitution that is a bare identifier or a call to an already-recorded name inlines that value, everything else becomes {}, and the result is truncated at the first ? (query strings are not part of a route's identity). This covers the real-world TanStack shape:
function activityPath(id: string) { return `/api/v1/team-members/${id}/activity` }
function buildPath(id: string, cursor: string) {
  const params = new URLSearchParams()
  return `${activityPath(id)}?${params.toString()}`
}
apiFetch(buildPath(id, cursor))   // -> HTTP_CALLS -> /api/v1/team-members/{}/activity

Same-file scope, document order (same constraints the const map already has).

Validation

  • New regression tests extract_ts_url_builder_issue1009 (return + arrow bodies) and extract_ts_url_builder_composed_issue1009 (composition + query truncation).
  • Full suite: 5988 passed, 1 skipped, 0 failures.
  • End-to-end fixture: queryFn -HTTP_CALLS-> /api/v1/team-members/{}/activity now exists for the builder shape, joining the server-side __route__GET__/api/v1/team-members/{}/activity exactly.

…#1006)

Client-side URL extraction only recognized static string literals; any
template literal was silently skipped, so parameterized endpoints never
produced HTTP_CALLS edges or Route nodes and cross-repo route matching
missed them (the server side already normalizes path params to {}).

New cbm_template_string_text() flattens a template_string node: string
fragments verbatim, each ${...} substitution becomes {}. Wired into:
- extract_positional_url / extract_string_value (call-arg URLs)
- handle_string_refs (URL-shaped refs from const/return positions)
- handle_string_constants (module-level const lookups)

`/api/v1/things/${id}` now yields __route__ANY__/api/v1/things/{} and
the enclosing function gets the HTTP_CALLS edge, joining the canonical
placeholder shape of server-side routes.
)

URL-shaped literals returned from small builder functions never reached
call arguments, so client(buildPath(id)) produced no HTTP_CALLS edge and
no Route node, static or template alike.

handle_url_builders() records builderName -> returned URL in the same
per-file constant map used for module-level consts, covering return
statements and arrow expression bodies; a call_expression branch in
extract_url_or_topic_arg() resolves client(buildPath(id)) through it.
Composed builders inline already-recorded substitutions and truncate the
query string, so `${basePath(id)}?${params}` joins the server route
exactly. Ambiguous builders (two different URLs) are tombstoned.
@CharlesQueiroz CharlesQueiroz requested a review from DeusData as a code owner July 10, 2026 17:15
detect_url_in_args() (the arg_url HTTP_CALLS emitter used when the callee
is a local client wrapper, not a known HTTP library) reads per-arg values,
not first_string_arg. Resolve call_expression args through the builder map
and flatten template_string args to the {} form there as well, so wrappers
like apiFetch(buildPath(id)) emit the edge and join the canonical route.
@CharlesQueiroz

Copy link
Copy Markdown
Author

Pushed a follow-up commit: detect_url_in_args() (the arg_url HTTP_CALLS emitter used when the callee is a local client wrapper rather than a known HTTP library) reads per-arg values, not first_string_arg. The builder-map resolution and template flattening are now applied there too, so wrapper clients like apiFetch(buildPath(id), opts) emit the edge. Validated end-to-end on a real TanStack codebase: the parameterized hooks now produce HTTP_CALLS -> /api/v1/team-members/{}/activity, joining the server route exactly. Suite still 5988 passed / 0 failed.

@DeusData DeusData added bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/normal Standard review queue; useful PR with ordinary maintainer urgency. labels Jul 10, 2026
@DeusData DeusData added this to the 0.9.1-rc milestone Jul 10, 2026
@DeusData

Copy link
Copy Markdown
Owner

Thanks for sending this follow-up. I have triaged it into 0.9.1-rc as the fix candidate for #1009. Review focus will be the stacked dependency on #1008, builder ambiguity handling, and avoiding speculative cross-repo routes that could create false positives.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working parsing/quality Graph extraction bugs, false positives, missing edges priority/normal Standard review queue; useful PR with ordinary maintainer urgency.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JS/TS: URL-builder helper pattern (URL returned from a function) produces no Route/HTTP_CALLS

2 participants