From 8856f8b6b136b782e90a98becd857965843218bf Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 16 Feb 2024 04:33:49 +0100 Subject: [PATCH 01/28] UseStatements/KeywordSpacing: add missing "fixed" test file The `Universal.UseStatement.KeywordSpacing` sniff has a difference in behaviour between PHP < 8.0 and PHP 8.0+ due to the change in how namespaced name tokens are tokenized in PHP 8.0+. For that reason, the `KeywordSpacingUnitTest.2.inc` did not have a ".fixed" file as whether or not a fix would be made depends on which PHP version the tests are being run on. As of PHPCS 3.9.0, PHPCS will throw a PHPUnit warning for missing "fixed" files and as of PHPCS 4.0.0, this will become an error. With that in mind, this commit adds the missing "fixed" file, but excludes that test from being run on PHP 8.0+ by overloading the `getTestFiles()` method and selectively removing the test case file from the list of files to test. --- .../KeywordSpacingUnitTest.2.inc.fixed | 11 +++++++ .../UseStatements/KeywordSpacingUnitTest.php | 32 ++++++++++++++++--- 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed diff --git a/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed new file mode 100644 index 00000000..5589d374 --- /dev/null +++ b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed @@ -0,0 +1,11 @@ + + */ + protected function getTestFiles($testFileBase) + { + $testFiles = parent::getTestFiles($testFileBase); + + if (\PHP_VERSION_ID < 80000) { + return $testFiles; + } + + // The issue being tested in the "2" test case file cannot be flagged/fixed on PHP 8.0+. + $target = 'KeywordSpacingUnitTest.2.inc'; + $length = \strlen($target); + foreach ($testFiles as $i => $fileName) { + if (\substr($fileName, -$length) === $target) { + unset($testFiles[$i]); + break; + } + } + + return $testFiles; + } + /** * Returns the lines where errors should occur. * @@ -55,10 +83,6 @@ public function getErrorList($testFile = '') ]; case 'KeywordSpacingUnitTest.2.inc': - if (\PHP_VERSION_ID >= 80000) { - return []; - } - return [ 11 => 1, ]; From f323022e11cd7cfd4b95bbec66accf3277439dbc Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 11 Feb 2024 02:26:06 +0100 Subject: [PATCH 02/28] GH Actions: minor tweaks * The `--ignore-platform-req=php+` is no longer needed now PHPUnit 8 and 9 are supported (since PR 299 / PHPCS 3.8.0). * Minor readability improvement of the script snippet. --- .github/workflows/quicktest.yml | 5 +++-- .github/workflows/test.yml | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index e914cd17..9bbcaa92 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -70,8 +70,9 @@ jobs: - name: "Composer: set PHPCS/PHPCSUtils version for tests (lowest)" if: ${{ matrix.phpcs_version == 'lowest' }} run: > - composer update squizlabs/php_codesniffer phpcsstandards/phpcsutils - --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction + composer update --prefer-lowest --no-scripts --no-interaction + squizlabs/php_codesniffer + phpcsstandards/phpcsutils - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3075e039..c1aee5d4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -76,8 +76,9 @@ jobs: - name: "Composer: set PHPCS/PHPCSUtils version for tests (lowest)" if: ${{ matrix.phpcs_version == 'lowest' }} run: > - composer update squizlabs/php_codesniffer phpcsstandards/phpcsutils - --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction + composer update --prefer-lowest --no-scripts --no-interaction + squizlabs/php_codesniffer + phpcsstandards/phpcsutils - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' @@ -143,8 +144,9 @@ jobs: - name: "Composer: set PHPCS/PHPCSUtils version for tests (lowest)" if: ${{ matrix.phpcs_version == 'lowest' }} run: > - composer update squizlabs/php_codesniffer phpcsstandards/phpcsutils - --prefer-lowest --ignore-platform-req=php+ --no-scripts --no-interaction + composer update --prefer-lowest --no-scripts --no-interaction + squizlabs/php_codesniffer + phpcsstandards/phpcsutils - name: Lint against parse errors if: matrix.phpcs_version == 'dev-master' From bd7b8c9249fbac0728c650e0a86d5f2865733b0d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Mar 2024 01:43:54 +0000 Subject: [PATCH 03/28] GH Actions: Bump ramsey/composer-install from 2 to 3 Bumps [ramsey/composer-install](https://github.com/ramsey/composer-install) from 2 to 3. - [Release notes](https://github.com/ramsey/composer-install/releases) - [Commits](https://github.com/ramsey/composer-install/compare/v2...v3) --- updated-dependencies: - dependency-name: ramsey/composer-install dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/basics.yml | 4 ++-- .github/workflows/quicktest.yml | 2 +- .github/workflows/test.yml | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index 265d7720..515241fc 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -48,7 +48,7 @@ jobs: # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") @@ -113,7 +113,7 @@ jobs: # Dependencies need to be installed to make sure the PHPCS and PHPUnit classes are recognized. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 9bbcaa92..76000742 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -62,7 +62,7 @@ jobs: # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c1aee5d4..45f68d44 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -68,7 +68,7 @@ jobs: # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") @@ -136,7 +136,7 @@ jobs: # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies - uses: "ramsey/composer-install@v2" + uses: "ramsey/composer-install@v3" with: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") From 622223e9b88779092601a75fdc02bb576363e4cf Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 01:29:50 +0000 Subject: [PATCH 04/28] GH Actions: Bump mondeja/remove-labels-gh-action from 1 to 2 Bumps [mondeja/remove-labels-gh-action](https://github.com/mondeja/remove-labels-gh-action) from 1 to 2. - [Release notes](https://github.com/mondeja/remove-labels-gh-action/releases) - [Commits](https://github.com/mondeja/remove-labels-gh-action/compare/v1...v2) --- updated-dependencies: - dependency-name: mondeja/remove-labels-gh-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/label-remove-outdated.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/label-remove-outdated.yml b/.github/workflows/label-remove-outdated.yml index ce4bc4ce..d3d3f6ac 100644 --- a/.github/workflows/label-remove-outdated.yml +++ b/.github/workflows/label-remove-outdated.yml @@ -17,7 +17,7 @@ jobs: name: Clean up labels on issue close steps: - - uses: mondeja/remove-labels-gh-action@v1 + - uses: mondeja/remove-labels-gh-action@v2 with: token: ${{ secrets.GITHUB_TOKEN }} labels: | @@ -31,7 +31,7 @@ jobs: name: Clean up labels on PR merge steps: - - uses: mondeja/remove-labels-gh-action@v1 + - uses: mondeja/remove-labels-gh-action@v2 with: token: ${{ secrets.GITHUB_TOKEN }} labels: | @@ -45,7 +45,7 @@ jobs: name: Clean up labels on PR close steps: - - uses: mondeja/remove-labels-gh-action@v1 + - uses: mondeja/remove-labels-gh-action@v2 with: token: ${{ secrets.GITHUB_TOKEN }} labels: | From cf5f8b43d4f5db96ce2d5b07f0b220c01551bd51 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 19 Apr 2024 14:37:40 +0200 Subject: [PATCH 05/28] Bug report template: tweak markdown ... to comply with changes in Remark. _sigh_ --- .github/ISSUE_TEMPLATE/bug_report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index a0ac7179..b6cd7972 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -60,7 +60,7 @@ You should be able to get the version numbers using the `composer info` command. --> | Environment | Answer | -|-------------------------|--------------------------------------------------------------------------------| +| ----------------------- | ------------------------------------------------------------------------------ | | PHP version | x.y.z | | PHP_CodeSniffer version | x.y.z | | PHPCSExtra version | x.y.z | From cd881d335cc475cc46edf7d65a324607915f3da7 Mon Sep 17 00:00:00 2001 From: Dan Wallis Date: Sun, 21 Apr 2024 19:24:34 +0100 Subject: [PATCH 06/28] Composer: avoid writing a lock file (#307) * Composer: avoid writing a lock file * Allow use of Composer lock file in some tests --- .github/workflows/quicktest.yml | 4 ++++ .github/workflows/test.yml | 8 ++++++++ composer.json | 3 ++- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 76000742..11d15306 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -59,6 +59,10 @@ jobs: if: ${{ matrix.phpcs_version != 'lowest' }} run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction + - name: "Composer: use lock file when necessary" + if: ${{ matrix.phpcs_version == 'lowest' }} + run: composer config --unset lock + # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 45f68d44..c8d0ba01 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -65,6 +65,10 @@ jobs: if: ${{ matrix.phpcs_version != 'lowest' }} run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction + - name: "Composer: use lock file when necessary" + if: ${{ matrix.phpcs_version == 'lowest' }} + run: composer config --unset lock + # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies @@ -133,6 +137,10 @@ jobs: if: ${{ matrix.phpcs_version != 'lowest' }} run: composer require squizlabs/php_codesniffer:"${{ matrix.phpcs_version }}" --no-update --no-scripts --no-interaction + - name: "Composer: use lock file when necessary" + if: ${{ matrix.phpcs_version == 'lowest' }} + run: composer config --unset lock + # Install dependencies and handle caching in one go. # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - name: Install Composer dependencies diff --git a/composer.json b/composer.json index 92122571..28617b0d 100644 --- a/composer.json +++ b/composer.json @@ -64,6 +64,7 @@ "config": { "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true - } + }, + "lock": false } } From fd2752e1fa13cf72931b5cb655eea6fb369be619 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 24 Apr 2024 12:48:10 +0200 Subject: [PATCH 07/28] GH Actions: work around intermittent apt-get errors Okay, so apparently, there is a long-standing bug in the Microsoft package deploy process which caused `apt-get update` to fail in the first half hour after Microsoft has deployed a package. The failure looks like this: ``` E: Failed to fetch https://packages.microsoft.com/ubuntu/22.04/prod/dists/jammy/InRelease Clearsigned file isn't valid, got 'NOSPLIT' (does the network require authentication?) ``` As this only happens intermittently (after a MS package deploy), the chance of running into this bug are slim, but guess what: today I ran into it. This change to the workflow is intended to prevent the next person running into this issue from having to waste time on figuring this out. By splitting the "Install xmllint" step into two steps: one doing the `apt-get update` and one doing the actual install and making the first step one which is allowed to `continue-on-error`, this issue should hopefully not crop up anymore. Any errors in the `apt-get update` step will now be ignored and as most errors which could potentially come from that step are irrelevant for the rest of the job anyway, this is fine. If a relevant error would be surfaced, the next step (the xmllint install), will fail the job anyway. Refs: * https://github.com/actions/runner-images/issues/3410 * https://github.com/dotnet/core/issues/4167 --- .github/workflows/basics.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index 515241fc..7d1fb0e8 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -53,10 +53,15 @@ jobs: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") + # Updating the lists can fail intermittently, typically after Microsoft has released a new package. + # This should not be blocking for this job, so ignore any errors from this step. + # Ref: https://github.com/dotnet/core/issues/4167 + - name: Update the available packages list + continue-on-error: true + run: sudo apt-get update + - name: Install xmllint - run: | - sudo apt-get update - sudo apt-get install --no-install-recommends -y libxml2-utils + run: sudo apt-get install --no-install-recommends -y libxml2-utils # Show XML violations inline in the file diff. # @link https://github.com/marketplace/actions/xmllint-problem-matcher From 3e5ce25e8347f23a70cb99b15edeb3cf282109dd Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 22 Jul 2024 18:07:52 +0200 Subject: [PATCH 08/28] Documentation: minor consistency fixes * Double checked that all existing XML docs have the `xsi` attributes and schema reference on the `` element. * Verified that the contents of `` elements is consistently indented (with four spaces). * Verified that all `` `title` attributes use proper capitalization and punctuation. --- Modernize/Docs/FunctionCalls/DirnameStandard.xml | 2 +- .../Docs/Arrays/ArrayBraceSpacingStandard.xml | 8 ++++---- .../Docs/Arrays/CommaAfterLastStandard.xml | 12 ++++++------ Universal/Docs/Arrays/DuplicateArrayKeyStandard.xml | 4 ++-- Universal/Docs/Arrays/MixedArrayKeyTypesStandard.xml | 2 +- .../Docs/Arrays/MixedKeyedUnkeyedArrayStandard.xml | 2 +- .../ConstructorDestructorReturnStandard.xml | 8 ++++---- .../CodeAnalysis/ForeachUniqueAssignmentStandard.xml | 4 ++-- .../Docs/CodeAnalysis/NoDoubleNegativeStandard.xml | 4 ++-- .../Docs/CodeAnalysis/NoEchoSprintfStandard.xml | 4 ++-- .../LowercaseClassResolutionKeywordStandard.xml | 4 ++-- .../Constants/UppercaseMagicConstantsStandard.xml | 4 ++-- .../DisallowAlternativeSyntaxStandard.xml | 4 ++-- .../ControlStructures/DisallowLonelyIfStandard.xml | 4 ++-- .../NoReservedKeywordParameterNamesStandard.xml | 4 ++-- Universal/Docs/Operators/ConcatPositionStandard.xml | 4 ++-- .../Docs/UseStatements/DisallowUseConstStandard.xml | 2 +- .../UseStatements/DisallowUseFunctionStandard.xml | 2 +- .../Docs/WhiteSpace/PrecisionAlignmentStandard.xml | 4 ++-- 19 files changed, 41 insertions(+), 41 deletions(-) diff --git a/Modernize/Docs/FunctionCalls/DirnameStandard.xml b/Modernize/Docs/FunctionCalls/DirnameStandard.xml index 5f486646..a4c65f7e 100644 --- a/Modernize/Docs/FunctionCalls/DirnameStandard.xml +++ b/Modernize/Docs/FunctionCalls/DirnameStandard.xml @@ -14,7 +14,7 @@ $path = __DIR__; ]]> - + dirname(__FILE__); ]]> diff --git a/NormalizedArrays/Docs/Arrays/ArrayBraceSpacingStandard.xml b/NormalizedArrays/Docs/Arrays/ArrayBraceSpacingStandard.xml index e8a006f0..3c655486 100644 --- a/NormalizedArrays/Docs/Arrays/ArrayBraceSpacingStandard.xml +++ b/NormalizedArrays/Docs/Arrays/ArrayBraceSpacingStandard.xml @@ -5,7 +5,7 @@ > @@ -22,7 +22,7 @@ $args = array (1, 2); @@ -43,7 +43,7 @@ $args = [ ]; @@ -64,7 +64,7 @@ $args = [ 1, 2 ]; diff --git a/NormalizedArrays/Docs/Arrays/CommaAfterLastStandard.xml b/NormalizedArrays/Docs/Arrays/CommaAfterLastStandard.xml index c5094c5c..9afebbd6 100644 --- a/NormalizedArrays/Docs/Arrays/CommaAfterLastStandard.xml +++ b/NormalizedArrays/Docs/Arrays/CommaAfterLastStandard.xml @@ -5,25 +5,25 @@ > no comma after the last array item. + For single-line arrays, there should be no comma after the last array item. - However, for multi-line arrays, there should be a comma after the last array item. + However, for multi-line arrays, there should be a comma after the last array item. ]]> - + - + , ); ]]> - + 'foo', @@ -31,7 +31,7 @@ $args = [ ]; ]]> - + 'foo', diff --git a/Universal/Docs/Arrays/DuplicateArrayKeyStandard.xml b/Universal/Docs/Arrays/DuplicateArrayKeyStandard.xml index 00f9b7bb..02c0974e 100644 --- a/Universal/Docs/Arrays/DuplicateArrayKeyStandard.xml +++ b/Universal/Docs/Arrays/DuplicateArrayKeyStandard.xml @@ -5,8 +5,8 @@ > diff --git a/Universal/Docs/Arrays/MixedArrayKeyTypesStandard.xml b/Universal/Docs/Arrays/MixedArrayKeyTypesStandard.xml index f7efdda1..f66b235a 100644 --- a/Universal/Docs/Arrays/MixedArrayKeyTypesStandard.xml +++ b/Universal/Docs/Arrays/MixedArrayKeyTypesStandard.xml @@ -5,7 +5,7 @@ > diff --git a/Universal/Docs/Arrays/MixedKeyedUnkeyedArrayStandard.xml b/Universal/Docs/Arrays/MixedKeyedUnkeyedArrayStandard.xml index 79897c19..5f2dbda5 100644 --- a/Universal/Docs/Arrays/MixedKeyedUnkeyedArrayStandard.xml +++ b/Universal/Docs/Arrays/MixedKeyedUnkeyedArrayStandard.xml @@ -5,7 +5,7 @@ > diff --git a/Universal/Docs/CodeAnalysis/ConstructorDestructorReturnStandard.xml b/Universal/Docs/CodeAnalysis/ConstructorDestructorReturnStandard.xml index b44b4777..35b76785 100644 --- a/Universal/Docs/CodeAnalysis/ConstructorDestructorReturnStandard.xml +++ b/Universal/Docs/CodeAnalysis/ConstructorDestructorReturnStandard.xml @@ -9,14 +9,14 @@ ]]> - + - + : int {} @@ -31,7 +31,7 @@ class Foo { ]]> - + - + - + $v ) {} ]]> - + $k ) {} ]]> diff --git a/Universal/Docs/CodeAnalysis/NoDoubleNegativeStandard.xml b/Universal/Docs/CodeAnalysis/NoDoubleNegativeStandard.xml index 953149b7..972a304b 100644 --- a/Universal/Docs/CodeAnalysis/NoDoubleNegativeStandard.xml +++ b/Universal/Docs/CodeAnalysis/NoDoubleNegativeStandard.xml @@ -9,14 +9,14 @@ ]]> - + ! $b; if((bool) callMe($a)) {} ]]> - + ! ! $b; diff --git a/Universal/Docs/CodeAnalysis/NoEchoSprintfStandard.xml b/Universal/Docs/CodeAnalysis/NoEchoSprintfStandard.xml index 914eb65d..08812140 100644 --- a/Universal/Docs/CodeAnalysis/NoEchoSprintfStandard.xml +++ b/Universal/Docs/CodeAnalysis/NoEchoSprintfStandard.xml @@ -9,13 +9,13 @@ ]]> - + printf('text %s text', $var); echo callMe('text %s text', $var); ]]> - + echo sprintf('text %s text', $var); echo vsprintf('text %s text', [$var]); diff --git a/Universal/Docs/Constants/LowercaseClassResolutionKeywordStandard.xml b/Universal/Docs/Constants/LowercaseClassResolutionKeywordStandard.xml index 7b61c8fa..6d34f128 100644 --- a/Universal/Docs/Constants/LowercaseClassResolutionKeywordStandard.xml +++ b/Universal/Docs/Constants/LowercaseClassResolutionKeywordStandard.xml @@ -9,12 +9,12 @@ ]]> - + - + MyClass::CLASS; ]]> diff --git a/Universal/Docs/Constants/UppercaseMagicConstantsStandard.xml b/Universal/Docs/Constants/UppercaseMagicConstantsStandard.xml index 2a9583fa..e89dceff 100644 --- a/Universal/Docs/Constants/UppercaseMagicConstantsStandard.xml +++ b/Universal/Docs/Constants/UppercaseMagicConstantsStandard.xml @@ -9,13 +9,13 @@ ]]> - + __LINE__; include __DIR__ . '/file.php'; ]]> - + __NameSpace__; include dirname(__file__) . '/file.php'; diff --git a/Universal/Docs/ControlStructures/DisallowAlternativeSyntaxStandard.xml b/Universal/Docs/ControlStructures/DisallowAlternativeSyntaxStandard.xml index 4be7e6df..816e812f 100644 --- a/Universal/Docs/ControlStructures/DisallowAlternativeSyntaxStandard.xml +++ b/Universal/Docs/ControlStructures/DisallowAlternativeSyntaxStandard.xml @@ -9,7 +9,7 @@ ]]> - + { $var = 1; @@ -20,7 +20,7 @@ while (++$i < 10) { } ]]> - + : $var = 1; diff --git a/Universal/Docs/ControlStructures/DisallowLonelyIfStandard.xml b/Universal/Docs/ControlStructures/DisallowLonelyIfStandard.xml index 88d09228..8acb7bfa 100644 --- a/Universal/Docs/ControlStructures/DisallowLonelyIfStandard.xml +++ b/Universal/Docs/ControlStructures/DisallowLonelyIfStandard.xml @@ -11,7 +11,7 @@ ]]> - + - + - + - + diff --git a/Universal/Docs/Operators/ConcatPositionStandard.xml b/Universal/Docs/Operators/ConcatPositionStandard.xml index 4d2761af..4936f04a 100644 --- a/Universal/Docs/Operators/ConcatPositionStandard.xml +++ b/Universal/Docs/Operators/ConcatPositionStandard.xml @@ -13,14 +13,14 @@ ]]> - + . $b . 'text' . $c; ]]> - + . $b . 'text' diff --git a/Universal/Docs/UseStatements/DisallowUseConstStandard.xml b/Universal/Docs/UseStatements/DisallowUseConstStandard.xml index 0dbec70b..b4340954 100644 --- a/Universal/Docs/UseStatements/DisallowUseConstStandard.xml +++ b/Universal/Docs/UseStatements/DisallowUseConstStandard.xml @@ -15,7 +15,7 @@ use Vendor\Sub\ClassName; use function Vendor\Sub\functionName; ]]> - + - + - + [space][space][space][space]$foo = 'bar'; @@ -17,7 +17,7 @@ [tab]$foo = 'bar'; ]]> - + [space][space]$foo = 'bar'; From 007d8fa5abc48326a27d6173aad88b33fb13c5c5 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 15 Jul 2024 03:58:40 +0200 Subject: [PATCH 09/28] Release checklist: minor update --- .github/release-checklist.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/release-checklist.md b/.github/release-checklist.md index c684f9e7..2c57bac0 100644 --- a/.github/release-checklist.md +++ b/.github/release-checklist.md @@ -24,4 +24,5 @@ PR for tracking changes for the x.x.x release. Target release date: **DOW MONTH - [ ] Fast-forward `develop` to be equal to `stable` ### Publicize +- [ ] Toot about the release. - [ ] Tweet about the release. From a04689a7f46d0308f3ba67c165e9c8adc5af250f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 3 Oct 2024 06:14:58 +0200 Subject: [PATCH 10/28] GH Actions/Basics: use reusable workflow A number of reusable workflows have been introduced in the `PHPCSStandards/.github` repository for workflows used in multiple repos in this organisation, for which the steps are basically the same everywhere. This will make maintenance of these workflows more straight-forward. This commit switches a number of the basic QA workflows over to start using the reusable workflows. --- .github/workflows/basics.yml | 101 ++--------------------------------- 1 file changed, 5 insertions(+), 96 deletions(-) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index 7d1fb0e8..84e5b2a4 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -101,105 +101,14 @@ jobs: phpstan: name: "PHPStan" - runs-on: "ubuntu-latest" - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install PHP - uses: shivammathur/setup-php@v2 - with: - php-version: 'latest' - coverage: none - tools: phpstan - - # Install dependencies and handle caching in one go. - # Dependencies need to be installed to make sure the PHPCS and PHPUnit classes are recognized. - # @link https://github.com/marketplace/actions/install-php-dependencies-with-composer - - name: Install Composer dependencies - uses: "ramsey/composer-install@v3" - with: - # Bust the cache at least once a month - output format: YYYY-MM. - custom-cache-suffix: $(date -u "+%Y-%m") - - - name: Run PHPStan - run: phpstan analyse + uses: PHPCSStandards/.github/.github/workflows/reusable-phpstan.yml@main remark: name: 'QA Markdown' - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up node and enable caching of dependencies - uses: actions/setup-node@v4 - with: - node-version: '16' - - # To make the command available on CLI, it needs to be installed globally. - - name: Install Remark CLI globally - run: npm install --global remark-cli --foreground-scripts true --fund false - - # To allow for creating a custom config which references rules which are included - # in the presets, without having to install all rules individually, a local install - # works best (and installing the presets in the first place, of course). - # - # Note: the first group of packages are all part of the mono "Remark lint" repo. - # The second group of packages (heading-whitespace and down) are additional - # "external" rules/plugins. - - name: Install Remark rules locally - run: > - npm install --foreground-scripts true --fund false - remark-lint - remark-gfm - remark-preset-lint-consistent - remark-preset-lint-recommended - remark-preset-lint-markdown-style-guide - remark-lint-checkbox-content-indent - remark-lint-linebreak-style - remark-lint-no-duplicate-defined-urls - remark-lint-no-empty-url - remark-lint-no-heading-like-paragraph - remark-lint-no-reference-like-url - remark-lint-no-unneeded-full-reference-image - remark-lint-no-unneeded-full-reference-link - remark-lint-strikethrough-marker - remark-lint-heading-whitespace - remark-lint-list-item-punctuation - remark-lint-match-punctuation - remark-lint-no-dead-urls - remark-lint-no-hr-after-heading - remark-lint-are-links-valid-duplicate - remark-validate-links - - - name: Run Remark-lint - run: remark . --frail - - # @link https://github.com/reviewdog/action-remark-lint - - name: Show Remark-lint annotations in PR - if: ${{ failure() && github.event_name == 'pull_request' }} - uses: reviewdog/action-remark-lint@v5 - with: - fail_on_error: true - install_deps: false - level: info - reporter: github-pr-check + uses: PHPCSStandards/.github/.github/workflows/reusable-remark.yml@main yamllint: name: 'Lint Yaml' - runs-on: ubuntu-latest - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - # Ref: https://yamllint.readthedocs.io/en/stable/ - - name: Run Yamllint on all yaml files in repo - run: yamllint . --format colored - - - name: Pipe Yamllint results on to GH for inline display - if: ${{ failure() }} - run: yamllint . --format github + uses: PHPCSStandards/.github/.github/workflows/reusable-yamllint.yml@main + with: + strict: true From f0f9421ac8789de07eaa78acc7bb838292ced766 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Thu, 3 Oct 2024 06:28:11 +0200 Subject: [PATCH 11/28] README/Changelog: fix a few URLs which have changed Fix a few URLs which were being redirected. Includes: * Replacing badges from poser.pugx.org with badges using img.shields.io. --- CHANGELOG.md | 4 ++-- README.md | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ee3258b..f06857ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -This projects adheres to [Keep a CHANGELOG](http://keepachangelog.com/) and uses [Semantic Versioning](http://semver.org/). +This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/en/1.1.0/) and uses [Semantic Versioning](https://semver.org/). **Legend**: :wrench: = Includes auto-fixer. @@ -401,7 +401,7 @@ The upgrade to PHPCSUtils 1.0.0-alpha4 took care of a number of bugs, which pote [php-manual-dirname]: https://www.php.net/function.dirname [php-rfc-negative_array_index]: https://wiki.php.net/rfc/negative_array_index -[ESLint "no lonely if"]: https://eslint.org/docs/rules/no-lonely-if +[ESLint "no lonely if"]: https://eslint.org/docs/latest/rules/no-lonely-if [PHPCSUtils 1.0.0-alpha4]: https://github.com/PHPCSStandards/PHPCSUtils/releases/tag/1.0.0-alpha4 diff --git a/README.md b/README.md index a82fa893..d391c122 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,20 @@ PHPCSExtra @@ -55,7 +55,7 @@ Installation Installing via Composer is highly recommended. -[Composer](http://getcomposer.org/) will automatically install the project dependencies and register the rulesets from PHPCSExtra and other external standards with PHP_CodeSniffer using the [Composer PHPCS plugin][composer-installer-gh]. +[Composer](https://getcomposer.org/) will automatically install the project dependencies and register the rulesets from PHPCSExtra and other external standards with PHP_CodeSniffer using the [Composer PHPCS plugin][composer-installer-gh]. ### Composer Project-based Installation From 50ef6a6a14199bfe6d8cd7621e718333f98f5840 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 13 Oct 2024 23:52:58 +0200 Subject: [PATCH 12/28] GH Actions: always quote variables ... to satisfy shellcheck rule SC2086: "Double quote to prevent globbing and word splitting". Ref: https://www.shellcheck.net/wiki/SC2086 --- .github/workflows/quicktest.yml | 4 ++-- .github/workflows/test.yml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/quicktest.yml b/.github/workflows/quicktest.yml index 11d15306..249cc0c6 100644 --- a/.github/workflows/quicktest.yml +++ b/.github/workflows/quicktest.yml @@ -43,9 +43,9 @@ jobs: id: set_ini run: | if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then - echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> "$GITHUB_OUTPUT" else - echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> "$GITHUB_OUTPUT" fi - name: Install PHP diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8d0ba01..67d61dd7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,9 +49,9 @@ jobs: id: set_ini run: | if [[ "${{ matrix.phpcs_version }}" != "dev-master" ]]; then - echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> "$GITHUB_OUTPUT" else - echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> "$GITHUB_OUTPUT" fi - name: Install PHP @@ -120,9 +120,9 @@ jobs: id: set_ini run: | if [ "${{ matrix.phpcs_version }}" != "dev-master" ]; then - echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> $GITHUB_OUTPUT + echo 'PHP_INI=error_reporting=E_ALL & ~E_DEPRECATED, display_errors=On' >> "$GITHUB_OUTPUT" else - echo 'PHP_INI=error_reporting=-1, display_errors=On' >> $GITHUB_OUTPUT + echo 'PHP_INI=error_reporting=-1, display_errors=On' >> "$GITHUB_OUTPUT" fi - name: Install PHP From deba277f1c22a2047e552ade77155cce3e5803f2 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 14 Oct 2024 00:12:58 +0200 Subject: [PATCH 13/28] Partially revert "README/Changelog: fix a few URLs which have changed" This partially reverts commit f0f9421ac8789de07eaa78acc7bb838292ced766 (PR 317) after improvements upstream in the Remark no-dead-urls module. Ref: remarkjs/remark-lint-no-dead-urls 54 --- .remarkrc | 8 ++++++-- CHANGELOG.md | 2 +- README.md | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.remarkrc b/.remarkrc index 568f5885..f5bc35c1 100644 --- a/.remarkrc +++ b/.remarkrc @@ -13,8 +13,12 @@ { "skipUrlPatterns": [ "https://www.php.net/", - "^https?://github\\.com/PHPCSStandards/PHPCSExtra/compare/[0-9\\.]+?\\.{3}[0-9\\.]+" - ] + "^https?://github\\.com/PHPCSStandards/PHPCSExtra/compare/[0-9\\.]+?\\.{3}[0-9\\.]+", + "https://packagist.org/packages/phpcsstandards/phpcsextra#dev-develop" + ], + "deadOrAliveOptions": { + "maxRetries": 3 + } } ], "remark-lint-no-duplicate-defined-urls", diff --git a/CHANGELOG.md b/CHANGELOG.md index f06857ee..8c087ded 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/en/1.1.0/) and uses [Semantic Versioning](https://semver.org/). +This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/) and uses [Semantic Versioning](https://semver.org/). **Legend**: :wrench: = Includes auto-fixer. diff --git a/README.md b/README.md index d391c122..d675943b 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,12 @@ PHPCSExtra [![Latest Stable Version](https://img.shields.io/packagist/v/phpcsstandards/phpcsextra?label=stable)][phpcsextra-packagist] [![Release Date of the Latest Version](https://img.shields.io/github/release-date/PHPCSStandards/PHPCSExtra.svg?maxAge=1800)](https://github.com/PHPCSStandards/PHPCSExtra/releases) :construction: -[![Latest Unstable Version](https://img.shields.io/badge/unstable-dev--develop-e68718.svg?maxAge=2419200)][phpcsextra-packagist] +[![Latest Unstable Version](https://img.shields.io/badge/unstable-dev--develop-e68718.svg?maxAge=2419200)](https://packagist.org/packages/phpcsstandards/phpcsextra#dev-develop) [![Last Commit to Unstable](https://img.shields.io/github/last-commit/PHPCSStandards/PHPCSExtra/develop.svg)](https://github.com/PHPCSStandards/PHPCSExtra/commits/develop) [![CS Build Status](https://github.com/PHPCSStandards/PHPCSExtra/actions/workflows/basics.yml/badge.svg?branch=develop)][gha-qa-results] [![Test Build Status](https://github.com/PHPCSStandards/PHPCSExtra/actions/workflows/test.yml/badge.svg?branch=develop)][gha-test-results] -[![Coverage Status](https://img.shields.io/coverallsCoverage/github/PHPCSStandards/PHPCSExtra)](https://coveralls.io/github/PHPCSStandards/PHPCSExtra) +[![Coverage Status](https://coveralls.io/repos/github/PHPCSStandards/PHPCSExtra/badge.svg)](https://coveralls.io/github/PHPCSStandards/PHPCSExtra) [![Minimum PHP Version](https://img.shields.io/packagist/dependency-v/phpcsstandards/phpcsextra/php.svg)][phpcsextra-packagist] [![Tested on PHP 5.4 to 8.3](https://img.shields.io/badge/tested%20on-PHP%205.4%20|%205.5%20|%205.6%20|%207.0%20|%207.1%20|%207.2%20|%207.3%20|%207.4%20|%208.0%20|%208.1%20|%208.2%20|%208.3-brightgreen.svg?maxAge=2419200)][gha-test-results] From 4523f4ea8a25cdea66a68332b89effae411dfe75 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 23 Oct 2024 05:13:49 +0200 Subject: [PATCH 14/28] Universal/DisallowInlineTabs: handle more tokens While likely to be edge cases, there are a couple more tokens in which inline, non-indentation tabs can exist: * `T_START_HEREDOC` and `T_START_NOWDOC` - between the `<<<` and the identifiers. * `T_YIELD_FROM` - between the `yield` and the `from` keywords. This updates the sniff to also handle those tokens. Includes additional unit tests. Loosely related to upstream changes which start doing tab replacement in these tokens too. Note: this PR is _not_ dependent on the upstream changes and does not warrant raising the minimum supported PHPCS version. --- .../WhiteSpace/DisallowInlineTabsSniff.php | 15 ++++++++++++- .../DisallowInlineTabsUnitTest.1.inc | 21 +++++++++++++++++++ .../DisallowInlineTabsUnitTest.1.inc.fixed | 21 +++++++++++++++++++ .../DisallowInlineTabsUnitTest.4.inc | 14 +++++++++++++ .../DisallowInlineTabsUnitTest.4.inc.fixed | 14 +++++++++++++ .../DisallowInlineTabsUnitTest.5.inc | 14 +++++++++++++ .../DisallowInlineTabsUnitTest.5.inc.fixed | 14 +++++++++++++ .../DisallowInlineTabsUnitTest.6.inc | 21 +++++++++++++++++++ .../WhiteSpace/DisallowInlineTabsUnitTest.php | 19 +++++++++++++++++ 9 files changed, 152 insertions(+), 1 deletion(-) diff --git a/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php b/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php index 817a44e1..77d15d00 100644 --- a/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php +++ b/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php @@ -63,6 +63,9 @@ final class DisallowInlineTabsSniff implements Sniff \T_DOC_COMMENT_WHITESPACE => true, \T_DOC_COMMENT_STRING => true, \T_COMMENT => true, + \T_START_HEREDOC => true, + \T_START_NOWDOC => true, + \T_YIELD_FROM => true, ]; /** @@ -102,7 +105,7 @@ public function process(File $phpcsFile, $stackPtr) $dummy = new DummyTokenizer('', $phpcsFile->config); for ($i = 0; $i < $phpcsFile->numTokens; $i++) { - // Skip all non-whitespace tokens and skip whitespace at the start of a new line. + // Skip all non-target tokens and skip whitespace at the start of a new line. if (isset($this->find[$tokens[$i]['code']]) === false || (($tokens[$i]['code'] === \T_WHITESPACE || $tokens[$i]['code'] === \T_DOC_COMMENT_WHITESPACE) @@ -147,6 +150,16 @@ public function process(File $phpcsFile, $stackPtr) } } + /* + * For "yield from", we should only handle tabs _between_ the keywords (single token), + * not indentation for those situations where the keyword is split in multiple tokens. + */ + if ($tokens[$i]['code'] === \T_YIELD_FROM + && \preg_match('`^yield.+from$`i', $tokens[$i]['content']) !== 1 + ) { + continue; + } + $fix = $phpcsFile->addFixableError( 'Spaces must be used for mid-line alignment; tabs are not allowed', $i, diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc index 0d065c08..f50b2102 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc @@ -59,3 +59,24 @@ $aaaaaaaa = true; // Tab indented, no tabs. // phpcs:ignore Stnd.Cat.SniffName -- testing mixed comment + annotations don't trigger on indentation. // Tab indented, no tabs. + +$a = <<< TAB_BETWEEN +text +TAB_BETWEEN; + +$a = <<< 'TABS_BETWEEN' +text +TABS_BETWEEN; + +function myGenerator() { + yield from tabsBetweenShouldBeFixed(); + +yield /*comment*/ from tabsBetweenShouldBeFixedEvenWhenKeywordStartsOnColumn1(); + + yield + from tabIndentationShouldBeIgnored(); + + yield + /*comment*/ + from tabIndentationShouldBeIgnored(); +} diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc.fixed b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc.fixed index 63726813..37c19527 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc.fixed +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.1.inc.fixed @@ -59,3 +59,24 @@ $aaaaaaaa = true; // Tab indented, no tabs. // phpcs:ignore Stnd.Cat.SniffName -- testing mixed comment + annotations don't trigger on indentation. // Tab indented, no tabs. + +$a = <<< TAB_BETWEEN +text +TAB_BETWEEN; + +$a = <<< 'TABS_BETWEEN' +text +TABS_BETWEEN; + +function myGenerator() { + yield from tabsBetweenShouldBeFixed(); + +yield /*comment*/ from tabsBetweenShouldBeFixedEvenWhenKeywordStartsOnColumn1(); + + yield + from tabIndentationShouldBeIgnored(); + + yield + /*comment*/ + from tabIndentationShouldBeIgnored(); +} diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc index 7227c96c..d79d8d3f 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc @@ -33,3 +33,17 @@ $aaaaaaaa = true; // Tab indented and inline tabs. // Tab indented and inline tabs. + +$a = <<< TAB_BETWEEN +text +TAB_BETWEEN; + +$a = <<< 'TABS_BETWEEN' +text +TABS_BETWEEN; + +function myGenerator() { + yield from tabsBetweenShouldBeFixed(); + +yield /*comment*/ from tabsBetweenShouldBeFixedEvenWhenKeywordStartsOnColumn1(); +} diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc.fixed b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc.fixed index 982e48ea..715f13e0 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc.fixed +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.4.inc.fixed @@ -33,3 +33,17 @@ $aaaaaaaa = true; // Tab indented and inline tabs. // Tab indented and inline tabs. + +$a = <<< TAB_BETWEEN +text +TAB_BETWEEN; + +$a = <<< 'TABS_BETWEEN' +text +TABS_BETWEEN; + +function myGenerator() { + yield from tabsBetweenShouldBeFixed(); + +yield /*comment*/ from tabsBetweenShouldBeFixedEvenWhenKeywordStartsOnColumn1(); +} diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc index 139b27fd..1904a508 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc @@ -33,3 +33,17 @@ $aaaaaaaa = true; // Tab indented and inline tabs. // Tab indented and inline tabs. + +$a = <<< TAB_BETWEEN +text +TAB_BETWEEN; + +$a = <<< 'TABS_BETWEEN' +text +TABS_BETWEEN; + +function myGenerator() { + yield from tabsBetweenShouldBeFixed(); + +yield /*comment*/ from tabsBetweenShouldBeFixedEvenWhenKeywordStartsOnColumn1(); +} diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc.fixed b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc.fixed index ce001601..e2bd84e0 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc.fixed +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.5.inc.fixed @@ -33,3 +33,17 @@ $aaaaaaaa = true; // Tab indented and inline tabs. // Tab indented and inline tabs. + +$a = <<< TAB_BETWEEN +text +TAB_BETWEEN; + +$a = <<< 'TABS_BETWEEN' +text +TABS_BETWEEN; + +function myGenerator() { + yield from tabsBetweenShouldBeFixed(); + +yield /*comment*/ from tabsBetweenShouldBeFixedEvenWhenKeywordStartsOnColumn1(); +} diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.6.inc b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.6.inc index 05b55208..9dcecd1b 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.6.inc +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.6.inc @@ -41,3 +41,24 @@ $aaaaaaaa = true; * @param int $var Description. * @param string $string Another description. */ + +$a = <<< TAB_BETWEEN +text +TAB_BETWEEN; + +$a = <<< 'TABS_BETWEEN' +text +TABS_BETWEEN; + +function myGenerator() { + yield from tabsBetweenShouldBeFixed(); + + yield /*comment*/ from tabsBetweenShouldBeFixed(); + + yield + from tabIndentationShouldBeIgnored(); + + yield + /*comment*/ + from tabIndentationShouldBeIgnored(); +} diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php index 147e3361..ba44d939 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php @@ -10,6 +10,7 @@ namespace PHPCSExtra\Universal\Tests\WhiteSpace; +use PHP_CodeSniffer\Config; use PHP_CodeSniffer\Tests\Standards\AbstractSniffUnitTest; /** @@ -73,6 +74,12 @@ public function setCliValues($testFile, $config) */ public function getErrorList($testFile = '') { + // As of PHP 8.3, comments may be tokenized within a "yield from" token, but only for PHPCS < 3.11.0. + $commentsInYieldFrom = false; + if (\PHP_VERSION_ID >= 80300 /*&& \version_compare(Config::VERSION, '3.11.0', '<')*/) { + $commentsInYieldFrom = true; + } + switch ($testFile) { case 'DisallowInlineTabsUnitTest.1.inc': return [ @@ -93,6 +100,10 @@ public function getErrorList($testFile = '') 49 => 1, 52 => 1, 53 => 1, + 63 => 1, + 67 => 1, + 72 => 1, + 74 => ($commentsInYieldFrom === true ? 1 : 2), ]; case 'DisallowInlineTabsUnitTest.2.inc': @@ -126,6 +137,10 @@ public function getErrorList($testFile = '') 31 => 1, 34 => 1, 35 => 1, + 37 => 1, + 41 => 1, + 46 => 1, + 48 => ($commentsInYieldFrom === true ? 1 : 2), ]; case 'DisallowInlineTabsUnitTest.5.inc': @@ -145,6 +160,10 @@ public function getErrorList($testFile = '') 31 => 1, 34 => 1, 35 => 1, + 37 => 1, + 41 => 1, + 46 => 1, + 48 => ($commentsInYieldFrom === true ? 1 : 2), ]; default: From a3ef964cd65cd12d0be326dece6c83473a513ac4 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 23 Oct 2024 05:55:24 +0200 Subject: [PATCH 15/28] Universal/DisallowInlineTabs: minor tweak to the tests Follow up on 320 The Tokenizer changes related to `yield from` with comments, which were expected to go into PHPCS 3.11.0, have been merged. This updates the condition used in the tests to reflect the upstream change. --- Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php index ba44d939..4de61162 100644 --- a/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php +++ b/Universal/Tests/WhiteSpace/DisallowInlineTabsUnitTest.php @@ -76,7 +76,7 @@ public function getErrorList($testFile = '') { // As of PHP 8.3, comments may be tokenized within a "yield from" token, but only for PHPCS < 3.11.0. $commentsInYieldFrom = false; - if (\PHP_VERSION_ID >= 80300 /*&& \version_compare(Config::VERSION, '3.11.0', '<')*/) { + if (\PHP_VERSION_ID >= 80300 && \version_compare(Config::VERSION, '3.11.0', '<')) { $commentsInYieldFrom = true; } From 7b88c12592ece09e099397b3c20e3c347d997d4f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 9 Nov 2024 00:38:35 +0100 Subject: [PATCH 16/28] Universal/SeparateFunctionsFromOO: simplify skipping the rest of the file This commit updates the sniff to use `return $phpcsFile->numTokens` instead of `return ($phpcsFile->numTokens + 1)`. If a sniff file contains 50 tokens, the last `$stackPtr` will be 49, so returning `50` will already get us passed the end of the token stack and the `+ 1` is redundant. Includes minor fix to the return type as the method never returns `void`. --- Universal/Sniffs/Files/SeparateFunctionsFromOOSniff.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Universal/Sniffs/Files/SeparateFunctionsFromOOSniff.php b/Universal/Sniffs/Files/SeparateFunctionsFromOOSniff.php index c274e751..9cf191e0 100644 --- a/Universal/Sniffs/Files/SeparateFunctionsFromOOSniff.php +++ b/Universal/Sniffs/Files/SeparateFunctionsFromOOSniff.php @@ -81,8 +81,7 @@ public function register() * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. + * @return int Integer stack pointer to skip forward. */ public function process(File $phpcsFile, $stackPtr) { @@ -185,6 +184,6 @@ public function process(File $phpcsFile, $stackPtr) } // Ignore the rest of the file. - return ($phpcsFile->numTokens + 1); + return $phpcsFile->numTokens; } } From bc5b3b362c7e2303f82064ba3ceee513f38af466 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Fri, 8 Nov 2024 14:10:22 +0100 Subject: [PATCH 17/28] GH Actions: use explicit PHPStan major This Monday, [PHPStan 2.0 will be released](https://phpc.social/@OndrejMirtes/113441109253809720). I've done some preliminary scans with PHPStan 2.0-dev to check if this would have an impact on this codebase and as things are, this would mean the build would start to fail. For now, I'm proposing to make a small change in the GH Actions workflow to explicitly use PHPStan 1.x. This buys us some time to evaluate PHPStan 2.0 properly and to make any changes needed to make the codebase compatible with PHPStan 2.x when we're ready for it. Note: At least one of the new issues reported has been identified as a bug and reported to PHPStan: https://github.com/phpstan/phpstan/issues/11980 --- .github/workflows/basics.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index 84e5b2a4..f753c1a0 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -102,6 +102,8 @@ jobs: phpstan: name: "PHPStan" uses: PHPCSStandards/.github/.github/workflows/reusable-phpstan.yml@main + with: + phpstanVersion: '1.x' remark: name: 'QA Markdown' From 9455319cbe93c1d60fbd8d6a599733a0177b1e3a Mon Sep 17 00:00:00 2001 From: jrfnl Date: Wed, 24 Apr 2024 23:16:54 +0200 Subject: [PATCH 18/28] Various minor doc fixes --- Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php | 3 --- .../Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php | 2 +- Universal/Sniffs/ControlStructures/DisallowLonelyIfSniff.php | 2 +- Universal/Sniffs/PHP/OneStatementInShortEchoTagSniff.php | 2 +- Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc | 2 -- .../Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed | 2 -- Universal/Tests/UseStatements/KeywordSpacingUnitTest.php | 2 +- 7 files changed, 4 insertions(+), 11 deletions(-) diff --git a/Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php b/Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php index 7097fad7..1fe6841a 100644 --- a/Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php +++ b/Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php @@ -80,9 +80,6 @@ final class DuplicateArrayKeySniff extends AbstractArrayDeclarationSniff /** * Process every part of the array declaration. * - * This contains the default logic for the sniff, but can be overloaded in a concrete child class - * if needed. - * * @since 1.0.0 * * @param \PHP_CodeSniffer\Files\File $phpcsFile The PHP_CodeSniffer file where the diff --git a/Universal/Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php b/Universal/Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php index 6f78cb66..147d46e7 100644 --- a/Universal/Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php +++ b/Universal/Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php @@ -166,7 +166,7 @@ public function process(File $phpcsFile, $stackPtr) $current = $tokens[$stackPtr]['scope_opener']; $end = $tokens[$stackPtr]['scope_closer']; - // Not searching for arrow functions as those have an implicit return, so no + // Not searching for arrow functions as those have an implicit return, so won't use the `return` keyword. $search = Collections::functionDeclarationTokens(); $search[\T_RETURN] = \T_RETURN; diff --git a/Universal/Sniffs/ControlStructures/DisallowLonelyIfSniff.php b/Universal/Sniffs/ControlStructures/DisallowLonelyIfSniff.php index 58c81ae1..f29a1fea 100644 --- a/Universal/Sniffs/ControlStructures/DisallowLonelyIfSniff.php +++ b/Universal/Sniffs/ControlStructures/DisallowLonelyIfSniff.php @@ -121,7 +121,7 @@ public function process(File $phpcsFile, $stackPtr) if ($tokens[$nextAfter]['code'] === \T_SEMICOLON) { $innerScopeCloser = $nextAfter; } else { - // Missing semi-colon. Report, but don't auto-fix. + // Missing semicolon. Report, but don't auto-fix. $autoFixable = false; } } else { diff --git a/Universal/Sniffs/PHP/OneStatementInShortEchoTagSniff.php b/Universal/Sniffs/PHP/OneStatementInShortEchoTagSniff.php index cbccb4c6..d68c38ee 100644 --- a/Universal/Sniffs/PHP/OneStatementInShortEchoTagSniff.php +++ b/Universal/Sniffs/PHP/OneStatementInShortEchoTagSniff.php @@ -75,7 +75,7 @@ public function process(File $phpcsFile, $stackPtr) return; } - // Semi-colon, so check for any code between it and the close tag. + // Semicolon, so check for any code between it and the close tag. $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($endOfStatement + 1), null, true); if ($nextNonEmpty === false || $tokens[$nextNonEmpty]['code'] === \T_CLOSE_TAG diff --git a/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc index 162e98b3..a12f3abb 100644 --- a/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc +++ b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc @@ -5,7 +5,5 @@ * For PHP < 8.0, it will correctly flag this as "no space" after the `use` keyword. * For PHP 8.0+, this will no longer be flagged as keywords are allowed in namespaced names, * so the `use` is tokenized as `T_STRING` instead of `T_USE` and won't be flagged. - * - * For this reason, there is no "fixed" file included as the test would not be able to pass on PHP 8.0+. */ use\Util\MyOtherClass; diff --git a/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed index 5589d374..e15065e9 100644 --- a/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed +++ b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.2.inc.fixed @@ -5,7 +5,5 @@ * For PHP < 8.0, it will correctly flag this as "no space" after the `use` keyword. * For PHP 8.0+, this will no longer be flagged as keywords are allowed in namespaced names, * so the `use` is tokenized as `T_STRING` instead of `T_USE` and won't be flagged. - * - * For this reason, there is no "fixed" file included as the test would not be able to pass on PHP 8.0+. */ use \Util\MyOtherClass; diff --git a/Universal/Tests/UseStatements/KeywordSpacingUnitTest.php b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.php index a7f201dc..abcc98c8 100644 --- a/Universal/Tests/UseStatements/KeywordSpacingUnitTest.php +++ b/Universal/Tests/UseStatements/KeywordSpacingUnitTest.php @@ -84,7 +84,7 @@ public function getErrorList($testFile = '') case 'KeywordSpacingUnitTest.2.inc': return [ - 11 => 1, + 9 => 1, ]; default: From 62898ebe28851228a685cef65dd5a8648b2601cd Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 11 Nov 2024 18:34:53 +0100 Subject: [PATCH 19/28] PHPStan 2.0: update configuration PHPStan 2.0 has been released :tada: This commit makes the necessary updates to switch to PHPStan 2.0. Includes normalizing slashes in path references in the PHPStan config file. Refs: * https://phpstan.org/blog/phpstan-2-0-released-level-10-elephpants * https://github.com/phpstan/phpstan/blob/2.0.x/UPGRADING.md * https://github.com/phpstan/phpstan/releases/tag/2.0.0 --- .github/workflows/basics.yml | 2 +- .../Sniffs/Operators/ConcatPositionSniff.php | 3 +- phpstan.neon.dist | 35 +++++++++++-------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index f753c1a0..d5cf0e9c 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -103,7 +103,7 @@ jobs: name: "PHPStan" uses: PHPCSStandards/.github/.github/workflows/reusable-phpstan.yml@main with: - phpstanVersion: '1.x' + phpstanVersion: '2.x' remark: name: 'QA Markdown' diff --git a/Universal/Sniffs/Operators/ConcatPositionSniff.php b/Universal/Sniffs/Operators/ConcatPositionSniff.php index 093785ad..1a035766 100644 --- a/Universal/Sniffs/Operators/ConcatPositionSniff.php +++ b/Universal/Sniffs/Operators/ConcatPositionSniff.php @@ -96,8 +96,7 @@ public function register() * @param int $stackPtr The position of the current token * in the stack passed in $tokens. * - * @return int|void Integer stack pointer to skip forward or void to continue - * normal file processing. + * @return void */ public function process(File $phpcsFile, $stackPtr) { diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 060dda93..95991de0 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -16,36 +16,41 @@ parameters: # Keep to stay in line with parent class. - message: '`^Constructor of class PHPCSExtra\\Universal\\Helpers\\DummyTokenizer has an unused parameter \$content\.$`' - path: Universal\Helpers\DummyTokenizer.php + path: Universal/Helpers/DummyTokenizer.php count: 1 # Level 4 # PHPStan doesn't seem to like uninitialized properties... + # Ref: https://github.com/phpstan/phpstan/issues/10305 - message: '`^Property \S+Sniff::\$(phpVersion|tabWidth) \(int\) in isset\(\) is not nullable\.$`' paths: - - Modernize\Sniffs\FunctionCalls\DirnameSniff.php - - Universal\Sniffs\Arrays\DuplicateArrayKeySniff.php - - Universal\Sniffs\CodeAnalysis\ConstructorDestructorReturnSniff.php - - Universal\Sniffs\WhiteSpace\CommaSpacingSniff.php - - Universal\Sniffs\WhiteSpace\DisallowInlineTabsSniff.php - - Universal\Sniffs\WhiteSpace\PrecisionAlignmentSniff.php + - Modernize/Sniffs/FunctionCalls/DirnameSniff.php + - Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php + - Universal/Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php + - Universal/Sniffs/WhiteSpace/CommaSpacingSniff.php + - Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php + - Universal/Sniffs/WhiteSpace/PrecisionAlignmentSniff.php - message: '`^Strict comparison using === between true and false will always evaluate to false\.$`' paths: - - Modernize\Sniffs\FunctionCalls\DirnameSniff.php - - Universal\Sniffs\Arrays\DuplicateArrayKeySniff.php - - Universal\Sniffs\CodeAnalysis\ConstructorDestructorReturnSniff.php - - Universal\Sniffs\WhiteSpace\CommaSpacingSniff.php - - Universal\Sniffs\WhiteSpace\DisallowInlineTabsSniff.php - - Universal\Sniffs\WhiteSpace\PrecisionAlignmentSniff.php + - Modernize/Sniffs/FunctionCalls/DirnameSniff.php + - Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php + - Universal/Sniffs/CodeAnalysis/ConstructorDestructorReturnSniff.php + - Universal/Sniffs/WhiteSpace/CommaSpacingSniff.php + - Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php + - Universal/Sniffs/WhiteSpace/PrecisionAlignmentSniff.php - message: '`^Property PHPCSExtra\\Universal\\Sniffs\\Arrays\\DuplicateArrayKeySniff\:\:\$currentMaxIntKey[GL]t8 \(int\) in isset\(\) is not nullable\.$`' - path: Universal\Sniffs\Arrays\DuplicateArrayKeySniff.php + path: Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php count: 5 + - + message: '`^Strict comparison using === between true and true will always evaluate to true\.$`' + path: Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php + count: 1 - message: '`^Result of && is always false\.$`' - path: Universal\Sniffs\Arrays\DuplicateArrayKeySniff.php + path: Universal/Sniffs/Arrays/DuplicateArrayKeySniff.php count: 1 # Level 5 From 3e73121d9f419c58752f4a7960a926047d9218c9 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 11 Nov 2024 18:48:21 +0100 Subject: [PATCH 20/28] GH Actions: update for the release of PHP 8.4 ... which is expected later this month. * Builds against PHP 8.4 are no longer allowed to fail. * Update PHP version on which code coverage is run (high should now be 8.4). * Add _allowed to fail_ build against PHP 8.5. * Update the "tested against" badge in the README. --- .github/workflows/test.yml | 6 +++--- README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 67d61dd7..bf2bb4e6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,12 +32,12 @@ jobs: # @link https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstrategymatrix # # The matrix is set up so as not to duplicate the builds which are run for code coverage. - php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.4'] + php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.5'] phpcs_version: ['lowest', 'dev-master'] name: "Test${{ matrix.phpcs_version == 'dev-master' && ' + Lint' || '' }}: PHP ${{ matrix.php }} - PHPCS ${{ matrix.phpcs_version }}" - continue-on-error: ${{ matrix.php == '8.4' }} + continue-on-error: ${{ matrix.php == '8.5' }} steps: - name: Checkout code @@ -105,7 +105,7 @@ jobs: strategy: matrix: - php: ['5.4', '8.3'] + php: ['5.4', '8.4'] phpcs_version: ['lowest', 'dev-master'] name: "Coverage${{ matrix.phpcs_version == 'dev-master' && ' + Lint' || '' }}: PHP ${{ matrix.php }} - PHPCS ${{ matrix.phpcs_version }}" diff --git a/README.md b/README.md index d675943b..c617f8ea 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ PHPCSExtra [![Coverage Status](https://coveralls.io/repos/github/PHPCSStandards/PHPCSExtra/badge.svg)](https://coveralls.io/github/PHPCSStandards/PHPCSExtra) [![Minimum PHP Version](https://img.shields.io/packagist/dependency-v/phpcsstandards/phpcsextra/php.svg)][phpcsextra-packagist] -[![Tested on PHP 5.4 to 8.3](https://img.shields.io/badge/tested%20on-PHP%205.4%20|%205.5%20|%205.6%20|%207.0%20|%207.1%20|%207.2%20|%207.3%20|%207.4%20|%208.0%20|%208.1%20|%208.2%20|%208.3-brightgreen.svg?maxAge=2419200)][gha-test-results] +[![Tested on PHP 5.4 to 8.4](https://img.shields.io/badge/tested%20on-PHP%205.4%20|%205.5%20|%205.6%20|%207.0%20|%207.1%20|%207.2%20|%207.3%20|%207.4%20|%208.0%20|%208.1%20|%208.2%20|%208.3%20|%208.4-brightgreen.svg?maxAge=2419200)][gha-test-results] [![License: LGPLv3](https://img.shields.io/github/license/PHPCSStandards/PHPCSExtra)](https://github.com/PHPCSStandards/PHPCSExtra/blob/stable/LICENSE) ![Awesome](https://img.shields.io/badge/awesome%3F-yes!-brightgreen.svg) From 793494e0c53408722682d71442e7a37bc86ec089 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Mar 2025 02:19:08 +0100 Subject: [PATCH 21/28] GH Actions: split XML code style check off from "Basic QA"check The intention is for there to be a dedicated action runner available at some point for XML code style checking, so let's move this to a separate job. Also see: https://github.com/PHPCSStandards/PHPCSDevTools/issues/145 --- .github/workflows/basics.yml | 40 ++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index d5cf0e9c..278da414 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -20,7 +20,6 @@ jobs: runs-on: ubuntu-latest env: - XMLLINT_INDENT: ' ' # - COMPOSER_ROOT_VERSION is needed to get round the recursive dependency when using CI. COMPOSER_ROOT_VERSION: '1.99.99' @@ -73,13 +72,6 @@ jobs: - name: Validate rulesets against schema run: xmllint --noout --schema vendor/squizlabs/php_codesniffer/phpcs.xsd ./*/ruleset.xml - # Check the code-style consistency of the XML ruleset files. - - name: Check XML code style - run: | - diff -B ./Modernize/ruleset.xml <(xmllint --format "./Modernize/ruleset.xml") - diff -B ./NormalizedArrays/ruleset.xml <(xmllint --format "./NormalizedArrays/ruleset.xml") - diff -B ./Universal/ruleset.xml <(xmllint --format "./Universal/ruleset.xml") - # Validate the Documentation XML files. - name: Validate documentation against schema run: xmllint --noout --schema vendor/phpcsstandards/phpcsdevtools/DocsXsd/phpcsdocs.xsd ./*/Docs/*/*Standard.xml @@ -99,6 +91,38 @@ jobs: - name: Check sniff feature completeness run: composer check-complete + xml-cs: + name: 'XML Code style' + runs-on: ubuntu-latest + + env: + XMLLINT_INDENT: ' ' + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + # Updating the lists can fail intermittently, typically after Microsoft has released a new package. + # This should not be blocking for this job, so ignore any errors from this step. + # Ref: https://github.com/dotnet/core/issues/4167 + - name: Update the available packages list + continue-on-error: true + run: sudo apt-get update + + - name: Install xmllint + run: sudo apt-get install --no-install-recommends -y libxml2-utils + + # Show XML violations inline in the file diff. + - name: Enable showing XML issues inline + uses: korelstar/xmllint-problem-matcher@v1 + + # Check the code-style consistency of the XML ruleset files. + - name: Check XML code style + run: | + diff -B ./Modernize/ruleset.xml <(xmllint --format "./Modernize/ruleset.xml") + diff -B ./NormalizedArrays/ruleset.xml <(xmllint --format "./NormalizedArrays/ruleset.xml") + diff -B ./Universal/ruleset.xml <(xmllint --format "./Universal/ruleset.xml") + phpstan: name: "PHPStan" uses: PHPCSStandards/.github/.github/workflows/reusable-phpstan.yml@main From 8e5edbf2afd964ff31f61abfa94960fba16b0c43 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Mar 2025 02:21:46 +0100 Subject: [PATCH 22/28] GH Actions: use the xmllint-validate action runner Instead of doing all the installation steps for xmllint validation in the workflow, use the :sparkles: new dedicated `phpcsstandards/xmllint-validate` action runner instead. Ref: https://github.com/marketplace/actions/xmllint-validate --- .github/workflows/basics.yml | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index 278da414..157972c6 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -52,29 +52,18 @@ jobs: # Bust the cache at least once a month - output format: YYYY-MM. custom-cache-suffix: $(date -u "+%Y-%m") - # Updating the lists can fail intermittently, typically after Microsoft has released a new package. - # This should not be blocking for this job, so ignore any errors from this step. - # Ref: https://github.com/dotnet/core/issues/4167 - - name: Update the available packages list - continue-on-error: true - run: sudo apt-get update - - - name: Install xmllint - run: sudo apt-get install --no-install-recommends -y libxml2-utils - - # Show XML violations inline in the file diff. - # @link https://github.com/marketplace/actions/xmllint-problem-matcher - - name: Enable showing XML issues inline - uses: korelstar/xmllint-problem-matcher@v1 - - # Validate the Ruleset XML file. - # @link http://xmlsoft.org/xmllint.html - - name: Validate rulesets against schema - run: xmllint --noout --schema vendor/squizlabs/php_codesniffer/phpcs.xsd ./*/ruleset.xml + # Validate XML files against schema. + - name: Validate XML rulesets against schema + uses: phpcsstandards/xmllint-validate@v1 + with: + pattern: "./*/ruleset.xml" + xsd-file: "vendor/squizlabs/php_codesniffer/phpcs.xsd" - # Validate the Documentation XML files. - - name: Validate documentation against schema - run: xmllint --noout --schema vendor/phpcsstandards/phpcsdevtools/DocsXsd/phpcsdocs.xsd ./*/Docs/*/*Standard.xml + - name: Validate documentation XML against schema + uses: phpcsstandards/xmllint-validate@v1 + with: + pattern: "./*/Docs/*/*Standard.xml" + xsd-file: "vendor/phpcsstandards/phpcsdevtools/DocsXsd/phpcsdocs.xsd" # Check the code-style consistency of the PHP files. - name: Check PHP code style From ce13c97a38e9239dccaf0fab3ee3ad44cda2a88c Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 3 Mar 2025 02:24:38 +0100 Subject: [PATCH 23/28] GH Actions: add some additional XML validation checks ... for dev tool files. --- .github/workflows/basics.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/.github/workflows/basics.yml b/.github/workflows/basics.yml index 157972c6..b39046bb 100644 --- a/.github/workflows/basics.yml +++ b/.github/workflows/basics.yml @@ -65,6 +65,24 @@ jobs: pattern: "./*/Docs/*/*Standard.xml" xsd-file: "vendor/phpcsstandards/phpcsdevtools/DocsXsd/phpcsdocs.xsd" + - name: Validate Project PHPCS ruleset against schema + uses: phpcsstandards/xmllint-validate@v1 + with: + pattern: "phpcs.xml.dist" + xsd-file: "vendor/squizlabs/php_codesniffer/phpcs.xsd" + + - name: "Validate PHPUnit config for use with PHPUnit 8" + uses: phpcsstandards/xmllint-validate@v1 + with: + pattern: "phpunit.xml.dist" + xsd-file: "vendor/phpunit/phpunit/schema/8.5.xsd" + + - name: "Validate PHPUnit config for use with PHPUnit 9" + uses: phpcsstandards/xmllint-validate@v1 + with: + pattern: "phpunit.xml.dist" + xsd-file: "vendor/phpunit/phpunit/schema/9.2.xsd" + # Check the code-style consistency of the PHP files. - name: Check PHP code style id: phpcs From 53fa0b60080907386131c1b16b2b476c51f48a19 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sat, 1 Mar 2025 20:37:38 +0100 Subject: [PATCH 24/28] :sparkles: New Universal.PHP.NoFQNTrueFalseNull sniff ... to forbid using `true`, `false` and `null` as fully qualified constants. Includes fixer. Includes unit tests. Includes documentation. Note: yes, there is a related tokenizer issue in PHPCS where these tokens are not tokenized the same PHP cross-version, however, the tokenization will change in PHPCS 4.0 as well, so there isn't much point addressing that now as it would just make things even more complicated for sniffs come PHPCS 4.0. And yes, this does mean that this sniff will need adjusting for PHPCS 4.0. --- .../Docs/PHP/NoFQNTrueFalseNullStandard.xml | 27 ++++++ .../Sniffs/PHP/NoFQNTrueFalseNullSniff.php | 92 +++++++++++++++++++ .../Tests/PHP/NoFQNTrueFalseNullUnitTest.inc | 27 ++++++ .../PHP/NoFQNTrueFalseNullUnitTest.inc.fixed | 27 ++++++ .../Tests/PHP/NoFQNTrueFalseNullUnitTest.php | 54 +++++++++++ 5 files changed, 227 insertions(+) create mode 100644 Universal/Docs/PHP/NoFQNTrueFalseNullStandard.xml create mode 100644 Universal/Sniffs/PHP/NoFQNTrueFalseNullSniff.php create mode 100644 Universal/Tests/PHP/NoFQNTrueFalseNullUnitTest.inc create mode 100644 Universal/Tests/PHP/NoFQNTrueFalseNullUnitTest.inc.fixed create mode 100644 Universal/Tests/PHP/NoFQNTrueFalseNullUnitTest.php diff --git a/Universal/Docs/PHP/NoFQNTrueFalseNullStandard.xml b/Universal/Docs/PHP/NoFQNTrueFalseNullStandard.xml new file mode 100644 index 00000000..205b4661 --- /dev/null +++ b/Universal/Docs/PHP/NoFQNTrueFalseNullStandard.xml @@ -0,0 +1,27 @@ + + + + + + + + null; + +if ($something === false) {} + ]]> + + + \null; + +if ($something === \false) {} + ]]> + + + diff --git a/Universal/Sniffs/PHP/NoFQNTrueFalseNullSniff.php b/Universal/Sniffs/PHP/NoFQNTrueFalseNullSniff.php new file mode 100644 index 00000000..6aa3b188 --- /dev/null +++ b/Universal/Sniffs/PHP/NoFQNTrueFalseNullSniff.php @@ -0,0 +1,92 @@ + + */ + public function register() + { + return [ + // PHP < 8.0. + \T_TRUE, + \T_FALSE, + \T_NULL, + + // PHP >= 8.0. + \T_STRING, + ]; + } + + /** + * Processes this test, when one of its tokens is encountered. + * + * @since 1.3.0 + * + * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned. + * @param int $stackPtr The position of the current token + * in the stack passed in $tokens. + * + * @return void + */ + public function process(File $phpcsFile, $stackPtr) + { + $tokens = $phpcsFile->getTokens(); + $content = $tokens[$stackPtr]['content']; + $contentLC = \strtolower($content); + + if ($contentLC !== 'true' && $contentLC !== 'false' && $contentLC !== 'null') { + return; + } + + $prev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$prev]['code'] !== \T_NS_SEPARATOR) { + return; + } + + $prevPrev = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($prev - 1), null, true); + if ($tokens[$prevPrev]['code'] === \T_STRING || $tokens[$prevPrev]['code'] === \T_NAMESPACE) { + return; + } + + $next = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($tokens[$next]['code'] === \T_NS_SEPARATOR) { + return; + } + + $fix = $phpcsFile->addFixableError( + 'The special PHP constant "%s" should not be fully qualified.', + $prev, + 'Found', + [$contentLC] + ); + + if ($fix === true) { + $phpcsFile->fixer->replaceToken($prev, ''); + } + } +} diff --git a/Universal/Tests/PHP/NoFQNTrueFalseNullUnitTest.inc b/Universal/Tests/PHP/NoFQNTrueFalseNullUnitTest.inc new file mode 100644 index 00000000..a537a293 --- /dev/null +++ b/Universal/Tests/PHP/NoFQNTrueFalseNullUnitTest.inc @@ -0,0 +1,27 @@ + Key is the line number, value is the number of expected errors. + */ + public function getErrorList() + { + return [ + 13 => 1, + 14 => 1, + 15 => 1, + 17 => 1, + 18 => 1, + 19 => 1, + 22 => 1, + 24 => 2, + 26 => 2, + ]; + } + + /** + * Returns the lines where warnings should occur. + * + * @return array Key is the line number, value is the number of expected warnings. + */ + public function getWarningList() + { + return []; + } +} From eeaa1fe59598b91fcbf5c363b101a73d29cc338f Mon Sep 17 00:00:00 2001 From: jrfnl Date: Mon, 21 Apr 2025 00:35:08 +0200 Subject: [PATCH 25/28] Composer: raise the minimum supported PHPCS version to 3.12.1 ... which is the latest release containing tokenizer changes. Includes removing some code which has become redundant after upstream PR PHPCSStandards/PHP_CodeSniffer 647 was merged (included in 3.11.0). --- README.md | 2 +- .../Sniffs/WhiteSpace/DisallowInlineTabsSniff.php | 10 ---------- composer.json | 2 +- 3 files changed, 2 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c617f8ea..49a21206 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ Minimum Requirements ------------------------------------------- * PHP 5.4 or higher. -* [PHP_CodeSniffer][phpcs-gh] version **3.8.0** or higher. +* [PHP_CodeSniffer][phpcs-gh] version **3.12.1** or higher. * [PHPCSUtils][phpcsutils-gh] version **1.0.9** or higher. diff --git a/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php b/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php index 77d15d00..c94934f1 100644 --- a/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php +++ b/Universal/Sniffs/WhiteSpace/DisallowInlineTabsSniff.php @@ -150,16 +150,6 @@ public function process(File $phpcsFile, $stackPtr) } } - /* - * For "yield from", we should only handle tabs _between_ the keywords (single token), - * not indentation for those situations where the keyword is split in multiple tokens. - */ - if ($tokens[$i]['code'] === \T_YIELD_FROM - && \preg_match('`^yield.+from$`i', $tokens[$i]['content']) !== 1 - ) { - continue; - } - $fix = $phpcsFile->addFixableError( 'Spaces must be used for mid-line alignment; tabs are not allowed', $i, diff --git a/composer.json b/composer.json index 28617b0d..b565df6a 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ }, "require" : { "php" : ">=5.4", - "squizlabs/php_codesniffer" : "^3.8.0", + "squizlabs/php_codesniffer" : "^3.12.1", "phpcsstandards/phpcsutils" : "^1.0.9" }, "require-dev" : { From b031559419b0b154fa03308b8164f2c60701d17d Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 20 Apr 2025 23:47:41 +0200 Subject: [PATCH 26/28] Universal/TypeSeparatorSpacing: add support for PHP 8.2 DNF types PHP 8.2 introduced DNF types, which use parenthesis. This commit adds support to the `Universal.Operators.TypeSeparatorSpacing` sniff to also check the spacing around the parenthesis for DNF types. Notes: * Allows for a new line before the start of a type for function parameters. * Expects one space before the type operator if the type starts with a DNF open parenthesis. * Expects one space after the type operator if the type ends on a DNF close parenthesis. * Includes protection against throwing two errors for the same issue, like when a DNF close parenthesis if followed by a union type operator and there is whitespace between these. Includes tests. Includes updated documentation. --- .../TypeSeparatorSpacingStandard.xml | 18 ++- .../Operators/TypeSeparatorSpacingSniff.php | 105 ++++++++++++++---- .../TypeSeparatorSpacingUnitTest.inc | 32 ++++++ .../TypeSeparatorSpacingUnitTest.inc.fixed | 29 +++++ .../TypeSeparatorSpacingUnitTest.php | 10 ++ 5 files changed, 167 insertions(+), 27 deletions(-) diff --git a/Universal/Docs/Operators/TypeSeparatorSpacingStandard.xml b/Universal/Docs/Operators/TypeSeparatorSpacingStandard.xml index 3d3c328e..58a3b561 100644 --- a/Universal/Docs/Operators/TypeSeparatorSpacingStandard.xml +++ b/Universal/Docs/Operators/TypeSeparatorSpacingStandard.xml @@ -5,25 +5,31 @@ > - + |string $paramA, - TypeA&TypeB $paramB + TypeA&TypeB $paramB, + (TypeA&TypeB)|null $paramC ): int|false {} ]]> - + | string $paramA, - TypeA & TypeB $paramB + TypeA & TypeB $paramB, + ( TypeA&TypeB ) |null $paramC ): int | false {} diff --git a/Universal/Sniffs/Operators/TypeSeparatorSpacingSniff.php b/Universal/Sniffs/Operators/TypeSeparatorSpacingSniff.php index 440ecc86..34d9c476 100644 --- a/Universal/Sniffs/Operators/TypeSeparatorSpacingSniff.php +++ b/Universal/Sniffs/Operators/TypeSeparatorSpacingSniff.php @@ -14,15 +14,31 @@ use PHP_CodeSniffer\Sniffs\Sniff; use PHP_CodeSniffer\Util\Tokens; use PHPCSUtils\Fixers\SpacesFixer; +use PHPCSUtils\Tokens\Collections; /** - * Enforce no space around union type and intersection type separators. + * Enforce spacing rules around union, intersection and DNF type separators. * * @since 1.0.0 + * @since 1.3.0 Support for DNF types. */ final class TypeSeparatorSpacingSniff implements Sniff { + /** + * Tokens this sniff targets. + * + * @since 1.3.0 + * + * @var array + */ + private $targetTokens = [ + \T_TYPE_UNION => \T_TYPE_UNION, + \T_TYPE_INTERSECTION => \T_TYPE_INTERSECTION, + \T_TYPE_OPEN_PARENTHESIS => \T_TYPE_OPEN_PARENTHESIS, + \T_TYPE_CLOSE_PARENTHESIS => \T_TYPE_CLOSE_PARENTHESIS, + ]; + /** * Returns an array of tokens this test wants to listen for. * @@ -32,10 +48,7 @@ final class TypeSeparatorSpacingSniff implements Sniff */ public function register() { - return [ - \T_TYPE_UNION, - \T_TYPE_INTERSECTION, - ]; + return $this->targetTokens; } /** @@ -53,28 +66,78 @@ public function process(File $phpcsFile, $stackPtr) { $tokens = $phpcsFile->getTokens(); - $type = ($tokens[$stackPtr]['code'] === \T_TYPE_UNION) ? 'union' : 'intersection'; - $code = \ucfirst($type) . 'Type'; + $type = 'union'; + $code = 'UnionType'; + if ($tokens[$stackPtr]['code'] === \T_TYPE_INTERSECTION) { + $type = 'intersection'; + $code = 'IntersectionType'; + } elseif ($tokens[$stackPtr]['code'] === \T_TYPE_OPEN_PARENTHESIS) { + $type = 'DNF parenthesis open'; + $code = 'DNFOpen'; + } elseif ($tokens[$stackPtr]['code'] === \T_TYPE_CLOSE_PARENTHESIS) { + $type = 'DNF parenthesis close'; + $code = 'DNFClose'; + } - $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); - SpacesFixer::checkAndFix( - $phpcsFile, - $stackPtr, - $prevNonEmpty, - 0, // Expected spaces. - 'Expected %s before the ' . $type . ' type separator. Found: %s', - $code . 'SpacesBefore', - 'error', - 0, // Severity. - 'Space before ' . $type . ' type separator' - ); + $expectedSpaces = 0; + $prevNonEmpty = $phpcsFile->findPrevious(Tokens::$emptyTokens, ($stackPtr - 1), null, true); + if ($tokens[$stackPtr]['code'] === \T_TYPE_OPEN_PARENTHESIS) { + if ($tokens[$prevNonEmpty]['code'] === \T_COLON + || $tokens[$prevNonEmpty]['code'] === \T_CONST + || isset(Collections::propertyModifierKeywords()[$tokens[$prevNonEmpty]['code']]) === true + ) { + // Start of return type or property/const type. Always demand 1 space. + $expectedSpaces = 1; + } + + if ($tokens[$prevNonEmpty]['code'] === \T_OPEN_PARENTHESIS + || $tokens[$prevNonEmpty]['code'] === \T_COMMA + ) { + // Start of parameter type. Allow new line/indent before. + if ($tokens[$prevNonEmpty]['line'] === $tokens[$stackPtr]['line']) { + $expectedSpaces = 1; + } else { + $expectedSpaces = 'skip'; + } + } + } + + if (isset($this->targetTokens[$tokens[$prevNonEmpty]['code']]) === true) { + // Prevent duplicate errors when there are two adjacent operators. + $expectedSpaces = 'skip'; + } + + if ($expectedSpaces !== 'skip') { + SpacesFixer::checkAndFix( + $phpcsFile, + $stackPtr, + $prevNonEmpty, + $expectedSpaces, + 'Expected %s before the ' . $type . ' type separator. Found: %s', + $code . 'SpacesBefore', + 'error', + 0, // Severity. + 'Space before ' . $type . ' type separator' + ); + } + + $expectedSpaces = 0; + $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); + if ($tokens[$stackPtr]['code'] === \T_TYPE_CLOSE_PARENTHESIS) { + if ($tokens[$nextNonEmpty]['code'] === \T_OPEN_CURLY_BRACKET + || $tokens[$nextNonEmpty]['code'] === \T_VARIABLE + || $tokens[$nextNonEmpty]['code'] === \T_STRING + ) { + // End of return type, parameter or property/const type. Always demand 1 space. + $expectedSpaces = 1; + } + } - $nextNonEmpty = $phpcsFile->findNext(Tokens::$emptyTokens, ($stackPtr + 1), null, true); SpacesFixer::checkAndFix( $phpcsFile, $stackPtr, $nextNonEmpty, - 0, // Expected spaces. + $expectedSpaces, 'Expected %s after the ' . $type . ' type separator. Found: %s', $code . 'SpacesAfter', 'error', diff --git a/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc b/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc index 530a14a5..ae6d1916 100644 --- a/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc +++ b/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc @@ -36,6 +36,38 @@ $closure = function (TypeA | TypeB $p, TypeA &namespace\TypeB $q): \ $arrow = fn (TypeA | TypeB $p, TypeA & namespace\TypeB $q): string | int => $p * $q; +/* + * PHP 8.2 DNF types. + */ +class DNFTypes { + private const (A&B)|false DNF_CORRECT_START = false; + protected const false|(A&B) DNF_CORRECT_END = false; + public const ( A&B ) |false DNF_INCORRECT_START = false; + final const false| ( A&B ) DNF_INCORRECT_END = false; + + private (A&B)|false $dnfCorrectStart = false; + readonly false|(A&B) $dnfCorrectEnd = false; + static ( A&B ) |false $dnfIncorrectStart = false; + final false| ( A&B ) $dnfIncorrectEnd = false; + + public function DNFCorrect( + (A&B)|false $paramA, (A&B)|false $paramB, + null|(\FQN&\Partially\Qualified) $paramC, + ): (A&B)|(C&D) { + } + + public function DNFIncorrect( + ( A&B ) | false $paramA, (A&B) |false $paramB, + null| ( \FQN&\Partially\Qualified ) + $paramC, + ): ( A &B ) + | + ( C&D ) { + } + + public function DNFIncorrectReturnTypeNoSpace():(A&B)|(C&D){} +} + // Live coding. // This test should be the last test in the file. function foo(int| diff --git a/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc.fixed b/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc.fixed index a1ec0ebb..a86fcc82 100644 --- a/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc.fixed +++ b/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.inc.fixed @@ -32,6 +32,35 @@ $closure = function (TypeA|TypeB $p, TypeA&namespace\TypeB $q): \Fully\Qualified $arrow = fn (TypeA|TypeB $p, TypeA&namespace\TypeB $q): string|int => $p * $q; +/* + * PHP 8.2 DNF types. + */ +class DNFTypes { + private const (A&B)|false DNF_CORRECT_START = false; + protected const false|(A&B) DNF_CORRECT_END = false; + public const (A&B)|false DNF_INCORRECT_START = false; + final const false|(A&B) DNF_INCORRECT_END = false; + + private (A&B)|false $dnfCorrectStart = false; + readonly false|(A&B) $dnfCorrectEnd = false; + static (A&B)|false $dnfIncorrectStart = false; + final false|(A&B) $dnfIncorrectEnd = false; + + public function DNFCorrect( + (A&B)|false $paramA, (A&B)|false $paramB, + null|(\FQN&\Partially\Qualified) $paramC, + ): (A&B)|(C&D) { + } + + public function DNFIncorrect( + (A&B)|false $paramA, (A&B)|false $paramB, + null|(\FQN&\Partially\Qualified) $paramC, + ): (A&B)|(C&D) { + } + + public function DNFIncorrectReturnTypeNoSpace(): (A&B)|(C&D) {} +} + // Live coding. // This test should be the last test in the file. function foo(int| diff --git a/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.php b/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.php index 76c2ad7d..e42fb6aa 100644 --- a/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.php +++ b/Universal/Tests/Operators/TypeSeparatorSpacingUnitTest.php @@ -38,6 +38,16 @@ public function getErrorList() 33 => 1, 35 => 5, 37 => 6, + 45 => 4, + 46 => 4, + 50 => 4, + 51 => 4, + 60 => 6, + 61 => 4, + 63 => 5, + 64 => 1, + 65 => 3, + 68 => 2, ]; } From 721cd8959e960c1c74675a0836df6fa01f5bb038 Mon Sep 17 00:00:00 2001 From: jrfnl Date: Sun, 20 Apr 2025 21:46:52 +0200 Subject: [PATCH 27/28] Changelog and readme updates for PHPCSExtra 1.3.0 --- CHANGELOG.md | 45 ++++++++++++++++++++++++++++++++++++++------- README.md | 12 ++++++++++-- 2 files changed, 48 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c087ded..b993a34b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,35 @@ This projects adheres to [Keep a CHANGELOG](https://keepachangelog.com/) and use _Nothing yet._ + +## [1.3.0] - 2025-04-21 + +### Added + +#### Universal + +* :wrench: :books: New `Universal.PHP.NoFQNTrueFalseNull` sniff to forbid using `true`, `false` and `null` as fully qualified constants. Thanks [@rodrigoprimo] for reviewing. [#327] +* `Universal.Operators.TypeSeparatorSpacing`: support for checking the spacing around the parenetheses used in PHP 8.2+ DNF types. [#329] + +### Changed + +#### Universal + +* The `Universal.WhiteSpace.DisallowInlineTabs` sniff will now also check for inline tabs in heredoc/nowdoc openers and between the `yield` and `from` keywords. [#320] + +#### Other + +* Composer: The minimum `PHP_CodeSniffer` requirement has been updated to `^3.12.1` (was `^3.8.0`). [#330] +* Developer happiness: prevent creating a `composer.lock` file. Thanks [@fredden]! [#307] +* Various housekeeping, including improvements to the documentation and tests. + +[#307]: https://github.com/PHPCSStandards/PHPCSExtra/pull/307 +[#320]: https://github.com/PHPCSStandards/PHPCSExtra/pull/320 +[#327]: https://github.com/PHPCSStandards/PHPCSExtra/pull/327 +[#329]: https://github.com/PHPCSStandards/PHPCSExtra/pull/329 +[#330]: https://github.com/PHPCSStandards/PHPCSExtra/pull/330 + + ## [1.2.1] - 2023-12-08 ### Changed @@ -567,6 +596,7 @@ This initial alpha release contains the following sniffs: [php_version-config]: https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki/Configuration-Options#setting-the-php-version [Unreleased]: https://github.com/PHPCSStandards/PHPCSExtra/compare/stable...HEAD +[1.3.0]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.2.1...1.3.0 [1.2.1]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.2.0...1.2.1 [1.2.0]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.1.2...1.2.0 [1.1.2]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.1.1...1.1.2 @@ -581,10 +611,11 @@ This initial alpha release contains the following sniffs: [1.0.0-alpha3]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.0-alpha2...1.0.0-alpha3 [1.0.0-alpha2]: https://github.com/PHPCSStandards/PHPCSExtra/compare/1.0.0-alpha1...1.0.0-alpha2 -[@anomiex]: https://github.com/anomiex -[@derickr]: https://github.com/derickr -[@diedexx]: https://github.com/diedexx -[@fredden]: https://github.com/fredden -[@GaryJones]: https://github.com/GaryJones -[@stronk7]: https://github.com/stronk7 -[@szepeviktor]: https://github.com/szepeviktor +[@anomiex]: https://github.com/anomiex +[@derickr]: https://github.com/derickr +[@diedexx]: https://github.com/diedexx +[@fredden]: https://github.com/fredden +[@GaryJones]: https://github.com/GaryJones +[@rodrigoprimo]: https://github.com/rodrigoprimo +[@stronk7]: https://github.com/stronk7 +[@szepeviktor]: https://github.com/szepeviktor diff --git a/README.md b/README.md index 49a21206..df37064d 100644 --- a/README.md +++ b/README.md @@ -403,14 +403,22 @@ This is considered a **_risky_ fixer**. #### `Universal.Operators.TypeSeparatorSpacing` :wrench: :bar_chart: :books: -Enforce no spaces around the union type and intersection type operators. +Enforce spacing rules around the union, intersection and DNF type operators. +* No space on either side of a union or intersection type operator. +* No space on the inside of DNF type parenthesis or before/after if the previous/next "thing" is part of the type. +* One space before a DNF open parenthesis when it is at the start of a type. +* One space after a DNF close parenthesis when it is at the end of a type. -The available error codes are: `UnionTypeSpacesBefore`, `UnionTypeSpacesAfter`, `IntersectionTypeSpacesBefore`, `IntersectionTypeSpacesAfter`. +The available error codes are: `UnionTypeSpacesBefore`, `UnionTypeSpacesAfter`, `IntersectionTypeSpacesBefore`, `IntersectionTypeSpacesAfter`, `DNFOpenSpacesBefore`, `DNFOpenSpacesAfter`, `DNFCloseTypeSpacesBefore`, `DNFCloseTypeSpacesAfter`. #### `Universal.PHP.LowercasePHPTag` :wrench: :bar_chart: :books: Enforces that the "PHP" in a PHP open tag is lowercase. +#### `Universal.PHP.NoFQNTrueFalseNull` :wrench: :books: + +Forbids using `true`, `false` and `null` as fully qualified constants. + #### `Universal.PHP.OneStatementInShortEchoTag` :wrench: :books: Disallow short open echo tags ` Date: Mon, 21 Apr 2025 01:24:04 +0200 Subject: [PATCH 28/28] Docs: fix typo --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b993a34b..c1cf7625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,7 +22,7 @@ _Nothing yet._ #### Universal * :wrench: :books: New `Universal.PHP.NoFQNTrueFalseNull` sniff to forbid using `true`, `false` and `null` as fully qualified constants. Thanks [@rodrigoprimo] for reviewing. [#327] -* `Universal.Operators.TypeSeparatorSpacing`: support for checking the spacing around the parenetheses used in PHP 8.2+ DNF types. [#329] +* `Universal.Operators.TypeSeparatorSpacing`: support for checking the spacing around the parentheses used in PHP 8.2+ DNF types. [#329] ### Changed