Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
/.php-cs-fixer.cache
/composer.lock
/phpunit.xml
/tests/Fixtures/config/
Comment thread
smnandre marked this conversation as resolved.
/tests/Fixtures/var/
/vendor/
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# CHANGELOG

## 1.3.0

- Add HTML support (`MinifierInterface::TYPE_HTML`)
- Add options support to `MinifierInterface::minify()` via a third, optional `OptionsInterface` argument. This argument will become part of the signature in 2.0.

## 1.2.0

- Add Symfony 8 support
Comment thread
smnandre marked this conversation as resolved.

## 1.1.0

- Support for PHP 8.1.0 or higher
Expand Down
11 changes: 11 additions & 0 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
parameters:
ignoreErrors:
-
message: "#^PHPDoc tag @param references unknown parameter\\: \\$options$#"
count: 1
path: src/Minifier/MinifierInterface.php

-
message: "#^Method Sensiolabs\\\\MinifyBundle\\\\Minifier\\\\MinifierInterface\\:\\:minify\\(\\) invoked with 3 parameters, 2 required\\.$#"
count: 1
path: src/Minifier/TraceableMinifier.php
3 changes: 3 additions & 0 deletions phpstan.dist.neon
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
includes:
- phpstan-baseline.neon

parameters:
level: 9
paths:
Expand Down
8 changes: 6 additions & 2 deletions src/Minifier/MinifierInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@

namespace Sensiolabs\MinifyBundle\Minifier;

use Sensiolabs\MinifyBundle\Minifier\Options\OptionsInterface;

/**
* @author Simon André <smn.andre@gmail.com>
*/
interface MinifierInterface
{
public const TYPE_CSS = 'css';
public const TYPE_JS = 'js';
public const TYPE_HTML = 'html';

/**
* @param self::TYPE_CSS|self::TYPE_JS $type
* @param self::TYPE_CSS|self::TYPE_JS|self::TYPE_HTML $type
* @param OptionsInterface|null $options
*/
public function minify(string $input, string $type): string;
public function minify(string $input, string $type/* , ?OptionsInterface $options = null */): string;
}
45 changes: 45 additions & 0 deletions src/Minifier/Options/HtmlOptions.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

/*
* This file is part of the SensioLabs MinifyBundle package.
*
* (c) Simon André - Sensiolabs
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sensiolabs\MinifyBundle\Minifier\Options;

use Sensiolabs\MinifyBundle\Minifier\MinifierInterface;

/**
* @author Hugo Alliaume <hugo@alliau.me>
*/
final class HtmlOptions implements OptionsInterface
{
/**
* @param bool $keepDocumentTags preserve html, head and body tags
*/
public function __construct(
public readonly bool $keepDocumentTags = false,
) {
}

public function getType(): string
{
return MinifierInterface::TYPE_HTML;
}

public function toCliArgs(): array
{
$args = [];
if ($this->keepDocumentTags) {
$args[] = '--html-keep-document-tags';
}

return $args;
}
}
32 changes: 32 additions & 0 deletions src/Minifier/Options/OptionsInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

declare(strict_types=1);

/*
* This file is part of the SensioLabs MinifyBundle package.
*
* (c) Simon André - Sensiolabs
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sensiolabs\MinifyBundle\Minifier\Options;

use Sensiolabs\MinifyBundle\Minifier\MinifierInterface;

/**
* @author Hugo Alliaume <hugo@alliau.me>
*/
interface OptionsInterface
Comment thread
smnandre marked this conversation as resolved.
{
/**
* @return MinifierInterface::TYPE_*
*/
public function getType(): string;

/**
* @return list<string>
*/
public function toCliArgs(): array;
}
6 changes: 4 additions & 2 deletions src/Minifier/TraceableMinifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,16 +27,18 @@ public function __construct(
) {
}

public function minify(string $input, string $type): string
public function minify(string $input, string $type/* , ?OptionsInterface $options = null */): string
{
$options = \func_num_args() > 2 ? \func_get_arg(2) : null;

$inputSize = strlen($input);
$this->logger->debug('Minify command input: {inputSize} kB', [
'inputSize' => round($inputSize / 1024, 1),
'input' => $input,
]);

$timeStart = microtime(true);
$output = $this->minifier->minify($input, $type);
$output = $this->minifier->minify($input, $type, $options);
$timeEnd = microtime(true);

$outputSize = strlen($output);
Expand Down
18 changes: 16 additions & 2 deletions src/Minify.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

use Sensiolabs\MinifyBundle\Exception\RuntimeException;
use Sensiolabs\MinifyBundle\Minifier\MinifierInterface;
use Sensiolabs\MinifyBundle\Minifier\Options\OptionsInterface;
use Symfony\Component\Process\Process;

/**
Expand All @@ -27,9 +28,22 @@ public function __construct(
) {
}

public function minify(string $input, string $type): string
public function minify(string $input, string $type/* , ?OptionsInterface $options = null */): string

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a comment / deprecartion here, this feels so legit i'd agree to release a 2.0 there if we generalise this

