miniread 1.11.0 → 1.12.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.
@@ -0,0 +1,3 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type { ExpressionStatement } from "@babel/types";
3
+ export declare const tryExpandExpressionStatementSequence: (path: NodePath<ExpressionStatement>) => boolean;
@@ -0,0 +1,92 @@
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
+ const shouldWrapFirstStringLiteralDirective = firstExpression?.type === "StringLiteral" &&
66
+ canReplaceWithMultiple(path) &&
67
+ isDirectiveProloguePosition(path);
68
+ const statements = expression.expressions.map((expr, index) => {
69
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
70
+ let clonedExpression = t.cloneNode(expr, true);
71
+ if (shouldWrapFirstStringLiteralDirective &&
72
+ index === 0 &&
73
+ expr.type === "StringLiteral") {
74
+ // Prevent inserting a directive prologue statement like `"use strict";`.
75
+ // `("use strict");` is not treated as a directive.
76
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
77
+ clonedExpression = t.parenthesizedExpression(clonedExpression);
78
+ }
79
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
80
+ return t.expressionStatement(clonedExpression);
81
+ });
82
+ if (canReplaceWithMultiple(path)) {
83
+ path.replaceWithMultiple(statements);
84
+ return true;
85
+ }
86
+ if (canWrapInBlock(path)) {
87
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
88
+ path.replaceWith(t.blockStatement(statements));
89
+ return true;
90
+ }
91
+ return false;
92
+ };
@@ -0,0 +1,3 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type { IfStatement } from "@babel/types";
3
+ export declare const tryExpandIfStatementTestSequence: (path: NodePath<IfStatement>) => boolean;
@@ -0,0 +1,104 @@
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 isDirectiveProloguePosition = (path) => {
30
+ const parentPath = path.parentPath;
31
+ if (parentPath.isBlockStatement()) {
32
+ const grandParent = parentPath.parentPath;
33
+ if (parentPath.key !== "body")
34
+ return false;
35
+ if (!grandParent.isFunction())
36
+ return false;
37
+ }
38
+ else if (!parentPath.isProgram()) {
39
+ return false;
40
+ }
41
+ const siblings = parentPath.get("body");
42
+ if (!Array.isArray(siblings))
43
+ return false;
44
+ const index = siblings.findIndex((sibling) => sibling.node === path.node);
45
+ if (index === -1)
46
+ return false;
47
+ for (let bodyIndex = 0; bodyIndex < index; bodyIndex++) {
48
+ const sibling = siblings[bodyIndex];
49
+ if (!sibling)
50
+ return false;
51
+ if (!sibling.isExpressionStatement())
52
+ return false;
53
+ if (sibling.node.expression.type !== "StringLiteral")
54
+ return false;
55
+ }
56
+ return true;
57
+ };
58
+ const createExpressionStatement = (expression, options) => {
59
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
60
+ let clonedExpression = t.cloneNode(expression, true);
61
+ if (options.wrapStringLiteralDirective &&
62
+ expression.type === "StringLiteral") {
63
+ // Prevent inserting a directive prologue statement like `"use strict";`.
64
+ // `("use strict");` is not treated as a directive.
65
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
66
+ clonedExpression = t.parenthesizedExpression(clonedExpression);
67
+ }
68
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
69
+ return t.expressionStatement(clonedExpression);
70
+ };
71
+ export const tryExpandIfStatementTestSequence = (path) => {
72
+ if (!canReplaceWithMultiple(path) && !canWrapInBlock(path))
73
+ return false;
74
+ const test = path.node.test;
75
+ if (test.type !== "SequenceExpression")
76
+ return false;
77
+ if (test.expressions.length < 2)
78
+ return false;
79
+ const leadingExpressions = test.expressions.slice(0, -1);
80
+ const lastExpression = test.expressions.at(-1);
81
+ if (!lastExpression)
82
+ return false;
83
+ const firstExpression = leadingExpressions[0];
84
+ const shouldWrapFirstStringLiteralDirective = firstExpression?.type === "StringLiteral" &&
85
+ isDirectiveProloguePosition(path);
86
+ const statements = leadingExpressions.map((expression, index) => createExpressionStatement(expression, {
87
+ wrapStringLiteralDirective: shouldWrapFirstStringLiteralDirective && index === 0,
88
+ }));
89
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
90
+ const updatedIfStatement = t.cloneNode(path.node, true);
91
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
92
+ updatedIfStatement.test = t.cloneNode(lastExpression, true);
93
+ statements.push(updatedIfStatement);
94
+ if (canReplaceWithMultiple(path)) {
95
+ path.replaceWithMultiple(statements);
96
+ return true;
97
+ }
98
+ if (canWrapInBlock(path)) {
99
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
100
+ path.replaceWith(t.blockStatement(statements));
101
+ return true;
102
+ }
103
+ return false;
104
+ };
@@ -0,0 +1,3 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type { ReturnStatement } from "@babel/types";
3
+ export declare const tryExpandReturnSequence: (path: NodePath<ReturnStatement>) => boolean;
@@ -0,0 +1,100 @@
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
+ const parentPath = path.parentPath;
40
+ if (parentPath.isBlockStatement()) {
41
+ if (parentPath.key !== "body")
42
+ return false;
43
+ if (!parentPath.parentPath.isFunction())
44
+ return false;
45
+ }
46
+ else if (!parentPath.isProgram()) {
47
+ return false;
48
+ }
49
+ const siblings = parentPath.get("body");
50
+ if (!Array.isArray(siblings))
51
+ return false;
52
+ const index = siblings.findIndex((sibling) => sibling.node === path.node);
53
+ if (index === -1)
54
+ return false;
55
+ for (let bodyIndex = 0; bodyIndex < index; bodyIndex++) {
56
+ const sibling = siblings[bodyIndex];
57
+ if (!sibling)
58
+ return false;
59
+ if (!sibling.isExpressionStatement())
60
+ return false;
61
+ if (sibling.node.expression.type !== "StringLiteral")
62
+ return false;
63
+ }
64
+ return true;
65
+ };
66
+ export const tryExpandReturnSequence = (path) => {
67
+ if (!canReplaceWithMultiple(path) && !canWrapInBlock(path))
68
+ return false;
69
+ const argument = path.node.argument;
70
+ if (!argument)
71
+ return false;
72
+ if (argument.type !== "SequenceExpression")
73
+ return false;
74
+ if (argument.expressions.length < 2)
75
+ return false;
76
+ const leadingExpressions = argument.expressions.slice(0, -1);
77
+ const lastExpression = argument.expressions.at(-1);
78
+ if (!lastExpression)
79
+ return false;
80
+ const firstExpression = leadingExpressions[0];
81
+ const shouldWrapFirstStringLiteralDirective = firstExpression?.type === "StringLiteral" &&
82
+ isDirectiveProloguePosition(path);
83
+ const statements = leadingExpressions.map((expression) => {
84
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
85
+ let clonedExpression = t.cloneNode(expression, true);
86
+ if (shouldWrapFirstStringLiteralDirective &&
87
+ expression === firstExpression) {
88
+ // Prevent inserting a directive prologue statement like `"use strict";`.
89
+ // `("use strict");` is not treated as a directive.
90
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
91
+ clonedExpression = t.parenthesizedExpression(clonedExpression);
92
+ }
93
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
94
+ return t.expressionStatement(clonedExpression);
95
+ });
96
+ statements.push(
97
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
98
+ t.returnStatement(t.cloneNode(lastExpression, true)));
99
+ return replaceReturnWithStatements(path, statements);
100
+ };
@@ -0,0 +1,2 @@
1
+ import type { Transform } from "../../core/types.js";
2
+ export declare const expandSequenceExpressionsV5Transform: Transform;
@@ -0,0 +1,55 @@
1
+ import { createRequire } from "node:module";
2
+ import { tryExpandExpressionStatementSequence } from "./expand-expression-statement-sequence.js";
3
+ import { tryExpandIfStatementTestSequence } from "./expand-if-statement-test-sequence.js";
4
+ import { tryExpandReturnSequence } from "./expand-return-sequence.js";
5
+ import { tryExpandThrowSequence } from "./expand-throw-sequence.js";
6
+ import { tryExpandVariableDeclarationSequenceInitializers } from "./expand-variable-declaration-sequence.js";
7
+ const require = createRequire(import.meta.url);
8
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
9
+ const traverse = require("@babel/traverse").default;
10
+ export const expandSequenceExpressionsV5Transform = {
11
+ id: "expand-sequence-expressions-v5",
12
+ description: "Expands comma operator sequences in returns, throws, statements (including control-flow bodies), variable initializers, and `if` tests",
13
+ scope: "file",
14
+ parallelizable: true,
15
+ transform(context) {
16
+ const { projectGraph } = context;
17
+ let nodesVisited = 0;
18
+ let transformationsApplied = 0;
19
+ for (const [, fileInfo] of projectGraph.files) {
20
+ traverse(fileInfo.ast, {
21
+ ReturnStatement(path) {
22
+ nodesVisited++;
23
+ if (!tryExpandReturnSequence(path))
24
+ return;
25
+ transformationsApplied += 1;
26
+ },
27
+ ThrowStatement(path) {
28
+ nodesVisited++;
29
+ if (!tryExpandThrowSequence(path))
30
+ return;
31
+ transformationsApplied += 1;
32
+ },
33
+ ExpressionStatement(path) {
34
+ nodesVisited++;
35
+ if (!tryExpandExpressionStatementSequence(path))
36
+ return;
37
+ transformationsApplied += 1;
38
+ },
39
+ VariableDeclaration(path) {
40
+ nodesVisited++;
41
+ if (!tryExpandVariableDeclarationSequenceInitializers(path))
42
+ return;
43
+ transformationsApplied += 1;
44
+ },
45
+ IfStatement(path) {
46
+ nodesVisited++;
47
+ if (!tryExpandIfStatementTestSequence(path))
48
+ return;
49
+ transformationsApplied += 1;
50
+ },
51
+ });
52
+ }
53
+ return Promise.resolve({ nodesVisited, transformationsApplied });
54
+ },
55
+ };
@@ -0,0 +1,3 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type { ThrowStatement } from "@babel/types";
3
+ export declare const tryExpandThrowSequence: (path: NodePath<ThrowStatement>) => boolean;
@@ -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
+ };
@@ -0,0 +1,3 @@
1
+ import type { NodePath } from "@babel/traverse";
2
+ import type { VariableDeclaration } from "@babel/types";
3
+ export declare const tryExpandVariableDeclarationSequenceInitializers: (path: NodePath<VariableDeclaration>) => boolean;
@@ -0,0 +1,103 @@
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, options) => {
6
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
7
+ let clonedExpression = t.cloneNode(expression, true);
8
+ if (options.wrapStringLiteralDirective &&
9
+ expression.type === "StringLiteral") {
10
+ // Prevent inserting a directive prologue statement like `"use strict";`.
11
+ // `("use strict");` is not treated as a directive.
12
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
13
+ clonedExpression = t.parenthesizedExpression(clonedExpression);
14
+ }
15
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
16
+ return t.expressionStatement(clonedExpression);
17
+ };
18
+ const createVariableDeclarationStatement = (kind, declarator) => {
19
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
20
+ return t.variableDeclaration(kind, [declarator]);
21
+ };
22
+ const createVariableDeclarator = (id, init) => {
23
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
24
+ return t.variableDeclarator(
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
26
+ t.cloneNode(id, true), init
27
+ ? // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
28
+ t.cloneNode(init, true)
29
+ : undefined);
30
+ };
31
+ const isSupportedStatementContainer = (path) => {
32
+ const parentPath = path.parentPath;
33
+ if (!parentPath)
34
+ return false;
35
+ return (parentPath.isProgram() ||
36
+ parentPath.isBlockStatement() ||
37
+ parentPath.isStaticBlock() ||
38
+ parentPath.isSwitchCase());
39
+ };
40
+ const isDirectiveProloguePosition = (path) => {
41
+ const parentPath = path.parentPath;
42
+ if (!parentPath)
43
+ return false;
44
+ if (parentPath.isBlockStatement()) {
45
+ const grandParent = parentPath.parentPath;
46
+ if (parentPath.key !== "body")
47
+ return false;
48
+ if (!grandParent.isFunction())
49
+ return false;
50
+ }
51
+ else if (!parentPath.isProgram()) {
52
+ return false;
53
+ }
54
+ const siblings = parentPath.get("body");
55
+ if (!Array.isArray(siblings))
56
+ return false;
57
+ const index = siblings.findIndex((sibling) => sibling.node === path.node);
58
+ if (index === -1)
59
+ return false;
60
+ for (let bodyIndex = 0; bodyIndex < index; bodyIndex++) {
61
+ const sibling = siblings[bodyIndex];
62
+ if (!sibling)
63
+ return false;
64
+ if (!sibling.isExpressionStatement())
65
+ return false;
66
+ if (sibling.node.expression.type !== "StringLiteral")
67
+ return false;
68
+ }
69
+ return true;
70
+ };
71
+ export const tryExpandVariableDeclarationSequenceInitializers = (path) => {
72
+ if (!isSupportedStatementContainer(path))
73
+ return false;
74
+ const isDirectivePrologueAtInsertion = isDirectiveProloguePosition(path);
75
+ const hasAnySequence = path.node.declarations.some((declarator) => declarator.init?.type === "SequenceExpression" &&
76
+ declarator.init.expressions.length >= 2);
77
+ if (!hasAnySequence)
78
+ return false;
79
+ const kind = path.node.kind;
80
+ const statements = [];
81
+ for (const declarator of path.node.declarations) {
82
+ const init = declarator.init;
83
+ if (init?.type !== "SequenceExpression") {
84
+ statements.push(createVariableDeclarationStatement(kind, declarator));
85
+ continue;
86
+ }
87
+ const leadingExpressions = init.expressions.slice(0, -1);
88
+ const lastExpression = init.expressions.at(-1);
89
+ if (!lastExpression) {
90
+ statements.push(createVariableDeclarationStatement(kind, declarator));
91
+ continue;
92
+ }
93
+ for (const expression of leadingExpressions) {
94
+ statements.push(createExpressionStatement(expression, {
95
+ wrapStringLiteralDirective: isDirectivePrologueAtInsertion && statements.length === 0,
96
+ }));
97
+ }
98
+ const newDeclarator = createVariableDeclarator(declarator.id, lastExpression);
99
+ statements.push(createVariableDeclarationStatement(kind, newDeclarator));
100
+ }
101
+ path.replaceWithMultiple(statements);
102
+ return true;
103
+ };
@@ -1,6 +1,7 @@
1
1
  import { expandBooleanLiteralsTransform } from "./expand-boolean-literals/expand-boolean-literals-transform.js";
