Files
codegraph/__tests__/minified-call-targets.test.ts
Colby Mchenry e7be363f95 fix(js): no call resolves by name into a minified bundle (#2204)
A vendored minified script (`*.min.js`, or a script of a few enormous lines
- the same detection #2122 uses to rank them last) keeps mangled one-letter
names, so a name match from any other file is coincidence: healthchecks'
369 `$(...)` jQuery calls went to a helper inside bootstrap-native.min.js,
TestBox's popper.min.js to jquery.min.js internals, flaskbb's docs script
to its vendors bundle. Such files' symbols are no longer visible across
files by name; calls inside a bundle still resolve.

healthchecks -460, flaskbb -48, TestBox -36; bat, lodash, minimal-mistakes,
netbox, express, excalidraw unchanged.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 21:09:20 +00:00

48 lines
1.8 KiB
TypeScript

/**
* A vendored minified script's names are mangled, so no other file's call
* means one of them by name: healthchecks' 369 `$(…)` calls — jQuery, loaded
* as a global — went to a one-letter helper inside bootstrap-native.min.js.
* Detected by name (`*.min.js`) or by text (a few enormous lines).
*/
import { describe, it, expect, afterAll, beforeAll } from 'vitest';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { CodeGraph } from '../src';
let root = '';
let cg: CodeGraph;
beforeAll(async () => {
root = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-minified-'));
const bundle = `!function(){${Array.from({ length: 120 }, (_, i) => `function f${i}(e,t){return e+t+${i}}`).join(';')};function u(e){return f1(e,2)}}();\n`;
const files: Record<string, string> = {
'static/js/vendor.min.js': `function $(e){return document.querySelector(e)}function q(e){return $(e)}\n`,
'static/js/bundle.js': bundle.repeat(4),
'static/js/app.js': `function init() {
$("#edit-name").click(function () {});
u("x");
}
`,
};
for (const [rel, content] of Object.entries(files)) {
fs.mkdirSync(path.dirname(path.join(root, rel)), { recursive: true });
fs.writeFileSync(path.join(root, rel), content);
}
cg = await CodeGraph.init(root, { index: true });
});
afterAll(() => {
cg?.close();
if (root) fs.rmSync(root, { recursive: true, force: true });
});
describe('calls into minified scripts', () => {
it('never resolve by name from another file', () => {
const ids = cg.getNodesInFile('static/js/app.js').map((n) => n.id);
const targets = cg.getOutgoingEdgesFrom(ids).filter((e) => e.kind === 'calls').map((e) => cg.getNode(e.target)!.filePath);
expect(targets).not.toContain('static/js/vendor.min.js');
expect(targets).not.toContain('static/js/bundle.js');
});
});