fix(javascript): honor effective symbolic descriptor values (#7222)

Resolve ordered descriptor values at the shared JavaScript fact owner and preserve uncertain intrinsic writes instead of stale exports. Normalize ordinary method values and reuse canonical primitive, prototype, ambient identity and ordering facts across consumers.

384 selected tests, format/static/docs checks, all final CI jobs and reviews pass. Actual Node controls cover 35 bundles; one possibly repeated factory explicitly stays unknown. Shipped Obsidian selected-source complete Evidence matches base/fixed CLI and MCP, with coverage and resource measurements in the PR.

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
SII-YDDandgensokyo-dev authored and GitHub committed 2026-10-27 03:08:00 +08:00
1 parent d54f5b07b4
commit d4c511ae6e
12 files changed
+1117 -102

No files matched your search

@@ -1,11 +1,17 @@
import * as t from "@babel/types";
import {
staticObjectPropertyReader,
readExactJavaScriptLiteral,
isObjectPrototypeSetter,
objectDataPropertyValue,
semanticStaticPropertyKey,
semanticWriteSiteTarget,
semanticWriteTargets,
runtimeFunctionParameters,
unwrapJavaScriptExpression,
} from "./javascriptAstValues.js";
import { createSemanticExpressionShapeResolver } from "./javascriptSemanticExpressionShapes.js";
import { createGlobalReferenceReader } from "./javascriptSemanticAmbientWrites.js";
import { javascriptBootstrapAt } from "./javascriptBootstrap.js";
import { ELECTRON_MODULE } from "./javascriptElectronMemberWrites.js";
import {
@@ -60,14 +66,6 @@ interface SymbolicReadBoundary {
type SymbolicNamespace = Extract<SymbolicValue, { kind: "namespace" }>;
const emptyEnvironment: SymbolicEnvironment = { values: new Map() };
const isObjectPrototypeSetter = (
property: t.ObjectMethod | t.ObjectProperty,
name: string,
): boolean =>
t.isObjectProperty(property) &&
!property.computed &&
!property.shorthand &&
name === "__proto__";
const containsOwnedReturn = (root: t.Node): boolean => {
let found = false;
@@ -131,6 +129,11 @@ export class JavaScriptSymbolicBindings {
),
) {
this.#electronIdentity = electronIdentity;
const shapes = createSemanticExpressionShapeResolver(state);
const defineProperty = createGlobalReferenceReader(state, [
"Object",
"defineProperty",
]);
this.#indexBindingAliases();
traverseJavaScriptAst(program, {
enter: (node) => {
@@ -141,29 +144,49 @@ export class JavaScriptSymbolicBindings {
enter: (node) => {
const target = semanticWriteSiteTarget(node);
if (target !== null) this.#indexWriteSite(target, node);
if (
t.isCallExpression(node) &&
t.isMemberExpression(node.callee) &&
t.isIdentifier(node.callee.object, { name: "Object" }) &&
!resolveSemanticBindingState(state, node.callee.object, "Object") &&
semanticStaticPropertyKey(
node.callee.property,
node.callee.computed,
) === "defineProperty"
) {
if (t.isCallExpression(node) && t.isMemberExpression(node.callee)) {
const intrinsic = defineProperty(node.callee);
if (intrinsic.status === "unrelated") return;
const [target, key, descriptor] = node.arguments;
if (
t.isIdentifier(target) &&
t.isStringLiteral(key) &&
t.isObjectExpression(descriptor)
descriptor !== undefined
) {
const value = descriptor.properties.find(
(p) =>
t.isObjectProperty(p) &&
semanticStaticPropertyKey(p.key, p.computed) === "value",
if (intrinsic.status !== "unmodified") {
const replacement =
intrinsic.status === "replacement"
? unwrapJavaScriptExpression(intrinsic.value).node
: undefined;
const unchanged =
(t.isFunctionExpression(replacement) ||
t.isArrowFunctionExpression(replacement)) &&
(t.isBlockStatement(replacement.body)
? replacement.body.body.length === 0
: readExactJavaScriptLiteral(replacement.body).found) &&
runtimeFunctionParameters(replacement).every(
(parameter) =>
t.isIdentifier(parameter) ||
(t.isRestElement(parameter) &&
t.isIdentifier(parameter.argument)),
);
if (!unchanged) this.#addWrite(target, [key.value], node, node);
return;
}
const properties = staticObjectPropertyReader(
unwrapJavaScriptExpression(descriptor).node,
shapes.isNullish,
);
if (t.isObjectProperty(value))
const value = properties("value");
const hasAccessor =
properties("get").status !== "missing" ||
properties("set").status !== "missing";
if (value.status === "explicit" && !hasAccessor)
this.#addWrite(target, [key.value], value.value, node);
else if (value.status !== "missing" || hasAccessor)
// Unknown values, accessor replacements and invalid mixed
// descriptors cannot preserve an earlier data export.
this.#addWrite(target, [key.value], node, node);
}
}
},
@@ -387,7 +410,7 @@ export class JavaScriptSymbolicBindings {
(candidate): candidate is t.ObjectMethod | t.ObjectProperty =>
!t.isSpreadElement(candidate),
)
.find((candidate) => isObjectPrototypeSetter(candidate, key));
.find((candidate) => isObjectPrototypeSetter(candidate));
if (prototypeSetter !== undefined)
return this.#objectPropertyValue(
prototypeSetter,
@@ -431,12 +454,10 @@ export class JavaScriptSymbolicBindings {
property: t.ObjectMethod | t.ObjectProperty,
environment: SymbolicEnvironment,
): SymbolicValue {
return t.isObjectMethod(property) && property.kind !== "method"
const value = objectDataPropertyValue(property);
return value === undefined
? symbolicUnknown("accessor property")
: this.evaluate(
t.isObjectProperty(property) ? property.value : property,
environment,
);
: this.evaluate(value, environment);
}
members(