Skip to content

Commit

Permalink
Fix crash with pestphp (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
sabbelasichon committed May 18, 2021
1 parent 5728069 commit 0d99693
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 11 deletions.
1 change: 0 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
"rector/rector-phpunit": "^0.11.1",
"rector/rector-symfony": "^0.11.2",
"sebastian/diff": "^4.0.4",
"shanethehat/pretty-xml": "^1.0",
"symfony/console": "^5.2",
"symfony/dependency-injection": "^5.2",
"symfony/finder": "^5.2",
Expand Down
2 changes: 0 additions & 2 deletions config/services.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,5 @@
$services->set(Printer::class);
$services->alias(PrinterInterface::class, Printer::class);

$services->set(Formatter::class);

$services->set(EditorConfig::class);
};
114 changes: 106 additions & 8 deletions packages/FileFormatter/Formatter/XmlFileFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

namespace Rector\FileFormatter\Formatter;

use PrettyXml\Formatter;
use Nette\Utils\Strings;
use Rector\Core\ValueObject\Application\File;
use Rector\FileFormatter\Contract\Formatter\FileFormatterInterface;
use Rector\FileFormatter\ValueObject\EditorConfigConfiguration;
Expand All @@ -16,10 +16,13 @@
*/
final class XmlFileFormatter implements FileFormatterInterface
{
public function __construct(
private Formatter $xmlFormatter
) {
}
private ?int $depth = null;

private int $indent = 4;

private string $padChar = ' ';

private bool $preserveWhitespace = false;

public function supports(File $file): bool
{
Expand All @@ -30,10 +33,10 @@ public function supports(File $file): bool

public function format(File $file, EditorConfigConfiguration $editorConfigConfiguration): void
{
$this->xmlFormatter->setIndentCharacter($editorConfigConfiguration->getIndentStyleCharacter());
$this->xmlFormatter->setIndentSize($editorConfigConfiguration->getIndentSize());
$this->padChar = $editorConfigConfiguration->getIndentStyleCharacter();
$this->indent = $editorConfigConfiguration->getIndentSize();

$newFileContent = $this->xmlFormatter->format($file->getFileContent());
$newFileContent = $this->formatXml($file->getFileContent());

$newFileContent .= $editorConfigConfiguration->getFinalNewline();

Expand All @@ -48,4 +51,99 @@ public function createDefaultEditorConfigConfigurationBuilder(): EditorConfigCon

return $editorConfigConfigurationBuilder;
}

private function formatXml(string $xml): string
{
$output = '';
$this->depth = 0;

$parts = $this->getXmlParts($xml);

if (strpos($parts[0], '<?xml') === 0) {
$output = array_shift($parts) . PHP_EOL;
}

foreach ($parts as $part) {
$output .= $this->getOutputForPart($part);
}

return trim($output);
}

/**
* @return string[]
*/
private function getXmlParts(string $xml): array
{
$xmlParts = '#(>)(<)(\/*)#';

$withNewLines = Strings::replace(trim($xml), $xmlParts, "$1\n$2$3");
return explode("\n", $withNewLines);
}

private function getOutputForPart(string $part): string
{
$output = '';
$this->runPre($part);

if ($this->preserveWhitespace) {
$output .= $part . PHP_EOL;
} else {
$part = trim($part);
$output .= $this->getPaddedString($part) . PHP_EOL;
}

$this->runPost($part);

return $output;
}

private function runPre(string $part): void
{
if ($this->isClosingTag($part)) {
--$this->depth;
}
}

private function runPost(string $part): void
{
if ($this->isOpeningTag($part)) {
++$this->depth;
}
if ($this->isClosingCdataTag($part)) {
$this->preserveWhitespace = false;
}
if ($this->isOpeningCdataTag($part)) {
$this->preserveWhitespace = true;
}
}

private function getPaddedString(string $part): string
{
return str_pad($part, strlen($part) + ($this->depth * $this->indent), $this->padChar, STR_PAD_LEFT);
}

private function isOpeningTag(string $part): bool
{
$isOpeningTag = '#^<[^\/]*>$#';

return (bool) Strings::match($part, $isOpeningTag);
}

private function isClosingTag(string $part): bool
{
$isClosingTag = '#^\s*<\/#';

return (bool) Strings::match($part, $isClosingTag);
}

private function isOpeningCdataTag(string $part): bool
{
return Strings::contains($part, '<![CDATA[');
}

private function isClosingCdataTag(string $part): bool
{
return Strings::contains($part, ']]>');
}
}

0 comments on commit 0d99693

Please sign in to comment.