2
2
  import { expandSpecialNumberLiteralsTransform } from "./expand-special-number-literals/expand-special-number-literals-transform.js";
3
3
  import { expandSequenceExpressionsV4Transform } from "./expand-sequence-expressions-v4/expand-sequence-expressions-v4-transform.js";
4
+ import { expandSequenceExpressionsV5Transform } from "./expand-sequence-expressions-v5/expand-sequence-expressions-v5-transform.js";
4
5
  import { expandUndefinedLiteralsTransform } from "./expand-undefined-literals/expand-undefined-literals-transform.js";
5
6
  import { renameCatchParametersTransform } from "./rename-catch-parameters/rename-catch-parameters-transform.js";
6
7
  import { renameDestructuredAliasesTransform } from "./rename-destructured-aliases/rename-destructured-aliases-transform.js";
@@ -19,6 +20,7 @@ export const transformRegistry = {
19
20
  [expandBooleanLiteralsTransform.id]: expandBooleanLiteralsTransform,
20
21
  [expandSpecialNumberLiteralsTransform.id]: expandSpecialNumberLiteralsTransform,
21
22
  [expandSequenceExpressionsV4Transform.id]: expandSequenceExpressionsV4Transform,
23
+ [expandSequenceExpressionsV5Transform.id]: expandSequenceExpressionsV5Transform,
22
24
  [expandUndefinedLiteralsTransform.id]: expandUndefinedLiteralsTransform,
23
25
  [renameCatchParametersTransform.id]: renameCatchParametersTransform,
24
26
  [renameDestructuredAliasesTransform.id]: renameDestructuredAliasesTransform,
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.11.0",
5
+ "version": "1.12.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",
@@ -97,9 +97,19 @@
97
97
  "scope": "file",
98
98
  "parallelizable": true,
99
99
  "diffReductionImpact": -0.01730809158000035,
100
- "recommended": true,
100
+ "recommended": false,
101
101
  "evaluatedAt": "2026-01-23T10:57:45.082Z",
102
- "notes": "Measured with baseline none: -1.73%. Supersedes all prior sequence expression transforms."
102
+ "notes": "Measured with baseline none: -1.73%. Supersedes all prior sequence expression transforms. Superseded by expand-sequence-expressions-v5.",
103
+ "supersededBy": "expand-sequence-expressions-v5"
104
+ },
105
+ {
106
+ "id": "expand-sequence-expressions-v5",
107
+ "description": "Expands comma operator sequences in returns, throws, statements (including control-flow bodies), variable initializers, and `if` tests",
108
+ "scope": "file",
109
+ "parallelizable": true,
110
+ "diffReductionImpact": -0.020243106019139034,
111
+ "recommended": true,
112
+ "notes": "Extends expand-sequence-expressions-v4 by also expanding `if ((a, b)) ...` style tests."
103
113
  },
104
114
  {
105
115
  "id": "rename-use-reference-guards",