From 9c04ccbca9d573c878c377ff9aaa05f3be3f0463 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Sun, 11 Jan 2026 10:50:03 +0100 Subject: [PATCH 1/3] update parser to @jorgsowa/php-parser --- package.json | 4 ++-- src/parser.mjs | 2 +- yarn.lock | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index bb2c4c42e..f996243c9 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "@prettier/plugin-php", + "name": "@jorgsowa/prettier-plugin-php", "version": "0.24.0", "description": "Prettier PHP Plugin", "repository": "prettier/prettier-php", @@ -27,7 +27,7 @@ ], "dependencies": { "linguist-languages": "^8.0.0", - "php-parser": "^3.2.5" + "@jorgsowa/php-parser": "^3.2.5-7" }, "devDependencies": { "@babel/preset-env": "^7.27.2", diff --git a/src/parser.mjs b/src/parser.mjs index 8df49870d..6aff4a6d1 100644 --- a/src/parser.mjs +++ b/src/parser.mjs @@ -1,4 +1,4 @@ -import engine from "php-parser"; +import engine from "@jorgsowa/php-parser"; import { LATEST_SUPPORTED_PHP_VERSION } from "./options.mjs"; import { resolvePhpVersion } from "./options.mjs"; diff --git a/yarn.lock b/yarn.lock index b36e788a3..889b5cc26 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1604,6 +1604,11 @@ "@types/yargs" "^17.0.33" chalk "^4.1.2" +"@jorgsowa/php-parser@^3.2.5-7": + version "3.2.5" + resolved "https://registry.yarnpkg.com/@jorgsowa/php-parser/-/php-parser-3.2.5.tgz#4ee2c03f48aa22b5bd22b785acb5f483b46e5b88" + integrity sha512-EOhxHfvDjofdhRcuyoY06GlaNsHFkfWKaRJ5Q5UdtAkhUwfnvQDznFAL7CiIGHYqB1YqFOc+uvnP5ubXEya8Qw== + "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -4701,11 +4706,6 @@ 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== - picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" From c2e38c1fdc6c7f0bb5a311bbe1417ff14ce751fa Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Sun, 11 Jan 2026 21:46:08 +0100 Subject: [PATCH 2/3] update GH actions --- .github/workflows/nodejs.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 7a644cbad..249a5f2b0 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -17,8 +17,8 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 with: cache: "yarn" - run: yarn install --frozen-lockfile @@ -37,15 +37,16 @@ jobs: AST_COMPARE: true steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v6 with: node-version: ${{ matrix.node-version }} cache: "yarn" - run: yarn install --frozen-lockfile - run: yarn c8 yarn test:node - uses: codecov/codecov-action@v5 + if: false with: fail_ci_if_error: true disable_search: true From b35fa5a74deaf87683c7b357be0c25bf997b5b47 Mon Sep 17 00:00:00 2001 From: Jorg Sowa Date: Sun, 11 Jan 2026 16:28:39 +0100 Subject: [PATCH 3/3] feat: propertyhooks --- package.json | 2 +- src/printer.mjs | 67 +++++++++++++++++++ src/util.mjs | 6 ++ tests/class/__snapshots__/jsfmt.spec.mjs.snap | 59 ++++++++++++++++ tests/class/class.php | 31 +++++++++ .../__snapshots__/jsfmt.spec.mjs.snap | 46 +++++++++++++ tests/property/property.php | 12 ++++ yarn.lock | 8 +-- 8 files changed, 226 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index f996243c9..4f0a51e4d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ ], "dependencies": { "linguist-languages": "^8.0.0", - "@jorgsowa/php-parser": "^3.2.5-7" + "@jorgsowa/php-parser": "3.2.5-7" }, "devDependencies": { "@babel/preset-env": "^7.27.2", diff --git a/src/printer.mjs b/src/printer.mjs index c3cf11cd0..17275d73a 100644 --- a/src/printer.mjs +++ b/src/printer.mjs @@ -1205,6 +1205,40 @@ function printAttrs(path, options, print, { inline = false } = {}) { return [...allAttrs, inline ? "" : hardline]; } +function printPropertyHook(path, options, print, hook) { + const parts = []; + if (hook.byref) { + parts.push("&"); + } + if (hook.visibility) { + parts.push(hook.visibility, " "); + } + if (hook.isFinal) { + parts.push("final "); + } + parts.push(hook.name); + + if (hook.parameter) { + path.call((parameterPath) => { + parts.push("(", print(parameterPath), ")"); + }, "parameter"); + } + + if (hook.body) { + if (hook.body.kind === "block") { + console.log(hook.body); + parts.push(" ", "{", indent([line, path.call(print, "body")]), line, "}"); + } else { + parts.push( + " => ", + path.call((p) => print(p), "body"), + ";" + ); + } + } + return group(parts); +} + function printClass(path, options, print) { const { node } = path; const isAnonymousClass = node.kind === "class" && node.isAnonymous; @@ -1782,6 +1816,7 @@ function printNode(path, options, print) { case "variadic": return ["...", print("what")]; case "property": + const isInterface = getAncestorNode(path, "interface"); return group([ node.readonly ? "readonly " : "", node.type ? [node.nullable ? "?" : "", print("type"), " "] : "", @@ -1799,6 +1834,38 @@ function printNode(path, options, print) { ), ] : "", + node.hooks && node.hooks.length > 0 && options.phpVersion >= 8.4 + ? isInterface + ? [ + " { ", + join( + " ", + path.map( + (p) => [ + printPropertyHook(p, options, print, p.node), + p.node.body ? "" : ";", + ], + "hooks" + ) + ), + " }", + ] + : [ + " {", + indent([ + hardline, + join( + [hardline, hardline], + path.map( + (p) => printPropertyHook(p, options, print, p.node), + "hooks" + ) + ), + ]), + hardline, + "}", + ] + : "", ]); case "propertystatement": { const attrs = []; diff --git a/src/util.mjs b/src/util.mjs index b4bf9e473..b289aade6 100644 --- a/src/util.mjs +++ b/src/util.mjs @@ -359,6 +359,12 @@ function lineShouldEndWithSemicolon(path) { return true; } } + if ( + node.kind === "propertystatement" && + node.properties.some((p) => p.hooks && p.hooks.length > 0) + ) { + return false; + } return [ "expressionstatement", "do", diff --git a/tests/class/__snapshots__/jsfmt.spec.mjs.snap b/tests/class/__snapshots__/jsfmt.spec.mjs.snap index 6fff7326e..208f18adf 100644 --- a/tests/class/__snapshots__/jsfmt.spec.mjs.snap +++ b/tests/class/__snapshots__/jsfmt.spec.mjs.snap @@ -943,6 +943,37 @@ class Bar extends Foo { public const ?int J = null; } +class B +{ + public string $bar { + get { + return $this->bar; + } + } + + public string $bar2 { + get => $this->bar2; + } + + public string $foo { + set => $this->foo = $value; + } + + public string $foo2 { + set(string $value2) { + { + $this->bar = $value2; + $this->foo2 = 'something'; + } + } + } +} + +interface ABC { + public string $foo { get; } + public string $bar { set; } +} + =====================================output===================================== bar; } + } + + public string $bar2 { + get => $this->bar2; + } + + public string $foo { + set => ($this->foo = $value); + } + + public string $foo2 { + set(string $value2) { + $this->bar = $value2; + $this->foo2 = "something"; + } + } +} + +interface ABC +{ + public string $foo { get; } + public string $bar { set; } +} + ================================================================================ `; diff --git a/tests/class/class.php b/tests/class/class.php index 626133292..d584d681d 100644 --- a/tests/class/class.php +++ b/tests/class/class.php @@ -339,3 +339,34 @@ class Bar extends Foo { public const int|null I = null; public const ?int J = null; } + +class B +{ + public string $bar { + get { + return $this->bar; + } + } + + public string $bar2 { + get => $this->bar2; + } + + public string $foo { + set => $this->foo = $value; + } + + public string $foo2 { + set(string $value2) { + { + $this->bar = $value2; + $this->foo2 = 'something'; + } + } + } +} + +interface ABC { + public string $foo { get; } + public string $bar { set; } +} diff --git a/tests/property/__snapshots__/jsfmt.spec.mjs.snap b/tests/property/__snapshots__/jsfmt.spec.mjs.snap index 2c29f3b9e..3d36e2548 100644 --- a/tests/property/__snapshots__/jsfmt.spec.mjs.snap +++ b/tests/property/__snapshots__/jsfmt.spec.mjs.snap @@ -47,6 +47,18 @@ string string' . 'string string string'; + + public $string3 { get => 'string'; } + public $string13 { &get => 'string'; } + public $string4 { get => $this->string4; } + public $string5 { final get => $this->string5; } + public $string6 { set => $this->string6 = $value; } + public $string7 { set => $this->string7 = $value; } + public string $string8 { set(string $value) => $this->string8 = $value; } + public string $string9 { set(string $value) { $this->string9 = $value; }} + public string $string10 { set { $this->string10 = $value; }} + public $string11 { final set => $this->string11 = $value; } + public $string12 { get { return $this->string12; } } } =====================================output===================================== @@ -99,6 +111,40 @@ string' . 'string string string'; + + public $string3 { + get => "string"; + } + public $string13 { + &get => "string"; + } + public $string4 { + get => $this->string4; + } + public $string5 { + final get => $this->string5; + } + public $string6 { + set => ($this->string6 = $value); + } + public $string7 { + set => ($this->string7 = $value); + } + public string $string8 { + set(string $value) => ($this->string8 = $value); + } + public string $string9 { + set(string $value) { $this->string9 = $value; } + } + public string $string10 { + set { $this->string10 = $value; } + } + public $string11 { + final set => ($this->string11 = $value); + } + public $string12 { + get { return $this->string12; } + } } ================================================================================ diff --git a/tests/property/property.php b/tests/property/property.php index ac8af4612..0277b3276 100644 --- a/tests/property/property.php +++ b/tests/property/property.php @@ -39,4 +39,16 @@ class Foo string' . 'string string string'; + + public $string3 { get => 'string'; } + public $string13 { &get => 'string'; } + public $string4 { get => $this->string4; } + public $string5 { final get => $this->string5; } + public $string6 { set => $this->string6 = $value; } + public $string7 { set => $this->string7 = $value; } + public string $string8 { set(string $value) => $this->string8 = $value; } + public string $string9 { set(string $value) { $this->string9 = $value; }} + public string $string10 { set { $this->string10 = $value; }} + public $string11 { final set => $this->string11 = $value; } + public $string12 { get { return $this->string12; } } } diff --git a/yarn.lock b/yarn.lock index 889b5cc26..ca9976d8e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1604,10 +1604,10 @@ "@types/yargs" "^17.0.33" chalk "^4.1.2" -"@jorgsowa/php-parser@^3.2.5-7": - version "3.2.5" - resolved "https://registry.yarnpkg.com/@jorgsowa/php-parser/-/php-parser-3.2.5.tgz#4ee2c03f48aa22b5bd22b785acb5f483b46e5b88" - integrity sha512-EOhxHfvDjofdhRcuyoY06GlaNsHFkfWKaRJ5Q5UdtAkhUwfnvQDznFAL7CiIGHYqB1YqFOc+uvnP5ubXEya8Qw== +"@jorgsowa/php-parser@3.2.5-7": + version "3.2.5-7" + resolved "https://registry.yarnpkg.com/@jorgsowa/php-parser/-/php-parser-3.2.5-7.tgz#65b0d3281f295271566c7fc51aa94b9d7811141d" + integrity sha512-FYIbu0b+hzWzUgc7oMwb8OMuDGsDSPP4Pm/tgGkuRxvQwCLuRRyVhCdjvkWsbXP+GL8gGWPn1D66BfZXX+IU4Q== "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3"