miniread 1.115.0 → 1.115.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "recommended": {
3
- "diffSizePercent": 25.50270249839362,
4
- "notes": "Average test/baseline diff size ratio for the recommended preset with baseline set to none."
3
+ "diffSizePercent": 25.296707865593227,
4
+ "notes": "Measured with baseline none: 25.30% of original diff."
5
5
  }
6
6
  }
@@ -2,10 +2,10 @@
2
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.94708394753752,
6
- "evaluatedAt": "2026-02-17T08:05:01.672Z",
7
- "changedLines": 9338,
8
- "durationSeconds": 41.067913833,
5
+ "diffSizePercent": 98.38606039989418,
6
+ "evaluatedAt": "2026-02-18T06:56:35.742Z",
7
+ "changedLines": 18428,
8
+ "durationSeconds": 52.968690957999996,
9
9
  "stableNames": 1360
10
10
  }
11
11
  },
@@ -5,42 +5,24 @@ const require = createRequire(import.meta.url);
5
5
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
6
6
  const traverse = require("@babel/traverse").default;
7
7
  const BASE_NAME = "results";
8
- /**
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
- */
12
- const isAccumulatorMutationReference = (referencePath) => {
13
- const memberPath = referencePath.parentPath;
14
- if (!memberPath?.isMemberExpression())
8
+ const isArrayInitialization = (path) => {
9
+ const init = path.node.init;
10
+ if (!init)
15
11
  return false;
16
- // Must be X.push/X.unshift (not X[push] or X["push"])
17
- if (memberPath.node.computed)
12
+ if (init.type === "ArrayExpression")
13
+ return true;
14
+ if (init.type !== "NewExpression")
18
15
  return false;
19
- if (memberPath.node.object !== referencePath.node)
16
+ if (init.callee.type !== "Identifier")
20
17
  return false;
21
- const property = memberPath.node.property;
22
- if (property.type !== "Identifier")
18
+ if (init.callee.name !== "Array")
23
19
  return false;
24
- if (property.name !== "push" && property.name !== "unshift")
25
- return false;
26
- // The member expression must be called: X.push(...) / X.unshift(...)
27
- const callPath = memberPath.parentPath;
28
- if (!callPath.isCallExpression())
29
- return false;
30
- if (callPath.node.callee !== memberPath.node)
31
- return false;
32
- return true;
33
- };
34
- /**
35
- * Checks whether a binding has at least one array mutation call reference,
36
- * confirming the accumulator pattern.
37
- */
38
- const hasAtLeastOneAccumulatorMutation = (referencePaths) => {
39
- return referencePaths.some((path) => isAccumulatorMutationReference(path));
20
+ // Only treat the global Array constructor as an array initializer.
21
+ return !path.scope.hasBinding("Array", true);
40
22
  };
41
23
  export const renameArrayAccumulatorVariablesTransform = {
42
24
  id: "rename-array-accumulator-variables",
43
- description: "Renames variables initialized as empty arrays with .push()/.unshift() usage to $results/$results2/... or results/results2/...",
25
+ description: "Renames local variables initialized as arrays to $results/$results2/... or results/results2/...",
44
26
  scope: "file",
45
27
  parallelizable: true,
46
28
  transform(context) {
@@ -59,24 +41,13 @@ export const renameArrayAccumulatorVariablesTransform = {
59
41
  return;
60
42
  if (currentName === BASE_NAME)
61
43
  return;
62
- // Must be initialized with an empty array literal: `let X = []`
63
- const init = path.node.init;
64
- if (init?.type !== "ArrayExpression")
65
- return;
66
- if (init.elements.length > 0)
44
+ if (!isArrayInitialization(path))
67
45
  return;
68
46
  const binding = path.scope.getBinding(currentName);
69
47
  if (!binding)
70
48
  return;
71
- // Must not be reassigned (Babel treats `const x = []; x.push(1)` as constant)
72
- if (!binding.constant)
73
- return;
74
- // Must have at least one reference
75
49
  if (binding.referencePaths.length === 0)
76
50
  return;
77
- // Must have at least one array mutation call to confirm accumulator pattern
78
- if (!hasAtLeastOneAccumulatorMutation(binding.referencePaths))
79
- return;
80
51
  group.add({
81
52
  scope: path.scope,
82
53
  currentName,
@@ -1,14 +1,14 @@
1
1
  {
2
- "recommended": true,
3
- "recommendedOrder": 100,
4
2
  "notes": "Added to recommended for readability of invalidParameterError call sites.",
5
3
  "evaluations": {
6
4
  "claude-code-2.1.10:claude-code-2.1.11": {
7
- "diffSizePercent": 100,
8
- "evaluatedAt": "2026-02-07T21:13:39.357Z",
9
- "changedLines": 0,
10
- "durationSeconds": 191.643123151,
11
- "stableNames": 1357
5
+ "diffSizePercent": 99.99811516350957,
6
+ "evaluatedAt": "2026-02-17T13:28:14.742Z",
7
+ "changedLines": 420,
8
+ "durationSeconds": 204.312632724,
9
+ "stableNames": 1379
12
10
  }
13
- }
11
+ },
12
+ "recommended": true,
13
+ "recommendedOrder": 100
14
14
  }
@@ -33,15 +33,13 @@ const isInvalidParameterErrorCallee = (callee) => {
33
33
  }
34
34
  if (callee.type !== "MemberExpression")
35
35
  return false;
36
- if (callee.object.type !== "Identifier")
37
- return false;
38
- if (callee.object.name !== "errors")
39
- return false;
40
- if (callee.computed)
41
- return false;
42
- if (callee.property.type !== "Identifier")
36
+ if (!callee.computed && callee.property.type === "Identifier") {
37
+ return callee.property.name === "invalidParameterError";
38
+ }
39
+ if (!callee.computed || callee.property.type !== "StringLiteral") {
43
40
  return false;
44
- return callee.property.name === "invalidParameterError";
41
+ }
42
+ return callee.property.value === "invalidParameterError";
45
43
  };
46
44
  const getInvalidParameterRename = (path) => {
47
45
  if (!isInvalidParameterErrorCallee(path.node.callee))
@@ -1,14 +1,14 @@
1
1
  {
2
- "recommended": true,
3
- "recommendedOrder": 4,
4
2
  "notes": "Stabilizes deferred top-level vars whose RHS contains only stable identifiers (globals or $h_/$f_/$v_ prefixed names). Derives names by hashing the RHS code. Complements stabilize-deferred-top-level-bindings by handling multi-var functions.",
5
3
  "evaluations": {
6
4
  "claude-code-2.1.10:claude-code-2.1.11": {
7
- "diffSizePercent": 100,
8
- "evaluatedAt": "2026-02-07T21:26:44.102Z",
9
- "changedLines": 0,
10
- "durationSeconds": 213.569470717,
11
- "stableNames": 1357
5
+ "diffSizePercent": 98.27455871791965,
6
+ "evaluatedAt": "2026-02-18T06:53:13.858Z",
7
+ "changedLines": 6008,
8
+ "durationSeconds": 43.110313000000005,
9
+ "stableNames": 1996
12
10
  }
13
- }
11
+ },
12
+ "recommended": true,
13
+ "recommendedOrder": 4
14
14
  }
@@ -5,7 +5,7 @@ import * as t from "@babel/types";
5
5
  import { getFilesToProcess, } from "../../core/types.js";
6
6
  import { generateCode } from "../../core/generate-code.js";
7
7
  import { isHashBasedStableName } from "../../core/stable-naming.js";
8
- import { findEnclosingBindingName, renameBindingInPlace, } from "../stabilize-deferred-top-level-bindings/rename-helpers.js";
8
+ import { renameBindingInPlace } from "../stabilize-deferred-top-level-bindings/rename-helpers.js";
9
9
  import { canRenameBindingSafely } from "../../transforms/shared/can-rename-binding-safely.js";
10
10
  import { hasAllStableReferences } from "./check-rhs-stability.js";
11
11
  const require = createRequire(import.meta.url);
@@ -35,7 +35,8 @@ export const stabilizeDeferredStableRhsTransform = {
35
35
  });
36
36
  if (!programScope)
37
37
  continue;
38
- const programScopeBindings = new Set(Object.keys(programScope.bindings));
38
+ const fileProgramScope = programScope;
39
+ const programScopeBindings = new Set(Object.keys(fileProgramScope.bindings));
39
40
  // Step 1: Find all uninitialized top-level vars that aren't already stable
40
41
  const uninitializedVariables = new Set();
41
42
  traverse(fileInfo.ast, {
@@ -54,7 +55,9 @@ export const stabilizeDeferredStableRhsTransform = {
54
55
  }
55
56
  },
56
57
  });
57
- // Step 2: Find assignments inside stable-named functions
58
+ // Step 2: Find assignments to those vars inside functions.
59
+ // Exclude shadowed locals by requiring the assignment target to resolve
60
+ // to the program-scope binding for that name.
58
61
  const assignments = [];
59
62
  traverse(fileInfo.ast, {
60
63
  AssignmentExpression(path) {
@@ -64,13 +67,14 @@ export const stabilizeDeferredStableRhsTransform = {
64
67
  const variableName = path.node.left.name;
65
68
  if (!uninitializedVariables.has(variableName))
66
69
  return;
70
+ const programBinding = fileProgramScope.getBinding(variableName);
71
+ if (!programBinding)
72
+ return;
73
+ if (path.scope.getBinding(variableName) !== programBinding)
74
+ return;
67
75
  const functionPath = path.findParent((p) => p.isFunction());
68
76
  if (!functionPath)
69
77
  return;
70
- const enclosingFunctionName = findEnclosingBindingName(functionPath);
71
- if (!enclosingFunctionName ||
72
- !isHashBasedStableName(enclosingFunctionName))
73
- return;
74
78
  // Check stability and capture RHS code NOW, before any renames happen.
75
79
  // This prevents order-dependent cascading where renaming one var
76
80
  // makes another var's RHS appear stable.
@@ -79,7 +83,6 @@ export const stabilizeDeferredStableRhsTransform = {
79
83
  assignments.push({
80
84
  variableName,
81
85
  rhsNode,
82
- enclosingFunctionName,
83
86
  rhsCode: isStable
84
87
  ? generate(rhsNode, { concise: true }).code
85
88
  : undefined,
@@ -1,14 +1,14 @@
1
1
  {
2
- "recommended": true,
3
- "recommendedOrder": 2,
4
2
  "notes": "Stabilizes local bindings inside CommonJS factory callbacks using content-hash naming ($f_<hash>). Must run AFTER stabilize-top-level-bindings. Combined with top-level stabilization, achieves 33.49% diff size (67% reduction from baseline).",
5
3
  "evaluations": {
6
4
  "claude-code-2.1.10:claude-code-2.1.11": {
7
- "diffSizePercent": 100,
8
- "evaluatedAt": "2026-02-07T21:15:58.445Z",
9
- "changedLines": 0,
10
- "durationSeconds": 207.29271774999998,
11
- "stableNames": 1357
5
+ "diffSizePercent": 56.44536417583248,
6
+ "evaluatedAt": "2026-02-18T06:56:26.504Z",
7
+ "changedLines": 115147,
8
+ "durationSeconds": 85.89585675000001,
9
+ "stableNames": 13284
12
10
  }
13
- }
11
+ },
12
+ "recommended": true,
13
+ "recommendedOrder": 2
14
14
  }
@@ -10,11 +10,29 @@ import { isFactoryCallback } from "./is-factory-callback.js";
10
10
  const require = createRequire(import.meta.url);
11
11
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
12
12
  const traverse = require("@babel/traverse").default;
13
- /**
14
- * Checks if a name looks like a stabilized top-level binding ($h_...)
15
- */
16
- const isStabilizedTopLevel = (name) => {
17
- return name.startsWith("$h_");
13
+ const renameCallbackLocalBindings = (path) => {
14
+ // Check if first argument is a function (the callback)
15
+ const callArguments = path.node.arguments;
16
+ if (callArguments.length === 0)
17
+ return 0;
18
+ const firstArgument = callArguments[0];
19
+ if (!t.isFunctionExpression(firstArgument) &&
20
+ !t.isArrowFunctionExpression(firstArgument))
21
+ return 0;
22
+ // Verify it looks like a callback shape this transform should process
23
+ if (!isFactoryCallback(firstArgument))
24
+ return 0;
25
+ // Get the path to the function argument
26
+ const functionArgumentPath = path.get("arguments.0");
27
+ if (!functionArgumentPath.isFunctionExpression() &&
28
+ !functionArgumentPath.isArrowFunctionExpression())
29
+ return 0;
30
+ // Skip renaming if callback contains dynamic name lookup (eval, with, etc.)
31
+ if (hasDynamicNameLookup(functionArgumentPath))
32
+ return 0;
33
+ // Collect and rename local bindings
34
+ const candidates = collectFactoryBindings(functionArgumentPath);
35
+ return applyRenames(candidates);
18
36
  };
19
37
  export const stabilizeNestedBindingsTransform = {
20
38
  id: "stabilize-nested-bindings",
@@ -29,34 +47,11 @@ export const stabilizeNestedBindingsTransform = {
29
47
  traverse(fileInfo.ast, {
30
48
  CallExpression(path) {
31
49
  nodesVisited++;
32
- // Check if callee is a stabilized top-level function ($h_...)
33
- const callee = path.node.callee;
34
- if (!t.isIdentifier(callee))
35
- return;
36
- if (!isStabilizedTopLevel(callee.name))
37
- return;
38
- // Check if first argument is a function (the factory callback)
39
- const callArguments = path.node.arguments;
40
- if (callArguments.length === 0)
41
- return;
42
- const firstArgument = callArguments[0];
43
- if (!t.isFunctionExpression(firstArgument) &&
44
- !t.isArrowFunctionExpression(firstArgument))
45
- return;
46
- // Verify it looks like a factory callback
47
- if (!isFactoryCallback(firstArgument))
48
- return;
49
- // Get the path to the function argument
50
- const functionArgumentPath = path.get("arguments.0");
51
- if (!functionArgumentPath.isFunctionExpression() &&
52
- !functionArgumentPath.isArrowFunctionExpression())
53
- return;
54
- // Skip renaming if factory contains dynamic name lookup (eval, with, etc.)
55
- if (hasDynamicNameLookup(functionArgumentPath))
56
- return;
57
- // Collect and rename local bindings
58
- const candidates = collectFactoryBindings(functionArgumentPath);
59
- fileTransformations += applyRenames(candidates);
50
+ fileTransformations += renameCallbackLocalBindings(path);
51
+ },
52
+ OptionalCallExpression(path) {
53
+ nodesVisited++;
54
+ fileTransformations += renameCallbackLocalBindings(path);
60
55
  },
61
56
  });
62
57
  transformationsApplied += fileTransformations;
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.115.0",
5
+ "version": "1.115.1",
6
6
  "description": "Transform minified JavaScript/TypeScript into a more readable form using deterministic AST-based transforms.",
7
7
  "repository": {
8
8
  "type": "git",