mirror of
https://github.com/morluto/rea.git
synced 2026-11-15 11:13:21 +00:00
fix(javascript): follow Electron through aliases of Webpack externals
General provenance only knew a literal require, so a bundled Electron
external held in one binding and destructured from another
(`const s=n(K);const{BrowserWindow}=s`) lost its windows and IPC. The
Electron binding origin now follows stable lexical aliases, and stops at
a rebindable binding that direct eval may have changed.
Fixes #4490
Supersedes #6993
Squashed from #6993 and rebased onto main. Rebase adaptation: the walk
uses the caller-selectable precision.alias_selections budget (the fixed
SEMANTIC_ALIAS_SELECTION_LIMIT it used was removed by #9706) and records
alias-selections when it stops there; a test pins that an over-budget
chain is not claimed and the limit is reported.
Co-Authored-By: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
1 parent
3a25046b8c
commit
f99d73bf39
3 files changed
+131
-1
No files matched your search
@@ -9,6 +9,7 @@ import {
|
||||
semanticOpaqueBindingEffects,
|
||||
semanticBindingCanBeRebound,
|
||||
semanticOpaqueBindingReadMayHaveChanged,
|
||||
semanticBindingMayHaveOpaqueEffect,
|
||||
} from "./javascriptSemanticOpaqueEffects.js";
|
||||
import type { JavaScriptOpenReceiverFact } from "./javascriptSemanticReceiverFacts.js";
|
||||
import * as t from "@babel/types";
|
||||
@@ -1138,9 +1139,16 @@ const electronRequireOrigin = (
|
||||
semanticRequireOrigin(node, state) ??
|
||||
semanticBundledRequireOrigin(node, state);
|
||||
|
||||
/**
|
||||
* General provenance only knows literal `require`, so a bundled external held
|
||||
* in one binding and destructured from another (`const s=n(K);const{X}=s`)
|
||||
* is followed here through stable lexical aliases. Like provenance, a hop
|
||||
* stops at a rebindable binding that direct eval may have changed.
|
||||
*/
|
||||
const bindingOrigin = (
|
||||
binding: JavaScriptSemanticBindingState,
|
||||
state: JavaScriptSemanticAnalysisState,
|
||||
visited: ReadonlySet<string> = new Set(),
|
||||
): JavaScriptModuleOrigin | undefined => {
|
||||
if (binding.directOrigins.length > 0)
|
||||
return binding.directOrigins.length === 1
|
||||
@@ -1148,7 +1156,29 @@ const bindingOrigin = (
|
||||
: undefined;
|
||||
const initializer = semanticStableInitializer(binding, state);
|
||||
if (initializer === undefined) return undefined;
|
||||
const origin = electronRequireOrigin(initializer.node, state)?.origin;
|
||||
const source = unwrapJavaScriptExpression(initializer.node).node;
|
||||
const alias =
|
||||
t.isIdentifier(source) &&
|
||||
!semanticResolutionBlocked(state, source, source.name)
|
||||
? resolveSemanticBindingState(state, source, source.name)
|
||||
: undefined;
|
||||
// The alias walk shares the caller-selectable alias budget; running out is a
|
||||
// reported resource limit, not a silent absence of the origin.
|
||||
const exhausted =
|
||||
alias !== undefined && visited.size >= state.precision.alias_selections;
|
||||
if (exhausted) state.valueResourceLimits.add("alias-selections");
|
||||
const origin =
|
||||
alias === undefined
|
||||
? electronRequireOrigin(initializer.node, state)?.origin
|
||||
: visited.has(alias.bindingId) ||
|
||||
exhausted ||
|
||||
[binding, alias].some(
|
||||
(hop) =>
|
||||
semanticBindingCanBeRebound(hop) &&
|
||||
semanticBindingMayHaveOpaqueEffect(hop, state),
|
||||
)
|
||||
? undefined
|
||||
: bindingOrigin(alias, state, new Set([...visited, binding.bindingId]));
|
||||
const projection = initializer.projection;
|
||||
return origin === undefined ||
|
||||
!projection.every((key): key is string => typeof key === "string")
|
||||
|
||||
Reference in new issue
Block a user