diff --git a/src/WebimpressCodingStandard/Sniffs/Arrays/DoubleArrowSniff.php b/src/WebimpressCodingStandard/Sniffs/Arrays/DoubleArrowSniff.php index cfa778c1..8f60ca66 100644 --- a/src/WebimpressCodingStandard/Sniffs/Arrays/DoubleArrowSniff.php +++ b/src/WebimpressCodingStandard/Sniffs/Arrays/DoubleArrowSniff.php @@ -6,7 +6,6 @@ use PHP_CodeSniffer\Files\File; use PHP_CodeSniffer\Sniffs\AbstractArraySniff; -use PHP_CodeSniffer\Util\Common; use PHP_CodeSniffer\Util\Tokens; use WebimpressCodingStandard\Helper\ArrayTrait; @@ -38,6 +37,14 @@ class DoubleArrowSniff extends AbstractArraySniff */ public $maxPadding = 1; + /** + * Whether array arrows which are in new lines should be ignored when + * aligning array arrows (when $maxPadding property is > 1). + * + * @var bool + */ + public $ignoreNewLineArrayArrow = true; + /** * Processes a single-line array definition. * @@ -108,6 +115,8 @@ protected function processMultiLineArray($phpcsFile, $stackPtr, $arrayStart, $ar $index = $tokens[$data['index_end']]; if ($index['line'] === $arrow['line']) { $this->checkSpace($phpcsFile, $data, $spaces[$k] ?? 1); + } elseif (! $this->ignoreNewLineArrayArrow && $index['line'] < $arrow['line']) { + $this->checkSpace($phpcsFile, $data, $spaces[$k] ?? 0); } } } @@ -120,6 +129,8 @@ private function calculateExpectedSpaces(File $phpcsFile, array $indices) : arra $tokens = $phpcsFile->getTokens(); + $newLineArrow = []; + $chars = []; foreach ($indices as $k => $data) { if (! isset($data['arrow'])) { @@ -130,10 +141,14 @@ private function calculateExpectedSpaces(File $phpcsFile, array $indices) : arra $index = $tokens[$data['index_end']]; if ($arrow['line'] !== $index['line']) { + if (! $this->ignoreNewLineArrayArrow) { + $newLineArrow[$k] = true; + $chars[$k] = $index['column'] - 1; + } continue; } - $chars[$k] = $index['column'] + $index['length'] - 1; + $chars[$k] = $index['column'] + $index['length']; } $res = []; @@ -192,7 +207,7 @@ private function calculateExpectedSpaces(File $phpcsFile, array $indices) : arra } } - $spaces[$k] = $max - $length + 1; + $spaces[$k] = isset($newLineArrow[$k]) ? $max : $max - $length + 1; } return $spaces; @@ -204,17 +219,33 @@ private function checkSpace(File $phpcsFile, array $element, int $expectedSpaces $space = $tokens[$element['arrow'] - 1]; $expected = str_repeat(' ', $expectedSpaces); - if ($space['code'] === T_WHITESPACE && $space['content'] !== $expected) { - $error = 'Expected "%s" before "=>"; "%s" found'; + if ($space['code'] === T_WHITESPACE + && $space['line'] === $tokens[$element['arrow']]['line'] + && $space['content'] !== $expected + ) { + $error = 'Expected %s before double arrow; %d found'; $data = [ - Common::prepareForOutput($expected), - Common::prepareForOutput($space['content']), + $expectedSpaces === 1 ? '1 space' : $expectedSpaces . ' spaces', + $space['length'], ]; $fix = $phpcsFile->addFixableError($error, $element['arrow'], 'SpacesBefore', $data); if ($fix) { $phpcsFile->fixer->replaceToken($element['arrow'] - 1, $expected); } + } elseif ($expected !== '' + && ($space['code'] !== T_WHITESPACE + || $space['line'] !== $tokens[$element['arrow']]['line']) + ) { + $error = 'Expected %s before double arrow; 0 found'; + $data = [ + $expectedSpaces === 1 ? '1 space' : $expectedSpaces . ' spaces', + ]; + $fix = $phpcsFile->addFixableError($error, $element['arrow'], 'SpacesBefore', $data); + + if ($fix) { + $phpcsFile->fixer->addContentBefore($element['arrow'], $expected); + } } } } diff --git a/src/WebimpressCodingStandard/Sniffs/WhiteSpace/ScopeIndentSniff.php b/src/WebimpressCodingStandard/Sniffs/WhiteSpace/ScopeIndentSniff.php index 3d2fc1bc..71aea6e1 100644 --- a/src/WebimpressCodingStandard/Sniffs/WhiteSpace/ScopeIndentSniff.php +++ b/src/WebimpressCodingStandard/Sniffs/WhiteSpace/ScopeIndentSniff.php @@ -39,6 +39,7 @@ use const T_CONSTANT_ENCAPSED_STRING; use const T_CONTINUE; use const T_DOC_COMMENT_OPEN_TAG; +use const T_DOUBLE_ARROW; use const T_DOUBLE_QUOTED_STRING; use const T_ECHO; use const T_ELSEIF; @@ -87,6 +88,15 @@ class ScopeIndentSniff implements Sniff */ public $alignObjectOperators = true; + /** + * Ignore alignment of array arrows which are at the beginning of new line. + * If set to true, other sniff should check alignment of these arrows + * - for example WebimpressCodingStandard.Arrays.DoubleArrow + * + * @var bool + */ + public $ignoreNewLineArrayArrow = false; + /** * @var int[] */ @@ -740,6 +750,8 @@ public function process(File $phpcsFile, $stackPtr) $expectedIndent += $this->indent; } } + } elseif ($this->ignoreNewLineArrayArrow && $tokens[$next]['code'] === T_DOUBLE_ARROW) { + continue; } $expectedIndent += $extraIndent; diff --git a/test/Integration/AlignOperators.php b/test/Integration/AlignOperators.php new file mode 100644 index 00000000..4b811337 --- /dev/null +++ b/test/Integration/AlignOperators.php @@ -0,0 +1,10 @@ + 'value', +'k' +=> 'value', +'k1' => 'value', +]; diff --git a/test/Integration/AlignOperators.php.fixed b/test/Integration/AlignOperators.php.fixed new file mode 100644 index 00000000..5a43ab2b --- /dev/null +++ b/test/Integration/AlignOperators.php.fixed @@ -0,0 +1,10 @@ + 'value', + 'k' + => 'value', + 'k1' => 'value', +]; diff --git a/test/Integration/AlignOperators.xml b/test/Integration/AlignOperators.xml new file mode 100644 index 00000000..ecb61db1 --- /dev/null +++ b/test/Integration/AlignOperators.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/IntegrationTest.php b/test/IntegrationTest.php index b2d4b24e..b53f0c6e 100644 --- a/test/IntegrationTest.php +++ b/test/IntegrationTest.php @@ -10,8 +10,10 @@ use function basename; use function copy; use function exec; +use function file_exists; use function glob; use function implode; +use function str_replace; use function sys_get_temp_dir; use function tempnam; @@ -25,7 +27,10 @@ public function testIntegration(string $file) : void $tmpname = tempnam(sys_get_temp_dir(), '') . '_' . basename($file); copy($file, $tmpname); - exec('vendor/bin/phpcbf ' . $tmpname, $output, $returnVal); + $rulesetFile = str_replace('.php', '.xml', $file); + $options = file_exists($rulesetFile) ? ' --standard=' . $rulesetFile : ''; + + exec('vendor/bin/phpcbf ' . $tmpname . $options, $output, $returnVal); self::assertSame(1, $returnVal, 'Output: ' . "\n" . implode("\n", $output)); self::assertFileEquals($file . '.fixed', $tmpname); diff --git a/test/Sniffs/Arrays/DoubleArrowUnitTest.1.inc.fixed b/test/Sniffs/Arrays/DoubleArrowUnitTest.1.inc.fixed index 399a12cf..48f9fdec 100644 --- a/test/Sniffs/Arrays/DoubleArrowUnitTest.1.inc.fixed +++ b/test/Sniffs/Arrays/DoubleArrowUnitTest.1.inc.fixed @@ -1,7 +1,7 @@ 'b', 'c'=>'d']; +$s = ['a' => 'b', 'c' =>'d']; $m = [ 'a' => 'b', diff --git a/test/Sniffs/Arrays/DoubleArrowUnitTest.2.inc b/test/Sniffs/Arrays/DoubleArrowUnitTest.2.inc new file mode 100644 index 00000000..89704aed --- /dev/null +++ b/test/Sniffs/Arrays/DoubleArrowUnitTest.2.inc @@ -0,0 +1,33 @@ + 'bar', + 'very-long-key' + => 'value', + 'foo-bar' => 'baz', +]; + +$x = [ + '1' => 1, + '1_____' => 1, + '1__' => 1, + '2_____________________________________________________' => 2, + '3' => 3, + '3____' => 3, + '3_' => 3, + '3_______' => 3, + '3____________________' => 3, + '3___' + => 'value in new line does not break aligning group', + '3__' => 3, + '3_____' => 3, + 'value without index breaks aligning group', + '4___' => 4, + '4' => 4, + + '5_' => 'empty line breaks alignment group', + // comment + '6_____' => 'comment breaks alignment group', +]; diff --git a/test/Sniffs/Arrays/DoubleArrowUnitTest.2.inc.fixed b/test/Sniffs/Arrays/DoubleArrowUnitTest.2.inc.fixed new file mode 100644 index 00000000..cedc69c2 --- /dev/null +++ b/test/Sniffs/Arrays/DoubleArrowUnitTest.2.inc.fixed @@ -0,0 +1,33 @@ + 'bar', + 'very-long-key' + => 'value', + 'foo-bar' => 'baz', +]; + +$x = [ + '1' => 1, + '1_____' => 1, + '1__' => 1, + '2_____________________________________________________' => 2, + '3' => 3, + '3____' => 3, + '3_' => 3, + '3_______' => 3, + '3____________________' => 3, + '3___' + => 'value in new line does not break aligning group', + '3__' => 3, + '3_____' => 3, + 'value without index breaks aligning group', + '4___' => 4, + '4' => 4, + + '5_' => 'empty line breaks alignment group', + // comment + '6_____' => 'comment breaks alignment group', +]; diff --git a/test/Sniffs/Arrays/DoubleArrowUnitTest.inc b/test/Sniffs/Arrays/DoubleArrowUnitTest.inc index 2ae52b8a..68b63579 100644 --- a/test/Sniffs/Arrays/DoubleArrowUnitTest.inc +++ b/test/Sniffs/Arrays/DoubleArrowUnitTest.inc @@ -1,4 +1,6 @@ - 'b', 'c'=>'d']; $m = [ diff --git a/test/Sniffs/Arrays/DoubleArrowUnitTest.inc.fixed b/test/Sniffs/Arrays/DoubleArrowUnitTest.inc.fixed index 96d2849e..1c4862af 100644 --- a/test/Sniffs/Arrays/DoubleArrowUnitTest.inc.fixed +++ b/test/Sniffs/Arrays/DoubleArrowUnitTest.inc.fixed @@ -1,6 +1,8 @@ - 'b', 'c'=>'d']; +$s = ['a' => 'b', 'c' =>'d']; $m = [ 'a' => 'b', diff --git a/test/Sniffs/Arrays/DoubleArrowUnitTest.php b/test/Sniffs/Arrays/DoubleArrowUnitTest.php index 184784ae..4b9f3e8b 100644 --- a/test/Sniffs/Arrays/DoubleArrowUnitTest.php +++ b/test/Sniffs/Arrays/DoubleArrowUnitTest.php @@ -13,7 +13,7 @@ protected function getErrorList(string $testFile = '') : array switch ($testFile) { case 'DoubleArrowUnitTest.1.inc': return [ - 4 => 1, + 4 => 2, 6 => 1, 10 => 1, 14 => 1, @@ -41,15 +41,31 @@ protected function getErrorList(string $testFile = '') : array 59 => 1, 61 => 1, ]; + case 'DoubleArrowUnitTest.2.inc': + return [ + 6 => 1, + 8 => 1, + 13 => 1, + 15 => 1, + 17 => 1, + 18 => 1, + 19 => 1, + 20 => 1, + 23 => 1, + 24 => 1, + 25 => 1, + 28 => 1, + 30 => 1, + ]; } return [ - 3 => 1, - 5 => 1, - 9 => 1, - 13 => 1, - 14 => 1, + 5 => 2, + 7 => 1, + 11 => 1, + 15 => 1, 16 => 1, + 18 => 1, ]; }