[PR #1810] [CLOSED] fix(javascript): recover GraphQL operations from exact template text #4833

Closed
opened 2026-10-31 00:55:31 +00:00 by bsakaguchi · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/morluto/rea/pull/1810
Author: @jayhemnani9910
Created: 10/11/2026
Status: ❌ Closed

Base: main ← Head: fix/graphql-leading-interpolation


📝 Commits (7)

  • 1be7e68 fix(javascript): recognize GraphQL operations after leading fragment interpolations
  • 38a1305 fix(javascript): keep GraphQL comment state across template interpolations
  • fe68cca fix(javascript): fold exact GraphQL interpolation values before scanning
  • a31ec81 fix(javascript): keep dynamic GraphQL interpolation semantics unknown
  • f67fb57 fix(javascript): retain observed GraphQL headers before dynamic suffixes
  • ae1f088 fix(javascript): assign folded GraphQL text one owner
  • ee6148e fix(javascript): preserve distinct folded GraphQL operations

📊 Changes

3 files changed (+156 additions, -21 deletions)

View changed files

📝 docs/javascript-artifact-reconstruction.md (+9 -2)
📝 src/domain/javascript/javascriptRpcEndpoints.test.ts (+90 -0)
📝 src/domain/javascript/javascriptRpcEndpoints.ts (+57 -19)

📄 Description

Summary

A GraphQL document written the way the Apollo Client docs show fragments, with the fragment interpolated before the operation, is not reported as an endpoint:

const GET_POST_DETAILS = gql`
  ${CORE_COMMENT_FIELDS}
  query CommentsForPost($postId: ID!) { ... }
`;

analyze-javascript-application and analyze-web-bundle report no graphql:query for CommentsForPost. The same document with the interpolation at the end is reported.

No related issue; this is a small follow-up to #1670, so it comes straight as a PR.

Problem and expected behavior

Trigger: a template literal whose text starts with one or more ${...} interpolations, then a named operation.

Before: the template branch in createJavaScriptRpcScan only reads the first quasi (src/domain/javascript/javascriptRpcEndpoints.ts:312-318). For the document above that quasi is just whitespace, so nothing is found. Modern bundles keep tagged templates as template literals, so this hits shipped code too, not only sources.

Expected: leading interpolations hold fragment definitions; the operation that follows them is reported, as it already is when the fragment comes after the operation.

Change and scope

The template branch now walks the quasis in order, skips those that hold only GraphQL ignored tokens (whitespace, commas, comments), and reads the first one with content, using the same header rule as before. The ignored-token loop moves into a small skipGraphqlIgnored function shared with graphqlOperationFromText. A template with text before its first interpolation behaves as before, and an uncooked quasi still stops the scan.

Not included: operations whose selection set starts with a fragment spread (query Q { ...F }); the docs already scope that out.

Contract and boundary impact

  • Semantic owner and earliest changed stage: inert JavaScript static analysis, RPC endpoint recognition (javascriptRpcEndpoints.ts).
  • CLI and MCP/tool-catalog contract: none; the same graphql:* endpoint records, now also for these templates.
  • Provider, bridge, target-format, or platform compatibility: none.
  • Evidence, artifact, provenance, or reconstruction contract: none.
  • Process execution, authorization, cleanup, or containment impact: none.
  • Generated metadata (docs/public/product-catalog.json), package, or installation impact: none.

Evidence and regression coverage

  • Tests added or updated: recognizes operations that follow leading fragment interpolations in src/domain/javascript/javascriptRpcEndpoints.test.ts (one leading interpolation; two adjacent ones plus a # comment; a negative control with prose before the operation). It fails on current main ([]) and passes with this change.
  • Base reproduction or other evidence: executed on Linux x64 with rea-agents 6.4.0 and main. A three-document app (Apollo docs GET_POST_DETAILS, GET_DOG, and a mutation with a trailing fragment):
    6.4.0 / main: graphql:mutation AddTodo, graphql:query GetDog
    this branch:  graphql:mutation AddTodo, graphql:query CommentsForPost, graphql:query GetDog
    
    The same page served locally and read through analyze-web-bundle in headless Chrome: GetDog only before, CommentsForPost and GetDog after.
  • User-visible CLI/MCP output: the lines above.
  • Remaining proof gaps: none known.

For evidence-bearing changes:

  • Observed, derived, and inferred claims remain distinguishable.
  • Artifact identity, source provenance, and failed attempts remain preserved.
  • Unsupported, incomplete, unavailable, or uncertain outcomes remain visible.

Validation performed

  • npx vitest run src/domain/javascript/javascriptRpcEndpoints.test.ts src/domain/webBundleAnalyzer.test.ts: 38 passed; the new case fails without the fix.
  • npx vitest run --project domain src/domain/javascript: 841 passed.
  • npm run check:fast: passed.
  • npx vitest run --project <name> for each project except acceptance, after npm run build:cached, on main 914ba833 before rebasing: 7421 passed, 21 failed, 87 skipped, against 7420 / 21 / 87 on untouched 914ba833 with an identical failure list (firmware tests that need Binwalk 3.1.x, ASAR tests whose unpacked companion file is missing here). acceptance was not run (out of memory on this machine).

Compatibility, safety, and release

  • Breaking changes or migration steps: none.
  • Real Hopper/Ghidra, browser, or OS coverage: Linux; headless Chrome for analyze-web-bundle.
  • Package or release metadata impact: none.
  • Security, privacy, process, or containment review: none; inert parsing only.

Review checklist

  • This PR addresses a concrete problem or an agreed enhancement.
  • The PR has one focused outcome and the title follows type(scope): outcome.
  • Related issue is linked, or the reason for not linking one is stated above.
  • Tests cover changed observable behavior and meaningful failure paths.
  • Owning docs, contracts, and generated metadata are updated where needed.
  • User-visible CLI/MCP changes include representative output.
  • I checked the final diff for secrets, unrelated cleanup, and unsupported claims.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/morluto/rea/pull/1810 **Author:** [@jayhemnani9910](https://github.com/jayhemnani9910) **Created:** 10/11/2026 **Status:** ❌ Closed **Base:** `main` ← **Head:** `fix/graphql-leading-interpolation` --- ### 📝 Commits (7) - [`1be7e68`](https://github.com/morluto/rea/commit/1be7e683e8a9810ce6e9a7ba525706906bc03146) fix(javascript): recognize GraphQL operations after leading fragment interpolations - [`38a1305`](https://github.com/morluto/rea/commit/38a13052f8ef37bc122b79334f586d59f196940c) fix(javascript): keep GraphQL comment state across template interpolations - [`fe68cca`](https://github.com/morluto/rea/commit/fe68cca99f4f65d8e58e06528fca1b2284f8bfbf) fix(javascript): fold exact GraphQL interpolation values before scanning - [`a31ec81`](https://github.com/morluto/rea/commit/a31ec81dd60acaec3ff85a737ddbbc7893dcd4b3) fix(javascript): keep dynamic GraphQL interpolation semantics unknown - [`f67fb57`](https://github.com/morluto/rea/commit/f67fb578c07dabf6059e273bf7cfa2e20c98cebd) fix(javascript): retain observed GraphQL headers before dynamic suffixes - [`ae1f088`](https://github.com/morluto/rea/commit/ae1f08894ba1736aef775727d8e05360a4af86bc) fix(javascript): assign folded GraphQL text one owner - [`ee6148e`](https://github.com/morluto/rea/commit/ee6148e648d8d346dd6a6fcc46a047693f6beaa0) fix(javascript): preserve distinct folded GraphQL operations ### 📊 Changes **3 files changed** (+156 additions, -21 deletions) <details> <summary>View changed files</summary> 📝 `docs/javascript-artifact-reconstruction.md` (+9 -2) 📝 `src/domain/javascript/javascriptRpcEndpoints.test.ts` (+90 -0) 📝 `src/domain/javascript/javascriptRpcEndpoints.ts` (+57 -19) </details> ### 📄 Description ## Summary A GraphQL document written the way the Apollo Client docs show fragments, with the fragment interpolated before the operation, is not reported as an endpoint: ```js const GET_POST_DETAILS = gql` ${CORE_COMMENT_FIELDS} query CommentsForPost($postId: ID!) { ... } `; ``` `analyze-javascript-application` and `analyze-web-bundle` report no `graphql:query` for `CommentsForPost`. The same document with the interpolation at the end is reported. No related issue; this is a small follow-up to #1670, so it comes straight as a PR. ## Problem and expected behavior Trigger: a template literal whose text starts with one or more `${...}` interpolations, then a named operation. Before: the template branch in `createJavaScriptRpcScan` only reads the first quasi (`src/domain/javascript/javascriptRpcEndpoints.ts:312-318`). For the document above that quasi is just whitespace, so nothing is found. Modern bundles keep tagged templates as template literals, so this hits shipped code too, not only sources. Expected: leading interpolations hold fragment definitions; the operation that follows them is reported, as it already is when the fragment comes after the operation. ## Change and scope The template branch now walks the quasis in order, skips those that hold only GraphQL ignored tokens (whitespace, commas, comments), and reads the first one with content, using the same header rule as before. The ignored-token loop moves into a small `skipGraphqlIgnored` function shared with `graphqlOperationFromText`. A template with text before its first interpolation behaves as before, and an uncooked quasi still stops the scan. Not included: operations whose selection set starts with a fragment spread (`query Q { ...F }`); the docs already scope that out. ## Contract and boundary impact - Semantic owner and earliest changed stage: inert JavaScript static analysis, RPC endpoint recognition (`javascriptRpcEndpoints.ts`). - CLI and MCP/tool-catalog contract: none; the same `graphql:*` endpoint records, now also for these templates. - Provider, bridge, target-format, or platform compatibility: none. - Evidence, artifact, provenance, or reconstruction contract: none. - Process execution, authorization, cleanup, or containment impact: none. - Generated metadata (`docs/public/product-catalog.json`), package, or installation impact: none. ## Evidence and regression coverage - Tests added or updated: `recognizes operations that follow leading fragment interpolations` in `src/domain/javascript/javascriptRpcEndpoints.test.ts` (one leading interpolation; two adjacent ones plus a `#` comment; a negative control with prose before the operation). It fails on current main (`[]`) and passes with this change. - Base reproduction or other evidence: executed on Linux x64 with rea-agents 6.4.0 and main. A three-document app (Apollo docs `GET_POST_DETAILS`, `GET_DOG`, and a mutation with a trailing fragment): ``` 6.4.0 / main: graphql:mutation AddTodo, graphql:query GetDog this branch: graphql:mutation AddTodo, graphql:query CommentsForPost, graphql:query GetDog ``` The same page served locally and read through `analyze-web-bundle` in headless Chrome: `GetDog` only before, `CommentsForPost` and `GetDog` after. - User-visible CLI/MCP output: the lines above. - Remaining proof gaps: none known. For evidence-bearing changes: - [x] Observed, derived, and inferred claims remain distinguishable. - [x] Artifact identity, source provenance, and failed attempts remain preserved. - [x] Unsupported, incomplete, unavailable, or uncertain outcomes remain visible. ## Validation performed - `npx vitest run src/domain/javascript/javascriptRpcEndpoints.test.ts src/domain/webBundleAnalyzer.test.ts`: 38 passed; the new case fails without the fix. - `npx vitest run --project domain src/domain/javascript`: 841 passed. - `npm run check:fast`: passed. - `npx vitest run --project <name>` for each project except `acceptance`, after `npm run build:cached`, on main 914ba833 before rebasing: 7421 passed, 21 failed, 87 skipped, against 7420 / 21 / 87 on untouched 914ba833 with an identical failure list (firmware tests that need Binwalk 3.1.x, ASAR tests whose unpacked companion file is missing here). `acceptance` was not run (out of memory on this machine). ## Compatibility, safety, and release - Breaking changes or migration steps: none. - Real Hopper/Ghidra, browser, or OS coverage: Linux; headless Chrome for `analyze-web-bundle`. - Package or release metadata impact: none. - Security, privacy, process, or containment review: none; inert parsing only. ## Review checklist - [x] This PR addresses a concrete problem or an agreed enhancement. - [x] The PR has one focused outcome and the title follows `type(scope): outcome`. - [x] Related issue is linked, or the reason for not linking one is stated above. - [x] Tests cover changed observable behavior and meaningful failure paths. - [x] Owning docs, contracts, and generated metadata are updated where needed. - [x] User-visible CLI/MCP changes include representative output. - [x] I checked the final diff for secrets, unrelated cleanup, and unsupported claims. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
bsakaguchi 2026-10-31 00:55:31 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4833
No description provided.