miniread 1.54.0 → 1.56.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.
@@ -23,6 +23,11 @@ const manifestData = {
23
23
  notes: "Auto-added by evaluation script.",
24
24
  evaluations: { "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 100, "evaluatedAt": "2026-01-25T22:59:37.142Z", "changedLines": 310, "durationSeconds": 57.105855792, "stableNames": 1357 } },
25
25
  },
26
+ "expand-typeof-undefined-comparisons": {
27
+ recommended: true,
28
+ notes: "Improves readability by expanding minified typeof comparisons; expected to be diff-neutral.",
29
+ evaluations: { "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 100, "evaluatedAt": "2026-02-01T22:27:53.830Z", "changedLines": 780, "durationSeconds": 138.901942826, "stableNames": 1357 } },
30
+ },
26
31
  "expand-undefined-literals": {
27
32
  recommended: true,
28
33
  notes: "Auto-added by evaluation script.",
@@ -118,6 +123,10 @@ const manifestData = {
118
123
  notes: "Added manually; recommended based on high-confidence heuristics. Evaluated diff-neutral on claude-code-2.1.10→2.1.11.",
119
124
  evaluations: { "legacy:evaluation": { "evaluatedAt": "2026-01-25T20:01:29.649Z", "changedLines": 8, "durationSeconds": 0, "stableNames": 0, "diffSizePercent": 100 }, "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 100, "evaluatedAt": "2026-01-29T14:35:18.029Z", "changedLines": 8, "durationSeconds": 34.694468833, "stableNames": 1358 } },
120
125
  },
126
+ "rename-interval-ids": {
127
+ recommended: true,
128
+ evaluations: { "claude-code-2.1.10:claude-code-2.1.11": { "diffSizePercent": 100, "evaluatedAt": "2026-02-01T09:30:55.276Z", "changedLines": 58, "durationSeconds": 201.398360841, "stableNames": 1358 } },
129
+ },
121
130
  "rename-loop-index-variables": {
122
131
  recommended: false,
123
132
  notes: "Superseded by rename-loop-index-variables-v3.",
@@ -320,6 +329,7 @@ export const recommendedTransformIds = [
320
329
  "expand-boolean-literals",
321
330
  "expand-sequence-expressions-v5",
322
331
  "expand-special-number-literals",
332
+ "expand-typeof-undefined-comparisons",
323
333
  "expand-undefined-literals",
324
334
  "remove-redundant-else",
325
335
  "rename-arguments-length-flags",
@@ -338,6 +348,7 @@ export const recommendedTransformIds = [
338
348
  "rename-error-first-callback-parameters",
339
349
  "rename-error-variables",
340
350
  "rename-event-parameters",
351
+ "rename-interval-ids",
341
352
  "rename-loop-index-variables-v3",
342
353
  "rename-loop-length-variables",
343
354
  "rename-object-keys-variables",
@@ -4,6 +4,7 @@ import { expandBooleanLiteralsTransform } from "../expand-boolean-literals/expan
4
4
  import { expandSequenceExpressionsV4Transform } from "../expand-sequence-expressions-v4/expand-sequence-expressions-v4-transform.js";
5
5
  import { expandSequenceExpressionsV5Transform } from "../expand-sequence-expressions-v5/expand-sequence-expressions-v5-transform.js";
6
6
  import { expandSpecialNumberLiteralsTransform } from "../expand-special-number-literals/expand-special-number-literals-transform.js";
7
+ import { expandTypeofUndefinedComparisonsTransform } from "../expand-typeof-undefined-comparisons/expand-typeof-undefined-comparisons-transform.js";
7
8
  import { expandUndefinedLiteralsTransform } from "../expand-undefined-literals/expand-undefined-literals-transform.js";
8
9
  import { removeRedundantElseTransform } from "../remove-redundant-else/remove-redundant-else-transform.js";
9
10
  import { renameArgumentsLengthFlagsTransform } from "../rename-arguments-length-flags/rename-arguments-length-flags-transform.js";
@@ -23,6 +24,7 @@ import { renameDestructuredAliasesTransform } from "../rename-destructured-alias
23
24
  import { renameErrorFirstCallbackParametersTransform } from "../rename-error-first-callback-parameters/rename-error-first-callback-parameters-transform.js";
24
25
  import { renameErrorVariablesTransform } from "../rename-error-variables/rename-error-variables-transform.js";
25
26
  import { renameEventParametersTransform } from "../rename-event-parameters/rename-event-parameters-transform.js";
27
+ import { renameIntervalIdsTransform } from "../rename-interval-ids/rename-interval-ids-transform.js";
26
28
  import { renameLoopIndexVariablesTransform } from "../rename-loop-index-variables/rename-loop-index-variables-transform.js";
27
29
  import { renameLoopIndexVariablesV2Transform } from "../rename-loop-index-variables-v2/rename-loop-index-variables-v2-transform.js";
28
30
  import { renameLoopIndexVariablesV3Transform } from "../rename-loop-index-variables-v3/rename-loop-index-variables-v3-transform.js";
@@ -64,6 +66,7 @@ export const transformRegistry = {
64
66
  [expandSequenceExpressionsV4Transform.id]: expandSequenceExpressionsV4Transform,
65
67
  [expandSequenceExpressionsV5Transform.id]: expandSequenceExpressionsV5Transform,
66
68
  [expandSpecialNumberLiteralsTransform.id]: expandSpecialNumberLiteralsTransform,
69
+ [expandTypeofUndefinedComparisonsTransform.id]: expandTypeofUndefinedComparisonsTransform,
67
70
  [expandUndefinedLiteralsTransform.id]: expandUndefinedLiteralsTransform,
68
71
  [removeRedundantElseTransform.id]: removeRedundantElseTransform,
69
72
  [renameArgumentsLengthFlagsTransform.id]: renameArgumentsLengthFlagsTransform,
@@ -83,6 +86,7 @@ export const transformRegistry = {
83
86
  [renameErrorFirstCallbackParametersTransform.id]: renameErrorFirstCallbackParametersTransform,
84
87
  [renameErrorVariablesTransform.id]: renameErrorVariablesTransform,
85
88
  [renameEventParametersTransform.id]: renameEventParametersTransform,
89
+ [renameIntervalIdsTransform.id]: renameIntervalIdsTransform,
86
90
  [renameLoopIndexVariablesTransform.id]: renameLoopIndexVariablesTransform,
87
91
  [renameLoopIndexVariablesV2Transform.id]: renameLoopIndexVariablesV2Transform,
88
92
  [renameLoopIndexVariablesV3Transform.id]: renameLoopIndexVariablesV3Transform,
@@ -0,0 +1,2 @@
1
+ import { type Transform } from "../../core/types.js";
2
+ export declare const expandTypeofUndefinedComparisonsTransform: Transform;
@@ -0,0 +1,65 @@
1
+ import { createRequire } from "node:module";
2
+ import * as t from "@babel/types";
3
+ import { getFilesToProcess, } from "../../core/types.js";
4
+ const require = createRequire(import.meta.url);
5
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
6
+ const traverse = require("@babel/traverse").default;
7
+ const isExpression = (value) => !t.isPrivateName(value);
8
+ const isTypeofExpression = (expression) => isExpression(expression) &&
9
+ t.isUnaryExpression(expression, {
10
+ operator: "typeof",
11
+ });
12
+ const isUStringLiteral = (expression) => isExpression(expression) && t.isStringLiteral(expression, { value: "u" });
13
+ const getTypeofUndefinedComparison = (expression) => {
14
+ if (expression.operator !== "<" &&
15
+ expression.operator !== "<=" &&
16
+ expression.operator !== ">" &&
17
+ expression.operator !== ">=") {
18
+ return undefined;
19
+ }
20
+ const operator = expression.operator === "<" || expression.operator === "<=" ? "<" : ">";
21
+ const { left, right } = expression;
22
+ const leftTypeof = isTypeofExpression(left) ? left : undefined;
23
+ const rightTypeof = isTypeofExpression(right) ? right : undefined;
24
+ const leftIsU = isUStringLiteral(left);
25
+ const rightIsU = isUStringLiteral(right);
26
+ if (leftTypeof && rightIsU) {
27
+ // "typeof X" strings are lexicographically < "u" for all types except "undefined".
28
+ return {
29
+ typeofExpression: leftTypeof,
30
+ operator: operator === "<" ? "!==" : "===",
31
+ };
32
+ }
33
+ if (rightTypeof && leftIsU) {
34
+ // "u" < typeof X only when typeof X === "undefined"; otherwise "u" > typeof X.
35
+ return {
36
+ typeofExpression: rightTypeof,
37
+ operator: operator === "<" ? "===" : "!==",
38
+ };
39
+ }
40
+ return undefined;
41
+ };
42
+ export const expandTypeofUndefinedComparisonsTransform = {
43
+ id: "expand-typeof-undefined-comparisons",
44
+ description: "Expands typeof comparisons against 'u' into explicit undefined checks",
45
+ scope: "file",
46
+ parallelizable: true,
47
+ transform(context) {
48
+ let nodesVisited = 0;
49
+ let transformationsApplied = 0;
50
+ for (const fileInfo of getFilesToProcess(context)) {
51
+ traverse(fileInfo.ast, {
52
+ BinaryExpression(path) {
53
+ nodesVisited++;
54
+ const comparison = getTypeofUndefinedComparison(path.node);
55
+ if (!comparison)
56
+ return;
57
+ const replacement = t.binaryExpression(comparison.operator, t.cloneNode(comparison.typeofExpression, true), t.stringLiteral("undefined"));
58
+ path.replaceWith(replacement);
59
+ transformationsApplied++;
60
+ },
61
+ });
62
+ }
63
+ return Promise.resolve({ nodesVisited, transformationsApplied });
64
+ },
65
+ };
@@ -0,0 +1,13 @@
1
+ {
2
+ "recommended": true,
3
+ "evaluations": {
4
+ "claude-code-2.1.10:claude-code-2.1.11": {
5
+ "diffSizePercent": 100,
6
+ "evaluatedAt": "2026-02-01T22:27:53.830Z",
7
+ "changedLines": 780,
8
+ "durationSeconds": 138.901942826,
9
+ "stableNames": 1357
10
+ }
11
+ },
12
+ "notes": "Improves readability by expanding minified typeof comparisons; expected to be diff-neutral."
13
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "recommended": {
3
- "diffSizePercent": 83.6526599845798,
4
- "notes": "Measured with baseline none: 83.65% of original diff."
3
+ "diffSizePercent": 78.49967015361418,
4
+ "notes": "Measured with baseline none: 78.50% of original diff."
5
5
  }
6
6
  }
@@ -4,4 +4,4 @@
4
4
  * This lets us tune transform interactions intentionally instead of relying on
5
5
  * alphabetical ID sorting.
6
6
  */
7
- export declare const recommendedTransformOrder: readonly ["stabilize-top-level-bindings", "expand-boolean-literals", "expand-sequence-expressions-v5", "expand-special-number-literals", "expand-undefined-literals", "remove-redundant-else", "rename-arguments-length-flags", "rename-asap-wrappers", "rename-awaiter-parameters", "rename-buffer-variables", "rename-catch-parameters", "rename-char-code-at", "rename-charcode-variables-v2", "rename-client-aliases", "rename-comparison-flags", "rename-date-now-start-times", "rename-default-options-parameters", "rename-deferred-resolve-parameters", "rename-destructured-aliases", "rename-error-first-callback-parameters", "rename-error-variables", "rename-event-parameters", "rename-loop-index-variables-v3", "rename-loop-length-variables", "rename-object-keys-variables", "rename-parameters-to-match-properties-v2", "rename-promise-executor-parameters-v2", "rename-range-parameters", "rename-read-file-lines", "rename-regex-builders", "rename-rest-parameters", "rename-search-parameters-variables", "rename-string-split-variables", "rename-this-aliases", "rename-timeout-ids", "rename-typeof-variables", "rename-typescript-helper-aliases", "rename-uint8array-concat-variables", "rename-url-parameters", "rename-url-variables", "rename-use-reference-guards-v2", "rename-use-reference-sets", "simplify-boolean-negations", "simplify-string-trim", "split-variable-declarations", "use-object-property-shorthand", "use-object-shorthand", "replace-dynamic-require-eval"];
7
+ export declare const recommendedTransformOrder: readonly ["stabilize-top-level-bindings", "expand-boolean-literals", "expand-sequence-expressions-v5", "expand-special-number-literals", "expand-typeof-undefined-comparisons", "expand-undefined-literals", "remove-redundant-else", "rename-arguments-length-flags", "rename-asap-wrappers", "rename-awaiter-parameters", "rename-buffer-variables", "rename-catch-parameters", "rename-char-code-at", "rename-charcode-variables-v2", "rename-client-aliases", "rename-comparison-flags", "rename-date-now-start-times", "rename-default-options-parameters", "rename-deferred-resolve-parameters", "rename-destructured-aliases", "rename-error-first-callback-parameters", "rename-error-variables", "rename-event-parameters", "rename-interval-ids", "rename-loop-index-variables-v3", "rename-loop-length-variables", "rename-object-keys-variables", "rename-parameters-to-match-properties-v2", "rename-promise-executor-parameters-v2", "rename-range-parameters", "rename-read-file-lines", "rename-regex-builders", "rename-rest-parameters", "rename-search-parameters-variables", "rename-string-split-variables", "rename-this-aliases", "rename-timeout-ids", "rename-typeof-variables", "rename-typescript-helper-aliases", "rename-uint8array-concat-variables", "rename-url-parameters", "rename-url-variables", "rename-use-reference-guards-v2", "rename-use-reference-sets", "simplify-boolean-negations", "simplify-string-trim", "split-variable-declarations", "use-object-property-shorthand", "use-object-shorthand", "replace-dynamic-require-eval"];
@@ -11,6 +11,7 @@ export const recommendedTransformOrder = [
11
11
  "expand-boolean-literals",
12
12
  "expand-sequence-expressions-v5",
13
13
  "expand-special-number-literals",
14
+ "expand-typeof-undefined-comparisons",
14
15
  "expand-undefined-literals",
15
16
  "remove-redundant-else",
16
17
  "rename-arguments-length-flags",
@@ -29,6 +30,7 @@ export const recommendedTransformOrder = [
29
30
  "rename-error-first-callback-parameters",
30
31
  "rename-error-variables",
31
32
  "rename-event-parameters",
33
+ "rename-interval-ids",
32
34
  "rename-loop-index-variables-v3",
33
35
  "rename-loop-length-variables",
34
36
  "rename-object-keys-variables",
@@ -0,0 +1,12 @@
1
+ {
2
+ "recommended": true,
3
+ "evaluations": {
4
+ "claude-code-2.1.10:claude-code-2.1.11": {
5
+ "diffSizePercent": 100,
6
+ "evaluatedAt": "2026-02-01T09:30:55.276Z",
7
+ "changedLines": 58,
8
+ "durationSeconds": 201.398360841,
9
+ "stableNames": 1358
10
+ }
11
+ }
12
+ }
@@ -0,0 +1,2 @@
1
+ import { type Transform } from "../../core/types.js";
2
+ export declare const renameIntervalIdsTransform: Transform;
@@ -0,0 +1,85 @@
1
+ import { createRequire } from "node:module";
2
+ import { isStableRenamed, RenameGroup } from "../../core/stable-naming.js";
3
+ import { getFilesToProcess, } from "../../core/types.js";
4
+ const require = createRequire(import.meta.url);
5
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
6
+ const traverse = require("@babel/traverse").default;
7
+ const BASE_NAME = "intervalId";
8
+ const isSetIntervalCall = (path, init) => {
9
+ if (init.callee.type !== "Identifier")
10
+ return false;
11
+ if (init.callee.name !== "setInterval")
12
+ return false;
13
+ // If setInterval is locally bound (imported or declared), semantics may differ.
14
+ if (path.scope.hasBinding("setInterval", true))
15
+ return false;
16
+ return true;
17
+ };
18
+ const isClearIntervalCallArgument = (referencePath, bindingName) => {
19
+ if (!referencePath.isIdentifier())
20
+ return false;
21
+ const callPath = referencePath.parentPath;
22
+ if (!callPath.isCallExpression())
23
+ return false;
24
+ const call = callPath.node;
25
+ if (call.callee.type !== "Identifier")
26
+ return false;
27
+ if (call.callee.name !== "clearInterval")
28
+ return false;
29
+ // If clearInterval is locally bound (imported or declared), semantics may differ.
30
+ if (callPath.scope.hasBinding("clearInterval", true))
31
+ return false;
32
+ const argument0 = call.arguments[0];
33
+ if (argument0?.type !== "Identifier")
34
+ return false;
35
+ if (argument0 !== referencePath.node)
36
+ return false;
37
+ if (argument0.name !== bindingName)
38
+ return false;
39
+ return true;
40
+ };
41
+ export const renameIntervalIdsTransform = {
42
+ id: "rename-interval-ids",
43
+ description: "Renames setInterval handle variables to $intervalId/$intervalId2/... or intervalId/intervalId2/... when usage is only clearInterval(...)",
44
+ scope: "file",
45
+ parallelizable: true,
46
+ transform(context) {
47
+ let nodesVisited = 0;
48
+ let transformationsApplied = 0;
49
+ for (const fileInfo of getFilesToProcess(context)) {
50
+ const group = new RenameGroup();
51
+ traverse(fileInfo.ast, {
52
+ VariableDeclarator(path) {
53
+ nodesVisited++;
54
+ const id = path.node.id;
55
+ if (id.type !== "Identifier")
56
+ return;
57
+ // Skip already-stable names
58
+ if (isStableRenamed(id.name))
59
+ return;
60
+ const init = path.node.init;
61
+ if (init?.type !== "CallExpression")
62
+ return;
63
+ if (!isSetIntervalCall(path, init))
64
+ return;
65
+ const binding = path.scope.getBinding(id.name);
66
+ if (!binding)
67
+ return;
68
+ if (!binding.constant)
69
+ return;
70
+ if (binding.referencePaths.length === 0)
71
+ return;
72
+ if (!binding.referencePaths.every((referencePath) => isClearIntervalCallArgument(referencePath, id.name)))
73
+ return;
74
+ group.add({
75
+ scope: path.scope,
76
+ currentName: id.name,
77
+ baseName: BASE_NAME,
78
+ });
79
+ },
80
+ });
81
+ transformationsApplied += group.apply();
82
+ }
83
+ return Promise.resolve({ nodesVisited, transformationsApplied });
84
+ },
85
+ };
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.54.0",
5
+ "version": "1.56.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",