mirror of
https://github.com/morluto/rea.git
synced 2026-10-26 17:35:11 +00:00
fix(javascript): resolve proven URL constructor aliases
Remove the redundant spelling gate after the shared intrinsic owner proves native constructor and source-base identity. Retain local-constructor and replaced-export uncertainty through public application analysis.
This commit is contained in:
1 parent
263a98c6ce
commit
37f24125ad
4 files changed
+49
-21
No files matched your search
@@ -427,6 +427,8 @@ member-mutation owners must establish the receiver before static API facts becom
|
||||
roles or storage observations. Path `join`, `resolve`, and `fileURLToPath` use
|
||||
proven Node imports; source-relative URL conversion additionally requires an
|
||||
unmodified global or proven Node `url.URL` constructor and `import.meta.url`.
|
||||
Native constructor aliases retain that identity; their local spelling does not
|
||||
determine URL semantics, and replaced exports or local constructors remain unknown.
|
||||
Relative results of native path operations retain filesystem-expression context;
|
||||
their spelling does not turn them into module specifiers. Other calls preserve
|
||||
their expressions. A property named `preload` outside a proven BrowserWindow
|
||||
|
||||
@@ -267,12 +267,6 @@ export interface JavaScriptStaticSourceUrlPath {
|
||||
readonly directory: boolean;
|
||||
}
|
||||
|
||||
/** Read a literal `new URL(relative, import.meta.url)` shape without evaluation. */
|
||||
export const staticSourceRelativeUrlPath = (
|
||||
node: t.Node,
|
||||
): JavaScriptStaticSourceUrlPath | undefined =>
|
||||
isSourceFileUrl(node) ? sourceRelativeFileUrlPath(node) : undefined;
|
||||
|
||||
/** Convert an exact static file URL expression to a POSIX path. */
|
||||
export const staticFileUrlPath = (
|
||||
node: t.CallExpression | t.NewExpression,
|
||||
@@ -282,8 +276,8 @@ export const staticFileUrlPath = (
|
||||
const rawArgument = argumentNode(node.arguments[0]);
|
||||
if (rawArgument === undefined) return undefined;
|
||||
const argument = unwrapJavaScriptExpression(rawArgument).node;
|
||||
if (isSourceFileUrl(argument) && pathIntrinsics?.(argument, "source-url"))
|
||||
return sourceRelativeFileUrlPath(argument)?.path;
|
||||
if (t.isNewExpression(argument) && pathIntrinsics?.(argument, "source-url"))
|
||||
return staticSourceRelativeUrlPath(argument)?.path;
|
||||
const value = staticPath(argument, pathIntrinsics);
|
||||
const rawPath = value?.split(/[?#]/u, 1)[0] ?? "";
|
||||
if (
|
||||
@@ -308,9 +302,9 @@ export const staticFileUrlPath = (
|
||||
}
|
||||
};
|
||||
|
||||
/** Project a known source-relative URL through the actual file URL decoder. */
|
||||
const sourceRelativeFileUrlPath = (
|
||||
node: t.CallExpression | t.NewExpression,
|
||||
/** Decode a source-relative URL after the caller proves constructor and base identity. */
|
||||
export const staticSourceRelativeUrlPath = (
|
||||
node: t.NewExpression,
|
||||
): JavaScriptStaticSourceUrlPath | undefined => {
|
||||
const value = stringValue(node.arguments[0]);
|
||||
if (
|
||||
@@ -350,14 +344,6 @@ const sourceRelativeFileUrlPath = (
|
||||
}
|
||||
};
|
||||
|
||||
const isSourceFileUrl = (
|
||||
node: t.Node,
|
||||
): node is t.CallExpression | t.NewExpression =>
|
||||
(t.isCallExpression(node) || t.isNewExpression(node)) &&
|
||||
(calleeName(node.callee) === "URL" ||
|
||||
calleeName(node.callee).endsWith(".URL")) &&
|
||||
isFileIdentity(argumentNode(node.arguments[1]));
|
||||
|
||||
const staticResolvedPath = (
|
||||
node: t.CallExpression | t.NewExpression,
|
||||
pathIntrinsics?: JavaScriptStaticPathIntrinsicQuery,
|
||||
|
||||
@@ -36,6 +36,42 @@ it.each([
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
[
|
||||
"named import",
|
||||
"import {URL as Constructor} from 'node:url';",
|
||||
"./native.js",
|
||||
],
|
||||
[
|
||||
"captured export",
|
||||
"import url from 'node:url'; const Constructor = url.URL;",
|
||||
"./native.js",
|
||||
],
|
||||
[
|
||||
"replaced export",
|
||||
"import url from 'node:url'; url.URL = class {}; const Constructor = url.URL;",
|
||||
null,
|
||||
],
|
||||
[
|
||||
"local constructor",
|
||||
"class Constructor {constructor(input, base) {return new globalThis.URL('./actual.js', base);}}",
|
||||
null,
|
||||
],
|
||||
] as const)(
|
||||
"uses the proven URL constructor identity for a %s alias",
|
||||
(_kind, declaration, expected) => {
|
||||
const analysis =
|
||||
analyzeJavaScriptStaticSource(`${windowPrefix}${declaration}
|
||||
new BrowserWindow({webPreferences:{preload:fileURLToPath(new Constructor('./native.js', import.meta.url))}});`);
|
||||
expect(analysis.electron.browser_windows).toMatchObject([
|
||||
{ preload_path: expected },
|
||||
]);
|
||||
expect(analysis.role_paths.map(({ path }) => path)).toEqual(
|
||||
expected === null ? [] : [expected],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
'["a", "b"].join("/")',
|
||||
'settings.join("/app", "preload.js")',
|
||||
|
||||
@@ -13,7 +13,7 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
|
||||
"package.json": JSON.stringify({ main: "main.mjs", type: "module" }),
|
||||
"main.mjs": `
|
||||
import {BrowserWindow as Win} from 'electron';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import {fileURLToPath, URL as NativeConstructor} from 'node:url';
|
||||
class URL {constructor(input, base) {return new globalThis.URL('./actual.js', base);}}
|
||||
const cache = {loadFile(value) {return value;}};
|
||||
cache.loadFile('data.json');
|
||||
@@ -22,11 +22,13 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
|
||||
globalThis.localStorage.setItem('real', 'value');
|
||||
const unrelated = {preload: './decoy.js'};
|
||||
new Win({webPreferences:{preload:fileURLToPath(new URL('./decoy.js', import.meta.url))}});
|
||||
new Win({webPreferences:{preload:fileURLToPath(new NativeConstructor('./native.js', import.meta.url))}});
|
||||
new Win({webPreferences:{preload:'./preload.js'}}).loadFile('index.html');
|
||||
`,
|
||||
"actual.js": "export {};",
|
||||
"decoy.js": "export {};",
|
||||
"preload.js": "export {};",
|
||||
"native.js": "export {};",
|
||||
"data.json": "{}",
|
||||
"index.html": "<!doctype html><title>Fixture</title>",
|
||||
});
|
||||
@@ -39,7 +41,9 @@ cliTest.for(["CLI", "stdio MCP"] as const)(
|
||||
roles.flatMap(({ observations }) =>
|
||||
observations.map(({ properties }) => properties.resolved_path),
|
||||
),
|
||||
).toEqual(expect.arrayContaining(["preload.js", "index.html"]));
|
||||
).toEqual(
|
||||
expect.arrayContaining(["preload.js", "native.js", "index.html"]),
|
||||
);
|
||||
expect(
|
||||
roles.flatMap(({ observations }) =>
|
||||
observations.map(({ properties }) => properties.resolved_path),
|
||||
|
||||
Reference in new issue
Block a user