* fix(javascript): resolve module-level Electron options in functions * fix(javascript): limit module option ancestry walk * fix(javascript): preserve uncertain captured argument ordering * fix(javascript): retain hoisted activation uncertainty * fix(javascript): retain function ownership through loops * fix(javascript): account for classic global activations * fix(javascript): bind first activations to lexical identities * fix(javascript): retain uncertain global activation timing * fix(javascript): isolate receiver facts and share computed reads * fix(javascript): retain projected and opaque global activations * fix(javascript): refresh activation bounds as opaque effects grow * fix(ci): format website watch directories without changing configuration * fix(javascript): share source reads across opaque-effect updates * fix(javascript): retain constructed-code global activation bounds * fix(javascript): share runtime activation and receiver facts * fix(javascript): reuse pattern reads and function positions * fix(javascript): isolate copied paths and preserve runtime reads * style(javascript): format migrated reference imports * fix(javascript): normalize constructor activation and receiver effects * fix(javascript): retain aliased receiver timing and lexical global this * fix(javascript): preserve effect-free receiver identity across activations * fix(javascript): retain outer activation and prototype effects * fix(javascript): index implicit reads without deep path rescans * fix(javascript): retain aliased prototype and parameter read uncertainty * fix(javascript): index reflected reads through intrinsic invocation facts * fix(javascript): retain unresolved global activation reads * chore: refresh PR branch after review fix publication * fix(javascript): retain projected receiver reads and cache method facts * fix(javascript): retain inherited and implicit activation reads * fix(javascript): retain caller-owned this uncertainty * fix(javascript): retain reflected reads with unresolved spread arguments * fix(javascript): preserve enclosing activation for decorators * fix(javascript): track intrinsic literal prototype effects * fix(javascript): retain catch activation from implicit reads * perf(javascript): reuse effective keys for projected reads * fix(javascript): retain possible caller-owned ambient effects
66 lines
2.3 KiB
TypeScript
66 lines
2.3 KiB
TypeScript
import * as t from "@babel/types";
|
|
import { unwrapJavaScriptExpression } from "./javascriptAstValues.js";
|
|
import { semanticBindingAtRead } from "./javascriptSemanticMutationInitializers.js";
|
|
import {
|
|
semanticStableInitializer,
|
|
type JavaScriptBindingIndex,
|
|
} from "./javascriptSemanticState.js";
|
|
|
|
/** Lexical candidates alone do not establish that object contents are intact. */
|
|
const optionObjectCandidate = (
|
|
input: t.Node | undefined,
|
|
index: JavaScriptBindingIndex,
|
|
):
|
|
| {
|
|
readonly object: t.ObjectExpression;
|
|
readonly references: readonly t.Identifier[];
|
|
}
|
|
| undefined => {
|
|
if (input === undefined) return undefined;
|
|
let node = unwrapJavaScriptExpression(input).node;
|
|
const seen = new Set<t.Node>();
|
|
const references: t.Identifier[] = [];
|
|
while (t.isIdentifier(node)) {
|
|
if (seen.has(node)) return undefined;
|
|
seen.add(node);
|
|
const binding = index.bindingForReferenceAt(node);
|
|
if (binding === undefined) return undefined;
|
|
const initializer = semanticStableInitializer(binding, index.bindings);
|
|
if (
|
|
binding.mutable ||
|
|
binding.declarationKinds.size !== 1 ||
|
|
!binding.declarationKinds.has("const") ||
|
|
initializer === undefined ||
|
|
initializer.projection.length !== 0 ||
|
|
!semanticBindingAtRead(binding, node, index.bindings)
|
|
.hasDefiniteInitializer
|
|
)
|
|
return undefined;
|
|
references.push(node);
|
|
node = unwrapJavaScriptExpression(initializer.node).node;
|
|
}
|
|
return t.isObjectExpression(node) ? { object: node, references } : undefined;
|
|
};
|
|
|
|
/** Avoid building mutation facts for parameters, missing or unresolved objects. */
|
|
export const hasElectronOptionObjectCandidate = (
|
|
input: t.Node | undefined,
|
|
index: JavaScriptBindingIndex,
|
|
): boolean => optionObjectCandidate(input, index) !== undefined;
|
|
|
|
/** Select an inert const object using the shared lexical and mutation owner. */
|
|
export const resolveElectronOptionObject = (
|
|
input: t.Node | undefined,
|
|
site: t.Node,
|
|
index: JavaScriptBindingIndex,
|
|
propertyPath: readonly string[] = [],
|
|
): t.ObjectExpression | undefined => {
|
|
const candidate = optionObjectCandidate(input, index);
|
|
if (candidate === undefined) return undefined;
|
|
for (const reference of candidate.references) {
|
|
if (index.referenceMayHaveChangedAt(site, reference, propertyPath))
|
|
return undefined;
|
|
}
|
|
return candidate.object;
|
|
};
|