fix(extractors): unwrap computed property keys in object-literal key resolution#1945
Conversation
…resolution
Object-literal computed string-literal keys (`{ ['foo']: () => {} }`) were
extracted as the literal bracketed/quoted text (`obj.['foo']`) instead of the
plain property name (`obj.foo`), since the `pair` key resolution only handled
plain `string`-typed keys and fell through to raw node text for
`computed_property_name` nodes. Call sites like `obj.foo()` could never
resolve to the emitted definition.
The identical bug pattern was duplicated across five other key-resolution call
sites in the JS/TS extractor (typeMap seeding, Object.defineProperties,
Object.create/prototype-literal seeding, prototype assignment) and mirrored in
the native Rust extractor. Added a shared `resolvePropertyKeyName` (WASM) /
`resolve_property_key_name` (native) helper — mirroring the existing
`resolveMethodDefinitionName` / `resolve_method_def_name` treatment of
`method_definition` name nodes — and switched all affected call sites to use
it, fixing the whole bug class in both engines identically.
Impact: 6 functions changed, 21 affected
Codegraph Impact Analysis6 functions changed → 21 callers affected across 1 files
|
Greptile SummaryFixes a key-resolution bug in both WASM/TS and native/Rust JS extractors where computed string-literal object-literal keys (e.g.,
Confidence Score: 5/5Safe to merge — well-scoped extraction fix with symmetric dual-engine helpers, comprehensive unit and integration test coverage, and no mutations to data-store schema or public APIs. All six previously duplicated inline key-resolution patterns are replaced by a single helper per engine that is demonstrably equivalent for existing cases and correct for the newly fixed computed-string case. The No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Object-literal pair key node] --> B{key node type}
B -->|computed_property_name| C[Get inner node at index 1]
C --> D{inner node type}
D -->|string| E[strip quotes via extract_string_fragment]
D -->|string_fragment| F[use text as-is]
D -->|other e.g. member_expression| G[return None or empty string]
B -->|string| H[strip surrounding quotes]
B -->|identifier etc.| I[use text as-is]
E --> J[qualify as varName.plainName]
F --> J
H --> J
I --> J
J --> K[emit Definition / TypeMapEntry / prototype method]
G --> L[skip — no emission]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[Object-literal pair key node] --> B{key node type}
B -->|computed_property_name| C[Get inner node at index 1]
C --> D{inner node type}
D -->|string| E[strip quotes via extract_string_fragment]
D -->|string_fragment| F[use text as-is]
D -->|other e.g. member_expression| G[return None or empty string]
B -->|string| H[strip surrounding quotes]
B -->|identifier etc.| I[use text as-is]
E --> J[qualify as varName.plainName]
F --> J
H --> J
I --> J
J --> K[emit Definition / TypeMapEntry / prototype method]
G --> L[skip — no emission]
Reviews (1): Last reviewed commit: "fix(extractors): unwrap computed propert..." | Re-trigger Greptile |
Fixes #1764
Bug
extractObjectLiteralFunctions'spairbranch only stripped quotes for plainstring-typed keys. For a computed string-literal key like{ ['foo']: () => {} }, the key node type iscomputed_property_name, so it fell through to the raw bracket/quote text, producingobj.['foo']instead ofobj.foo. Call sites likeobj.foo()could never resolve to it. Reproduced identically on both engines.Fix
Auditing the codebase turned up the identical bug pattern duplicated across five other key-resolution call sites in the JS/TS extractor (typeMap seeding for object literals,
Object.defineProperties,Object.create/prototype-literal seeding, prototype assignment), and mirrored in the native Rust extractor. Per the project's "best architecture over smallest diff" guidance, I added one shared helper per engine —resolvePropertyKeyName(WASM/TS) andresolve_property_key_name(native/Rust) — that unwrapscomputed_property_namestring literals the same way the existingresolveMethodDefinitionName/resolve_method_def_namealready did formethod_definitionname nodes, and switched all six affected call sites in each engine to use it. This fixes the whole bug class identically in both engines instead of leaving four latent copies of the same defect behind.Non-string computed keys (e.g.
[Symbol.iterator]) are skipped rather than producing a garbage name, matching the existingmethod_definitionbehavior.Out of scope
Found a separate, distinct bug while auditing this code:
resolveMethodDefinitionName/resolve_method_def_namedon't strip quotes for non-computed quoted string keys ({ 'foo'() {} }→A.'foo'instead ofA.foo). Filed as #1944, not fixed here.Validation
tests/parsers/javascript.test.tscovering thepairbranch (arrow/function values, non-string computed keys).tests/integration/issue-1764-computed-objlit-key.test.tsexercising both WASM and native engines end-to-end (build graph, verify plain node name, verify call edge resolves, verify no bracketed names leak).crates/codegraph-core/src/extractors/javascript.rscoveringextract_object_literal_functions,extract_js_prototype_object_literal, andseed_descriptor_objectwith computed keys.codegraph where --file sample.js -T --json) with both--engine nativeand--engine wasmbefore and after the fix — both now reportobj.fooidentically.npm test(214 files, 3550 passed),cargo test --release(451 passed),npm run lintclean,npm run buildclean.codegraph diff-impact --staged -Tconfirmed the blast radius matched intent: the 5 fixed call sites plus the new shared helper, 21 transitive callers, no unexpected files touched.