miniread 1.5.0 → 1.6.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/rename-use-reference-guards-v2/get-member-expression-for-reference.d.ts +3 -0
- package/dist/transforms/rename-use-reference-guards-v2/get-member-expression-for-reference.js +10 -0
- package/dist/transforms/rename-use-reference-guards-v2/get-reference-usage.d.ts +8 -0
- package/dist/transforms/rename-use-reference-guards-v2/get-reference-usage.js +58 -0
- package/dist/transforms/rename-use-reference-guards-v2/get-target-name.d.ts +2 -0
- package/dist/transforms/rename-use-reference-guards-v2/get-target-name.js +23 -0
- package/dist/transforms/rename-use-reference-guards-v2/is-use-reference-false-initializer.d.ts +2 -0
- package/dist/transforms/rename-use-reference-guards-v2/is-use-reference-false-initializer.js +40 -0
- package/dist/transforms/rename-use-reference-guards-v2/is-valid-binding-identifier.d.ts +1 -0
- package/dist/transforms/rename-use-reference-guards-v2/is-valid-binding-identifier.js +10 -0
- package/dist/transforms/rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.d.ts +3 -0
- package/dist/transforms/rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.js +52 -0
- package/dist/transforms/transform-registry.js +2 -0
- package/package.json +1 -1
- package/transform-manifest.json +12 -2
package/dist/transforms/rename-use-reference-guards-v2/get-member-expression-for-reference.d.ts
ADDED
|
@@ -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,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,23 @@
|
|
|
1
|
+
import { isValidBindingIdentifier } from "./is-valid-binding-identifier.js";
|
|
2
|
+
const BASE_NAME = "hasRunRef";
|
|
3
|
+
// Cap retries to avoid pathological loops while handling large bundles.
|
|
4
|
+
const MAX_CANDIDATES = 1000;
|
|
5
|
+
export const getTargetName = (bindingScope, binding) => {
|
|
6
|
+
const programScope = bindingScope.getProgramParent();
|
|
7
|
+
for (let index = 0; index < MAX_CANDIDATES; index++) {
|
|
8
|
+
const candidate = index === 0 ? BASE_NAME : `${BASE_NAME}${index + 1}`;
|
|
9
|
+
if (!isValidBindingIdentifier(candidate))
|
|
10
|
+
continue;
|
|
11
|
+
// Avoid shadowing bindings in parent scopes.
|
|
12
|
+
if (bindingScope.hasBinding(candidate))
|
|
13
|
+
continue;
|
|
14
|
+
if (Object.hasOwn(programScope.globals, candidate))
|
|
15
|
+
continue;
|
|
16
|
+
const wouldBeShadowed = binding.referencePaths.some((referencePath) => referencePath.scope !== bindingScope &&
|
|
17
|
+
referencePath.scope.hasBinding(candidate));
|
|
18
|
+
if (wouldBeShadowed)
|
|
19
|
+
continue;
|
|
20
|
+
return candidate;
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
};
|
|
@@ -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 @@
|
|
|
1
|
+
export declare const isValidBindingIdentifier: (name: string) => boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { isIdentifierName, isKeyword, isStrictBindReservedWord, } from "@babel/helper-validator-identifier";
|
|
2
|
+
export const isValidBindingIdentifier = (name) => {
|
|
3
|
+
if (!isIdentifierName(name))
|
|
4
|
+
return false;
|
|
5
|
+
if (isKeyword(name))
|
|
6
|
+
return false;
|
|
7
|
+
if (isStrictBindReservedWord(name, true))
|
|
8
|
+
return false;
|
|
9
|
+
return true;
|
|
10
|
+
};
|
package/dist/transforms/rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { getReferenceUsage } from "./get-reference-usage.js";
|
|
3
|
+
import { getTargetName } from "./get-target-name.js";
|
|
4
|
+
import { isUseReferenceFalseInitializer } from "./is-use-reference-false-initializer.js";
|
|
5
|
+
const require = createRequire(import.meta.url);
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
7
|
+
const traverse = require("@babel/traverse").default;
|
|
8
|
+
const renameUseReferenceGuardsV2Transform = {
|
|
9
|
+
id: "rename-use-reference-guards-v2",
|
|
10
|
+
description: "Renames boolean useRef(false) guard variables (including reset-to-false guards) to hasRunRef/hasRunRef2/...",
|
|
11
|
+
scope: "file",
|
|
12
|
+
parallelizable: true,
|
|
13
|
+
transform(context) {
|
|
14
|
+
const { projectGraph } = context;
|
|
15
|
+
let nodesVisited = 0;
|
|
16
|
+
let transformationsApplied = 0;
|
|
17
|
+
for (const [, fileInfo] of projectGraph.files) {
|
|
18
|
+
traverse(fileInfo.ast, {
|
|
19
|
+
VariableDeclarator(path) {
|
|
20
|
+
nodesVisited++;
|
|
21
|
+
const id = path.node.id;
|
|
22
|
+
if (id.type !== "Identifier")
|
|
23
|
+
return;
|
|
24
|
+
if (id.name.length > 2)
|
|
25
|
+
return;
|
|
26
|
+
if (!isUseReferenceFalseInitializer(path.node))
|
|
27
|
+
return;
|
|
28
|
+
const binding = path.scope.getBinding(id.name);
|
|
29
|
+
if (!binding)
|
|
30
|
+
return;
|
|
31
|
+
if (!binding.constant)
|
|
32
|
+
return;
|
|
33
|
+
const usage = getReferenceUsage(binding);
|
|
34
|
+
if (!usage.isSafe || !usage.hasRead || !usage.hasTrueWrite)
|
|
35
|
+
return;
|
|
36
|
+
const targetName = getTargetName(path.scope, binding);
|
|
37
|
+
if (!targetName)
|
|
38
|
+
return;
|
|
39
|
+
if (id.name === targetName)
|
|
40
|
+
return;
|
|
41
|
+
path.scope.rename(id.name, targetName);
|
|
42
|
+
transformationsApplied++;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return Promise.resolve({
|
|
47
|
+
nodesVisited,
|
|
48
|
+
transformationsApplied,
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
export { renameUseReferenceGuardsV2Transform };
|
|
@@ -14,6 +14,7 @@ import { renameLoopIndexVariablesTransform } from "./rename-loop-index-variables
|
|
|
14
14
|
import { renamePromiseExecutorParametersTransform } from "./rename-promise-executor-parameters/rename-promise-executor-parameters-transform.js";
|
|
15
15
|
import { renameTimeoutIdsTransform } from "./rename-timeout-ids/rename-timeout-ids-transform.js";
|
|
16
16
|
import { renameUseReferenceGuardsTransform } from "./rename-use-reference-guards/rename-use-reference-guards-transform.js";
|
|
17
|
+
import { renameUseReferenceGuardsV2Transform } from "./rename-use-reference-guards-v2/rename-use-reference-guards-v2-transform.js";
|
|
17
18
|
import { splitVariableDeclarationsTransform } from "./split-variable-declarations/split-variable-declarations-transform.js";
|
|
18
19
|
export const transformRegistry = {
|
|
19
20
|
[expandBooleanLiteralsTransform.id]: expandBooleanLiteralsTransform,
|
|
@@ -32,6 +33,7 @@ export const transformRegistry = {
|
|
|
32
33
|
[renamePromiseExecutorParametersTransform.id]: renamePromiseExecutorParametersTransform,
|
|
33
34
|
[renameTimeoutIdsTransform.id]: renameTimeoutIdsTransform,
|
|
34
35
|
[renameUseReferenceGuardsTransform.id]: renameUseReferenceGuardsTransform,
|
|
36
|
+
[renameUseReferenceGuardsV2Transform.id]: renameUseReferenceGuardsV2Transform,
|
|
35
37
|
[splitVariableDeclarationsTransform.id]: splitVariableDeclarationsTransform,
|
|
36
38
|
};
|
|
37
39
|
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
|
+
"version": "1.6.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",
|
package/transform-manifest.json
CHANGED
|
@@ -115,9 +115,19 @@
|
|
|
115
115
|
"scope": "file",
|
|
116
116
|
"parallelizable": true,
|
|
117
117
|
"diffReductionImpact": 0,
|
|
118
|
-
"recommended":
|
|
118
|
+
"recommended": false,
|
|
119
119
|
"evaluatedAt": "2026-01-22T17:03:19.826Z",
|
|
120
|
-
"notes": "
|
|
120
|
+
"notes": "Superseded by rename-use-reference-guards-v2.",
|
|
121
|
+
"supersededBy": "rename-use-reference-guards-v2"
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
"id": "rename-use-reference-guards-v2",
|
|
125
|
+
"description": "Renames boolean useRef(false) guard variables (including reset-to-false guards) to hasRunRef/hasRunRef2/...",
|
|
126
|
+
"scope": "file",
|
|
127
|
+
"parallelizable": true,
|
|
128
|
+
"diffReductionImpact": 0,
|
|
129
|
+
"recommended": true,
|
|
130
|
+
"notes": "Supersedes rename-use-reference-guards and also covers guards that reset to false."
|
|
121
131
|
},
|
|
122
132
|
{
|
|
123
133
|
"id": "rename-timeout-ids",
|