From 0d06b2eebf46f981e881aea086329594705d7ea0 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Sat, 21 Mar 2026 23:53:51 +0100 Subject: [PATCH 1/4] 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 b4bf9e473..41a415534 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 6ad88c1fea29989b4dba4f0886b8cde7be8654d7 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Sun, 22 Mar 2026 18:03:43 +0100 Subject: [PATCH 2/4] 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 bb2c4c42e..61b649888 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 b36e788a3..8a28a943e 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 42a25257e9362526493366fa1a4d8522efa078a7 Mon Sep 17 00:00:00 2001 From: Jorg Adam Sowa Date: Sun, 22 Mar 2026 19:01:38 +0100 Subject: [PATCH 3/4] 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/4] 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);