diff --git a/FUNDING.yml b/.github/FUNDING.yml similarity index 100% rename from FUNDING.yml rename to .github/FUNDING.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..82795b2 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,133 @@ +name: Tests + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +env: + PACKAGE_FOLDER: Shel.CriticalCSS + +jobs: + codestyle: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.2 + + - name: Add additional dependencies + run: | + composer require --no-update --no-interaction neos/contentgraph-doctrinedbaladapter:"~9.0.0" + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ~/.composer/cache + key: dependencies-composer-${{ hashFiles('composer.json') }} + + - name: Install dependencies + uses: php-actions/composer@v6 + with: + php_version: 8.2 + version: 2 + + - name: PHPStan + uses: php-actions/phpstan@v3 + with: + php_version: 8.2 + version: 2.1.17 + command: analyse + path: 'Classes/' + + build: + runs-on: ubuntu-latest + + strategy: + matrix: + php-versions: + - '8.2' + neosVersion: + - '9.0' + + services: + mariadb: + # see https://mariadb.com/kb/en/mariadb-server-release-dates/ + # this should be a current release, e.g. the LTS version + image: mariadb:10.8 + env: + MYSQL_USER: neos + MYSQL_PASSWORD: neos + MYSQL_DATABASE: neos_functional_testing + MYSQL_ROOT_PASSWORD: neos + ports: + - "3306:3306" + options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + + name: 'Shel.CriticalCSS with Neos ${{ matrix.neosVersion }} test' + + env: + NEOS_TARGET_VERSION: ${{matrix.neosVersion}} + FLOW_CONTEXT: Testing + FLOW_FOLDER: ../neos-base-distribution + + steps: + - uses: actions/checkout@v3 + + - name: Set package branch name + run: echo "PACKAGE_TARGET_VERSION=${GITHUB_BASE_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_ENV + working-directory: . + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, xml, json, zlib, iconv, intl, pdo_sqlite, mysql + tools: composer:v2 + + - name: Cache dependencies + uses: actions/cache@v3 + with: + path: ~/.composer/cache + key: dependencies-composer-${{ hashFiles('composer.json') }} + + - name: Prepare Flow distribution + run: | + git clone https://github.com/neos/neos-base-distribution.git -b ${NEOS_TARGET_VERSION} ${FLOW_FOLDER} + cd ${FLOW_FOLDER} + + git -C ../${{ env.PACKAGE_FOLDER }} checkout -b build + composer config repositories.package '{ "type": "path", "url": "../${{ env.PACKAGE_FOLDER }}", "options": { "symlink": false } }' + composer require --no-update --no-interaction shel/critical-css:"dev-build as dev-${PACKAGE_TARGET_VERSION}" + composer require --no-update --no-interaction neos/contentgraph-doctrinedbaladapter:"~9.0.0" + + - name: Composer Install + run: | + cd ${FLOW_FOLDER} + composer update --no-interaction --no-progress + + - name: Setup Flow configuration + run: | + cd ${FLOW_FOLDER} + rm -f Configuration/Testing/Settings.yaml + cat <> Configuration/Testing/Settings.yaml + Neos: + Flow: + persistence: + backendOptions: + host: '127.0.0.1' + driver: pdo_mysql + user: 'neos' + password: 'neos' + dbname: 'neos_functional_testing' + EOF + + - name: Run Functional tests + run: | + cd ${FLOW_FOLDER} + bin/phpunit --colors -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Plugins/Shel.CriticalCSS/Tests/Functional/ diff --git a/.styleci.yml b/.styleci.yml deleted file mode 100644 index 14c4d58..0000000 --- a/.styleci.yml +++ /dev/null @@ -1,6 +0,0 @@ -preset: psr2 - -finder: - path: - - "Classes" - - "Tests" diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4703c80..0000000 --- a/.travis.yml +++ /dev/null @@ -1,23 +0,0 @@ -language: php -sudo: false -git: - depth: 5 - submodules: false -matrix: - include: - - php: 7.4 - -before_install: - - export FLOW_TARGET_VERSION=7.0 - - cd .. - - git clone https://github.com/neos/flow-base-distribution.git -b ${FLOW_TARGET_VERSION} - - cd flow-base-distribution - - composer require --no-update --no-interaction shel/critical-css -install: - - composer install --no-interaction - - cd .. - - rm -rf flow-base-distribution/Packages/Plugins/Shel.CriticalCSS - - mv Shel.CriticalCSS flow-base-distribution/Packages/Plugins/Shel.CriticalCSS - - cd flow-base-distribution -script: - - bin/phpunit --colors -c Build/BuildEssentials/PhpUnit/FunctionalTests.xml Packages/Plugins/Shel.CriticalCSS/Tests/Functional/ diff --git a/Classes/Command/StylesCommandController.php b/Classes/Command/StylesCommandController.php index b1fe6ee..ae7629b 100644 --- a/Classes/Command/StylesCommandController.php +++ b/Classes/Command/StylesCommandController.php @@ -11,33 +11,18 @@ use Neos\Flow\Annotations as Flow; use Neos\Flow\Cli\CommandController; use Neos\Flow\Mvc\ActionRequest; -use Neos\Flow\Mvc\ActionResponse; -use Neos\Flow\Mvc\Controller\Arguments; -use Neos\Flow\Mvc\Controller\ControllerContext; -use Neos\Flow\Mvc\Routing\UriBuilder; use Neos\Flow\Security\Exception as SecurityException; use Neos\Neos\Domain\Repository\SiteRepository; use Shel\CriticalCSS\Fusion\FusionView; -use Shel\CriticalCSS\Service\FusionService; /** * The User Command Controller - * - * @Flow\Scope("singleton") */ +#[Flow\Scope('singleton')] class StylesCommandController extends CommandController { - /** - * @Flow\Inject - * @var SiteRepository - */ - protected $siteRepository; - - /** - * @Flow\Inject - * @var FusionService - */ - protected $fusionService; + #[Flow\Inject] + protected SiteRepository $siteRepository; /** * This command returns all styles for a given site node and prototype name. @@ -56,7 +41,7 @@ public function exportCommand(string $siteNodeName, string $basePrototypeName = } $fusionView = new FusionView(); - $fusionView->setControllerContext($this->createSimpleControllerContext()); + $fusionView->assign('request', $this->createSimpleControllerRequest()); $fusionView->setFusionPath('shelCriticalStyles'); $fusionView->setPackageKey($site->getSiteResourcesPackageKey()); $fusionView->assign('site', $site->getNodeName()); @@ -65,17 +50,11 @@ public function exportCommand(string $siteNodeName, string $basePrototypeName = } /** - * Create a simple controller context which can be used to instantiate a Fusion runtime etc. + * Create a simple controller context which can be used to instantiate a Fusion runtime, etc. */ - protected function createSimpleControllerContext(): ControllerContext + protected function createSimpleControllerRequest(): ActionRequest { $httpRequest = new ServerRequest('POST', 'http://localhost'); - $request = ActionRequest::fromHttpRequest($httpRequest); - $response = new ActionResponse(); - $arguments = new Arguments([]); - $uriBuilder = new UriBuilder(); - $uriBuilder->setRequest($request); - - return new ControllerContext($request, $response, $arguments, $uriBuilder); + return ActionRequest::fromHttpRequest($httpRequest); } } diff --git a/Classes/Fusion/FusionView.php b/Classes/Fusion/FusionView.php index 5322627..4b549cb 100644 --- a/Classes/Fusion/FusionView.php +++ b/Classes/Fusion/FusionView.php @@ -10,7 +10,8 @@ use Neos\Flow\Annotations as Flow; use Neos\Flow\Mvc\Exception; use Neos\Flow\Security\Exception as SecurityException; -use Neos\FluidAdaptor\View\TemplateView; +use Neos\Fusion\Core\FusionConfiguration; +use Neos\Fusion\Core\FusionGlobals; use Neos\Fusion\View\FusionView as BaseFusionView; use Neos\Fusion\Core\Runtime as FusionRuntime; use Shel\CriticalCSS\Service\FusionService; @@ -20,30 +21,20 @@ */ class FusionView extends BaseFusionView { - protected $styleRenderPath = 'shelCriticalStyles'; + protected string $styleRenderPath = 'shelCriticalStyles'; - /** - * @Flow\Inject - * @var FusionService - */ - protected $fusionService; - - /** - * @Flow\Inject - * @var TemplateView - */ - protected $fallbackView; + #[Flow\Inject] + protected FusionService $fusionService; /** * @inheritDoc + * @throws Exception */ protected function loadFusion(): void { - $fusionAst = []; - try { - $fusionAst = $this->fusionService->getMergedFusionObjectTreeForSitePackage($this->getOption('packageKey')); - } catch (Exception $e) { - } + $fusionAst = $this->fusionService->getFusionConfigurationForSitePackage( + $this->getOption('packageKey') + ); $this->parsedFusion = $fusionAst; } @@ -51,24 +42,31 @@ protected function loadFusion(): void * Iterates through the Fusion AST and renders all instantiated * objects of the given prototype and returns the concatenated results as string. * - * @param string $stylePrototypeName - * @return string * @throws SecurityException */ public function renderStyles(string $stylePrototypeName): string { + /** @noinspection PhpConditionAlreadyCheckedInspection */ + /** @phpstan-ignore booleanNot.alwaysFalse */ if (!$this->parsedFusion) { - $this->loadFusion(); + try { + $this->loadFusion(); + } catch (Exception) { + return ''; + } + } + $fusionAst = $this->parsedFusion->toArray(); + $prototypes = $fusionAst['__prototypes'] ?? []; + + if (!$prototypes) { + return ''; } - $fusionAst = $this->parsedFusion; - $prototypes = $fusionAst['__prototypes']; $arrayIterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($fusionAst)); $outputArray = []; /** @noinspection PhpUnusedLocalVariableInspection */ foreach ($arrayIterator as $sub) { - $subArray = $arrayIterator->getSubIterator(); - /** @noinspection PhpParamsInspection */ + $subArray = iterator_to_array($arrayIterator->getSubIterator()); if (!array_key_exists('__objectType', $subArray)) { continue; } @@ -77,7 +75,7 @@ public function renderStyles(string $stylePrototypeName): string ($prototypeName && array_key_exists($prototypeName, $prototypes) && array_key_exists('__prototypeChain', $prototypes[$prototypeName]) - && in_array($stylePrototypeName, $prototypes[$prototypeName]['__prototypeChain']))) { + && in_array($stylePrototypeName, $prototypes[$prototypeName]['__prototypeChain'], true))) { $props = iterator_to_array($subArray); $props['__meta']['stylesOnly'] = true; $outputArray[] = $props; @@ -89,7 +87,10 @@ public function renderStyles(string $stylePrototypeName): string // Render each found instantiated prototype foreach ($outputArray as $props) { $fusionAst[$this->styleRenderPath] = $props; - $fusionRuntime = new FusionRuntime($fusionAst, $this->controllerContext); + $fusionGlobals = FusionGlobals::fromArray(array_filter([ + 'request' => $this->assignedActionRequest, + ])); + $fusionRuntime = new FusionRuntime(FusionConfiguration::fromArray($fusionAst), $fusionGlobals); $fusionRuntime->pushContextArray($this->variables); $output .= $fusionRuntime->render($this->styleRenderPath); $fusionRuntime->popContext(); diff --git a/Classes/FusionObjects/LoadStylesImplementation.php b/Classes/FusionObjects/LoadStylesImplementation.php index 0bf856c..b655643 100644 --- a/Classes/FusionObjects/LoadStylesImplementation.php +++ b/Classes/FusionObjects/LoadStylesImplementation.php @@ -1,4 +1,5 @@ fusionValue('path'); } - /** - * @return string - */ public function evaluate(): string { try { $styles = $this->loadResourceContent($this->getPath()); - } catch (InvalidVariableException $e) { + } catch (InvalidVariableException) { throw new \InvalidArgumentException('Resource ' . $this->getPath() . ' cannot be loaded!', 1573314641); } @@ -51,8 +45,6 @@ public function evaluate(): string /** * Loads the content of a resource and returns it as string - * - * @return string Content of the resource * @throws InvalidVariableException */ public function loadResourceContent(?string $path): string @@ -60,7 +52,6 @@ public function loadResourceContent(?string $path): string if ($path === null) { throw new InvalidVariableException('You have to define a path.', 1573317165); } - - return file_get_contents($path); + return file_get_contents($path) ?: ''; } } diff --git a/Classes/FusionObjects/StyleCollectorImplementation.php b/Classes/FusionObjects/StyleCollectorImplementation.php index 8da6652..02564f0 100644 --- a/Classes/FusionObjects/StyleCollectorImplementation.php +++ b/Classes/FusionObjects/StyleCollectorImplementation.php @@ -11,7 +11,7 @@ /** * Collects all style tags defined with the `Shel.CriticalCSS:Styles` object - * and puts them in the html head or at the start of the object the collector is applied to. + * and puts them in the HTML head or at the start of the object the collector is applied to. */ class StyleCollectorImplementation extends AbstractFusionObject { @@ -22,21 +22,30 @@ public function evaluate() { $content = $this->fusionValue('content'); - preg_match_all('/'; - if (strpos($content, '') !== false) { - return str_replace('', $styleTag . '', $content); + if (str_contains($modifiedContent, '')) { + /** @var string $modifiedContent */ + $modifiedContent = str_replace('', $styleTag . '', $modifiedContent); + if ($modifiedContent) { + return $modifiedContent; + } + return $content; } - return $styleTag . $content; + return $styleTag . $modifiedContent; } } diff --git a/Classes/FusionObjects/StylesImplementation.php b/Classes/FusionObjects/StylesImplementation.php index 83a4d85..60af901 100644 --- a/Classes/FusionObjects/StylesImplementation.php +++ b/Classes/FusionObjects/StylesImplementation.php @@ -14,36 +14,28 @@ use Shel\CriticalCSS\Service\StylesService; /** - * Adds all attributes as css styles into a style tag with a css class and adds the class to the tag + * Adds all attributes as CSS styles into a style tag with a CSS class and adds the class to the tag */ class StylesImplementation extends DataStructureImplementation { - /** - * @Flow\Inject - * @var HtmlAugmenter - */ - protected $htmlAugmenter; + #[Flow\Inject] + protected HtmlAugmenter $htmlAugmenter; - /** - * @Flow\Inject - * @var StylesService - */ - protected $stylesService; + #[Flow\Inject] + protected StylesService $stylesService; /** * Properties that are ignored * - * @var array + * @var string[] */ protected $ignoreProperties = ['__meta']; /** - * The content that will be applied the generated css class or + * The content that will be applied the generated CSS class or * if it's multiple elements they will be wrapped with a new * tag and the generated class. See `fallbackTagName`. - * - * @return string */ protected function getContent(): string { @@ -54,8 +46,6 @@ protected function getContent(): string * The tag that will be used when content contains multiple tags * and needs to be wrapped for a class to be applied. * This behaves the same as with the HTML Augmenter. - * - * @return string */ protected function getFallbackTagName(): string { @@ -63,11 +53,9 @@ protected function getFallbackTagName(): string } /** - * When this is set a selector is used instead of the generated class. - * - * @return bool|string + * When this is set, a selector is used instead of the generated class. */ - protected function getSelector() + protected function getSelector(): bool|string { return $this->fusionValue('__meta/selector') ?? false; } @@ -86,13 +74,13 @@ protected function getClassPrefix(): string } /** - * @return string * @throws FusionException + * @phpstan-ignore method.childReturnType */ public function evaluate(): string { $content = $this->getContent(); - $sortedChildFusionKeys = $this->sortNestedFusionKeys(); + $sortedChildFusionKeys = $this->preparePropertyKeys($this->properties, $this->ignoreProperties); $selector = $this->getSelector(); $classPrefix = $this->getClassPrefix(); @@ -100,7 +88,7 @@ public function evaluate(): string foreach ($sortedChildFusionKeys as $key) { $value = $this->fusionValue($key); - // When using simple nesting with `{` instead of using Neos.Fusion:DataStructure + // When using simple nesting with `{` instead of using Neos.Fusion:DataStructure, // we have to retrieve the value from the properties as the value is null. if ($value === null && array_key_exists($key, $this->properties)) { $value = $this->properties[$key]; @@ -112,7 +100,7 @@ public function evaluate(): string $styleProperties[$key] = $value; } - $path = [$selector !== false ? $selector : '.' . $classPrefix . '#{$hash}']; + $path = [$selector !== false ? (string)$selector : '.' . $classPrefix . '#{$hash}']; $stylesHash = $this->stylesService->getHashForStyles($styleProperties, $path); $styles = $this->stylesService->renderStyles($styleProperties, $path); $styles = str_replace('#{$hash}', $stylesHash, $styles); @@ -139,7 +127,7 @@ public function evaluate(): string /** * @param string $path - * @param array $props + * @param array $props */ protected function evaluateNestedProps(string $path, array &$props): void { diff --git a/Classes/Http/StyleMiddleware.php b/Classes/Http/StyleMiddleware.php index e7504b4..57cebd0 100644 --- a/Classes/Http/StyleMiddleware.php +++ b/Classes/Http/StyleMiddleware.php @@ -1,4 +1,5 @@ handle($request); @@ -39,17 +32,16 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface return $response; } - if (strpos($request->getUri()->getPath(), '/neos/') === 0) { + if (str_starts_with($request->getUri()->getPath(), '/neos/')) { return $response; } - $content = $response->getBody()->getContents(); + $renderedContent = $response->getBody()->getContents(); $response->getBody()->rewind(); // Retrieve all inline style tags - preg_match_all('/'; - $content = str_replace('', $styleTag . '', $content); + $content = preg_replace('/'; + $content = str_replace('', $styleTag . '', $content); + } else { + $content = $renderedContent; + } return $response->withBody(ContentStream::fromContents($content)); } diff --git a/Classes/Service/FusionService.php b/Classes/Service/FusionService.php index 2a1f018..dbdb091 100644 --- a/Classes/Service/FusionService.php +++ b/Classes/Service/FusionService.php @@ -8,8 +8,8 @@ */ use Neos\Flow\Annotations as Flow; -use Neos\Fusion\Exception as FusionException; -use Neos\Neos\Domain\Exception as DomainException; +use Neos\Fusion\Core\FusionConfiguration; +use Neos\Neos\Domain\Repository\SiteRepository; use Neos\Neos\Domain\Service\FusionService as NeosFusionService; /** @@ -17,30 +17,17 @@ class FusionService extends NeosFusionService { - /** - * @Flow\InjectConfiguration(path="fusion.autoInclude", package="Neos.Neos") - * @var array - */ - protected $autoIncludeConfiguration = []; + #[Flow\Inject] + protected SiteRepository $siteRepository; /** * Returns a merged fusion object tree in the context of the given site-package - * - * @param string $siteResourcesPackageKey - * @return array The merged object tree as of the given node - * @throws DomainException - * @throws FusionException */ - public function getMergedFusionObjectTreeForSitePackage(string $siteResourcesPackageKey): array + public function getFusionConfigurationForSitePackage(string $siteResourcesPackageKey): FusionConfiguration { - $siteRootFusionPathAndFilename = sprintf($this->siteRootFusionPattern, $siteResourcesPackageKey); - - $mergedFusionCode = $this->generateNodeTypeDefinitions(); - $mergedFusionCode .= $this->getFusionIncludes($this->prepareAutoIncludeFusion()); - $mergedFusionCode .= $this->getFusionIncludes($this->prependFusionIncludes); - $mergedFusionCode .= $this->readExternalFusionFile($siteRootFusionPathAndFilename); - $mergedFusionCode .= $this->getFusionIncludes($this->appendFusionIncludes); + /** @noinspection PhpUndefinedMethodInspection */ + $site = $this->siteRepository->findOneBySiteResourcesPackageKey($siteResourcesPackageKey); - return $this->fusionParser->parse($mergedFusionCode, $siteRootFusionPathAndFilename); + return $this->createFusionConfigurationFromSite($site); } } diff --git a/Classes/Service/StylesService.php b/Classes/Service/StylesService.php index 3532cf7..c1fb15c 100644 --- a/Classes/Service/StylesService.php +++ b/Classes/Service/StylesService.php @@ -11,20 +11,18 @@ /** * The User Command Controller - * - * @Flow\Scope("singleton") */ +#[Flow\Scope('singleton')] class StylesService { /** - * @var array + * @var array */ - protected $stylesCache = []; + protected array $stylesCache = []; /** - * @param array $styleProperties - * @param array $path - * @return string + * @param array $styleProperties + * @param string[] $path */ public function getHashForStyles(array $styleProperties, array $path = []): string { @@ -32,9 +30,8 @@ public function getHashForStyles(array $styleProperties, array $path = []): stri } /** - * @param array $styleProperties - * @param array $path - * @return string + * @param array $styleProperties + * @param string[] $path */ public function renderStyles(array $styleProperties, array $path = []): string { @@ -50,15 +47,14 @@ public function renderStyles(array $styleProperties, array $path = []): string } /** - * @param array $properties - * @param array $path - * @return string + * @param array $properties + * @param string[] $path */ protected function renderProperties(array $properties, array $path = []): string { // Construct full CSS selector $pathName = implode(' ', array_map(static function ($part) { - return strpos($part, '@') === 0 ? $part . '{' : $part; + return str_starts_with($part, '@') ? $part . '{' : $part; }, $path)); $pathName = str_replace('{ ', '{', $pathName); @@ -68,10 +64,10 @@ protected function renderProperties(array $properties, array $path = []): string if (is_iterable($styleValue)) { $childPath = array_merge($path, [$styleName]); // Check for @media or @supports queries and reorder the selector - if (strpos($styleName, '@') === 0) { - usort($childPath, 'self::compareSelectorParts'); + if (str_starts_with($styleName, '@')) { + usort($childPath, self::compareSelectorParts(...)); } - $subSelectors[] = $this->renderProperties($styleValue, $childPath); + $subSelectors[] = $this->renderProperties((array)$styleValue, $childPath); } elseif ($styleValue !== null && $styleValue !== '') { $styleProps[]= $styleName . ':' . $styleValue; } @@ -96,15 +92,11 @@ protected function renderProperties(array $properties, array $path = []): string /** * Sorts a CSS selector to keep media queries at the start of the given array - * - * @param string $a - * @param string $b - * @return int */ private static function compareSelectorParts(string $a, string $b): int { - $aIsMediaQuery = strpos($a, '@') === 0; - $bIsMediaQuery = strpos($b, '@') === 0; + $aIsMediaQuery = str_starts_with($a, '@'); + $bIsMediaQuery = str_starts_with($b, '@'); if ($aIsMediaQuery && !$bIsMediaQuery) { return -1; } diff --git a/Tests/Functional/Fixtures/Fusion/example.css b/Resources/Private/Tests/example.css similarity index 100% rename from Tests/Functional/Fixtures/Fusion/example.css rename to Resources/Private/Tests/example.css diff --git a/Tests/Functional/AbstractFusionStylingTestCase.php b/Tests/Functional/AbstractFusionStylingTestCase.php new file mode 100644 index 0000000..c3c4d8e --- /dev/null +++ b/Tests/Functional/AbstractFusionStylingTestCase.php @@ -0,0 +1,37 @@ +request = ActionRequest::fromHttpRequest(new ServerRequest('GET', 'http://localhost/')); + + $runtime = $this->objectManager->get(RuntimeFactory::class)->createFromSourceCode( + FusionSourceCodeCollection::fromFilePath(__DIR__ . '/Fixtures/Fusion/Root.fusion'), + FusionGlobals::fromArray(['request' => $this->request]) + ); + + $view = new TestingViewForFusionRuntime($runtime); + $view->assign('fixtureDirectory', __DIR__ . '/Fixtures/'); + return $view; + } +} diff --git a/Tests/Functional/Fixtures/Fusion/Common.fusion b/Tests/Functional/Fixtures/Fusion/Common.fusion new file mode 100644 index 0000000..31687fb --- /dev/null +++ b/Tests/Functional/Fixtures/Fusion/Common.fusion @@ -0,0 +1,7 @@ +prototype(Neos.Fusion:Tag).@class = 'Neos\\Fusion\\FusionObjects\\TagImplementation' +prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' +prototype(Neos.Fusion:DataStructure).@class = 'Neos\\Fusion\\FusionObjects\\DataStructureImplementation' + +prototype(Shel.CriticalCSS:LoadStyles).@class = 'Shel\\CriticalCSS\\FusionObjects\\LoadStylesImplementation' +prototype(Shel.CriticalCSS:StyleCollector).@class = 'Shel\\CriticalCSS\\FusionObjects\\StyleCollectorImplementation' +prototype(Shel.CriticalCSS:Styles).@class = 'Shel\\CriticalCSS\\FusionObjects\\StylesImplementation' diff --git a/Tests/Functional/Fixtures/Fusion/LoadStyles.fusion b/Tests/Functional/Fixtures/Fusion/LoadStyles.fusion index 0a59e9e..1258150 100644 --- a/Tests/Functional/Fixtures/Fusion/LoadStyles.fusion +++ b/Tests/Functional/Fixtures/Fusion/LoadStyles.fusion @@ -1,18 +1,9 @@ -prototype(Shel.CriticalCSS:LoadStyles).@class = 'Shel\\CriticalCSS\\FusionObjects\\LoadStylesImplementation' -prototype(Neos.Fusion:Tag).@class = 'Neos\\Fusion\\FusionObjects\\TagImplementation' -prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' - styleLoader.insertStyles = Shel.CriticalCSS:LoadStyles { - path = 'Packages/Plugins/Shel.CriticalCSS/Tests/Functional/Fixtures/Fusion/example.css' -} - -styleLoader.prependStyles = Shel.CriticalCSS:LoadStyles { - path = 'Packages/Plugins/Shel.CriticalCSS/Tests/Functional/Fixtures/Fusion/example.css' - content = '
foo
' + path = 'resource://Shel.CriticalCSS/Private/Tests/example.css' } styleLoader.prependStyles = Shel.CriticalCSS:LoadStyles { - path = 'Packages/Plugins/Shel.CriticalCSS/Tests/Functional/Fixtures/Fusion/example.css' + path = 'resource://Shel.CriticalCSS/Private/Tests/example.css' content = '
foo
' } @@ -20,6 +11,6 @@ styleLoader.asProcess = Neos.Fusion:Tag { content = 'foo' @process.style = Shel.CriticalCSS:LoadStyles { content = ${value} - path = 'Packages/Plugins/Shel.CriticalCSS/Tests/Functional/Fixtures/Fusion/example.css' + path = 'resource://Shel.CriticalCSS/Private/Tests/example.css' } } diff --git a/Tests/Functional/Fixtures/Fusion/Root.fusion b/Tests/Functional/Fixtures/Fusion/Root.fusion new file mode 100644 index 0000000..a92a174 --- /dev/null +++ b/Tests/Functional/Fixtures/Fusion/Root.fusion @@ -0,0 +1 @@ +include: **/* diff --git a/Tests/Functional/Fixtures/Fusion/StyleCollector.fusion b/Tests/Functional/Fixtures/Fusion/StyleCollector.fusion index cf69b5b..816822e 100644 --- a/Tests/Functional/Fixtures/Fusion/StyleCollector.fusion +++ b/Tests/Functional/Fixtures/Fusion/StyleCollector.fusion @@ -1,6 +1,3 @@ -prototype(Shel.CriticalCSS:StyleCollector).@class = 'Shel\\CriticalCSS\\FusionObjects\\StyleCollectorImplementation' -prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' - styleCollector.collectMultipleStyles = Shel.CriticalCSS:StyleCollector { content = ' diff --git a/Tests/Functional/Fixtures/Fusion/Styles.fusion b/Tests/Functional/Fixtures/Fusion/Styles.fusion index a105cf2..4c1f272 100644 --- a/Tests/Functional/Fixtures/Fusion/Styles.fusion +++ b/Tests/Functional/Fixtures/Fusion/Styles.fusion @@ -1,7 +1,3 @@ -prototype(Shel.CriticalCSS:Styles).@class = 'Shel\\CriticalCSS\\FusionObjects\\StylesImplementation' -prototype(Neos.Fusion:DataStructure).@class = 'Neos\\Fusion\\FusionObjects\\DataStructureImplementation' -prototype(Neos.Fusion:TestRenderer).@class = 'Neos\\Fusion\\Tests\\Functional\\View\\Fixtures\\TestRenderer' - styles.basic = Shel.CriticalCSS:Styles { @content = '
foo
' color = 'green' diff --git a/Tests/Functional/StyleCollectorTest.php b/Tests/Functional/StyleCollectorTest.php index c384fdc..472708b 100644 --- a/Tests/Functional/StyleCollectorTest.php +++ b/Tests/Functional/StyleCollectorTest.php @@ -1,4 +1,5 @@ setPackageKey('Shel.CriticalCSS'); - $view->setFusionPathPattern(__DIR__ . '/Fixtures/Fusion'); - return $view; - } - /** * @test */ - public function collectMultipleStylesWorks() + public function collectMultipleStylesWorks(): void { - $view = $this->buildView(); - - $view->setFusionPath('styleCollector/collectMultipleStyles'); - $this->assertEquals( + $this->assertFusionPath( ' Test -
foo
-
bar
- ', $view->render()); + ', + 'styleCollector/collectMultipleStyles' + ); } /** * @test */ - public function removeDuplicatesStylesWorks() + public function removeDuplicatesStylesWorks(): void { - $view = $this->buildView(); - - $view->setFusionPath('styleCollector/removeDuplicatesStyles'); - $this->assertEquals( + $this->assertFusionPath( ' Test -
foo
-
foo
- ', $view->render()); + ', + 'styleCollector/removeDuplicatesStyles' + ); } } diff --git a/Tests/Functional/StyleLoaderTest.php b/Tests/Functional/StyleLoaderTest.php index f328e4e..586c94e 100644 --- a/Tests/Functional/StyleLoaderTest.php +++ b/Tests/Functional/StyleLoaderTest.php @@ -7,67 +7,45 @@ * This file is part of the Shel.CriticalCSS package. */ -use Neos\Fusion\Tests\Functional\FusionObjects\AbstractFusionObjectTest; -use Neos\Fusion\View\FusionView; - /** * Testcase for the style loader object */ -class StyleLoaderTest extends AbstractFusionObjectTest +class StyleLoaderTest extends AbstractFusionStylingTestCase { - /** - * @inheritDoc - */ - protected function buildView(): FusionView - { - $view = parent::buildView(); - $view->setPackageKey('Shel.CriticalCSS'); - $view->setFusionPathPattern(__DIR__ . '/Fixtures/Fusion'); - return $view; - } /** * @test */ - public function insertingStylesWorks() + public function insertingStylesWorks(): void { - $view = $this->buildView(); - - $view->setFusionPath('styleLoader/insertStyles'); - $this->assertEquals( + $this->assertFusionPath( '', $view->render()); +', 'styleLoader/insertStyles'); } /** * @test */ - public function prependingStylesWorks() + public function prependingStylesWorks(): void { - $view = $this->buildView(); - - $view->setFusionPath('styleLoader/prependStyles'); - $this->assertEquals( + $this->assertFusionPath( '
foo
', $view->render()); +
foo
', 'styleLoader/prependStyles'); } /** * @test */ - public function addStylesAsProcessWorks() + public function addStylesAsProcessWorks(): void { - $view = $this->buildView(); - - $view->setFusionPath('styleLoader/asProcess'); - $this->assertEquals( + $this->assertFusionPath( '
foo
', $view->render()); +
foo
', 'styleLoader/asProcess'); } } diff --git a/Tests/Functional/StylesTest.php b/Tests/Functional/StylesTest.php index e7d5779..4e31c2e 100644 --- a/Tests/Functional/StylesTest.php +++ b/Tests/Functional/StylesTest.php @@ -1,4 +1,5 @@ setPackageKey('Shel.CriticalCSS'); - $view->setFusionPathPattern(__DIR__ . '/Fixtures/Fusion'); - return $view; - } /** * @test @@ -38,7 +26,8 @@ public function basicRenderingWorks() '' . - '
foo
', $view->render() + '
foo
', + $view->render() ); } @@ -70,7 +59,8 @@ public function eelExpressionRenderingWorks() '' . - '
foo
', $view->render() + '
foo
', + $view->render() ); } @@ -87,7 +77,8 @@ public function nestedRenderingWorks() '.style--0e1e7d5620{color:blue}' . '.style--0e1e7d5620 strong{font-weight:bold}' . '' . - '
foo bar
', $view->render() + '
foo bar
', + $view->render() ); } @@ -105,7 +96,8 @@ public function nestedRenderingWithoutDataStructuresWorks() '.style--e2384db9d9 strong{font-weight:bold}' . '.style--e2384db9d9 strong em{color:pink}' . '' . - '
foo bar pony
', $view->render() + '
foo bar pony
', + $view->render() ); } @@ -123,7 +115,8 @@ public function nestedEvaluationRenderingWorks() '.style--385286f4a7 strong{font-weight:bold}' . '.style--385286f4a7 strong em{margin-top:50px}' . '' . - '
foo bar pony
', $view->render() + '
foo bar pony
', + $view->render() ); } @@ -139,7 +132,8 @@ public function selectorRenderingWorks() '' . - 'foo', $view->render() + 'foo', + $view->render() ); } @@ -156,7 +150,8 @@ public function mediaQueryRenderingWorks() '.style--3e741db00a{color:blue}' . '@media all{.style--3e741db00a{color:green}}' . '' . - '
foo
', $view->render() + '
foo
', + $view->render() ); } @@ -174,7 +169,8 @@ public function mediaQueryWithNestingRenderingWorks() '@media all{.style--751ebabd93{color:green}}' . '@media all{.style--751ebabd93 strong{color:yellow}}' . '' . - '
foo bar
', $view->render() + '
foo bar
', + $view->render() ); } @@ -195,7 +191,8 @@ public function nestedMediaQueriesRenderingWorks() '.style--2d1e5ab0be strong{display:block}' . '}}' . '' . - '
foo bar
', $view->render() + '
foo bar
', + $view->render() ); } @@ -217,7 +214,8 @@ public function supportsQueryRenderingWorks() 'display:flex' . '}}' . '' . - '
foo
', $view->render() + '
foo
', + $view->render() ); } } diff --git a/composer.json b/composer.json index 51d6348..ee3a311 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,8 @@ "Components" ], "require": { - "neos/neos": "~7.0 || ~8.0 || dev-master" + "php": ">=8.2", + "neos/neos": "^9.0" }, "authors": [ { @@ -32,9 +33,20 @@ "Shel\\CriticalCSS\\Tests\\": "Tests" } }, + "scripts": { + "test": "../../../bin/phpunit --enforce-time-limit --bootstrap ../../Libraries/autoload.php --testdox Tests", + "test:ci": "phpunit --enforce-time-limit --bootstrap vendor/autoload.php --testdox Tests", + "codestyle": "phpstan analyse --autoload-file ../../Libraries/autoload.php", + "codestyle:ci": "phpstan analyse" + }, "extra": { "neos": { "package-key": "Shel.CriticalCSS" } + }, + "config": { + "allow-plugins": { + "neos/composer-plugin": true + } } } diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 0000000..ad9bda7 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,7 @@ +parameters: + level: 8 + paths: + - Classes + ignoreErrors: +# - '#Call to an undefined method [a-zA-Z0-9\\_]+Repository::findBy[a-zA-Z]+\(\)#' + - '#Call to an undefined method [a-zA-Z0-9\\_]+Repository::findOneBy[a-zA-Z]+\(\)#'