diff --git a/InpsydeTemplates/Sniffs/Formatting/TrailingSemicolonSniff.php b/InpsydeTemplates/Sniffs/Formatting/TrailingSemicolonSniff.php new file mode 100644 index 0000000..caa7a96 --- /dev/null +++ b/InpsydeTemplates/Sniffs/Formatting/TrailingSemicolonSniff.php @@ -0,0 +1,109 @@ + + */ + public function register(): array + { + return [ + T_SEMICOLON, + ]; + } + + /** + * @param File $phpcsFile + * @param int $stackPtr + * + * phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration + */ + public function process(File $phpcsFile, $stackPtr): void + { + // phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration + + /** @var array $tokens */ + $tokens = $phpcsFile->getTokens(); + $currentLine = $tokens[$stackPtr]['line']; + + $nextNonEmptyPosition = $phpcsFile->findNext( + Tokens::$emptyTokens, + ($stackPtr + 1), + null, + true + ); + + if (!is_int($nextNonEmptyPosition) || !isset($tokens[$nextNonEmptyPosition])) { + return; + } + + $nextNonEmptyToken = $tokens[$nextNonEmptyPosition]; + + if ($nextNonEmptyToken['line'] !== $currentLine) { + return; + } + + if ($nextNonEmptyToken['code'] !== T_CLOSE_TAG) { + return; + } + + $message = sprintf('Trailing semicolon found in line %d.', $currentLine); + + if ($phpcsFile->addFixableWarning($message, $stackPtr, 'Found')) { + $this->fix($stackPtr, $phpcsFile); + } + } + + /** + * @param int $position + * @param File $file + */ + private function fix(int $position, File $file): void + { + $fixer = $file->fixer; + $fixer->beginChangeset(); + + $fixer->replaceToken($position, ''); + + $fixer->endChangeset(); + } +} diff --git a/InpsydeTemplates/ruleset.xml b/InpsydeTemplates/ruleset.xml new file mode 100644 index 0000000..098918e --- /dev/null +++ b/InpsydeTemplates/ruleset.xml @@ -0,0 +1,10 @@ + + + + Coding standards for PHP templates. + + + + + + diff --git a/README.md b/README.md index 7cc6a65..9938325 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,40 @@ For **notes and configuration** see [`/inpsyde-custom-sniffs.md`](/inpsyde-custo ------------- +## Template Rules + +The `InpsydeTemplates` ruleset extends the standard `Inpsyde` ruleset with some template-specific +sniffs while disabling some rules that are not useful in templating context. + +The recommended way to use the `InpsydeTemplates` ruleset is as follows: + +```xml + + ./src/ + ./tests + ./templates + ./views + + + */templates/* + */views/* + + + + */templates/* + */views/* + + +``` +The following `Inpsyde` rules are disabled: +* `NoElse` + +The following templates-specific rules are available: + +| Sniff name | Description | Has Config | Auto-Fixable | +|:--------------------|:--------------------------------------------------|:----------:|:------------:| +| `TrailingSemicolon` | Remove trailing semicolon before closing PHP tag. | | ✓ | + # Removing or Disabling Rules ## Rules Tree diff --git a/tests/bootstrap.php b/tests/bootstrap.php index d1ec1a4..ea8ee05 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -35,7 +35,7 @@ die('Please install via Composer before running tests.'); } -putenv("SNIFFS_PATH={$libDir}/Inpsyde/Sniffs"); +putenv("LIB_PATH={$libDir}"); putenv('SNIFFS_NAMESPACE=Inpsyde\\Sniffs'); putenv("FIXTURES_PATH={$testsDir}/fixtures"); diff --git a/tests/cases/FixturesTest.php b/tests/cases/FixturesTest.php index d8d7631..1dfab1b 100644 --- a/tests/cases/FixturesTest.php +++ b/tests/cases/FixturesTest.php @@ -209,24 +209,36 @@ private function createPhpcsForFixture( array $properties ): File { - $sniffFile = str_replace('.', '/', "{$sniffName}Sniff"); - $sniffPath = getenv('SNIFFS_PATH') . "/{$sniffFile}.php"; + $sniffFile = $this->buildSniffFile($sniffName); + $sniffPath = getenv('LIB_PATH') . "/{$sniffFile}.php"; if (!file_exists($sniffPath) || !is_readable($sniffPath)) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped throw new Exception("Non-existent of unreadable sniff file '{$sniffPath}' found."); } + $standard = strtok($sniffName, '.'); $config = new Config(); - $config->standards = [dirname(getenv('SNIFFS_PATH'))]; - $config->sniffs = ["Inpsyde.{$sniffName}"]; + $config->standards = [getenv('LIB_PATH') . "/{$standard}"]; + $config->sniffs = [$sniffName]; $ruleset = new Ruleset($config); - $baseSniffNamespace = getenv('SNIFFS_NAMESPACE'); $sniffFqn = str_replace('/', '\\', $sniffFile); foreach ($properties as $name => $value) { - $ruleset->setSniffProperty("{$baseSniffNamespace}\\{$sniffFqn}", $name, $value); + $ruleset->setSniffProperty( + $sniffFqn, + $name, + ['scope' => 'sniff', 'value' => $value], + ); } return new LocalFile($fixtureFile, $ruleset, $config); } + + private function buildSniffFile(string $sniffName): string + { + $parts = explode('.', $sniffName); + array_splice($parts, 1, 0, 'Sniffs'); + + return implode('/', $parts) . 'Sniff'; + } } diff --git a/tests/fixtures/Psr4Fixture.php b/tests/fixtures/Psr4Fixture.php index acaec22..f3b1f60 100644 --- a/tests/fixtures/Psr4Fixture.php +++ b/tests/fixtures/Psr4Fixture.php @@ -1,5 +1,5 @@
diff --git a/tests/fixtures/element-name-minimal-length.php b/tests/fixtures/element-name-minimal-length.php index 350ddc4..cc36ab0 100644 --- a/tests/fixtures/element-name-minimal-length.php +++ b/tests/fixtures/element-name-minimal-length.php @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/tests/fixtures/forbidden-public-property.php b/tests/fixtures/forbidden-public-property.php index 8c0a65d..8d6de37 100644 --- a/tests/fixtures/forbidden-public-property.php +++ b/tests/fixtures/forbidden-public-property.php @@ -1,5 +1,5 @@ @@ -117,4 +117,3 @@ function longComment() {
- diff --git a/tests/fixtures/nesting-level.php b/tests/fixtures/nesting-level.php index d5dc871..669f30c 100644 --- a/tests/fixtures/nesting-level.php +++ b/tests/fixtures/nesting-level.php @@ -1,5 +1,5 @@ + + + + + + + + + + + +
+ + +
+ +