Skip to content

Commit

Permalink
Introduce SingleQuoteRule (#212)
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet authored Apr 26, 2024
1 parent 6b75478 commit d3577e9
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 0 deletions.
2 changes: 2 additions & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- **OperatorSpacingRule**: ensures there is one space before and after an operator except for `..`.
- **PunctuationSpacingRule**: ensures there is no space before and after a punctuation except for `:` and `,` (configurable).
- **TrailingCommaSingleLineRule**: ensures that single-line arrays, objects and argument lists do not have a trailing comma.
- **SingleQuoteRule**: ensures that strings use single quotes when possible (configurable).
- **BlankEOFRule**: ensures that files ends with one blank line.
- **EmptyLinesRule**: ensures that 2 empty lines do not follow each other.
- **IndentRule**: ensures that files are not indented with tabs (configurable).
Expand Down Expand Up @@ -55,6 +56,7 @@ new TwigCsFixer\Rules\Whitespace\IndentRule(3);
- BlockNameSpacingRule
- EmptyLinesRule
- IndentRule
- SingleQuoteRule
- TrailingCommaSingleLineRule
- TrailingSpaceRule

Expand Down
55 changes: 55 additions & 0 deletions src/Rules/String/SingleQuoteRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace TwigCsFixer\Rules\String;

use TwigCsFixer\Rules\AbstractFixableRule;
use TwigCsFixer\Rules\ConfigurableRuleInterface;
use TwigCsFixer\Token\Token;

/**
* Ensures that strings use single quotes when possible.
*/
final class SingleQuoteRule extends AbstractFixableRule implements ConfigurableRuleInterface
{
public function __construct(private bool $skipStringContainingSingleQuote = true)
{
}

public function getConfiguration(): array
{
return [
'skip_string_containing_single_quote' => $this->skipStringContainingSingleQuote,
];
}

protected function process(int $tokenPosition, array $tokens): void
{
$token = $tokens[$tokenPosition];
if (!$this->isTokenMatching($token, Token::STRING_TYPE)) {
return;
}

$content = $token->getValue();
if (
!str_starts_with($content, '"')
|| str_contains($content, '\'') && $this->skipStringContainingSingleQuote
) {
return;
}

$fixer = $this->addFixableError('String should be declared with single quotes.', $token);
if (null === $fixer) {
return;
}

$content = substr($content, 1, -1);
$content = str_replace(
['\\"', '\\#{', '#\\{', '\\\'', '\''],
['"', '#{', '#{', '\'', '\\\''],
$content
);
$fixer->replaceToken($tokenPosition, '\''.$content.'\'');
}
}
2 changes: 2 additions & 0 deletions src/Standard/TwigCsFixer.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use TwigCsFixer\Rules\Delimiter\BlockNameSpacingRule;
use TwigCsFixer\Rules\Punctuation\TrailingCommaSingleLineRule;
use TwigCsFixer\Rules\String\SingleQuoteRule;
use TwigCsFixer\Rules\Whitespace\BlankEOFRule;
use TwigCsFixer\Rules\Whitespace\EmptyLinesRule;
use TwigCsFixer\Rules\Whitespace\IndentRule;
Expand All @@ -24,6 +25,7 @@ public function getRules(): array
new BlockNameSpacingRule(),
new EmptyLinesRule(),
new IndentRule(),
new SingleQuoteRule(),
new TrailingCommaSingleLineRule(),
new TrailingSpaceRule(),
];
Expand Down
11 changes: 11 additions & 0 deletions tests/Rules/String/SimpleQuote/SingleQuoteRuleTest.all.fixed.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'foo'
"foo"

{% set foo = 'foo' %}
{% set foo2 = 'foo' %}
{% set foo3 = '\'foo\'' %}
{% set foo4 = '\'foo\'' %}

{% set foo5 = "#{p.first}" %}
{% set foo6 = '#{p.first}' %}
{% set foo7 = '#{p.first}' %}
11 changes: 11 additions & 0 deletions tests/Rules/String/SimpleQuote/SingleQuoteRuleTest.fixed.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'foo'
"foo"

{% set foo = 'foo' %}
{% set foo2 = 'foo' %}
{% set foo3 = "'foo'" %}
{% set foo4 = "\'foo\'" %}

{% set foo5 = "#{p.first}" %}
{% set foo6 = '#{p.first}' %}
{% set foo7 = '#{p.first}' %}
43 changes: 43 additions & 0 deletions tests/Rules/String/SimpleQuote/SingleQuoteRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php

declare(strict_types=1);

namespace TwigCsFixer\Tests\Rules\String\SimpleQuote;

use TwigCsFixer\Rules\String\SingleQuoteRule;
use TwigCsFixer\Tests\Rules\AbstractRuleTestCase;

class SingleQuoteRuleTest extends AbstractRuleTestCase
{
public function testConfiguration(): void
{
static::assertSame(
['skip_string_containing_single_quote' => true],
(new SingleQuoteRule())->getConfiguration()
);
static::assertSame(
['skip_string_containing_single_quote' => false],
(new SingleQuoteRule(false))->getConfiguration()
);
}

public function testRule(): void
{
$this->checkRule(new SingleQuoteRule(), [
'SingleQuote.Error:5:15' => 'String should be declared with single quotes.',
'SingleQuote.Error:10:15' => 'String should be declared with single quotes.',
'SingleQuote.Error:11:15' => 'String should be declared with single quotes.',
]);
}

public function testRuleWithoutSkippingSingleQuote(): void
{
$this->checkRule(new SingleQuoteRule(false), [
'SingleQuote.Error:5:15' => 'String should be declared with single quotes.',
'SingleQuote.Error:6:15' => 'String should be declared with single quotes.',
'SingleQuote.Error:7:15' => 'String should be declared with single quotes.',
'SingleQuote.Error:10:15' => 'String should be declared with single quotes.',
'SingleQuote.Error:11:15' => 'String should be declared with single quotes.',
], fixedFilePath: __DIR__.'/SingleQuoteRuleTest.all.fixed.twig');
}
}
11 changes: 11 additions & 0 deletions tests/Rules/String/SimpleQuote/SingleQuoteRuleTest.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
'foo'
"foo"

{% set foo = 'foo' %}
{% set foo2 = "foo" %}
{% set foo3 = "'foo'" %}
{% set foo4 = "\'foo\'" %}

{% set foo5 = "#{p.first}" %}
{% set foo6 = "\#{p.first}" %}
{% set foo7 = "#\{p.first}" %}
2 changes: 2 additions & 0 deletions tests/Standard/TwigCsFixerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use TwigCsFixer\Rules\Operator\OperatorSpacingRule;
use TwigCsFixer\Rules\Punctuation\PunctuationSpacingRule;
use TwigCsFixer\Rules\Punctuation\TrailingCommaSingleLineRule;
use TwigCsFixer\Rules\String\SingleQuoteRule;
use TwigCsFixer\Rules\Variable\VariableNameRule;
use TwigCsFixer\Rules\Whitespace\BlankEOFRule;
use TwigCsFixer\Rules\Whitespace\EmptyLinesRule;
Expand All @@ -34,6 +35,7 @@ public function testGetRules(): void
new BlockNameSpacingRule(),
new EmptyLinesRule(),
new IndentRule(),
new SingleQuoteRule(),
new TrailingCommaSingleLineRule(),
new TrailingSpaceRule(),
], $standard->getRules());
Expand Down

0 comments on commit d3577e9

Please sign in to comment.