miniread 1.113.0 → 1.115.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.
Files changed (18) hide show
  1. package/dist/transforms/preset-stats.json +2 -2
  2. package/dist/transforms-by-id/rename-array-accumulator-variables/manifest.json +5 -5
  3. package/dist/transforms-by-id/rename-array-accumulator-variables/rename-array-accumulator-variables-transform.js +14 -12
  4. package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/deferred-executor-heuristics.d.ts +2 -1
  5. package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/deferred-executor-heuristics.js +22 -8
  6. package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/manifest.json +4 -4
  7. package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/rename-deferred-resolve-parameters-v2-transform.js +16 -15
  8. package/dist/transforms-by-id/rename-loop-index-variables-v3/get-loop-counter-name.js +0 -4
  9. package/dist/transforms-by-id/rename-loop-index-variables-v3/manifest.json +3 -3
  10. package/dist/transforms-by-id/rename-return-object-bindings/collect-return-object-binding-candidates.d.ts +0 -2
  11. package/dist/transforms-by-id/rename-return-object-bindings/collect-return-object-binding-candidates.js +3 -10
  12. package/dist/transforms-by-id/rename-return-object-bindings/manifest.json +5 -5
  13. package/dist/transforms-by-id/rename-return-object-bindings/rename-return-object-bindings-transform.js +0 -3
  14. package/dist/transforms-by-id/stabilize-deferred-top-level-bindings/collect-deferred-variables.d.ts +4 -3
  15. package/dist/transforms-by-id/stabilize-deferred-top-level-bindings/collect-deferred-variables.js +28 -6
  16. package/dist/transforms-by-id/stabilize-deferred-top-level-bindings/manifest.json +6 -6
  17. package/dist/transforms-by-id/stabilize-deferred-top-level-bindings/stabilize-deferred-top-level-bindings-transform.js +5 -5
  18. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "recommended": {
3
- "diffSizePercent": 26.062100767282757,
4
- "notes": "Measured with baseline none: 26.06% of original diff."
3
+ "diffSizePercent": 25.50270249839362,
4
+ "notes": "Average test/baseline diff size ratio for the recommended preset with baseline set to none."
5
5
  }
6
6
  }
