Skip to content

Commit 3dd8965

Browse files
fix(minify): keep a call in place whose arguments read what its body declares
An argument reading a name the function's body declares would read the block's binding once moved into it. Also key the comment decisions by file, count a source's inline map against the choice limit, and restore the size choice switch a test turns off. Claude-Session: https://claude.ai/code/session_01ViD41i2KdwwGxrDk7yrjeD
1 parent 4ec906e commit 3dd8965

3 files changed

Lines changed: 21 additions & 9 deletions

File tree

‎lib/javascript/syntax-printer.js‎

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,7 @@ const NO_NODE = /** @type {Node} */ (/** @type {Node | null} */ (null));
974974
* @internal
975975
* @typedef {PrintNode} CommentedNode
976976
*/
977-
/** @typedef {{ type: "comment1" | "comment2" | "comment3" | "comment4", value: string, pos: number, line: number, col: number }} KeptComment a comment as a `comments` callback is handed it: terser's comment token, its offset, line from 1 and column from 0 */
977+
/** @typedef {{ type: "comment1" | "comment2" | "comment3" | "comment4", value: string, pos: number, line: number, col: number, file?: string }} KeptComment a comment as a `comments` callback is handed it: terser's comment token, its offset, line from 1 and column from 0, and the file it was read from */
978978
/** @typedef {(this: PrintNode, comment: Comment) => boolean} CommentFilter which comments are printed, `this` the node they are read off */
979979
/**
980980
* What the output stream reads off a node for comments, an ESTree node or a
@@ -20290,7 +20290,7 @@ const withCommentsDecidedOnce = (options) => {
2029020290
result[key] = {
2029120291
...group,
2029220292
comments: (node, comment) => {
20293-
const id = `${comment.type}:${comment.pos}:${comment.line}:${comment.col}:${comment.value}`;
20293+
const id = `${comment.file}:${comment.type}:${comment.pos}:${comment.line}:${comment.col}:${comment.value}`;
2029420294
let kept = decided.get(id);
2029520295
if (kept === undefined) {
2029620296
kept = callback(node, comment);
@@ -20319,7 +20319,7 @@ const withoutMapUrl = (text) => text.replace(MAP_URL_COMMENT, "");
2031920319
* @returns {number} their total length, or -1 unless a string, or an array or object of strings
2032020320
*/
2032120321
const sourceTextLength = (files) => {
20322-
if (typeof files === "string") return withoutMapUrl(files).length;
20322+
if (typeof files === "string") return files.length;
2032320323
const values = Array.isArray(files)
2032420324
? files
2032520325
: Object.getPrototypeOf(files) === Object.prototype
@@ -20328,7 +20328,7 @@ const sourceTextLength = (files) => {
2032820328
let length = values.length > 0 ? 0 : -1;
2032920329
for (const value of values) {
2033020330
if (typeof value !== "string") return -1;
20331-
length += withoutMapUrl(value).length;
20331+
length += value.length;
2033220332
}
2033320333
return length;
2033420334
};
@@ -21029,7 +21029,14 @@ const installImprove = (modules) => {
2102921029
}
2103021030
names.add(parameter.name);
2103121031
}
21032-
// A value naming a parameter would read the `let` in its dead zone,
21032+
// What the body declares the block declares, ahead of its `let`s.
21033+
A.walk(/** @type {Node} */ (fn.body), (/** @type {Node} */ node) => {
21034+
if (A.isSymbolDeclarationNode(node)) names.add(node.name);
21035+
if (!A.isLambdaNode(node)) return;
21036+
if (A.isDefunNode(node)) names.add(node.id.name);
21037+
return true;
21038+
});
21039+
// A value naming a parameter or one of those would read it there,
2103321040
// and a spread passes values to more than one.
2103421041
return !args.some(
2103521042
(/** @type {Node} */ value) =>

‎test/unitCases/javascript/printer.unittest.js‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9023,11 +9023,14 @@ describe("syntax-printer", () => {
90239023
for (const input of [
90249024
"var a = 8; (function (b, b) { b.toString(); })(--a, a |= 10); console.log(a);",
90259025
'var c = "FAIL"; (function (a, NaN) { switch (a) { case a: break; case (c = "PASS"), NaN: break; } })(NaN); console.log(c);',
9026-
"var values = [2, 3]; (function (large, e) { console.log(large, e); })({ large: 1 }, ...values);"
9026+
"var values = [2, 3]; (function (large, e) { console.log(large, e); })({ large: 1 }, ...values);",
9027+
"var x = 3; (function (a) { let x = String(a); console.log(a, x, x); })(x);",
9028+
"var g = 3; (function (a) { function g() {} console.log(a, typeof g, g.name); })(g);"
90279029
]) {
90289030
const { code } = await minify(input, { compress: { passes: 2 }, mangle: false });
90299031
expect(runProgram(/** @type {string} */ (code))).toBe(runProgram(input));
9030-
expect(code).not.toContain("{let");
9032+
// A block of `let`s opens a statement, where the function's body follows `)`.
9033+
expect(code).not.toMatch(/(^|[;}])\{let /);
90319034
}
90329035
});
90339036

@@ -12479,14 +12482,15 @@ const minifyCounted = async (input, options, fromTree) => {
1247912482
};
1248012483
treePrinting.enabled = fromTree;
1248112484
// One run, as choosing a spelling by size prints the program again.
12485+
const choseBySize = choosesBySize.enabled;
1248212486
choosesBySize.enabled = false;
1248312487
try {
1248412488
const { code, map } = await minify(input, options);
1248512489
return { code, map, printedFromTree };
1248612490
} finally {
1248712491
modules.printTree = printTree;
1248812492
treePrinting.enabled = true;
12489-
choosesBySize.enabled = true;
12493+
choosesBySize.enabled = choseBySize;
1249012494
}
1249112495
};
1249212496

‎types.d.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17985,14 +17985,15 @@ declare class JsonpTemplatePlugin {
1798517985
}
1798617986

1798717987
/**
17988-
* a comment as a `comments` callback is handed it: terser's comment token, its offset, line from 1 and column from 0
17988+
* a comment as a `comments` callback is handed it: terser's comment token, its offset, line from 1 and column from 0, and the file it was read from
1798917989
*/
1799017990
declare interface KeptComment {
1799117991
type: "comment1" | "comment2" | "comment3" | "comment4";
1799217992
value: string;
1799317993
pos: number;
1799417994
line: number;
1799517995
col: number;
17996+
file?: string;
1799617997
}
1799717998

1799817999
/**

0 commit comments

Comments
 (0)