miniread 1.5.0 → 1.7.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 (69) hide show
  1. package/dist/core/normalize-code.d.ts +17 -0
  2. package/dist/core/normalize-code.js +35 -0
  3. package/dist/core/stable-naming.d.ts +61 -0
  4. package/dist/core/stable-naming.js +121 -0
  5. package/dist/scripts/evaluate/check-expected-evaluations.js +2 -0
  6. package/dist/scripts/evaluate/check-recommended-snapshot.d.ts +11 -0
  7. package/dist/scripts/evaluate/check-recommended-snapshot.js +53 -0
  8. package/dist/scripts/evaluate/check-snapshots.d.ts +1 -0
  9. package/dist/scripts/evaluate/check-snapshots.js +21 -2
  10. package/dist/scripts/evaluate/transform-content.d.ts +5 -0
  11. package/dist/scripts/evaluate/transform-content.js +23 -13
  12. package/dist/transforms/rename-catch-parameters/rename-catch-parameters-transform.js +15 -38
  13. package/dist/transforms/rename-destructured-aliases/rename-destructured-aliases-transform.js +13 -12
  14. package/dist/transforms/rename-event-parameters/process-event-handler-function.d.ts +2 -3
  15. package/dist/transforms/rename-event-parameters/process-event-handler-function.js +13 -9
  16. package/dist/transforms/rename-event-parameters/rename-event-parameters-transform.d.ts +1 -1
  17. package/dist/transforms/rename-event-parameters/rename-event-parameters-transform.js +10 -7
  18. package/dist/transforms/rename-loop-index-variables/rename-loop-index-variables-transform.js +19 -13
  19. package/dist/transforms/rename-promise-executor-parameters/rename-promise-executor-parameters-transform.js +12 -5
  20. package/dist/transforms/rename-timeout-ids/rename-timeout-ids-transform.d.ts +1 -1
  21. package/dist/transforms/rename-timeout-ids/rename-timeout-ids-transform.js +10 -11
  22. package/dist/transforms/rename-use-reference-guards/rename-use-reference-guards-transform.js +10 -11
  23. package/dist/transforms/rename-use-reference-guards-v2/get-member-expression-for-reference.d.ts +3 -0
  24. package/dist/transforms/rename-use-reference-guards-v2/get-member-expression-for-reference.js +10 -0
  25. package/dist/transforms/rename-use-reference-guards-v2/get-reference-usage.d.ts +8 -0
  26. package/dist/transforms/rename-use-reference-guards-v2/get-reference-usage.js +58 -0
  27. package/dist/transforms/rename-use-reference-guards-v2/is-use-reference-false-initializer.d.ts +2 -0
  28. package/dist/transforms/rename-use-reference-guards-v2/is-use-reference-false-initializer.js +40 -0
  29. package/dist/transforms/rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.d.ts +3 -0
  30. package/dist/transforms/rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.js +54 -0
  31. package/dist/transforms/transform-registry.js +2 -10
  32. package/package.json +1 -1
  33. package/transform-manifest.json +15 -55
  34. package/dist/transforms/expand-return-sequence/expand-return-sequence-transform.d.ts +0 -2
  35. package/dist/transforms/expand-return-sequence/expand-return-sequence-transform.js +0 -91
  36. package/dist/transforms/expand-sequence-expressions/expand-expression-statement-sequence.d.ts +0 -3
  37. package/dist/transforms/expand-sequence-expressions/expand-expression-statement-sequence.js +0 -57
  38. package/dist/transforms/expand-sequence-expressions/expand-sequence-expressions-transform.d.ts +0 -2
  39. package/dist/transforms/expand-sequence-expressions/expand-sequence-expressions-transform.js +0 -34
  40. package/dist/transforms/expand-sequence-expressions/expand-variable-declaration-sequence.d.ts +0 -3
  41. package/dist/transforms/expand-sequence-expressions/expand-variable-declaration-sequence.js +0 -93
  42. package/dist/transforms/expand-sequence-expressions-v2/expand-expression-statement-sequence.d.ts +0 -3
  43. package/dist/transforms/expand-sequence-expressions-v2/expand-expression-statement-sequence.js +0 -55
  44. package/dist/transforms/expand-sequence-expressions-v2/expand-return-sequence.d.ts +0 -3
  45. package/dist/transforms/expand-sequence-expressions-v2/expand-return-sequence.js +0 -86
  46. package/dist/transforms/expand-sequence-expressions-v2/expand-sequence-expressions-v2-transform.d.ts +0 -2
  47. package/dist/transforms/expand-sequence-expressions-v2/expand-sequence-expressions-v2-transform.js +0 -41
  48. package/dist/transforms/expand-sequence-expressions-v2/expand-variable-declaration-sequence.d.ts +0 -3
  49. package/dist/transforms/expand-sequence-expressions-v2/expand-variable-declaration-sequence.js +0 -93
  50. package/dist/transforms/expand-sequence-expressions-v3/expand-expression-statement-sequence.d.ts +0 -3
  51. package/dist/transforms/expand-sequence-expressions-v3/expand-expression-statement-sequence.js +0 -64
  52. package/dist/transforms/expand-sequence-expressions-v3/expand-return-sequence.d.ts +0 -3
  53. package/dist/transforms/expand-sequence-expressions-v3/expand-return-sequence.js +0 -91
  54. package/dist/transforms/expand-sequence-expressions-v3/expand-sequence-expressions-v3-transform.d.ts +0 -2
  55. package/dist/transforms/expand-sequence-expressions-v3/expand-sequence-expressions-v3-transform.js +0 -48
  56. package/dist/transforms/expand-sequence-expressions-v3/expand-throw-sequence.d.ts +0 -3
  57. package/dist/transforms/expand-sequence-expressions-v3/expand-throw-sequence.js +0 -101
  58. package/dist/transforms/expand-sequence-expressions-v3/expand-variable-declaration-sequence.d.ts +0 -3
  59. package/dist/transforms/expand-sequence-expressions-v3/expand-variable-declaration-sequence.js +0 -99
  60. package/dist/transforms/expand-throw-sequence/expand-throw-sequence-transform.d.ts +0 -2
  61. package/dist/transforms/expand-throw-sequence/expand-throw-sequence-transform.js +0 -117
  62. package/dist/transforms/rename-binding/get-target-name.d.ts +0 -4
  63. package/dist/transforms/rename-binding/get-target-name.js +0 -25
  64. package/dist/transforms/rename-binding/is-valid-binding-identifier.d.ts +0 -1
  65. package/dist/transforms/rename-binding/is-valid-binding-identifier.js +0 -10
  66. package/dist/transforms/rename-use-reference-guards/get-target-name.d.ts +0 -2
  67. package/dist/transforms/rename-use-reference-guards/get-target-name.js +0 -23
  68. package/dist/transforms/rename-use-reference-guards/is-valid-binding-identifier.d.ts +0 -1
  69. package/dist/transforms/rename-use-reference-guards/is-valid-binding-identifier.js +0 -10