@@ -1,11 +1,11 @@
1
1
  {
2
- "notes": "Renames variables initialized as empty arrays with .push() usage to stable/readable names.",
2
+ "notes": "Renames variables initialized as empty arrays with .push()/.unshift() usage to stable/readable names.",
3
3
  "evaluations": {
4
4
  "claude-code-2.1.10:claude-code-2.1.11": {
5
- "diffSizePercent": 99.95275352458707,
6
- "evaluatedAt": "2026-02-12T07:32:40.071Z",
7
- "changedLines": 9226,
8
- "durationSeconds": 44.1652115,
5
+ "diffSizePercent": 99.94708394753752,
6
+ "evaluatedAt": "2026-02-17T08:05:01.672Z",
7
+ "changedLines": 9338,
8
+ "durationSeconds": 41.067913833,
9
9
  "stableNames": 1360
10
10
  }
11
11
  },
@@ -6,22 +6,24 @@ const require = createRequire(import.meta.url);
6
6
  const traverse = require("@babel/traverse").default;
7
7
  const BASE_NAME = "results";
8
8
  /**
9
- * Checks whether a binding reference is a `.push()` call on the variable.
10
- * Matches: `X.push(...)` where X is the binding.
9
+ * Checks whether a binding reference is an accumulator mutation call on the variable.
10
+ * Matches: `X.push(...)` or `X.unshift(...)` where X is the binding.
11
11
  */
12
- const isPushCallReference = (referencePath) => {
12
+ const isAccumulatorMutationReference = (referencePath) => {
13
13
  const memberPath = referencePath.parentPath;
14
14
  if (!memberPath?.isMemberExpression())
15
15
  return false;
16
- // Must be X.push (not X[push] or X["push"])
16
+ // Must be X.push/X.unshift (not X[push] or X["push"])
17
17
  if (memberPath.node.computed)
18
18
  return false;
19
19
  if (memberPath.node.object !== referencePath.node)
20
20
  return false;
21
21
  const property = memberPath.node.property;
22
- if (property.type !== "Identifier" || property.name !== "push")
22
+ if (property.type !== "Identifier")
23
23
  return false;
24
- // The member expression must be called: X.push(...)
24
+ if (property.name !== "push" && property.name !== "unshift")
25
+ return false;
26
+ // The member expression must be called: X.push(...) / X.unshift(...)
25
27
  const callPath = memberPath.parentPath;
26
28
  if (!callPath.isCallExpression())
27
29
  return false;
@@ -30,15 +32,15 @@ const isPushCallReference = (referencePath) => {
30
32
  return true;
31
33
  };
32
34
  /**
33
- * Checks whether a binding has at least one `.push()` call reference,
35
+ * Checks whether a binding has at least one array mutation call reference,
34
36
  * confirming the accumulator pattern.
35
37
  */
36
- const hasAtLeastOnePushCall = (referencePaths) => {
37
- return referencePaths.some((path) => isPushCallReference(path));
38
+ const hasAtLeastOneAccumulatorMutation = (referencePaths) => {
39
+ return referencePaths.some((path) => isAccumulatorMutationReference(path));
38
40
  };
39
41
  export const renameArrayAccumulatorVariablesTransform = {
40
42
  id: "rename-array-accumulator-variables",
41
- description: "Renames variables initialized as empty arrays with .push() usage to $results/$results2/... or results/results2/...",
43
+ description: "Renames variables initialized as empty arrays with .push()/.unshift() usage to $results/$results2/... or results/results2/...",
42
44
  scope: "file",
43
45
  parallelizable: true,
44
46
  transform(context) {
@@ -72,8 +74,8 @@ export const renameArrayAccumulatorVariablesTransform = {
72
74
  // Must have at least one reference
73
75
  if (binding.referencePaths.length === 0)
74
76
  return;
75
- // Must have at least one .push() call to confirm accumulator pattern
76
- if (!hasAtLeastOnePushCall(binding.referencePaths))
77
+ // Must have at least one array mutation call to confirm accumulator pattern
78
+ if (!hasAtLeastOneAccumulatorMutation(binding.referencePaths))
77
79
  return;
78
80
  group.add({
79
81
  scope: path.scope,
@@ -1,5 +1,6 @@
1
1
  import type { NodePath } from "@babel/traverse";
2
2
  import type { ArrowFunctionExpression, FunctionExpression, NewExpression } from "@babel/types";
3
3
  export declare const getExecutorFunctionIfEligible: (path: NodePath<NewExpression>) => NodePath<FunctionExpression | ArrowFunctionExpression> | undefined;
4
- export declare const isStoredReference: (referencePath: NodePath) => boolean;
4
+ export declare const isResolvePromiseLikeReference: (referencePath: NodePath) => boolean;
5
+ export declare const isRejectPromiseLikeReference: (referencePath: NodePath) => boolean;
5
6
  export declare const wouldShadowReferencedOuterBinding: (executorPath: NodePath<FunctionExpression | ArrowFunctionExpression>, targetName: string) => boolean;
@@ -1,3 +1,4 @@
1
+ import { isAssignedToOnHandlerProperty, isCatchRejectionHandlerArgument, isDirectCallOfBinding, isErrorEventHandlerArgument, isErrorEventHandlerRemovalArgument, isThenFulfillmentHandlerArgument, isThenRejectionHandlerArgument, } from "../rename-promise-executor-parameters-v2/promise-executor-heuristics.js";
1
2
  import { isValidBindingIdentifier } from "./is-valid-binding-identifier.js";
2
3
  const isExecutorParameterEligible = (parameter) => {
3
4
  if (!isValidBindingIdentifier(parameter.name))
@@ -63,14 +64,27 @@ const isVariableDeclaratorInitReference = (referencePath) => {
63
64
  return false;
64
65
  return referencePath.key === "init";
65
66
  };
66
- export const isStoredReference = (referencePath) => {
67
- // Keep this narrow on purpose: direct call-argument passing (e.g. `queue.push(resolve)`) is
68
- // excluded as lower-confidence. We still allow identifiers inside array/object literals
69
- // (e.g. `queue.push([resolve, reject])`) because those references are explicit storage sites.
70
- return (isArrayElementReference(referencePath) ||
71
- isObjectPropertyValueReference(referencePath) ||
72
- isAssignmentValueReference(referencePath) ||
73
- isVariableDeclaratorInitReference(referencePath));
67
+ const isStoredReference = (referencePath) => isArrayElementReference(referencePath) ||
68
+ isObjectPropertyValueReference(referencePath) ||
69
+ isAssignmentValueReference(referencePath) ||
70
+ isVariableDeclaratorInitReference(referencePath);
71
+ export const isResolvePromiseLikeReference = (referencePath) => {
72
+ if (!referencePath.isIdentifier())
73
+ return false;
74
+ return (isStoredReference(referencePath) ||
75
+ isDirectCallOfBinding(referencePath) ||
76
+ isThenFulfillmentHandlerArgument(referencePath));
77
+ };
78
+ export const isRejectPromiseLikeReference = (referencePath) => {
79
+ if (!referencePath.isIdentifier())
80
+ return false;
81
+ return (isStoredReference(referencePath) ||
82
+ isDirectCallOfBinding(referencePath) ||
83
+ isThenRejectionHandlerArgument(referencePath) ||
84
+ isCatchRejectionHandlerArgument(referencePath) ||
85
+ isAssignedToOnHandlerProperty(referencePath) ||
86
+ isErrorEventHandlerArgument(referencePath) ||
87
+ isErrorEventHandlerRemovalArgument(referencePath));
74
88
  };
75
89
  export const wouldShadowReferencedOuterBinding = (executorPath, targetName) => {
76
90
  const parentBinding = executorPath.scope.getBinding(targetName);
@@ -2,10 +2,10 @@
2
2
  "notes": "Renames deferred promise executor parameters to $resolve/$reject when both are only stored.",
3
3
  "evaluations": {
4
4
  "claude-code-2.1.10:claude-code-2.1.11": {
5
- "diffSizePercent": 100,
6
- "evaluatedAt": "2026-02-10T20:26:59.436Z",
7
- "changedLines": 92,
8
- "durationSeconds": 36.222931665999994,
5
+ "diffSizePercent": 99.99244056393393,
6
+ "evaluatedAt": "2026-02-16T08:21:48.869Z",
7
+ "changedLines": 1670,
8
+ "durationSeconds": 40.99589079100001,
9
9
  "stableNames": 1359
10
10
  }
11
11
  },
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
2
  import { isStableRenamed } from "../../core/stable-naming.js";
3
3
  import { getFilesToProcess, } from "../../core/types.js";
4
- import { getExecutorFunctionIfEligible, isStoredReference, wouldShadowReferencedOuterBinding, } from "./deferred-executor-heuristics.js";
4
+ import { getExecutorFunctionIfEligible, isRejectPromiseLikeReference, isResolvePromiseLikeReference, wouldShadowReferencedOuterBinding, } from "./deferred-executor-heuristics.js";
5
5
  import { hasExecutorLocalDynamicNameLookup } from "./has-executor-local-dynamic-name-lookup.js";
6
6
  import { canRenameBindingSafely } from "./rename-binding-if-safe.js";
7
7
  const require = createRequire(import.meta.url);
@@ -10,7 +10,7 @@ const traverse = require("@babel/traverse").default;
10
10
  const STABLE_PREFIX = "$";
11
11
  export const renameDeferredResolveParametersV2Transform = {
12
12
  id: "rename-deferred-resolve-parameters-v2",
13
- description: "Renames deferred promise resolve/reject parameters to $resolve/$reject when each parameter is only stored or unused",
13
+ description: "Renames deferred promise resolve/reject parameters to $resolve/$reject when safe",
14
14
  scope: "file",
15
15
  parallelizable: true,
16
16
  transform(context) {
@@ -60,28 +60,29 @@ export const renameDeferredResolveParametersV2Transform = {
60
60
  const rejectBinding = bindingScope.getBinding(rejectParameter.name);
61
61
  if (!resolveBinding || !rejectBinding)
62
62
  return;
63
- if (resolveBinding.constantViolations.length > 0)
64
- return;
65
- if (rejectBinding.constantViolations.length > 0)
66
- return;
67
- const resolveHasReferences = resolveBinding.referencePaths.length > 0;
68
- const rejectHasReferences = rejectBinding.referencePaths.length > 0;
69
63
  const resolveReferencePaths = resolveBinding.referencePaths;
70
64
  const rejectReferencePaths = rejectBinding.referencePaths;
71
65
  const hasUsageSignal = resolveReferencePaths.length > 0 || rejectReferencePaths.length > 0;
72
66
  if (!hasUsageSignal)
73
67
  return;
74
- const resolveIsStoredOnly = resolveReferencePaths.every((referencePath) => referencePath.isIdentifier() && isStoredReference(referencePath));
75
- if (!resolveIsStoredOnly)
68
+ const resolveHasOnlyPromiseLikeReferences = resolveReferencePaths.every((referencePath) => isResolvePromiseLikeReference(referencePath));
69
+ if (!resolveHasOnlyPromiseLikeReferences)
76
70
  return;
77
- const rejectIsStoredOnly = rejectReferencePaths.every((referencePath) => referencePath.isIdentifier() && isStoredReference(referencePath));
78
- if (!rejectIsStoredOnly)
71
+ const rejectHasOnlyPromiseLikeReferences = rejectReferencePaths.every((referencePath) => isRejectPromiseLikeReference(referencePath));
72
+ if (!rejectHasOnlyPromiseLikeReferences)
79
73
  return;
80
- // Avoid introducing semantic names for never-used parameters.
81
- const wantsResolveRename = resolveHasReferences && resolveParameter.name !== targetResolveName;
82
- const wantsRejectRename = rejectHasReferences && rejectParameter.name !== targetRejectName;
74
+ const wantsResolveRename = resolveParameter.name !== targetResolveName;
75
+ const wantsRejectRename = rejectParameter.name !== targetRejectName;
83
76
  if (!wantsResolveRename && !wantsRejectRename)
84
77
  return;
78
+ if (wantsResolveRename &&
79
+ resolveBinding.constantViolations.length > 0) {
80
+ return;
81
+ }
82
+ if (wantsRejectRename &&
83
+ rejectBinding.constantViolations.length > 0) {
84
+ return;
85
+ }
85
86
  // Shadowing checks require a full traversal of the executor, so only do them for parameters
86
87
  // that actually need renaming.
87
88
  const resolveWouldShadow = wantsResolveRename &&
@@ -105,8 +105,6 @@ export const getStableRenamedIndexLoopCounterName = (path) => {
105
105
  continue;
106
106
  if (declarator.init.type !== "NumericLiteral")
107
107
  continue;
108
- if (declarator.init.value !== 0)
109
- continue;
110
108
  if (!isLoopCounterDeclarator(loopCounterName, path))
111
109
  continue;
112
110
  if (stableName !== undefined)
@@ -133,8 +131,6 @@ export const getLoopCounterNameIfEligible = (path) => {
133
131
  continue;
134
132
  if (declarator.init.type !== "NumericLiteral")
135
133
  continue;
136
- if (declarator.init.value !== 0)
137
- continue;
138
134
  const loopCounterName = declarator.id.name;
139
135
  if (!isLoopCounterDeclarator(loopCounterName, path))
140
136
  continue;
@@ -3,9 +3,9 @@
3
3
  "evaluations": {
4
4
  "claude-code-2.1.10:claude-code-2.1.11": {
5
5
  "diffSizePercent": 100,
6
- "evaluatedAt": "2026-02-10T17:29:03.499Z",
7
- "changedLines": 3478,
8
- "durationSeconds": 60.688113084,
6
+ "evaluatedAt": "2026-02-14T13:04:12.173Z",
7
+ "changedLines": 3626,
8
+ "durationSeconds": 180.525304795,
9
9
  "stableNames": 1361
10
10
  }
11
11
  },
@@ -4,7 +4,6 @@ type BindingCandidate = {
4
4
  binding: Binding;
5
5
  currentName: string;
6
6
  baseName: string;
7
- conflicted: boolean;
8
7
  };
9
8
  type CollectReturnObjectBindingCandidatesResult = {
10
9
  candidates: Map<Binding, BindingCandidate>;
@@ -12,7 +11,6 @@ type CollectReturnObjectBindingCandidatesResult = {
12
11
  };
13
12
  type CollectReturnObjectBindingCandidatesOptions = {
14
13
  ast: File;
15
- isScript: boolean;
16
14
  exportedNames: ReadonlySet<string>;
17
15
  };
18
16
  export declare const collectReturnObjectBindingCandidates: (options: CollectReturnObjectBindingCandidatesOptions) => CollectReturnObjectBindingCandidatesResult;
@@ -25,8 +25,6 @@ const collectCandidatesForObjectExpression = (options) => {
25
25
  const propertyName = getPropertyName(property.key);
26
26
  if (!propertyName)
27
27
  continue;
28
- if (propertyName.length <= 1)
29
- continue;
30
28
  if (!isValidBindingIdentifier(propertyName))
31
29
  continue;
32
30
  if (isHashBasedStableName(`$${propertyName}`))
@@ -53,23 +51,18 @@ const collectCandidatesForObjectExpression = (options) => {
53
51
  exportedNames.has(currentName)) {
54
52
  continue;
55
53
  }
56
- const existing = candidates.get(binding);
57
- if (existing) {
58
- if (existing.baseName !== propertyName) {
59
- existing.conflicted = true;
60
- }
54
+ if (candidates.has(binding))
61
55
  continue;
62
- }
63
56
  candidates.set(binding, {
64
57
  binding,
65
58
  currentName,
66
59
  baseName: propertyName,
67
- conflicted: false,
68
60
  });
69
61
  }
70
62
  };
71
63
  export const collectReturnObjectBindingCandidates = (options) => {
72
- const { ast, isScript, exportedNames } = options;
64
+ const { ast, exportedNames } = options;
65
+ const isScript = ast.program.sourceType === "script";
73
66
  let nodesVisited = 0;
74
67
  const candidates = new Map();
75
68
  traverse(ast, {
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "evaluations": {
3
3
  "claude-code-2.1.10:claude-code-2.1.11": {
4
- "diffSizePercent": 99.87715916392636,
5
- "evaluatedAt": "2026-02-12T09:10:04.050Z",
6
- "changedLines": 13347,
7
- "durationSeconds": 44.633210875,
8
- "stableNames": 2444
4
+ "diffSizePercent": 99.88282874097592,
5
+ "evaluatedAt": "2026-02-17T12:48:21.759Z",
6
+ "changedLines": 13827,
7
+ "durationSeconds": 47.550179875,
8
+ "stableNames": 2458
9
9
  }
10
10
  },
11
11
  "recommended": true,
@@ -30,15 +30,12 @@ export const renameReturnObjectBindingsTransform = {
30
30
  const exportedNames = collectExportedNames(fileInfo.ast.program);
31
31
  const { candidates, nodesVisited: fileNodesVisited } = collectReturnObjectBindingCandidates({
32
32
  ast: fileInfo.ast,
33
- isScript,
34
33
  exportedNames,
35
34
  });
36
35
  nodesVisited += fileNodesVisited;
37
36
  const dynamicLookupScopes = collectLocalDynamicLookupScopes(fileInfo.ast);
38
37
  const group = new RenameGroup();
39
38
  for (const candidate of candidates.values()) {
40
- if (candidate.conflicted)
41
- continue;
42
39
  if (candidate.binding.scope.block.type === "Program"
43
40
  ? hasProgramScopeDynamicNameLookup
44
41
  : hasBindingLocalDynamicNameLookup(candidate.binding, candidate.currentName, dynamicLookupScopes)) {
@@ -5,6 +5,7 @@ type DeferredVariableInfo = {
5
5
  enclosingFunctionName: string;
6
6
  enclosingFunctionScopeUid: number;
7
7
  scope: Scope;
8
+ declarationStart: number | undefined;
8
9
  };
9
10
  /**
10
11
  * Collect information about deferred top-level var declarations.
@@ -16,8 +17,8 @@ export declare const collectDeferredVariables: (ast: t.File, programScope: Scope
16
17
  nodesVisited: number;
17
18
  };
18
19
  /**
19
- * Group deferred vars by their enclosing function.
20
- * Returns only vars where the function has exactly ONE deferred var.
20
+ * Group deferred vars by enclosing function and select one deterministic
21
+ * candidate for each function.
21
22
  */
22
- export declare const filterToSingleVariableFunctions: (deferredVariables: DeferredVariableInfo[]) => DeferredVariableInfo[];
23
+ export declare const selectDeferredVariablesForRename: (deferredVariables: DeferredVariableInfo[]) => DeferredVariableInfo[];
23
24
  export {};
@@ -87,6 +87,7 @@ export const collectDeferredVariables = (ast, programScope) => {
87
87
  enclosingFunctionName: info.enclosingFunctionName,
88
88
  enclosingFunctionScopeUid: info.enclosingFunctionScopeUid,
89
89
  scope: binding.scope,
90
+ declarationStart: binding.identifier.start ?? undefined,
90
91
  });
91
92
  }
92
93
  }
@@ -94,10 +95,10 @@ export const collectDeferredVariables = (ast, programScope) => {
94
95
  return { deferredVariables, nodesVisited };
95
96
  };
96
97
  /**
97
- * Group deferred vars by their enclosing function.
98
- * Returns only vars where the function has exactly ONE deferred var.
98
+ * Group deferred vars by enclosing function and select one deterministic
99
+ * candidate for each function.
99
100
  */
100
- export const filterToSingleVariableFunctions = (deferredVariables) => {
101
+ export const selectDeferredVariablesForRename = (deferredVariables) => {
101
102
  // Group by enclosing function identity (name + scope UID).
102
103
  const byFunction = new Map();
103
104
  for (const info of deferredVariables) {
@@ -110,12 +111,33 @@ export const filterToSingleVariableFunctions = (deferredVariables) => {
110
111
  byFunction.set(functionIdentity, [info]);
111
112
  }
112
113
  }
113
- // Only keep vars where function has exactly one
114
+ // Keep one candidate per function:
115
+ // - Skip already-stable bindings (`$...`) to avoid churn.
116
+ // - For multi-candidate functions, pick the earliest declaration position.
117
+ // This tie-break is independent of minified identifier text.
114
118
  const result = [];
115
119
  for (const variables of byFunction.values()) {
116
- if (variables.length === 1 && variables[0]) {
117
- result.push(variables[0]);
120
+ const unstabilizedVariables = variables.filter((variableInfo) => !isStableRenamed(variableInfo.variableName));
121
+ if (unstabilizedVariables.length === 0)
122
+ continue;
123
+ if (unstabilizedVariables.length === 1 && unstabilizedVariables[0]) {
124
+ result.push(unstabilizedVariables[0]);
125
+ continue;
118
126
  }
127
+ const sortedByDeclarationStart = unstabilizedVariables.toSorted((left, right) => {
128
+ const leftStart = left.declarationStart ?? Number.POSITIVE_INFINITY;
129
+ const rightStart = right.declarationStart ?? Number.POSITIVE_INFINITY;
130
+ return leftStart - rightStart;
131
+ });
132
+ const first = sortedByDeclarationStart[0];
133
+ const second = sortedByDeclarationStart[1];
134
+ if (!first)
135
+ continue;
136
+ const firstStart = first.declarationStart ?? Number.POSITIVE_INFINITY;
137
+ const secondStart = second?.declarationStart ?? Number.POSITIVE_INFINITY;
138
+ if (firstStart === secondStart)
139
+ continue;
140
+ result.push(first);
119
141
  }
120
142
  return result;
121
143
  };
@@ -1,12 +1,12 @@
1
1
  {
2
- "notes": "Stabilizes top-level var declarations that are initialized inside stable-named functions (lazy init pattern). Only applies when the enclosing function has exactly one such deferred var to avoid order-dependent naming. Renames ~750 vars but diff reduction is minimal (0.03%) because most vars already have consistent minified names between versions. The stabilization helps when minifiers do vary names.",
2
+ "notes": "Stabilizes top-level var declarations initialized inside stable-named functions (lazy init pattern). For multi-deferred functions, picks a deterministic candidate by declaration order and skips already-stable `$...` bindings to avoid churn from minifier-dependent variable names.",
3
3
  "evaluations": {
4
4
  "claude-code-2.1.10:claude-code-2.1.11": {
5
- "diffSizePercent": 100.13606984918925,
6
- "evaluatedAt": "2026-02-10T06:27:28.231Z",
7
- "changedLines": 126,
8
- "durationSeconds": 39.356983667,
9
- "stableNames": 1367
5
+ "diffSizePercent": 100.24568167214727,
6
+ "evaluatedAt": "2026-02-17T12:58:15.137Z",
7
+ "changedLines": 448,
8
+ "durationSeconds": 44.418337541,
9
+ "stableNames": 1380
10
10
  }
11
11
  },
12
12
  "recommended": true,
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
2
2
  import { parse } from "@babel/parser";
3
3
  import { getFilesToProcess, } from "../../core/types.js";
4
4
  import { generateCode } from "../../core/generate-code.js";
5
- import { collectDeferredVariables, filterToSingleVariableFunctions, } from "./collect-deferred-variables.js";
5
+ import { collectDeferredVariables, selectDeferredVariablesForRename, } from "./collect-deferred-variables.js";
6
6
  import { extractHashFromStableName, renameBindingInPlace, } from "./rename-helpers.js";
7
7
  import { canRenameBindingSafely } from "../../transforms/shared/can-rename-binding-safely.js";
8
8
  const require = createRequire(import.meta.url);
@@ -11,8 +11,8 @@ const traverse = require("@babel/traverse").default;
11
11
  export const stabilizeDeferredTopLevelBindingsTransform = {
12
12
  id: "stabilize-deferred-top-level-bindings",
13
13
  description: "Renames top-level var declarations without initializers (deferred bindings) to stable names " +
14
- "derived from their enclosing stable function. Only applies when the function has exactly one " +
15
- "such deferred var to avoid order-dependent naming.",
14
+ "derived from their enclosing stable function. For functions with multiple deferred vars, " +
15
+ "chooses a deterministic candidate by declaration order and skips already-stable bindings.",
16
16
  scope: "file",
17
17
  parallelizable: true,
18
18
  transform(context) {
@@ -33,8 +33,8 @@ export const stabilizeDeferredTopLevelBindingsTransform = {
33
33
  // Collect deferred vars
34
34
  const { deferredVariables, nodesVisited: fileNodesVisited } = collectDeferredVariables(fileInfo.ast, programScope);
35
35
  nodesVisited += fileNodesVisited;
36
- // Filter to vars where function has exactly one deferred var
37
- const eligibleVariables = filterToSingleVariableFunctions(deferredVariables);
36
+ // Select one deterministic deferred var candidate per function.
37
+ const eligibleVariables = selectDeferredVariablesForRename(deferredVariables);
38
38
  // Apply renames. Track used names for consistency with stabilize-deferred-stable-rhs
39
39
  // and to avoid duplicate `$v_...` targets when different functions produce
40
40
  // the same derived hash.
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.113.0",
5
+ "version": "1.115.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",