mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
fix(javascript): retain assignment and nested-default destructuring
Share source identity and one iterative pattern walker across declarations and assignments. Traverse nested default targets without losing dependency paths, preserving existing scalar-default occurrence identities and conservative unresolved slots. Validation: 405 focused tests across five files, including public CLI dependency Evidence. Refs #4609, #4604
This commit is contained in:
@@ -65,7 +65,24 @@ export const collectJavaScriptSemanticObjects = (
|
||||
t.isVariableDeclarator(node) &&
|
||||
(t.isObjectPattern(node.id) || t.isArrayPattern(node.id))
|
||||
)
|
||||
collectDestructuring(node, ownerCallableId, state, output);
|
||||
collectDestructuring(
|
||||
node.id,
|
||||
node.init,
|
||||
ownerCallableId,
|
||||
state,
|
||||
output,
|
||||
);
|
||||
else if (
|
||||
t.isAssignmentExpression(node, { operator: "=" }) &&
|
||||
(t.isObjectPattern(node.left) || t.isArrayPattern(node.left))
|
||||
)
|
||||
collectDestructuring(
|
||||
node.left,
|
||||
node.right,
|
||||
ownerCallableId,
|
||||
state,
|
||||
output,
|
||||
);
|
||||
},
|
||||
exit: (node) => callableStack.exit(node),
|
||||
});
|
||||
@@ -126,46 +143,62 @@ const collectMember = (
|
||||
};
|
||||
|
||||
const collectDestructuring = (
|
||||
node: t.VariableDeclarator,
|
||||
root: t.Node,
|
||||
initializer: t.Node | null | undefined,
|
||||
ownerCallableId: string | null,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
output: JavaScriptSemanticObjectOperation[],
|
||||
): void => {
|
||||
const source = expressionObjectIdentity(node.init, state);
|
||||
const visit = (pattern: t.Node, path: readonly string[]): void => {
|
||||
const source = expressionObjectIdentity(initializer, state);
|
||||
const pending: {
|
||||
readonly pattern: t.Node;
|
||||
readonly path: readonly string[];
|
||||
}[] = [{ pattern: root, path: [] }];
|
||||
while (pending.length > 0) {
|
||||
const next = pending.pop();
|
||||
if (next === undefined) break;
|
||||
const { path } = next;
|
||||
const occurrence = unwrapJavaScriptExpression(next.pattern).node;
|
||||
const pattern = t.isAssignmentPattern(occurrence)
|
||||
? unwrapJavaScriptExpression(occurrence.left).node
|
||||
: occurrence;
|
||||
if (t.isObjectPattern(pattern)) {
|
||||
for (const property of pattern.properties) {
|
||||
for (const property of pattern.properties.toReversed()) {
|
||||
if (!t.isObjectProperty(property)) continue;
|
||||
const name = semanticStaticPropertyKey(property.key, property.computed);
|
||||
if (name !== null) visit(property.value, [...path, name]);
|
||||
if (name !== null)
|
||||
pending.push({ pattern: property.value, path: [...path, name] });
|
||||
}
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if (t.isArrayPattern(pattern)) {
|
||||
pattern.elements.forEach((element, index) => {
|
||||
if (element !== null && !t.isRestElement(element))
|
||||
visit(element, [...path, String(index)]);
|
||||
});
|
||||
return;
|
||||
for (let index = pattern.elements.length - 1; index >= 0; index -= 1) {
|
||||
const element = pattern.elements[index];
|
||||
if (
|
||||
element !== null &&
|
||||
element !== undefined &&
|
||||
!t.isRestElement(element)
|
||||
)
|
||||
pending.push({ pattern: element, path: [...path, String(index)] });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
const target = bindingIdentifier(pattern);
|
||||
if (target === null) return;
|
||||
if (!t.isIdentifier(pattern)) continue;
|
||||
addObjectOperation(
|
||||
{
|
||||
node: pattern,
|
||||
node: occurrence,
|
||||
kind: "destructure",
|
||||
ownerCallableId,
|
||||
objectBindingId: source.bindingId,
|
||||
targetBindingId:
|
||||
resolveSemanticBindingState(state, target, target.name)?.bindingId ??
|
||||
null,
|
||||
resolveSemanticBindingState(state, pattern, pattern.name)
|
||||
?.bindingId ?? null,
|
||||
propertyPath: source.path === null ? null : [...source.path, ...path],
|
||||
},
|
||||
state,
|
||||
output,
|
||||
);
|
||||
};
|
||||
visit(node.id, []);
|
||||
}
|
||||
};
|
||||
|
||||
interface AddObjectOperationInput {
|
||||
@@ -240,10 +273,3 @@ const expressionObjectIdentity = (
|
||||
path: staticPath ? path.reverse() : null,
|
||||
};
|
||||
};
|
||||
|
||||
const bindingIdentifier = (node: t.Node): t.Identifier | null => {
|
||||
if (t.isIdentifier(node)) return node;
|
||||
if (t.isAssignmentPattern(node) && t.isIdentifier(node.left))
|
||||
return node.left;
|
||||
return null;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user