miniread 1.116.0 → 1.116.2
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/README.md +3 -0
- package/dist/transforms/preset-stats.json +2 -2
- package/dist/transforms-by-id/rename-platform-win32-flags/add-assignment-win32-rename-candidate.d.ts +14 -0
- package/dist/transforms-by-id/rename-platform-win32-flags/add-assignment-win32-rename-candidate.js +57 -0
- package/dist/transforms-by-id/rename-platform-win32-flags/is-safe-process-binding.d.ts +1 -2
- package/dist/transforms-by-id/rename-platform-win32-flags/manifest.json +8 -8
- package/dist/transforms-by-id/rename-platform-win32-flags/rename-platform-win32-flags-transform.js +28 -9
- package/dist/transforms-by-id/rename-use-reference-sets/get-set-reference-usage.d.ts +1 -0
- package/dist/transforms-by-id/rename-use-reference-sets/get-set-reference-usage.js +127 -42
- package/dist/transforms-by-id/rename-use-reference-sets/is-disallowed-member-usage-parent.d.ts +3 -0
- package/dist/transforms-by-id/rename-use-reference-sets/is-disallowed-member-usage-parent.js +28 -0
- package/dist/transforms-by-id/rename-use-reference-sets/is-use-reference-set-initializer.js +31 -11
- package/dist/transforms-by-id/rename-use-reference-sets/manifest.json +6 -6
- package/dist/transforms-by-id/rename-use-reference-sets/rename-use-reference-sets-transform.js +4 -2
- package/dist/transforms-by-id/stabilize-top-level-bindings/collect-first-program-scope-assignments.d.ts +9 -0
- package/dist/transforms-by-id/stabilize-top-level-bindings/collect-first-program-scope-assignments.js +107 -0
- package/dist/transforms-by-id/stabilize-top-level-bindings/collect-nested-program-scope-variable-initializers.js +20 -20
- package/dist/transforms-by-id/stabilize-top-level-bindings/collect-rename-candidates.js +31 -26
- package/dist/transforms-by-id/stabilize-top-level-bindings/has-disallowed-function-class-assignment-reference.d.ts +8 -0
- package/dist/transforms-by-id/stabilize-top-level-bindings/has-disallowed-function-class-assignment-reference.js +74 -0
- package/dist/transforms-by-id/stabilize-top-level-bindings/manifest.json +9 -9
- package/package.json +1 -1
- package/dist/transforms-by-id/stabilize-top-level-bindings/collect-first-program-body-assignments.d.ts +0 -12
- package/dist/transforms-by-id/stabilize-top-level-bindings/collect-first-program-body-assignments.js +0 -29
package/README.md
CHANGED
|
@@ -102,6 +102,9 @@ Use `miniread` when you need readable JavaScript/TypeScript from minified input
|
|
|
102
102
|
Development workflow/tooling documentation lives under `development-workflows/`:
|
|
103
103
|
|
|
104
104
|
- `development-workflows/AGENTS.md` — shared development tooling and workflow helper docs
|
|
105
|
+
- `development-workflows/codex-task-to-worktree.md` — import Codex task patches into local task worktrees
|
|
106
|
+
- `development-workflows/cherry-pick-worktrees-into-main.md` — cherry-pick worktree commits into main, discard conflicts, remove processed worktrees
|
|
107
|
+
- `development-workflows/generalize-overlapping-transforms.md` — pattern for consolidating overlapping transform behavior
|
|
105
108
|
- `development-workflows/new-transform.md` — transform iteration workflow
|
|
106
109
|
- `development-workflows/improve-transform-performance.md` — runtime performance optimization workflow
|
|
107
110
|
- `development-workflows/improve-transform-coverage.md` — coverage improvement workflow
|
package/dist/transforms-by-id/rename-platform-win32-flags/add-assignment-win32-rename-candidate.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { NodePath, Scope } from "@babel/traverse";
|
|
2
|
+
import type { AssignmentExpression, BinaryExpression } from "@babel/types";
|
|
3
|
+
import { type RenameGroup } from "../../core/stable-naming.js";
|
|
4
|
+
import type { HashRenameEntry } from "./apply-hash-stable-win32-renames.js";
|
|
5
|
+
type AddAssignmentWin32RenameCandidateInput = {
|
|
6
|
+
getPlatformIdentifierName: (node: BinaryExpression) => string | undefined;
|
|
7
|
+
getWin32BaseName: (node: BinaryExpression) => "isWindows" | "isNotWindows" | undefined;
|
|
8
|
+
group: RenameGroup;
|
|
9
|
+
hashEntries: HashRenameEntry[];
|
|
10
|
+
path: NodePath<AssignmentExpression>;
|
|
11
|
+
scope: Scope;
|
|
12
|
+
};
|
|
13
|
+
export declare const addAssignmentWin32RenameCandidate: ({ getPlatformIdentifierName, getWin32BaseName, group, hashEntries, path, scope, }: AddAssignmentWin32RenameCandidateInput) => void;
|
|
14
|
+
export {};
|
package/dist/transforms-by-id/rename-platform-win32-flags/add-assignment-win32-rename-candidate.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { isHashBasedStableName, } from "../../core/stable-naming.js";
|
|
2
|
+
import { isSafeProcessBinding } from "./is-safe-process-binding.js";
|
|
3
|
+
const getAssignmentTargetName = (path) => {
|
|
4
|
+
if (path.node.operator !== "=")
|
|
5
|
+
return undefined;
|
|
6
|
+
if (path.node.left.type !== "Identifier")
|
|
7
|
+
return undefined;
|
|
8
|
+
return path.node.left.name;
|
|
9
|
+
};
|
|
10
|
+
const getAssignmentBinaryExpression = (path) => {
|
|
11
|
+
if (path.node.right.type !== "BinaryExpression")
|
|
12
|
+
return undefined;
|
|
13
|
+
return path.node.right;
|
|
14
|
+
};
|
|
15
|
+
export const addAssignmentWin32RenameCandidate = ({ getPlatformIdentifierName, getWin32BaseName, group, hashEntries, path, scope, }) => {
|
|
16
|
+
const assignmentTargetName = getAssignmentTargetName(path);
|
|
17
|
+
if (!assignmentTargetName)
|
|
18
|
+
return;
|
|
19
|
+
const binaryExpression = getAssignmentBinaryExpression(path);
|
|
20
|
+
if (!binaryExpression)
|
|
21
|
+
return;
|
|
22
|
+
const platformIdentifierName = getPlatformIdentifierName(binaryExpression);
|
|
23
|
+
if (!platformIdentifierName)
|
|
24
|
+
return;
|
|
25
|
+
if (!isSafeProcessBinding(path, platformIdentifierName))
|
|
26
|
+
return;
|
|
27
|
+
const baseName = getWin32BaseName(binaryExpression);
|
|
28
|
+
if (!baseName)
|
|
29
|
+
return;
|
|
30
|
+
const binding = scope.getBinding(assignmentTargetName);
|
|
31
|
+
if (!binding)
|
|
32
|
+
return;
|
|
33
|
+
if (binding.constant)
|
|
34
|
+
return;
|
|
35
|
+
if (binding.constantViolations.length !== 1)
|
|
36
|
+
return;
|
|
37
|
+
const firstViolation = binding.constantViolations[0];
|
|
38
|
+
if (!firstViolation)
|
|
39
|
+
return;
|
|
40
|
+
if (firstViolation.node !== path.node)
|
|
41
|
+
return;
|
|
42
|
+
const bindingScope = binding.scope;
|
|
43
|
+
if (isHashBasedStableName(assignmentTargetName)) {
|
|
44
|
+
hashEntries.push({
|
|
45
|
+
baseName,
|
|
46
|
+
binding,
|
|
47
|
+
currentName: assignmentTargetName,
|
|
48
|
+
scope: bindingScope,
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
group.add({
|
|
53
|
+
scope: bindingScope,
|
|
54
|
+
currentName: assignmentTargetName,
|
|
55
|
+
baseName,
|
|
56
|
+
});
|
|
57
|
+
};
|
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
import type { NodePath } from "@babel/traverse";
|
|
2
|
-
|
|
3
|
-
export declare const isSafeProcessBinding: (path: NodePath<VariableDeclarator>, identifierName: string) => boolean;
|
|
2
|
+
export declare const isSafeProcessBinding: (path: NodePath, identifierName: string) => boolean;
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"recommended": true,
|
|
3
|
-
"recommendedOrder": 50,
|
|
4
2
|
"evaluations": {
|
|
5
3
|
"claude-code-2.1.10:claude-code-2.1.11": {
|
|
6
|
-
"diffSizePercent": 99.
|
|
7
|
-
"evaluatedAt": "2026-02-
|
|
8
|
-
"changedLines":
|
|
9
|
-
"durationSeconds":
|
|
10
|
-
"stableNames":
|
|
4
|
+
"diffSizePercent": 99.98677098688438,
|
|
5
|
+
"evaluatedAt": "2026-02-21T16:59:41.380Z",
|
|
6
|
+
"changedLines": 62,
|
|
7
|
+
"durationSeconds": 41.748348541,
|
|
8
|
+
"stableNames": 1359
|
|
11
9
|
}
|
|
12
|
-
}
|
|
10
|
+
},
|
|
11
|
+
"recommended": true,
|
|
12
|
+
"recommendedOrder": 50
|
|
13
13
|
}
|
package/dist/transforms-by-id/rename-platform-win32-flags/rename-platform-win32-flags-transform.js
CHANGED
|
@@ -3,6 +3,7 @@ import { isHashBasedStableName, RenameGroup, } from "../../core/stable-naming.js
|
|
|
3
3
|
import { getFilesToProcess, } from "../../core/types.js";
|
|
4
4
|
import { applyHashStableWin32Renames, } from "./apply-hash-stable-win32-renames.js";
|
|
5
5
|
import { isSafeProcessBinding } from "./is-safe-process-binding.js";
|
|
6
|
+
import { addAssignmentWin32RenameCandidate } from "./add-assignment-win32-rename-candidate.js";
|
|
6
7
|
const require = createRequire(import.meta.url);
|
|
7
8
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
8
9
|
const traverse = require("@babel/traverse").default;
|
|
@@ -11,11 +12,16 @@ const ESCAPE_CHARACTER = "\\";
|
|
|
11
12
|
const isProcessPlatformExpression = (node) => {
|
|
12
13
|
if (node.type !== "MemberExpression")
|
|
13
14
|
return false;
|
|
14
|
-
if (node.computed)
|
|
15
|
-
return false;
|
|
16
15
|
if (node.object.type !== "Identifier")
|
|
17
16
|
return false;
|
|
18
17
|
// We intentionally keep this structural and verify process identity separately.
|
|
18
|
+
if (node.computed) {
|
|
19
|
+
if (node.property.type !== "StringLiteral")
|
|
20
|
+
return false;
|
|
21
|
+
if (node.property.value !== "platform")
|
|
22
|
+
return false;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
19
25
|
if (node.property.type !== "Identifier")
|
|
20
26
|
return false;
|
|
21
27
|
if (node.property.name !== "platform")
|
|
@@ -28,13 +34,20 @@ const isWin32Literal = (node) => {
|
|
|
28
34
|
return node.value === WIN32_LITERAL;
|
|
29
35
|
};
|
|
30
36
|
const getWin32BaseName = (node) => {
|
|
31
|
-
if (node.operator !== "===" &&
|
|
37
|
+
if (node.operator !== "===" &&
|
|
38
|
+
node.operator !== "!==" &&
|
|
39
|
+
node.operator !== "==" &&
|
|
40
|
+
node.operator !== "!=") {
|
|
32
41
|
return undefined;
|
|
42
|
+
}
|
|
33
43
|
const matchesLeft = isProcessPlatformExpression(node.left) && isWin32Literal(node.right);
|
|
34
44
|
const matchesRight = isProcessPlatformExpression(node.right) && isWin32Literal(node.left);
|
|
35
45
|
if (!matchesLeft && !matchesRight)
|
|
36
46
|
return undefined;
|
|
37
|
-
|
|
47
|
+
if (node.operator === "===" || node.operator === "==") {
|
|
48
|
+
return "isWindows";
|
|
49
|
+
}
|
|
50
|
+
return "isNotWindows";
|
|
38
51
|
};
|
|
39
52
|
const getPlatformIdentifierName = (node) => {
|
|
40
53
|
if (isProcessPlatformExpression(node.left)) {
|
|
@@ -99,11 +112,6 @@ export const renamePlatformWin32FlagsTransform = {
|
|
|
99
112
|
return;
|
|
100
113
|
if (!binding.constant)
|
|
101
114
|
return;
|
|
102
|
-
// Intentionally skip single-declaration dead flags to avoid churn;
|
|
103
|
-
// unlike generic comparison-flags, this transform targets a narrow,
|
|
104
|
-
// semantically named pattern where dead-code renames add little value.
|
|
105
|
-
if (binding.referencePaths.length === 0)
|
|
106
|
-
return;
|
|
107
115
|
if (isHashBasedStableName(id.name)) {
|
|
108
116
|
hashEntries.push({
|
|
109
117
|
baseName,
|
|
@@ -119,6 +127,17 @@ export const renamePlatformWin32FlagsTransform = {
|
|
|
119
127
|
baseName,
|
|
120
128
|
});
|
|
121
129
|
},
|
|
130
|
+
AssignmentExpression(path) {
|
|
131
|
+
nodesVisited++;
|
|
132
|
+
addAssignmentWin32RenameCandidate({
|
|
133
|
+
getPlatformIdentifierName,
|
|
134
|
+
getWin32BaseName,
|
|
135
|
+
group,
|
|
136
|
+
hashEntries,
|
|
137
|
+
path,
|
|
138
|
+
scope: path.scope,
|
|
139
|
+
});
|
|
140
|
+
},
|
|
122
141
|
});
|
|
123
142
|
transformationsApplied += applyHashStableWin32Renames(hashEntries);
|
|
124
143
|
transformationsApplied += group.apply();
|
|
@@ -1,78 +1,163 @@
|
|
|
1
|
-
|
|
1
|
+
import { isDisallowedMemberUsageParent } from "./is-disallowed-member-usage-parent.js";
|
|
2
|
+
const allowedSetMethodCalls = new Set([
|
|
3
|
+
"add",
|
|
4
|
+
"has",
|
|
5
|
+
"delete",
|
|
6
|
+
"clear",
|
|
7
|
+
"forEach",
|
|
8
|
+
"entries",
|
|
9
|
+
"keys",
|
|
10
|
+
"values",
|
|
11
|
+
]);
|
|
12
|
+
const createResult = (isSafe, usage) => {
|
|
13
|
+
return {
|
|
14
|
+
isSafe,
|
|
15
|
+
hasSetMethodCall: usage.hasSetMethodCall,
|
|
16
|
+
hasSizeRead: usage.hasSizeRead,
|
|
17
|
+
hasCurrentRead: usage.hasCurrentRead,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
const getSafeCurrentRead = (hasSetMethodCall, hasSizeRead, hasCurrentRead, currentMemberPath) => {
|
|
21
|
+
const usagePath = currentMemberPath.parentPath;
|
|
22
|
+
if (isDisallowedMemberUsageParent(usagePath, currentMemberPath.node)) {
|
|
23
|
+
return createResult(false, {
|
|
24
|
+
hasSetMethodCall,
|
|
25
|
+
hasSizeRead,
|
|
26
|
+
hasCurrentRead,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (!currentMemberPath.isReferenced()) {
|
|
30
|
+
return createResult(false, {
|
|
31
|
+
hasSetMethodCall,
|
|
32
|
+
hasSizeRead,
|
|
33
|
+
hasCurrentRead,
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return createResult(true, {
|
|
37
|
+
hasSetMethodCall,
|
|
38
|
+
hasSizeRead,
|
|
39
|
+
hasCurrentRead: true,
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
const getSafeSizeRead = (hasSetMethodCall, hasSizeRead, hasCurrentRead, usagePath) => {
|
|
43
|
+
const sizeParentPath = usagePath.parentPath;
|
|
44
|
+
if (isDisallowedMemberUsageParent(sizeParentPath, usagePath.node)) {
|
|
45
|
+
return createResult(false, {
|
|
46
|
+
hasSetMethodCall,
|
|
47
|
+
hasSizeRead,
|
|
48
|
+
hasCurrentRead,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (!usagePath.isReferenced()) {
|
|
52
|
+
return createResult(false, {
|
|
53
|
+
hasSetMethodCall,
|
|
54
|
+
hasSizeRead,
|
|
55
|
+
hasCurrentRead,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
return createResult(true, {
|
|
59
|
+
hasSetMethodCall,
|
|
60
|
+
hasSizeRead: true,
|
|
61
|
+
hasCurrentRead,
|
|
62
|
+
});
|
|
63
|
+
};
|
|
2
64
|
export const getSetReferenceUsage = (binding) => {
|
|
3
65
|
let hasSetMethodCall = false;
|
|
4
66
|
let hasSizeRead = false;
|
|
67
|
+
let hasCurrentRead = false;
|
|
5
68
|
for (const referencePath of binding.referencePaths) {
|
|
6
69
|
if (!referencePath.isIdentifier()) {
|
|
7
|
-
return
|
|
70
|
+
return createResult(false, {
|
|
71
|
+
hasSetMethodCall,
|
|
72
|
+
hasSizeRead,
|
|
73
|
+
hasCurrentRead,
|
|
74
|
+
});
|
|
8
75
|
}
|
|
9
76
|
const currentMemberPath = referencePath.parentPath;
|
|
10
77
|
if (!currentMemberPath.isMemberExpression()) {
|
|
11
|
-
return
|
|
78
|
+
return createResult(false, {
|
|
79
|
+
hasSetMethodCall,
|
|
80
|
+
hasSizeRead,
|
|
81
|
+
hasCurrentRead,
|
|
82
|
+
});
|
|
12
83
|
}
|
|
13
84
|
if (currentMemberPath.node.computed) {
|
|
14
|
-
return
|
|
85
|
+
return createResult(false, {
|
|
86
|
+
hasSetMethodCall,
|
|
87
|
+
hasSizeRead,
|
|
88
|
+
hasCurrentRead,
|
|
89
|
+
});
|
|
15
90
|
}
|
|
16
91
|
const currentProperty = currentMemberPath.get("property");
|
|
17
92
|
if (!currentProperty.isIdentifier({ name: "current" })) {
|
|
18
|
-
return
|
|
93
|
+
return createResult(false, {
|
|
94
|
+
hasSetMethodCall,
|
|
95
|
+
hasSizeRead,
|
|
96
|
+
hasCurrentRead,
|
|
97
|
+
});
|
|
19
98
|
}
|
|
20
99
|
const usagePath = currentMemberPath.parentPath;
|
|
100
|
+
if (usagePath.isOptionalMemberExpression() &&
|
|
101
|
+
usagePath.node.object === currentMemberPath.node) {
|
|
102
|
+
return createResult(false, {
|
|
103
|
+
hasSetMethodCall,
|
|
104
|
+
hasSizeRead,
|
|
105
|
+
hasCurrentRead,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
21
108
|
if (!usagePath.isMemberExpression()) {
|
|
22
|
-
|
|
109
|
+
const currentRead = getSafeCurrentRead(hasSetMethodCall, hasSizeRead, hasCurrentRead, currentMemberPath);
|
|
110
|
+
if (!currentRead.isSafe)
|
|
111
|
+
return currentRead;
|
|
112
|
+
hasCurrentRead = currentRead.hasCurrentRead;
|
|
113
|
+
continue;
|
|
23
114
|
}
|
|
24
115
|
if (usagePath.node.computed) {
|
|
25
|
-
return
|
|
116
|
+
return createResult(false, {
|
|
117
|
+
hasSetMethodCall,
|
|
118
|
+
hasSizeRead,
|
|
119
|
+
hasCurrentRead,
|
|
120
|
+
});
|
|
26
121
|
}
|
|
27
122
|
const usageProperty = usagePath.get("property");
|
|
28
123
|
if (!usageProperty.isIdentifier()) {
|
|
29
|
-
return
|
|
124
|
+
return createResult(false, {
|
|
125
|
+
hasSetMethodCall,
|
|
126
|
+
hasSizeRead,
|
|
127
|
+
hasCurrentRead,
|
|
128
|
+
});
|
|
30
129
|
}
|
|
31
130
|
if (allowedSetMethodCalls.has(usageProperty.node.name)) {
|
|
32
131
|
const callPath = usagePath.parentPath;
|
|
33
132
|
if (!callPath.isCallExpression()) {
|
|
34
|
-
return
|
|
133
|
+
return createResult(false, {
|
|
134
|
+
hasSetMethodCall,
|
|
135
|
+
hasSizeRead,
|
|
136
|
+
hasCurrentRead,
|
|
137
|
+
});
|
|
35
138
|
}
|
|
36
139
|
if (callPath.node.callee !== usagePath.node) {
|
|
37
|
-
return
|
|
140
|
+
return createResult(false, {
|
|
141
|
+
hasSetMethodCall,
|
|
142
|
+
hasSizeRead,
|
|
143
|
+
hasCurrentRead,
|
|
144
|
+
});
|
|
38
145
|
}
|
|
39
146
|
hasSetMethodCall = true;
|
|
40
147
|
continue;
|
|
41
148
|
}
|
|
42
149
|
if (usageProperty.node.name === "size") {
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
if (sizeParentPath.isUpdateExpression() &&
|
|
49
|
-
sizeParentPath.node.argument === usagePath.node) {
|
|
50
|
-
return { isSafe: false, hasSetMethodCall, hasSizeRead };
|
|
51
|
-
}
|
|
52
|
-
if (sizeParentPath.isUnaryExpression() &&
|
|
53
|
-
sizeParentPath.node.operator === "delete" &&
|
|
54
|
-
sizeParentPath.node.argument === usagePath.node) {
|
|
55
|
-
return { isSafe: false, hasSetMethodCall, hasSizeRead };
|
|
56
|
-
}
|
|
57
|
-
if (sizeParentPath.isCallExpression() &&
|
|
58
|
-
sizeParentPath.node.callee === usagePath.node) {
|
|
59
|
-
return { isSafe: false, hasSetMethodCall, hasSizeRead };
|
|
60
|
-
}
|
|
61
|
-
if (sizeParentPath.isOptionalCallExpression() &&
|
|
62
|
-
sizeParentPath.node.callee === usagePath.node) {
|
|
63
|
-
return { isSafe: false, hasSetMethodCall, hasSizeRead };
|
|
64
|
-
}
|
|
65
|
-
if (sizeParentPath.isNewExpression() &&
|
|
66
|
-
sizeParentPath.node.callee === usagePath.node) {
|
|
67
|
-
return { isSafe: false, hasSetMethodCall, hasSizeRead };
|
|
68
|
-
}
|
|
69
|
-
if (!usagePath.isReferenced()) {
|
|
70
|
-
return { isSafe: false, hasSetMethodCall, hasSizeRead };
|
|
71
|
-
}
|
|
72
|
-
hasSizeRead = true;
|
|
150
|
+
const sizeRead = getSafeSizeRead(hasSetMethodCall, hasSizeRead, hasCurrentRead, usagePath);
|
|
151
|
+
if (!sizeRead.isSafe)
|
|
152
|
+
return sizeRead;
|
|
153
|
+
hasSizeRead = sizeRead.hasSizeRead;
|
|
73
154
|
continue;
|
|
74
155
|
}
|
|
75
|
-
return
|
|
156
|
+
return createResult(false, {
|
|
157
|
+
hasSetMethodCall,
|
|
158
|
+
hasSizeRead,
|
|
159
|
+
hasCurrentRead,
|
|
160
|
+
});
|
|
76
161
|
}
|
|
77
|
-
return
|
|
162
|
+
return createResult(true, { hasSetMethodCall, hasSizeRead, hasCurrentRead });
|
|
78
163
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const isDisallowedMemberUsageParent = (parentPath, memberNode) => {
|
|
2
|
+
if (!parentPath)
|
|
3
|
+
return true;
|
|
4
|
+
if (parentPath.isAssignmentExpression() &&
|
|
5
|
+
parentPath.node.left === memberNode) {
|
|
6
|
+
return true;
|
|
7
|
+
}
|
|
8
|
+
if (parentPath.isUpdateExpression() &&
|
|
9
|
+
parentPath.node.argument === memberNode) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (parentPath.isUnaryExpression() &&
|
|
13
|
+
parentPath.node.operator === "delete" &&
|
|
14
|
+
parentPath.node.argument === memberNode) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if (parentPath.isCallExpression() && parentPath.node.callee === memberNode) {
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
if (parentPath.isOptionalCallExpression() &&
|
|
21
|
+
parentPath.node.callee === memberNode) {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
if (parentPath.isNewExpression() && parentPath.node.callee === memberNode) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
const isUseReferenceCallee = (callee) => {
|
|
2
|
+
if (!callee)
|
|
3
|
+
return false;
|
|
4
|
+
if (callee.type === "V8IntrinsicIdentifier")
|
|
5
|
+
return false;
|
|
6
|
+
if (callee.type === "Identifier") {
|
|
7
|
+
return callee.name === "useRef";
|
|
8
|
+
}
|
|
9
|
+
if (callee.type === "MemberExpression") {
|
|
10
|
+
if (callee.computed)
|
|
11
|
+
return false;
|
|
12
|
+
if (callee.property.type !== "Identifier")
|
|
13
|
+
return false;
|
|
14
|
+
return callee.property.name === "useRef";
|
|
15
|
+
}
|
|
16
|
+
if (callee.type === "SequenceExpression") {
|
|
17
|
+
const lastExpression = callee.expressions.at(-1);
|
|
18
|
+
return isUseReferenceCallee(lastExpression);
|
|
19
|
+
}
|
|
20
|
+
if (callee.type === "TSAsExpression" || callee.type === "TSTypeAssertion") {
|
|
21
|
+
return isUseReferenceCallee(callee.expression);
|
|
22
|
+
}
|
|
23
|
+
if (callee.type === "TSNonNullExpression") {
|
|
24
|
+
return isUseReferenceCallee(callee.expression);
|
|
25
|
+
}
|
|
26
|
+
if (callee.type === "ParenthesizedExpression") {
|
|
27
|
+
return isUseReferenceCallee(callee.expression);
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
};
|
|
1
31
|
export const isUseReferenceSetInitializer = (declarator) => {
|
|
2
32
|
const init = declarator.init;
|
|
3
33
|
if (!init)
|
|
@@ -30,15 +60,5 @@ export const isUseReferenceSetInitializer = (declarator) => {
|
|
|
30
60
|
if (setArgument.type === "ArgumentPlaceholder")
|
|
31
61
|
return false;
|
|
32
62
|
}
|
|
33
|
-
|
|
34
|
-
if (callee.type === "Identifier") {
|
|
35
|
-
return callee.name === "useRef";
|
|
36
|
-
}
|
|
37
|
-
if (callee.type !== "MemberExpression")
|
|
38
|
-
return false;
|
|
39
|
-
if (callee.computed)
|
|
40
|
-
return false;
|
|
41
|
-
if (callee.property.type !== "Identifier")
|
|
42
|
-
return false;
|
|
43
|
-
return callee.property.name === "useRef";
|
|
63
|
+
return isUseReferenceCallee(init.callee);
|
|
44
64
|
};
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
|
-
"recommended": true,
|
|
3
|
-
"recommendedOrder": 100,
|
|
4
2
|
"evaluations": {
|
|
5
3
|
"claude-code-2.1.10:claude-code-2.1.11": {
|
|
6
4
|
"diffSizePercent": 100,
|
|
7
|
-
"evaluatedAt": "2026-02-
|
|
8
|
-
"changedLines":
|
|
9
|
-
"durationSeconds":
|
|
5
|
+
"evaluatedAt": "2026-02-21T16:46:50.151Z",
|
|
6
|
+
"changedLines": 38,
|
|
7
|
+
"durationSeconds": 32.887656167,
|
|
10
8
|
"stableNames": 1358
|
|
11
9
|
}
|
|
12
|
-
}
|
|
10
|
+
},
|
|
11
|
+
"recommended": true,
|
|
12
|
+
"recommendedOrder": 100
|
|
13
13
|
}
|
package/dist/transforms-by-id/rename-use-reference-sets/rename-use-reference-sets-transform.js
CHANGED
|
@@ -9,7 +9,7 @@ const traverse = require("@babel/traverse").default;
|
|
|
9
9
|
const BASE_NAME = "setRef";
|
|
10
10
|
export const renameUseReferenceSetsTransform = {
|
|
11
11
|
id: "rename-use-reference-sets",
|
|
12
|
-
description: "Renames useRef(new Set()) variables to $setRef/$setRef2/... or setRef/setRef2/... when usage is limited to safe Set operations
|
|
12
|
+
description: "Renames useRef(new Set()) variables to $setRef/$setRef2/... or setRef/setRef2/... when usage is limited to safe Set operations or read-only .current access.",
|
|
13
13
|
scope: "file",
|
|
14
14
|
parallelizable: true,
|
|
15
15
|
transform(context) {
|
|
@@ -37,7 +37,9 @@ export const renameUseReferenceSetsTransform = {
|
|
|
37
37
|
const usage = getSetReferenceUsage(binding);
|
|
38
38
|
if (!usage.isSafe)
|
|
39
39
|
return;
|
|
40
|
-
if (!usage.hasSetMethodCall &&
|
|
40
|
+
if (!usage.hasSetMethodCall &&
|
|
41
|
+
!usage.hasSizeRead &&
|
|
42
|
+
!usage.hasCurrentRead)
|
|
41
43
|
return;
|
|
42
44
|
group.add({
|
|
43
45
|
scope: path.scope,
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Scope } from "@babel/traverse";
|
|
2
|
+
import type { Node } from "@babel/types";
|
|
3
|
+
export declare const collectFirstProgramScopeAssignments: (options: {
|
|
4
|
+
exportedNames: ReadonlySet<string>;
|
|
5
|
+
programScope: Scope;
|
|
6
|
+
}) => Map<string, {
|
|
7
|
+
rhs: Node;
|
|
8
|
+
statementIndex: number;
|
|
9
|
+
}>;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { isStableRenamed } from "../../core/stable-naming.js";
|
|
3
|
+
import { hasDisallowedFunctionClassAssignmentReference } from "./has-disallowed-function-class-assignment-reference.js";
|
|
4
|
+
const ALWAYS_STABLE_REFERENCE_IDENTIFIER_NAMES = [
|
|
5
|
+
"__dirname",
|
|
6
|
+
"__filename",
|
|
7
|
+
"arguments",
|
|
8
|
+
"Buffer",
|
|
9
|
+
"Promise",
|
|
10
|
+
"clearInterval",
|
|
11
|
+
"clearTimeout",
|
|
12
|
+
"console",
|
|
13
|
+
"document",
|
|
14
|
+
"eval",
|
|
15
|
+
"exports",
|
|
16
|
+
"global",
|
|
17
|
+
"globalThis",
|
|
18
|
+
"module",
|
|
19
|
+
"process",
|
|
20
|
+
"queueMicrotask",
|
|
21
|
+
"require",
|
|
22
|
+
"self",
|
|
23
|
+
"setInterval",
|
|
24
|
+
"setTimeout",
|
|
25
|
+
"window",
|
|
26
|
+
];
|
|
27
|
+
const getTopLevelAssignmentPosition = (path) => {
|
|
28
|
+
let current = path;
|
|
29
|
+
let fromFunctionOrClass = false;
|
|
30
|
+
while (current.parentPath) {
|
|
31
|
+
if (current.isFunction())
|
|
32
|
+
fromFunctionOrClass = true;
|
|
33
|
+
if (current.isClass())
|
|
34
|
+
fromFunctionOrClass = true;
|
|
35
|
+
if (current.parentPath.isProgram()) {
|
|
36
|
+
return typeof current.key === "number"
|
|
37
|
+
? { statementIndex: current.key, fromFunctionOrClass }
|
|
38
|
+
: undefined;
|
|
39
|
+
}
|
|
40
|
+
current = current.parentPath;
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
};
|
|
44
|
+
export const collectFirstProgramScopeAssignments = (options) => {
|
|
45
|
+
const { exportedNames, programScope } = options;
|
|
46
|
+
const allowedReferenceIdentifierNames = new Set([
|
|
47
|
+
...Object.keys(programScope.globals),
|
|
48
|
+
...exportedNames,
|
|
49
|
+
...ALWAYS_STABLE_REFERENCE_IDENTIFIER_NAMES,
|
|
50
|
+
"Infinity",
|
|
51
|
+
"NaN",
|
|
52
|
+
"undefined",
|
|
53
|
+
]);
|
|
54
|
+
const firstAssignmentByName = new Map();
|
|
55
|
+
for (const [name, binding] of Object.entries(programScope.bindings)) {
|
|
56
|
+
if (isStableRenamed(name))
|
|
57
|
+
continue;
|
|
58
|
+
if (exportedNames.has(name))
|
|
59
|
+
continue;
|
|
60
|
+
let firstAssignment;
|
|
61
|
+
for (const violation of binding.constantViolations) {
|
|
62
|
+
const assignmentPath = violation.isAssignmentExpression()
|
|
63
|
+
? violation
|
|
64
|
+
: violation.parentPath?.isAssignmentExpression()
|
|
65
|
+
? violation.parentPath
|
|
66
|
+
: undefined;
|
|
67
|
+
if (!assignmentPath)
|
|
68
|
+
continue;
|
|
69
|
+
const assignmentExpression = assignmentPath.node;
|
|
70
|
+
if (assignmentExpression.operator !== "=")
|
|
71
|
+
continue;
|
|
72
|
+
if (!t.isIdentifier(assignmentExpression.left, { name }))
|
|
73
|
+
continue;
|
|
74
|
+
const assignmentPosition = getTopLevelAssignmentPosition(assignmentPath);
|
|
75
|
+
if (!assignmentPosition)
|
|
76
|
+
continue;
|
|
77
|
+
if (assignmentPosition.fromFunctionOrClass &&
|
|
78
|
+
hasDisallowedFunctionClassAssignmentReference({
|
|
79
|
+
rhs: assignmentExpression.right,
|
|
80
|
+
currentName: name,
|
|
81
|
+
programScope,
|
|
82
|
+
allowedReferenceIdentifierNames,
|
|
83
|
+
})) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const statementIndex = assignmentPosition.statementIndex;
|
|
87
|
+
const nodeStart = assignmentExpression.start ?? Number.MAX_SAFE_INTEGER;
|
|
88
|
+
if (!firstAssignment ||
|
|
89
|
+
statementIndex < firstAssignment.statementIndex ||
|
|
90
|
+
(statementIndex === firstAssignment.statementIndex &&
|
|
91
|
+
nodeStart < firstAssignment.nodeStart)) {
|
|
92
|
+
firstAssignment = {
|
|
93
|
+
rhs: assignmentExpression.right,
|
|
94
|
+
statementIndex,
|
|
95
|
+
nodeStart,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (!firstAssignment)
|
|
100
|
+
continue;
|
|
101
|
+
firstAssignmentByName.set(name, {
|
|
102
|
+
rhs: firstAssignment.rhs,
|
|
103
|
+
statementIndex: firstAssignment.statementIndex,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
return firstAssignmentByName;
|
|
107
|
+
};
|
|
@@ -4,29 +4,29 @@ export const collectNestedProgramScopeVariableInitializers = (options) => {
|
|
|
4
4
|
const { node, statementIndex, exportedNames, programScope, firstAssignmentByName, } = options;
|
|
5
5
|
const results = [];
|
|
6
6
|
const tryAddFromVariableDeclarator = (variableDeclarator) => {
|
|
7
|
-
if (!t.isIdentifier(variableDeclarator.id))
|
|
8
|
-
return;
|
|
9
|
-
const name = variableDeclarator.id.name;
|
|
10
|
-
if (isStableRenamed(name))
|
|
11
|
-
return;
|
|
12
|
-
if (exportedNames.has(name))
|
|
13
|
-
return;
|
|
14
7
|
if (!variableDeclarator.init)
|
|
15
8
|
return;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
9
|
+
const names = Object.keys(t.getBindingIdentifiers(variableDeclarator.id));
|
|
10
|
+
for (const name of names) {
|
|
11
|
+
if (isStableRenamed(name))
|
|
12
|
+
continue;
|
|
13
|
+
if (exportedNames.has(name))
|
|
14
|
+
continue;
|
|
15
|
+
// `var` declarations inside top-level blocks (e.g. `if (...) { var x = ... }`) are
|
|
16
|
+
// still program-scope bindings. Only include them if the binding actually belongs
|
|
17
|
+
// to the program scope (not a nested function scope).
|
|
18
|
+
const binding = programScope.getBinding(name);
|
|
19
|
+
if (binding?.scope !== programScope)
|
|
20
|
+
continue;
|
|
21
|
+
const assignmentInfo = firstAssignmentByName.get(name);
|
|
22
|
+
if (assignmentInfo && assignmentInfo.statementIndex < statementIndex) {
|
|
23
|
+
// Precedence rule: if a binding is written via an earlier top-level assignment
|
|
24
|
+
// before a later initializer (including nested `var` redeclarations), prefer the
|
|
25
|
+
// first write for stable naming.
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
results.push({ name, init: variableDeclarator.init });
|
|
28
29
|
}
|
|
29
|
-
results.push({ name, init: variableDeclarator.init });
|
|
30
30
|
};
|
|
31
31
|
const visit = (nodeToVisit) => {
|
|
32
32
|
if (t.isFunction(nodeToVisit))
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as t from "@babel/types";
|
|
2
2
|
import { isStableRenamed } from "../../core/stable-naming.js";
|
|
3
3
|
import { hashFingerprintNode } from "../../core/fingerprint/hash-fingerprint-node.js";
|
|
4
|
-
import {
|
|
4
|
+
import { collectFirstProgramScopeAssignments } from "./collect-first-program-scope-assignments.js";
|
|
5
5
|
import { collectNestedProgramScopeVariableInitializers } from "./collect-nested-program-scope-variable-initializers.js";
|
|
6
6
|
import { addRenameCandidate } from "./rename-candidate.js";
|
|
7
7
|
export const collectRenameCandidates = (options) => {
|
|
@@ -14,8 +14,7 @@ export const collectRenameCandidates = (options) => {
|
|
|
14
14
|
// / assignment we encounter for that binding.
|
|
15
15
|
const seenCandidateNames = new Set();
|
|
16
16
|
let nodesVisited = 0;
|
|
17
|
-
const firstAssignmentByName =
|
|
18
|
-
program,
|
|
17
|
+
const firstAssignmentByName = collectFirstProgramScopeAssignments({
|
|
19
18
|
exportedNames,
|
|
20
19
|
programScope,
|
|
21
20
|
});
|
|
@@ -36,35 +35,40 @@ export const collectRenameCandidates = (options) => {
|
|
|
36
35
|
if (t.isVariableDeclaration(effectiveStmt)) {
|
|
37
36
|
const variableDeclaration = effectiveStmt;
|
|
38
37
|
for (const decl of variableDeclaration.declarations) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const name = decl.id.name;
|
|
42
|
-
if (isStableRenamed(name))
|
|
43
|
-
continue;
|
|
44
|
-
if (exportedNames.has(name))
|
|
38
|
+
const names = Object.keys(t.getBindingIdentifiers(decl.id));
|
|
39
|
+
if (names.length === 0)
|
|
45
40
|
continue;
|
|
46
41
|
if (!decl.init) {
|
|
47
42
|
// No initializer: if there's a later top-level `name = ...`, we'll pick it up
|
|
48
43
|
// from `firstAssignmentByName` below.
|
|
49
44
|
continue;
|
|
50
45
|
}
|
|
51
|
-
const assignmentInfo = firstAssignmentByName.get(name);
|
|
52
|
-
if (assignmentInfo && assignmentInfo.statementIndex < statementIndex) {
|
|
53
|
-
// Precedence rule: if a binding is written via a direct Program-body assignment
|
|
54
|
-
// before a later redeclaration initializer, prefer the first write for stable
|
|
55
|
-
// naming. Example: `var a; a = 1; var a = 2;` hashes based on `1`, not `2`.
|
|
56
|
-
continue;
|
|
57
|
-
}
|
|
58
46
|
const hash = hashFingerprintNode(decl.init);
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
47
|
+
for (const name of names) {
|
|
48
|
+
if (isStableRenamed(name))
|
|
49
|
+
continue;
|
|
50
|
+
if (exportedNames.has(name))
|
|
51
|
+
continue;
|
|
52
|
+
const assignmentInfo = firstAssignmentByName.get(name);
|
|
53
|
+
if (variableDeclaration.kind !== "const" &&
|
|
54
|
+
assignmentInfo &&
|
|
55
|
+
assignmentInfo.statementIndex < statementIndex) {
|
|
56
|
+
// Precedence rule: if a mutable binding is written via an earlier top-level
|
|
57
|
+
// assignment before a later redeclaration initializer, prefer the first write
|
|
58
|
+
// for stable naming. Example: `var a; a = 1; var a = 2;` hashes based on `1`,
|
|
59
|
+
// not `2`.
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
addRenameCandidate({
|
|
63
|
+
candidates,
|
|
64
|
+
hashToNames,
|
|
65
|
+
seenCandidateNames,
|
|
66
|
+
name,
|
|
67
|
+
hash,
|
|
68
|
+
kind: variableDeclaration.kind,
|
|
69
|
+
scope: programScope,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
68
72
|
}
|
|
69
73
|
}
|
|
70
74
|
else if (t.isFunctionDeclaration(effectiveStmt)) {
|
|
@@ -156,7 +160,8 @@ export const collectRenameCandidates = (options) => {
|
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
162
|
}
|
|
159
|
-
// Pass 2: Add the first write for any binding that hasn't already
|
|
163
|
+
// Pass 2: Add the first top-level write for any binding that hasn't already
|
|
164
|
+
// been fingerprinted.
|
|
160
165
|
for (const [name, { rhs }] of firstAssignmentByName) {
|
|
161
166
|
if (seenCandidateNames.has(name))
|
|
162
167
|
continue;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Scope } from "@babel/traverse";
|
|
2
|
+
import type { Node } from "@babel/types";
|
|
3
|
+
export declare const hasDisallowedFunctionClassAssignmentReference: (options: {
|
|
4
|
+
rhs: Node;
|
|
5
|
+
currentName: string;
|
|
6
|
+
programScope: Scope;
|
|
7
|
+
allowedReferenceIdentifierNames: ReadonlySet<string>;
|
|
8
|
+
}) => boolean;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { isStableRenamed } from "../../core/stable-naming.js";
|
|
3
|
+
const isNonReferenceIdentifier = (parent, parentKey) => {
|
|
4
|
+
if (!parent || !parentKey)
|
|
5
|
+
return false;
|
|
6
|
+
if (t.isMemberExpression(parent) || t.isOptionalMemberExpression(parent)) {
|
|
7
|
+
return parentKey === "property" && !parent.computed;
|
|
8
|
+
}
|
|
9
|
+
if (t.isObjectProperty(parent) ||
|
|
10
|
+
t.isObjectMethod(parent) ||
|
|
11
|
+
t.isClassMethod(parent) ||
|
|
12
|
+
t.isClassProperty(parent)) {
|
|
13
|
+
return parentKey === "key" && !parent.computed;
|
|
14
|
+
}
|
|
15
|
+
return false;
|
|
16
|
+
};
|
|
17
|
+
const collectReferencedIdentifierNames = (node, identifiers, parent, parentKey) => {
|
|
18
|
+
if (t.isIdentifier(node)) {
|
|
19
|
+
if (!isNonReferenceIdentifier(parent, parentKey)) {
|
|
20
|
+
identifiers.add(node.name);
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const keys = t.VISITOR_KEYS[node.type];
|
|
25
|
+
if (!keys)
|
|
26
|
+
return;
|
|
27
|
+
const nodeRecord = node;
|
|
28
|
+
for (const key of keys) {
|
|
29
|
+
const value = nodeRecord[key];
|
|
30
|
+
if (Array.isArray(value)) {
|
|
31
|
+
for (const item of value) {
|
|
32
|
+
if (item && typeof item === "object" && "type" in item) {
|
|
33
|
+
collectReferencedIdentifierNames(item, identifiers, node, key);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (value && typeof value === "object" && "type" in value) {
|
|
39
|
+
collectReferencedIdentifierNames(value, identifiers, node, key);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const isProgramScopeConstBinding = (options) => {
|
|
44
|
+
const { programScope, identifierName } = options;
|
|
45
|
+
const referencedBinding = programScope.getBinding(identifierName);
|
|
46
|
+
return (referencedBinding?.scope === programScope &&
|
|
47
|
+
referencedBinding.kind === "const");
|
|
48
|
+
};
|
|
49
|
+
const isAllowedReferenceIdentifierName = (options) => {
|
|
50
|
+
const { currentName, identifierName, programScope, allowedReferenceIdentifierNames, } = options;
|
|
51
|
+
if (identifierName === currentName)
|
|
52
|
+
return true;
|
|
53
|
+
if (isStableRenamed(identifierName))
|
|
54
|
+
return true;
|
|
55
|
+
if (allowedReferenceIdentifierNames.has(identifierName))
|
|
56
|
+
return true;
|
|
57
|
+
return isProgramScopeConstBinding({ programScope, identifierName });
|
|
58
|
+
};
|
|
59
|
+
export const hasDisallowedFunctionClassAssignmentReference = (options) => {
|
|
60
|
+
const { rhs, currentName, programScope, allowedReferenceIdentifierNames } = options;
|
|
61
|
+
const referencedIdentifierNames = new Set();
|
|
62
|
+
collectReferencedIdentifierNames(rhs, referencedIdentifierNames);
|
|
63
|
+
for (const identifierName of referencedIdentifierNames) {
|
|
64
|
+
if (!isAllowedReferenceIdentifierName({
|
|
65
|
+
currentName,
|
|
66
|
+
identifierName,
|
|
67
|
+
programScope,
|
|
68
|
+
allowedReferenceIdentifierNames,
|
|
69
|
+
})) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return false;
|
|
74
|
+
};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"recommendedOrder": 1,
|
|
4
|
-
"notes": "Renames program-scope bindings to stable `$h_<hash>` names (simple identifiers only; destructuring patterns are skipped; uninitialized var/let bindings are stabilized only via direct top-level `x = ...` assignment statements; collisions are disambiguated with an encounter-order suffix). For classic scripts/UMD bundles, renaming globals can still be risky; see transform description and safety gates. Note: in scripts, sloppy-mode `this.foo` is treated conservatively as a possible global-object property lookup, and dynamic computed global-object lookups (including `this[expr]`) cause `var`/`function` renames to be skipped for the file. Default behavior is now unsafe with respect to dynamic-name hazards (e.g. direct eval): it will still run, which improves diff stability but may produce non-runnable output.",
|
|
2
|
+
"notes": "Renames program-scope bindings to stable `$h_<hash>` names (including destructuring-bound identifiers; uninitialized var/let bindings are stabilized via their first program-scope `x = ...` assignment. Assignments discovered inside function/class bodies are considered only when RHS identifier references stay in a stable allowlist: globals/known runtime names, already-stabilized names, self-reference, or program-scope const bindings; collisions are disambiguated with an encounter-order suffix). For classic scripts/UMD bundles, renaming globals can still be risky; see transform description and safety gates. Note: in scripts, sloppy-mode `this.foo` is treated conservatively as a possible global-object property lookup, and dynamic computed global-object lookups (including `this[expr]`) cause `var`/`function` renames to be skipped for the file. Default behavior is now unsafe with respect to dynamic-name hazards (e.g. direct eval): it will still run, which improves diff stability but may produce non-runnable output.",
|
|
5
3
|
"evaluations": {
|
|
6
4
|
"claude-code-2.1.10:claude-code-2.1.11": {
|
|
7
|
-
"diffSizePercent":
|
|
8
|
-
"evaluatedAt": "2026-02-
|
|
9
|
-
"changedLines":
|
|
10
|
-
"durationSeconds":
|
|
11
|
-
"stableNames":
|
|
5
|
+
"diffSizePercent": 77.95101485429187,
|
|
6
|
+
"evaluatedAt": "2026-02-21T15:43:38.877Z",
|
|
7
|
+
"changedLines": 114776,
|
|
8
|
+
"durationSeconds": 43.780172209,
|
|
9
|
+
"stableNames": 15218
|
|
12
10
|
}
|
|
13
|
-
}
|
|
11
|
+
},
|
|
12
|
+
"recommended": true,
|
|
13
|
+
"recommendedOrder": 1
|
|
14
14
|
}
|
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.116.
|
|
5
|
+
"version": "1.116.2",
|
|
6
6
|
"description": "Transform minified JavaScript/TypeScript into a more readable form using deterministic AST-based transforms.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { Scope } from "@babel/traverse";
|
|
2
|
-
import type { Node, Program } from "@babel/types";
|
|
3
|
-
type FirstProgramBodyAssignment = {
|
|
4
|
-
rhs: Node;
|
|
5
|
-
statementIndex: number;
|
|
6
|
-
};
|
|
7
|
-
export declare const collectFirstProgramBodyAssignments: (options: {
|
|
8
|
-
program: Program;
|
|
9
|
-
exportedNames: ReadonlySet<string>;
|
|
10
|
-
programScope: Scope;
|
|
11
|
-
}) => Map<string, FirstProgramBodyAssignment>;
|
|
12
|
-
export {};
|
package/dist/transforms-by-id/stabilize-top-level-bindings/collect-first-program-body-assignments.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import * as t from "@babel/types";
|
|
2
|
-
import { isStableRenamed } from "../../core/stable-naming.js";
|
|
3
|
-
export const collectFirstProgramBodyAssignments = (options) => {
|
|
4
|
-
const { program, exportedNames, programScope } = options;
|
|
5
|
-
const firstAssignmentByName = new Map();
|
|
6
|
-
for (const [statementIndex, stmt] of program.body.entries()) {
|
|
7
|
-
if (!t.isExpressionStatement(stmt))
|
|
8
|
-
continue;
|
|
9
|
-
const expression = stmt.expression;
|
|
10
|
-
if (!t.isAssignmentExpression(expression))
|
|
11
|
-
continue;
|
|
12
|
-
if (expression.operator !== "=")
|
|
13
|
-
continue;
|
|
14
|
-
const left = expression.left;
|
|
15
|
-
if (!t.isIdentifier(left))
|
|
16
|
-
continue;
|
|
17
|
-
const name = left.name;
|
|
18
|
-
if (firstAssignmentByName.has(name))
|
|
19
|
-
continue;
|
|
20
|
-
if (isStableRenamed(name))
|
|
21
|
-
continue;
|
|
22
|
-
if (exportedNames.has(name))
|
|
23
|
-
continue;
|
|
24
|
-
if (!programScope.getBinding(name))
|
|
25
|
-
continue;
|
|
26
|
-
firstAssignmentByName.set(name, { rhs: expression.right, statementIndex });
|
|
27
|
-
}
|
|
28
|
-
return firstAssignmentByName;
|
|
29
|
-
};
|