From e231bd956f1a3b9410be91013969f4b0cca2e278 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Sat, 21 Mar 2026 23:53:51 +0100 Subject: [PATCH 1/9] feat: support php-parser 3.4.0 (pipe operator and readonly anonymous classes) --- src/printer.mjs | 4 ++-- src/util.mjs | 1 + tests/bin/bin.php | 16 ++++++++++++++++ tests/class/anonymous.php | 20 ++++++++++++++++++++ 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/src/printer.mjs b/src/printer.mjs index c3cf11cd0..67f987c2f 100644 --- a/src/printer.mjs +++ b/src/printer.mjs @@ -1219,7 +1219,7 @@ function printClass(path, options, print) { declaration.push("abstract "); } - if (node.isReadonly) { + if (node.isReadonly && !isAnonymousClass) { declaration.push("readonly "); } @@ -2094,7 +2094,7 @@ function printNode(path, options, print) { () => printAttrs(path, options, print, { inline: true }), "what" ), - "class", + node.what.isReadonly ? "readonly class" : "class", node.arguments.length > 0 ? [" ", printArgumentsList(path, options, print)] : "", diff --git a/src/util.mjs b/src/util.mjs index dd2f5f2bf..59edb0095 100644 --- a/src/util.mjs +++ b/src/util.mjs @@ -41,6 +41,7 @@ const PRECEDENCE = new Map( "<<=", ">>=", ], + ["|>"], ["??"], ["||"], ["&&"], diff --git a/tests/bin/bin.php b/tests/bin/bin.php index 4326c4a30..a7fcc4fbc 100644 --- a/tests/bin/bin.php +++ b/tests/bin/bin.php @@ -331,3 +331,19 @@ function () { $this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value'; // Instead of repeating variables with long names, the equal coalesce operator is used $this->request->data['comments']['user_id'] ??= 'value'; + +$result = "Hello, World!" |> strtoupper(...); +$result = "Hello, World!" |> strtoupper(...) |> trim(...); +$result = "Hello, World!" |> strtoupper(...) |> trim(...) |> htmlspecialchars(...); + +return $value |> transform(...); +echo $value |> format(...); + +if ($x |> validate(...)) {} + +$result = $value |> fn1(...) ?? $fallback; +$result = $value ?? $fallback |> fn1(...); + +foo($value |> transform(...), $other); + +$veryLongVariableName |> someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...); diff --git a/tests/class/anonymous.php b/tests/class/anonymous.php index 63c145a77..66cb125c3 100644 --- a/tests/class/anonymous.php +++ b/tests/class/anonymous.php @@ -265,3 +265,23 @@ function () { return 1; } ) extends VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass implements VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass {}; + +new readonly class() {}; +new readonly class {}; +new readonly class($one, $two, $three) {}; + +$class = new readonly class {}; +$class = new readonly class() {}; +$class = new readonly class { public int $x = 0; }; +$class = new readonly class implements MyInterface {}; +$class = new readonly class implements MyInterface, MyOtherInterface {}; +$class = new readonly class extends MyParent {}; +$class = new readonly class extends MyParent implements MyInterface {}; +$class = new readonly class extends MyParent implements MyInterface, MyOtherInterface {}; + +$class = new readonly class implements VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyOtherClass {}; +$class = new readonly class extends VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass {}; +$class = new readonly class extends VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass implements MyI, MyII, MyIII {}; + +$class = new readonly class($one, $two) implements MyInterface {}; +$class = new readonly class($one, $two) extends MyParent implements MyInterface {}; From 5a5352096505379cb1afcabfa7011f3ae5c55c8a Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Sun, 22 Mar 2026 18:03:43 +0100 Subject: [PATCH 2/9] Bump parser to 3.4.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index bd07301e0..5e6abae0b 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ ], "dependencies": { "linguist-languages": "^8.0.0", - "php-parser": "^3.2.5" + "php-parser": "^3.4.0" }, "devDependencies": { "@babel/preset-env": "^7.27.2", diff --git a/yarn.lock b/yarn.lock index 7c46e3c4c..3fbfd736f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4701,10 +4701,10 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -php-parser@^3.2.5: - version "3.2.5" - resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-3.2.5.tgz#24ff4b4f3e1788967f7737e43c273a5a8e7cd0ac" - integrity sha512-M1ZYlALFFnESbSdmRtTQrBFUHSriHgPhgqtTF/LCbZM4h7swR5PHtUceB2Kzby5CfqcsYwBn7OXTJ0+8Sajwkw== +php-parser@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/php-parser/-/php-parser-3.4.0.tgz#dcd7743bf01caaaa7281e8b253f4cdbbea6e1265" + integrity sha512-JoDPazv8OESrVtcoIuO8HC587zVNJYSYUIl9zYn+JEpwlHSOrxmyMHB+sDS0O1ID5z1aFxPnr+vAUGoSKphlHA== picocolors@^1.0.0: version "1.0.0" From 19bac28c4b87d04a863425b163a466e3560b6e49 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Sun, 22 Mar 2026 19:01:38 +0100 Subject: [PATCH 3/9] move new tests accordingly to new folders dure to PHP version difference --- tests/bin/bin.php | 16 ---------------- tests/class/anonymous.php | 20 -------------------- tests/pipe/jsfmt.spec.mjs | 1 + tests/pipe/pipe.php | 17 +++++++++++++++++ tests/readonly-class/anonymous.php | 21 +++++++++++++++++++++ tests/readonly-class/jsfmt.spec.mjs | 1 + 6 files changed, 40 insertions(+), 36 deletions(-) create mode 100644 tests/pipe/jsfmt.spec.mjs create mode 100644 tests/pipe/pipe.php create mode 100644 tests/readonly-class/anonymous.php create mode 100644 tests/readonly-class/jsfmt.spec.mjs diff --git a/tests/bin/bin.php b/tests/bin/bin.php index a7fcc4fbc..4326c4a30 100644 --- a/tests/bin/bin.php +++ b/tests/bin/bin.php @@ -331,19 +331,3 @@ function () { $this->request->data['comments']['user_id'] = $this->request->data['comments']['user_id'] ?? 'value'; // Instead of repeating variables with long names, the equal coalesce operator is used $this->request->data['comments']['user_id'] ??= 'value'; - -$result = "Hello, World!" |> strtoupper(...); -$result = "Hello, World!" |> strtoupper(...) |> trim(...); -$result = "Hello, World!" |> strtoupper(...) |> trim(...) |> htmlspecialchars(...); - -return $value |> transform(...); -echo $value |> format(...); - -if ($x |> validate(...)) {} - -$result = $value |> fn1(...) ?? $fallback; -$result = $value ?? $fallback |> fn1(...); - -foo($value |> transform(...), $other); - -$veryLongVariableName |> someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...); diff --git a/tests/class/anonymous.php b/tests/class/anonymous.php index 66cb125c3..63c145a77 100644 --- a/tests/class/anonymous.php +++ b/tests/class/anonymous.php @@ -265,23 +265,3 @@ function () { return 1; } ) extends VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass implements VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass {}; - -new readonly class() {}; -new readonly class {}; -new readonly class($one, $two, $three) {}; - -$class = new readonly class {}; -$class = new readonly class() {}; -$class = new readonly class { public int $x = 0; }; -$class = new readonly class implements MyInterface {}; -$class = new readonly class implements MyInterface, MyOtherInterface {}; -$class = new readonly class extends MyParent {}; -$class = new readonly class extends MyParent implements MyInterface {}; -$class = new readonly class extends MyParent implements MyInterface, MyOtherInterface {}; - -$class = new readonly class implements VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyOtherClass {}; -$class = new readonly class extends VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass {}; -$class = new readonly class extends VeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryVeryLongMyClass implements MyI, MyII, MyIII {}; - -$class = new readonly class($one, $two) implements MyInterface {}; -$class = new readonly class($one, $two) extends MyParent implements MyInterface {}; diff --git a/tests/pipe/jsfmt.spec.mjs b/tests/pipe/jsfmt.spec.mjs new file mode 100644 index 000000000..49eaa5ec8 --- /dev/null +++ b/tests/pipe/jsfmt.spec.mjs @@ -0,0 +1 @@ +run_spec(import.meta, ["php"], { phpVersion: "8.5" }); diff --git a/tests/pipe/pipe.php b/tests/pipe/pipe.php new file mode 100644 index 000000000..d96ddbddd --- /dev/null +++ b/tests/pipe/pipe.php @@ -0,0 +1,17 @@ + strtoupper(...); +$result = "Hello, World!" |> strtoupper(...) |> trim(...); +$result = "Hello, World!" |> strtoupper(...) |> trim(...) |> htmlspecialchars(...); + +return $value |> transform(...); +echo $value |> format(...); + +if ($x |> validate(...)) {} + +$result = $value |> fn1(...) ?? $fallback; +$result = $value ?? $fallback |> fn1(...); + +foo($value |> transform(...), $other); + +$veryLongVariableName |> someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...); diff --git a/tests/readonly-class/anonymous.php b/tests/readonly-class/anonymous.php new file mode 100644 index 000000000..1dc0bd302 --- /dev/null +++ b/tests/readonly-class/anonymous.php @@ -0,0 +1,21 @@ + Date: Sun, 22 Mar 2026 19:03:18 +0100 Subject: [PATCH 4/9] Support PHP 8.5 --- src/options.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/options.mjs b/src/options.mjs index e7444d804..e650f85ad 100644 --- a/src/options.mjs +++ b/src/options.mjs @@ -7,7 +7,7 @@ const CATEGORY_PHP = "PHP"; const SUPPORTED_PHP_VERSIONS = [ 5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 7.0, 7.1, 7.2, 7.3, 7.4, - 8.0, 8.1, 8.2, 8.3, 8.4, + 8.0, 8.1, 8.2, 8.3, 8.4, 8.5, ]; export const LATEST_SUPPORTED_PHP_VERSION = Math.max(...SUPPORTED_PHP_VERSIONS); From b2df869b61ff45a8c432a7b32337c47ddca20d33 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Mon, 23 Mar 2026 00:24:33 +0100 Subject: [PATCH 5/9] create snapshots for tests readonly and pipe --- tests/pipe/__snapshots__/jsfmt.spec.mjs.snap | 52 ++++++++++++++ .../__snapshots__/jsfmt.spec.mjs.snap | 68 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 tests/pipe/__snapshots__/jsfmt.spec.mjs.snap create mode 100644 tests/readonly-class/__snapshots__/jsfmt.spec.mjs.snap diff --git a/tests/pipe/__snapshots__/jsfmt.spec.mjs.snap b/tests/pipe/__snapshots__/jsfmt.spec.mjs.snap new file mode 100644 index 000000000..73e8453bb --- /dev/null +++ b/tests/pipe/__snapshots__/jsfmt.spec.mjs.snap @@ -0,0 +1,52 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`pipe.php 1`] = ` +====================================options===================================== +parsers: ["php"] +phpVersion: "8.5" +printWidth: 80 + | printWidth +=====================================input====================================== + strtoupper(...); +$result = "Hello, World!" |> strtoupper(...) |> trim(...); +$result = "Hello, World!" |> strtoupper(...) |> trim(...) |> htmlspecialchars(...); + +return $value |> transform(...); +echo $value |> format(...); + +if ($x |> validate(...)) {} + +$result = $value |> fn1(...) ?? $fallback; +$result = $value ?? $fallback |> fn1(...); + +foo($value |> transform(...), $other); + +$veryLongVariableName |> someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...); + +=====================================output===================================== + strtoupper(...); +$result = "Hello, World!" |> (strtoupper(...) |> trim(...)); +$result = + "Hello, World!" |> + (strtoupper(...) |> (trim(...) |> htmlspecialchars(...))); + +return $value |> transform(...); +echo $value |> format(...); + +if ($x |> validate(...)) { +} + +$result = $value |> fn1(...) ?? $fallback; +$result = $value ?? ($fallback |> fn1(...)); + +foo($value |> transform(...), $other); + +$veryLongVariableName |> + (someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...)); + +================================================================================ +`; diff --git a/tests/readonly-class/__snapshots__/jsfmt.spec.mjs.snap b/tests/readonly-class/__snapshots__/jsfmt.spec.mjs.snap new file mode 100644 index 000000000..b044616a0 --- /dev/null +++ b/tests/readonly-class/__snapshots__/jsfmt.spec.mjs.snap @@ -0,0 +1,68 @@ +// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing + +exports[`anonymous.php 1`] = ` +====================================options===================================== +parsers: ["php"] +phpVersion: "8.4" +printWidth: 80 + | printWidth +=====================================input====================================== + Date: Mon, 23 Mar 2026 23:40:05 +0100 Subject: [PATCH 6/9] folding longer expressions with pipe operator --- src/needs-parens.mjs | 4 ++ src/printer.mjs | 44 +++++++++++++++++++- tests/pipe/__snapshots__/jsfmt.spec.mjs.snap | 36 +++++++++++++--- tests/pipe/pipe.php | 6 +++ 4 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/needs-parens.mjs b/src/needs-parens.mjs index 8ea379e2c..0442e214e 100644 --- a/src/needs-parens.mjs +++ b/src/needs-parens.mjs @@ -90,6 +90,10 @@ function needsParens(path, options) { return true; } + if (po === "|>" && no === "|>") { + return false; + } + if (pp === np && key === "right") { return true; } diff --git a/src/printer.mjs b/src/printer.mjs index 67f987c2f..8ab871de4 100644 --- a/src/printer.mjs +++ b/src/printer.mjs @@ -50,6 +50,7 @@ const { dedent, ifBreak, hardline, + hardlineWithoutBreakParent, softline, literalline, align, @@ -114,7 +115,15 @@ function genericPrint(path, options, print) { } if (lineShouldEndWithSemicolon(path)) { - parts.push(";"); + const isPipeChainStatement = + node.kind === "expressionstatement" && + (node.expression.kind === "bin" && node.expression.type === "|>" || + (node.expression.kind === "assign" && + node.expression.right.kind === "bin" && + node.expression.right.type === "|>")); + if (!isPipeChainStatement) { + parts.push(";"); + } } if (fileShouldEndWithHardline(path)) { @@ -741,6 +750,28 @@ function shouldInlineLogicalExpression(node) { // precedence level and the AST is structured based on precedence // level, things are naturally broken up correctly, i.e. `&&` is // broken before `+`. +function printPipeChain(path, print, trailingSemicolon = false) { + const elements = []; + + function collect() { + const { node } = path; + if (node.kind === "bin" && node.type === "|>") { + elements.push(path.call(print, "left")); + path.call(collect, "right"); + } else { + elements.push(print()); + } + } + + collect(); + + const [first, ...rest] = elements; + const semicolon = trailingSemicolon + ? ifBreak([hardlineWithoutBreakParent, ";"], ";") + : ""; + return group([first, indent(rest.flatMap((el) => [line, "|> ", el])), semicolon]); +} + function printBinaryExpression( path, print, @@ -1524,6 +1555,7 @@ function printAssignmentRight( const canBreak = (pureRightNode.kind === "bin" && + pureRightNode.type !== "|>" && !shouldInlineLogicalExpression(pureRightNode)) || (pureRightNode.kind === "retif" && ((!pureRightNode.trueExpr && @@ -2487,6 +2519,16 @@ function printNode(path, options, print) { ); } case "bin": { + if (node.type === "|>") { + const { parent, grandparent } = path; + const isStatementLevel = + parent.kind === "expressionstatement" || + (parent.kind === "assign" && + grandparent && + grandparent.kind === "expressionstatement"); + return printPipeChain(path, print, isStatementLevel); + } + const { parent, grandparent: parentParent } = path; const isInsideParenthesis = node !== parent.body && diff --git a/tests/pipe/__snapshots__/jsfmt.spec.mjs.snap b/tests/pipe/__snapshots__/jsfmt.spec.mjs.snap index 73e8453bb..a6c86866d 100644 --- a/tests/pipe/__snapshots__/jsfmt.spec.mjs.snap +++ b/tests/pipe/__snapshots__/jsfmt.spec.mjs.snap @@ -25,14 +25,22 @@ foo($value |> transform(...), $other); $veryLongVariableName |> someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...); +$result = $a |> fn1(...) || $b |> fn2(...); + +$result = $value |> fn1($inner |> transform(...)) |> fn2(...); + +$result = $veryLongValue |> someFunction($innerValue |> innerTransform(...) |> anotherInnerTransform(...) |> yetAnotherInnerTransform(...)) |> finalTransform(...); + =====================================output===================================== strtoupper(...); -$result = "Hello, World!" |> (strtoupper(...) |> trim(...)); -$result = - "Hello, World!" |> - (strtoupper(...) |> (trim(...) |> htmlspecialchars(...))); +$result = "Hello, World!" |> strtoupper(...) |> trim(...); +$result = "Hello, World!" + |> strtoupper(...) + |> trim(...) + |> htmlspecialchars(...) +; return $value |> transform(...); echo $value |> format(...); @@ -45,8 +53,24 @@ $result = $value ?? ($fallback |> fn1(...)); foo($value |> transform(...), $other); -$veryLongVariableName |> - (someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...)); +$veryLongVariableName + |> someVeryLongFunctionName(...) + |> anotherVeryLongFunctionName(...) +; + +$result = $a |> fn1(...) || ($b |> fn2(...)); + +$result = $value |> fn1($inner |> transform(...)) |> fn2(...); + +$result = $veryLongValue + |> someFunction( + $innerValue + |> innerTransform(...) + |> anotherInnerTransform(...) + |> yetAnotherInnerTransform(...), + ) + |> finalTransform(...) +; ================================================================================ `; diff --git a/tests/pipe/pipe.php b/tests/pipe/pipe.php index d96ddbddd..5732917cb 100644 --- a/tests/pipe/pipe.php +++ b/tests/pipe/pipe.php @@ -15,3 +15,9 @@ foo($value |> transform(...), $other); $veryLongVariableName |> someVeryLongFunctionName(...) |> anotherVeryLongFunctionName(...); + +$result = $a |> fn1(...) || $b |> fn2(...); + +$result = $value |> fn1($inner |> transform(...)) |> fn2(...); + +$result = $veryLongValue |> someFunction($innerValue |> innerTransform(...) |> anotherInnerTransform(...) |> yetAnotherInnerTransform(...)) |> finalTransform(...); From e2aa7d306d1aca307c03e7754fa0ab7f6a59a3ee Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Mon, 23 Mar 2026 23:43:14 +0100 Subject: [PATCH 7/9] linter --- src/printer.mjs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/printer.mjs b/src/printer.mjs index 8ab871de4..f883ce106 100644 --- a/src/printer.mjs +++ b/src/printer.mjs @@ -117,7 +117,7 @@ function genericPrint(path, options, print) { if (lineShouldEndWithSemicolon(path)) { const isPipeChainStatement = node.kind === "expressionstatement" && - (node.expression.kind === "bin" && node.expression.type === "|>" || + ((node.expression.kind === "bin" && node.expression.type === "|>") || (node.expression.kind === "assign" && node.expression.right.kind === "bin" && node.expression.right.type === "|>")); @@ -769,7 +769,11 @@ function printPipeChain(path, print, trailingSemicolon = false) { const semicolon = trailingSemicolon ? ifBreak([hardlineWithoutBreakParent, ";"], ";") : ""; - return group([first, indent(rest.flatMap((el) => [line, "|> ", el])), semicolon]); + return group([ + first, + indent(rest.flatMap((el) => [line, "|> ", el])), + semicolon, + ]); } function printBinaryExpression( From c2bc0fcce96d8f6ddbbeeec46cd40a390f6aecbd Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Mon, 23 Mar 2026 23:44:38 +0100 Subject: [PATCH 8/9] dead code --- src/needs-parens.mjs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/needs-parens.mjs b/src/needs-parens.mjs index 0442e214e..8ea379e2c 100644 --- a/src/needs-parens.mjs +++ b/src/needs-parens.mjs @@ -90,10 +90,6 @@ function needsParens(path, options) { return true; } - if (po === "|>" && no === "|>") { - return false; - } - if (pp === np && key === "right") { return true; } From ced949464fbbd7a3d1175a262622f9c1c861a759 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Wed, 25 Mar 2026 21:49:08 +0100 Subject: [PATCH 9/9] moved logic to lineShouldEndWithSemicolon --- src/printer.mjs | 10 +--------- src/util.mjs | 11 +++++++++++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/printer.mjs b/src/printer.mjs index f883ce106..9a1136c82 100644 --- a/src/printer.mjs +++ b/src/printer.mjs @@ -115,15 +115,7 @@ function genericPrint(path, options, print) { } if (lineShouldEndWithSemicolon(path)) { - const isPipeChainStatement = - node.kind === "expressionstatement" && - ((node.expression.kind === "bin" && node.expression.type === "|>") || - (node.expression.kind === "assign" && - node.expression.right.kind === "bin" && - node.expression.right.type === "|>")); - if (!isPipeChainStatement) { - parts.push(";"); - } + parts.push(";"); } if (fileShouldEndWithHardline(path)) { diff --git a/src/util.mjs b/src/util.mjs index 59edb0095..0c20266a0 100644 --- a/src/util.mjs +++ b/src/util.mjs @@ -360,6 +360,17 @@ function lineShouldEndWithSemicolon(path) { return true; } } + if (node.kind === "expressionstatement") { + const expr = node.expression; + const isPipeChain = + (expr.kind === "bin" && expr.type === "|>") || + (expr.kind === "assign" && + expr.right.kind === "bin" && + expr.right.type === "|>"); + if (isPipeChain) { + return false; + } + } return [ "expressionstatement", "do",