{
$process = new Process([$this->binaryPath, '--type', $type]);
$options = \func_num_args() > 2 ? \func_get_arg(2) : null;
if (null !== $options && !$options instanceof OptionsInterface) {
throw new RuntimeException(sprintf('Expected $options to be an instance of "%s", got "%s".', OptionsInterface::class, get_debug_type($options)));
}
if (null !== $options && $options->getType() !== $type) {
throw new RuntimeException(sprintf('Options type "%s" does not match minify type "%s".', $options->getType(), $type));
}

$args = [$this->binaryPath, '--type', $type];
if (null !== $options) {
$args = [...$args, ...$options->toCliArgs()];
}

$process = new Process($args);
$process->setInput($input);

try {
Expand Down
14 changes: 10 additions & 4 deletions tests/Fixtures/bin/fakify
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ if (!isset($argv[1]) || '--type' !== $argv[1] || !isset($argv[2])) {
echo 'ERROR: Missing type argument.';
exit(1);
}
if (!in_array($argv[2], ['css', 'js'])) {
if (!in_array($argv[2], ['css', 'js', 'html'])) {
echo 'ERROR: Invalid type argument.';
exit(1);
}
Expand All @@ -15,14 +15,20 @@ $input = file_get_contents('php://stdin');

if ('css' === $typeArg) {
file_put_contents('php://stdout', $input);


return;
}

if ('html' === $typeArg) {
$extraArgs = array_slice($argv, 3);
file_put_contents('php://stdout', $input.'|args='.implode(' ', $extraArgs));

return;
}

if ('js' === $typeArg) {
// file_put_contents('php://stdout', $input);
exit(20000000);

return;
}

41 changes: 41 additions & 0 deletions tests/Minifier/Options/HtmlOptionsTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/*
* This file is part of the SensioLabs MinifyBundle package.
*
* (c) Simon André - Sensiolabs
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Sensiolabs\MinifyBundle\Tests\Minifier\Options;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Sensiolabs\MinifyBundle\Minifier\MinifierInterface;
use Sensiolabs\MinifyBundle\Minifier\Options\HtmlOptions;

#[CoversClass(HtmlOptions::class)]
class HtmlOptionsTest extends TestCase
{
public function testGetTypeReturnsHtml(): void
{
$this->assertSame(MinifierInterface::TYPE_HTML, (new HtmlOptions())->getType());
}

public function testToCliArgsIsEmptyByDefault(): void
{
$this->assertSame([], (new HtmlOptions())->toCliArgs());
}

public function testToCliArgsIncludesKeepDocumentTagsFlag(): void
{
$this->assertSame(
['--html-keep-document-tags'],
(new HtmlOptions(keepDocumentTags: true))->toCliArgs(),
);
}
}
15 changes: 15 additions & 0 deletions tests/Minifier/TraceableMinifierTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
use Sensiolabs\MinifyBundle\Minifier\MinifierInterface;
use Sensiolabs\MinifyBundle\Minifier\Options\HtmlOptions;
use Sensiolabs\MinifyBundle\Minifier\TraceableMinifier;

#[CoversClass(TraceableMinifier::class)]
Expand Down Expand Up @@ -64,6 +65,20 @@ public function testMinifyHandlesEmptyInput(): void
$this->assertSame('', $traceableMinifier->minify('', 'css'));
}

public function testMinifyForwardsOptionsToInnerMinifier(): void
{
$options = new HtmlOptions(keepDocumentTags: true);

$minifier = $this->createMock(MinifierInterface::class);
$minifier->expects($this->once())
->method('minify')
->with('input content', 'html', $options)
->willReturn('minified content');

$traceableMinifier = new TraceableMinifier($minifier);
$this->assertSame('minified content', $traceableMinifier->minify('input content', 'html', $options));
}

public function testMinifyHandlesExceptionFromMinifier(): void
{
$this->expectException(\RuntimeException::class);
Expand Down
26 changes: 26 additions & 0 deletions tests/MinifyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\TestCase;
use Sensiolabs\MinifyBundle\Exception\RuntimeException;
use Sensiolabs\MinifyBundle\Minifier\Options\HtmlOptions;
use Sensiolabs\MinifyBundle\Minify;
use Symfony\Component\Filesystem\Filesystem;

Expand Down Expand Up @@ -57,4 +58,29 @@ public function testMinifyThrowsRuntimeExceptionOnProcessFailure(): void

$minify->minify('input content', 'foo');
}

public function testMinifyForwardsOptionsCliArgs(): void
{
$minify = new Minify(self::FIXTURES_BINARY_PATH);
$output = $minify->minify('<html></html>', 'html', new HtmlOptions(keepDocumentTags: true));

$this->assertSame('<html></html>|args=--html-keep-document-tags', $output);
}

public function testMinifyPassesNoExtraArgsWhenOptionsHaveNoFlags(): void
{
$minify = new Minify(self::FIXTURES_BINARY_PATH);
$output = $minify->minify('<html></html>', 'html', new HtmlOptions());

$this->assertSame('<html></html>|args=', $output);
}

public function testMinifyThrowsWhenOptionsTypeDoesNotMatch(): void
{
$this->expectException(RuntimeException::class);
$this->expectExceptionMessage('Options type "html" does not match minify type "css".');

$minify = new Minify(self::FIXTURES_BINARY_PATH);
$minify->minify('input', 'css', new HtmlOptions());
}
}
Loading