Browse Source

feature #3454 Add StringLineEndingFixer (iluuu1994, SpacePossum, keradus, julienfalque)

This PR was squashed before being merged into the 2.11-dev branch (closes #3454).

Discussion
----------

Add StringLineEndingFixer

Closes #3452
Closes #2224

Commits
-------

86c4a886 Add StringLineEndingFixer
Dariusz Ruminski 7 years ago
parent
commit
d668ac357b

+ 1 - 0
.php_cs.dist

@@ -54,6 +54,7 @@ $config = PhpCsFixer\Config::create()
         'single_line_comment_style' => true,
         'strict_comparison' => true,
         'strict_param' => true,
+        'string_line_ending' => true,
         'yoda_style' => true,
     ])
     ->setFinder(

+ 6 - 0
README.rst

@@ -1441,6 +1441,12 @@ Choose from the list of available rules:
 
   *Risky rule: risky when the fixed function is overridden or if the code relies on non-strict usage.*
 
+* **string_line_ending**
+
+  All multi-line strings must use correct line ending.
+
+  *Risky rule: changing the line endings of multi-line strings might affect string comparisons and outputs.*
+
 * **switch_case_semicolon_to_colon** [@PSR2, @Symfony]
 
   A case should be followed by a colon and not a semicolon.

+ 84 - 0
src/Fixer/StringNotation/StringLineEndingFixer.php

@@ -0,0 +1,84 @@
+<?php
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\Fixer\StringNotation;
+
+use PhpCsFixer\AbstractFixer;
+use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
+use PhpCsFixer\FixerDefinition\CodeSample;
+use PhpCsFixer\FixerDefinition\FixerDefinition;
+use PhpCsFixer\Tokenizer\Token;
+use PhpCsFixer\Tokenizer\Tokens;
+
+/**
+ * Fixes the line endings in multi-line strings.
+ *
+ * @author Ilija Tovilo <ilija.tovilo@me.com>
+ */
+final class StringLineEndingFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
+{
+    /**
+     * {@inheritdoc}
+     */
+    public function isCandidate(Tokens $tokens)
+    {
+        return $tokens->isAnyTokenKindsFound([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE]);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function isRisky()
+    {
+        return true;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDefinition()
+    {
+        return new FixerDefinition(
+            'All multi-line strings must use correct line ending.',
+            [
+                new CodeSample(
+                    "<?php \$a = 'my\r\nmulti\nline\r\nstring';\r\n"
+                ),
+            ],
+            null,
+            'Changing the line endings of multi-line strings might affect string comparisons and outputs.'
+        );
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function applyFix(\SplFileInfo $file, Tokens $tokens)
+    {
+        $ending = $this->whitespacesConfig->getLineEnding();
+
+        foreach ($tokens as $tokenIndex => $token) {
+            if (!$token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE])) {
+                continue;
+            }
+
+            $tokens[$tokenIndex] = new Token([
+                $token->getId(),
+                preg_replace(
+                    '#\R#u',
+                    $ending,
+                    $token->getContent()
+                ),
+            ]);
+        }
+    }
+}

+ 92 - 0
tests/Fixer/StringNotation/StringLineEndingFixerTest.php

@@ -0,0 +1,92 @@
+<?php
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\Tests\Fixer\StringNotation;
+
+use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
+use PhpCsFixer\WhitespacesFixerConfig;
+
+/**
+ * @author Ilija Tovilo <ilija.tovilo@me.com>
+ *
+ * @internal
+ *
+ * @covers \PhpCsFixer\Fixer\StringNotation\StringLineEndingFixer
+ */
+final class StringLineEndingFixerTest extends AbstractFixerTestCase
+{
+    /**
+     * @param string      $expected
+     * @param null|string $input
+     *
+     * @dataProvider provideFixCases
+     */
+    public function testFix($expected, $input = null)
+    {
+        $this->doTest($expected, $input);
+    }
+
+    public function provideFixCases()
+    {
+        $heredocTemplate = "<?php\n\$a=\n<<<EOT\n%s\n\nEOT;\n";
+        $nowdocTemplate = "<?php\n\$a=\n<<<'EOT'\n%s\n\nEOT;\n";
+        $input = '/**
+* @SWG\Get(
+*     path="/api/v0/cards",
+*     operationId="listCards",
+*     tags={"Банковские карты"},
+*     summary="Возвращает список банковских карт."
+*  )
+*/';
+
+        return [
+            [
+                "<?php \$a = 'my\nmulti\nline\nstring';\r\n",
+                "<?php \$a = 'my\r\nmulti\nline\r\nstring';\r\n",
+            ],
+            [
+                "<?php \$a = \"my\nmulti\nline\nstring\";\r\n",
+                "<?php \$a = \"my\r\nmulti\nline\r\nstring\";\r\n",
+            ],
+            [
+                "<?php \$a = \"my\nmulti\nline\nstring\nwith\n\$b\ninterpolation\";\r\n",
+                "<?php \$a = \"my\r\nmulti\nline\r\nstring\nwith\r\n\$b\ninterpolation\";\r\n",
+            ],
+            [
+                sprintf($heredocTemplate, $input),
+                sprintf($heredocTemplate, str_replace("\n", "\r", $input)),
+            ],
+            [
+                sprintf($heredocTemplate, $input),
+                sprintf($heredocTemplate, str_replace("\n", "\r\n", $input)),
+            ],
+            [
+                sprintf($nowdocTemplate, $input),
+                sprintf($nowdocTemplate, str_replace("\n", "\r", $input)),
+            ],
+            [
+                sprintf($nowdocTemplate, $input),
+                sprintf($nowdocTemplate, str_replace("\n", "\r\n", $input)),
+            ],
+        ];
+    }
+
+    public function testWithDifferentLineEndingConfiguration()
+    {
+        $this->fixer->setWhitespacesConfig(new WhitespacesFixerConfig("\t", "\r\n"));
+
+        $this->doTest(
+            "<?php \$a = 'my\r\nmulti\r\nline\r\nstring';",
+            "<?php \$a = 'my\nmulti\nline\nstring';"
+        );
+    }
+}