mirror of
https://github.com/morluto/rea
synced 2026-10-27 14:42:18 -04:00
fix(javascript): trace wrapped Electron IPC paths in large bundles (#1874)
Co-authored-by: David <17119984+fengdwx@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
import * as t from "@babel/types";
|
||||
|
||||
import { semanticStaticPropertyKey } from "./javascriptAstValues.js";
|
||||
import { moduleFactory } from "./javascriptStaticAnalysisHelpers.js";
|
||||
import { traverseJavaScriptAst } from "./javascriptSemanticTraversal.js";
|
||||
|
||||
/** A literal module table dispatched by a standalone CommonJS-style runtime. */
|
||||
interface JavaScriptBootstrap {
|
||||
readonly body: t.BlockStatement;
|
||||
readonly table: t.ObjectExpression;
|
||||
readonly loaderName: string;
|
||||
}
|
||||
|
||||
/** Recognize syntax, never invoke a bootstrap or infer it from variable names. */
|
||||
export const javascriptBootstrapAt = (
|
||||
call: t.CallExpression,
|
||||
): JavaScriptBootstrap | undefined => {
|
||||
if (
|
||||
(!t.isFunctionExpression(call.callee) &&
|
||||
!t.isArrowFunctionExpression(call.callee)) ||
|
||||
!t.isBlockStatement(call.callee.body) ||
|
||||
call.callee.params.length !== 0 ||
|
||||
call.arguments.length !== 0
|
||||
)
|
||||
return undefined;
|
||||
const body = call.callee.body;
|
||||
const tables = new Map<string, t.ObjectExpression>();
|
||||
for (const statement of body.body) {
|
||||
if (!t.isVariableDeclaration(statement)) continue;
|
||||
for (const declaration of statement.declarations) {
|
||||
if (
|
||||
t.isIdentifier(declaration.id) &&
|
||||
t.isObjectExpression(declaration.init) &&
|
||||
declaration.init.properties.length > 0 &&
|
||||
declaration.init.properties.every(
|
||||
(property) => moduleFactory(property) !== undefined,
|
||||
)
|
||||
)
|
||||
tables.set(declaration.id.name, declaration.init);
|
||||
}
|
||||
}
|
||||
if (tables.size === 0) return undefined;
|
||||
for (const loader of body.body) {
|
||||
if (
|
||||
!t.isFunctionDeclaration(loader) ||
|
||||
loader.id === null ||
|
||||
loader.id === undefined ||
|
||||
loader.params.length !== 1
|
||||
)
|
||||
continue;
|
||||
const parameter = loader.params[0];
|
||||
if (!t.isIdentifier(parameter)) continue;
|
||||
const loaderName = loader.id.name;
|
||||
let tableName: string | undefined;
|
||||
traverseJavaScriptAst(loader.body, {
|
||||
enter: (node, _parent, ancestors) => {
|
||||
if (
|
||||
!t.isCallExpression(node) ||
|
||||
ancestors().some((node) => t.isFunction(node))
|
||||
)
|
||||
return;
|
||||
const candidate = dispatchedTableName(node, loaderName, parameter.name);
|
||||
if (candidate !== undefined && tables.has(candidate))
|
||||
tableName = candidate;
|
||||
},
|
||||
});
|
||||
const table = tableName === undefined ? undefined : tables.get(tableName);
|
||||
if (table !== undefined && tableName !== undefined)
|
||||
return { body, table, loaderName };
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const dispatchedTableName = (
|
||||
call: t.CallExpression,
|
||||
loaderName: string,
|
||||
keyName: string,
|
||||
): string | undefined => {
|
||||
const member = call.callee;
|
||||
const viaCall =
|
||||
t.isMemberExpression(member) &&
|
||||
semanticStaticPropertyKey(member.property, member.computed) === "call";
|
||||
const dispatch =
|
||||
viaCall && t.isMemberExpression(member) ? member.object : member;
|
||||
if (
|
||||
!t.isMemberExpression(dispatch) ||
|
||||
!dispatch.computed ||
|
||||
!t.isIdentifier(dispatch.object) ||
|
||||
!t.isIdentifier(dispatch.property, { name: keyName })
|
||||
)
|
||||
return undefined;
|
||||
const args = viaCall ? call.arguments.slice(1) : call.arguments;
|
||||
const [module, exports, require] = args;
|
||||
if (
|
||||
args.length !== 3 ||
|
||||
!t.isIdentifier(module) ||
|
||||
!t.isMemberExpression(exports) ||
|
||||
!t.isIdentifier(exports.object, { name: module.name }) ||
|
||||
semanticStaticPropertyKey(exports.property, exports.computed) !==
|
||||
"exports" ||
|
||||
!t.isIdentifier(require, { name: loaderName })
|
||||
)
|
||||
return undefined;
|
||||
if (
|
||||
viaCall &&
|
||||
(!t.isNode(call.arguments[0]) ||
|
||||
!t.isNodesEquivalent(call.arguments[0], exports))
|
||||
)
|
||||
return undefined;
|
||||
return dispatch.object.name;
|
||||
};
|
||||
Reference in New Issue
Block a user