diff --git a/.editorconfig b/.editorconfig index f7f18227a..b825f7fa4 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,3 +9,6 @@ indent_size = 4 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true + +[tabs.txt] +indent_style = tab diff --git a/config/config.php b/config/config.php index a21f60e51..6af134a8c 100644 --- a/config/config.php +++ b/config/config.php @@ -81,6 +81,4 @@ ]]); $services->set(\PhpParser\PrettyPrinter\Standard::class); - - $parameters->set(Typo3Option::TYPOSCRIPT_INDENT_SIZE, 4); }; diff --git a/src/FileProcessor/TypoScript/TypoScriptFileProcessor.php b/src/FileProcessor/TypoScript/TypoScriptFileProcessor.php index a7f636807..4bde3f12d 100644 --- a/src/FileProcessor/TypoScript/TypoScriptFileProcessor.php +++ b/src/FileProcessor/TypoScript/TypoScriptFileProcessor.php @@ -13,7 +13,6 @@ use Helmich\TypoScriptParser\Parser\Traverser\Traverser; use Helmich\TypoScriptParser\Parser\Traverser\Visitor; use Helmich\TypoScriptParser\Tokenizer\TokenizerException; -use Nette\Utils\Strings; use Rector\ChangesReporting\ValueObjectFactory\FileDiffFactory; use Rector\Core\Application\FileSystem\RemovedAndAddedFilesCollector; use Rector\Core\Configuration\Parameter\ParameterProvider; @@ -32,6 +31,7 @@ use Ssch\TYPO3Rector\Contract\Processor\ConfigurableProcessorInterface; use Ssch\TYPO3Rector\FileProcessor\TypoScript\Collector\RemoveTypoScriptStatementCollector; use Ssch\TYPO3Rector\FileProcessor\TypoScript\Rector\AbstractTypoScriptRector; +use Ssch\TYPO3Rector\ValueObject\Indent; use Symfony\Component\Console\Output\BufferedOutput; use Symplify\SmartFileSystem\SmartFileInfo; use Webmozart\Assert\Assert; @@ -209,20 +209,20 @@ private function processFile(File $file): void return; } - // keep original json format - $tabMatches = Strings::match($file->getFileContent(), "#^\n#"); - $indentStyle = $tabMatches ? 'tab' : 'space'; + // keep original TypoScript format + $indent = Indent::fromFile($file); $prettyPrinterConfiguration = PrettyPrinterConfiguration::create(); $prettyPrinterConfiguration = $prettyPrinterConfiguration->withEmptyLineBreaks(); - if ('tab' === $indentStyle) { - $prettyPrinterConfiguration = $prettyPrinterConfiguration->withTabs(); - } else { + if ($indent->isSpace()) { // default indent - $prettyPrinterConfiguration = $prettyPrinterConfiguration->withSpaceIndentation( - $this->parameterProvider->provideParameter(Typo3Option::TYPOSCRIPT_INDENT_SIZE) - ); + $indentation = $this->parameterProvider->provideParameter( + Typo3Option::TYPOSCRIPT_INDENT_SIZE + ) ?? $indent->length(); + $prettyPrinterConfiguration = $prettyPrinterConfiguration->withSpaceIndentation($indentation); + } else { + $prettyPrinterConfiguration = $prettyPrinterConfiguration->withTabs(); } $prettyPrinterConfiguration = $prettyPrinterConfiguration->withClosingGlobalStatement(); diff --git a/src/FileProcessor/Yaml/Form/FormYamlFileProcessor.php b/src/FileProcessor/Yaml/Form/FormYamlFileProcessor.php index a8f8e354d..ad06b9505 100644 --- a/src/FileProcessor/Yaml/Form/FormYamlFileProcessor.php +++ b/src/FileProcessor/Yaml/Form/FormYamlFileProcessor.php @@ -13,7 +13,7 @@ use Rector\Core\ValueObject\Reporting\FileDiff; use Rector\Parallel\ValueObject\Bridge; use Ssch\TYPO3Rector\Contract\FileProcessor\Yaml\Form\FormYamlRectorInterface; -use Ssch\TYPO3Rector\FileProcessor\Yaml\YamlIndentResolver; +use Ssch\TYPO3Rector\ValueObject\Indent; use Symfony\Component\Yaml\Yaml; use Symplify\SmartFileSystem\SmartFileInfo; @@ -34,11 +34,6 @@ final class FormYamlFileProcessor implements FileProcessorInterface */ private FileDiffFactory $fileDiffFactory; - /** - * @readonly - */ - private YamlIndentResolver $yamlIndentResolver; - /** * @var FormYamlRectorInterface[] * @readonly @@ -51,12 +46,10 @@ final class FormYamlFileProcessor implements FileProcessorInterface public function __construct( CurrentFileProvider $currentFileProvider, FileDiffFactory $fileDiffFactory, - YamlIndentResolver $yamlIndentResolver, array $transformer ) { $this->currentFileProvider = $currentFileProvider; $this->fileDiffFactory = $fileDiffFactory; - $this->yamlIndentResolver = $yamlIndentResolver; $this->transformer = $transformer; } @@ -72,6 +65,8 @@ public function process(File $file, Configuration $configuration): array $this->currentFileProvider->setFile($file); + $indent = Indent::fromFile($file); + $smartFileInfo = new SmartFileInfo($file->getFilePath()); $oldYamlContent = $smartFileInfo->getContents(); $yaml = Yaml::parse($oldYamlContent, Yaml::PARSE_CUSTOM_TAGS); @@ -91,9 +86,7 @@ public function process(File $file, Configuration $configuration): array return $systemErrorsAndFileDiffs; } - $spaceCount = $this->yamlIndentResolver->resolveIndentSpaceCount($oldYamlContent); - - $newFileContent = Yaml::dump($newYaml, 99, $spaceCount); + $newFileContent = Yaml::dump($newYaml, 99, $indent->length()); $file->changeFileContent($newFileContent); $fileDiff = $this->fileDiffFactory->createFileDiff($file, $oldYamlContent, $newFileContent); diff --git a/src/FileProcessor/Yaml/YamlIndentResolver.php b/src/FileProcessor/Yaml/YamlIndentResolver.php deleted file mode 100644 index e4958b322..000000000 --- a/src/FileProcessor/Yaml/YamlIndentResolver.php +++ /dev/null @@ -1,38 +0,0 @@ -\s+)[\w\-]#m'; - - /** - * @var string - */ - private const FIRST_INDENT_KEY = 'first_indent'; - - /** - * @var int - */ - private const DEFAULT_INDENT_SPACE_COUNT = 4; - - public function resolveIndentSpaceCount(string $yamlFileContent): int - { - $firstSpaceMatch = Strings::match(trim($yamlFileContent), self::FIRST_INDENT_REGEX); - if (! isset($firstSpaceMatch[self::FIRST_INDENT_KEY])) { - return self::DEFAULT_INDENT_SPACE_COUNT; - } - - $firstIndent = $firstSpaceMatch[self::FIRST_INDENT_KEY]; - - return substr_count((string) $firstIndent, ' '); - } -} diff --git a/src/ValueObject/Indent.php b/src/ValueObject/Indent.php new file mode 100644 index 000000000..b95799fe5 --- /dev/null +++ b/src/ValueObject/Indent.php @@ -0,0 +1,67 @@ + ' ', + 'tab' => "\t", + ]; + + private string $value; + + private function __construct(string $value) + { + $this->value = $value; + } + + public static function fromFile(File $file): self + { + if (1 === \preg_match('/^(?P( +|\t+)).*/m', $file->getFileContent(), $match)) { + return self::fromString($match['indent']); + } + + return self::fromSizeAndStyle(4, 'space',); + } + + public function toString(): string + { + return $this->value; + } + + public function isSpace(): bool + { + return 1 === \preg_match('/^( +).*/', $this->value); + } + + public function length(): int + { + return strlen($this->value); + } + + private static function fromSizeAndStyle(int $size, string $style): self + { + Assert::greaterThanEq($size, 1); + Assert::keyExists(self::CHARACTERS, $style); + + $value = \str_repeat(self::CHARACTERS[$style], $size); + + return new self($value); + } + + private static function fromString(string $value): self + { + Assert::regex($value, '/^( *|\t+)$/'); + + return new self($value); + } +} diff --git a/tests/FileProcessor/TypoScript/config/configured_rule.php b/tests/FileProcessor/TypoScript/config/configured_rule.php index bfdbb9314..605df2ce5 100644 --- a/tests/FileProcessor/TypoScript/config/configured_rule.php +++ b/tests/FileProcessor/TypoScript/config/configured_rule.php @@ -3,7 +3,6 @@ declare(strict_types=1); use Rector\Config\RectorConfig; -use Ssch\TYPO3Rector\Configuration\Typo3Option; use Ssch\TYPO3Rector\FileProcessor\TypoScript\Conditions\ApplicationContextConditionMatcher; use Ssch\TYPO3Rector\FileProcessor\TypoScript\Conditions\BrowserConditionMatcher; use Ssch\TYPO3Rector\FileProcessor\TypoScript\Conditions\CompatVersionConditionMatcher; @@ -48,7 +47,6 @@ $services->set(VersionConditionMatcher::class); $parameters = $rectorConfig->parameters(); - $parameters->set(Typo3Option::TYPOSCRIPT_INDENT_SIZE, 4); $rectorConfig->rule(AdditionalHeadersToArrayTypoScriptRector::class); $rectorConfig->rule(LibFluidContentToLibContentElementRector::class); diff --git a/tests/Rector/v12/v0/typoscript/RemoveMetaCharSetRector/Fixture/fixture.typoscript b/tests/Rector/v12/v0/typoscript/RemoveMetaCharSetRector/Fixture/fixture.typoscript index 28ee876a7..b5b016178 100644 --- a/tests/Rector/v12/v0/typoscript/RemoveMetaCharSetRector/Fixture/fixture.typoscript +++ b/tests/Rector/v12/v0/typoscript/RemoveMetaCharSetRector/Fixture/fixture.typoscript @@ -1,8 +1,8 @@ config.metaCharset = utf-8 config { - metaCharset = utf-8 - dummy = 1 + metaCharset = utf-8 + dummy = 1 } config.foo = true diff --git a/tests/Rector/v12/v0/typoscript/RemoveNewContentElementWizardOptionsRector/Fixture/fixture.typoscript b/tests/Rector/v12/v0/typoscript/RemoveNewContentElementWizardOptionsRector/Fixture/fixture.typoscript index d6f4443a1..b39fbdd58 100644 --- a/tests/Rector/v12/v0/typoscript/RemoveNewContentElementWizardOptionsRector/Fixture/fixture.typoscript +++ b/tests/Rector/v12/v0/typoscript/RemoveNewContentElementWizardOptionsRector/Fixture/fixture.typoscript @@ -2,9 +2,9 @@ mod.web_layout.disableNewContentElementWizard = 1 mod.newContentElementWizard.override = 1 mod { - web_layout.disableNewContentElementWizard = 0 - newContentElementWizard.override = 0 - dummy = 1 + web_layout.disableNewContentElementWizard = 0 + newContentElementWizard.override = 0 + dummy = 1 } config.foo = true diff --git a/tests/Rector/v12/v0/typoscript/RemoveSendCacheHeadersConfigOptionRector/Fixture/fixture.typoscript b/tests/Rector/v12/v0/typoscript/RemoveSendCacheHeadersConfigOptionRector/Fixture/fixture.typoscript index 64e4d86b9..b7ca75cba 100644 --- a/tests/Rector/v12/v0/typoscript/RemoveSendCacheHeadersConfigOptionRector/Fixture/fixture.typoscript +++ b/tests/Rector/v12/v0/typoscript/RemoveSendCacheHeadersConfigOptionRector/Fixture/fixture.typoscript @@ -1,8 +1,8 @@ config.sendCacheHeaders_onlyWhenLoginDeniedInBranch = 1 config { - sendCacheHeaders_onlyWhenLoginDeniedInBranch = 0 - dummy = 1 + sendCacheHeaders_onlyWhenLoginDeniedInBranch = 0 + dummy = 1 } config.foo = true diff --git a/tests/Rector/v12/v0/typoscript/RemoveTSConfigModesRector/Fixture/fixture.typoscript b/tests/Rector/v12/v0/typoscript/RemoveTSConfigModesRector/Fixture/fixture.typoscript index 814fa7cf9..a8d8ae0ac 100644 --- a/tests/Rector/v12/v0/typoscript/RemoveTSConfigModesRector/Fixture/fixture.typoscript +++ b/tests/Rector/v12/v0/typoscript/RemoveTSConfigModesRector/Fixture/fixture.typoscript @@ -4,11 +4,11 @@ options.workspaces.changeStageMode = any options.workspaces.changeStageMode = page options { - workspaces.swapMode = any - workspaces.swapMode = page - workspaces.changeStageMode = any - workspaces.changeStageMode = page - dummy = 1 + workspaces.swapMode = any + workspaces.swapMode = page + workspaces.changeStageMode = any + workspaces.changeStageMode = page + dummy = 1 } config.foo = true diff --git a/tests/ValueObject/Fixtures/file-with-spaces.txt b/tests/ValueObject/Fixtures/file-with-spaces.txt new file mode 100644 index 000000000..594c531ec --- /dev/null +++ b/tests/ValueObject/Fixtures/file-with-spaces.txt @@ -0,0 +1,10 @@ + +plugin.tx_news { + view { + templateRootPaths { + 0 = EXT:news/Resources/Private/Templates/ + 1 = EXT:news/Resources/Private/Templates/Styles/Twb/Templates + 2 = {$plugin.tx_news.view.twb.templateRootPath} + } + } +} diff --git a/tests/ValueObject/Fixtures/tabs.txt b/tests/ValueObject/Fixtures/tabs.txt new file mode 100644 index 000000000..b281f23fb --- /dev/null +++ b/tests/ValueObject/Fixtures/tabs.txt @@ -0,0 +1,10 @@ + +plugin.tx_news { + view { + templateRootPaths { + 0 = EXT:news/Resources/Private/Templates/ + 1 = EXT:news/Resources/Private/Templates/Styles/Twb/Templates + 2 = {$plugin.tx_news.view.twb.templateRootPath} + } + } +} diff --git a/tests/ValueObject/IndentTest.php b/tests/ValueObject/IndentTest.php new file mode 100644 index 000000000..dbf2b58ae --- /dev/null +++ b/tests/ValueObject/IndentTest.php @@ -0,0 +1,64 @@ +toString()); + } + + public function testIsSpaceReturnsTrue(): void + { + self::assertTrue(Indent::fromFile($this->fileWithSpaces())->isSpace()); + } + + public function testLengthReturnsCorrectValue(): void + { + self::assertSame(2, Indent::fromFile($this->fileWithSpaces())->length()); + } + + public function testIsSpaceReturnsFalse(): void + { + self::assertFalse(Indent::fromFile($this->fileWithTabs())->isSpace()); + } + + /** + * @return \Generator> + */ + public function provideValidStringValues(): \Generator + { + yield 'Tabs' => ["\t", "\t"]; + yield 'Spaces' => [' ', ' ']; + } + + /** + * @return \Generator> + */ + public function provideValidFiles(): \Generator + { + yield 'File with tab content' => ["\t", $this->fileWithTabs()]; + yield 'File with two spaces content' => [' ', $this->fileWithSpaces()]; + } + + public function fileWithSpaces(): File + { + return new File('foobar.txt', (string) file_get_contents(__DIR__ . '/Fixtures/file-with-spaces.txt')); + } + + public function fileWithTabs(): File + { + return new File('foobar.txt', (string) file_get_contents(__DIR__ . '/Fixtures/tabs.txt')); + } +}