miniread 1.4.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/expand-sequence-expressions-v4/expand-expression-statement-sequence.d.ts +3 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-expression-statement-sequence.js +86 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-return-sequence.d.ts +3 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-return-sequence.js +91 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-sequence-expressions-v4-transform.d.ts +2 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-sequence-expressions-v4-transform.js +48 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-throw-sequence.d.ts +3 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-throw-sequence.js +101 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-variable-declaration-sequence.d.ts +3 -0
- package/dist/transforms/expand-sequence-expressions-v4/expand-variable-declaration-sequence.js +99 -0
- 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 +4 -0
- package/package.json +1 -1
- package/transform-manifest.json +25 -5
package/dist/transforms/expand-sequence-expressions-v4/expand-expression-statement-sequence.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
4
|
+
const t = require("@babel/types");
|
|
5
|
+
const canReplaceWithMultiple = (path) => path.parentPath.isProgram() ||
|
|
6
|
+
path.parentPath.isBlockStatement() ||
|
|
7
|
+
path.parentPath.isStaticBlock() ||
|
|
8
|
+
path.parentPath.isSwitchCase();
|
|
9
|
+
const canWrapInBlock = (path) => {
|
|
10
|
+
const parentPath = path.parentPath;
|
|
11
|
+
if (parentPath.isIfStatement() &&
|
|
12
|
+
(path.key === "consequent" || path.key === "alternate")) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
if ((parentPath.isForStatement() ||
|
|
16
|
+
parentPath.isForInStatement() ||
|
|
17
|
+
parentPath.isForOfStatement() ||
|
|
18
|
+
parentPath.isWhileStatement() ||
|
|
19
|
+
parentPath.isDoWhileStatement() ||
|
|
20
|
+
parentPath.isWithStatement() ||
|
|
21
|
+
parentPath.isLabeledStatement()) &&
|
|
22
|
+
path.key === "body") {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
return false;
|
|
26
|
+
};
|
|
27
|
+
const isDirectiveProloguePosition = (path) => {
|
|
28
|
+
const parentPath = path.parentPath;
|
|
29
|
+
if (parentPath.isBlockStatement()) {
|
|
30
|
+
const grandParent = parentPath.parentPath;
|
|
31
|
+
if (parentPath.key !== "body")
|
|
32
|
+
return false;
|
|
33
|
+
if (!grandParent.isFunction())
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
else if (!parentPath.isProgram()) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const siblings = parentPath.get("body");
|
|
40
|
+
if (!Array.isArray(siblings))
|
|
41
|
+
return false;
|
|
42
|
+
const index = siblings.findIndex((sibling) => sibling.node === path.node);
|
|
43
|
+
if (index === -1)
|
|
44
|
+
return false;
|
|
45
|
+
for (let bodyIndex = 0; bodyIndex < index; bodyIndex++) {
|
|
46
|
+
const sibling = siblings[bodyIndex];
|
|
47
|
+
if (!sibling)
|
|
48
|
+
return false;
|
|
49
|
+
if (!sibling.isExpressionStatement())
|
|
50
|
+
return false;
|
|
51
|
+
if (sibling.node.expression.type !== "StringLiteral")
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
};
|
|
56
|
+
export const tryExpandExpressionStatementSequence = (path) => {
|
|
57
|
+
if (!canReplaceWithMultiple(path) && !canWrapInBlock(path))
|
|
58
|
+
return false;
|
|
59
|
+
const expression = path.node.expression;
|
|
60
|
+
if (expression.type !== "SequenceExpression")
|
|
61
|
+
return false;
|
|
62
|
+
if (expression.expressions.length < 2)
|
|
63
|
+
return false;
|
|
64
|
+
const firstExpression = expression.expressions[0];
|
|
65
|
+
if (firstExpression?.type === "StringLiteral" &&
|
|
66
|
+
canReplaceWithMultiple(path) &&
|
|
67
|
+
isDirectiveProloguePosition(path)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
const statements = expression.expressions.map((expr) => {
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
72
|
+
return t.expressionStatement(
|
|
73
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
74
|
+
t.cloneNode(expr, true));
|
|
75
|
+
});
|
|
76
|
+
if (canReplaceWithMultiple(path)) {
|
|
77
|
+
path.replaceWithMultiple(statements);
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (canWrapInBlock(path)) {
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
82
|
+
path.replaceWith(t.blockStatement(statements));
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
};
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
4
|
+
const t = require("@babel/types");
|
|
5
|
+
const canReplaceWithMultiple = (path) => {
|
|
6
|
+
return path.parentPath.isBlockStatement() || path.parentPath.isSwitchCase();
|
|
7
|
+
};
|
|
8
|
+
const canWrapInBlock = (path) => {
|
|
9
|
+
const parentPath = path.parentPath;
|
|
10
|
+
if (parentPath.isIfStatement() &&
|
|
11
|
+
(path.key === "consequent" || path.key === "alternate")) {
|
|
12
|
+
return true;
|
|
13
|
+
}
|
|
14
|
+
if ((parentPath.isForStatement() ||
|
|
15
|
+
parentPath.isForInStatement() ||
|
|
16
|
+
parentPath.isForOfStatement() ||
|
|
17
|
+
parentPath.isWhileStatement() ||
|
|
18
|
+
parentPath.isDoWhileStatement() ||
|
|
19
|
+
parentPath.isWithStatement() ||
|
|
20
|
+
parentPath.isLabeledStatement()) &&
|
|
21
|
+
path.key === "body") {
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
return false;
|
|
25
|
+
};
|
|
26
|
+
const replaceReturnWithStatements = (path, statements) => {
|
|
27
|
+
if (canReplaceWithMultiple(path)) {
|
|
28
|
+
path.replaceWithMultiple(statements);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
if (canWrapInBlock(path)) {
|
|
32
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
33
|
+
path.replaceWith(t.blockStatement(statements));
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
37
|
+
};
|
|
38
|
+
const isDirectiveProloguePosition = (path) => {
|
|
39
|
+
if (!path.parentPath.isBlockStatement())
|
|
40
|
+
return false;
|
|
41
|
+
if (path.parentPath.key !== "body")
|
|
42
|
+
return false;
|
|
43
|
+
if (!path.parentPath.parentPath.isFunction())
|
|
44
|
+
return false;
|
|
45
|
+
const siblings = path.parentPath.get("body");
|
|
46
|
+
if (!Array.isArray(siblings))
|
|
47
|
+
return false;
|
|
48
|
+
const index = siblings.findIndex((sibling) => sibling.node === path.node);
|
|
49
|
+
if (index === -1)
|
|
50
|
+
return false;
|
|
51
|
+
for (let bodyIndex = 0; bodyIndex < index; bodyIndex++) {
|
|
52
|
+
const sibling = siblings[bodyIndex];
|
|
53
|
+
if (!sibling)
|
|
54
|
+
return false;
|
|
55
|
+
if (!sibling.isExpressionStatement())
|
|
56
|
+
return false;
|
|
57
|
+
if (sibling.node.expression.type !== "StringLiteral")
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
return true;
|
|
61
|
+
};
|
|
62
|
+
export const tryExpandReturnSequence = (path) => {
|
|
63
|
+
if (!canReplaceWithMultiple(path) && !canWrapInBlock(path))
|
|
64
|
+
return false;
|
|
65
|
+
const argument = path.node.argument;
|
|
66
|
+
if (!argument)
|
|
67
|
+
return false;
|
|
68
|
+
if (argument.type !== "SequenceExpression")
|
|
69
|
+
return false;
|
|
70
|
+
if (argument.expressions.length < 2)
|
|
71
|
+
return false;
|
|
72
|
+
const leadingExpressions = argument.expressions.slice(0, -1);
|
|
73
|
+
const lastExpression = argument.expressions.at(-1);
|
|
74
|
+
if (!lastExpression)
|
|
75
|
+
return false;
|
|
76
|
+
const firstExpression = leadingExpressions[0];
|
|
77
|
+
if (firstExpression?.type === "StringLiteral" &&
|
|
78
|
+
isDirectiveProloguePosition(path)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const statements = leadingExpressions.map((expression) => {
|
|
82
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
83
|
+
return t.expressionStatement(
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
85
|
+
t.cloneNode(expression, true));
|
|
86
|
+
});
|
|
87
|
+
statements.push(
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
89
|
+
t.returnStatement(t.cloneNode(lastExpression, true)));
|
|
90
|
+
return replaceReturnWithStatements(path, statements);
|
|
91
|
+
};
|
package/dist/transforms/expand-sequence-expressions-v4/expand-sequence-expressions-v4-transform.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { tryExpandExpressionStatementSequence } from "./expand-expression-statement-sequence.js";
|
|
3
|
+
import { tryExpandReturnSequence } from "./expand-return-sequence.js";
|
|
4
|
+
import { tryExpandThrowSequence } from "./expand-throw-sequence.js";
|
|
5
|
+
import { tryExpandVariableDeclarationSequenceInitializers } from "./expand-variable-declaration-sequence.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
|
+
export const expandSequenceExpressionsV4Transform = {
|
|
10
|
+
id: "expand-sequence-expressions-v4",
|
|
11
|
+
description: "Expands comma operator sequences in returns, throws, statements (including control-flow bodies), and variable initializers",
|
|
12
|
+
scope: "file",
|
|
13
|
+
parallelizable: true,
|
|
14
|
+
transform(context) {
|
|
15
|
+
const { projectGraph } = context;
|
|
16
|
+
let nodesVisited = 0;
|
|
17
|
+
let transformationsApplied = 0;
|
|
18
|
+
for (const [, fileInfo] of projectGraph.files) {
|
|
19
|
+
traverse(fileInfo.ast, {
|
|
20
|
+
ReturnStatement(path) {
|
|
21
|
+
nodesVisited++;
|
|
22
|
+
if (!tryExpandReturnSequence(path))
|
|
23
|
+
return;
|
|
24
|
+
transformationsApplied += 1;
|
|
25
|
+
},
|
|
26
|
+
ThrowStatement(path) {
|
|
27
|
+
nodesVisited++;
|
|
28
|
+
if (!tryExpandThrowSequence(path))
|
|
29
|
+
return;
|
|
30
|
+
transformationsApplied += 1;
|
|
31
|
+
},
|
|
32
|
+
ExpressionStatement(path) {
|
|
33
|
+
nodesVisited++;
|
|
34
|
+
if (!tryExpandExpressionStatementSequence(path))
|
|
35
|
+
return;
|
|
36
|
+
transformationsApplied += 1;
|
|
37
|
+
},
|
|
38
|
+
VariableDeclaration(path) {
|
|
39
|
+
nodesVisited++;
|
|
40
|
+
if (!tryExpandVariableDeclarationSequenceInitializers(path))
|
|
41
|
+
return;
|
|
42
|
+
transformationsApplied += 1;
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return Promise.resolve({ nodesVisited, transformationsApplied });
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
4
|
+
const t = require("@babel/types");
|
|
5
|
+
const canReplaceWithMultiple = (path) => {
|
|
6
|
+
return (path.parentPath.isProgram() ||
|
|
7
|
+
path.parentPath.isBlockStatement() ||
|
|
8
|
+
path.parentPath.isStaticBlock() ||
|
|
9
|
+
path.parentPath.isSwitchCase());
|
|
10
|
+
};
|
|
11
|
+
const canWrapInBlock = (path) => {
|
|
12
|
+
const parentPath = path.parentPath;
|
|
13
|
+
if (parentPath.isIfStatement() &&
|
|
14
|
+
(path.key === "consequent" || path.key === "alternate")) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
if ((parentPath.isForStatement() ||
|
|
18
|
+
parentPath.isForInStatement() ||
|
|
19
|
+
parentPath.isForOfStatement() ||
|
|
20
|
+
parentPath.isWhileStatement() ||
|
|
21
|
+
parentPath.isDoWhileStatement() ||
|
|
22
|
+
parentPath.isWithStatement() ||
|
|
23
|
+
parentPath.isLabeledStatement()) &&
|
|
24
|
+
path.key === "body") {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
29
|
+
const replaceThrowWithStatements = (path, statements) => {
|
|
30
|
+
if (canReplaceWithMultiple(path)) {
|
|
31
|
+
path.replaceWithMultiple(statements);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
if (canWrapInBlock(path)) {
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
36
|
+
path.replaceWith(t.blockStatement(statements));
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
};
|
|
41
|
+
const isDirectiveProloguePosition = (path) => {
|
|
42
|
+
const parentPath = path.parentPath;
|
|
43
|
+
if (parentPath.isBlockStatement()) {
|
|
44
|
+
const grandParent = parentPath.parentPath;
|
|
45
|
+
if (parentPath.key !== "body")
|
|
46
|
+
return false;
|
|
47
|
+
if (!grandParent.isFunction())
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
else if (!parentPath.isProgram()) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
const siblings = parentPath.get("body");
|
|
54
|
+
if (!Array.isArray(siblings))
|
|
55
|
+
return false;
|
|
56
|
+
const index = siblings.findIndex((sibling) => sibling.node === path.node);
|
|
57
|
+
if (index === -1)
|
|
58
|
+
return false;
|
|
59
|
+
for (let bodyIndex = 0; bodyIndex < index; bodyIndex++) {
|
|
60
|
+
const sibling = siblings[bodyIndex];
|
|
61
|
+
if (!sibling)
|
|
62
|
+
return false;
|
|
63
|
+
if (!sibling.isExpressionStatement())
|
|
64
|
+
return false;
|
|
65
|
+
if (sibling.node.expression.type !== "StringLiteral")
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
};
|
|
70
|
+
export const tryExpandThrowSequence = (path) => {
|
|
71
|
+
if (!canReplaceWithMultiple(path) && !canWrapInBlock(path))
|
|
72
|
+
return false;
|
|
73
|
+
const argument = path.node.argument;
|
|
74
|
+
if (argument.type !== "SequenceExpression")
|
|
75
|
+
return false;
|
|
76
|
+
if (argument.expressions.length < 2)
|
|
77
|
+
return false;
|
|
78
|
+
const leadingExpressions = argument.expressions.slice(0, -1);
|
|
79
|
+
const lastExpression = argument.expressions.at(-1);
|
|
80
|
+
if (!lastExpression)
|
|
81
|
+
return false;
|
|
82
|
+
const firstExpression = leadingExpressions[0];
|
|
83
|
+
const shouldWrapFirstStringLiteral = firstExpression?.type === "StringLiteral" &&
|
|
84
|
+
isDirectiveProloguePosition(path);
|
|
85
|
+
const statements = leadingExpressions.map((expression) => {
|
|
86
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
87
|
+
let clonedExpression = t.cloneNode(expression, true);
|
|
88
|
+
if (shouldWrapFirstStringLiteral && expression === firstExpression) {
|
|
89
|
+
// Prevent inserting a directive prologue statement like `"use strict";`.
|
|
90
|
+
// `("use strict");` is not treated as a directive.
|
|
91
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
92
|
+
clonedExpression = t.parenthesizedExpression(clonedExpression);
|
|
93
|
+
}
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
95
|
+
return t.expressionStatement(clonedExpression);
|
|
96
|
+
});
|
|
97
|
+
statements.push(
|
|
98
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
99
|
+
t.throwStatement(t.cloneNode(lastExpression, true)));
|
|
100
|
+
return replaceThrowWithStatements(path, statements);
|
|
101
|
+
};
|
package/dist/transforms/expand-sequence-expressions-v4/expand-variable-declaration-sequence.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const require = createRequire(import.meta.url);
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
4
|
+
const t = require("@babel/types");
|
|
5
|
+
const createExpressionStatement = (expression) => {
|
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
7
|
+
return t.expressionStatement(
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
9
|
+
t.cloneNode(expression, true));
|
|
10
|
+
};
|
|
11
|
+
const createVariableDeclarationStatement = (kind, declarator) => {
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
13
|
+
return t.variableDeclaration(kind, [declarator]);
|
|
14
|
+
};
|
|
15
|
+
const createVariableDeclarator = (id, init) => {
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
17
|
+
return t.variableDeclarator(
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
19
|
+
t.cloneNode(id, true), init
|
|
20
|
+
? // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
|
|
21
|
+
t.cloneNode(init, true)
|
|
22
|
+
: undefined);
|
|
23
|
+
};
|
|
24
|
+
const isSupportedStatementContainer = (path) => {
|
|
25
|
+
const parentPath = path.parentPath;
|
|
26
|
+
if (!parentPath)
|
|
27
|
+
return false;
|
|
28
|
+
return (parentPath.isProgram() ||
|
|
29
|
+
parentPath.isBlockStatement() ||
|
|
30
|
+
parentPath.isStaticBlock() ||
|
|
31
|
+
parentPath.isSwitchCase());
|
|
32
|
+
};
|
|
33
|
+
const isDirectiveProloguePosition = (path) => {
|
|
34
|
+
const parentPath = path.parentPath;
|
|
35
|
+
if (!parentPath)
|
|
36
|
+
return false;
|
|
37
|
+
if (parentPath.isBlockStatement()) {
|
|
38
|
+
const grandParent = parentPath.parentPath;
|
|
39
|
+
if (parentPath.key !== "body")
|
|
40
|
+
return false;
|
|
41
|
+
if (!grandParent.isFunction())
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
else if (!parentPath.isProgram()) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
const siblings = parentPath.get("body");
|
|
48
|
+
if (!Array.isArray(siblings))
|
|
49
|
+
return false;
|
|
50
|
+
const index = siblings.findIndex((sibling) => sibling.node === path.node);
|
|
51
|
+
if (index === -1)
|
|
52
|
+
return false;
|
|
53
|
+
for (let bodyIndex = 0; bodyIndex < index; bodyIndex++) {
|
|
54
|
+
const sibling = siblings[bodyIndex];
|
|
55
|
+
if (!sibling)
|
|
56
|
+
return false;
|
|
57
|
+
if (!sibling.isExpressionStatement())
|
|
58
|
+
return false;
|
|
59
|
+
if (sibling.node.expression.type !== "StringLiteral")
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
};
|
|
64
|
+
export const tryExpandVariableDeclarationSequenceInitializers = (path) => {
|
|
65
|
+
if (!isSupportedStatementContainer(path))
|
|
66
|
+
return false;
|
|
67
|
+
if (isDirectiveProloguePosition(path)) {
|
|
68
|
+
const wouldInsertStringLiteral = path.node.declarations.some((declarator) => declarator.init?.type === "SequenceExpression" &&
|
|
69
|
+
declarator.init.expressions[0]?.type === "StringLiteral");
|
|
70
|
+
if (wouldInsertStringLiteral)
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
const hasAnySequence = path.node.declarations.some((declarator) => declarator.init?.type === "SequenceExpression" &&
|
|
74
|
+
declarator.init.expressions.length >= 2);
|
|
75
|
+
if (!hasAnySequence)
|
|
76
|
+
return false;
|
|
77
|
+
const kind = path.node.kind;
|
|
78
|
+
const statements = [];
|
|
79
|
+
for (const declarator of path.node.declarations) {
|
|
80
|
+
const init = declarator.init;
|
|
81
|
+
if (init?.type !== "SequenceExpression") {
|
|
82
|
+
statements.push(createVariableDeclarationStatement(kind, declarator));
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
const leadingExpressions = init.expressions.slice(0, -1);
|
|
86
|
+
const lastExpression = init.expressions.at(-1);
|
|
87
|
+
if (!lastExpression) {
|
|
88
|
+
statements.push(createVariableDeclarationStatement(kind, declarator));
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
for (const expression of leadingExpressions) {
|
|
92
|
+
statements.push(createExpressionStatement(expression));
|
|
93
|
+
}
|
|
94
|
+
const newDeclarator = createVariableDeclarator(declarator.id, lastExpression);
|
|
95
|
+
statements.push(createVariableDeclarationStatement(kind, newDeclarator));
|
|
96
|
+
}
|
|
97
|
+
path.replaceWithMultiple(statements);
|
|
98
|
+
return true;
|
|
99
|
+
};
|
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 };
|
|
@@ -4,6 +4,7 @@ import { expandSequenceExpressionsTransform } from "./expand-sequence-expression
|
|
|
4
4
|
import { expandSequenceExpressionsV2Transform } from "./expand-sequence-expressions-v2/expand-sequence-expressions-v2-transform.js";
|
|
5
5
|
import { expandSpecialNumberLiteralsTransform } from "./expand-special-number-literals/expand-special-number-literals-transform.js";
|
|
6
6
|
import { expandSequenceExpressionsV3Transform } from "./expand-sequence-expressions-v3/expand-sequence-expressions-v3-transform.js";
|
|
7
|
+
import { expandSequenceExpressionsV4Transform } from "./expand-sequence-expressions-v4/expand-sequence-expressions-v4-transform.js";
|
|
7
8
|
import { expandThrowSequenceTransform } from "./expand-throw-sequence/expand-throw-sequence-transform.js";
|
|
8
9
|
import { expandUndefinedLiteralsTransform } from "./expand-undefined-literals/expand-undefined-literals-transform.js";
|
|
9
10
|
import { renameCatchParametersTransform } from "./rename-catch-parameters/rename-catch-parameters-transform.js";
|
|
@@ -13,6 +14,7 @@ import { renameLoopIndexVariablesTransform } from "./rename-loop-index-variables
|
|
|
13
14
|
import { renamePromiseExecutorParametersTransform } from "./rename-promise-executor-parameters/rename-promise-executor-parameters-transform.js";
|
|
14
15
|
import { renameTimeoutIdsTransform } from "./rename-timeout-ids/rename-timeout-ids-transform.js";
|
|
15
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";
|
|
16
18
|
import { splitVariableDeclarationsTransform } from "./split-variable-declarations/split-variable-declarations-transform.js";
|
|
17
19
|
export const transformRegistry = {
|
|
18
20
|
[expandBooleanLiteralsTransform.id]: expandBooleanLiteralsTransform,
|
|
@@ -21,6 +23,7 @@ export const transformRegistry = {
|
|
|
21
23
|
[expandSequenceExpressionsV2Transform.id]: expandSequenceExpressionsV2Transform,
|
|
22
24
|
[expandSequenceExpressionsV3Transform.id]: expandSequenceExpressionsV3Transform,
|
|
23
25
|
[expandSpecialNumberLiteralsTransform.id]: expandSpecialNumberLiteralsTransform,
|
|
26
|
+
[expandSequenceExpressionsV4Transform.id]: expandSequenceExpressionsV4Transform,
|
|
24
27
|
[expandThrowSequenceTransform.id]: expandThrowSequenceTransform,
|
|
25
28
|
[expandUndefinedLiteralsTransform.id]: expandUndefinedLiteralsTransform,
|
|
26
29
|
[renameCatchParametersTransform.id]: renameCatchParametersTransform,
|
|
@@ -30,6 +33,7 @@ export const transformRegistry = {
|
|
|
30
33
|
[renamePromiseExecutorParametersTransform.id]: renamePromiseExecutorParametersTransform,
|
|
31
34
|
[renameTimeoutIdsTransform.id]: renameTimeoutIdsTransform,
|
|
32
35
|
[renameUseReferenceGuardsTransform.id]: renameUseReferenceGuardsTransform,
|
|
36
|
+
[renameUseReferenceGuardsV2Transform.id]: renameUseReferenceGuardsV2Transform,
|
|
33
37
|
[splitVariableDeclarationsTransform.id]: splitVariableDeclarationsTransform,
|
|
34
38
|
};
|
|
35
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
|
@@ -95,19 +95,39 @@
|
|
|
95
95
|
"scope": "file",
|
|
96
96
|
"parallelizable": true,
|
|
97
97
|
"diffReductionImpact": -0.014391951831788763,
|
|
98
|
-
"recommended":
|
|
98
|
+
"recommended": false,
|
|
99
99
|
"evaluatedAt": "2026-01-23T08:21:23.662Z",
|
|
100
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
101
|
},
|
|
102
|
+
{
|
|
103
|
+
"id": "expand-sequence-expressions-v4",
|
|
104
|
+
"description": "Expands comma operator sequences in returns, throws, statements (including control-flow bodies), and variable initializers",
|
|
105
|
+
"scope": "file",
|
|
106
|
+
"parallelizable": true,
|
|
107
|
+
"diffReductionImpact": -0.01730809158000035,
|
|
108
|
+
"recommended": true,
|
|
109
|
+
"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."
|
|
111
|
+
},
|
|
102
112
|
{
|
|
103
113
|
"id": "rename-use-reference-guards",
|
|
104
114
|
"description": "Renames boolean useRef(false) guard variables to hasRunRef/hasRunRef2/...",
|
|
105
115
|
"scope": "file",
|
|
106
116
|
"parallelizable": true,
|
|
107
117
|
"diffReductionImpact": 0,
|
|
108
|
-
"recommended":
|
|
118
|
+
"recommended": false,
|
|
109
119
|
"evaluatedAt": "2026-01-22T17:03:19.826Z",
|
|
110
|
-
"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."
|
|
111
131
|
},
|
|
112
132
|
{
|
|
113
133
|
"id": "rename-timeout-ids",
|
|
@@ -162,8 +182,8 @@
|
|
|
162
182
|
],
|
|
163
183
|
"presetStats": {
|
|
164
184
|
"recommended": {
|
|
165
|
-
"diffReductionImpact": 0.
|
|
166
|
-
"notes": "Measured with baseline none: 0.
|
|
185
|
+
"diffReductionImpact": 0.0027273928389422997,
|
|
186
|
+
"notes": "Measured with baseline none: 0.27%."
|
|
167
187
|
}
|
|
168
188
|
}
|
|
169
189
|
}
|