mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-07 02:58:02 +00:00
feat(scope-resolution): capture record construction as property writes
The read side answered well after the narrowing work while "who SETS this
field?" still missed the code that stamps the value. A record built inline —
`return { exitContract: { exitMinAtrMult: settings.x } }` — is bound to no
variable, so it minted no definition and its keys referenced nothing.
Modelled as WRITE REFERENCES, deliberately not definitions. The round-1 rule
already mints Property nodes for literals bound to a variable; minting more for
anonymous records would add same-named competitors to the very name-narrowing
that makes these fields resolvable — measured at 26 competing definitions for
one field on the reporting repo, which is what made every backend read
unanswerable in the first place. A construction site is a USE of a field, not
another declaration of it.
Two positions only: nested under a key, and returned. Both are records with a
name attached (the key, or the function). An inline call argument
(`doThing({ id: 1 })`) stays excluded for the same reason round 1 excluded it
from definitions — it is call-site data, not a named surface — and is asserted
as such.
The enclosing literal is the receiver and it is anonymous, so these route
through the same narrowing and the same refusal-to-guess as every other
untyped receiver.
Verified on the reporting repo: `entryPlan.js` went from no rows to
`selectExitEnvelope` as a writer of `exitMinAtrMult`. Both captures
mutation-checked.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
19974b49d8
commit
85800fc4e2
3 changed files with 88 additions and 0 deletions
|
|
@ -647,6 +647,39 @@ export const JAVASCRIPT_SCOPE_QUERY = `
|
|||
key: (property_identifier) @reference.name
|
||||
@reference.read.destructured)) @reference.receiver)
|
||||
|
||||
;; Object-literal keys in RECORD CONSTRUCTION position (R2-1b). Building
|
||||
;; \`{ exitContract: { exitMinAtrMult: settings.x } }\` SETS that field, so this
|
||||
;; is the write counterpart to the destructured read above — without it
|
||||
;; "who reads this setting?" answers well and "who SETS it?" misses the code
|
||||
;; that stamps the value.
|
||||
;;
|
||||
;; A WRITE REFERENCE, deliberately not a definition. The round-1 rule already
|
||||
;; mints Property nodes for literals bound to a variable; minting more for
|
||||
;; anonymous records would add same-named competitors to the very name-narrowing
|
||||
;; that makes these reads resolvable — measured at 26 competing definitions for
|
||||
;; one field on the reporting repo. A construction site is a USE of a field, not
|
||||
;; another declaration of it.
|
||||
;;
|
||||
;; Two positions only: nested under a key, and returned. Both are records with a
|
||||
;; name attached (the key, or the function). An inline call argument
|
||||
;; (\`doThing({ id: 1 })\`) stays excluded for the same reason round 1 excluded
|
||||
;; it from definitions — it is call-site data, not a named surface.
|
||||
;;
|
||||
;; The enclosing literal is the receiver, and it is anonymous, which routes
|
||||
;; these through the same narrowing and the same refusal-to-guess as every other
|
||||
;; untyped receiver.
|
||||
(pair
|
||||
value: (object
|
||||
(pair
|
||||
key: (property_identifier) @reference.name
|
||||
@reference.write.property-key) @_r2b.nested) @reference.receiver)
|
||||
|
||||
(return_statement
|
||||
(object
|
||||
(pair
|
||||
key: (property_identifier) @reference.name
|
||||
@reference.write.property-key) @_r2b.returned) @reference.receiver)
|
||||
|
||||
`;
|
||||
|
||||
/** JSX-only suffix — appended when compiling against the JSX grammar for .jsx files. */
|
||||
|
|
|
|||
|
|
@ -17,3 +17,28 @@ export function appliesRenamed({ destructuredOnlyField: aliased }) {
|
|||
export function appliesShorthand({ destructuredOnlyField }) {
|
||||
return destructuredOnlyField;
|
||||
}
|
||||
|
||||
// R2-1b: record CONSTRUCTION. Both of these SET `destructuredOnlyField` —
|
||||
// the nested-under-a-key form and the returned-literal form — and neither is
|
||||
// bound to a variable, so neither mints a definition.
|
||||
export function buildPlan(settings) {
|
||||
return {
|
||||
exitContract: {
|
||||
destructuredOnlyField: settings.raw ?? 0,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function buildFlat(settings) {
|
||||
return {
|
||||
destructuredOnlyField: settings.raw ?? 1,
|
||||
};
|
||||
}
|
||||
|
||||
// NEGATIVE CONTROL: an inline call-argument prop bag is call-site data, not a
|
||||
// record with a name attached, and must stay excluded exactly as it is for
|
||||
// definitions.
|
||||
function consume(bag) {
|
||||
return bag;
|
||||
}
|
||||
export const consumed = consume({ notAConstructedField: 3 });
|
||||
|
|
|
|||
|
|
@ -124,6 +124,36 @@ describe('JavaScript plain-object property access (A1/A5)', () => {
|
|||
});
|
||||
});
|
||||
|
||||
// R2-1b. The read side answered well while "who SETS this field?" missed the
|
||||
// code that stamps the value, because a record built inline is bound to no
|
||||
// variable and so mints no definition to point at.
|
||||
describe('record construction writes (R2-1b)', () => {
|
||||
const writersOf = (field: string): string[] =>
|
||||
getRelationships(result, 'ACCESSES')
|
||||
.filter((e) => e.target === field && (e.rel.reason ?? '').includes('write'))
|
||||
.map((e) => e.source);
|
||||
|
||||
it('emits a WRITE for a literal nested under a key', () => {
|
||||
expect(writersOf('destructuredOnlyField')).toContain('buildPlan');
|
||||
});
|
||||
|
||||
it('emits a WRITE for a returned literal', () => {
|
||||
expect(writersOf('destructuredOnlyField')).toContain('buildFlat');
|
||||
});
|
||||
|
||||
// The point of modelling these as writes rather than definitions: more
|
||||
// definitions would add same-named competitors to the narrowing that makes
|
||||
// these fields resolvable in the first place.
|
||||
it('mints NO new definition for a constructed record', () => {
|
||||
expect(propertyNames().filter((n) => n === 'destructuredOnlyField')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('leaves an inline call-argument prop bag alone', () => {
|
||||
expect(propertyNames()).not.toContain('notAConstructedField');
|
||||
expect(writersOf('notAConstructedField')).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
// R2. Strict workspace uniqueness was measurably too blunt: in the reporting
|
||||
// repo `exitMinAtrMult` had 26 definitions, 16 of them in one-off scripts the
|
||||
// backend has no relationship with, so every backend read was refused because
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue