diff --git a/.dev/phpcs.xml b/.dev/phpcs.xml
new file mode 100644
index 0000000..5821512
--- /dev/null
+++ b/.dev/phpcs.xml
@@ -0,0 +1,285 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.dev/phpstan/phpstan.neon b/.dev/phpstan/phpstan.neon
new file mode 100755
index 0000000..eefcbfc
--- /dev/null
+++ b/.dev/phpstan/phpstan.neon
@@ -0,0 +1,25 @@
+parameters:
+ tmpDir: %currentWorkingDirectory%/temp/phpstan/
+
+ paths:
+ - %currentWorkingDirectory%/src/
+ - %currentWorkingDirectory%/tests/
+
+ excludePaths:
+ - %currentWorkingDirectory%/tests/temp/*
+
+ level: 8
+
+ ignoreErrors:
+ -
+ message: '#Parameter \#1 \$filter of method WebLoader\\Compiler::addFilter\(\) expects callable\(\): mixed, 4 given\.#'
+ path: %currentWorkingDirectory%/tests/CompilerTest.php
+ -
+ message: '#Parameter \#1 \$filter of method WebLoader\\Compiler::addFileFilter\(\) expects callable\(\): mixed, 4 given\.#'
+ path: %currentWorkingDirectory%/tests/CompilerTest.php
+ -
+ message: '#Access to an undefined property WebLoader\\Filter\\VariablesFilter::\$bar\.#'
+ path: %currentWorkingDirectory%/tests/Filter/VariablesFilterTest.php
+ -
+ message: '#Property WebLoader\\Nette\\Diagnostics\\Panel::\$root is never read, only written.#'
+ path: %currentWorkingDirectory%/src/Nette/Diagnostics/Panel.php
diff --git a/.editorconfig b/.editorconfig
new file mode 100755
index 0000000..fb6c057
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,14 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+indent_style = tab
+indent_size = 3
+charset = utf-8
+trim_trailing_whitespace = true
+
+[{*.svg,.htaccess,*.expected}]
+insert_final_newline = false
diff --git a/.gitignore b/.gitignore
index 45bdece..bfbbf45 100755
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,16 @@
-vendor
+# Masks
+*.bak
+
+# Files
composer.lock
-.idea
-.editorconfig
+.phpunit.result.cache
+tests/.phpunit.cache/
+
+# Dirs
+vendor/
+temp/
+.idea/
+
+# Custom
+run
+composer.phar
diff --git a/README.md b/README.md
index 354ab36..b52187f 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,13 @@
-WebLoader [](http://travis-ci.org/janmarek/WebLoader)
+WebLoader
=======================
-Component for CSS and JS files loading
+Component for CSS and JS files loading.
-Author: Jan Marek
+Author: [Jan Marek](https://github.com/janmarek)
Licence: MIT
+Updated for Nette 3/3.1 and PHP 8.0 by [Gappa](https://github.com/Gappa).
+
Example
-------
@@ -75,9 +77,6 @@ webloader:
js:
default:
- remoteFiles:
- - http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js
- - http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js
files:
- %appDir%/../libs/nette/nette/client-side/netteForms.js
- web.js
diff --git a/WebLoader/File.php b/WebLoader/File.php
deleted file mode 100644
index bc21f6a..0000000
--- a/WebLoader/File.php
+++ /dev/null
@@ -1,47 +0,0 @@
-file = $file;
- $this->lastModified = $lastModified;
- $this->sourceFiles = $sourceFiles;
- }
-
-
- public function getFile(): string
- {
- return $this->file;
- }
-
-
- public function getLastModified(): ?int
- {
- return $this->lastModified;
- }
-
-
- public function getSourceFiles(): array
- {
- return $this->sourceFiles;
- }
-}
diff --git a/WebLoader/FileNotFoundException.php b/WebLoader/FileNotFoundException.php
deleted file mode 100644
index bda3b4b..0000000
--- a/WebLoader/FileNotFoundException.php
+++ /dev/null
@@ -1,14 +0,0 @@
-bin = $bin;
- }
-
-
- public function __invoke(string $code, Compiler $loader, ?string $file = null): string
- {
- $file = (string) $file;
-
- if (pathinfo($file, PATHINFO_EXTENSION) === 'coffee') {
- $code = $this->compileCoffee($code);
- }
-
- return $code;
- }
-
-
- public function compileCoffee(string $source, ?bool $bare = null): string
- {
- if ($bare === null) {
- $bare = $this->bare;
- }
-
- $cmd = $this->bin . ' -p -s' . ($bare ? ' -b' : '');
-
- return Process::run($cmd, $source);
- }
-}
diff --git a/WebLoader/Filter/LessFilter.php b/WebLoader/Filter/LessFilter.php
deleted file mode 100644
index c775d48..0000000
--- a/WebLoader/Filter/LessFilter.php
+++ /dev/null
@@ -1,51 +0,0 @@
-lc = $lc;
- }
-
-
- private function getLessC(): lessc
- {
- // lazy loading
- if (empty($this->lc)) {
- $this->lc = new lessc();
- }
-
- return clone $this->lc;
- }
-
-
- /**
- * Invoke filter
- */
- public function __invoke(string $code, Compiler $loader, string $file): string
- {
- if (pathinfo($file, PATHINFO_EXTENSION) === 'less') {
- $lessc = $this->getLessC();
- $lessc->importDir = pathinfo($file, PATHINFO_DIRNAME) . '/';
- return $lessc->compile($code);
- }
-
- return $code;
- }
-}
diff --git a/WebLoader/Filter/PHPCoffeeScriptFilter.php b/WebLoader/Filter/PHPCoffeeScriptFilter.php
deleted file mode 100644
index 988022f..0000000
--- a/WebLoader/Filter/PHPCoffeeScriptFilter.php
+++ /dev/null
@@ -1,38 +0,0 @@
-compileCoffee($code, $file);
- }
-
- return $code;
- }
-
-
- public function compileCoffee(string $source, ?string $file): string
- {
- try {
- return Compiler::compile($source, ['filename' => $file]);
- } catch (Throwable $e) {
- throw new WebLoaderException('CoffeeScript Filter Error: ' . $e->getMessage(), 0, $e);
- }
- }
-}
diff --git a/WebLoader/Filter/ScssFilter.php b/WebLoader/Filter/ScssFilter.php
deleted file mode 100644
index 6a61483..0000000
--- a/WebLoader/Filter/ScssFilter.php
+++ /dev/null
@@ -1,50 +0,0 @@
-sc = $sc;
- }
-
-
- private function getScssC(): Compiler
- {
- // lazy loading
- if (empty($this->sc)) {
- $this->sc = new Compiler();
- }
-
- return $this->sc;
- }
-
-
- public function __invoke(string $code, \WebLoader\Compiler $loader, string $file): string
- {
- $file = (string) $file;
-
- if (pathinfo($file, PATHINFO_EXTENSION) === 'scss') {
- $this->getScssC()->setImportPaths(['', pathinfo($file, PATHINFO_DIRNAME) . '/']);
- return $this->getScssC()->compile($code);
- }
-
- return (string) $code;
- }
-}
diff --git a/WebLoader/InvalidArgumentException.php b/WebLoader/InvalidArgumentException.php
deleted file mode 100644
index 9303a36..0000000
--- a/WebLoader/InvalidArgumentException.php
+++ /dev/null
@@ -1,14 +0,0 @@
-
- */
-class CompilationException extends \WebLoader\WebLoaderException
-{
-}
diff --git a/WebLoader/Nette/Extension.php b/WebLoader/Nette/Extension.php
deleted file mode 100755
index 20ce4d4..0000000
--- a/WebLoader/Nette/Extension.php
+++ /dev/null
@@ -1,277 +0,0 @@
- Expect::structure([
- 'checkLastModified' => Expect::bool(true),
- 'debug' => Expect::bool(false),
- 'sourceDir' => Expect::string('%wwwDir%/js'),
- 'tempDir' => Expect::string('%wwwDir%/' . self::DEFAULT_TEMP_PATH),
- 'tempPath' => Expect::string(self::DEFAULT_TEMP_PATH),
- 'files' => Expect::array(),
- 'watchFiles' => Expect::array(),
- 'remoteFiles' => Expect::array(),
- 'filters' => Expect::array(),
- 'fileFilters' => Expect::array(),
- 'joinFiles' => Expect::bool(true),
- 'async' => Expect::bool(false),
- 'defer' => Expect::bool(false),
- 'nonce' => Expect::string()->nullable(),
- 'absoluteUrl' => Expect::bool(false),
- 'namingConvention' => Expect::string('@' . $this->prefix('jsNamingConvention')),
- ]),
- 'cssDefaults' => Expect::structure([
- 'checkLastModified' => Expect::bool(true),
- 'debug' => Expect::bool(false),
- 'sourceDir' => Expect::string('%wwwDir%/css')->dynamic(),
- 'tempDir' => Expect::string('%wwwDir%/' . self::DEFAULT_TEMP_PATH),
- 'tempPath' => Expect::string(self::DEFAULT_TEMP_PATH),
- 'files' => Expect::array(),
- 'watchFiles' => Expect::array(),
- 'remoteFiles' => Expect::array(),
- 'filters' => Expect::array(),
- 'fileFilters' => Expect::array(),
- 'joinFiles' => Expect::bool(true),
- 'async' => Expect::bool(false),
- 'defer' => Expect::bool(false),
- 'nonce' => Expect::string()->nullable(),
- 'absoluteUrl' => Expect::bool(false),
- 'namingConvention' => Expect::string('@' . $this->prefix('cssNamingConvention')),
- ]),
- 'js' => Expect::array(),
- 'css' => Expect::array(),
- 'debugger' => Expect::bool('%debugMode%'),
- ]);
- }
-
-
- public function loadConfiguration(): void
- {
- $builder = $this->getContainerBuilder();
-
- $params = $this->getContainerBuilder()->parameters;
- $json = json_encode($this->getConfig());
- $config = json_decode((string) $json, true);
- $config = Helpers::expand($config, $params);
-
- $builder->addDefinition($this->prefix('cssNamingConvention'))
- ->setFactory('WebLoader\DefaultOutputNamingConvention::createCssConvention');
-
- $builder->addDefinition($this->prefix('jsNamingConvention'))
- ->setFactory('WebLoader\DefaultOutputNamingConvention::createJsConvention');
-
- if ($config['debugger']) {
- $builder->addDefinition($this->prefix('tracyPanel'))
- ->setClass('WebLoader\Nette\Diagnostics\Panel')
- ->setArguments([$params['appDir']]);
- }
-
- $builder->parameters['webloader'] = $config;
-
- $loaderFactoryTempPaths = [];
-
- foreach (['css', 'js'] as $type) {
- foreach ($config[$type] as $name => $wlConfig) {
- /** @var array $wlConfig */
- $wlConfig = \Nette\Schema\Helpers::merge($wlConfig, $config[$type . 'Defaults']);
- $this->addWebLoader($builder, $type . ucfirst($name), $wlConfig);
- $loaderFactoryTempPaths[strtolower($name)] = $wlConfig['tempPath'];
-
- if (!is_dir($wlConfig['tempDir']) || !is_writable($wlConfig['tempDir'])) {
- throw new CompilationException(sprintf("You must create a writable directory '%s'", $wlConfig['tempDir']));
- }
- }
- }
-
- $builder->addDefinition($this->prefix('factory'))
- ->setFactory('WebLoader\Nette\LoaderFactory', [$loaderFactoryTempPaths, $this->name]);
-
- if (class_exists('Symfony\Component\Console\Command\Command')) {
- $builder->addDefinition($this->prefix('generateCommand'))
- ->setClass('WebLoader\Nette\SymfonyConsole\GenerateCommand')
- ->addTag('kdyby.console.command');
- }
- }
-
-
- private function addWebLoader(ContainerBuilder $builder, string $name, array $config): void
- {
- $filesServiceName = $this->prefix($name . 'Files');
-
- $files = $builder->addDefinition($filesServiceName)
- ->setClass('WebLoader\FileCollection')
- ->setArguments([$config['sourceDir']]);
-
- foreach ($this->findFiles($config['files'], $config['sourceDir']) as $file) {
- $files->addSetup('addFile', [$file]);
- }
-
- foreach ($this->findFiles($config['watchFiles'], $config['sourceDir']) as $file) {
- $files->addSetup('addWatchFile', [$file]);
- }
-
- $files->addSetup('addRemoteFiles', [$config['remoteFiles']]);
-
- $compiler = $builder->addDefinition($this->prefix($name . 'Compiler'))
- ->setClass('WebLoader\Compiler')
- ->setArguments([
- '@' . $filesServiceName,
- $config['namingConvention'],
- $config['tempDir'],
- ]);
-
- $compiler
- ->addSetup('setJoinFiles', [$config['joinFiles']])
- ->addSetup('setAsync', [$config['async']])
- ->addSetup('setDefer', [$config['defer']])
- ->addSetup('setNonce', [$config['nonce']])
- ->addSetup('setAbsoluteUrl', [$config['absoluteUrl']]);
-
- if ($builder->parameters['webloader']['debugger']) {
- $compiler->addSetup('@' . $this->prefix('tracyPanel') . '::addLoader', [
- $name,
- '@' . $this->prefix($name . 'Compiler'),
- ]);
- }
-
- foreach ($config['filters'] as $filter) {
- $compiler->addSetup('addFilter', [$filter]);
- }
-
- foreach ($config['fileFilters'] as $filter) {
- $compiler->addSetup('addFileFilter', [$filter]);
- }
-
- if (isset($config['debug']) && $config['debug']) {
- $compiler->addSetup('enableDebugging');
- }
-
- $compiler->addSetup('setCheckLastModified', [$config['checkLastModified']]);
-
- // todo css media
- }
-
-
- // I have no clue what this is supposed to do...
- // public function afterCompile(Nette\PhpGenerator\ClassType $class): void
- // {
- // $meta = $class->getProperty('meta');
- // if (array_key_exists('webloader\\nette\\loaderfactory', $meta->value['types'])) {
- // $meta->value['types']['webloader\\loaderfactory'] = $meta->value['types']['webloader\\nette\\loaderfactory'];
- // }
- // if (array_key_exists('WebLoader\\Nette\\LoaderFactory', $meta->value['types'])) {
- // $meta->value['types']['WebLoader\\LoaderFactory'] = $meta->value['types']['WebLoader\\Nette\\LoaderFactory'];
- // }
- //
- // $init = $class->methods['initialize'];
- // $init->addBody('if (!class_exists(?, ?)) class_alias(?, ?);', ['WebLoader\\LoaderFactory', false, 'WebLoader\\Nette\\LoaderFactory', 'WebLoader\\LoaderFactory']);
- // }
-
-
- public function install(Configurator $configurator): void
- {
- $self = $this;
- $configurator->onCompile[] = function ($configurator, Compiler $compiler) use ($self): void {
- $compiler->addExtension($self::EXTENSION_NAME, $self);
- };
- }
-
-
- private function findFiles(array $filesConfig, string $sourceDir): array
- {
- $normalizedFiles = [];
-
- /** @var array|string $file */
- foreach ($filesConfig as $file) {
- // finder support
- if (is_array($file) && isset($file['files']) && (isset($file['in']) || isset($file['from']))) {
- $finder = Finder::findFiles($file['files']);
-
- if (isset($file['exclude'])) {
- $finder->exclude($file['exclude']);
- }
-
- if (isset($file['in'])) {
- $finder->in(is_dir($file['in']) ? $file['in'] : $sourceDir . DIRECTORY_SEPARATOR . $file['in']);
- } else {
- $finder->from(is_dir($file['from']) ? $file['from'] : $sourceDir . DIRECTORY_SEPARATOR . $file['from']);
- }
-
- $foundFilesList = [];
- foreach ($finder as $foundFile) {
- /** @var SplFileInfo $foundFile */
- $foundFilesList[] = $foundFile->getPathname();
- }
-
- natsort($foundFilesList);
-
- /** @var string $foundFilePathname */
- foreach ($foundFilesList as $foundFilePathname) {
- $normalizedFiles[] = $foundFilePathname;
- }
-
- } else {
- if (is_string($file)) {
- $this->checkFileExists($file, $sourceDir);
- $normalizedFiles[] = $file;
- }
- }
- }
-
- return $normalizedFiles;
- }
-
-
- protected function checkFileExists(string $file, string $sourceDir): void
- {
- if (!$this->fileExists($file)) {
- $tmp = rtrim($sourceDir, '/\\') . DIRECTORY_SEPARATOR . $file;
- if (!$this->fileExists($tmp)) {
- throw new FileNotFoundException(sprintf("Neither '%s' or '%s' was found", $file, $tmp));
- }
- }
- }
-
-
- /**
- * Some servers seem to have problems under cron user with open_basedir restriction when using relative paths
- */
- protected function fileExists(string $file): bool
- {
- $file = realpath($file);
-
- if ($file === false) {
- $file = '';
- }
-
- return file_exists($file);
- }
-}
diff --git a/WebLoader/Nette/LoaderFactory.php b/WebLoader/Nette/LoaderFactory.php
deleted file mode 100755
index 450edde..0000000
--- a/WebLoader/Nette/LoaderFactory.php
+++ /dev/null
@@ -1,59 +0,0 @@
-httpRequest = $httpRequest;
- $this->serviceLocator = $serviceLocator;
- $this->tempPaths = $tempPaths;
- $this->extensionName = $extensionName;
- }
-
-
- public function createCssLoader(string $name, bool $appendLastModified = false): CssLoader
- {
- /** @var Compiler $compiler */
- $compiler = $this->serviceLocator->getService($this->extensionName . '.css' . ucfirst($name) . 'Compiler');
- return new CssLoader($compiler, $this->formatTempPath($name, $compiler->isAbsoluteUrl()), $appendLastModified);
- }
-
-
- public function createJavaScriptLoader(string $name, bool $appendLastModified = false): JavaScriptLoader
- {
- /** @var Compiler $compiler */
- $compiler = $this->serviceLocator->getService($this->extensionName . '.js' . ucfirst($name) . 'Compiler');
- return new JavaScriptLoader($compiler, $this->formatTempPath($name, $compiler->isAbsoluteUrl()), $appendLastModified);
- }
-
-
- private function formatTempPath(string $name, $absoluteUrl = false): string
- {
- $lName = strtolower($name);
- $tempPath = isset($this->tempPaths[$lName]) ? $this->tempPaths[$lName] : Extension::DEFAULT_TEMP_PATH;
- $method = $absoluteUrl ? 'getBaseUrl' : 'getBasePath';
- return rtrim($this->httpRequest->getUrl()->{$method}(), '/') . '/' . $tempPath;
- }
-}
diff --git a/WebLoader/Nette/SymfonyConsole/GenerateCommand.php b/WebLoader/Nette/SymfonyConsole/GenerateCommand.php
deleted file mode 100755
index 7b121ba..0000000
--- a/WebLoader/Nette/SymfonyConsole/GenerateCommand.php
+++ /dev/null
@@ -1,61 +0,0 @@
-findByType(WebLoader\Compiler::class);
- foreach ($compilers as $compilerName) {
- $this->compilers[$compilerName] = $container->getService($compilerName);
- }
- }
-
-
- protected function configure(): void
- {
- $this->setName(self::$defaultName)
- ->setDescription('Generates files.')
- ->addOption('force', 'f', InputOption::VALUE_NONE, 'Generate if not modified.');
- }
-
-
- protected function execute(InputInterface $input, OutputInterface $output): void
- {
- $force = $input->getOption('force');
-
- $nofiles = true;
- foreach ($this->compilers as $compiler) {
- $files = $compiler->generate(!$force);
- foreach ($files as $file) {
- $output->writeln($file->file);
- $nofiles = false;
- }
- }
-
- if ($nofiles) {
- $output->writeln('No files generated.');
- }
- }
-}
diff --git a/WebLoader/Nette/WebLoader.php b/WebLoader/Nette/WebLoader.php
deleted file mode 100755
index a3ec962..0000000
--- a/WebLoader/Nette/WebLoader.php
+++ /dev/null
@@ -1,109 +0,0 @@
-compiler = $compiler;
- $this->tempPath = $tempPath;
- $this->appendLastModified = $appendLastModified;
- }
-
-
- public function getCompiler(): Compiler
- {
- return $this->compiler;
- }
-
-
- public function setCompiler(Compiler $compiler): void
- {
- $this->compiler = $compiler;
- }
-
-
- public function getTempPath(): string
- {
- return $this->tempPath;
- }
-
-
- public function setTempPath(string $tempPath): void
- {
- $this->tempPath = $tempPath;
- }
-
-
- /**
- * Get html element including generated content
- */
- abstract public function getElement(string $source): Html;
-
-
- /**
- * Generate compiled file(s) and render link(s)
- */
- public function render(): void
- {
- $hasArgs = func_num_args() > 0;
-
- if ($hasArgs) {
- $backup = $this->compiler->getFileCollection();
- $newFiles = new FileCollection($backup->getRoot());
- $newFiles->addFiles(func_get_args());
- $this->compiler->setFileCollection($newFiles);
- }
-
- // remote files
- foreach ($this->compiler->getFileCollection()->getRemoteFiles() as $file) {
- echo $this->getElement($file), PHP_EOL;
- }
-
- foreach ($this->compiler->generate() as $file) {
- echo $this->getElement($this->getGeneratedFilePath($file)), PHP_EOL;
- }
-
- if ($hasArgs && !empty($backup)) {
- $this->compiler->setFileCollection($backup);
- }
- }
-
-
- protected function getGeneratedFilePath(File $file)
- {
- $path = $this->tempPath . '/' . $file->getFile();
-
- if ($this->appendLastModified) {
- $path .= '?' . $file->getLastModified();
- }
-
- return $path;
- }
-}
diff --git a/WebLoader/Path.php b/WebLoader/Path.php
deleted file mode 100755
index 7b95eb6..0000000
--- a/WebLoader/Path.php
+++ /dev/null
@@ -1,29 +0,0 @@
-= 7.1",
- "nette/application": "^3.0",
+ "php": "^8.3",
+ "nette/application": "^3.1",
"nette/di": "^3.0",
- "nette/utils": "^3.0",
- "ext-json": "*"
+ "nette/utils": "^4.0",
+ "ext-json": "*",
+ "nette/schema": "^1.2",
+ "nette/finder": "^3.0",
+ "latte/latte": "^3.0",
+ "tracy/tracy": "^2.8"
},
"suggest": {
- "oyejorge/less.php": "LESS compiler written in PHP.",
- "leafo/scssphp": "SCSS compiler written in PHP.",
- "joseki/webloader-filters": "CSSMin & JSMin filters written in PHP.",
- "coffeescript/coffeescript": "CoffeeScript compiler written in PHP."
+ "wikimedia/less.php": "LESS compiler written in PHP.",
+ "scssphp/scssphp": "SCSS compiler written in PHP.",
+ "tedivm/jshrink": "Javascript Minifier built in PHP",
+ "tubalmartin/cssmin": "A PHP port of the YUI CSS compressor",
+ "symfony/console": "For pre-generating files from CLI",
+ "nette/safe-stream": "Atomic and safe manipulation with files via native PHP functions."
},
"require-dev": {
- "nette/application": "^3.0",
- "nette/bootstrap": "^3.0",
- "nette/caching": "^3.0",
+ "nette/bootstrap": "^3.1",
+ "nette/caching": "^3.1",
"nette/component-model": "^3.0",
- "nette/database": "^3.0",
- "nette/deprecated": "^2.3",
- "nette/di": "^3.0",
- "nette/finder": "^2.5",
- "nette/forms": "^3.0",
"nette/http": "^3.0",
- "nette/mail": "^3.0",
"nette/neon": "^3.0",
- "nette/php-generator": "^3.0",
- "nette/reflection": "^2.4",
- "nette/robot-loader": "^3.0",
- "nette/safe-stream": "^2.4",
- "nette/security": "^3.0",
- "nette/tokenizer": "^3.0",
- "nette/utils": "^3.0",
- "latte/latte": "^2.5",
- "tracy/tracy": "^2.6",
- "oyejorge/less.php": "^1.7",
- "leafo/scssphp": "^0.7",
- "kylekatarnls/coffeescript": "1.3.*",
+ "nette/robot-loader": "^3.0 || ^4.0",
+ "wikimedia/less.php": "^5.0.0",
+ "scssphp/scssphp": "^2.0.0",
"mockery/mockery": "1.*",
- "phpunit/phpunit": "7.*",
- "jakub-onderka/php-parallel-lint": "~0.7",
- "phpstan/phpstan-shim": "^0.11.0",
- "phpstan/phpstan-nette": "^0.11.0"
+ "phpunit/phpunit": "12.*",
+ "phpstan/extension-installer": "^1.0",
+ "phpstan/phpstan": "^2.0.0",
+ "phpstan/phpstan-nette": "^2.0.0",
+ "roave/security-advisories": "dev-master",
+ "symfony/console": "^4.2.9|^5.0.0|^6.0.0||^7.0.0",
+ "phpstan/phpstan-mockery": "^2.0.0",
+ "tubalmartin/cssmin": "^4.1",
+ "tedivm/jshrink": "^1.3",
+ "slevomat/coding-standard": "^8.15"
+ },
+ "scripts": {
+ "phpstan": "@php ./vendor/bin/phpstan analyse --configuration ./phpstan/phpstan.neon --memory-limit 512M",
+ "tests": "@php ./vendor/bin/phpunit --configuration tests/phpunit.xml tests"
},
- "extra": {
- "branch-alias": {
- "dev-master": "2.4-dev"
+ "config": {
+ "allow-plugins": {
+ "phpstan/extension-installer": true,
+ "dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
diff --git a/phpstan/phpstan b/phpstan/phpstan
deleted file mode 100755
index 9e146d0..0000000
--- a/phpstan/phpstan
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-
-./vendor/bin/phpstan analyse --configuration ./phpstan/phpstan.neon
diff --git a/phpstan/phpstan.neon b/phpstan/phpstan.neon
deleted file mode 100755
index 331b515..0000000
--- a/phpstan/phpstan.neon
+++ /dev/null
@@ -1,13 +0,0 @@
-parameters:
- autoload_directories:
- - WebLoader/
-
- paths:
- - WebLoader/
-
- level: 7
-
-
-includes:
- - ../vendor/phpstan/phpstan-nette/extension.neon
- - ../vendor/phpstan/phpstan-nette/rules.neon
diff --git a/src/BatchCollection.php b/src/BatchCollection.php
new file mode 100755
index 0000000..e225375
--- /dev/null
+++ b/src/BatchCollection.php
@@ -0,0 +1,41 @@
+ */
+ private array $batches = [];
+
+
+ public function __construct()
+ {
+ }
+
+
+ /** @return array */
+ public function getBatches(): array
+ {
+ return $this->batches;
+ }
+
+
+ /**
+ * @param array $batch
+ * @throws BatchAlreadyExistsException
+ */
+ public function addBatch(string $type, string $name, array $batch): void
+ {
+ if (isset($this->batches[$type][$name])) {
+ throw new BatchAlreadyExistsException(
+ sprintf("Batch '%s' of type '%s', already exists.", $name, $type)
+ );
+ }
+
+ $this->batches[$type][$name] = $batch;
+ }
+}
diff --git a/WebLoader/Compiler.php b/src/Compiler.php
similarity index 70%
rename from WebLoader/Compiler.php
rename to src/Compiler.php
index 38a06dc..6319598 100755
--- a/WebLoader/Compiler.php
+++ b/src/Compiler.php
@@ -1,9 +1,15 @@
*/
+ private array $filters = [];
- /** @var bool */
- private $async = false;
+ /** @var list */
+ private array $fileFilters = [];
- /** @var bool */
- private $defer = false;
-
- /** @var string|null */
- private $nonce;
-
- /** @var bool */
- private $absoluteUrl = false;
+ private bool $checkLastModified = true;
+ private bool $debugging = false;
+ private bool $async = false;
+ private bool $defer = false;
+ private bool $absoluteUrl = false;
+ private ?string $nonce = null;
public function __construct(IFileCollection $files, IOutputNamingConvention $convention, string $outputDir)
@@ -62,7 +48,7 @@ public function __construct(IFileCollection $files, IOutputNamingConvention $con
*/
public static function createCssCompiler(IFileCollection $files, string $outputDir): self
{
- return new static($files, DefaultOutputNamingConvention::createCssConvention(), $outputDir);
+ return new self($files, DefaultOutputNamingConvention::createCssConvention(), $outputDir);
}
@@ -71,7 +57,7 @@ public static function createCssCompiler(IFileCollection $files, string $outputD
*/
public static function createJsCompiler(IFileCollection $files, string $outputDir): self
{
- return new static($files, DefaultOutputNamingConvention::createJsConvention(), $outputDir);
+ return new self($files, DefaultOutputNamingConvention::createJsConvention(), $outputDir);
}
@@ -115,24 +101,6 @@ public function setOutputDir(string $tempPath): void
}
- /**
- * Get join files
- */
- public function getJoinFiles(): bool
- {
- return $this->joinFiles;
- }
-
-
- /**
- * Set join files
- */
- public function setJoinFiles(bool $joinFiles): void
- {
- $this->joinFiles = $joinFiles;
- }
-
-
public function isAsync(): bool
{
return $this->async;
@@ -183,6 +151,7 @@ public function setCheckLastModified(bool $checkLastModified): void
/**
* Get last modified timestamp of newest file
+ * @param list|null $files
*/
public function getLastModified(?array $files = null): int
{
@@ -192,6 +161,7 @@ public function getLastModified(?array $files = null): int
$modified = 0;
+ /** @var string $file */
foreach ($files as $file) {
$modified = max($modified, filemtime((string) realpath($file)));
}
@@ -202,6 +172,7 @@ public function getLastModified(?array $files = null): int
/**
* Get joined content of all files
+ * @param array|null $files
*/
public function getContent(?array $files = null): string
{
@@ -224,49 +195,44 @@ public function getContent(?array $files = null): string
}
- /**
- * Load content and save file
- */
- public function generate(): array
+ public function generate(): ?File
{
$files = $this->collection->getFiles();
if (!count($files)) {
- return [];
+ return null;
}
- if ($this->joinFiles) {
- $watchFiles = $this->checkLastModified ? array_unique(array_merge($files, $this->collection->getWatchFiles())) : [];
-
- return [
- $this->generateFiles($files, $watchFiles),
- ];
-
+ if ($this->checkLastModified) {
+ $watchFiles = array_unique(array_merge($files, $this->collection->getWatchFiles()));
+ $watchFiles = array_values($watchFiles);
} else {
- $arr = [];
-
- foreach ($files as $file) {
- $watchFiles = $this->checkLastModified ? array_unique(array_merge([$file], $this->collection->getWatchFiles())) : [];
- $arr[] = $this->generateFiles([$file], $watchFiles);
- }
-
- return $arr;
+ $watchFiles = [];
}
+
+ return $this->generateFiles($files, $watchFiles);
}
- protected function generateFiles(array $files, array $watchFiles = [])
+ /**
+ * @param list $files
+ * @param list $watchFiles
+ */
+ protected function generateFiles(array $files, array $watchFiles = []): File
{
$name = $this->namingConvention->getFilename($files, $this);
$path = $this->outputDir . '/' . $name;
- $lastModified = $this->checkLastModified ? $this->getLastModified($watchFiles) : 0;
+ $lastModified = $this->checkLastModified
+ ? $this->getLastModified($watchFiles)
+ : 0;
if (!file_exists($path) || $lastModified > filemtime($path) || $this->debugging === true) {
- $outPath = in_array('nette.safe', stream_get_wrappers(), true) ? 'nette.safe://' . $path : $path;
- file_put_contents($outPath, $this->getContent($files));
+ // disabled: https://github.com/nette/safe-stream/pull/5
+ // $outPath = in_array('nette.safe', stream_get_wrappers(), true) ? 'nette.safe://' . $path : $path;
+ FileSystem::write($path, $this->getContent($files));
}
- return new File($name, (int) filemtime($path), $files);
+ return new File($path, $files);
}
@@ -312,6 +278,7 @@ public function addFilter(callable $filter): void
}
+ /** @return list */
public function getFilters(): array
{
return $this->filters;
@@ -324,6 +291,7 @@ public function addFileFilter(callable $filter): void
}
+ /** @return list */
public function getFileFilters(): array
{
return $this->fileFilters;
diff --git a/src/Contract/IBatchCollection.php b/src/Contract/IBatchCollection.php
new file mode 100755
index 0000000..ffe2dab
--- /dev/null
+++ b/src/Contract/IBatchCollection.php
@@ -0,0 +1,13 @@
+ */
+ public function getBatches(): array;
+
+ /** @param array $batch */
+ public function addBatch(string $type, string $name, array $batch): void;
+}
diff --git a/WebLoader/IFileCollection.php b/src/Contract/IFileCollection.php
similarity index 61%
rename from WebLoader/IFileCollection.php
rename to src/Contract/IFileCollection.php
index 1e49601..dcb62e8 100755
--- a/WebLoader/IFileCollection.php
+++ b/src/Contract/IFileCollection.php
@@ -1,8 +1,8 @@
*/
public function getFiles(): array;
- public function getRemoteFiles(): array;
-
+ /** @return list */
public function getWatchFiles(): array;
}
diff --git a/WebLoader/IOutputNamingConvention.php b/src/Contract/IOutputNamingConvention.php
similarity index 58%
rename from WebLoader/IOutputNamingConvention.php
rename to src/Contract/IOutputNamingConvention.php
index 866ca08..252eac8 100755
--- a/WebLoader/IOutputNamingConvention.php
+++ b/src/Contract/IOutputNamingConvention.php
@@ -1,8 +1,10 @@
$files */
public function getFilename(array $files, Compiler $compiler): string;
}
diff --git a/src/Contract/IWebloaderAssetProvider.php b/src/Contract/IWebloaderAssetProvider.php
new file mode 100755
index 0000000..f18af55
--- /dev/null
+++ b/src/Contract/IWebloaderAssetProvider.php
@@ -0,0 +1,10 @@
+> */
+ public function getWebloaderAssets(): array;
+}
diff --git a/WebLoader/DefaultOutputNamingConvention.php b/src/DefaultOutputNamingConvention.php
similarity index 79%
rename from WebLoader/DefaultOutputNamingConvention.php
rename to src/DefaultOutputNamingConvention.php
index b470c18..ee821fb 100644
--- a/WebLoader/DefaultOutputNamingConvention.php
+++ b/src/DefaultOutputNamingConvention.php
@@ -1,27 +1,25 @@
setSuffix('.css');
return $convention;
@@ -30,7 +28,7 @@ public static function createCssConvention(): self
public static function createJsConvention(): self
{
- $convention = new static();
+ $convention = new self;
$convention->setSuffix('.js');
return $convention;
@@ -77,6 +75,7 @@ public function setSuffix(string $suffix): void
/**
* Filename of generated file
+ * @param array $files
*/
public function getFilename(array $files, Compiler $compiler): string
{
@@ -84,7 +83,8 @@ public function getFilename(array $files, Compiler $compiler): string
}
- protected function createHash(array $files, Compiler $compiler)
+ /** @param array $files */
+ protected function createHash(array $files, Compiler $compiler): string
{
$parts = $files;
foreach ($files as $file) {
diff --git a/src/Enum/RenderMode.php b/src/Enum/RenderMode.php
new file mode 100644
index 0000000..918998d
--- /dev/null
+++ b/src/Enum/RenderMode.php
@@ -0,0 +1,11 @@
+
+ */
+class CompilationException extends \WebLoader\Exception\WebLoaderException
+{
+}
diff --git a/src/Exception/FileNotFoundException.php b/src/Exception/FileNotFoundException.php
new file mode 100644
index 0000000..822cfc3
--- /dev/null
+++ b/src/Exception/FileNotFoundException.php
@@ -0,0 +1,15 @@
+ */
+ private array $sourceFiles;
+
+
+ /** @param array $sourceFiles */
+ public function __construct(
+ string $path,
+ array $sourceFiles,
+ ) {
+ $this->file = new SplFileInfo($path);
+ $this->sourceFiles = $sourceFiles;
+ }
+
+
+ public function getFileName(): string
+ {
+ return $this->file->getBasename();
+ }
+
+
+ public function getPath(): string
+ {
+ return $this->file->getPathname();
+ }
+
+
+ public function getLastModified(): int
+ {
+ return $this->file->getMTime();
+ }
+
+
+ /** @return array */
+ public function getSourceFiles(): array
+ {
+ return $this->sourceFiles;
+ }
+}
diff --git a/WebLoader/FileCollection.php b/src/FileCollection.php
similarity index 57%
rename from WebLoader/FileCollection.php
rename to src/FileCollection.php
index 9da7fe6..dad99d5 100755
--- a/WebLoader/FileCollection.php
+++ b/src/FileCollection.php
@@ -1,44 +1,34 @@
*/
+ private array $files = [];
- /** @var string */
- private $root;
+ /** @var array */
+ private array $watchFiles = [];
- /** @var array */
- private $files = [];
- /** @var array */
- private $watchFiles = [];
-
- /** @var array */
- private $remoteFiles = [];
-
-
- /**
- * @param string|null $root files root for relative paths
- */
- public function __construct(?string $root = null)
+ public function __construct(private readonly string $root)
{
- $this->root = (string) $root;
}
- /**
- * Get file list
- */
+ /** @return list */
public function getFiles(): array
{
return array_values($this->files);
@@ -66,7 +56,11 @@ public function cannonicalizePath(string $path): string
}
- public function addFile($file): void
+ /**
+ * @param SplFileInfo|string $file
+ * @throws FileNotFoundException
+ */
+ public function addFile(SplFileInfo|string $file): void
{
$file = $this->cannonicalizePath((string) $file);
@@ -80,9 +74,9 @@ public function addFile($file): void
/**
* Add files
- * @param array|Traversable $files array list of files
+ * @param iterable $files array list of files
*/
- public function addFiles($files): void
+ public function addFiles(iterable $files): void
{
foreach ($files as $file) {
$this->addFile($file);
@@ -96,6 +90,7 @@ public function removeFile(string $file): void
}
+ /** @param array $files */
public function removeFiles(array $files): void
{
$files = array_map([$this, 'cannonicalizePath'], $files);
@@ -103,32 +98,6 @@ public function removeFiles(array $files): void
}
- /**
- * Add file in remote repository (for example Google CDN).
- * @param string $file URL address
- */
- public function addRemoteFile(string $file): void
- {
- if (in_array($file, $this->remoteFiles, true)) {
- return;
- }
-
- $this->remoteFiles[] = $file;
- }
-
-
- /**
- * Add multiple remote files
- * @param array|Traversable $files
- */
- public function addRemoteFiles($files): void
- {
- foreach ($files as $file) {
- $this->addRemoteFile($file);
- }
- }
-
-
/**
* Remove all files
*/
@@ -136,13 +105,6 @@ public function clear(): void
{
$this->files = [];
$this->watchFiles = [];
- $this->remoteFiles = [];
- }
-
-
- public function getRemoteFiles(): array
- {
- return $this->remoteFiles;
}
@@ -166,9 +128,9 @@ public function addWatchFile(string $file): void
/**
* Add watch files
- * @param array|Traversable $files array list of files
+ * @param iterable $files array list of files
*/
- public function addWatchFiles($files): void
+ public function addWatchFiles(iterable $files): void
{
foreach ($files as $file) {
$this->addWatchFile($file);
@@ -176,6 +138,7 @@ public function addWatchFiles($files): void
}
+ /** @return list */
public function getWatchFiles(): array
{
return array_values($this->watchFiles);
diff --git a/src/Filter/CssMinFilter.php b/src/Filter/CssMinFilter.php
new file mode 100755
index 0000000..0b72468
--- /dev/null
+++ b/src/Filter/CssMinFilter.php
@@ -0,0 +1,16 @@
+run($code);
+ }
+}
diff --git a/WebLoader/Filter/CssUrlsFilter.php b/src/Filter/CssUrlsFilter.php
similarity index 84%
rename from WebLoader/Filter/CssUrlsFilter.php
rename to src/Filter/CssUrlsFilter.php
index fd505ef..02beef0 100755
--- a/WebLoader/Filter/CssUrlsFilter.php
+++ b/src/Filter/CssUrlsFilter.php
@@ -1,11 +1,11 @@
docRoot = Path::normalize($docRoot);
if (!is_dir($this->docRoot)) {
throw new InvalidArgumentException('Given document root is not directory.');
}
-
- $this->basePath = $basePath;
}
@@ -112,9 +107,7 @@ public function __invoke(string $code, Compiler $loader, ?string $file = null):
$self = $this;
- $return = preg_replace_callback($regexp, function ($matches) use ($self, $file) {
- return "url('" . $self->absolutizeUrl($matches[2], $matches[1], $file) . "')";
- }, $code);
+ $return = preg_replace_callback($regexp, fn($matches) => "url('" . $self->absolutizeUrl($matches[2], $matches[1], $file) . "')", $code);
return (string) $return;
}
diff --git a/src/Filter/JsMinFilter.php b/src/Filter/JsMinFilter.php
new file mode 100755
index 0000000..4596033
--- /dev/null
+++ b/src/Filter/JsMinFilter.php
@@ -0,0 +1,21 @@
+ */
+ private array $env;
- /** @var string */
- private $bin;
- /** @var array */
- private $env;
-
-
- public function __construct(string $bin = 'lessc', array $env = [])
+ /** @param array $env */
+ public function __construct(private string $bin = 'lessc', array $env = [])
{
- $this->bin = $bin;
$this->env = $env + $_ENV;
unset($this->env['argv'], $this->env['argc']);
}
diff --git a/src/Filter/LessFilter.php b/src/Filter/LessFilter.php
new file mode 100644
index 0000000..886b55b
--- /dev/null
+++ b/src/Filter/LessFilter.php
@@ -0,0 +1,36 @@
+getLessParser();
+ $parser->parseFile($file);
+ return $parser->getCss();
+ }
+
+ return $code;
+ }
+}
diff --git a/WebLoader/Filter/Process.php b/src/Filter/Process.php
similarity index 79%
rename from WebLoader/Filter/Process.php
rename to src/Filter/Process.php
index ea41bb9..b297a01 100644
--- a/WebLoader/Filter/Process.php
+++ b/src/Filter/Process.php
@@ -1,6 +1,6 @@
$env */
+ public static function run(
+ string $cmd,
+ ?string $stdin = null,
+ ?string $cwd = null,
+ ?array $env = null
+ ): string {
$descriptorspec = [
0 => ['pipe', 'r'], // stdin
1 => ['pipe', 'w'], // stdout
diff --git a/src/Filter/ScssFilter.php b/src/Filter/ScssFilter.php
new file mode 100644
index 0000000..039afa9
--- /dev/null
+++ b/src/Filter/ScssFilter.php
@@ -0,0 +1,30 @@
+getCompiler();
+ $compiler->setImportPaths([pathinfo($file, PATHINFO_DIRNAME) . '/']);
+ $result = $compiler->compileString($code);
+ return $result->getCss();
+ }
+
+ return $code;
+ }
+}
diff --git a/WebLoader/Filter/StylusFilter.php b/src/Filter/StylusFilter.php
similarity index 66%
rename from WebLoader/Filter/StylusFilter.php
rename to src/Filter/StylusFilter.php
index 330f180..7ac4b30 100755
--- a/WebLoader/Filter/StylusFilter.php
+++ b/src/Filter/StylusFilter.php
@@ -1,6 +1,6 @@
bin = $bin;
}
@@ -40,7 +32,7 @@ public function __invoke(string $code, Compiler $loader, ?string $file = null):
try {
$code = Process::run($cmd, $code);
} catch (\RuntimeException $e) {
- throw new \WebLoader\WebLoaderException('Stylus Filter Error', 0, $e);
+ throw new \WebLoader\Exception\WebLoaderException('Stylus Filter Error', 0, $e);
}
}
diff --git a/WebLoader/Filter/TypeScriptFilter.php b/src/Filter/TypeScriptFilter.php
similarity index 77%
rename from WebLoader/Filter/TypeScriptFilter.php
rename to src/Filter/TypeScriptFilter.php
index 81b0c89..88764f2 100755
--- a/WebLoader/Filter/TypeScriptFilter.php
+++ b/src/Filter/TypeScriptFilter.php
@@ -1,6 +1,6 @@
*/
+ private array $env;
- /** @var string|null */
- private $bin;
- /** @var array|null */
- private $env;
-
-
- public function __construct(string $bin = 'tsc', array $env = [])
+ /** @param array $env */
+ public function __construct(private string $bin = 'tsc', array $env = [])
{
- $this->bin = $bin;
$this->env = $env + $_ENV;
unset($this->env['argv'], $this->env['argc']);
}
diff --git a/WebLoader/Filter/VariablesFilter.php b/src/Filter/VariablesFilter.php
similarity index 56%
rename from WebLoader/Filter/VariablesFilter.php
rename to src/Filter/VariablesFilter.php
index 65e0b84..e97895a 100644
--- a/WebLoader/Filter/VariablesFilter.php
+++ b/src/Filter/VariablesFilter.php
@@ -1,9 +1,11 @@
$variables */
+ public function __construct(private array $variables = [])
{
foreach ($variables as $key => $value) {
$this->$key = $value;
@@ -34,30 +27,20 @@ public function __construct(array $variables = [])
}
- /**
- * Set delimiter
- *
- * @return \WebLoader\Filter\VariablesFilter
- */
public function setDelimiter(string $start, string $end): self
{
- $this->startVariable = (string) $start;
- $this->endVariable = (string) $end;
+ $this->startVariable = $start;
+ $this->endVariable = $end;
return $this;
}
- /**
- * Invoke filter
- */
public function __invoke(string $code): string
{
$start = $this->startVariable;
$end = $this->endVariable;
- $variables = array_map(function ($key) use ($start, $end) {
- return $start . $key . $end;
- }, array_keys($this->variables));
+ $variables = array_map(fn($key) => $start . $key . $end, array_keys($this->variables));
$values = array_values($this->variables);
@@ -76,15 +59,14 @@ public function __set(string $name, string $value): void
/**
* Magic get variable, do not call directly
- *
- * @throws \WebLoader\InvalidArgumentException
+ * @throws InvalidArgumentException
*/
public function &__get(string $name): string
{
if (array_key_exists($name, $this->variables)) {
return $this->variables[$name];
} else {
- throw new \WebLoader\InvalidArgumentException("Variable '$name' is not set.");
+ throw new InvalidArgumentException("Variable '$name' is not set.");
}
}
}
diff --git a/WebLoader/Nette/CssLoader.php b/src/Nette/CssLoader.php
similarity index 60%
rename from WebLoader/Nette/CssLoader.php
rename to src/Nette/CssLoader.php
index 7e02647..8b77dab 100755
--- a/WebLoader/Nette/CssLoader.php
+++ b/src/Nette/CssLoader.php
@@ -1,10 +1,12 @@
media;
}
@@ -40,7 +34,7 @@ public function getType(): string
}
- public function getTitle(): string
+ public function getTitle(): ?string
{
return $this->title;
}
@@ -80,7 +74,7 @@ public function setAlternate(bool $alternate): self
}
- public function getElement(string $source): Html
+ public function getElement(File $file): Html
{
if ($this->alternate) {
$alternate = ' alternate';
@@ -94,7 +88,20 @@ public function getElement(string $source): Html
$el->setAttribute('media', $this->media);
$el->setAttribute('title', $this->title);
$el->setAttribute('nonce', $this->getCompiler()->getNonce());
- $el->setAttribute('href', $source);
+ $el->setAttribute('href', $this->getGeneratedFilePath($file));
+
+ return $el;
+ }
+
+
+ public function getInlineElement(File $file): Html
+ {
+ $el = Html::el('style');
+ $el->setAttribute('type', $this->type);
+ $el->setAttribute('media', $this->media);
+ $el->setAttribute('title', $this->title);
+ $el->setAttribute('nonce', $this->getCompiler()->getNonce());
+ $el->setHtml(FileSystem::read($file->getPath()));
return $el;
}
diff --git a/WebLoader/Nette/CssUrlFilter.php b/src/Nette/CssUrlFilter.php
similarity index 92%
rename from WebLoader/Nette/CssUrlFilter.php
rename to src/Nette/CssUrlFilter.php
index 17e5091..2733164 100755
--- a/WebLoader/Nette/CssUrlFilter.php
+++ b/src/Nette/CssUrlFilter.php
@@ -1,6 +1,6 @@
*/
+ public static array $types = [
'css' => 'CSS files',
'js' => 'JavaScript files',
'less' => 'Less files',
'scss' => 'Sass files',
- 'coffee' => 'CoffeeScript files',
];
/** @var Compiler[] */
- private $compilers = [];
+ private array $compilers = [];
- /** @var array */
- private $size;
+ /** @var array{original: int, combined: int, ratio: float}|null */
+ private ?array $size = null;
- /** @var array */
- private $files;
+ /** @var array */
+ private array $files;
- /** @var array */
- private $sizes;
+ /** @var array */
+ private array $sizes;
- /** @var string */
- private $root;
+ private string $root;
public function __construct(?string $appDir = null)
{
- $this->root = $appDir ? str_replace('\\', DIRECTORY_SEPARATOR, (string) realpath(dirname($appDir))) : '';
+ $this->root = $appDir
+ ? str_replace('\\', DIRECTORY_SEPARATOR, (string) realpath(dirname($appDir)))
+ : '';
Debugger::getBar()->addPanel($this);
}
@@ -53,6 +51,8 @@ public function __construct(?string $appDir = null)
/**
* Registers a compiler.
*
+ * @param string $name
+ * @param Compiler $compiler
* @return Panel
*/
public function addLoader(string $name, Compiler $compiler): self
@@ -64,6 +64,7 @@ public function addLoader(string $name, Compiler $compiler): self
/**
* Computes the info.
+ * @return array{original: int, combined: int, ratio: float}
*/
private function compute(): array
{
@@ -77,6 +78,10 @@ private function compute(): array
];
$this->files = $this->sizes = [];
+ /**
+ * @var string $name
+ * @var Compiler $compiler
+ */
foreach ($this->compilers as $name => $compiler) {
$group = lcfirst(substr($name, $name[0] === 'c' ? 3 : 2));
@@ -89,33 +94,37 @@ private function compute(): array
$compilerCombinedSize = 0;
- /** @var File $generated */
- foreach ($compiler->generate() as $generated) {
- $generatedSize = filesize($compiler->getOutputDir() . DIRECTORY_SEPARATOR . $generated->getFile());
- $size['combined'] += $generatedSize;
- $compilerCombinedSize += $generatedSize;
-
- foreach ($generated->getSourceFiles() as $file) {
- $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
- $file = str_replace('\\', DIRECTORY_SEPARATOR, (string) realpath($file));
-
- if (!isset($this->files[$group][$extension])) {
- $this->files[$group][$extension] = [];
- }
- if (!isset($this->sizes[$group][$extension])) {
- $this->sizes[$group][$extension] = ['original' => 0, 'combined' => 0];
- }
-
- $this->files[$group][$extension][] = [
- 'name' => basename($file),
- 'full' => $file,
- 'size' => $fileSize = filesize($file),
- ];
-
- $size['original'] += $fileSize;
- $this->sizes[$group][$extension]['original'] += $fileSize;
- $this->sizes[$group]['.']['original'] += $fileSize;
+ $generated = $compiler->generate();
+
+ if (null === $generated) {
+ continue;
+ }
+
+ $generatedSize = filesize($compiler->getOutputDir() . DIRECTORY_SEPARATOR . $generated->getFileName());
+ $size['combined'] += $generatedSize;
+
+ $compilerCombinedSize += $generatedSize;
+
+ foreach ($generated->getSourceFiles() as $file) {
+ $extension = strtolower(pathinfo($file, PATHINFO_EXTENSION));
+ $file = str_replace('\\', DIRECTORY_SEPARATOR, (string) realpath($file));
+
+ if (!isset($this->files[$group][$extension])) {
+ $this->files[$group][$extension] = [];
+ }
+ if (!isset($this->sizes[$group][$extension])) {
+ $this->sizes[$group][$extension] = ['original' => 0, 'combined' => 0];
}
+
+ $this->files[$group][$extension][] = [
+ 'name' => basename($file),
+ 'full' => $file,
+ 'size' => $fileSize = filesize($file),
+ ];
+
+ $size['original'] += $fileSize;
+ $this->sizes[$group][$extension]['original'] += $fileSize;
+ $this->sizes[$group]['.']['original'] += $fileSize;
}
$this->sizes[$group]['.']['combined'] += $compilerCombinedSize;
@@ -132,9 +141,7 @@ private function getTable(): string
{
$latte = new Latte\Engine;
- $latte->addFilter('extension', function ($extension) {
- return isset(self::$types[$extension]) ? self::$types[$extension] : $extension;
- });
+ $latte->addFilter('extension', fn($extension) => self::$types[$extension] ?? $extension);
return $latte->renderToString(__DIR__ . '/panel.latte', [
'files' => $this->files,
@@ -149,7 +156,7 @@ private function getTable(): string
*/
public function getPanel(): string
{
- return $this->compute() ? $this->getTable() : '';
+ return $this->compute() ? $this->getTable() : ''; //@phpstan-ignore ternary.alwaysTrue
}
@@ -160,9 +167,13 @@ public function getTab(): string
{
$this->compute();
+ if (empty($this->size['combined'])) {
+ return '';
+ }
+
return ''
. ''
- . Filters::bytes($this->size['combined'])
+ . (new Filters())->bytes($this->size['combined'])
. '';
}
}
diff --git a/WebLoader/Nette/Diagnostics/panel.latte b/src/Nette/Diagnostics/panel.latte
similarity index 100%
rename from WebLoader/Nette/Diagnostics/panel.latte
rename to src/Nette/Diagnostics/panel.latte
diff --git a/src/Nette/Extension.php b/src/Nette/Extension.php
new file mode 100644
index 0000000..b42baf0
--- /dev/null
+++ b/src/Nette/Extension.php
@@ -0,0 +1,384 @@
+appDir = $appDir;
+ $this->wwwDir = $wwwDir;
+ $this->debugMode = $debugMode;
+ $this->batchCollection = new BatchCollection;
+ }
+
+
+ private function getJsConfigSchema(bool $useDefaults = false): Schema
+ {
+ $checkLastModified = $useDefaults ? true : null;
+ $debug = $useDefaults ? false : null;
+ $sourceDir = $useDefaults ? ($this->wwwDir . '/js') : null;
+ $tempDir = $useDefaults ? ($this->wwwDir . '/' . self::DEFAULT_TEMP_PATH) : null;
+ $tempPath = $useDefaults ? self::DEFAULT_TEMP_PATH : null;
+ $async = $useDefaults ? false : null;
+ $defer = $useDefaults ? false : null;
+ $absoluteUrl = $useDefaults ? false : null;
+ $namingConvention = $useDefaults
+ ? ('@' . $this->prefix('jsNamingConvention'))
+ : null;
+
+ return Expect::structure([
+ 'checkLastModified' => Expect::bool($checkLastModified),
+ 'debug' => Expect::bool($debug),
+ 'sourceDir' => Expect::string($sourceDir),
+ 'tempDir' => Expect::string($tempDir),
+ 'tempPath' => Expect::string($tempPath),
+ 'files' => Expect::array(),
+ 'watchFiles' => Expect::array(),
+ 'filters' => Expect::array(),
+ 'fileFilters' => Expect::array(),
+ 'async' => Expect::bool($async),
+ 'defer' => Expect::bool($defer),
+ 'nonce' => Expect::string()->nullable(),
+ 'absoluteUrl' => Expect::bool($absoluteUrl),
+ 'namingConvention' => Expect::string($namingConvention),
+ ]);
+ }
+
+
+ private function getCssConfigSchema(bool $useDefaults = false): Schema
+ {
+ $checkLastModified = $useDefaults ? true : null;
+ $debug = $useDefaults ? false : null;
+ $sourceDir = $useDefaults ? ($this->wwwDir . '/css') : null;
+ $tempDir = $useDefaults ? ($this->wwwDir . '/' . self::DEFAULT_TEMP_PATH) : null;
+ $tempPath = $useDefaults ? self::DEFAULT_TEMP_PATH : null;
+ $async = $useDefaults ? false : null;
+ $defer = $useDefaults ? false : null;
+ $absoluteUrl = $useDefaults ? false : null;
+ $namingConvention = $useDefaults
+ ? ('@' . $this->prefix('cssNamingConvention'))
+ : null;
+
+ return Expect::structure([
+ 'checkLastModified' => Expect::bool($checkLastModified),
+ 'debug' => Expect::bool($debug),
+ 'sourceDir' => Expect::string($sourceDir),
+ 'tempDir' => Expect::string($tempDir),
+ 'tempPath' => Expect::string($tempPath),
+ 'files' => Expect::array(),
+ 'watchFiles' => Expect::array(),
+ 'filters' => Expect::array(),
+ 'fileFilters' => Expect::array(),
+ 'async' => Expect::bool($async),
+ 'defer' => Expect::bool($defer),
+ 'nonce' => Expect::string()->nullable(),
+ 'absoluteUrl' => Expect::bool($absoluteUrl),
+ 'namingConvention' => Expect::string($namingConvention),
+ ]);
+ }
+
+
+ public function getConfigSchema(): Schema
+ {
+ return Expect::structure([
+ 'jsDefaults' => $this->getJsConfigSchema(true),
+ 'cssDefaults' => $this->getCssConfigSchema(true),
+ 'js' => Expect::arrayOf($this->getJsConfigSchema())->nullable(),
+ 'css' => Expect::arrayOf($this->getCssConfigSchema())->nullable(),
+ 'debugger' => Expect::bool($this->debugMode),
+ ]);
+ }
+
+
+ public function loadConfiguration(): void
+ {
+ $builder = $this->getContainerBuilder();
+ $config = json_decode((string) json_encode($this->getConfig()), true);
+
+ $builder->addDefinition($this->prefix('cssNamingConvention'))
+ ->setFactory('WebLoader\DefaultOutputNamingConvention::createCssConvention');
+
+ $builder->addDefinition($this->prefix('jsNamingConvention'))
+ ->setFactory('WebLoader\DefaultOutputNamingConvention::createJsConvention');
+
+ if ($config['debugger']) {
+ $builder->addDefinition($this->prefix('tracyPanel'))
+ ->setType(Panel::class)
+ ->setArguments([$this->appDir]);
+ }
+
+ $builder->parameters['webloader'] = $config;
+
+ $loaderFactoryTempPaths = [];
+
+ $this->extractBatchesFromExtensions();
+ $this->extractNormalBatches($config);
+
+ $batchTypes = $this->batchCollection->getBatches();
+ foreach ($batchTypes as $type => $batches) {
+ foreach ($batches as $name => $batch) {
+ $batch = array_filter($batch);
+ $batch = SchemaHelpers::merge($batch, $config[$type . 'Defaults']);
+
+ if (!is_array($batch)) {
+ throw new CompilationException('Batch config not valid.');
+ }
+
+ $this->addWebLoader($builder, $type . ucfirst($name), $batch);
+ $loaderFactoryTempPaths[strtolower($name)] = $batch['tempPath'];
+
+ if (!is_dir($batch['tempDir']) || !is_writable($batch['tempDir'])) {
+ throw new CompilationException(sprintf("You must create a writable directory '%s'", $batch['tempDir']));
+ }
+ }
+ }
+
+ $builder->addDefinition($this->prefix('factory'))
+ ->setType(LoaderFactory::class)
+ ->setArguments([$loaderFactoryTempPaths, $this->name]);
+
+ if (class_exists('Symfony\Component\Console\Command\Command')) {
+ $builder->addDefinition($this->prefix('generateCommand'))
+ ->setType(GenerateCommand::class)
+ ->addTag('kdyby.console.command');
+ }
+ }
+
+
+ /**
+ * @param ContainerBuilder $builder
+ * @param string $name
+ * @param array $config
+ * @return void
+ * @throws FileNotFoundException
+ */
+ private function addWebLoader(ContainerBuilder $builder, string $name, array $config): void
+ {
+ $filesServiceName = $this->prefix($name . 'Files');
+
+ $files = $builder->addDefinition($filesServiceName)
+ ->setType(FileCollection::class)
+ ->setArguments([$config['sourceDir']]);
+
+ foreach ($this->findFiles($config['files'], $config['sourceDir']) as $file) {
+ $files->addSetup('addFile', [$file]);
+ }
+
+ foreach ($this->findFiles($config['watchFiles'], $config['sourceDir']) as $file) {
+ $files->addSetup('addWatchFile', [$file]);
+ }
+
+ $compiler = $builder->addDefinition($this->prefix($name . 'Compiler'))
+ ->setType(WebloaderCompiler::class)
+ ->setArguments([
+ '@' . $filesServiceName,
+ $config['namingConvention'],
+ $config['tempDir'],
+ ]);
+
+ $compiler
+ ->addSetup('setAsync', [$config['async']])
+ ->addSetup('setDefer', [$config['defer']])
+ ->addSetup('setNonce', [$config['nonce']])
+ ->addSetup('setAbsoluteUrl', [$config['absoluteUrl']]);
+
+ if ($builder->parameters['webloader']['debugger']) {
+ $compiler->addSetup('@' . $this->prefix('tracyPanel') . '::addLoader', [
+ $name,
+ '@' . $this->prefix($name . 'Compiler'),
+ ]);
+ }
+
+ foreach ($config['filters'] as $filter) {
+ $compiler->addSetup('addFilter', [$filter]);
+ }
+
+ foreach ($config['fileFilters'] as $filter) {
+ $compiler->addSetup('addFileFilter', [$filter]);
+ }
+
+ if (isset($config['debug']) && $config['debug']) {
+ $compiler->addSetup('enableDebugging');
+ }
+
+ $compiler->addSetup('setCheckLastModified', [$config['checkLastModified']]);
+
+ // todo css media
+ }
+
+
+ // I have no clue what this is supposed to do...
+ // public function afterCompile(ClassType $class): void
+ // {
+ // $types = $class->getProperty('types');
+ // if (array_key_exists('webloader\\nette\\loaderfactory', $types)) {
+ // $types['webloader\\loaderfactory'] = $types['webloader\\nette\\loaderfactory'];
+ // }
+ // if (array_key_exists('WebLoader\\Nette\\LoaderFactory', $types)) {
+ // $types['WebLoader\\LoaderFactory'] = $types['WebLoader\\Nette\\LoaderFactory'];
+ // }
+ //
+ // $init = $class->methods['initialize'];
+ // $init->addBody('if (!class_exists(?, ?)) class_alias(?, ?);', ['WebLoader\\LoaderFactory', false, 'WebLoader\\Nette\\LoaderFactory', 'WebLoader\\LoaderFactory']);
+ // }
+
+
+ public function install(Configurator $configurator): void
+ {
+ $self = $this;
+ $configurator->onCompile[] = function ($configurator, Compiler $compiler) use ($self): void {
+ $compiler->addExtension($self::EXTENSION_NAME, $self);
+ };
+ }
+
+
+ /**
+ * @param array $filesConfig
+ * @param string $sourceDir
+ * @return array
+ * @throws FileNotFoundException
+ */
+ private function findFiles(array $filesConfig, string $sourceDir): array
+ {
+ $normalizedFiles = [];
+
+ /** @var array|string $file */
+ foreach ($filesConfig as $file) {
+ // finder support
+ if (is_array($file) && isset($file['files']) && (isset($file['in']) || isset($file['from']))) {
+ $finder = Finder::findFiles($file['files']);
+
+ if (isset($file['exclude'])) {
+ $finder->exclude($file['exclude']);
+ }
+
+ if (isset($file['in'])) {
+ $finder->in(is_dir($file['in']) ? $file['in'] : $sourceDir . DIRECTORY_SEPARATOR . $file['in']);
+ } else {
+ $finder->from(is_dir($file['from']) ? $file['from'] : $sourceDir . DIRECTORY_SEPARATOR . $file['from']);
+ }
+
+ $foundFilesList = [];
+ foreach ($finder as $foundFile) {
+ /** @var FileInfo $foundFile */
+ $foundFilesList[] = $foundFile->getPathname();
+ }
+
+ natsort($foundFilesList);
+
+ /** @var string $foundFilePathname */
+ foreach ($foundFilesList as $foundFilePathname) {
+ $normalizedFiles[] = $foundFilePathname;
+ }
+
+ } else {
+ if (is_string($file)) {
+ $this->checkFileExists($file, $sourceDir);
+ $normalizedFiles[] = $file;
+ }
+ }
+ }
+
+ return $normalizedFiles;
+ }
+
+
+ protected function checkFileExists(string $file, string $sourceDir): void
+ {
+ if (!$this->fileExists($file)) {
+ $tmp = rtrim($sourceDir, '/\\') . DIRECTORY_SEPARATOR . $file;
+ if (!$this->fileExists($tmp)) {
+ throw new FileNotFoundException(sprintf("Neither '%s' or '%s' was found", $file, $tmp));
+ }
+ }
+ }
+
+
+ /**
+ * Some servers seem to have problems under cron user with open_basedir restriction when using relative paths
+ */
+ protected function fileExists(string $file): bool
+ {
+ $file = realpath($file);
+
+ if ($file === false) {
+ $file = '';
+ }
+
+ return file_exists($file);
+ }
+
+
+ private function extractBatchesFromExtensions(): void
+ {
+ // Extension batches
+ /** @var array $batchProviders */
+ $batchProviders = $this->compiler->getExtensions(IWebloaderAssetProvider::class);
+
+ if (empty($batchProviders)) {
+ return;
+ }
+
+ $schemaProcessor = new Processor;
+
+ foreach ($batchProviders as $batchProvider) {
+ $assets = $batchProvider->getWebloaderAssets();
+ $schemaProcessor->process($this->getConfigSchema(), $assets);
+
+ foreach ($assets as $type => $batches) {
+ foreach ($batches as $name => $batch) {
+ $this->batchCollection->addBatch($type, $name, $batch);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * @param array $config
+ * @throws BatchAlreadyExistsException
+ */
+ private function extractNormalBatches(array $config): void
+ {
+ foreach (['css', 'js'] as $type) {
+ foreach ($config[$type] as $name => $batch) {
+ $this->batchCollection->addBatch($type, $name, $batch);
+ }
+ }
+ }
+}
diff --git a/WebLoader/Nette/JavaScriptLoader.php b/src/Nette/JavaScriptLoader.php
similarity index 50%
rename from WebLoader/Nette/JavaScriptLoader.php
rename to src/Nette/JavaScriptLoader.php
index a752f17..45ee64e 100644
--- a/WebLoader/Nette/JavaScriptLoader.php
+++ b/src/Nette/JavaScriptLoader.php
@@ -1,10 +1,12 @@
setAttribute('async', $this->getCompiler()->isAsync());
$el->setAttribute('defer', $this->getCompiler()->isDefer());
$el->setAttribute('nonce', $this->getCompiler()->getNonce());
- $el->setAttribute('src', $source);
+ $el->setAttribute('src', $this->getGeneratedFilePath($file));
+
+ return $el;
+ }
+
+
+ public function getInlineElement(File $file): Html
+ {
+ $el = Html::el('script');
+ $el->setAttribute('nonce', $this->getCompiler()->getNonce());
+ $el->setHtml(FileSystem::read($file->getPath()));
return $el;
}
diff --git a/src/Nette/LoaderFactory.php b/src/Nette/LoaderFactory.php
new file mode 100644
index 0000000..51ac554
--- /dev/null
+++ b/src/Nette/LoaderFactory.php
@@ -0,0 +1,70 @@
+ $tempPaths */
+ public function __construct(
+ private array $tempPaths,
+ private string $extensionName,
+ private IRequest $httpRequest,
+ private Container $diContainer
+ ) {
+ }
+
+
+ private function getCompiler(string $name, string $type): Compiler
+ {
+ /** @var Compiler $compiler */
+ $compiler = $this->diContainer->getService(
+ $this->extensionName .
+ '.' .
+ $type .
+ ucfirst($name) .
+ 'Compiler'
+ );
+ return $compiler;
+ }
+
+
+ public function createCssLoader(string $name, bool $appendLastModified = true): CssLoader
+ {
+ $compiler = $this->getCompiler($name, 'css');
+ $this->modifyConvention($compiler->getOutputNamingConvention(), $name);
+ return new CssLoader($compiler, $this->formatTempPath($name, $compiler->isAbsoluteUrl()), $appendLastModified);
+ }
+
+
+ public function createJavaScriptLoader(string $name, bool $appendLastModified = true): JavaScriptLoader
+ {
+ $compiler = $this->getCompiler($name, 'js');
+ $this->modifyConvention($compiler->getOutputNamingConvention(), $name);
+ return new JavaScriptLoader($compiler, $this->formatTempPath($name, $compiler->isAbsoluteUrl()), $appendLastModified);
+ }
+
+
+ private function formatTempPath(string $name, bool $absoluteUrl = false): string
+ {
+ $lName = strtolower($name);
+ $tempPath = $this->tempPaths[$lName] ?? Extension::DEFAULT_TEMP_PATH;
+ $method = $absoluteUrl ? 'getBaseUrl' : 'getBasePath';
+ return rtrim($this->httpRequest->getUrl()->withoutUserInfo()->{$method}(), '/') . '/' . $tempPath;
+ }
+
+
+ private function modifyConvention(IOutputNamingConvention $convention, string $name): void
+ {
+ if ($convention instanceof DefaultOutputNamingConvention) {
+ $convention->setPrefix($name . '-');
+ }
+ }
+}
diff --git a/src/Nette/SymfonyConsole/GenerateCommand.php b/src/Nette/SymfonyConsole/GenerateCommand.php
new file mode 100644
index 0000000..e4050d0
--- /dev/null
+++ b/src/Nette/SymfonyConsole/GenerateCommand.php
@@ -0,0 +1,61 @@
+findByType(Compiler::class);
+ foreach ($compilers as $compilerName) {
+ $this->compilers[$compilerName] = $container->getService($compilerName);
+ }
+ }
+
+
+ protected function configure(): void
+ {
+ $this->addOption('force', 'f', InputOption::VALUE_NONE, 'Generate if not modified.');
+ }
+
+
+ protected function execute(InputInterface $input, OutputInterface $output): int
+ {
+ $noFiles = true;
+ foreach ($this->compilers as $compiler) {
+ $file = $compiler->generate();
+ if (null !== $file) {
+ $output->writeln($file->getFileName());
+ $noFiles = false;
+ }
+ }
+
+ if ($noFiles) {
+ $output->writeln('No files generated.');
+ return 1;
+ }
+
+ return 0;
+ }
+}
diff --git a/src/Nette/WebLoader.php b/src/Nette/WebLoader.php
new file mode 100755
index 0000000..6888af8
--- /dev/null
+++ b/src/Nette/WebLoader.php
@@ -0,0 +1,121 @@
+compiler;
+ }
+
+
+ public function setCompiler(Compiler $compiler): void
+ {
+ $this->compiler = $compiler;
+ }
+
+
+ public function getTempPath(): string
+ {
+ return $this->tempPath;
+ }
+
+
+ public function setTempPath(string $tempPath): void
+ {
+ $this->tempPath = $tempPath;
+ }
+
+
+ /**
+ * Get html element including generated content
+ */
+ abstract public function getElement(File $file): Html;
+
+
+ abstract public function getInlineElement(File $file): Html;
+
+
+ public function setRenderMode(RenderMode $renderMode): void
+ {
+ $this->renderMode = $renderMode;
+ }
+
+
+ protected function getUrl(File $file): string
+ {
+ return $this->getGeneratedFilePath($file);
+ }
+
+
+ /**
+ * Generate compiled file(s) and render link(s)
+ */
+ public function render(): void
+ {
+ $file = $this->compiler->generate();
+
+ if ($file === null) {
+ return;
+ }
+
+ $output = match ($this->renderMode) {
+ RenderMode::URL => $this->getUrl($file),
+ RenderMode::LINK => $this->getElement($file),
+ RenderMode::INLINE => $this->getInlineElement($file),
+ };
+
+ echo $output, PHP_EOL;
+ }
+
+
+ public function renderInline(): void
+ {
+ $this->setRenderMode(RenderMode::INLINE);
+ $this->render();
+ }
+
+
+ public function renderUrl(): void
+ {
+ $this->setRenderMode(renderMode::URL);
+ $this->render();
+ }
+
+
+ protected function getGeneratedFilePath(File $file): string
+ {
+ $path = $this->tempPath . '/' . $file->getFileName();
+
+ if ($this->appendLastModified) {
+ $path .= '?' . $file->getLastModified();
+ }
+
+ return $path;
+ }
+}
diff --git a/src/Path.php b/src/Path.php
new file mode 100755
index 0000000..1b9a650
--- /dev/null
+++ b/src/Path.php
@@ -0,0 +1,15 @@
+batchCollection = new BatchCollection();
+ }
+
+
+ public function testAddGetBatches(): void
+ {
+ $this->batchCollection->addBatch('css', 'front.screen', []);
+ $this->batchCollection->addBatch('js', 'front.head', []);
+
+ $expected = [
+ 'css' => [
+ 'front.screen' => [],
+ ],
+ 'js' => [
+ 'front.head' => [],
+ ],
+ ];
+
+ $this->assertSame($expected, $this->batchCollection->getBatches());
+ }
+
+
+ public function testAddBatchException(): void
+ {
+ $this->expectException(BatchAlreadyExistsException::class);
+ $this->batchCollection->addBatch('css', 'front.screen', []);
+ $this->batchCollection->addBatch('css', 'front.screen', []);
+ }
+}
diff --git a/tests/CompilerTest.php b/tests/CompilerTest.php
old mode 100755
new mode 100644
index 03ab732..cf703e2
--- a/tests/CompilerTest.php
+++ b/tests/CompilerTest.php
@@ -3,10 +3,16 @@
namespace WebLoader\Test;
+use Exception;
use Mockery;
use PHPUnit\Framework\TestCase;
+use TypeError;
use WebLoader\Compiler;
+use WebLoader\Contract\IFileCollection;
+use WebLoader\Contract\IOutputNamingConvention;
use WebLoader\File;
+use WebLoader\FileCollection;
+use WebLoader\Exception\FileNotFoundException;
/**
* CompilerTest
@@ -16,13 +22,12 @@
class CompilerTest extends TestCase
{
- /** @var \WebLoader\Compiler */
- private $object;
+ private Compiler $object;
protected function setUp(): void
{
- $fileCollection = Mockery::mock('WebLoader\IFileCollection');
+ $fileCollection = Mockery::mock(IFileCollection::class);
$fileCollection->shouldReceive('getFiles')->andReturn([
__DIR__ . '/fixtures/a.txt',
__DIR__ . '/fixtures/b.txt',
@@ -34,7 +39,7 @@ protected function setUp(): void
__DIR__ . '/fixtures/c.txt',
]);
- $convention = Mockery::mock('WebLoader\IOutputNamingConvention');
+ $convention = Mockery::mock(IOutputNamingConvention::class);
$convention->shouldReceive('getFilename')->andReturnUsing(function ($files, $compiler) {
return 'webloader-' . md5(join(',', $files));
});
@@ -47,49 +52,32 @@ protected function setUp(): void
}
+ /** @return list */
private function getTempFiles(): array
{
- return glob(__DIR__ . '/temp/webloader-*');
- }
-
+ $files = glob(__DIR__ . '/temp/webloader-*');
- public function testJoinFiles(): void
- {
- $this->assertTrue($this->object->getJoinFiles());
+ if ($files === false) {
+ return [];
+ }
- $ret = $this->object->generate();
- $this->assertEquals(1, count($ret), 'Multiple files are generated instead of join.');
- $this->assertEquals(1, count($this->getTempFiles()), 'Multiple files are generated instead of join.');
+ return $files;
}
public function testEmptyFiles(): void
{
- $this->assertTrue($this->object->getJoinFiles());
- $this->object->setFileCollection(new \WebLoader\FileCollection());
+ $this->object->setFileCollection(new FileCollection(''));
$ret = $this->object->generate();
- $this->assertEquals(0, count($ret));
- $this->assertEquals(0, count($this->getTempFiles()));
+ $this->assertNull($ret);
+ $this->assertCount(0, $this->getTempFiles());
}
- public function testNotJoinFiles(): void
- {
- $this->object->setJoinFiles(false);
- $this->assertFalse($this->object->getJoinFiles());
-
- $ret = $this->object->generate();
- $this->assertEquals(3, count($ret), 'Wrong file count generated.');
- $this->assertEquals(3, count($this->getTempFiles()), 'Wrong file count generated.');
- }
-
-
- /**
- * @expectedException \WebLoader\FileNotFoundException
- */
public function testSetOutDir(): void
{
+ $this->expectException(FileNotFoundException::class);
$this->object->setOutputDir('blablabla');
}
@@ -112,14 +100,11 @@ public function testGeneratingAndFilters(): void
$expectedContent = '-' . PHP_EOL . 'a:cba,' . PHP_EOL . 'b:fed,' . PHP_EOL .
'c:ihg,-' . PHP_EOL . 'a:cba,' . PHP_EOL . 'b:fed,' . PHP_EOL . 'c:ihg,';
- /**
- * @var $files File[]
- */
- $files = $this->object->generate();
+ $file = $this->generateFile();
- $this->assertTrue(is_numeric($files[0]->getLastModified()) && $files[0]->getLastModified() > 0, 'Generate does not provide last modified timestamp correctly.');
+ $this->assertTrue($file->getLastModified() && $file->getLastModified() > 0, 'Generate does not provide last modified timestamp correctly.');
- $content = file_get_contents($this->object->getOutputDir() . '/' . $files[0]->getFile());
+ $content = file_get_contents($this->object->getOutputDir() . '/' . $file->getFileName());
$this->assertEquals($expectedContent, $content);
}
@@ -127,19 +112,16 @@ public function testGeneratingAndFilters(): void
public function testGenerateReturnsSourceFilePaths(): void
{
- /**
- * @var $res File[]
- */
- $res = $this->object->generate();
- $this->assertInternalType('array', $res[0]->getSourceFiles());
- $this->assertCount(3, $res[0]->getSourceFiles());
- $this->assertFileExists($res[0]->getSourceFiles()[0]);
+ $file = $this->generateFile();
+
+ $this->assertCount(3, $file->getSourceFiles());
+ $this->assertFileExists($file->getSourceFiles()[0]);
}
public function testFilters(): void
{
- $filter = function ($code, \WebLoader\Compiler $loader) {
+ $filter = function ($code, Compiler $loader) {
return $code . $code;
};
$this->object->addFilter($filter);
@@ -150,7 +132,7 @@ public function testFilters(): void
public function testFileFilters(): void
{
- $filter = function ($code, \WebLoader\Compiler $loader, $file = null) {
+ $filter = function ($code, Compiler $loader, $file = null) {
return $code . $code;
};
$this->object->addFileFilter($filter);
@@ -159,20 +141,28 @@ public function testFileFilters(): void
}
- /**
- * @expectedException \TypeError
- */
public function testNonCallableFilter(): void
{
+ $this->expectException(TypeError::class);
$this->object->addFilter(4);
}
- /**
- * @expectedException \TypeError
- */
public function testNonCallableFileFilter(): void
{
+ $this->expectException(TypeError::class);
$this->object->addFileFilter(4);
}
+
+
+ private function generateFile(): File
+ {
+ $file = $this->object->generate();
+
+ if ($file === null) {
+ throw new Exception('Should not be empty');
+ }
+
+ return $file;
+ }
}
diff --git a/tests/DefaultOutputNamingConventionTest.php b/tests/DefaultOutputNamingConventionTest.php
old mode 100755
new mode 100644
index df285a1..3e7fee5
--- a/tests/DefaultOutputNamingConventionTest.php
+++ b/tests/DefaultOutputNamingConventionTest.php
@@ -3,7 +3,9 @@
namespace WebLoader\Test;
+use Mockery;
use PHPUnit\Framework\TestCase;
+use WebLoader\Compiler;
use WebLoader\DefaultOutputNamingConvention;
/**
@@ -14,16 +16,14 @@
class DefaultOutputNamingConventionTest extends TestCase
{
- /** @var DefaultOutputNamingConvention */
- private $object;
-
- private $compiler;
+ private DefaultOutputNamingConvention $object;
+ protected Compiler $compiler;
protected function setUp(): void
{
$this->object = new DefaultOutputNamingConvention();
- $this->compiler = \Mockery::mock('Webloader\Compiler');
+ $this->compiler = Mockery::mock(Compiler::class);
}
@@ -35,7 +35,7 @@ public function testMultipleFiles(): void
];
$name = $this->object->getFilename($files, $this->compiler);
- $this->assertRegExp('/^[0-9a-f]{12}$/', $name);
+ $this->assertMatchesRegularExpression('/^[0-9a-f]{12}$/', $name);
// another hash
$files[] = __DIR__ . DIRECTORY_SEPARATOR . 'fixtures' . DIRECTORY_SEPARATOR . 'c.txt';
@@ -51,7 +51,7 @@ public function testOneFile(): void
];
$name = $this->object->getFilename($files, $this->compiler);
- $this->assertRegExp('/^[0-9a-f]{12}$/', $name);
+ $this->assertMatchesRegularExpression('/^[0-9a-f]{12}$/', $name);
}
@@ -62,7 +62,7 @@ public function testCssConvention(): void
];
$name = DefaultOutputNamingConvention::createCssConvention()->getFilename($files, $this->compiler);
- $this->assertRegExp('/^[0-9a-f]{12}.css$/', $name);
+ $this->assertMatchesRegularExpression('/^[0-9a-f]{12}.css$/', $name);
}
@@ -73,6 +73,6 @@ public function testJsConvention(): void
];
$name = DefaultOutputNamingConvention::createJsConvention()->getFilename($files, $this->compiler);
- $this->assertRegExp('/^[0-9a-f]{12}.js$/', $name);
+ $this->assertMatchesRegularExpression('/^[0-9a-f]{12}.js$/', $name);
}
}
diff --git a/tests/FileCollectionTest.php b/tests/FileCollectionTest.php
index c5af843..2f8496f 100755
--- a/tests/FileCollectionTest.php
+++ b/tests/FileCollectionTest.php
@@ -3,8 +3,11 @@
namespace WebLoader\Test;
+use ArrayIterator;
use PHPUnit\Framework\TestCase;
+use SplFileInfo;
use WebLoader\FileCollection;
+use WebLoader\Exception\FileNotFoundException;
/**
* FileCollection test
@@ -14,8 +17,7 @@
class FileCollectionTest extends TestCase
{
- /** @var FileCollection */
- private $object;
+ private FileCollection $object;
protected function setUp(): void
@@ -39,16 +41,14 @@ public function testAddGetFiles(): void
}
- /**
- * @expectedException \Webloader\FileNotFoundException
- */
- public function testAddNonExistingFile()
+ public function testAddNonExistingFile(): void
{
+ $this->expectException(FileNotFoundException::class);
$this->object->addFile('sdfsdg.txt');
}
- public function testRemoveFile()
+ public function testRemoveFile(): void
{
$this->object->addFile(__DIR__ . '/fixtures/a.txt');
$this->object->addFile(__DIR__ . '/fixtures/b.txt');
@@ -63,7 +63,7 @@ public function testRemoveFile()
}
- public function testCannonicalizePath()
+ public function testCannonicalizePath(): void
{
$abs = __DIR__ . '/./fixtures/a.txt';
$rel = 'a.txt';
@@ -75,41 +75,23 @@ public function testCannonicalizePath()
try {
$this->object->cannonicalizePath('nesdagf');
$this->fail('Exception was not thrown.');
- } catch (\WebLoader\FileNotFoundException $e) {
+ } catch (FileNotFoundException $e) {
}
}
- public function testClear()
+ public function testClear(): void
{
$this->object->addFile('a.txt');
- $this->object->addRemoteFile('http://jquery.com/jquery.js');
$this->object->addWatchFile('b.txt');
$this->object->clear();
$this->assertEquals([], $this->object->getFiles());
- $this->assertEquals([], $this->object->getRemoteFiles());
$this->assertEquals([], $this->object->getWatchFiles());
}
- public function testRemoteFiles()
- {
- $this->object->addRemoteFile('http://jquery.com/jquery.js');
- $this->object->addRemoteFiles([
- 'http://jquery.com/jquery.js',
- 'http://google.com/angular.js',
- ]);
-
- $expected = [
- 'http://jquery.com/jquery.js',
- 'http://google.com/angular.js',
- ];
- $this->assertEquals($expected, $this->object->getRemoteFiles());
- }
-
-
- public function testWatchFiles()
+ public function testWatchFiles(): void
{
$this->object->addWatchFile(__DIR__ . '/fixtures/a.txt');
$this->object->addWatchFile(__DIR__ . '/fixtures/b.txt');
@@ -123,28 +105,25 @@ public function testWatchFiles()
}
- public function testTraversableFiles()
+ public function testTraversableFiles(): void
{
- $this->object->addFiles(new \ArrayIterator(['a.txt']));
- $this->assertEquals(1, count($this->object->getFiles()));
+ $this->object->addFiles(new ArrayIterator(['a.txt']));
+ $this->assertCount(1, $this->object->getFiles());
}
- public function testTraversableRemoteFiles()
+ public function testSplFileInfo(): void
{
- $this->object->addRemoteFiles(new \ArrayIterator(['http://jquery.com/jquery.js']));
- $this->assertEquals(1, count($this->object->getRemoteFiles()));
+ $this->object->addFile(new SplFileInfo(__DIR__ . '/fixtures/a.txt'));
+ $this->assertCount(1, $this->object->getFiles());
}
- public function testSplFileInfo()
- {
- $this->object->addFile(new \SplFileInfo(__DIR__ . '/fixtures/a.txt'));
- $this->assertEquals(1, count($this->object->getFiles()));
- }
-
-
- private function assertEqualPaths($expected, $actual)
+ /**
+ * @param mixed $expected
+ * @param mixed $actual
+ */
+ private function assertEqualPaths($expected, $actual): void
{
$actual = (array) $actual;
foreach ((array) $expected as $key => $path) {
diff --git a/tests/Filter/CssMinFilterTest.php b/tests/Filter/CssMinFilterTest.php
new file mode 100755
index 0000000..aeb8b9f
--- /dev/null
+++ b/tests/Filter/CssMinFilterTest.php
@@ -0,0 +1,38 @@
+filter = new CssMinFilter();
+
+ $files = new FileCollection(__DIR__ . '/../fixtures');
+ @mkdir($outputDir = __DIR__ . '/../temp/');
+ $this->compiler = new Compiler($files, new DefaultOutputNamingConvention(), $outputDir);
+ }
+
+
+ public function testMinify(): void
+ {
+ $file = __DIR__ . '/../fixtures/cssmin.css';
+ $minified = $this->filter->__invoke(
+ (string) file_get_contents($file),
+ $this->compiler,
+ $file
+ );
+ $this->assertSame(file_get_contents(__DIR__ . '/../fixtures/cssmin.css.expected'), $minified);
+ }
+}
diff --git a/tests/Filter/CssUrlsFilterTest.php b/tests/Filter/CssUrlsFilterTest.php
index 9113527..8d1b6d7 100755
--- a/tests/Filter/CssUrlsFilterTest.php
+++ b/tests/Filter/CssUrlsFilterTest.php
@@ -9,8 +9,7 @@
class CssUrlsFilterTest extends TestCase
{
- /** @var CssUrlsFilter */
- private $object;
+ private CssUrlsFilter $object;
protected function setUp(): void
diff --git a/tests/Filter/JsMinFilterTest.php b/tests/Filter/JsMinFilterTest.php
new file mode 100755
index 0000000..4bdb734
--- /dev/null
+++ b/tests/Filter/JsMinFilterTest.php
@@ -0,0 +1,38 @@
+filter = new JsMinFilter();
+
+ $files = new FileCollection(__DIR__ . '/../fixtures');
+ @mkdir($outputDir = __DIR__ . '/../temp/');
+ $this->compiler = new Compiler($files, new DefaultOutputNamingConvention(), $outputDir);
+ }
+
+
+ public function testMinify(): void
+ {
+ $file = __DIR__ . '/../fixtures/jsmin.js';
+ $minified = $this->filter->__invoke(
+ (string) file_get_contents($file),
+ $this->compiler,
+ $file
+ );
+ $this->assertSame(file_get_contents(__DIR__ . '/../fixtures/jsmin.js.expected'), $minified);
+ }
+}
diff --git a/tests/Filter/LessFilterTest.php b/tests/Filter/LessFilterTest.php
index e0d9c0d..20c9079 100755
--- a/tests/Filter/LessFilterTest.php
+++ b/tests/Filter/LessFilterTest.php
@@ -11,16 +11,13 @@
class LessFilterTest extends TestCase
{
- /** @var LessFilter */
- private $filter;
-
- /** @var Compiler */
- private $compiler;
+ private LessFilter $filter;
+ private Compiler $compiler;
protected function setUp(): void
{
- $this->filter = new LessFilter(new \lessc());
+ $this->filter = new LessFilter();
$files = new FileCollection(__DIR__ . '/../fixtures');
@mkdir($outputDir = __DIR__ . '/../temp/');
@@ -31,7 +28,12 @@ protected function setUp(): void
public function testReplace(): void
{
$file = __DIR__ . '/../fixtures/style.less';
- $less = $this->filter->__invoke(file_get_contents($file), $this->compiler, $file);
- $this->assertSame(file_get_contents(__DIR__ . '/../fixtures/style.less.expected'), $less);
+ $minified = $this->filter->__invoke(
+ (string) file_get_contents($file),
+ $this->compiler,
+ $file
+ );
+
+ $this->assertSame(file_get_contents(__DIR__ . '/../fixtures/style.less.expected'), $minified);
}
}
diff --git a/tests/Filter/PHPCoffeeScriptFilterTest.php b/tests/Filter/PHPCoffeeScriptFilterTest.php
deleted file mode 100755
index 3114ccf..0000000
--- a/tests/Filter/PHPCoffeeScriptFilterTest.php
+++ /dev/null
@@ -1,51 +0,0 @@
-object = new PHPCoffeeScriptFilter();
- }
-
-
- public function testSimpleLoadAndParse(): void
- {
- if (!class_exists('CoffeeScript\Compiler')) {
- $this->markTestSkipped('Missing CoffeeScript compiler.');
- }
-
- $compiler = new PHPCoffeeScriptFilter();
- $coffee = $compiler->compileCoffee('number = -42 if opposite', null);
-
- $version = COFFEESCRIPT_VERSION;
- $expected = <<assertEquals($expected, $coffee);
- }
-}
diff --git a/tests/Filter/ScssFilterTest.php b/tests/Filter/ScssFilterTest.php
index 1dd4904..5e643b1 100755
--- a/tests/Filter/ScssFilterTest.php
+++ b/tests/Filter/ScssFilterTest.php
@@ -4,6 +4,7 @@
namespace WebLoader\Test\Filter;
use PHPUnit\Framework\TestCase;
+use ScssPhp\ScssPhp\Compiler as ScssCompiler;
use WebLoader\Compiler;
use WebLoader\DefaultOutputNamingConvention;
use WebLoader\FileCollection;
@@ -12,16 +13,13 @@
class ScssFilterTest extends TestCase
{
- /** @var ScssFilter */
- private $filter;
-
- /** @var Compiler */
- private $compiler;
+ private ScssFilter $filter;
+ private Compiler $compiler;
protected function setUp(): void
{
- $this->filter = new ScssFilter(new \Leafo\ScssPhp\Compiler());
+ $this->filter = new ScssFilter(new ScssCompiler());
$files = new FileCollection(__DIR__ . '/../fixtures');
@mkdir($outputDir = __DIR__ . '/../temp/');
@@ -32,7 +30,11 @@ protected function setUp(): void
public function testReplace(): void
{
$file = __DIR__ . '/../fixtures/style.scss';
- $less = $this->filter->__invoke(file_get_contents($file), $this->compiler, $file);
+ $less = $this->filter->__invoke(
+ (string) file_get_contents($file),
+ $this->compiler,
+ $file
+ );
$this->assertSame(file_get_contents(__DIR__ . '/../fixtures/style.scss.expected'), $less);
}
@@ -41,9 +43,9 @@ public function testImportAbsolutePath(): void
{
$file = __DIR__ . '/../fixtures/styleAbsolute.scss';
$filter = new VariablesFilter([
- 'fixturesAbsolutePath' => realpath(__DIR__ . '/../fixtures'),
+ 'fixturesAbsolutePath' => (string) realpath(__DIR__ . '/../fixtures'),
]);
- $code = file_get_contents($file);
+ $code = (string) file_get_contents($file);
$filtered = $filter($code);
$less = $this->filter->__invoke($filtered, $this->compiler, $file);
$this->assertSame(file_get_contents(__DIR__ . '/../fixtures/styleAbsolute.scss.expected'), $less);
diff --git a/tests/Filter/VariablesFilterTest.php b/tests/Filter/VariablesFilterTest.php
old mode 100755
new mode 100644
index 3c3b534..9e720ee
--- a/tests/Filter/VariablesFilterTest.php
+++ b/tests/Filter/VariablesFilterTest.php
@@ -9,8 +9,7 @@
class VariablesFilterTest extends TestCase
{
- /** @var VariablesFilter */
- private $object;
+ private VariablesFilter $object;
protected function setUp(): void
diff --git a/tests/Nette/ExtensionTest.php b/tests/Nette/ExtensionTest.php
index 3fbb4c6..2856126 100755
--- a/tests/Nette/ExtensionTest.php
+++ b/tests/Nette/ExtensionTest.php
@@ -3,43 +3,61 @@
namespace WebLoader\Test\Nette;
-use Nette\Configurator;
+use Nette\Bootstrap\Configurator;
use Nette\DI\Compiler;
use Nette\DI\Container;
use Nette\Utils\Finder;
use PHPUnit\Framework\TestCase;
+use WebLoader\Compiler as WebloaderCompiler;
use WebLoader\Nette\Extension;
use WebLoader\Path;
-
class ExtensionTest extends TestCase
{
+ private Container $container;
+ private string $appDir;
+ private string $wwwDir;
+ private string $tempDir;
+ private string $fixturesDir;
+ private bool $debugMode;
+
- /** @var Container */
- private $container;
+ protected function setUp(): void
+ {
+ $this->appDir = __DIR__;
+ $this->wwwDir = $this->appDir . '/..';
+ $this->tempDir = $this->wwwDir . '/../temp';
+ $this->fixturesDir = $this->appDir . '/../fixtures';
+ $this->debugMode = false;
+ }
- private function prepareContainer($configFiles): void
+ /** @param list $configFiles */
+ private function prepareContainer(array $configFiles): void
{
- $tempDir = __DIR__ . '/../temp';
- foreach (Finder::findFiles('*')->exclude('.gitignore')->from($tempDir . '/cache') as $file) {
+ $finder = Finder::findFiles('*')
+ ->exclude('.gitignore')
+ ->from($this->tempDir . '/cache');
+
+ foreach ($finder as $file) {
unlink((string) $file);
}
$configurator = new Configurator();
- $configurator->setTempDirectory($tempDir);
+ $configurator->setTempDirectory($this->tempDir);
+ /** @var string $file */
foreach ($configFiles as $file) {
$configurator->addConfig($file);
}
$configurator->addParameters([
- 'wwwDir' => __DIR__ . '/..',
- 'fixturesDir' => __DIR__ . '/../fixtures',
- 'tempDir' => $tempDir,
+ 'wwwDir' => $this->wwwDir,
+ 'fixturesDir' => $this->fixturesDir,
+ 'tempDir' => $this->tempDir,
]);
- $extension = new Extension(__DIR__ . '/..', $configurator->isDebugMode());
+ $extension = new Extension($this->appDir, $this->wwwDir, $this->debugMode);
$extension->install($configurator);
$this->container = @$configurator->createContainer(); // sends header X-Powered-By, ...
@@ -48,55 +66,26 @@ private function prepareContainer($configFiles): void
public function testJsCompilerService(): void
{
- $this->prepareContainer([__DIR__ . '/../fixtures/extension.neon']);
+ $this->prepareContainer([$this->fixturesDir . '/extension.neon']);
$this->assertInstanceOf('WebLoader\Compiler', $this->container->getService('webloader.jsDefaultCompiler'));
}
public function testExcludeFiles(): void
{
- $this->prepareContainer([__DIR__ . '/../fixtures/extension.neon']);
+ $this->prepareContainer([$this->fixturesDir . '/extension.neon']);
$files = $this->container->getService('webloader.jsExcludeCompiler')->getFileCollection()->getFiles();
- $this->assertTrue(in_array(Path::normalize(__DIR__ . '/../fixtures/a.txt'), $files, true));
- $this->assertFalse(in_array(Path::normalize(__DIR__ . '/../fixtures/dir/one.js'), $files, true));
- }
-
-
- public function testJoinFilesOn(): void
- {
- $this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionJoinFilesTrue.neon',
- ]);
- $this->assertTrue($this->container->getService('webloader.jsDefaultCompiler')->getJoinFiles());
- }
-
-
- public function testJoinFilesOff(): void
- {
- $this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionJoinFilesFalse.neon',
- ]);
- $this->assertFalse($this->container->getService('webloader.jsDefaultCompiler')->getJoinFiles());
- }
-
-
- public function testJoinFilesOffInOneService(): void
- {
- $this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- ]);
- $this->assertFalse($this->container->getService('webloader.cssJoinOffCompiler')->getJoinFiles());
+ $this->assertTrue(in_array(Path::normalize($this->fixturesDir . '/a.txt'), $files, true));
+ $this->assertFalse(in_array(Path::normalize($this->fixturesDir . '/dir/one.js'), $files, true));
}
public function testAsyncOn(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionAsyncTrue.neon',
+ $this->fixturesDir . '/extension.neon',
+ $this->fixturesDir . '/extensionAsyncTrue.neon',
]);
$this->assertTrue($this->container->getService('webloader.jsDefaultCompiler')->isAsync());
}
@@ -105,8 +94,8 @@ public function testAsyncOn(): void
public function testAsyncOff(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionAsyncFalse.neon',
+ $this->fixturesDir . '/extension.neon',
+ $this->fixturesDir . '/extensionAsyncFalse.neon',
]);
$this->assertFalse($this->container->getService('webloader.jsDefaultCompiler')->isAsync());
}
@@ -115,8 +104,8 @@ public function testAsyncOff(): void
public function testDeferOn(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionDeferTrue.neon',
+ $this->fixturesDir . '/extension.neon',
+ $this->fixturesDir . '/extensionDeferTrue.neon',
]);
$this->assertTrue($this->container->getService('webloader.jsDefaultCompiler')->isDefer());
}
@@ -125,8 +114,8 @@ public function testDeferOn(): void
public function testDeferOff(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionDeferFalse.neon',
+ $this->fixturesDir . '/extension.neon',
+ $this->fixturesDir . '/extensionDeferFalse.neon',
]);
$this->assertFalse($this->container->getService('webloader.jsDefaultCompiler')->isDefer());
}
@@ -135,8 +124,8 @@ public function testDeferOff(): void
public function testAbsoluteUrlOn(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionAbsoluteUrlTrue.neon',
+ $this->fixturesDir . '/extension.neon',
+ $this->fixturesDir . '/extensionAbsoluteUrlTrue.neon',
]);
$this->assertTrue($this->container->getService('webloader.jsDefaultCompiler')->isAbsoluteUrl());
}
@@ -145,8 +134,8 @@ public function testAbsoluteUrlOn(): void
public function testAbsoluteUrlOff(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionAbsoluteUrlFalse.neon',
+ $this->fixturesDir . '/extension.neon',
+ $this->fixturesDir . '/extensionAbsoluteUrlFalse.neon',
]);
$this->assertFalse($this->container->getService('webloader.jsDefaultCompiler')->isAbsoluteUrl());
}
@@ -155,8 +144,8 @@ public function testAbsoluteUrlOff(): void
public function testNonceSet(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
- __DIR__ . '/../fixtures/extensionNonce.neon',
+ $this->fixturesDir . '/extension.neon',
+ $this->fixturesDir . '/extensionNonce.neon',
]);
$this->assertEquals('rAnd0m123', $this->container->getService('webloader.jsDefaultCompiler')->getNonce());
}
@@ -165,7 +154,7 @@ public function testNonceSet(): void
public function testNonceNotSet(): void
{
$this->prepareContainer([
- __DIR__ . '/../fixtures/extension.neon',
+ $this->fixturesDir . '/extension.neon',
]);
$this->assertNull($this->container->getService('webloader.jsDefaultCompiler')->getNonce());
}
@@ -173,20 +162,25 @@ public function testNonceNotSet(): void
public function testExtensionName(): void
{
- $tempDir = __DIR__ . '/../temp';
$class = 'ExtensionNameServiceContainer';
$configurator = new Configurator();
- $configurator->setTempDirectory($tempDir);
+ $configurator->setTempDirectory($this->tempDir);
$configurator->addParameters(['container' => ['class' => $class]]);
$configurator->onCompile[] = function (Configurator $configurator, Compiler $compiler) {
- $extension = new Extension(__DIR__ . '/..', $configurator->isDebugMode());
+ $extension = new Extension($this->appDir, $this->wwwDir, $this->debugMode);
$compiler->addExtension('Foo', $extension);
};
- $configurator->addConfig(__DIR__ . '/../fixtures/extensionName.neon');
+ $configurator->addConfig($this->fixturesDir . '/extensionName.neon');
$container = $configurator->createContainer();
- $this->assertInstanceOf('WebLoader\Compiler', $container->getService('Foo.cssDefaultCompiler'));
- $this->assertInstanceOf('WebLoader\Compiler', $container->getService('Foo.jsDefaultCompiler'));
+ $this->assertInstanceOf(
+ WebloaderCompiler::class,
+ $container->getService('Foo.cssDefaultCompiler')
+ );
+ $this->assertInstanceOf(
+ WebloaderCompiler::class,
+ $container->getService('Foo.jsDefaultCompiler')
+ );
}
}
diff --git a/tests/Path/PathTest.php b/tests/Path/PathTest.php
index b8f25dd..1fabe27 100755
--- a/tests/Path/PathTest.php
+++ b/tests/Path/PathTest.php
@@ -13,4 +13,11 @@ public function testNormalize(): void
$normalized = Path::normalize('/path/to//project//that/contains/0/in/it');
$this->assertEquals('/path/to/project/that/contains/0/in/it', $normalized);
}
+
+
+ public function testDirectoryJump(): void
+ {
+ $normalized = Path::normalize('/path/to/my/project/../../wrong/path/../../correct/one/');
+ $this->assertEquals('/path/to/correct/one/', $normalized);
+ }
}
diff --git a/tests/fixtures/cssmin.css b/tests/fixtures/cssmin.css
new file mode 100755
index 0000000..6ad0010
--- /dev/null
+++ b/tests/fixtures/cssmin.css
@@ -0,0 +1,57 @@
+.clearFix {
+ display: block;
+ zoom: 1;
+}
+.clearFix:after {
+ content: " ";
+ display: block;
+ font-size: 0;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+div.banners {
+ display: block;
+ zoom: 1;
+ padding: 0 0 20px;
+ margin: 0 10px;
+ border-bottom: #f4f4f4 1px solid;
+}
+div.banners:after {
+ content: " ";
+ display: block;
+ font-size: 0;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+div.banners > div {
+ float: left;
+ width: 610px;
+ height: 194px;
+ background: #f9f2e8;
+ margin: 20px 0 0 20px;
+ position: relative;
+}
+div.banners > div h3 {
+ width: auto;
+ color: #be2025;
+ font-weight: 600;
+ padding: 10px 20px;
+ margin: 10px 10px 0 10px;
+ text-shadow: 0 2px 0 rgba(0, 0, 0, 0.3);
+ display: inline-block;
+ font-size: 24px;
+}
+div.banners > div h3,
+div.banners > div p {
+ color: #ffffff;
+}
+div.banners > div p {
+ font-size: 13px;
+ max-width: 360px;
+ padding: 10px;
+}
+div.banners > div p strong {
+ font-weight: 600;
+}
diff --git a/tests/fixtures/cssmin.css.expected b/tests/fixtures/cssmin.css.expected
new file mode 100755
index 0000000..10ae4dd
--- /dev/null
+++ b/tests/fixtures/cssmin.css.expected
@@ -0,0 +1 @@
+.clearFix{display:block;zoom:1}.clearFix:after{content:" ";display:block;font-size:0;height:0;clear:both;visibility:hidden}div.banners{display:block;zoom:1;padding:0 0 20px;margin:0 10px;border-bottom:#f4f4f4 1px solid}div.banners:after{content:" ";display:block;font-size:0;height:0;clear:both;visibility:hidden}div.banners>div{float:left;width:610px;height:194px;background:#f9f2e8;margin:20px 0 0 20px;position:relative}div.banners>div h3{width:auto;color:#be2025;font-weight:600;padding:10px 20px;margin:10px 10px 0;text-shadow:0 2px 0 rgba(0,0,0,.3);display:inline-block;font-size:24px}div.banners>div h3,div.banners>div p{color:#fff}div.banners>div p{font-size:13px;max-width:360px;padding:10px}div.banners>div p strong{font-weight:600}
\ No newline at end of file
diff --git a/tests/fixtures/extension.neon b/tests/fixtures/extension.neon
index d8ac1d8..b71f33c 100755
--- a/tests/fixtures/extension.neon
+++ b/tests/fixtures/extension.neon
@@ -1,6 +1,3 @@
-parameters:
- cssJoinFiles: false
-
http:
frames: yes
@@ -20,16 +17,9 @@ webloader:
files:
- style.css
- {files: ["*.css"], from: %fixturesDir%/dir}
- joinOff:
- joinFiles: %cssJoinFiles%
- files:
- - style.css
js:
default:
- remoteFiles:
- - http://ajax.googleapis.com/ajax/libs/jquery/1.7/jquery.min.js
- - http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.min.js
files:
- %fixturesDir%/dir/one.js
- dir/two.js
@@ -37,4 +27,4 @@ webloader:
- @variablesFilter
exclude:
files:
- - {files: ["*"], from: %fixturesDir%, exclude: [dir/*]}
\ No newline at end of file
+ - {files: ["*"], from: %fixturesDir%, exclude: [dir/*]}
diff --git a/tests/fixtures/extensionJoinFilesFalse.neon b/tests/fixtures/extensionJoinFilesFalse.neon
deleted file mode 100644
index 8a3f58d..0000000
--- a/tests/fixtures/extensionJoinFilesFalse.neon
+++ /dev/null
@@ -1,3 +0,0 @@
-webloader:
- jsDefaults:
- joinFiles: false
\ No newline at end of file
diff --git a/tests/fixtures/extensionJoinFilesTrue.neon b/tests/fixtures/extensionJoinFilesTrue.neon
deleted file mode 100644
index 1523860..0000000
--- a/tests/fixtures/extensionJoinFilesTrue.neon
+++ /dev/null
@@ -1,3 +0,0 @@
-webloader:
- jsDefaults:
- joinFiles: true
\ No newline at end of file
diff --git a/tests/fixtures/jsmin.js b/tests/fixtures/jsmin.js
new file mode 100755
index 0000000..2dd0288
--- /dev/null
+++ b/tests/fixtures/jsmin.js
@@ -0,0 +1,9 @@
+;(function() {
+ window.alert('Hello World!');
+
+ if (true === false) {
+ window.alert('Paradox');
+ } else {
+ window.alert('All is well.');
+ }
+})();
diff --git a/tests/fixtures/jsmin.js.expected b/tests/fixtures/jsmin.js.expected
new file mode 100755
index 0000000..238dd79
--- /dev/null
+++ b/tests/fixtures/jsmin.js.expected
@@ -0,0 +1 @@
+;(function(){window.alert('Hello World!');if(true===false){window.alert('Paradox');}else{window.alert('All is well.');}})();
\ No newline at end of file
diff --git a/tests/fixtures/style.scss b/tests/fixtures/style.scss
index 2e98946..2334920 100644
--- a/tests/fixtures/style.scss
+++ b/tests/fixtures/style.scss
@@ -1,19 +1,18 @@
-
@import 'style2.scss';
.navigation {
- ul {
- line-height: 20px;
- color: blue;
- a {
- color: red;
- }
- }
+ ul {
+ line-height: 20px;
+ color: blue;
+
+ a {
+ color: red;
+ }
+ }
}
.footer {
- .copyright {
- color: silver;
- }
+ .copyright {
+ color: silver;
+ }
}
-
diff --git a/tests/fixtures/style.scss.expected b/tests/fixtures/style.scss.expected
index d4249e7..fe3ebaf 100644
--- a/tests/fixtures/style.scss.expected
+++ b/tests/fixtures/style.scss.expected
@@ -1,12 +1,16 @@
.clearFix {
display: block;
- zoom: 1; }
+ zoom: 1;
+}
.navigation ul {
line-height: 20px;
- color: blue; }
- .navigation ul a {
- color: red; }
+ color: blue;
+}
+.navigation ul a {
+ color: red;
+}
.footer .copyright {
- color: silver; }
+ color: silver;
+}
\ No newline at end of file
diff --git a/tests/fixtures/style2.scss b/tests/fixtures/style2.scss
index 1155d28..8de238e 100644
--- a/tests/fixtures/style2.scss
+++ b/tests/fixtures/style2.scss
@@ -1,4 +1,4 @@
.clearFix {
- display: block;
- zoom: 1;
+ display: block;
+ zoom: 1;
}
diff --git a/tests/fixtures/styleAbsolute.scss b/tests/fixtures/styleAbsolute.scss
index e4ed002..2958f1d 100644
--- a/tests/fixtures/styleAbsolute.scss
+++ b/tests/fixtures/styleAbsolute.scss
@@ -1,19 +1,19 @@
-
@import '{{$fixturesAbsolutePath}}/style2.scss';
.navigation {
- ul {
- line-height: 20px;
- color: blue;
- a {
- color: red;
- }
- }
+ ul {
+ line-height: 20px;
+ color: blue;
+
+ a {
+ color: red;
+ }
+ }
}
.footer {
- .copyright {
- color: silver;
- }
+ .copyright {
+ color: silver;
+ }
}
diff --git a/tests/fixtures/styleAbsolute.scss.expected b/tests/fixtures/styleAbsolute.scss.expected
index d4249e7..fe3ebaf 100644
--- a/tests/fixtures/styleAbsolute.scss.expected
+++ b/tests/fixtures/styleAbsolute.scss.expected
@@ -1,12 +1,16 @@
.clearFix {
display: block;
- zoom: 1; }
+ zoom: 1;
+}
.navigation ul {
line-height: 20px;
- color: blue; }
- .navigation ul a {
- color: red; }
+ color: blue;
+}
+.navigation ul a {
+ color: red;
+}
.footer .copyright {
- color: silver; }
+ color: silver;
+}
\ No newline at end of file
diff --git a/tests/phpunit.xml b/tests/phpunit.xml
index 9e655c9..0cfdb62 100644
--- a/tests/phpunit.xml
+++ b/tests/phpunit.xml
@@ -1,12 +1,3 @@
-
+
+