Skip to content

Commit

Permalink
refactor php compactor
Browse files Browse the repository at this point in the history
  • Loading branch information
smoench committed Dec 17, 2020
1 parent 6c6f139 commit 00d2f96
Show file tree
Hide file tree
Showing 12 changed files with 1,031 additions and 452 deletions.
3 changes: 3 additions & 0 deletions src/Annotation/CompactedFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@
use phpDocumentor\Reflection\DocBlock\Tags\Generic;
use function strpos;

/**
* @private
*/
final class CompactedFormatter implements Formatter
{
public function format(Tag $tag): string
Expand Down
65 changes: 65 additions & 0 deletions src/Annotation/DocblockCompactor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Annotation;

use function count;
use function str_repeat;
use function substr_count;

/**
* @private
*/
final class DocblockCompactor
{
private $annotationParser;

public function __construct(DocblockAnnotationParser $annotationParser)
{
$this->annotationParser = $annotationParser;
}

public function compact(string $docblock): string
{
if (false === strpos($docblock, '@')) {
return str_repeat("\n", substr_count($docblock, "\n"));
}

$breaksNbr = substr_count($docblock, "\n");

$annotations = $this->annotationParser->parse($docblock);

if ([] === $annotations) {
return str_repeat("\n", $breaksNbr);
}

$compactedDocblock = '/**';

foreach ($annotations as $annotation) {
$compactedDocblock .= "\n".$annotation;
}

$breaksNbr -= count($annotations);

if ($breaksNbr > 0) {
$compactedDocblock .= str_repeat("\n", $breaksNbr - 1);
$compactedDocblock .= "\n*/";
} else {
// A space is required here to avoid having /***/
$compactedDocblock .= ' */';
}

return $compactedDocblock;
}
}
100 changes: 5 additions & 95 deletions src/Compactor/Php.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,117 +14,27 @@

namespace KevinGH\Box\Compactor;

use function count;
use function in_array;
use function is_string;
use KevinGH\Box\Annotation\DocblockAnnotationParser;
use KevinGH\Box\Annotation\InvalidToken;
use function preg_replace;
use RuntimeException;
use function str_repeat;
use function strpos;
use function substr_count;
use const T_COMMENT;
use const T_DOC_COMMENT;
use const T_WHITESPACE;
use function token_get_all;
use KevinGH\Box\Compactor\Php\PhpVersionCompactor;

/**
* A PHP source code compactor copied from Composer.
*
* @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
*
* @author Kevin Herrera <[email protected]>
* @author Fabien Potencier <[email protected]>
* @author Jordi Boggiano <[email protected]>
* @author Théo Fidry <[email protected]>
* @private
*/
final class Php extends FileExtensionCompactor
{
private $annotationParser;
private $phpVersionCompactor;

/**
* {@inheritdoc}
*/
public function __construct(DocblockAnnotationParser $annotationParser, array $extensions = ['php'])
public function __construct(PhpVersionCompactor $phpVersionCompactor, array $extensions = ['php'])
{
parent::__construct($extensions);

$this->annotationParser = $annotationParser;
$this->phpVersionCompactor = $phpVersionCompactor;
}

/**
* {@inheritdoc}
*/
protected function compactContent(string $contents): string
{
$output = '';

foreach (token_get_all($contents) as $token) {
if (is_string($token)) {
$output .= $token;
} elseif (in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
if (false !== strpos($token[1], '@')) {
try {
$output .= $this->compactAnnotations($token[1]);
} catch (InvalidToken $exception) {
// This exception is due to the dumper to be out of sync with the current grammar and/or the
// grammar being incomplete. In both cases throwing here is better in order to identify and
// this those cases instead of silently failing.

throw $exception;
} catch (RuntimeException $exception) {
$output .= $token[1];
}
} else {
$output .= str_repeat("\n", substr_count($token[1], "\n"));
}
} elseif (T_WHITESPACE === $token[0]) {
// reduce wide spaces
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);

// normalize newlines to \n
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);

// trim leading spaces
$whitespace = preg_replace('{\n +}', "\n", $whitespace);

$output .= $whitespace;
} else {
$output .= $token[1];
}
}

return $output;
}

