miniread 1.112.0 → 1.114.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/transforms/_generated/catalog.js +7 -0
- package/dist/transforms/preset-stats.json +1 -1
- package/dist/transforms-by-id/rename-array-accumulator-variables/manifest.json +5 -5
- package/dist/transforms-by-id/rename-array-accumulator-variables/rename-array-accumulator-variables-transform.js +14 -12
- package/dist/transforms-by-id/rename-command-result-variables/manifest.json +2 -2
- package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/deferred-executor-heuristics.d.ts +2 -1
- package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/deferred-executor-heuristics.js +22 -8
- package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/manifest.json +4 -4
- package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/rename-deferred-resolve-parameters-v2-transform.js +16 -15
- package/dist/transforms-by-id/rename-git-command-results/manifest.json +13 -0
- package/dist/transforms-by-id/rename-git-command-results/rename-git-command-results-transform.d.ts +2 -0
- package/dist/transforms-by-id/rename-git-command-results/rename-git-command-results-transform.js +110 -0
- package/dist/transforms-by-id/rename-promise-executor-parameters-v2/get-promise-executor-rename-plan.d.ts +2 -2
- package/dist/transforms-by-id/rename-promise-executor-parameters-v2/get-promise-executor-rename-plan.js +41 -27
- package/dist/transforms-by-id/rename-promise-executor-parameters-v2/manifest.json +3 -3
- package/dist/transforms-by-id/rename-promise-executor-parameters-v2/promise-executor-heuristics.js +3 -3
- package/dist/transforms-by-id/rename-promise-executor-parameters-v2/rename-promise-executor-parameters-v2-transform.js +4 -0
- package/dist/transforms-by-id/rename-timeout-ids/manifest.json +9 -9
- package/dist/transforms-by-id/rename-timeout-ids/rename-timeout-ids-transform.js +44 -21
- package/package.json +1 -1
|
@@ -74,6 +74,8 @@ import { renameFileReaderVariablesTransform } from "../../transforms-by-id/renam
|
|
|
74
74
|
import renameFileReaderVariablesManifest from "../../transforms-by-id/rename-file-reader-variables/manifest.json" with { type: "json" };
|
|
75
75
|
import { renameFsSyncVariablesTransform } from "../../transforms-by-id/rename-fs-sync-variables/rename-fs-sync-variables-transform.js";
|
|
76
76
|
import renameFsSyncVariablesManifest from "../../transforms-by-id/rename-fs-sync-variables/manifest.json" with { type: "json" };
|
|
77
|
+
import { renameGitCommandResultsTransform } from "../../transforms-by-id/rename-git-command-results/rename-git-command-results-transform.js";
|
|
78
|
+
import renameGitCommandResultsManifest from "../../transforms-by-id/rename-git-command-results/manifest.json" with { type: "json" };
|
|
77
79
|
import { renameHttpMethodParametersTransform } from "../../transforms-by-id/rename-http-method-parameters/rename-http-method-parameters-transform.js";
|
|
78
80
|
import renameHttpMethodParametersManifest from "../../transforms-by-id/rename-http-method-parameters/manifest.json" with { type: "json" };
|
|
79
81
|
import { renameHttpServerParametersTransform } from "../../transforms-by-id/rename-http-server-parameters/rename-http-server-parameters-transform.js";
|
|
@@ -380,6 +382,11 @@ export const generatedTransformCatalog = [
|
|
|
380
382
|
transform: renameFsSyncVariablesTransform,
|
|
381
383
|
manifest: renameFsSyncVariablesManifest,
|
|
382
384
|
},
|
|
385
|
+
{
|
|
386
|
+
id: renameGitCommandResultsTransform.id,
|
|
387
|
+
transform: renameGitCommandResultsTransform,
|
|
388
|
+
manifest: renameGitCommandResultsManifest,
|
|
389
|
+
},
|
|
383
390
|
{
|
|
384
391
|
id: renameHttpMethodParametersTransform.id,
|
|
385
392
|
transform: renameHttpMethodParametersTransform,
|
|
@@ -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.
|
|
6
|
-
"evaluatedAt": "2026-02-
|
|
7
|
-
"changedLines":
|
|
8
|
-
"durationSeconds":
|
|
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
|
|
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
|
|
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"
|
|
22
|
+
if (property.type !== "Identifier")
|
|
23
23
|
return false;
|
|
24
|
-
|
|
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
|
|
35
|
+
* Checks whether a binding has at least one array mutation call reference,
|
|
34
36
|
* confirming the accumulator pattern.
|
|
35
37
|
*/
|
|
36
|
-
const
|
|
37
|
-
return referencePaths.some((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
|
|
76
|
-
if (!
|
|
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,
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"evaluations": {
|
|
3
3
|
"claude-code-2.1.10:claude-code-2.1.11": {
|
|
4
4
|
"diffSizePercent": 100,
|
|
5
|
-
"evaluatedAt": "2026-02-
|
|
5
|
+
"evaluatedAt": "2026-02-14T12:53:18.669Z",
|
|
6
6
|
"changedLines": 338,
|
|
7
|
-
"durationSeconds":
|
|
7
|
+
"durationSeconds": 38.783343792,
|
|
8
8
|
"stableNames": 1359
|
|
9
9
|
}
|
|
10
10
|
},
|
|
@@ -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
|
|
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;
|
package/dist/transforms-by-id/rename-deferred-resolve-parameters-v2/deferred-executor-heuristics.js
CHANGED
|
@@ -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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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":
|
|
6
|
-
"evaluatedAt": "2026-02-
|
|
7
|
-
"changedLines":
|
|
8
|
-
"durationSeconds":
|
|
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,
|
|
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
|
|
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
|
|
75
|
-
if (!
|
|
68
|
+
const resolveHasOnlyPromiseLikeReferences = resolveReferencePaths.every((referencePath) => isResolvePromiseLikeReference(referencePath));
|
|
69
|
+
if (!resolveHasOnlyPromiseLikeReferences)
|
|
76
70
|
return;
|
|
77
|
-
const
|
|
78
|
-
if (!
|
|
71
|
+
const rejectHasOnlyPromiseLikeReferences = rejectReferencePaths.every((referencePath) => isRejectPromiseLikeReference(referencePath));
|
|
72
|
+
if (!rejectHasOnlyPromiseLikeReferences)
|
|
79
73
|
return;
|
|
80
|
-
|
|
81
|
-
const
|
|
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 &&
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"notes": "Pending evaluation.",
|
|
3
|
+
"evaluations": {
|
|
4
|
+
"claude-code-2.1.10:claude-code-2.1.11": {
|
|
5
|
+
"diffSizePercent": 100,
|
|
6
|
+
"evaluatedAt": "2026-02-14T12:52:39.042Z",
|
|
7
|
+
"changedLines": 350,
|
|
8
|
+
"durationSeconds": 39.629334792,
|
|
9
|
+
"stableNames": 1365
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"recommended": false
|
|
13
|
+
}
|
package/dist/transforms-by-id/rename-git-command-results/rename-git-command-results-transform.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
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 RESULT_PROPERTY_BASE_NAMES = {
|
|
8
|
+
code: "gitExitCode",
|
|
9
|
+
signal: "gitSignal",
|
|
10
|
+
stderr: "gitStderr",
|
|
11
|
+
stdout: "gitStdout",
|
|
12
|
+
};
|
|
13
|
+
const GIT_RESULT_BASE_NAME = "gitResult";
|
|
14
|
+
const isResultPropertyName = (name) => Object.hasOwn(RESULT_PROPERTY_BASE_NAMES, name);
|
|
15
|
+
const isGitCommandCall = (call) => {
|
|
16
|
+
const firstArgument = call.arguments[0];
|
|
17
|
+
if (!firstArgument)
|
|
18
|
+
return false;
|
|
19
|
+
if (firstArgument.type !== "StringLiteral")
|
|
20
|
+
return false;
|
|
21
|
+
return firstArgument.value === "git";
|
|
22
|
+
};
|
|
23
|
+
const getCallFromAwaitExpression = (expression) => {
|
|
24
|
+
if (expression.argument.type !== "CallExpression")
|
|
25
|
+
return undefined;
|
|
26
|
+
return expression.argument;
|
|
27
|
+
};
|
|
28
|
+
const getCallFromInitializer = (init) => {
|
|
29
|
+
if (!init)
|
|
30
|
+
return undefined;
|
|
31
|
+
if (init.type === "CallExpression")
|
|
32
|
+
return init;
|
|
33
|
+
if (init.type !== "AwaitExpression")
|
|
34
|
+
return undefined;
|
|
35
|
+
return getCallFromAwaitExpression(init);
|
|
36
|
+
};
|
|
37
|
+
const addObjectPatternRenames = (path, objectPattern, group) => {
|
|
38
|
+
for (const property of objectPattern.properties) {
|
|
39
|
+
if (property.type !== "ObjectProperty")
|
|
40
|
+
continue;
|
|
41
|
+
addObjectPropertyRename(path, property, group);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const addObjectPropertyRename = (path, property, group) => {
|
|
45
|
+
if (property.computed)
|
|
46
|
+
return;
|
|
47
|
+
if (property.key.type !== "Identifier")
|
|
48
|
+
return;
|
|
49
|
+
if (!isResultPropertyName(property.key.name))
|
|
50
|
+
return;
|
|
51
|
+
const value = property.value;
|
|
52
|
+
if (value.type !== "Identifier")
|
|
53
|
+
return;
|
|
54
|
+
if (isStableRenamed(value.name))
|
|
55
|
+
return;
|
|
56
|
+
const binding = path.scope.getBinding(value.name);
|
|
57
|
+
if (!binding)
|
|
58
|
+
return;
|
|
59
|
+
group.add({
|
|
60
|
+
scope: path.scope,
|
|
61
|
+
currentName: value.name,
|
|
62
|
+
baseName: RESULT_PROPERTY_BASE_NAMES[property.key.name],
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const addIdentifierRename = (path, identifier, group) => {
|
|
66
|
+
if (isStableRenamed(identifier.name))
|
|
67
|
+
return;
|
|
68
|
+
const binding = path.scope.getBinding(identifier.name);
|
|
69
|
+
if (!binding)
|
|
70
|
+
return;
|
|
71
|
+
if (binding.referencePaths.length === 0)
|
|
72
|
+
return;
|
|
73
|
+
group.add({
|
|
74
|
+
scope: path.scope,
|
|
75
|
+
currentName: identifier.name,
|
|
76
|
+
baseName: GIT_RESULT_BASE_NAME,
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
export const renameGitCommandResultsTransform = {
|
|
80
|
+
id: "rename-git-command-results",
|
|
81
|
+
description: "Renames git command result bindings and destructured stdout/stderr/code/signal aliases to stable names",
|
|
82
|
+
scope: "file",
|
|
83
|
+
parallelizable: true,
|
|
84
|
+
transform(context) {
|
|
85
|
+
let nodesVisited = 0;
|
|
86
|
+
let transformationsApplied = 0;
|
|
87
|
+
for (const fileInfo of getFilesToProcess(context)) {
|
|
88
|
+
const group = new RenameGroup();
|
|
89
|
+
traverse(fileInfo.ast, {
|
|
90
|
+
VariableDeclarator(path) {
|
|
91
|
+
nodesVisited++;
|
|
92
|
+
const call = getCallFromInitializer(path.node.init);
|
|
93
|
+
if (!call)
|
|
94
|
+
return;
|
|
95
|
+
if (!isGitCommandCall(call))
|
|
96
|
+
return;
|
|
97
|
+
if (path.node.id.type === "Identifier") {
|
|
98
|
+
addIdentifierRename(path, path.node.id, group);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
if (path.node.id.type !== "ObjectPattern")
|
|
102
|
+
return;
|
|
103
|
+
addObjectPatternRenames(path, path.node.id, group);
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
transformationsApplied += group.apply();
|
|
107
|
+
}
|
|
108
|
+
return Promise.resolve({ nodesVisited, transformationsApplied });
|
|
109
|
+
},
|
|
110
|
+
};
|
|
@@ -3,9 +3,9 @@ import type { ArrowFunctionExpression, FunctionExpression } from "@babel/types";
|
|
|
3
3
|
type PromiseExecutorRenamePlan = {
|
|
4
4
|
bindingScope: Scope;
|
|
5
5
|
fromResolveName: string;
|
|
6
|
-
fromRejectName: string;
|
|
6
|
+
fromRejectName: string | undefined;
|
|
7
7
|
targetResolveName: string;
|
|
8
|
-
targetRejectName: string;
|
|
8
|
+
targetRejectName: string | undefined;
|
|
9
9
|
wantsResolveRename: boolean;
|
|
10
10
|
wantsRejectRename: boolean;
|
|
11
11
|
};
|
|
@@ -5,37 +5,42 @@ import { isAssignedToOnHandlerProperty, isCatchRejectionHandlerArgument, isDirec
|
|
|
5
5
|
const STABLE_PREFIX = "$";
|
|
6
6
|
export const getPromiseExecutorRenamePlan = (executorPath) => {
|
|
7
7
|
const parameters = executorPath.node.params;
|
|
8
|
-
if (parameters.length !== 2)
|
|
8
|
+
if (parameters.length !== 1 && parameters.length !== 2)
|
|
9
9
|
return;
|
|
10
10
|
const [firstParameter, secondParameter] = parameters;
|
|
11
|
-
if (!firstParameter
|
|
11
|
+
if (!firstParameter)
|
|
12
12
|
return;
|
|
13
13
|
if (firstParameter.type !== "Identifier")
|
|
14
14
|
return;
|
|
15
|
-
if (secondParameter.type !== "Identifier")
|
|
16
|
-
return;
|
|
17
15
|
const resolveParameter = firstParameter;
|
|
18
|
-
const rejectParameter = secondParameter;
|
|
16
|
+
const rejectParameter = secondParameter?.type === "Identifier" ? secondParameter : undefined;
|
|
17
|
+
if (parameters.length === 2 && !rejectParameter)
|
|
18
|
+
return;
|
|
19
19
|
// Non-strict scripts can allow duplicate parameter names like `function (a, a) {}`.
|
|
20
20
|
// Babel models these as a single binding, so we can't safely rename parameters independently.
|
|
21
|
-
if (resolveParameter.name === rejectParameter
|
|
21
|
+
if (resolveParameter.name === rejectParameter?.name)
|
|
22
22
|
return;
|
|
23
23
|
const targetResolveName = `${STABLE_PREFIX}resolve`;
|
|
24
|
-
const targetRejectName =
|
|
24
|
+
const targetRejectName = rejectParameter
|
|
25
|
+
? `${STABLE_PREFIX}reject`
|
|
26
|
+
: undefined;
|
|
25
27
|
// Skip already-stable names, unless they already match the target stable names.
|
|
26
28
|
// This allows completing a partially-stable executor like `($resolve, e)` → `($resolve, $reject)`.
|
|
27
29
|
if (isStableRenamed(resolveParameter.name) &&
|
|
28
30
|
resolveParameter.name !== targetResolveName) {
|
|
29
31
|
return;
|
|
30
32
|
}
|
|
31
|
-
if (
|
|
33
|
+
if (rejectParameter &&
|
|
34
|
+
isStableRenamed(rejectParameter.name) &&
|
|
32
35
|
rejectParameter.name !== targetRejectName) {
|
|
33
36
|
return;
|
|
34
37
|
}
|
|
35
38
|
const bindingScope = executorPath.scope;
|
|
36
39
|
const resolveBinding = bindingScope.getBinding(resolveParameter.name);
|
|
37
|
-
const rejectBinding =
|
|
38
|
-
|
|
40
|
+
const rejectBinding = rejectParameter
|
|
41
|
+
? bindingScope.getBinding(rejectParameter.name)
|
|
42
|
+
: undefined;
|
|
43
|
+
if (!resolveBinding || (rejectParameter && !rejectBinding))
|
|
39
44
|
return;
|
|
40
45
|
const resolveIsCalledOrThenHandled = resolveBinding.referencePaths.some((referencePath) => isDirectCallOfBinding(referencePath) ||
|
|
41
46
|
isThenFulfillmentHandlerArgument(referencePath));
|
|
@@ -47,24 +52,30 @@ export const getPromiseExecutorRenamePlan = (executorPath) => {
|
|
|
47
52
|
// unlike `reject` as an `"error"` handler, those patterns are lower-confidence and easier to misclassify.
|
|
48
53
|
if (!resolveIsOnlyCalledOrThenHandled)
|
|
49
54
|
return;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
if (rejectBinding) {
|
|
56
|
+
const rejectIsCalledOrHandled = rejectBinding.referencePaths.some((referencePath) => isDirectCallOfBinding(referencePath) ||
|
|
57
|
+
isThenRejectionHandlerArgument(referencePath) ||
|
|
58
|
+
isCatchRejectionHandlerArgument(referencePath));
|
|
59
|
+
const rejectIsOnHandler = rejectBinding.referencePaths.some((referencePath) => isAssignedToOnHandlerProperty(referencePath));
|
|
60
|
+
const rejectIsErrorHandler = rejectBinding.referencePaths.some((referencePath) => isErrorEventHandlerArgument(referencePath));
|
|
61
|
+
if (!rejectIsCalledOrHandled &&
|
|
62
|
+
!rejectIsOnHandler &&
|
|
63
|
+
!rejectIsErrorHandler) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const rejectIsOnlyCalledOrHandlerAssigned = rejectBinding.referencePaths.every((referencePath) => isDirectCallOfBinding(referencePath) ||
|
|
67
|
+
isThenRejectionHandlerArgument(referencePath) ||
|
|
68
|
+
isCatchRejectionHandlerArgument(referencePath) ||
|
|
69
|
+
isAssignedToOnHandlerProperty(referencePath) ||
|
|
70
|
+
isErrorEventHandlerArgument(referencePath) ||
|
|
71
|
+
isErrorEventHandlerRemovalArgument(referencePath));
|
|
72
|
+
if (!rejectIsOnlyCalledOrHandlerAssigned)
|
|
73
|
+
return;
|
|
57
74
|
}
|
|
58
|
-
const rejectIsOnlyCalledOrHandlerAssigned = rejectBinding.referencePaths.every((referencePath) => isDirectCallOfBinding(referencePath) ||
|
|
59
|
-
isThenRejectionHandlerArgument(referencePath) ||
|
|
60
|
-
isCatchRejectionHandlerArgument(referencePath) ||
|
|
61
|
-
isAssignedToOnHandlerProperty(referencePath) ||
|
|
62
|
-
isErrorEventHandlerArgument(referencePath) ||
|
|
63
|
-
isErrorEventHandlerRemovalArgument(referencePath));
|
|
64
|
-
if (!rejectIsOnlyCalledOrHandlerAssigned)
|
|
65
|
-
return;
|
|
66
75
|
const wantsResolveRename = resolveParameter.name !== targetResolveName;
|
|
67
|
-
const wantsRejectRename = rejectParameter
|
|
76
|
+
const wantsRejectRename = rejectParameter && targetRejectName
|
|
77
|
+
? rejectParameter.name !== targetRejectName
|
|
78
|
+
: false;
|
|
68
79
|
// Nothing to do: both parameters are already the stable target names.
|
|
69
80
|
if (!wantsResolveRename && !wantsRejectRename)
|
|
70
81
|
return;
|
|
@@ -73,9 +84,10 @@ export const getPromiseExecutorRenamePlan = (executorPath) => {
|
|
|
73
84
|
const resolveWouldShadow = wantsResolveRename &&
|
|
74
85
|
wouldShadowReferencedOuterBinding(executorPath, targetResolveName);
|
|
75
86
|
const rejectWouldShadow = wantsRejectRename &&
|
|
87
|
+
targetRejectName !== undefined &&
|
|
76
88
|
wouldShadowReferencedOuterBinding(executorPath, targetRejectName);
|
|
77
89
|
const fromResolveName = resolveParameter.name;
|
|
78
|
-
const fromRejectName = rejectParameter
|
|
90
|
+
const fromRejectName = rejectParameter?.name;
|
|
79
91
|
const canRenameResolve = !wantsResolveRename ||
|
|
80
92
|
(!resolveWouldShadow &&
|
|
81
93
|
canRenameBindingSafely(bindingScope, fromResolveName, targetResolveName, {
|
|
@@ -83,6 +95,8 @@ export const getPromiseExecutorRenamePlan = (executorPath) => {
|
|
|
83
95
|
}));
|
|
84
96
|
const canRenameReject = !wantsRejectRename ||
|
|
85
97
|
(!rejectWouldShadow &&
|
|
98
|
+
fromRejectName !== undefined &&
|
|
99
|
+
targetRejectName !== undefined &&
|
|
86
100
|
canRenameBindingSafely(bindingScope, fromRejectName, targetRejectName, {
|
|
87
101
|
strictMode: false,
|
|
88
102
|
}));
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
"evaluations": {
|
|
4
4
|
"claude-code-2.1.10:claude-code-2.1.11": {
|
|
5
5
|
"diffSizePercent": 99.99623032701913,
|
|
6
|
-
"evaluatedAt": "2026-02-
|
|
7
|
-
"changedLines":
|
|
8
|
-
"durationSeconds":
|
|
6
|
+
"evaluatedAt": "2026-02-13T08:17:00.590Z",
|
|
7
|
+
"changedLines": 1880,
|
|
8
|
+
"durationSeconds": 184.31310626599998,
|
|
9
9
|
"stableNames": 1359
|
|
10
10
|
}
|
|
11
11
|
},
|
package/dist/transforms-by-id/rename-promise-executor-parameters-v2/promise-executor-heuristics.js
CHANGED
|
@@ -31,14 +31,14 @@ export const getExecutorFunctionIfEligible = (path) => {
|
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
33
|
const parameters = executor.node.params;
|
|
34
|
-
if (parameters.length !== 2)
|
|
34
|
+
if (parameters.length !== 1 && parameters.length !== 2)
|
|
35
35
|
return;
|
|
36
36
|
const [firstParameter, secondParameter] = parameters;
|
|
37
|
-
if (!firstParameter
|
|
37
|
+
if (!firstParameter)
|
|
38
38
|
return;
|
|
39
39
|
if (firstParameter.type !== "Identifier")
|
|
40
40
|
return;
|
|
41
|
-
if (secondParameter.type !== "Identifier")
|
|
41
|
+
if (secondParameter !== undefined && secondParameter.type !== "Identifier")
|
|
42
42
|
return;
|
|
43
43
|
// v1 checked that the *source* parameter names are valid identifiers, but this is redundant:
|
|
44
44
|
// if Babel produced Identifier nodes under `sourceType: "unambiguous"` parsing, then the names
|
|
@@ -36,6 +36,10 @@ export const renamePromiseExecutorParametersV2Transform = {
|
|
|
36
36
|
renamedResolve = true;
|
|
37
37
|
}
|
|
38
38
|
if (renamePlan.wantsRejectRename) {
|
|
39
|
+
if (renamePlan.fromRejectName === undefined ||
|
|
40
|
+
renamePlan.targetRejectName === undefined) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
39
43
|
renamePlan.bindingScope.rename(renamePlan.fromRejectName, renamePlan.targetRejectName);
|
|
40
44
|
renamedReject = true;
|
|
41
45
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"recommendedOrder": 100,
|
|
4
|
-
"notes": "Measured with baseline none: 0.00%. Added to recommended for readability.",
|
|
2
|
+
"notes": "Generalized timer-handle rename transform for setTimeout and setInterval. Measured with baseline none: 0.00%. Added to recommended for readability.",
|
|
5
3
|
"evaluations": {
|
|
6
4
|
"claude-code-2.1.10:claude-code-2.1.11": {
|
|
7
|
-
"diffSizePercent": 99.
|
|
8
|
-
"evaluatedAt": "2026-02-
|
|
9
|
-
"changedLines":
|
|
10
|
-
"durationSeconds":
|
|
11
|
-
"stableNames":
|
|
5
|
+
"diffSizePercent": 99.99622028196697,
|
|
6
|
+
"evaluatedAt": "2026-02-14T12:54:44.910Z",
|
|
7
|
+
"changedLines": 200,
|
|
8
|
+
"durationSeconds": 38.705412083000006,
|
|
9
|
+
"stableNames": 1359
|
|
12
10
|
}
|
|
13
|
-
}
|
|
11
|
+
},
|
|
12
|
+
"recommended": true,
|
|
13
|
+
"recommendedOrder": 100
|
|
14
14
|
}
|
|
@@ -4,18 +4,33 @@ 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;
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
const TIMER_HANDLE_RENAME_RULES = [
|
|
8
|
+
{
|
|
9
|
+
setName: "setTimeout",
|
|
10
|
+
clearName: "clearTimeout",
|
|
11
|
+
baseName: "timeoutId",
|
|
12
|
+
batch: "timeout",
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
setName: "setInterval",
|
|
16
|
+
clearName: "clearInterval",
|
|
17
|
+
baseName: "intervalId",
|
|
18
|
+
batch: "interval",
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
const getTimerHandleRenameRule = (path, init) => {
|
|
22
|
+
const callee = init.callee;
|
|
23
|
+
if (callee.type !== "Identifier")
|
|
24
|
+
return undefined;
|
|
25
|
+
const renameRule = TIMER_HANDLE_RENAME_RULES.find((rule) => rule.setName === callee.name);
|
|
26
|
+
if (!renameRule)
|
|
27
|
+
return undefined;
|
|
28
|
+
// If timer constructor is locally bound (imported or declared), semantics may differ.
|
|
29
|
+
if (path.scope.hasBinding(renameRule.setName, true))
|
|
30
|
+
return undefined;
|
|
31
|
+
return renameRule;
|
|
17
32
|
};
|
|
18
|
-
const
|
|
33
|
+
const isMatchingClearCallArgument = (referencePath, bindingName, renameRule) => {
|
|
19
34
|
if (!referencePath.isIdentifier())
|
|
20
35
|
return false;
|
|
21
36
|
const callPath = referencePath.parentPath;
|
|
@@ -24,10 +39,10 @@ const isClearTimeoutCallArgument = (referencePath, bindingName) => {
|
|
|
24
39
|
const call = callPath.node;
|
|
25
40
|
if (call.callee.type !== "Identifier")
|
|
26
41
|
return false;
|
|
27
|
-
if (call.callee.name !==
|
|
42
|
+
if (call.callee.name !== renameRule.clearName)
|
|
28
43
|
return false;
|
|
29
|
-
// If
|
|
30
|
-
if (callPath.scope.hasBinding(
|
|
44
|
+
// If clear function is locally bound (imported or declared), semantics may differ.
|
|
45
|
+
if (callPath.scope.hasBinding(renameRule.clearName, true))
|
|
31
46
|
return false;
|
|
32
47
|
const argument0 = call.arguments[0];
|
|
33
48
|
if (argument0?.type !== "Identifier")
|
|
@@ -40,14 +55,15 @@ const isClearTimeoutCallArgument = (referencePath, bindingName) => {
|
|
|
40
55
|
};
|
|
41
56
|
export const renameTimeoutIdsTransform = {
|
|
42
57
|
id: "rename-timeout-ids",
|
|
43
|
-
description: "Renames setTimeout handle variables to
|
|
58
|
+
description: "Renames setTimeout/setInterval handle variables to stable timer names when usage is only clearTimeout(...) or clearInterval(...)",
|
|
44
59
|
scope: "file",
|
|
45
60
|
parallelizable: true,
|
|
46
61
|
transform(context) {
|
|
47
62
|
let nodesVisited = 0;
|
|
48
63
|
let transformationsApplied = 0;
|
|
49
64
|
for (const fileInfo of getFilesToProcess(context)) {
|
|
50
|
-
const
|
|
65
|
+
const intervalRenameGroup = new RenameGroup();
|
|
66
|
+
const timeoutRenameGroup = new RenameGroup();
|
|
51
67
|
traverse(fileInfo.ast, {
|
|
52
68
|
VariableDeclarator(path) {
|
|
53
69
|
nodesVisited++;
|
|
@@ -60,7 +76,8 @@ export const renameTimeoutIdsTransform = {
|
|
|
60
76
|
const init = path.node.init;
|
|
61
77
|
if (init?.type !== "CallExpression")
|
|
62
78
|
return;
|
|
63
|
-
|
|
79
|
+
const renameRule = getTimerHandleRenameRule(path, init);
|
|
80
|
+
if (!renameRule)
|
|
64
81
|
return;
|
|
65
82
|
const binding = path.scope.getBinding(id.name);
|
|
66
83
|
if (!binding)
|
|
@@ -69,16 +86,22 @@ export const renameTimeoutIdsTransform = {
|
|
|
69
86
|
return;
|
|
70
87
|
if (binding.referencePaths.length === 0)
|
|
71
88
|
return;
|
|
72
|
-
if (!binding.referencePaths.every((referencePath) =>
|
|
89
|
+
if (!binding.referencePaths.every((referencePath) => isMatchingClearCallArgument(referencePath, id.name, renameRule)))
|
|
73
90
|
return;
|
|
74
|
-
|
|
91
|
+
const renameGroup = renameRule.batch === "interval"
|
|
92
|
+
? intervalRenameGroup
|
|
93
|
+
: timeoutRenameGroup;
|
|
94
|
+
renameGroup.add({
|
|
75
95
|
scope: path.scope,
|
|
76
96
|
currentName: id.name,
|
|
77
|
-
baseName:
|
|
97
|
+
baseName: renameRule.baseName,
|
|
78
98
|
});
|
|
79
99
|
},
|
|
80
100
|
});
|
|
81
|
-
|
|
101
|
+
// Preserve pre-generalization ordering: interval handle renames first,
|
|
102
|
+
// timeout handle renames second.
|
|
103
|
+
transformationsApplied += intervalRenameGroup.apply();
|
|
104
|
+
transformationsApplied += timeoutRenameGroup.apply();
|
|
82
105
|
}
|
|
83
106
|
return Promise.resolve({ nodesVisited, transformationsApplied });
|
|
84
107
|
},
|
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.114.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",
|