@@ -1,4 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
+ import { RenameGroup } from "../../core/stable-naming.js";
3
+ import { getFilesToProcess, } from "../../core/types.js";
2
4
  import { processEventHandlerFunction } from "./process-event-handler-function.js";
3
5
  const require = createRequire(import.meta.url);
4
6
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
@@ -9,28 +11,29 @@ export const renameEventParametersTransform = {
9
11
  scope: "file",
10
12
  parallelizable: true,
11
13
  transform(context) {
12
- const { projectGraph } = context;
13
14
  let nodesVisited = 0;
14
- const stats = { transformationsApplied: 0 };
15
- for (const [, fileInfo] of projectGraph.files) {
15
+ let transformationsApplied = 0;
16
+ for (const fileInfo of getFilesToProcess(context)) {
17
+ const group = new RenameGroup();
16
18
  traverse(fileInfo.ast, {
17
19
  FunctionDeclaration(path) {
18
20
  nodesVisited++;
19
- processEventHandlerFunction(path, stats);
21
+ processEventHandlerFunction(path, group);
20
22
  },
21
23
  FunctionExpression(path) {
22
24
  nodesVisited++;
23
- processEventHandlerFunction(path, stats);
25
+ processEventHandlerFunction(path, group);
24
26
  },
25
27
  ArrowFunctionExpression(path) {
26
28
  nodesVisited++;
27
- processEventHandlerFunction(path, stats);
29
+ processEventHandlerFunction(path, group);
28
30
  },
29
31
  });
32
+ transformationsApplied += group.apply();
30
33
  }
31
34
  return Promise.resolve({
32
35
  nodesVisited,
33
- transformationsApplied: stats.transformationsApplied,
36
+ transformationsApplied,
34
37
  });
35
38
  },
36
39
  };
@@ -1,4 +1,5 @@
1
1
  import { createRequire } from "node:module";
2
+ import { isStableRenamed, RenameGroup } from "../../core/stable-naming.js";
2
3
  import { getFilesToProcess, } from "../../core/types.js";
3
4
  const require = createRequire(import.meta.url);
4
5
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
@@ -15,10 +16,11 @@ const getRenamedAncestorLoopCount = (path, renamedLoops) => {
15
16
  }
16
17
  return count;
17
18
  };
