mirror of
https://github.com/rectorphp/rector.git
synced 2025-04-22 00:12:29 +02:00
[TASK] Take .editorconfig into account (#6272)
This commit is contained in:
parent
aca76ddc2a
commit
16d5930435
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -41,3 +41,4 @@ phpstan-for-rector.neon export-ignore
|
||||
|
||||
# testing Windows spaces - https://help.github.com/en/github/using-git/configuring-git-to-handle-line-endings
|
||||
packages/better-php-doc-parser/tests/PhpDocInfo/PhpDocInfoPrinter/FixtureBasic/with_spac.txt text eol=crlf
|
||||
packages-tests/FileFormatter/ValueObject/Fixture/composer_carriage_return_line_feed.json json eol=crlf
|
||||
|
@ -32,6 +32,8 @@
|
||||
"composer/xdebug-handler": "^2.0",
|
||||
"danielstjules/stringy": "^3.1",
|
||||
"doctrine/inflector": "^2.0",
|
||||
"ergebnis/json-printer": "^3.1",
|
||||
"idiosyncratic/editorconfig": "^0.1.0",
|
||||
"jean85/pretty-package-versions": "^1.6",
|
||||
"nette/caching": "^3.1",
|
||||
"nette/utils": "^3.2",
|
||||
@ -48,6 +50,7 @@
|
||||
"rector/rector-phpunit": "^0.10.8",
|
||||
"rector/rector-symfony": "^0.10.5",
|
||||
"sebastian/diff": "^4.0.4",
|
||||
"shanethehat/pretty-xml": "^1.0",
|
||||
"symfony/console": "^4.4.8|^5.1",
|
||||
"symfony/dependency-injection": "^5.1",
|
||||
"symfony/finder": "^4.4.8|^5.1",
|
||||
@ -153,7 +156,5 @@
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"platform-check": false
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,9 @@ declare(strict_types=1);
|
||||
use Composer\Semver\VersionParser;
|
||||
use Doctrine\Inflector\Inflector;
|
||||
use Doctrine\Inflector\Rules\English\InflectorFactory;
|
||||
use Ergebnis\Json\Printer\Printer;
|
||||
use Ergebnis\Json\Printer\PrinterInterface;
|
||||
use Idiosyncratic\EditorConfig\EditorConfig;
|
||||
use Nette\Caching\Cache;
|
||||
use PhpParser\BuilderFactory;
|
||||
use PhpParser\Lexer;
|
||||
@ -21,6 +24,7 @@ use PHPStan\PhpDoc\TypeNodeResolver;
|
||||
use PHPStan\PhpDocParser\Parser\PhpDocParser;
|
||||
use PHPStan\PhpDocParser\Parser\TypeParser;
|
||||
use PHPStan\Reflection\ReflectionProvider;
|
||||
use PrettyXml\Formatter;
|
||||
use Rector\BetterPhpDocParser\PhpDocParser\BetterPhpDocParser;
|
||||
use Rector\BetterPhpDocParser\PhpDocParser\BetterTypeParser;
|
||||
use Rector\Caching\Cache\NetteCacheFactory;
|
||||
@ -28,6 +32,8 @@ use Rector\Core\Console\ConsoleApplication;
|
||||
use Rector\Core\NonPhpFile\Rector\RenameClassNonPhpRector;
|
||||
use Rector\Core\PhpParser\Parser\NikicPhpParserFactory;
|
||||
use Rector\Core\PhpParser\Parser\PhpParserLexerFactory;
|
||||
use Rector\FileFormatter\Contract\EditorConfig\EditorConfigParserInterface;
|
||||
use Rector\FileFormatter\EditorConfig\EditorConfigIdiosyncraticParser;
|
||||
use Rector\NodeTypeResolver\DependencyInjection\PHPStanServicesFactory;
|
||||
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocator\IntermediateSourceLocator;
|
||||
use Rector\NodeTypeResolver\Reflection\BetterReflection\SourceLocatorProvider\DynamicSourceLocatorProvider;
|
||||
@ -146,4 +152,13 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
||||
->factory([service(PHPStanServicesFactory::class), 'createTypeNodeResolver']);
|
||||
$services->set(DynamicSourceLocatorProvider::class)
|
||||
->factory([service(PHPStanServicesFactory::class), 'createDynamicSourceLocatorProvider']);
|
||||
|
||||
$services->set(Printer::class);
|
||||
$services->alias(PrinterInterface::class, Printer::class);
|
||||
|
||||
$services->set(Formatter::class);
|
||||
|
||||
$services->set(EditorConfig::class);
|
||||
|
||||
$services->alias(EditorConfigParserInterface::class, EditorConfigIdiosyncraticParser::class);
|
||||
};
|
||||
|
@ -0,0 +1,3 @@
|
||||
[composer.json]
|
||||
indent_size = 1
|
||||
indent_style = tab
|
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\FileFormatter\EditorConfig\EditorConfigIdiosyncraticParser;
|
||||
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Contract\EditorConfig\EditorConfigParserInterface;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
use Rector\Testing\PHPUnit\AbstractTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class EditorConfigIdiosyncraticParserTest extends AbstractTestCase
|
||||
{
|
||||
/**
|
||||
* @var EditorConfigParserInterface
|
||||
*/
|
||||
private $editorConfigParser;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->boot();
|
||||
$this->editorConfigParser = $this->getService(EditorConfigParserInterface::class);
|
||||
}
|
||||
|
||||
public function testComposerJsonFile(): void
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createSpaceWithSize(20));
|
||||
|
||||
$composerJsonFile = new SmartFileInfo(__DIR__ . '/Fixture/composer.json');
|
||||
|
||||
$file = new File($composerJsonFile, $composerJsonFile->getContents());
|
||||
|
||||
$editorConfigConfiguration = $this->editorConfigParser->extractConfigurationForFile(
|
||||
$file,
|
||||
$editorConfigConfigurationBuilder
|
||||
);
|
||||
|
||||
$this->assertSame('tab', $editorConfigConfiguration->getIndentStyle());
|
||||
$this->assertSame(1, $editorConfigConfiguration->getIndentSize());
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"description": "A foo bar baz extension",
|
||||
"license": "GPL-2.0-or-later"
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"description": "A foo bar baz extension",
|
||||
"license": "GPL-2.0-or-later"
|
||||
}
|
||||
-----
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"description": "A foo bar baz extension",
|
||||
"license": "GPL-2.0-or-later"
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\FileFormatter\Formatter\JsonFileFormatter;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Formatter\JsonFileFormatter;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
use Rector\Testing\PHPUnit\AbstractTestCase;
|
||||
use Symplify\EasyTesting\DataProvider\StaticFixtureFinder;
|
||||
use Symplify\EasyTesting\StaticFixtureSplitter;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class JsonFileFormatterTest extends AbstractTestCase
|
||||
{
|
||||
/**
|
||||
* @var JsonFileFormatter
|
||||
*/
|
||||
private $jsonFileFormatter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->boot();
|
||||
$this->jsonFileFormatter = $this->getService(JsonFileFormatter::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Iterator<array<int, SmartFileInfo>>
|
||||
*/
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return StaticFixtureFinder::yieldDirectory(__DIR__ . '/Fixture', '*.json');
|
||||
}
|
||||
|
||||
private function doTestFileInfo(SmartFileInfo $smartFileInfo): void
|
||||
{
|
||||
$inputFileInfoAndExpected = StaticFixtureSplitter::splitFileInfoToLocalInputAndExpected($smartFileInfo);
|
||||
|
||||
$inputFileInfo = $inputFileInfoAndExpected->getInputFileInfo();
|
||||
$file = new File($inputFileInfo, $inputFileInfo->getContents());
|
||||
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createTabWithSize(1));
|
||||
|
||||
$this->jsonFileFormatter->format($file, $editorConfigConfigurationBuilder->build());
|
||||
|
||||
$this->assertSame($inputFileInfoAndExpected->getExpected(), $file->getFileContent());
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0"?>
|
||||
<catalog>
|
||||
<book id="bk101">
|
||||
<author>Gambardella, Matthew</author>
|
||||
<title>XML Developer's Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>44.95</price>
|
||||
<publish_date>2000-10-01</publish_date>
|
||||
<description>An in-depth look at creating applications
|
||||
with XML.</description>
|
||||
</book>
|
||||
</catalog>
|
||||
-----
|
||||
<?xml version="1.0"?>
|
||||
<catalog>
|
||||
<book id="bk101">
|
||||
<author>Gambardella, Matthew</author>
|
||||
<title>XML Developer's Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>44.95</price>
|
||||
<publish_date>2000-10-01</publish_date>
|
||||
<description>An in-depth look at creating applications
|
||||
with XML.</description>
|
||||
</book>
|
||||
</catalog>
|
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\FileFormatter\Formatter\XmlFileFormatter;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Formatter\XmlFileFormatter;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
use Rector\Testing\PHPUnit\AbstractTestCase;
|
||||
use Symplify\EasyTesting\DataProvider\StaticFixtureFinder;
|
||||
use Symplify\EasyTesting\StaticFixtureSplitter;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class XmlFileFormatterTest extends AbstractTestCase
|
||||
{
|
||||
/**
|
||||
* @var XmlFileFormatter
|
||||
*/
|
||||
private $xmlFileFormatter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->boot();
|
||||
$this->xmlFileFormatter = $this->getService(XmlFileFormatter::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Iterator<array<int, SmartFileInfo>>
|
||||
*/
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return StaticFixtureFinder::yieldDirectory(__DIR__ . '/Fixture', '*.xml');
|
||||
}
|
||||
|
||||
private function doTestFileInfo(SmartFileInfo $smartFileInfo): void
|
||||
{
|
||||
$inputFileInfoAndExpected = StaticFixtureSplitter::splitFileInfoToLocalInputAndExpected($smartFileInfo);
|
||||
|
||||
$inputFileInfo = $inputFileInfoAndExpected->getInputFileInfo();
|
||||
$file = new File($inputFileInfo, $inputFileInfo->getContents());
|
||||
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createTabWithSize(1));
|
||||
|
||||
$this->xmlFileFormatter->format($file, $editorConfigConfigurationBuilder->build());
|
||||
|
||||
$this->assertSame($inputFileInfoAndExpected->getExpected(), $file->getFileContent());
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
martin:
|
||||
name: Martin
|
||||
job: Developer
|
||||
skills:
|
||||
- python
|
||||
- perl
|
||||
- pascal
|
||||
-----
|
||||
martin:
|
||||
name: Martin
|
||||
job: Developer
|
||||
skills:
|
||||
- python
|
||||
- perl
|
||||
- pascal
|
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\FileFormatter\Formatter\YamlFileFormatter;
|
||||
|
||||
use Iterator;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Formatter\YamlFileFormatter;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
use Rector\Testing\PHPUnit\AbstractTestCase;
|
||||
use Symplify\EasyTesting\DataProvider\StaticFixtureFinder;
|
||||
use Symplify\EasyTesting\StaticFixtureSplitter;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class YamlFileFormatterTest extends AbstractTestCase
|
||||
{
|
||||
/**
|
||||
* @var YamlFileFormatter
|
||||
*/
|
||||
private $yamlFileFormatter;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
$this->boot();
|
||||
$this->yamlFileFormatter = $this->getService(YamlFileFormatter::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Iterator<array<int, SmartFileInfo>>
|
||||
*/
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return StaticFixtureFinder::yieldDirectory(__DIR__ . '/Fixture', '*.yaml');
|
||||
}
|
||||
|
||||
private function doTestFileInfo(SmartFileInfo $smartFileInfo): void
|
||||
{
|
||||
$inputFileInfoAndExpected = StaticFixtureSplitter::splitFileInfoToLocalInputAndExpected($smartFileInfo);
|
||||
|
||||
$inputFileInfo = $inputFileInfoAndExpected->getInputFileInfo();
|
||||
$file = new File($inputFileInfo, $inputFileInfo->getContents());
|
||||
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createSpaceWithSize(4));
|
||||
$editorConfigConfigurationBuilder->withInsertFinalNewline(false);
|
||||
|
||||
$this->yamlFileFormatter->format($file, $editorConfigConfigurationBuilder->build());
|
||||
|
||||
$this->assertSame($inputFileInfoAndExpected->getExpected(), $file->getFileContent());
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\FileFormatter\ValueObject;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
use Symplify\PackageBuilder\Configuration\StaticEolConfiguration;
|
||||
|
||||
final class EditorConfigConfigurationTest extends TestCase
|
||||
{
|
||||
public function testWithFinalNewline(): void
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfiguration = $editorConfigConfigurationBuilder->build();
|
||||
|
||||
$this->assertSame(StaticEolConfiguration::getEolChar(), $editorConfigConfiguration->getFinalNewline());
|
||||
}
|
||||
|
||||
public function testWithoutFinalNewline(): void
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfigurationBuilder->withInsertFinalNewline(false);
|
||||
|
||||
$editorConfigConfiguration = $editorConfigConfigurationBuilder->build();
|
||||
|
||||
$this->assertSame('', $editorConfigConfiguration->getFinalNewline());
|
||||
}
|
||||
|
||||
public function testIndentForTab(): void
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createTabWithSize(4));
|
||||
|
||||
$editorConfigConfiguration = $editorConfigConfigurationBuilder->build();
|
||||
|
||||
$this->assertSame(' ', $editorConfigConfiguration->getIndent());
|
||||
}
|
||||
|
||||
public function testIndentForSpace(): void
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createSpaceWithSize(10));
|
||||
|
||||
$editorConfigConfiguration = $editorConfigConfigurationBuilder->build();
|
||||
|
||||
$this->assertSame(' ', $editorConfigConfiguration->getIndent());
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{
"name": "foo/bar",
"description": "A foo bar baz extension",
"license": "GPL-2.0-or-later"
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"description": "A foo bar baz extension",
|
||||
"license": "GPL-2.0-or-later"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"description": "A foo bar baz extension",
|
||||
"license": "GPL-2.0-or-later"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"description": "A foo bar baz extension",
|
||||
"license": "GPL-2.0-or-later"
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "foo/bar",
|
||||
"description": "A foo bar baz extension",
|
||||
"license": "GPL-2.0-or-later"
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0"?>
|
||||
<catalog>
|
||||
<book id="bk101">
|
||||
<author>Gambardella, Matthew</author>
|
||||
<title>XML Developer's Guide</title>
|
||||
<genre>Computer</genre>
|
||||
<price>44.95</price>
|
||||
<publish_date>2000-10-01</publish_date>
|
||||
<description>An in-depth look at creating applications
|
||||
with XML.</description>
|
||||
</book>
|
||||
</catalog>
|
@ -0,0 +1 @@
|
||||
martin:
name: Martin
job: Developer
skills:
- python
- perl
- pascal
|
@ -0,0 +1,7 @@
|
||||
martin:
|
||||
name: Martin
|
||||
job: Developer
|
||||
skills:
|
||||
- python
|
||||
- perl
|
||||
- pascal
|
@ -0,0 +1,7 @@
|
||||
martin:
|
||||
name: Martin
|
||||
job: Developer
|
||||
skills:
|
||||
- python
|
||||
- perl
|
||||
- pascal
|
104
packages-tests/FileFormatter/ValueObject/IndentTest.php
Normal file
104
packages-tests/FileFormatter/ValueObject/IndentTest.php
Normal file
@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\FileFormatter\ValueObject;
|
||||
|
||||
use Generator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Rector\FileFormatter\Exception\InvalidIndentSizeException;
|
||||
use Rector\FileFormatter\Exception\InvalidIndentStyleException;
|
||||
use Rector\FileFormatter\Exception\ParseIndentException;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class IndentTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider extractFromFiles
|
||||
*/
|
||||
public function testFromFiles(SmartFileInfo $smartFileInfo, string $expectedIndent): void
|
||||
{
|
||||
$indent = Indent::fromContent($smartFileInfo->getContents());
|
||||
$this->assertSame($expectedIndent, $indent->__toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideSizeStyleAndIndentString
|
||||
*/
|
||||
public function testFromSizeAndStyle(int $size, string $style, string $string): void
|
||||
{
|
||||
$indent = Indent::fromSizeAndStyle($size, $style);
|
||||
|
||||
$this->assertSame($string, $indent->__toString());
|
||||
$this->assertSame($size, $indent->getIndentSize());
|
||||
$this->assertSame($style, $indent->getIndentStyle());
|
||||
}
|
||||
|
||||
public function testFromSizeAndStyleWithInvalidSizeThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidIndentSizeException::class);
|
||||
Indent::createTabWithSize(0);
|
||||
}
|
||||
|
||||
public function testFromSizeAndStyleWithInvalidStyleThrowsException(): void
|
||||
{
|
||||
$this->expectException(InvalidIndentStyleException::class);
|
||||
Indent::fromSizeAndStyle(1, 'invalid');
|
||||
}
|
||||
|
||||
public function testFromInvalidContentThrowsException(): void
|
||||
{
|
||||
$this->expectException(ParseIndentException::class);
|
||||
Indent::fromContent('This is invalid content');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Generator<array<string>>
|
||||
*/
|
||||
public function extractFromFiles(): Generator
|
||||
{
|
||||
yield 'Yaml file with space indentation of size 4' => [
|
||||
new SmartFileInfo(__DIR__ . '/Fixture/yaml_indentation_space_four.yaml'),
|
||||
' ',
|
||||
];
|
||||
|
||||
yield 'Yaml file with space indentation of size 2' => [
|
||||
new SmartFileInfo(__DIR__ . '/Fixture/yaml_indentation_space_two.yaml'),
|
||||
' ',
|
||||
];
|
||||
|
||||
yield 'Json file with tab indentation of size 2' => [
|
||||
new SmartFileInfo(__DIR__ . '/Fixture/composer_indentation_tab_two.json'),
|
||||
' ',
|
||||
];
|
||||
|
||||
yield 'Json file with space indentation of size 6' => [
|
||||
new SmartFileInfo(__DIR__ . '/Fixture/composer_indentation_space_six.json'),
|
||||
' ',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Generator<array{0: int, 1: string, 2: string}>
|
||||
*/
|
||||
public function provideSizeStyleAndIndentString(): Generator
|
||||
{
|
||||
foreach ($this->sizes() as $size) {
|
||||
foreach (Indent::CHARACTERS as $style => $character) {
|
||||
$string = str_repeat($character, $size);
|
||||
|
||||
yield [$size, $style, $string];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
private static function sizes(): array
|
||||
{
|
||||
return [
|
||||
'int-one' => 1,
|
||||
'int-greater-than-one' => 5,
|
||||
];
|
||||
}
|
||||
}
|
110
packages-tests/FileFormatter/ValueObject/NewLineTest.php
Normal file
110
packages-tests/FileFormatter/ValueObject/NewLineTest.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\FileFormatter\ValueObject;
|
||||
|
||||
use Generator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Rector\FileFormatter\Exception\InvalidNewLineStringException;
|
||||
use Rector\FileFormatter\ValueObject\NewLine;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class NewLineTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider extractFromFiles
|
||||
*/
|
||||
public function testFromFiles(SmartFileInfo $smartFileInfo, string $expectedNewLine): void
|
||||
{
|
||||
$newLine = NewLine::fromContent($smartFileInfo->getContents());
|
||||
$this->assertSame($expectedNewLine, $newLine->__toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideInvalidNewLineString
|
||||
*/
|
||||
public function testFromStringRejectsInvalidNewLineString(string $string): void
|
||||
{
|
||||
$this->expectException(InvalidNewLineStringException::class);
|
||||
|
||||
NewLine::fromSingleCharacter($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideValidNewLineString
|
||||
*/
|
||||
public function testFromStringReturnsNewLine(string $string): void
|
||||
{
|
||||
$newLine = NewLine::fromSingleCharacter($string);
|
||||
|
||||
$this->assertSame($string, $newLine->__toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideValidNewLineStringFromEditorConfig
|
||||
*/
|
||||
public function testFromEditorConfigReturnsNewLine(string $string, string $expected): void
|
||||
{
|
||||
$newLine = NewLine::fromEditorConfig($string);
|
||||
|
||||
$this->assertSame($expected, $newLine->__toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Generator<array<string>>
|
||||
*/
|
||||
public function provideValidNewLineString(): Generator
|
||||
{
|
||||
foreach (["\n", "\r", "\r\n"] as $string) {
|
||||
yield [$string];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Generator<array<string>>
|
||||
*/
|
||||
public function provideInvalidNewLineString(): Generator
|
||||
{
|
||||
foreach (["\t", " \r ", " \r\n ", " \n ", ' ', "\f", "\x0b", "\x85"] as $string) {
|
||||
yield [$string];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Generator<array<string>>
|
||||
*/
|
||||
public function extractFromFiles(): Generator
|
||||
{
|
||||
yield 'Yaml file with carriage return' => [
|
||||
new SmartFileInfo(__DIR__ . '/Fixture/yaml_carriage_return.yaml'),
|
||||
"\r",
|
||||
];
|
||||
|
||||
yield 'Xml file with line feed' => [new SmartFileInfo(__DIR__ . '/Fixture/xml_line_feed.xml'), "\n"];
|
||||
|
||||
yield 'Json file with line feed' => [new SmartFileInfo(__DIR__ . '/Fixture/composer_line_feed.json'), "\n"];
|
||||
|
||||
yield 'Json file with carriage return' => [
|
||||
new SmartFileInfo(__DIR__ . '/Fixture/composer_carriage_return.json'),
|
||||
"\r",
|
||||
];
|
||||
|
||||
yield 'Json file with carriage return and line feed' => [
|
||||
new SmartFileInfo(__DIR__ . '/Fixture/composer_carriage_return_line_feed.json'),
|
||||
"\r\n",
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Generator<array<string>>
|
||||
*/
|
||||
public function provideValidNewLineStringFromEditorConfig(): Generator
|
||||
{
|
||||
foreach ([
|
||||
'lf' => "\n",
|
||||
'cr' => "\r",
|
||||
'crlf' => "\r\n",
|
||||
] as $editorConfig => $string) {
|
||||
yield [$editorConfig, $string];
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\FileFormatter\Contract\EditorConfig;
|
||||
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
|
||||
interface EditorConfigParserInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const INDENT_STYLE = 'indent_style';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const INDENT_SIZE = 'indent_size';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const END_OF_LINE = 'end_of_line';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const INSERT_FINAL_NEWLINE = 'insert_final_newline';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const TAB_WIDTH = 'tab_width';
|
||||
|
||||
public function extractConfigurationForFile(
|
||||
File $file,
|
||||
EditorConfigConfigurationBuilder $editorConfigConfigurationBuilder
|
||||
): EditorConfigConfiguration;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\FileFormatter\Contract\Formatter;
|
||||
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
|
||||
interface FileFormatterInterface
|
||||
{
|
||||
public function supports(File $file): bool;
|
||||
|
||||
public function format(File $file, EditorConfigConfiguration $editorConfigConfiguration): void;
|
||||
|
||||
public function createDefaultEditorConfigConfigurationBuilder(): EditorConfigConfigurationBuilder;
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\EditorConfig;
|
||||
|
||||
use Idiosyncratic\EditorConfig\EditorConfig;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Contract\EditorConfig\EditorConfigParserInterface;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\FileFormatter\EditorConfig\EditorConfigIdiosyncraticParser\EditorConfigIdiosyncraticParserTest
|
||||
*/
|
||||
final class EditorConfigIdiosyncraticParser implements EditorConfigParserInterface
|
||||
{
|
||||
/**
|
||||
* @var EditorConfig
|
||||
*/
|
||||
private $editorConfig;
|
||||
|
||||
public function __construct(EditorConfig $editorConfig)
|
||||
{
|
||||
$this->editorConfig = $editorConfig;
|
||||
}
|
||||
|
||||
public function extractConfigurationForFile(
|
||||
File $file,
|
||||
EditorConfigConfigurationBuilder $editorConfigConfigurationBuilder
|
||||
): EditorConfigConfiguration {
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
$configuration = $this->editorConfig->getConfigForPath($smartFileInfo->getRealPath());
|
||||
|
||||
if (array_key_exists(self::INDENT_STYLE, $configuration)) {
|
||||
$indentStyle = (string) $configuration[self::INDENT_STYLE]->getValue();
|
||||
|
||||
$editorConfigConfigurationBuilder->withIndentStyle($indentStyle);
|
||||
}
|
||||
|
||||
if (array_key_exists(self::INDENT_SIZE, $configuration)) {
|
||||
$indentSize = (int) $configuration[self::INDENT_SIZE]->getValue();
|
||||
|
||||
$editorConfigConfigurationBuilder->withIndentSize($indentSize);
|
||||
}
|
||||
|
||||
if (array_key_exists(self::END_OF_LINE, $configuration)) {
|
||||
$endOfLine = (string) $configuration[self::END_OF_LINE]->getValue();
|
||||
|
||||
$editorConfigConfigurationBuilder->withEndOfLineFromEditorConfig($endOfLine);
|
||||
}
|
||||
|
||||
if (array_key_exists(self::INSERT_FINAL_NEWLINE, $configuration)) {
|
||||
$insertFinalNewline = (bool) $configuration[self::INSERT_FINAL_NEWLINE]->getValue();
|
||||
|
||||
$editorConfigConfigurationBuilder->withInsertFinalNewline($insertFinalNewline);
|
||||
}
|
||||
|
||||
if (array_key_exists(self::TAB_WIDTH, $configuration)) {
|
||||
$editorConfigConfigurationBuilder->withIndentSize($configuration[self::TAB_WIDTH]->getValue());
|
||||
}
|
||||
|
||||
return $editorConfigConfigurationBuilder->build();
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class InvalidIndentSizeException extends InvalidArgumentException
|
||||
{
|
||||
public static function fromSizeAndMinimumSize(int $size, int $minimumSize): self
|
||||
{
|
||||
$message = sprintf('Size %d must be greater than %d', $size, $minimumSize);
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class InvalidIndentStringException extends InvalidArgumentException
|
||||
{
|
||||
public static function fromString(string $string): self
|
||||
{
|
||||
$message = sprintf('This is not valid indentation "%s"', $string);
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class InvalidIndentStyleException extends InvalidArgumentException
|
||||
{
|
||||
/**
|
||||
* @param array<int, string> $allowedStyles
|
||||
*/
|
||||
public static function fromStyleAndAllowedStyles(string $style, array $allowedStyles): self
|
||||
{
|
||||
$message = sprintf('Given style "%s" is not allowed. Allowed are "%s"', $style, implode(' ', $allowedStyles));
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class InvalidNewLineStringException extends InvalidArgumentException
|
||||
{
|
||||
public static function fromString(string $string): self
|
||||
{
|
||||
return new self(sprintf('"%s" is not a valid new-line character sequence.', $string));
|
||||
}
|
||||
|
||||
public static function create(string $message): self
|
||||
{
|
||||
return new self($message);
|
||||
}
|
||||
}
|
17
packages/FileFormatter/Exception/ParseIndentException.php
Normal file
17
packages/FileFormatter/Exception/ParseIndentException.php
Normal file
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Exception;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
final class ParseIndentException extends UnexpectedValueException
|
||||
{
|
||||
public static function fromString(string $string): self
|
||||
{
|
||||
$message = sprintf('The content "%s" could not be parsed', $string);
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
}
|
103
packages/FileFormatter/FileFormatter.php
Normal file
103
packages/FileFormatter/FileFormatter.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter;
|
||||
|
||||
use Rector\Core\Configuration\Option;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Contract\EditorConfig\EditorConfigParserInterface;
|
||||
use Rector\FileFormatter\Contract\Formatter\FileFormatterInterface;
|
||||
use Rector\FileFormatter\Exception\InvalidNewLineStringException;
|
||||
use Rector\FileFormatter\Exception\ParseIndentException;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObject\NewLine;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
use Symplify\PackageBuilder\Parameter\ParameterProvider;
|
||||
|
||||
final class FileFormatter
|
||||
{
|
||||
/**
|
||||
* @var EditorConfigParserInterface
|
||||
*/
|
||||
private $editorConfigParser;
|
||||
|
||||
/**
|
||||
* @var FileFormatterInterface[]
|
||||
*/
|
||||
private $fileFormatters = [];
|
||||
|
||||
/**
|
||||
* @var ParameterProvider
|
||||
*/
|
||||
private $parameterProvider;
|
||||
|
||||
/**
|
||||
* @param FileFormatterInterface[] $fileFormatters
|
||||
*/
|
||||
public function __construct(
|
||||
EditorConfigParserInterface $editorConfigParser,
|
||||
ParameterProvider $parameterProvider,
|
||||
array $fileFormatters = [])
|
||||
{
|
||||
$this->editorConfigParser = $editorConfigParser;
|
||||
$this->fileFormatters = $fileFormatters;
|
||||
$this->parameterProvider = $parameterProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param File[] $files
|
||||
*/
|
||||
public function format(array $files): void
|
||||
{
|
||||
foreach ($files as $file) {
|
||||
if (! $file->hasChanged()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($this->fileFormatters as $fileFormatter) {
|
||||
if (! $fileFormatter->supports($file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$editorConfigConfigurationBuilder = $fileFormatter->createDefaultEditorConfigConfigurationBuilder();
|
||||
|
||||
$this->sniffOriginalFileContent($file, $editorConfigConfigurationBuilder);
|
||||
|
||||
$editorConfiguration = $this->createEditorConfiguration($file, $editorConfigConfigurationBuilder);
|
||||
|
||||
$fileFormatter->format($file, $editorConfiguration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function sniffOriginalFileContent(
|
||||
File $file,
|
||||
EditorConfigConfigurationBuilder $editorConfigConfigurationBuilder
|
||||
): void {
|
||||
// Try to sniff into the original content to get the indentation and new line
|
||||
try {
|
||||
$indent = Indent::fromContent($file->getOriginalFileContent());
|
||||
$editorConfigConfigurationBuilder->withIndent($indent);
|
||||
} catch (ParseIndentException $parseIndentException) {
|
||||
}
|
||||
|
||||
try {
|
||||
$newLine = NewLine::fromContent($file->getOriginalFileContent());
|
||||
$editorConfigConfigurationBuilder->withNewLine($newLine);
|
||||
} catch (InvalidNewLineStringException $invalidNewLineStringException) {
|
||||
}
|
||||
}
|
||||
|
||||
private function createEditorConfiguration(
|
||||
File $file,
|
||||
EditorConfigConfigurationBuilder $editorConfigConfigurationBuilder
|
||||
): EditorConfigConfiguration {
|
||||
if (! $this->parameterProvider->provideBoolParameter(Option::ENABLE_EDITORCONFIG)) {
|
||||
return $editorConfigConfigurationBuilder->build();
|
||||
}
|
||||
|
||||
return $this->editorConfigParser->extractConfigurationForFile($file, $editorConfigConfigurationBuilder);
|
||||
}
|
||||
}
|
57
packages/FileFormatter/Formatter/JsonFileFormatter.php
Normal file
57
packages/FileFormatter/Formatter/JsonFileFormatter.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Formatter;
|
||||
|
||||
use Ergebnis\Json\Printer\PrinterInterface;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Contract\Formatter\FileFormatterInterface;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\FileFormatter\Formatter\JsonFileFormatter\JsonFileFormatterTest
|
||||
*/
|
||||
final class JsonFileFormatter implements FileFormatterInterface
|
||||
{
|
||||
/**
|
||||
* @var PrinterInterface
|
||||
*/
|
||||
private $jsonPrinter;
|
||||
|
||||
public function __construct(PrinterInterface $jsonPrinter)
|
||||
{
|
||||
$this->jsonPrinter = $jsonPrinter;
|
||||
}
|
||||
|
||||
public function supports(File $file): bool
|
||||
{
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
|
||||
return $smartFileInfo->getExtension() === 'json';
|
||||
}
|
||||
|
||||
public function format(File $file, EditorConfigConfiguration $editorConfigConfiguration): void
|
||||
{
|
||||
$newFileContent = $this->jsonPrinter->print(
|
||||
$file->getFileContent(),
|
||||
$editorConfigConfiguration->getIndent(),
|
||||
$editorConfigConfiguration->getNewLine()
|
||||
);
|
||||
|
||||
$newFileContent .= $editorConfigConfiguration->getFinalNewline();
|
||||
|
||||
$file->changeFileContent($newFileContent);
|
||||
}
|
||||
|
||||
public function createDefaultEditorConfigConfigurationBuilder(): EditorConfigConfigurationBuilder
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createSpaceWithSize(4));
|
||||
|
||||
return $editorConfigConfigurationBuilder;
|
||||
}
|
||||
}
|
56
packages/FileFormatter/Formatter/XmlFileFormatter.php
Normal file
56
packages/FileFormatter/Formatter/XmlFileFormatter.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Formatter;
|
||||
|
||||
use PrettyXml\Formatter;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Contract\Formatter\FileFormatterInterface;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\FileFormatter\Formatter\XmlFileFormatter\XmlFileFormatterTest
|
||||
*/
|
||||
final class XmlFileFormatter implements FileFormatterInterface
|
||||
{
|
||||
/**
|
||||
* @var Formatter
|
||||
*/
|
||||
private $xmlFormatter;
|
||||
|
||||
public function __construct(Formatter $xmlFormatter)
|
||||
{
|
||||
$this->xmlFormatter = $xmlFormatter;
|
||||
}
|
||||
|
||||
public function supports(File $file): bool
|
||||
{
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
|
||||
return $smartFileInfo->getExtension() === 'xml';
|
||||
}
|
||||
|
||||
public function format(File $file, EditorConfigConfiguration $editorConfigConfiguration): void
|
||||
{
|
||||
$this->xmlFormatter->setIndentCharacter($editorConfigConfiguration->getIndentStyleCharacter());
|
||||
$this->xmlFormatter->setIndentSize($editorConfigConfiguration->getIndentSize());
|
||||
|
||||
$newFileContent = $this->xmlFormatter->format($file->getFileContent());
|
||||
|
||||
$newFileContent .= $editorConfigConfiguration->getFinalNewline();
|
||||
|
||||
$file->changeFileContent($newFileContent);
|
||||
}
|
||||
|
||||
public function createDefaultEditorConfigConfigurationBuilder(): EditorConfigConfigurationBuilder
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createTabWithSize(1));
|
||||
|
||||
return $editorConfigConfigurationBuilder;
|
||||
}
|
||||
}
|
45
packages/FileFormatter/Formatter/YamlFileFormatter.php
Normal file
45
packages/FileFormatter/Formatter/YamlFileFormatter.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\Formatter;
|
||||
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\Contract\Formatter\FileFormatterInterface;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\FileFormatter\Formatter\YamlFileFormatter\YamlFileFormatterTest
|
||||
*/
|
||||
final class YamlFileFormatter implements FileFormatterInterface
|
||||
{
|
||||
public function supports(File $file): bool
|
||||
{
|
||||
$smartFileInfo = $file->getSmartFileInfo();
|
||||
|
||||
return in_array($smartFileInfo->getExtension(), ['yaml', 'yml'], true);
|
||||
}
|
||||
|
||||
public function format(File $file, EditorConfigConfiguration $editorConfigConfiguration): void
|
||||
{
|
||||
$yaml = Yaml::parse($file->getFileContent());
|
||||
|
||||
$newFileContent = Yaml::dump($yaml, 99, $editorConfigConfiguration->getIndentSize());
|
||||
|
||||
$newFileContent .= $editorConfigConfiguration->getFinalNewline();
|
||||
|
||||
$file->changeFileContent($newFileContent);
|
||||
}
|
||||
|
||||
public function createDefaultEditorConfigConfigurationBuilder(): EditorConfigConfigurationBuilder
|
||||
{
|
||||
$editorConfigConfigurationBuilder = EditorConfigConfigurationBuilder::anEditorConfigConfiguration();
|
||||
|
||||
$editorConfigConfigurationBuilder->withIndent(Indent::createSpaceWithSize(2));
|
||||
|
||||
return $editorConfigConfigurationBuilder;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\ValueObject;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\FileFormatter\ValueObject\EditorConfigConfigurationTest
|
||||
*/
|
||||
final class EditorConfigConfiguration
|
||||
{
|
||||
/**
|
||||
* @var NewLine
|
||||
*/
|
||||
private $newLine;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $insertFinalNewline = false;
|
||||
|
||||
/**
|
||||
* @var Indent
|
||||
*/
|
||||
private $indent;
|
||||
|
||||
public function __construct(Indent $indent, NewLine $newLine, bool $insertFinalNewline)
|
||||
{
|
||||
$this->indent = $indent;
|
||||
$this->newLine = $newLine;
|
||||
$this->insertFinalNewline = $insertFinalNewline;
|
||||
}
|
||||
|
||||
public function getNewLine(): string
|
||||
{
|
||||
return $this->newLine->__toString();
|
||||
}
|
||||
|
||||
public function getFinalNewline(): string
|
||||
{
|
||||
return $this->insertFinalNewline ? $this->getNewLine() : '';
|
||||
}
|
||||
|
||||
public function getIndent(): string
|
||||
{
|
||||
return $this->indent->__toString();
|
||||
}
|
||||
|
||||
public function getIndentStyleCharacter(): string
|
||||
{
|
||||
return $this->indent->getIndentStyleCharacter();
|
||||
}
|
||||
|
||||
public function getIndentStyle(): string
|
||||
{
|
||||
return $this->indent->getIndentStyle();
|
||||
}
|
||||
|
||||
public function getIndentSize(): int
|
||||
{
|
||||
return $this->indent->getIndentSize();
|
||||
}
|
||||
}
|
133
packages/FileFormatter/ValueObject/Indent.php
Normal file
133
packages/FileFormatter/ValueObject/Indent.php
Normal file
@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\ValueObject;
|
||||
|
||||
use Nette\Utils\Strings;
|
||||
use Rector\FileFormatter\Exception\InvalidIndentSizeException;
|
||||
use Rector\FileFormatter\Exception\InvalidIndentStringException;
|
||||
use Rector\FileFormatter\Exception\InvalidIndentStyleException;
|
||||
use Rector\FileFormatter\Exception\ParseIndentException;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\FileFormatter\ValueObject\IndentTest
|
||||
*/
|
||||
final class Indent
|
||||
{
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public const CHARACTERS = [
|
||||
self::SPACE => ' ',
|
||||
self::TAB => "\t",
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const SPACE = 'space';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private const TAB = 'tab';
|
||||
|
||||
/**
|
||||
* @see https://regex101.com/r/A2XiaF/1
|
||||
* @var string
|
||||
*/
|
||||
private const VALID_INDENT_REGEX = '/^( *|\t+)$/';
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private const MINIMUM_SIZE = 1;
|
||||
|
||||
/**
|
||||
* @see https://regex101.com/r/3HFEjX/1
|
||||
* @var string
|
||||
*/
|
||||
private const PARSE_INDENT_REGEX = '/^(?P<indent>( +|\t+)).*/m';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $string;
|
||||
|
||||
private function __construct(string $string)
|
||||
{
|
||||
$this->string = $string;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
public static function fromString(string $string): self
|
||||
{
|
||||
$validIndent = preg_match(self::VALID_INDENT_REGEX, $string);
|
||||
|
||||
if ($validIndent !== 1) {
|
||||
throw InvalidIndentStringException::fromString($string);
|
||||
}
|
||||
|
||||
return new self($string);
|
||||
}
|
||||
|
||||
public static function createSpaceWithSize(int $size): self
|
||||
{
|
||||
return self::fromSizeAndStyle($size, self::SPACE);
|
||||
}
|
||||
|
||||
public static function createTabWithSize(int $size): self
|
||||
{
|
||||
return self::fromSizeAndStyle($size, self::TAB);
|
||||
}
|
||||
|
||||
public static function fromSizeAndStyle(int $size, string $style): self
|
||||
{
|
||||
if ($size < self::MINIMUM_SIZE) {
|
||||
throw InvalidIndentSizeException::fromSizeAndMinimumSize($size, self::MINIMUM_SIZE);
|
||||
}
|
||||
|
||||
if (! array_key_exists($style, self::CHARACTERS)) {
|
||||
throw InvalidIndentStyleException::fromStyleAndAllowedStyles($style, array_keys(self::CHARACTERS));
|
||||
}
|
||||
|
||||
$value = str_repeat(self::CHARACTERS[$style], $size);
|
||||
|
||||
return new self($value);
|
||||
}
|
||||
|
||||
public static function fromContent(string $string): self
|
||||
{
|
||||
$validIndent = preg_match(self::PARSE_INDENT_REGEX, $string, $match);
|
||||
if ($validIndent === 1) {
|
||||
return self::fromString($match['indent']);
|
||||
}
|
||||
|
||||
throw ParseIndentException::fromString($string);
|
||||
}
|
||||
|
||||
public function getIndentSize(): int
|
||||
{
|
||||
return strlen($this->string);
|
||||
}
|
||||
|
||||
public function getIndentStyle(): string
|
||||
{
|
||||
return $this->startsWithSpace() ? self::SPACE : self::TAB;
|
||||
}
|
||||
|
||||
public function getIndentStyleCharacter(): string
|
||||
{
|
||||
return $this->startsWithSpace() ? self::CHARACTERS[self::SPACE] : self::CHARACTERS[self::TAB];
|
||||
}
|
||||
|
||||
private function startsWithSpace(): bool
|
||||
{
|
||||
return Strings::startsWith($this->string, ' ');
|
||||
}
|
||||
}
|
91
packages/FileFormatter/ValueObject/NewLine.php
Normal file
91
packages/FileFormatter/ValueObject/NewLine.php
Normal file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\ValueObject;
|
||||
|
||||
use const PHP_EOL;
|
||||
use Rector\FileFormatter\Exception\InvalidNewLineStringException;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\FileFormatter\ValueObject\NewLineTest
|
||||
*/
|
||||
final class NewLine
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const LINE_FEED = 'lf';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const CARRIAGE_RETURN = 'cr';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const CARRIAGE_RETURN_LINE_FEED = 'crlf';
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
private const ALLOWED_END_OF_LINE = [
|
||||
self::LINE_FEED => "\n",
|
||||
self::CARRIAGE_RETURN => "\r",
|
||||
self::CARRIAGE_RETURN_LINE_FEED => "\r\n",
|
||||
];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $string;
|
||||
|
||||
private function __construct(string $string)
|
||||
{
|
||||
$this->string = $string;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return $this->string;
|
||||
}
|
||||
|
||||
public static function fromSingleCharacter(string $string): self
|
||||
{
|
||||
$validNewLineRegularExpression = '/^(?>\r\n|\n|\r)$/';
|
||||
$validNewLine = preg_match($validNewLineRegularExpression, $string);
|
||||
|
||||
if ($validNewLine !== 1) {
|
||||
throw InvalidNewLineStringException::fromString($string);
|
||||
}
|
||||
|
||||
return new self($string);
|
||||
}
|
||||
|
||||
public static function fromContent(string $string): self
|
||||
{
|
||||
$validNewLineRegularExpression = '/(?P<newLine>\r\n|\n|\r)/';
|
||||
$validNewLine = preg_match($validNewLineRegularExpression, $string, $match);
|
||||
if ($validNewLine === 1) {
|
||||
return self::fromSingleCharacter($match['newLine']);
|
||||
}
|
||||
|
||||
return self::fromSingleCharacter(PHP_EOL);
|
||||
}
|
||||
|
||||
public static function fromEditorConfig(string $endOfLine): self
|
||||
{
|
||||
if (! array_key_exists($endOfLine, self::ALLOWED_END_OF_LINE)) {
|
||||
$allowedEndOfLineValues = array_keys(self::ALLOWED_END_OF_LINE);
|
||||
$message = sprintf(
|
||||
'The endOfLine "%s" is not allowed. Allowed are "%s"',
|
||||
$endOfLine,
|
||||
implode(',', $allowedEndOfLineValues)
|
||||
);
|
||||
throw InvalidNewLineStringException::create($message);
|
||||
}
|
||||
|
||||
return self::fromSingleCharacter(self::ALLOWED_END_OF_LINE[$endOfLine]);
|
||||
}
|
||||
}
|
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\FileFormatter\ValueObjectFactory;
|
||||
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObject\Indent;
|
||||
use Rector\FileFormatter\ValueObject\NewLine;
|
||||
|
||||
final class EditorConfigConfigurationBuilder
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private $indentStyle;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $indentSize;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $insertFinalNewline = false;
|
||||
|
||||
/**
|
||||
* @var NewLine
|
||||
*/
|
||||
private $newLine;
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->indentStyle = 'space';
|
||||
$this->indentSize = 2;
|
||||
$this->newLine = NewLine::fromEditorConfig('lf');
|
||||
$this->insertFinalNewline = true;
|
||||
}
|
||||
|
||||
public static function anEditorConfigConfiguration(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function withNewLine(NewLine $newLine): self
|
||||
{
|
||||
$this->newLine = $newLine;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withIndent(Indent $indent): self
|
||||
{
|
||||
$this->indentSize = $indent->getIndentSize();
|
||||
$this->indentStyle = $indent->getIndentStyle();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withIndentStyle(string $indentStyle): self
|
||||
{
|
||||
$this->indentStyle = $indentStyle;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withIndentSize(int $indentSize): self
|
||||
{
|
||||
$this->indentSize = $indentSize;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withInsertFinalNewline(bool $insertFinalNewline): self
|
||||
{
|
||||
$this->insertFinalNewline = $insertFinalNewline;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function withEndOfLineFromEditorConfig(string $endOfLine): self
|
||||
{
|
||||
$this->newLine = NewLine::fromEditorConfig($endOfLine);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function build(): EditorConfigConfiguration
|
||||
{
|
||||
$newLine = $this->newLine;
|
||||
|
||||
return new EditorConfigConfiguration(
|
||||
Indent::fromSizeAndStyle($this->indentSize, $this->indentStyle),
|
||||
$newLine,
|
||||
$this->insertFinalNewline
|
||||
);
|
||||
}
|
||||
}
|
@ -8,6 +8,7 @@ use Rector\Core\Application\FileDecorator\FileDiffFileDecorator;
|
||||
use Rector\Core\Configuration\Configuration;
|
||||
use Rector\Core\Contract\Processor\FileProcessorInterface;
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\FileFormatter;
|
||||
use Symplify\SmartFileSystem\SmartFileSystem;
|
||||
|
||||
final class ApplicationFileProcessor
|
||||
@ -32,6 +33,11 @@ final class ApplicationFileProcessor
|
||||
*/
|
||||
private $fileDiffFileDecorator;
|
||||
|
||||
/**
|
||||
* @var FileFormatter
|
||||
*/
|
||||
private $fileFormatter;
|
||||
|
||||
/**
|
||||
* @param FileProcessorInterface[] $fileProcessors
|
||||
*/
|
||||
@ -39,12 +45,14 @@ final class ApplicationFileProcessor
|
||||
Configuration $configuration,
|
||||
SmartFileSystem $smartFileSystem,
|
||||
FileDiffFileDecorator $fileDiffFileDecorator,
|
||||
FileFormatter $fileFormatter,
|
||||
array $fileProcessors = []
|
||||
) {
|
||||
$this->fileProcessors = $fileProcessors;
|
||||
$this->smartFileSystem = $smartFileSystem;
|
||||
$this->configuration = $configuration;
|
||||
$this->fileDiffFileDecorator = $fileDiffFileDecorator;
|
||||
$this->fileFormatter = $fileFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -54,6 +62,8 @@ final class ApplicationFileProcessor
|
||||
{
|
||||
$this->processFiles($files);
|
||||
|
||||
$this->fileFormatter->format($files);
|
||||
|
||||
$this->fileDiffFileDecorator->decorate($files);
|
||||
|
||||
$this->printFiles($files);
|
||||
|
@ -162,4 +162,9 @@ final class Option
|
||||
* @var string
|
||||
*/
|
||||
public const TEMPLATE_TYPE = 'template-type';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public const ENABLE_EDITORCONFIG = 'enable_editorconfig';
|
||||
}
|
||||
|
16
src/Contract/Formatter/FileFormatterInterface.php
Normal file
16
src/Contract/Formatter/FileFormatterInterface.php
Normal file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Rector\Core\Contract\Formatter;
|
||||
|
||||
use Rector\Core\ValueObject\Application\File;
|
||||
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
|
||||
use Rector\FileFormatter\ValueObjectFactory\EditorConfigConfigurationBuilder;
|
||||
|
||||
interface FileFormatterInterface
|
||||
{
|
||||
public function supports(File $file): bool;
|
||||
|
||||
public function format(File $file, EditorConfigConfiguration $editorConfigConfiguration): void;
|
||||
|
||||
public function createEditorConfigConfigurationBuilder(): EditorConfigConfigurationBuilder;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user