mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
refactor(javascript): break the semantic analysis import cycle (#8063)
* refactor(javascript): break the semantic analysis import cycle Split shared semantic facts out of the analysis hub so projectors of effects, evaluation, and identity no longer import one another in a cycle. * refactor(javascript): share the import specifier reader Read static imports in one module used by the boundary checker and both cycle guards, so those rules cannot drift apart. --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
1 parent
940d71a45a
commit
249b90c5e3
33 files changed
+1043
-772
No files matched your search
@@ -10,16 +10,15 @@ import {
|
||||
} from "./javascriptElectronMemberWrites.js";
|
||||
import { createSemanticModuleInterop } from "./javascriptModuleInterop.js";
|
||||
import {
|
||||
isUnshadowedGlobal,
|
||||
resolveSemanticBindingState,
|
||||
semanticStableInitializer,
|
||||
type JavaScriptSemanticAnalysisState,
|
||||
} from "./javascriptSemanticState.js";
|
||||
import { isImportMetaUrl } from "./javascriptStaticAnalysisHelpers.js";
|
||||
import {
|
||||
isUnshadowedGlobal,
|
||||
semanticBindingAtRead,
|
||||
semanticEffectTiming,
|
||||
semanticDefiniteEffectPrecedesReference,
|
||||
semanticEffectTiming,
|
||||
} from "./javascriptSemanticMutationInitializers.js";
|
||||
import {
|
||||
semanticIterationSources,
|
||||
@@ -30,20 +29,24 @@ import {
|
||||
semanticPropertyPathKeyMatches,
|
||||
} from "./javascriptSemanticPropertyPaths.js";
|
||||
import { createSemanticReturnedReferences } from "./javascriptSemanticReturnedReferences.js";
|
||||
import { semanticRequireLoaderAt } from "./javascriptSemanticRequireOrigin.js";
|
||||
import {
|
||||
GLOBAL_OBJECT_NAMES,
|
||||
globalObjectName,
|
||||
globalReferenceNamespace,
|
||||
isUnmodifiedGlobalReference,
|
||||
isUnmodifiedImportMetaUrl,
|
||||
} from "./javascriptSemanticGlobalReference.js";
|
||||
import { readSemanticRequireLoader } from "./javascriptSemanticRequireOriginSlot.js";
|
||||
import {
|
||||
semanticCopiedReferencePath,
|
||||
semanticReferenceIterationUnknown,
|
||||
semanticReferenceSourcesInactive,
|
||||
} from "./javascriptSemanticReferenceSources.js";
|
||||
|
||||
const GLOBAL_OBJECT_NAMES = ["globalThis", "global", "window", "self"];
|
||||
|
||||
const globalObjectName = (
|
||||
node: t.Node,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): string | undefined =>
|
||||
GLOBAL_OBJECT_NAMES.find((name) => isUnshadowedGlobal(node, state, name));
|
||||
export {
|
||||
isUnmodifiedGlobalReference,
|
||||
isUnmodifiedImportMetaUrl,
|
||||
} from "./javascriptSemanticGlobalReference.js";
|
||||
|
||||
/** Global self references retain object identity, rather than adding a property. */
|
||||
const canonicalAmbientPath = (
|
||||
@@ -801,7 +804,7 @@ export function* indexJavaScriptAmbientWritesSteps(
|
||||
(t.isCallExpression(node) || t.isOptionalCallExpression(node)) &&
|
||||
!state.ambientWrites.covers(["global", "require", "resolve"]) &&
|
||||
!state.ambientEscapes.covers(["global", "require", "resolve"]) &&
|
||||
semanticRequireLoaderAt(node, state, new Set()) === "commonjs-loader"
|
||||
readSemanticRequireLoader(node, state, new Set()) === "commonjs-loader"
|
||||
)
|
||||
continue;
|
||||
retainEscapeEffect(effect);
|
||||
@@ -835,42 +838,6 @@ export function* indexJavaScriptAmbientWritesSteps(
|
||||
state.ambientEscapes.retain(["global", null]);
|
||||
}
|
||||
|
||||
/** Match lexical global identity; null denotes a direct global root. */
|
||||
const globalReferenceNamespace = (
|
||||
callee: t.Node,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
path: readonly [string, ...string[]],
|
||||
): string | null | undefined => {
|
||||
const { root, members } = electronMemberPath(callee);
|
||||
const matches = (expected: readonly string[]) =>
|
||||
members.length === expected.length &&
|
||||
members.every((key, index) => key === expected[index]);
|
||||
if (isUnshadowedGlobal(root, state, path[0]) && matches(path.slice(1)))
|
||||
return null;
|
||||
const namespace = globalObjectName(root, state);
|
||||
return namespace !== undefined && matches(path) ? namespace : undefined;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recognize an ambient property path, optionally through a global object, without a visible
|
||||
* source-local overwrite. This is a syntax-local identity fact, not proof that
|
||||
* the runtime's globals have never been patched by other code.
|
||||
*/
|
||||
export const isUnmodifiedGlobalReference = (
|
||||
callee: t.Node,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
name: string | readonly [string, ...string[]],
|
||||
): boolean => {
|
||||
const path: readonly [string, ...string[]] =
|
||||
typeof name === "string" ? [name] : name;
|
||||
if (state.ambientWrites.covers(["global", ...path])) return false;
|
||||
const namespace = globalReferenceNamespace(callee, state, path);
|
||||
return (
|
||||
namespace !== undefined &&
|
||||
(namespace === null || !state.ambientWrites.covers(["global", namespace]))
|
||||
);
|
||||
};
|
||||
|
||||
export type GlobalReferenceRead =
|
||||
| { readonly status: "unmodified" | "unrelated" | "unknown" }
|
||||
| { readonly status: "replacement"; readonly value: t.Expression };
|
||||
@@ -975,10 +942,3 @@ export const createGlobalReferenceReader = (
|
||||
return { status: "replacement", value: confirmed.right };
|
||||
};
|
||||
};
|
||||
|
||||
/** A module URL base is known only while its property has no visible write. */
|
||||
export const isUnmodifiedImportMetaUrl = (
|
||||
node: t.Node | undefined,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
): boolean =>
|
||||
isImportMetaUrl(node) && !state.ambientWrites.covers(["import-meta", "url"]);
|
||||
Reference in new issue
Block a user