diff --git a/src/AssetMapper/SassCssCompiler.php b/src/AssetMapper/SassCssCompiler.php index 8270e82..fcc520a 100644 --- a/src/AssetMapper/SassCssCompiler.php +++ b/src/AssetMapper/SassCssCompiler.php @@ -36,7 +36,9 @@ public function supports(MappedAsset $asset): bool public function compile(string $content, MappedAsset $asset, AssetMapperInterface $assetMapper): string { - $cssFile = $this->sassBuilder->guessCssNameFromSassFile($asset->sourcePath, $this->cssPathDirectory); + $fileName = $this->sassBuilder->getIdentifierByLogicalPath($asset->logicalPath); + + $cssFile = SassBuilder::guessCssNameFromSassFile($asset->sourcePath, $this->cssPathDirectory, $fileName); $asset->addFileDependency($cssFile); diff --git a/src/DependencyInjection/SymfonycastsSassExtension.php b/src/DependencyInjection/SymfonycastsSassExtension.php index c07d9a4..9439207 100644 --- a/src/DependencyInjection/SymfonycastsSassExtension.php +++ b/src/DependencyInjection/SymfonycastsSassExtension.php @@ -61,7 +61,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->validate() ->ifTrue(static function (array $paths): bool { - if (1 === \count($paths)) { + if (1 === \count($paths) || !array_is_list($paths)) { return false; } diff --git a/src/SassBuilder.php b/src/SassBuilder.php index c200a9c..0becd01 100644 --- a/src/SassBuilder.php +++ b/src/SassBuilder.php @@ -71,12 +71,12 @@ public function runBuild(bool $watch): Process public function getScssCssTargets(): array { $targets = []; - foreach ($this->sassPaths as $sassPath) { + foreach ($this->sassPaths as $fileName => $sassPath) { if (!is_file($sassPath)) { throw new \Exception(sprintf('Could not find Sass file: "%s"', $sassPath)); } - $targets[] = $sassPath.':'.$this->guessCssNameFromSassFile($sassPath, $this->cssPath); + $targets[] = $sassPath.':'.self::guessCssNameFromSassFile($sassPath, $this->cssPath, $fileName); } return $targets; @@ -90,13 +90,34 @@ public function setOutput(SymfonyStyle $output): void /** * @internal */ - public static function guessCssNameFromSassFile(string $sassFile, string $outputDirectory): string + public static function guessCssNameFromSassFile(string $sassFile, string $outputDirectory, string|int $fileName = null): string { - $fileName = basename($sassFile, '.scss'); + if (null === $fileName || \is_int($fileName)) { + $fileName = basename($sassFile, '.scss'); + } return $outputDirectory.'/'.$fileName.'.output.css'; } + public function getIdentifierByLogicalPath(string $path): ?string + { + if (array_is_list($this->sassPaths)) { + return null; + } + + foreach ($this->sassPaths as $identifier => $configuredSassPath) { + // as the configured paths include the project dir, we need to subtract it to be able to compare the paths + $pathPrefix = $this->projectRootDir.'/assets/'; + $logicalPath = substr($configuredSassPath, \strlen($pathPrefix)); + + if ($path === $logicalPath) { + return $identifier; + } + } + + return null; + } + private function createBinary(): SassBinary { return new SassBinary($this->projectRootDir.'/var', $this->binaryPath, $this->output); diff --git a/tests/AssetMapper/SassCssCompilerTest.php b/tests/AssetMapper/SassCssCompilerTest.php new file mode 100644 index 0000000..3a4ead8 --- /dev/null +++ b/tests/AssetMapper/SassCssCompilerTest.php @@ -0,0 +1,120 @@ + + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfonycasts\SassBundle\Tests\AssetMapper; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\AssetMapper\AssetMapperInterface; +use Symfony\Component\AssetMapper\MappedAsset; +use Symfonycasts\SassBundle\AssetMapper\SassCssCompiler; +use Symfonycasts\SassBundle\SassBuilder; + +final class SassCssCompilerTest extends TestCase +{ + private const CSS_DIR = __DIR__.'/../fixtures/var/sass'; + + protected function setUp(): void + { + if (!is_dir(self::CSS_DIR)) { + mkdir(self::CSS_DIR, 0777, true); + } + } + + public function testCompileSingleSassPath(): void + { + $scssFile = __DIR__.'/../fixtures/assets/app.scss'; + $scssPaths = [ + $scssFile, + ]; + $cssFile = self::CSS_DIR.'/app.output.css'; + + $compiler = new SassCssCompiler( + $scssPaths, + self::CSS_DIR, + $this->createSassBuilder($scssPaths) + ); + + $mappedAsset = new MappedAsset( + 'app.scss', + $scssFile, + 'app.css' + ); + + file_put_contents($cssFile, <<compile( + file_get_contents($scssFile), + $mappedAsset, + $this->createMock(AssetMapperInterface::class) + ); + + $this->assertStringEqualsFile( + $cssFile, + $compiledContent + ); + } + + public function testCompileNamedSassPath() + { + $scssFile = __DIR__.'/../fixtures/assets/admin/app.scss'; + + $scssPaths = [ + 'admin' => $scssFile, + ]; + $cssFile = self::CSS_DIR.'/admin.output.css'; + + $compiler = new SassCssCompiler( + $scssPaths, + self::CSS_DIR, + $this->createSassBuilder($scssPaths) + ); + + $mappedAsset = new MappedAsset( + 'admin/app.scss', + $scssFile, + 'admin.css' + ); + + file_put_contents($cssFile, <<compile( + file_get_contents($scssFile), + $mappedAsset, + $this->createMock(AssetMapperInterface::class) + ); + + $this->assertStringEqualsFile( + $cssFile, + $compiledContent + ); + } + + private function createSassBuilder(array $sassPaths): SassBuilder + { + return new SassBuilder( + $sassPaths, + self::CSS_DIR, + __DIR__.'/../fixtures', + null, + false + ); + } +} diff --git a/tests/ConfigurationTest.php b/tests/DependencyInjection/ConfigurationTest.php similarity index 80% rename from tests/ConfigurationTest.php rename to tests/DependencyInjection/ConfigurationTest.php index f1b724e..6575a3e 100644 --- a/tests/ConfigurationTest.php +++ b/tests/DependencyInjection/ConfigurationTest.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfonycasts\SassBundle\Tests; +namespace Symfonycasts\SassBundle\Tests\DependencyInjection; use Matthias\SymfonyConfigTest\PhpUnit\ConfigurationTestCaseTrait; use PHPUnit\Framework\TestCase; @@ -47,6 +47,18 @@ public function testMultipleSassRootPaths(): void ]); } + public function testMultipleSassRootPathsWithIdentifier(): void + { + $this->assertConfigurationIsValid([ + 'symfonycasts_sass' => [ + 'root_sass' => [ + 'website' => '%kernel.project_dir%/assets/scss/app.scss', + 'admin' => '%kernel.project_dir%/assets/admin/scss/app.scss', + ], + ], + ]); + } + public function testMultipleSassRootPathsWithSameFilename(): void { $this->assertConfigurationIsInvalid([ diff --git a/tests/SassBuilderTest.php b/tests/SassBuilderTest.php index a651d96..ac86fa3 100644 --- a/tests/SassBuilderTest.php +++ b/tests/SassBuilderTest.php @@ -16,8 +16,14 @@ class SassBuilderTest extends TestCase { protected function tearDown(): void { - unlink(__DIR__.'/fixtures/assets/app.output.css'); - unlink(__DIR__.'/fixtures/assets/app.output.css.map'); + @unlink(__DIR__.'/fixtures/assets/app.output.css'); + @unlink(__DIR__.'/fixtures/assets/app.output.css.map'); + + @unlink(__DIR__.'/fixtures/assets/foo.output.css'); + @unlink(__DIR__.'/fixtures/assets/foo.output.css.map'); + + @unlink(__DIR__.'/fixtures/assets/bar.output.css'); + @unlink(__DIR__.'/fixtures/assets/bar.output.css.map'); } public function testIntegration(): void @@ -37,4 +43,27 @@ public function testIntegration(): void $this->assertFileExists(__DIR__.'/fixtures/assets/app.output.css'); $this->assertStringContainsString('color: red;', file_get_contents(__DIR__.'/fixtures/assets/app.output.css')); } + + public function testPathsConfigWithKeys(): void + { + $builder = new SassBuilder( + [ + 'foo' => __DIR__.'/fixtures/assets/app.scss', + 'bar' => __DIR__.'/fixtures/assets/admin/app.scss', + ], + __DIR__.'/fixtures/assets', + __DIR__.'/fixtures', + null, + false + ); + + $process = $builder->runBuild(false); + $process->wait(); + + $this->assertTrue($process->isSuccessful()); + $this->assertFileExists(__DIR__.'/fixtures/assets/foo.output.css'); + $this->assertFileExists(__DIR__.'/fixtures/assets/bar.output.css'); + $this->assertStringContainsString('color: red;', file_get_contents(__DIR__.'/fixtures/assets/foo.output.css')); + $this->assertStringContainsString('color: blue;', file_get_contents(__DIR__.'/fixtures/assets/bar.output.css')); + } } diff --git a/tests/fixtures/assets/admin/app.scss b/tests/fixtures/assets/admin/app.scss new file mode 100644 index 0000000..6b583f9 --- /dev/null +++ b/tests/fixtures/assets/admin/app.scss @@ -0,0 +1,5 @@ +$color: blue; + +p { + color: $color; +}