18
- const getTargetIndexName = (renamedAncestorLoopCount) => {
19
+ const BASE_NAME = "index";
20
+ const getTargetIndexBaseName = (renamedAncestorLoopCount) => {
19
21
  if (renamedAncestorLoopCount === 0)
20
- return "index";
21
- return `index${renamedAncestorLoopCount + 1}`;
22
+ return BASE_NAME;
23
+ return `${BASE_NAME}${renamedAncestorLoopCount + 1}`;
22
24
  };
23
25
  const getLoopCounterNameIfEligible = (path) => {
24
26
  const init = path.node.init;
@@ -91,31 +93,35 @@ const getLoopCounterNameIfEligible = (path) => {
91
93
  };
92
94
  export const renameLoopIndexVariablesTransform = {
93
95
  id: "rename-loop-index-variables",
94
- description: "Renames numeric for-loop counters to index/index2/... based on nesting depth",
96
+ description: "Renames numeric for-loop counters to $index/$index2/... based on nesting depth",
95
97
  scope: "file",
96
98
  parallelizable: true,
97
99
  transform(context) {
98
100
  let nodesVisited = 0;
99
101
  let transformationsApplied = 0;
100
102
  for (const fileInfo of getFilesToProcess(context)) {
101
- const renamedLoops = new WeakMap();
103
+ const group = new RenameGroup();
104
+ const eligibleLoops = new WeakMap();
102
105
  traverse(fileInfo.ast, {
103
106
  ForStatement(path) {
104
107
  nodesVisited++;
105
108
  const loopCounterName = getLoopCounterNameIfEligible(path);
106
109
  if (!loopCounterName)
107
110
  return;
108
- const renamedAncestorLoopCount = getRenamedAncestorLoopCount(path, renamedLoops);
109
- const targetName = getTargetIndexName(renamedAncestorLoopCount);
110
- if (loopCounterName === targetName)
111
+ // Skip already-stable names
112
+ if (isStableRenamed(loopCounterName))
111
113
  return;
112
- if (path.scope.hasBinding(targetName))
113
- return;
114
- path.scope.rename(loopCounterName, targetName);
115
- renamedLoops.set(path.node, targetName);
116
- transformationsApplied++;
114
+ const renamedAncestorLoopCount = getRenamedAncestorLoopCount(path, eligibleLoops);
115
+ const baseName = getTargetIndexBaseName(renamedAncestorLoopCount);
116
+ eligibleLoops.set(path.node, baseName);
117
+ group.add({
118
+ scope: path.scope,
119
+ currentName: loopCounterName,
120
+ baseName,
121
+ });
117
122
  },
118
123
  });
124
+ transformationsApplied += group.apply();
119
125
  }
120
126
  return Promise.resolve({
121
127
  nodesVisited,
@@ -1,13 +1,15 @@
1
1
  import { createRequire } from "node:module";
2
+ import { isStableRenamed } from "../../core/stable-naming.js";
2
3
  import { getFilesToProcess, } from "../../core/types.js";
3
4
  import { getExecutorFunctionIfEligible, isAssignedToOnHandlerProperty, isDirectCallOfBinding, wouldShadowReferencedOuterBinding, } from "./promise-executor-heuristics.js";
4
5
  import { canRenameBindingSafely, renameBindingIfSafe, } from "./rename-binding-if-safe.js";
6
+ const STABLE_PREFIX = "$";
5
7
  const require = createRequire(import.meta.url);
6
8
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
7
9
  const traverse = require("@babel/traverse").default;
8
10
  export const renamePromiseExecutorParametersTransform = {
9
11
  id: "rename-promise-executor-parameters",
10
- description: "Renames promise-like executor parameters in `new X(executor)` to resolve/reject when usage is high-confidence",
12
+ description: "Renames promise-like executor parameters in `new X(executor)` to $resolve/$reject when usage is high-confidence",
11
13
  scope: "file",
12
14
  parallelizable: true,
13
15
  transform(context) {
@@ -22,6 +24,11 @@ export const renamePromiseExecutorParametersTransform = {
22
24
  return;
23
25
  const [resolveParameter, rejectParameter] = executorPath.node
24
26
  .params;
27
+ // Skip already-stable names
28
+ if (isStableRenamed(resolveParameter.name))
29
+ return;
30
+ if (isStableRenamed(rejectParameter.name))
31
+ return;
25
32
  const bindingScope = executorPath.scope;
26
33
  const resolveBinding = bindingScope.getBinding(resolveParameter.name);
27
34
  const rejectBinding = bindingScope.getBinding(rejectParameter.name);
@@ -41,10 +48,10 @@ export const renamePromiseExecutorParametersTransform = {
41
48
  isAssignedToOnHandlerProperty(referencePath));
42
49
  if (!rejectIsOnlyCalledOrHandlerAssigned)
43
50
  return;
44
- const resolveWouldShadow = wouldShadowReferencedOuterBinding(executorPath, "resolve");
45
- const rejectWouldShadow = wouldShadowReferencedOuterBinding(executorPath, "reject");
46
- const targetResolveName = "resolve";
47
- const targetRejectName = "reject";
51
+ const targetResolveName = `${STABLE_PREFIX}resolve`;
52
+ const targetRejectName = `${STABLE_PREFIX}reject`;
53
+ const resolveWouldShadow = wouldShadowReferencedOuterBinding(executorPath, targetResolveName);
54
+ const rejectWouldShadow = wouldShadowReferencedOuterBinding(executorPath, targetRejectName);
48
55
  const wantsResolveRename = resolveParameter.name !== targetResolveName;
49
56
  const wantsRejectRename = rejectParameter.name !== targetRejectName;
50
57
  const canRenameResolve = !wantsResolveRename ||
@@ -1,2 +1,2 @@
1
- import type { Transform } from "../../core/types.js";
1
+ import { type Transform } from "../../core/types.js";
2
2
  export declare const renameTimeoutIdsTransform: Transform;
@@ -1,6 +1,6 @@
1
1
  import { createRequire } from "node:module";
2
- import { getFilesToProcess } from "../../core/types.js";
3
- import { getTargetName } from "../rename-binding/get-target-name.js";
2
+ import { isStableRenamed, RenameGroup } from "../../core/stable-naming.js";
3
+ import { getFilesToProcess, } from "../../core/types.js";
4
4
  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;
@@ -40,20 +40,22 @@ const isClearTimeoutCallArgument = (referencePath, bindingName) => {
40
40
  };
41
41
  export const renameTimeoutIdsTransform = {
42
42
  id: "rename-timeout-ids",
43
- description: "Renames setTimeout handle variables to timeoutId/timeoutId2/... when usage is only clearTimeout(...)",
43
+ description: "Renames setTimeout handle variables to $timeoutId/$timeoutId2/... or timeoutId/timeoutId2/... when usage is only clearTimeout(...)",
44
44
  scope: "file",
45
45
  parallelizable: true,
46
46
  transform(context) {
47
47
  let nodesVisited = 0;
48
48
  let transformationsApplied = 0;
49
49
  for (const fileInfo of getFilesToProcess(context)) {
50
+ const group = new RenameGroup();
50
51
  traverse(fileInfo.ast, {
51
52
  VariableDeclarator(path) {
52
53
  nodesVisited++;
53
54
  const id = path.node.id;
54
55
  if (id.type !== "Identifier")
55
56
  return;
56
- if (id.name.length > 2)
57
+ // Skip already-stable names
58
+ if (isStableRenamed(id.name))
57
59
  return;
58
60
  const init = path.node.init;
59
61
  if (init?.type !== "CallExpression")
@@ -69,17 +71,14 @@ export const renameTimeoutIdsTransform = {
69
71
  return;
70
72
  if (!binding.referencePaths.every((referencePath) => isClearTimeoutCallArgument(referencePath, id.name)))
71
73
  return;
72
- const targetName = getTargetName(path.scope, binding, {
74
+ group.add({
75
+ scope: path.scope,
76
+ currentName: id.name,
73
77
  baseName: BASE_NAME,
74
78
  });
75
- if (!targetName)
76
- return;
77
- if (id.name === targetName)
78
- return;
79
- path.scope.rename(id.name, targetName);
80
- transformationsApplied++;
81
79
  },
82
80
  });
81
+ transformationsApplied += group.apply();
83
82
  }
84
83
  return Promise.resolve({ nodesVisited, transformationsApplied });
85
84
  },
@@ -1,28 +1,28 @@
1
1
  import { createRequire } from "node:module";
2
+ import { RenameGroup } from "../../core/stable-naming.js";
2
3
  import { getFilesToProcess, } from "../../core/types.js";
3
4
  import { getReferenceUsage } from "./get-reference-usage.js";
4
- import { getTargetName } from "./get-target-name.js";
5
5
  import { isUseReferenceFalseInitializer } from "./is-use-reference-false-initializer.js";
6
6
  const require = createRequire(import.meta.url);
7
7
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
8
8
  const traverse = require("@babel/traverse").default;
9
+ const BASE_NAME = "hasRunRef";
9
10
  const renameUseReferenceGuardsTransform = {
10
11
  id: "rename-use-reference-guards",
11
- description: "Renames boolean useRef(false) guard variables to hasRunRef/hasRunRef2/...",
12
+ description: "Renames boolean useRef(false) guard variables to $hasRunRef/$hasRunRef2/... or hasRunRef/hasRunRef2/...",
12
13
  scope: "file",
13
14
  parallelizable: true,
14
15
  transform(context) {
15
16
  let nodesVisited = 0;
16
17
  let transformationsApplied = 0;
17
18
  for (const fileInfo of getFilesToProcess(context)) {
19
+ const group = new RenameGroup();
18
20
  traverse(fileInfo.ast, {
19
21
  VariableDeclarator(path) {
20
22
  nodesVisited++;
21
23
  const id = path.node.id;
22
24
  if (id.type !== "Identifier")
23
25
  return;
24
- if (id.name.length > 2)
25
- return;
26
26
  if (!isUseReferenceFalseInitializer(path.node))
27
27
  return;
28
28
  const binding = path.scope.getBinding(id.name);
@@ -36,15 +36,14 @@ const renameUseReferenceGuardsTransform = {
36
36
  !usage.hasTrueWrite ||
37
37
  usage.hasFalseWrite)
38
38
  return;
39
- const targetName = getTargetName(path.scope, binding);
40
- if (!targetName)
41
- return;
42
- if (id.name === targetName)
43
- return;
44
- path.scope.rename(id.name, targetName);
45
- transformationsApplied++;
39
+ group.add({
40
+ scope: path.scope,
41
+ currentName: id.name,
42
+ baseName: BASE_NAME,
43
+ });
46
44
  },
47
45
  });
46
+ transformationsApplied += group.apply();
48
47
  }
49
48
  return Promise.resolve({
50
49
  nodesVisited,
@@ -0,0 +1,3 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type { Identifier, MemberExpression, OptionalMemberExpression } from "@babel/types";
3
+ export declare const getMemberExpressionForReference: (referencePath: NodePath<Identifier>) => NodePath<MemberExpression | OptionalMemberExpression> | undefined;
@@ -0,0 +1,10 @@
1
+ export const getMemberExpressionForReference = (referencePath) => {
2
+ const parentPath = referencePath.parentPath;
3
+ if (parentPath.isMemberExpression() &&
4
+ parentPath.node.object === referencePath.node)
5
+ return parentPath;
6
+ if (parentPath.isOptionalMemberExpression() &&
7
+ parentPath.node.object === referencePath.node)
8
+ return parentPath;
9
+ return;
10
+ };
@@ -0,0 +1,8 @@
1
+ import type { Binding } from "@babel/traverse";
2
+ type ReferenceUsage = {
3
+ isSafe: boolean;
4
+ hasRead: boolean;
5
+ hasTrueWrite: boolean;
6
+ };
7
+ export declare const getReferenceUsage: (binding: Binding) => ReferenceUsage;
8
+ export {};
@@ -0,0 +1,58 @@
1
+ import { getMemberExpressionForReference } from "./get-member-expression-for-reference.js";
2
+ const getKnownBooleanValue = (expression) => {
3
+ if (expression.type === "BooleanLiteral")
4
+ return expression.value;
5
+ if (expression.type === "UnaryExpression" &&
6
+ expression.operator === "!" &&
7
+ expression.argument.type === "NumericLiteral" &&
8
+ (expression.argument.value === 0 || expression.argument.value === 1)) {
9
+ return !expression.argument.value;
10
+ }
11
+ return;
12
+ };
13
+ export const getReferenceUsage = (binding) => {
14
+ let hasRead = false;
15
+ let hasTrueWrite = false;
16
+ for (const referencePath of binding.referencePaths) {
17
+ if (!referencePath.isIdentifier())
18
+ return { isSafe: false, hasRead, hasTrueWrite };
19
+ const memberPath = getMemberExpressionForReference(referencePath);
20
+ if (!memberPath)
21
+ return { isSafe: false, hasRead, hasTrueWrite };
22
+ const memberNode = memberPath.node;
23
+ if (memberNode.computed)
24
+ return { isSafe: false, hasRead, hasTrueWrite };
25
+ if (memberNode.property.type !== "Identifier" ||
26
+ memberNode.property.name !== "current") {
27
+ return { isSafe: false, hasRead, hasTrueWrite };
28
+ }
29
+ const parentPath = memberPath.parentPath;
30
+ if (parentPath.isAssignmentExpression() &&
31
+ parentPath.node.left === memberNode) {
32
+ if (parentPath.node.operator !== "=")
33
+ return { isSafe: false, hasRead, hasTrueWrite };
34
+ const right = parentPath.node.right;
35
+ const value = getKnownBooleanValue(right);
36
+ if (value === undefined)
37
+ return { isSafe: false, hasRead, hasTrueWrite };
38
+ if (value) {
39
+ hasTrueWrite = true;
40
+ }
41
+ continue;
42
+ }
43
+ if (parentPath.isUpdateExpression() &&
44
+ parentPath.node.argument === memberNode) {
45
+ return { isSafe: false, hasRead, hasTrueWrite };
46
+ }
47
+ if (parentPath.isUnaryExpression() &&
48
+ parentPath.node.operator === "delete" &&
49
+ parentPath.node.argument === memberNode) {
50
+ return { isSafe: false, hasRead, hasTrueWrite };
51
+ }
52
+ if (!memberPath.isReferenced()) {
53
+ return { isSafe: false, hasRead, hasTrueWrite };
54
+ }
55
+ hasRead = true;
56
+ }
57
+ return { isSafe: true, hasRead, hasTrueWrite };
58
+ };
@@ -0,0 +1,2 @@
1
+ import type { VariableDeclarator } from "@babel/types";
2
+ export declare const isUseReferenceFalseInitializer: (declarator: VariableDeclarator) => boolean;
@@ -0,0 +1,40 @@
1
+ const isKnownFalseValue = (expression) => {
2
+ if (expression.type === "BooleanLiteral")
3
+ return !expression.value;
4
+ if (expression.type === "UnaryExpression" &&
5
+ expression.operator === "!" &&
6
+ expression.argument.type === "NumericLiteral" &&
7
+ expression.argument.value === 1) {
8
+ return true;
9
+ }
10
+ return false;
11
+ };
12
+ export const isUseReferenceFalseInitializer = (declarator) => {
13
+ const init = declarator.init;
14
+ if (!init)
15
+ return false;
16
+ if (init.type !== "CallExpression")
17
+ return false;
18
+ if (init.arguments.length !== 1)
19
+ return false;
20
+ const argument = init.arguments[0];
21
+ if (!argument)
22
+ return false;
23
+ if (argument.type === "SpreadElement")
24
+ return false;
25
+ if (argument.type === "ArgumentPlaceholder")
26
+ return false;
27
+ if (!isKnownFalseValue(argument))
28
+ return false;
29
+ const callee = init.callee;
30
+ if (callee.type === "Identifier") {
31
+ return callee.name === "useRef";
32
+ }
33
+ if (callee.type !== "MemberExpression")
34
+ return false;
35
+ if (callee.computed)
36
+ return false;
37
+ if (callee.property.type !== "Identifier")
38
+ return false;
39
+ return callee.property.name === "useRef";
40
+ };
@@ -0,0 +1,3 @@
1
+ import { type Transform } from "../../core/types.js";
2
+ declare const renameUseReferenceGuardsV2Transform: Transform;
3
+ export { renameUseReferenceGuardsV2Transform };
@@ -0,0 +1,54 @@
1
+ import { createRequire } from "node:module";
2
+ import { isStableRenamed, RenameGroup } from "../../core/stable-naming.js";
3
+ import { getFilesToProcess, } from "../../core/types.js";
4
+ import { getReferenceUsage } from "./get-reference-usage.js";
5
+ import { isUseReferenceFalseInitializer } from "./is-use-reference-false-initializer.js";
6
+ const require = createRequire(import.meta.url);
7
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
8
+ const traverse = require("@babel/traverse").default;
9
+ const BASE_NAME = "hasRunRef";
10
+ const renameUseReferenceGuardsV2Transform = {
11
+ id: "rename-use-reference-guards-v2",
12
+ description: "Renames boolean useRef(false) guard variables (including reset-to-false guards) to $hasRunRef/$hasRunRef2/... or hasRunRef/hasRunRef2/...",
13
+ scope: "file",
14
+ parallelizable: true,
15
+ transform(context) {
16
+ let nodesVisited = 0;
17
+ let transformationsApplied = 0;
18
+ for (const fileInfo of getFilesToProcess(context)) {
19
+ const group = new RenameGroup();
20
+ traverse(fileInfo.ast, {
21
+ VariableDeclarator(path) {
22
+ nodesVisited++;
23
+ const id = path.node.id;
24
+ if (id.type !== "Identifier")
25
+ return;
26
+ if (isStableRenamed(id.name))
27
+ return;
28
+ if (!isUseReferenceFalseInitializer(path.node))
29
+ return;
30
+ const binding = path.scope.getBinding(id.name);
31
+ if (!binding)
32
+ return;
33
+ if (!binding.constant)
34
+ return;
35
+ const usage = getReferenceUsage(binding);
36
+ // Unlike v1, this version also accepts guards that reset to false
37
+ if (!usage.isSafe || !usage.hasRead || !usage.hasTrueWrite)
38
+ return;
39
+ group.add({
40
+ scope: path.scope,
41
+ currentName: id.name,
42
+ baseName: BASE_NAME,
43
+ });
44
+ },
45
+ });
46
+ transformationsApplied += group.apply();
47
+ }
48
+ return Promise.resolve({
49
+ nodesVisited,
50
+ transformationsApplied,
51
+ });
52
+ },
53
+ };
54
+ export { renameUseReferenceGuardsV2Transform };
@@ -1,11 +1,6 @@
1
1
  import { expandBooleanLiteralsTransform } from "./expand-boolean-literals/expand-boolean-literals-transform.js";
2
- import { expandReturnSequenceTransform } from "./expand-return-sequence/expand-return-sequence-transform.js";
3
- import { expandSequenceExpressionsTransform } from "./expand-sequence-expressions/expand-sequence-expressions-transform.js";
4
- import { expandSequenceExpressionsV2Transform } from "./expand-sequence-expressions-v2/expand-sequence-expressions-v2-transform.js";
5
2
  import { expandSpecialNumberLiteralsTransform } from "./expand-special-number-literals/expand-special-number-literals-transform.js";
6
- import { expandSequenceExpressionsV3Transform } from "./expand-sequence-expressions-v3/expand-sequence-expressions-v3-transform.js";
7
3
  import { expandSequenceExpressionsV4Transform } from "./expand-sequence-expressions-v4/expand-sequence-expressions-v4-transform.js";
8
- import { expandThrowSequenceTransform } from "./expand-throw-sequence/expand-throw-sequence-transform.js";
9
4
  import { expandUndefinedLiteralsTransform } from "./expand-undefined-literals/expand-undefined-literals-transform.js";
10
5
  import { renameCatchParametersTransform } from "./rename-catch-parameters/rename-catch-parameters-transform.js";
11
6
  import { renameDestructuredAliasesTransform } from "./rename-destructured-aliases/rename-destructured-aliases-transform.js";
@@ -14,16 +9,12 @@ import { renameLoopIndexVariablesTransform } from "./rename-loop-index-variables
14
9
  import { renamePromiseExecutorParametersTransform } from "./rename-promise-executor-parameters/rename-promise-executor-parameters-transform.js";
15
10
  import { renameTimeoutIdsTransform } from "./rename-timeout-ids/rename-timeout-ids-transform.js";
16
11
  import { renameUseReferenceGuardsTransform } from "./rename-use-reference-guards/rename-use-reference-guards-transform.js";
12
+ import { renameUseReferenceGuardsV2Transform } from "./rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.js";
17
13
  import { splitVariableDeclarationsTransform } from "./split-variable-declarations/split-variable-declarations-transform.js";
18
14
  export const transformRegistry = {
19
15
  [expandBooleanLiteralsTransform.id]: expandBooleanLiteralsTransform,
20
- [expandReturnSequenceTransform.id]: expandReturnSequenceTransform,
21
- [expandSequenceExpressionsTransform.id]: expandSequenceExpressionsTransform,
22
- [expandSequenceExpressionsV2Transform.id]: expandSequenceExpressionsV2Transform,
23
- [expandSequenceExpressionsV3Transform.id]: expandSequenceExpressionsV3Transform,
24
16
  [expandSpecialNumberLiteralsTransform.id]: expandSpecialNumberLiteralsTransform,
25
17
  [expandSequenceExpressionsV4Transform.id]: expandSequenceExpressionsV4Transform,
26
- [expandThrowSequenceTransform.id]: expandThrowSequenceTransform,
27
18
  [expandUndefinedLiteralsTransform.id]: expandUndefinedLiteralsTransform,
28
19
  [renameCatchParametersTransform.id]: renameCatchParametersTransform,
29
20
  [renameDestructuredAliasesTransform.id]: renameDestructuredAliasesTransform,
@@ -32,6 +23,7 @@ export const transformRegistry = {
32
23
  [renamePromiseExecutorParametersTransform.id]: renamePromiseExecutorParametersTransform,
33
24
  [renameTimeoutIdsTransform.id]: renameTimeoutIdsTransform,
34
25
  [renameUseReferenceGuardsTransform.id]: renameUseReferenceGuardsTransform,
26
+ [renameUseReferenceGuardsV2Transform.id]: renameUseReferenceGuardsV2Transform,
35
27
  [splitVariableDeclarationsTransform.id]: splitVariableDeclarationsTransform,
36
28
  };
37
29
  export const allTransformIds = Object.keys(transformRegistry);
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.0",
5
+ "version": "1.7.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",
@@ -59,46 +59,6 @@
59
59
  "evaluatedAt": "2026-01-22T12:49:10.952Z",
60
60
  "notes": "Auto-added by evaluation script. Measured with baseline none: 0.09%."
61
61
  },
62
- {
63
- "id": "expand-return-sequence",
64
- "description": "Expands return sequences like `return a(), b();`",
65
- "scope": "file",
66
- "parallelizable": true,
67
- "diffReductionImpact": -0.0012834789830316051,
68
- "recommended": false,
69
- "evaluatedAt": "2026-01-22T15:19:04.615Z",
70
- "notes": "Auto-added by evaluation script. Measured with baseline none: -0.13%. Superseded by expand-sequence-expressions-v2 in the recommended preset."
71
- },
72
- {
73
- "id": "expand-sequence-expressions",
74
- "description": "Expands comma operator sequences in statements and variable initializers",
75
- "scope": "file",
76
- "parallelizable": true,
77
- "diffReductionImpact": -0.01282535248485317,
78
- "recommended": false,
79
- "evaluatedAt": "2026-01-22T17:15:48.528Z",
80
- "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."
81
- },
82
- {
83
- "id": "expand-sequence-expressions-v2",
84
- "description": "Expands comma operator sequences in returns, statements, and variable initializers",
85
- "scope": "file",
86
- "parallelizable": true,
87
- "diffReductionImpact": -0.014316453068081048,
88
- "recommended": false,
89
- "evaluatedAt": "2026-01-22T18:22:48.609Z",
90
- "notes": "Superseded by expand-sequence-expressions-v3."
91
- },
92
- {
93
- "id": "expand-sequence-expressions-v3",
94
- "description": "Expands comma operator sequences in returns, throws, statements, and variable initializers",
95
- "scope": "file",
96
- "parallelizable": true,
97
- "diffReductionImpact": -0.014391951831788763,
98
- "recommended": false,
99
- "evaluatedAt": "2026-01-23T08:21:23.662Z",
100
- "notes": "Supersedes expand-sequence-expressions-v2 in the recommended preset. Measured with baseline none: -1.44%. Enabled for readability even when line diffs increase."
101
- },
102
62
  {
103
63
  "id": "expand-sequence-expressions-v4",
104
64
  "description": "Expands comma operator sequences in returns, throws, statements (including control-flow bodies), and variable initializers",
@@ -107,7 +67,7 @@
107
67
  "diffReductionImpact": -0.01730809158000035,
108
68
  "recommended": true,
109
69
  "evaluatedAt": "2026-01-23T10:57:45.082Z",
110
- "notes": "Measured with baseline none: -1.73%. Supersedes expand-sequence-expressions-v3 and includes control-flow-body expansion."
70
+ "notes": "Measured with baseline none: -1.73%. Supersedes all prior sequence expression transforms."
111
71
  },
112
72
  {
113
73
  "id": "rename-use-reference-guards",
@@ -115,9 +75,19 @@
115
75
  "scope": "file",
116
76
  "parallelizable": true,
117
77
  "diffReductionImpact": 0,
118
- "recommended": true,
78
+ "recommended": false,
119
79
  "evaluatedAt": "2026-01-22T17:03:19.826Z",
120
- "notes": "Auto-added by evaluation script."
80
+ "notes": "Superseded by rename-use-reference-guards-v2.",
81
+ "supersededBy": "rename-use-reference-guards-v2"
82
+ },
83
+ {
84
+ "id": "rename-use-reference-guards-v2",
85
+ "description": "Renames boolean useRef(false) guard variables (including reset-to-false guards) to hasRunRef/hasRunRef2/...",
86
+ "scope": "file",
87
+ "parallelizable": true,
88
+ "diffReductionImpact": 0,
89
+ "recommended": true,
90
+ "notes": "Supersedes rename-use-reference-guards and also covers guards that reset to false."
121
91
  },
122
92
  {
123
93
  "id": "rename-timeout-ids",
@@ -125,9 +95,9 @@
125
95
  "scope": "file",
126
96
  "parallelizable": true,
127
97
  "diffReductionImpact": 0.00003774938185385768,
128
- "recommended": false,
98
+ "recommended": true,
129
99
  "evaluatedAt": "2026-01-23T10:29:23.279Z",
130
- "notes": "Measured with baseline none: 0.00%. Not enabled by default (readability-only)."
100
+ "notes": "Measured with baseline none: 0.00%. Added to recommended for readability."
131
101
  },
132
102
  {
133
103
  "id": "split-variable-declarations",
@@ -139,16 +109,6 @@
139
109
  "evaluatedAt": "2026-01-23T05:45:27.981Z",
140
110
  "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."
141
111
  },
142
- {
143
- "id": "expand-throw-sequence",
144
- "description": "Expands throw sequences like `throw (a(), b)`",
145
- "scope": "file",
146
- "parallelizable": true,
147
- "diffReductionImpact": -0.00007549876370771536,
148
- "recommended": false,
149
- "evaluatedAt": "2026-01-23T07:48:29.356Z",
150
- "notes": "Largely superseded by expand-sequence-expressions-v3 (which also expands throw sequences), but kept for isolated runs and comparison."
151
- },
152
112
  {
153
113
  "id": "rename-promise-executor-parameters",
154
114
  "description": "Renames promise-like executor parameters in `new X(executor)` to resolve/reject when usage is high-confidence",
@@ -1,2 +0,0 @@
1
- import { type Transform } from "../../core/types.js";
2
- export declare const expandReturnSequenceTransform: Transform;