fix(javascript): bind bundle exports and mutations to factory roles

This commit is contained in:
morluto committed 2026-10-24 02:29:44 +08:00
1 parent 1998640669
commit 5cbcd58550
7 files changed
+234 -62

No files matched your search

@@ -8,7 +8,7 @@ import {
type JavaScriptSemanticAnalysisState,
} from "./javascriptSemanticState.js";
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
import { argumentValue } from "./javascriptStaticAnalysisHelpers.js";
import { evaluateSemanticExpression } from "./javascriptSemanticValues.js";
type Bootstrap = NonNullable<ReturnType<typeof javascriptBootstrapAt>>;
@@ -452,7 +452,7 @@ const referencesAreContained = (
const use: Use = { node, parent, ancestors, shape, loaderIds, state };
if (role !== "loader") contained = containedUse(role, use);
else if (exposedTableUse(use) === "escaped") contained = false;
else exposedSlotWrite(use, replacedKeys);
else contained = exposedSlotWrite(use, replacedKeys);
},
});
return contained ? { replacedKeys } : undefined;
@@ -522,13 +522,9 @@ const exposedTableUse = (use: Use): "other" | "contained" | "escaped" => {
return entryWritten ? "escaped" : "contained";
};
/**
* `loader.m[key] = factory` or `delete loader.c[key]` replaces a literal slot.
* Writes with runtime keys are chunk installation, which adds modules under
* their own ids; they are not treated as replacing a declared slot.
*/
const exposedSlotWrite = (use: Use, replacedKeys: Set<string>): void => {
const { parent, ancestors } = use;
/** Unknown computed writes may replace any existing slot; fresh installation is unproven. */
const exposedSlotWrite = (use: Use, replacedKeys: Set<string>): boolean => {
const { parent, ancestors, state } = use;
const slot = ancestors.at(-2);
const write = ancestors.at(-3);
if (
@@ -545,11 +541,21 @@ const exposedSlotWrite = (use: Use, replacedKeys: Set<string>): void => {
t.isUpdateExpression(write)
)
)
return;
const key = slot.computed
? argumentValue(slot.property)
: semanticStaticPropertyKey(slot.property, false);
if (key !== undefined && key !== null) replacedKeys.add(key);
return true;
if (!slot.computed) {
const key = semanticStaticPropertyKey(slot.property, false);
if (key === null) return false;
replacedKeys.add(key);
return true;
}
const key = evaluateSemanticExpression(slot.property, state);
if (
key.status !== "literal" ||
(typeof key.value !== "string" && typeof key.value !== "number")
)
return false;
replacedKeys.add(String(key.value));
return true;
};
const bindingOf = (