private function compactAnnotations(string $docblock): string
{
$breaksNbr = substr_count($docblock, "\n");

$annotations = $this->annotationParser->parse($docblock);

if ([] === $annotations) {
return str_repeat("\n", $breaksNbr);
}

$compactedDocblock = '/**';

foreach ($annotations as $annotation) {
$compactedDocblock .= "\n".$annotation;
}

$breaksNbr -= count($annotations);

if ($breaksNbr > 0) {
$compactedDocblock .= str_repeat("\n", $breaksNbr - 1);
$compactedDocblock .= "\n*/";
} else {
// A space is required here to avoid having /***/
$compactedDocblock .= ' */';
}

return $compactedDocblock;
return $this->phpVersionCompactor->compact($contents);
}
}
85 changes: 85 additions & 0 deletions src/Compactor/Php/Php7.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Compactor\Php;

use function in_array;
use function is_string;
use KevinGH\Box\Annotation\DocblockCompactor;
use function preg_replace;
use RuntimeException;
use function str_repeat;
use function strpos;
use function substr_count;
use const T_COMMENT;
use const T_DOC_COMMENT;
use const T_WHITESPACE;
use function token_get_all;

/**
* A PHP source code compactor copied from Composer.
*
* @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
*
* @author Kevin Herrera <[email protected]>
* @author Fabien Potencier <[email protected]>
* @author Jordi Boggiano <[email protected]>
* @author Théo Fidry <[email protected]>
* @private
*/
final class Php7 implements PhpVersionCompactor
{
private $docblockCompactor;

public function __construct(DocblockCompactor $docblockCompactor)
{
$this->docblockCompactor = $docblockCompactor;
}

public function compact(string $contents): string
{
$output = '';

foreach (token_get_all($contents) as $token) {
if (is_string($token)) {
$output .= $token;
} elseif (in_array($token[0], [T_COMMENT, T_DOC_COMMENT], true)) {
if (false !== strpos($token[1], '@')) {
try {
$output .= $this->docblockCompactor->compact($token[1]);
} catch (RuntimeException $exception) {
$output .= $token[1];
}
} else {
$output .= str_repeat("\n", substr_count($token[1], "\n"));
}
} elseif (T_WHITESPACE === $token[0]) {
// reduce wide spaces
$whitespace = preg_replace('{[ \t]+}', ' ', $token[1]);

// normalize newlines to \n
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);

// trim leading spaces
$whitespace = preg_replace('{\n +}', "\n", $whitespace);

$output .= $whitespace;
} else {
$output .= $token[1];
}
}

return $output;
}
}
81 changes: 81 additions & 0 deletions src/Compactor/Php/Php8.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Compactor\Php;

use KevinGH\Box\Annotation\DocblockCompactor;
use PhpToken;
use function preg_replace;
use RuntimeException;
use function str_repeat;
use function strpos;
use function substr_count;
use const T_COMMENT;
use const T_DOC_COMMENT;
use const T_WHITESPACE;

/**
* A PHP source code compactor copied from Composer.
*
* @see https://github.com/composer/composer/blob/a8df30c09be550bffc37ba540fb7c7f0383c3944/src/Composer/Compiler.php#L214
*
* @author Kevin Herrera <[email protected]>
* @author Fabien Potencier <[email protected]>
* @author Jordi Boggiano <[email protected]>
* @author Théo Fidry <[email protected]>
* @private
*/
final class Php8 implements PhpVersionCompactor
{
private $docblockCompactor;

public function __construct(DocblockCompactor $docblockCompactor)
{
$this->docblockCompactor = $docblockCompactor;
}

public function compact(string $contents): string
{
$output = '';

foreach (PhpToken::tokenize($contents) as $token) {
if ($token->is([T_COMMENT, T_DOC_COMMENT])) {
if (false !== strpos($token->text, '@')) {
try {
$output .= $this->docblockCompactor->compact($token->text);
} catch (RuntimeException $exception) {
$output .= $token[1];
}
} else {
$output .= str_repeat("\n", substr_count($token->text, "\n"));
}
} elseif ($token->is(T_WHITESPACE)) {
// reduce wide spaces
$whitespace = preg_replace('{[ \t]+}', ' ', $token->text);

// normalize newlines to \n
$whitespace = preg_replace('{(?:\r\n|\r|\n)}', "\n", $whitespace);

// trim leading spaces
$whitespace = preg_replace('{\n +}', "\n", $whitespace);

$output .= $whitespace;
} else {
$output .= $token->text;
}
}

return $output;
}
}
20 changes: 20 additions & 0 deletions src/Compactor/Php/PhpVersionCompactor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

/*
* This file is part of the box project.
*
* (c) Kevin Herrera <[email protected]>
* Théo Fidry <[email protected]>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace KevinGH\Box\Compactor\Php;

interface PhpVersionCompactor
{
public function compact(string $contents): string;
}
Loading

0 comments on commit 00d2f96

Please sign in to comment.