miniread 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scripts/evaluate/parse-transform-manifest.d.ts +1 -1
- package/dist/scripts/evaluate/parse-transform-manifest.js +1 -1
- package/dist/scripts/evaluate/transform-manifest.js +1 -1
- package/dist/transforms/expand-special-number-literals/expand-special-number-literals-transform.d.ts +2 -0
- package/dist/transforms/expand-special-number-literals/expand-special-number-literals-transform.js +139 -0
- package/dist/transforms/rename-binding/get-target-name.d.ts +4 -0
- package/dist/transforms/rename-binding/get-target-name.js +25 -0
- package/dist/transforms/rename-binding/is-valid-binding-identifier.d.ts +1 -0
- package/dist/transforms/rename-binding/is-valid-binding-identifier.js +10 -0
- package/dist/transforms/rename-timeout-ids/rename-timeout-ids-transform.d.ts +2 -0
- package/dist/transforms/rename-timeout-ids/rename-timeout-ids-transform.js +86 -0
- package/dist/transforms/transform-presets.js +2 -2
- package/dist/transforms/transform-registry.js +4 -0
- package/package.json +1 -1
- package/transform-manifest.json +33 -13
|
@@ -6,7 +6,7 @@ const TransformManifestEntrySchema = z
|
|
|
6
6
|
scope: z.union([z.literal("file"), z.literal("project")]),
|
|
7
7
|
parallelizable: z.boolean(),
|
|
8
8
|
diffReductionImpact: z.number(),
|
|
9
|
-
|
|
9
|
+
recommended: z.boolean(),
|
|
10
10
|
evaluatedAt: z.iso.datetime().optional(),
|
|
11
11
|
notes: z.string().optional(),
|
|
12
12
|
supersededBy: z.string().min(1).optional(),
|
|
@@ -45,7 +45,7 @@ export const updateTransformManifestFromEvaluation = async (options) => {
|
|
|
45
45
|
}
|
|
46
46
|
if (isBaselineNone) {
|
|
47
47
|
const recommendedIds = manifest.transforms
|
|
48
|
-
.filter((entry) => entry.
|
|
48
|
+
.filter((entry) => entry.recommended)
|
|
49
49
|
.map((entry) => entry.id);
|
|
50
50
|
const testUniqueIds = uniqueIds(testIds);
|
|
51
51
|
const recommendedUniqueIds = uniqueIds(recommendedIds);
|
package/dist/transforms/expand-special-number-literals/expand-special-number-literals-transform.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
4
|
+
const traverse = require("@babel/traverse").default;
|
|
5
|
+
const t = require("@babel/types");
|
|
6
|
+
const directEvalCache = new WeakMap();
|
|
7
|
+
const containsDirectEval = (container) => {
|
|
8
|
+
const cached = directEvalCache.get(container.node);
|
|
9
|
+
if (cached !== undefined)
|
|
10
|
+
return cached;
|
|
11
|
+
let found = false;
|
|
12
|
+
container.traverse({
|
|
13
|
+
CallExpression(callPath) {
|
|
14
|
+
if (callPath.node.callee.type !== "Identifier")
|
|
15
|
+
return;
|
|
16
|
+
if (callPath.node.callee.name !== "eval")
|
|
17
|
+
return;
|
|
18
|
+
// We only care about direct eval in sloppy mode because it can introduce `var`
|
|
19
|
+
// bindings into the current function scope (which could shadow `Infinity`/`NaN`
|
|
20
|
+
// and change the meaning of an identifier replacement).
|
|
21
|
+
//
|
|
22
|
+
// Note: Even if `eval` is lexically shadowed, we can't reliably prove statically
|
|
23
|
+
// that it's not bound to the built-in eval at runtime (e.g. `const eval =
|
|
24
|
+
// globalThis.eval`). Be conservative and treat any `eval(...)` call as direct.
|
|
25
|
+
found = true;
|
|
26
|
+
callPath.stop();
|
|
27
|
+
},
|
|
28
|
+
Function(functionPath) {
|
|
29
|
+
if (functionPath.node === container.node)
|
|
30
|
+
return;
|
|
31
|
+
functionPath.skip();
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
directEvalCache.set(container.node, found);
|
|
35
|
+
return found;
|
|
36
|
+
};
|
|
37
|
+
const isWithinWithStatement = (path) => {
|
|
38
|
+
return Boolean(path.findParent((p) => p.isWithStatement()));
|
|
39
|
+
};
|
|
40
|
+
const isWithinSloppyDirectEvalScope = (path) => {
|
|
41
|
+
for (let functionPath = path.getFunctionParent(); functionPath; functionPath = functionPath.getFunctionParent()) {
|
|
42
|
+
if (functionPath.isInStrictMode())
|
|
43
|
+
continue;
|
|
44
|
+
if (containsDirectEval(functionPath))
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
const programPath = path.scope.getProgramParent().path;
|
|
48
|
+
if (!programPath.isInStrictMode() && containsDirectEval(programPath)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
return false;
|
|
52
|
+
};
|
|
53
|
+
const isDivisionByZero = (value) => {
|
|
54
|
+
return value === 0 || Object.is(value, -0);
|
|
55
|
+
};
|
|
56
|
+
export const expandSpecialNumberLiteralsTransform = {
|
|
57
|
+
id: "expand-special-number-literals",
|
|
58
|
+
description: "Expands 1/0 to Infinity, -1/0 (and 1/-0) to -Infinity, and 0/0 to NaN (when not shadowed)",
|
|
59
|
+
scope: "file",
|
|
60
|
+
parallelizable: true,
|
|
61
|
+
transform(context) {
|
|
62
|
+
const { projectGraph } = context;
|
|
63
|
+
let nodesVisited = 0;
|
|
64
|
+
let transformationsApplied = 0;
|
|
65
|
+
for (const [, fileInfo] of projectGraph.files) {
|
|
66
|
+
traverse(fileInfo.ast, {
|
|
67
|
+
BinaryExpression(path) {
|
|
68
|
+
nodesVisited++;
|
|
69
|
+
const { operator, left } = path.node;
|
|
70
|
+
if (operator !== "/")
|
|
71
|
+
return;
|
|
72
|
+
// Babel types allow `PrivateName` as a BinaryExpression operand for `#x in obj`
|
|
73
|
+
// brand checks (operator `in`). This guard is just to satisfy the type system.
|
|
74
|
+
if (left.type === "PrivateName")
|
|
75
|
+
return;
|
|
76
|
+
const leftPath = path.get("left");
|
|
77
|
+
const rightPath = path.get("right");
|
|
78
|
+
// Avoid dropping side effects: `evaluate()` can be confident for expressions that
|
|
79
|
+
// are not pure (e.g. `(foo(), 1) / 0`). Only rewrite when both sides are pure.
|
|
80
|
+
if (!leftPath.isPure() || !rightPath.isPure())
|
|
81
|
+
return;
|
|
82
|
+
const leftEvaluation = leftPath.evaluate();
|
|
83
|
+
if (!leftEvaluation.confident)
|
|
84
|
+
return;
|
|
85
|
+
if (typeof leftEvaluation.value !== "number")
|
|
86
|
+
return;
|
|
87
|
+
const leftValue = leftEvaluation.value;
|
|
88
|
+
const rightEvaluation = rightPath.evaluate();
|
|
89
|
+
if (!rightEvaluation.confident)
|
|
90
|
+
return;
|
|
91
|
+
if (typeof rightEvaluation.value !== "number")
|
|
92
|
+
return;
|
|
93
|
+
const rightValue = rightEvaluation.value;
|
|
94
|
+
if (!isDivisionByZero(rightValue))
|
|
95
|
+
return;
|
|
96
|
+
const result = leftValue / rightValue;
|
|
97
|
+
if (Number.isNaN(result)) {
|
|
98
|
+
// `0/0` is unaffected by dynamic scope, but `NaN` can be shadowed via `with` and
|
|
99
|
+
// sloppy direct `eval()` in this scope or any enclosing scope.
|
|
100
|
+
if (isWithinWithStatement(path))
|
|
101
|
+
return;
|
|
102
|
+
if (isWithinSloppyDirectEvalScope(path))
|
|
103
|
+
return;
|
|
104
|
+
if (path.scope.hasBinding("NaN", true))
|
|
105
|
+
return;
|
|
106
|
+
path.replaceWith(t.identifier("NaN"));
|
|
107
|
+
transformationsApplied++;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (result === Infinity) {
|
|
111
|
+
// `1/0` is unaffected by dynamic scope, but `Infinity` can be shadowed via `with` and
|
|
112
|
+
// sloppy direct `eval()` in this scope or any enclosing scope.
|
|
113
|
+
if (isWithinWithStatement(path))
|
|
114
|
+
return;
|
|
115
|
+
if (isWithinSloppyDirectEvalScope(path))
|
|
116
|
+
return;
|
|
117
|
+
if (path.scope.hasBinding("Infinity", true))
|
|
118
|
+
return;
|
|
119
|
+
path.replaceWith(t.identifier("Infinity"));
|
|
120
|
+
transformationsApplied++;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
if (result === -Infinity) {
|
|
124
|
+
if (isWithinWithStatement(path))
|
|
125
|
+
return;
|
|
126
|
+
if (isWithinSloppyDirectEvalScope(path))
|
|
127
|
+
return;
|
|
128
|
+
if (path.scope.hasBinding("Infinity", true))
|
|
129
|
+
return;
|
|
130
|
+
path.replaceWith(t.unaryExpression("-", t.identifier("Infinity")));
|
|
131
|
+
transformationsApplied++;
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return Promise.resolve({ nodesVisited, transformationsApplied });
|
|
138
|
+
},
|
|
139
|
+
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { isValidBindingIdentifier } from "./is-valid-binding-identifier.js";
|
|
2
|
+
// Cap retries to avoid pathological loops while handling large bundles.
|
|
3
|
+
const MAX_CANDIDATES = 1000;
|
|
4
|
+
export const getTargetName = (bindingScope, binding, options) => {
|
|
5
|
+
const { baseName } = options;
|
|
6
|
+
if (baseName.length === 0)
|
|
7
|
+
return;
|
|
8
|
+
const programScope = bindingScope.getProgramParent();
|
|
9
|
+
for (let index = 0; index < MAX_CANDIDATES; index++) {
|
|
10
|
+
const candidate = index === 0 ? baseName : `${baseName}${index + 1}`;
|
|
11
|
+
if (!isValidBindingIdentifier(candidate))
|
|
12
|
+
continue;
|
|
13
|
+
// Avoid shadowing bindings in parent scopes.
|
|
14
|
+
if (bindingScope.hasBinding(candidate))
|
|
15
|
+
continue;
|
|
16
|
+
if (Object.hasOwn(programScope.globals, candidate))
|
|
17
|
+
continue;
|
|
18
|
+
const wouldBeShadowed = binding.referencePaths.some((referencePath) => referencePath.scope !== bindingScope &&
|
|
19
|
+
referencePath.scope.hasBinding(candidate));
|
|
20
|
+
if (wouldBeShadowed)
|
|
21
|
+
continue;
|
|
22
|
+
return candidate;
|
|
23
|
+
}
|
|
24
|
+
return;
|
|
25
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const isValidBindingIdentifier: (name: string) => boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isIdentifierName, isKeyword, isStrictBindReservedWord, } from "@babel/helper-validator-identifier";
|
|
2
|
+
export const isValidBindingIdentifier = (name) => {
|
|
3
|
+
if (!isIdentifierName(name))
|
|
4
|
+
return false;
|
|
5
|
+
if (isKeyword(name))
|
|
6
|
+
return false;
|
|
7
|
+
if (isStrictBindReservedWord(name, true))
|
|
8
|
+
return false;
|
|
9
|
+
return true;
|
|
10
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { getTargetName } from "../rename-binding/get-target-name.js";
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
5
|
+
const traverse = require("@babel/traverse").default;
|
|
6
|
+
const BASE_NAME = "timeoutId";
|
|
7
|
+
const isSetTimeoutCall = (path, init) => {
|
|
8
|
+
if (init.callee.type !== "Identifier")
|
|
9
|
+
return false;
|
|
10
|
+
if (init.callee.name !== "setTimeout")
|
|
11
|
+
return false;
|
|
12
|
+
// If setTimeout is locally bound (imported or declared), semantics may differ.
|
|
13
|
+
if (path.scope.hasBinding("setTimeout", true))
|
|
14
|
+
return false;
|
|
15
|
+
return true;
|
|
16
|
+
};
|
|
17
|
+
const isClearTimeoutCallArgument = (referencePath, bindingName) => {
|
|
18
|
+
if (!referencePath.isIdentifier())
|
|
19
|
+
return false;
|
|
20
|
+
const callPath = referencePath.parentPath;
|
|
21
|
+
if (!callPath.isCallExpression())
|
|
22
|
+
return false;
|
|
23
|
+
const call = callPath.node;
|
|
24
|
+
if (call.callee.type !== "Identifier")
|
|
25
|
+
return false;
|
|
26
|
+
if (call.callee.name !== "clearTimeout")
|
|
27
|
+
return false;
|
|
28
|
+
// If clearTimeout is locally bound (imported or declared), semantics may differ.
|
|
29
|
+
if (callPath.scope.hasBinding("clearTimeout", true))
|
|
30
|
+
return false;
|
|
31
|
+
const argument0 = call.arguments[0];
|
|
32
|
+
if (argument0?.type !== "Identifier")
|
|
33
|
+
return false;
|
|
34
|
+
if (argument0 !== referencePath.node)
|
|
35
|
+
return false;
|
|
36
|
+
if (argument0.name !== bindingName)
|
|
37
|
+
return false;
|
|
38
|
+
return true;
|
|
39
|
+
};
|
|
40
|
+
export const renameTimeoutIdsTransform = {
|
|
41
|
+
id: "rename-timeout-ids",
|
|
42
|
+
description: "Renames setTimeout handle variables to timeoutId/timeoutId2/... when usage is only clearTimeout(...)",
|
|
43
|
+
scope: "file",
|
|
44
|
+
parallelizable: true,
|
|
45
|
+
transform(context) {
|
|
46
|
+
const { projectGraph } = context;
|
|
47
|
+
let nodesVisited = 0;
|
|
48
|
+
let transformationsApplied = 0;
|
|
49
|
+
for (const [, fileInfo] of projectGraph.files) {
|
|
50
|
+
traverse(fileInfo.ast, {
|
|
51
|
+
VariableDeclarator(path) {
|
|
52
|
+
nodesVisited++;
|
|
53
|
+
const id = path.node.id;
|
|
54
|
+
if (id.type !== "Identifier")
|
|
55
|
+
return;
|
|
56
|
+
if (id.name.length > 2)
|
|
57
|
+
return;
|
|
58
|
+
const init = path.node.init;
|
|
59
|
+
if (init?.type !== "CallExpression")
|
|
60
|
+
return;
|
|
61
|
+
if (!isSetTimeoutCall(path, init))
|
|
62
|
+
return;
|
|
63
|
+
const binding = path.scope.getBinding(id.name);
|
|
64
|
+
if (!binding)
|
|
65
|
+
return;
|
|
66
|
+
if (!binding.constant)
|
|
67
|
+
return;
|
|
68
|
+
if (binding.referencePaths.length === 0)
|
|
69
|
+
return;
|
|
70
|
+
if (!binding.referencePaths.every((referencePath) => isClearTimeoutCallArgument(referencePath, id.name)))
|
|
71
|
+
return;
|
|
72
|
+
const targetName = getTargetName(path.scope, binding, {
|
|
73
|
+
baseName: BASE_NAME,
|
|
74
|
+
});
|
|
75
|
+
if (!targetName)
|
|
76
|
+
return;
|
|
77
|
+
if (id.name === targetName)
|
|
78
|
+
return;
|
|
79
|
+
path.scope.rename(id.name, targetName);
|
|
80
|
+
transformationsApplied++;
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return Promise.resolve({ nodesVisited, transformationsApplied });
|
|
85
|
+
},
|
|
86
|
+
};
|
|
@@ -3,7 +3,7 @@ import * as z from "zod";
|
|
|
3
3
|
const TransformManifestEntry = z
|
|
4
4
|
.object({
|
|
5
5
|
id: z.string().min(1),
|
|
6
|
-
|
|
6
|
+
recommended: z.boolean(),
|
|
7
7
|
})
|
|
8
8
|
.loose();
|
|
9
9
|
const TransformManifest = z
|
|
@@ -14,6 +14,6 @@ const TransformManifest = z
|
|
|
14
14
|
const transformManifest = TransformManifest.parse(transformManifestJson);
|
|
15
15
|
export const transformPresets = {
|
|
16
16
|
recommended: transformManifest.transforms
|
|
17
|
-
.filter((transform) => transform.
|
|
17
|
+
.filter((transform) => transform.recommended)
|
|
18
18
|
.map((transform) => transform.id),
|
|
19
19
|
};
|
|
@@ -2,6 +2,7 @@ import { expandBooleanLiteralsTransform } from "./expand-boolean-literals/expand
|
|
|
2
2
|
import { expandReturnSequenceTransform } from "./expand-return-sequence/expand-return-sequence-transform.js";
|
|
3
3
|
import { expandSequenceExpressionsTransform } from "./expand-sequence-expressions/expand-sequence-expressions-transform.js";
|
|
4
4
|
import { expandSequenceExpressionsV2Transform } from "./expand-sequence-expressions-v2/expand-sequence-expressions-v2-transform.js";
|
|
5
|
+
import { expandSpecialNumberLiteralsTransform } from "./expand-special-number-literals/expand-special-number-literals-transform.js";
|
|
5
6
|
import { expandSequenceExpressionsV3Transform } from "./expand-sequence-expressions-v3/expand-sequence-expressions-v3-transform.js";
|
|
6
7
|
import { expandThrowSequenceTransform } from "./expand-throw-sequence/expand-throw-sequence-transform.js";
|
|
7
8
|
import { expandUndefinedLiteralsTransform } from "./expand-undefined-literals/expand-undefined-literals-transform.js";
|
|
@@ -9,6 +10,7 @@ import { renameCatchParametersTransform } from "./rename-catch-parameters/rename
|
|
|
9
10
|
import { renameDestructuredAliasesTransform } from "./rename-destructured-aliases/rename-destructured-aliases-transform.js";
|
|
10
11
|
import { renameLoopIndexVariablesTransform } from "./rename-loop-index-variables/rename-loop-index-variables-transform.js";
|
|
11
12
|
import { renamePromiseExecutorParametersTransform } from "./rename-promise-executor-parameters/rename-promise-executor-parameters-transform.js";
|
|
13
|
+
import { renameTimeoutIdsTransform } from "./rename-timeout-ids/rename-timeout-ids-transform.js";
|
|
12
14
|
import { renameUseReferenceGuardsTransform } from "./rename-use-reference-guards/rename-use-reference-guards-transform.js";
|
|
13
15
|
import { splitVariableDeclarationsTransform } from "./split-variable-declarations/split-variable-declarations-transform.js";
|
|
14
16
|
export const transformRegistry = {
|
|
@@ -17,12 +19,14 @@ export const transformRegistry = {
|
|
|
17
19
|
[expandSequenceExpressionsTransform.id]: expandSequenceExpressionsTransform,
|
|
18
20
|
[expandSequenceExpressionsV2Transform.id]: expandSequenceExpressionsV2Transform,
|
|
19
21
|
[expandSequenceExpressionsV3Transform.id]: expandSequenceExpressionsV3Transform,
|
|
22
|
+
[expandSpecialNumberLiteralsTransform.id]: expandSpecialNumberLiteralsTransform,
|
|
20
23
|
[expandThrowSequenceTransform.id]: expandThrowSequenceTransform,
|
|
21
24
|
[expandUndefinedLiteralsTransform.id]: expandUndefinedLiteralsTransform,
|
|
22
25
|
[renameCatchParametersTransform.id]: renameCatchParametersTransform,
|
|
23
26
|
[renameDestructuredAliasesTransform.id]: renameDestructuredAliasesTransform,
|
|
24
27
|
[renameLoopIndexVariablesTransform.id]: renameLoopIndexVariablesTransform,
|
|
25
28
|
[renamePromiseExecutorParametersTransform.id]: renamePromiseExecutorParametersTransform,
|
|
29
|
+
[renameTimeoutIdsTransform.id]: renameTimeoutIdsTransform,
|
|
26
30
|
[renameUseReferenceGuardsTransform.id]: renameUseReferenceGuardsTransform,
|
|
27
31
|
[splitVariableDeclarationsTransform.id]: splitVariableDeclarationsTransform,
|
|
28
32
|
};
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "miniread",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.3.0",
|
|
6
6
|
"description": "Transform minified JavaScript/TypeScript into a more readable form using deterministic AST-based transforms.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
package/transform-manifest.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"scope": "file",
|
|
7
7
|
"parallelizable": true,
|
|
8
8
|
"diffReductionImpact": 0,
|
|
9
|
-
"
|
|
9
|
+
"recommended": true,
|
|
10
10
|
"evaluatedAt": "2026-01-21T15:01:23.708Z",
|
|
11
11
|
"notes": "Improves readability but does not reduce diffs (boolean literals are already deterministic)"
|
|
12
12
|
},
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"scope": "file",
|
|
17
17
|
"parallelizable": true,
|
|
18
18
|
"diffReductionImpact": 0,
|
|
19
|
-
"
|
|
19
|
+
"recommended": true,
|
|
20
20
|
"evaluatedAt": "2026-01-21T16:27:42.316Z",
|
|
21
21
|
"notes": "Auto-added by evaluation script."
|
|
22
22
|
},
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"scope": "file",
|
|
27
27
|
"parallelizable": true,
|
|
28
28
|
"diffReductionImpact": 0,
|
|
29
|
-
"
|
|
29
|
+
"recommended": true,
|
|
30
30
|
"evaluatedAt": "2026-01-21T21:06:19.512Z",
|
|
31
31
|
"notes": "Auto-added by evaluation script."
|
|
32
32
|
},
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"scope": "file",
|
|
37
37
|
"parallelizable": true,
|
|
38
38
|
"diffReductionImpact": 0.0007738623280043599,
|
|
39
|
-
"
|
|
39
|
+
"recommended": true,
|
|
40
40
|
"evaluatedAt": "2026-01-23T07:48:59.087Z",
|
|
41
41
|
"notes": "Auto-added by evaluation script."
|
|
42
42
|
},
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"scope": "file",
|
|
47
47
|
"parallelizable": true,
|
|
48
48
|
"diffReductionImpact": 0.000943734546346775,
|
|
49
|
-
"
|
|
49
|
+
"recommended": true,
|
|
50
50
|
"evaluatedAt": "2026-01-22T12:49:10.952Z",
|
|
51
51
|
"notes": "Auto-added by evaluation script. Measured with baseline none: 0.09%."
|
|
52
52
|
},
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"scope": "file",
|
|
57
57
|
"parallelizable": true,
|
|
58
58
|
"diffReductionImpact": -0.0012834789830316051,
|
|
59
|
-
"
|
|
59
|
+
"recommended": false,
|
|
60
60
|
"evaluatedAt": "2026-01-22T15:19:04.615Z",
|
|
61
61
|
"notes": "Auto-added by evaluation script. Measured with baseline none: -0.13%. Superseded by expand-sequence-expressions-v2 in the recommended preset."
|
|
62
62
|
},
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
"scope": "file",
|
|
67
67
|
"parallelizable": true,
|
|
68
68
|
"diffReductionImpact": -0.01282535248485317,
|
|
69
|
-
"
|
|
69
|
+
"recommended": false,
|
|
70
70
|
"evaluatedAt": "2026-01-22T17:15:48.528Z",
|
|
71
71
|
"notes": "Auto-added by evaluation script. Measured with baseline none: -1.28%. Enabled for readability even when line diffs increase. Kept separate from expand-return-sequence to avoid modifying existing transforms and to allow independent enabling."
|
|
72
72
|
},
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"scope": "file",
|
|
77
77
|
"parallelizable": true,
|
|
78
78
|
"diffReductionImpact": -0.014316453068081048,
|
|
79
|
-
"
|
|
79
|
+
"recommended": false,
|
|
80
80
|
"evaluatedAt": "2026-01-22T18:22:48.609Z",
|
|
81
81
|
"notes": "Superseded by expand-sequence-expressions-v3."
|
|
82
82
|
},
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"scope": "file",
|
|
87
87
|
"parallelizable": true,
|
|
88
88
|
"diffReductionImpact": -0.014391951831788763,
|
|
89
|
-
"
|
|
89
|
+
"recommended": true,
|
|
90
90
|
"evaluatedAt": "2026-01-23T08:21:23.662Z",
|
|
91
91
|
"notes": "Supersedes expand-sequence-expressions-v2 in the recommended preset. Measured with baseline none: -1.44%. Enabled for readability even when line diffs increase."
|
|
92
92
|
},
|
|
@@ -96,17 +96,27 @@
|
|
|
96
96
|
"scope": "file",
|
|
97
97
|
"parallelizable": true,
|
|
98
98
|
"diffReductionImpact": 0,
|
|
99
|
-
"
|
|
99
|
+
"recommended": true,
|
|
100
100
|
"evaluatedAt": "2026-01-22T17:03:19.826Z",
|
|
101
101
|
"notes": "Auto-added by evaluation script."
|
|
102
102
|
},
|
|
103
|
+
{
|
|
104
|
+
"id": "rename-timeout-ids",
|
|
105
|
+
"description": "Renames setTimeout handle variables to timeoutId/timeoutId2/... when usage is only clearTimeout(...)",
|
|
106
|
+
"scope": "file",
|
|
107
|
+
"parallelizable": true,
|
|
108
|
+
"diffReductionImpact": 0.00003774938185385768,
|
|
109
|
+
"recommended": false,
|
|
110
|
+
"evaluatedAt": "2026-01-23T10:29:23.279Z",
|
|
111
|
+
"notes": "Measured with baseline none: 0.00%. Not enabled by default (readability-only)."
|
|
112
|
+
},
|
|
103
113
|
{
|
|
104
114
|
"id": "split-variable-declarations",
|
|
105
115
|
"description": "Splits multi-declarator variable declarations into separate statements",
|
|
106
116
|
"scope": "file",
|
|
107
117
|
"parallelizable": true,
|
|
108
118
|
"diffReductionImpact": -0.0027651422207961573,
|
|
109
|
-
"
|
|
119
|
+
"recommended": true,
|
|
110
120
|
"evaluatedAt": "2026-01-23T05:45:27.981Z",
|
|
111
121
|
"notes": "Auto-added by evaluation script. Measured with baseline none: -0.28%. Enabled in the recommended preset for readability and to normalize variable declarations even when line diffs increase."
|
|
112
122
|
},
|
|
@@ -116,7 +126,7 @@
|
|
|
116
126
|
"scope": "file",
|
|
117
127
|
"parallelizable": true,
|
|
118
128
|
"diffReductionImpact": -0.00007549876370771536,
|
|
119
|
-
"
|
|
129
|
+
"recommended": false,
|
|
120
130
|
"evaluatedAt": "2026-01-23T07:48:29.356Z",
|
|
121
131
|
"notes": "Largely superseded by expand-sequence-expressions-v3 (which also expands throw sequences), but kept for isolated runs and comparison."
|
|
122
132
|
},
|
|
@@ -126,9 +136,19 @@
|
|
|
126
136
|
"scope": "file",
|
|
127
137
|
"parallelizable": true,
|
|
128
138
|
"diffReductionImpact": 0,
|
|
129
|
-
"
|
|
139
|
+
"recommended": true,
|
|
130
140
|
"evaluatedAt": "2026-01-22T21:39:53.578Z",
|
|
131
141
|
"notes": "Auto-added by evaluation script."
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"id": "expand-special-number-literals",
|
|
145
|
+
"description": "Expands 1/0 to Infinity, -1/0 (and 1/-0) to -Infinity, and 0/0 to NaN (when not shadowed)",
|
|
146
|
+
"scope": "file",
|
|
147
|
+
"parallelizable": true,
|
|
148
|
+
"diffReductionImpact": 0,
|
|
149
|
+
"recommended": true,
|
|
150
|
+
"evaluatedAt": "2026-01-23T08:17:45.579Z",
|
|
151
|
+
"notes": "Auto-added by evaluation script."
|
|
132
152
|
}
|
|
133
153
|
],
|
|
134
154
|
"presetStats": {
|