Files
reverse-engineering-anything/src/domain/javascript/javascriptStaticAnalysisModuleIndex.test.ts
T
morluto 5ab0cbb48e fix(javascript): resolve bundled exports by binding identity
Identify the factory exports parameter through the existing semantic binding owner, including renamed and minified Webpack parameters. Reject nested targets, bare alias rebinding, and shadowed identifiers. Prune the duplicated source happy path after validating the public CLI workflow.

Validation: public analyze-javascript-application CLI acceptance and focused semantic traversal/module-index tests.

Fixes #2171
2026-10-13 04:12:14 +08:00

213 lines
7.0 KiB
TypeScript

import { expect, it } from "vitest";
import { JavaScriptModuleRangeIndex } from "./javascriptStaticAnalysisFindings.js";
import { analyzeJavaScriptStaticSource } from "./javascriptStaticAnalysis.js";
it.each(["direct", "call"])(
"recovers standalone module factories dispatched with %s",
(style) => {
const dispatch =
style === "call"
? "modules[id].call(module.exports, module, module.exports, load)"
: "modules[id](module, module.exports, load)";
const source = `(() => {
const modules = {
17(module, exports, req) { exports.read = req(23); },
23(module) { module.exports = require("electron"); }
};
const cache = {};
function load(id) {
if (cache[id]) return cache[id].exports;
const module = cache[id] = { exports: {} };
${dispatch};
return module.exports;
}
load(17);
})();`;
const analysis = analyzeJavaScriptStaticSource(source);
expect(analysis.bundler_registrations).toMatchObject([
{
bundler: "webpack",
entry_module_keys: ["17"],
modules: [{ module_key: "17" }, { module_key: "23" }],
},
]);
expect(analysis.references).toEqual(
expect.arrayContaining([
expect.objectContaining({ specifier: "23", module_key: "17" }),
expect.objectContaining({ specifier: "electron", module_key: "23" }),
]),
);
},
);
it("does not infer a bootstrap from a function table without a matching loader", () => {
const analysis = analyzeJavaScriptStaticSource(`(() => {
const handlers = { 17(module) { module.exports = require("electron"); } };
function load(id) { return handlers[id](userInput); }
load(17);
})();`);
expect(analysis.bundler_registrations).toEqual([]);
});
it("does not treat a same-named shadow as the factory exports parameter", () => {
const analysis =
analyzeJavaScriptStaticSource(`globalThis.webpackChunkApp.push([[1], {
first(module, e, require) {
{ const e = {}; require.d(e, { shadowed: () => 1 }); e.other = 2; }
}
}]);`);
expect(analysis.bundler_registrations[0]?.modules).toMatchObject([
{ module_key: "first", exports: [] },
]);
});
it("does not confuse a shadowed dispatch table with the outer module table", () => {
const analysis = analyzeJavaScriptStaticSource(`(() => {
const modules = { 17(module) { module.exports = require("electron"); } };
function load(id) {
const modules = userInput;
const module = { exports: {} };
modules[id](module, module.exports, load);
return module.exports;
}
load(17);
})();`);
expect(analysis.bundler_registrations).toEqual([]);
});
it("retains a stable var module table without treating declaration mutability as a write", () => {
const analysis = analyzeJavaScriptStaticSource(`(() => {
var modules = { 17(module) { module.exports = require("electron"); } };
function load(id) {
const module = { exports: {} };
modules[id](module, module.exports, load);
return module.exports;
}
load(17);
})();`);
expect(analysis.bundler_registrations).toMatchObject([
{ entry_module_keys: ["17"], modules: [{ module_key: "17" }] },
]);
});
it("only attributes bootstrap entries to the recovered loader binding", () => {
const analysis = analyzeJavaScriptStaticSource(`(() => {
const modules = { 17(module) { module.exports = require("electron"); } };
function load(id) {
const module = { exports: {} };
modules[id](module, module.exports, load);
return module.exports;
}
{ const load = userInput; load(99); }
load(17);
})();`);
expect(analysis.bundler_registrations).toMatchObject([
{ entry_module_keys: ["17"] },
]);
});
it("preserves first insertion precedence and inclusive interval bounds", () => {
const nested = new JavaScriptModuleRangeIndex(100);
expect(nested.find(0)).toBeUndefined();
nested.add({
start: 10,
end: 90,
key: "outer-first",
runtime: "webpackChunkApp",
requireName: null,
});
nested.add({
start: 20,
end: 30,
key: "inner-second",
runtime: "webpackChunkApp",
requireName: null,
});
nested.add({
start: 30,
end: 40,
key: "later-overlap",
runtime: "webpackChunkApp",
requireName: null,
});
expect(nested.find(9)).toBeUndefined();
expect(nested.find(10)?.key).toBe("outer-first");
expect(nested.find(20)?.key).toBe("outer-first");
expect(nested.find(30)?.key).toBe("outer-first");
expect(nested.find(90)?.key).toBe("outer-first");
expect(nested.find(91)).toBeUndefined();
expect(nested.find(100)).toBeUndefined();
});
it("rejects missing and out-of-range lookup offsets", () => {
const index = new JavaScriptModuleRangeIndex(20);
index.add({
start: 5,
end: 10,
key: "bounded",
runtime: "webpackChunkApp",
requireName: null,
});
expect(index.find(undefined)).toBeUndefined();
expect(index.find(null)).toBeUndefined();
expect(index.find(-1)).toBeUndefined();
expect(index.find(0)).toBeUndefined();
expect(index.find(11)).toBeUndefined();
expect(index.find(20)).toBeUndefined();
expect(index.find(Number.NaN)).toBeUndefined();
expect(index.find(5)?.key).toBe("bounded");
expect(index.find(10)?.key).toBe("bounded");
});
it("keeps module references attributed across many real factory ranges", () => {
const count = 200;
const factories = Array.from({ length: count }, (_, index) =>
index === 0
? '"module-0": function(module, exports, req) { globalThis.webpackChunkInner.push([[2], { "inner": function(innerModule, innerExports, req) { req("nested-dependency"); } }]); req("dependency-0"); }'
: `"module-${index}": function(module, exports, req) { req("dependency-${index}"); }`,
).join(",\n");
const analysis = analyzeJavaScriptStaticSource(
`require("outside");\nglobalThis.webpackChunkApp.push([[1], {\n${factories}\n}]);`,
);
expect(analysis.references).toHaveLength(count + 2);
expect(
analysis.bundler_registrations.some(
({ runtime, modules }) =>
runtime === "webpackChunkInner" &&
modules.some(({ module_key }) => module_key === "inner"),
),
).toBe(true);
expect(
analysis.references.find(({ specifier }) => specifier === "outside")
?.module_key,
).toBeNull();
for (let index = 0; index < count; index += 1) {
expect(
analysis.references.find(
({ specifier }) => specifier === `dependency-${index}`,
),
).toMatchObject({
module_key: `module-${index}`,
module_runtime: "webpackChunkApp",
});
}
expect(
analysis.references.find(
({ specifier }) => specifier === "nested-dependency",
)?.module_key,
).toBe("module-0");
});
it("retains the chunk runtime through a TypeScript-only expression wrapper", () => {
const analysis = analyzeJavaScriptStaticSource(
'(globalThis.webpackChunkApp satisfies unknown).push([[1], { "entry": function () {} }]);',
);
expect(analysis.bundler_registrations).toEqual([
expect.objectContaining({
runtime: "webpackChunkApp",
modules: [expect.objectContaining({ module_key: "entry" })],
}),
]);
});