diff --git a/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php index 9acda6a..88aef27 100644 --- a/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php +++ b/core/lib/Drupal/Core/Asset/LibraryDiscoveryParser.php @@ -129,13 +129,16 @@ public function buildByExtension($extension) { // properly resolve dependencies for all (css) libraries per category, // and only once prior to rendering out an HTML page. if ($type == 'css' && !empty($library[$type])) { + assert('\Drupal\Core\Asset\LibraryDiscoveryParser::validateCssLibrary($library[$type])', 'CSS must be nested under a category. See https://www.drupal.org/node/2274843.'); foreach ($library[$type] as $category => $files) { + $category_weight = 'CSS_' . strtoupper($category); + assert('defined($category_weight)', 'Invalid CSS category: ' . $category . '. See https://www.drupal.org/node/2274843.'); foreach ($files as $source => $options) { if (!isset($options['weight'])) { $options['weight'] = 0; } // Apply the corresponding weight defined by CSS_* constants. - $options['weight'] += constant('CSS_' . strtoupper($category)); + $options['weight'] += constant($category_weight); $library[$type][$source] = $options; } unset($library[$type][$category]); @@ -460,4 +463,29 @@ protected function resolveThemeAssetPath($theme_path, $overriding_asset) { return $overriding_asset; } + /** + * Validates CSS library structure. + * + * @param array $library + * The library definition array. + * + * @return bool + * Returns TRUE for a valid library. Proper category checking is not done + * here, as that is captured by a separate assertion. + */ + public static function validateCssLibrary($library) { + $categories = []; + // Verify options first and return early if invalid. + foreach ($library as $category => $files) { + $categories[] = $category; + foreach ($files as $source => $options) { + if (!is_array($options)) { + return FALSE; + } + } + } + + return TRUE; + } + } diff --git a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php index ed0c9ce..e18b0ae 100644 --- a/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php +++ b/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryParserTest.php @@ -533,6 +533,48 @@ public function testLibraryWithLicenses() { $this->assertEquals($library['license'], $expected_license); } + /** + * Verify an assertion fails if CSS declarations have non-existent categories. + * + * @expectedException \AssertionError + * @expectedExceptionMessage Invalid CSS category: bad_category. See https://www.drupal.org/node/2274843. + */ + public function testCssCategoryAssert() { + $this->moduleHandler->expects($this->atLeastOnce()) + ->method('moduleExists') + ->with('css_bad_category') + ->will($this->returnValue(TRUE)); + + $path = __DIR__ . '/library_test_files'; + $path = substr($path, strlen($this->root) + 1); + $this->libraryDiscoveryParser->setPaths('module', 'css_bad_category', $path); + + // This will fail since the CSS declaration isn't properly nested under + // a category. + $this->libraryDiscoveryParser->buildByExtension('css_bad_category'); + } + + /** + * Verify an assertion fails if CSS declarations aren't properly nested. + * + * @expectedException \AssertionError + * @expectedExceptionMessage CSS must be nested under a category. See https://www.drupal.org/node/2274843. + */ + public function testCssNestingAssert() { + $this->moduleHandler->expects($this->atLeastOnce()) + ->method('moduleExists') + ->with('css_bad_nesting') + ->will($this->returnValue(TRUE)); + + $path = __DIR__ . '/library_test_files'; + $path = substr($path, strlen($this->root) + 1); + $this->libraryDiscoveryParser->setPaths('module', 'css_bad_nesting', $path); + + // This will fail since the CSS declaration isn't properly nested under + // a category. + $this->libraryDiscoveryParser->buildByExtension('css_bad_nesting'); + } + } /** diff --git a/core/tests/Drupal/Tests/Core/Asset/library_test_files/css_bad_category.libraries.yml b/core/tests/Drupal/Tests/Core/Asset/library_test_files/css_bad_category.libraries.yml new file mode 100644 index 0000000..803efc3 --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Asset/library_test_files/css_bad_category.libraries.yml @@ -0,0 +1,5 @@ +bad_category: + css: + # Non-existent category. + bad_category: + css/styles.css: { minified: true } diff --git a/core/tests/Drupal/Tests/Core/Asset/library_test_files/css_bad_nesting.libraries.yml b/core/tests/Drupal/Tests/Core/Asset/library_test_files/css_bad_nesting.libraries.yml new file mode 100644 index 0000000..44c9c0e --- /dev/null +++ b/core/tests/Drupal/Tests/Core/Asset/library_test_files/css_bad_nesting.libraries.yml @@ -0,0 +1,4 @@ +bad_nesting: + css: + # No nesting here will break. + css/styles.css: { minified: true } diff --git a/core/tests/Drupal/Tests/Core/Asset/library_test_files/dependencies.libraries.yml b/core/tests/Drupal/Tests/Core/Asset/library_test_files/dependencies.libraries.yml index 9a8b4dd..068a9a3 100644 --- a/core/tests/Drupal/Tests/Core/Asset/library_test_files/dependencies.libraries.yml +++ b/core/tests/Drupal/Tests/Core/Asset/library_test_files/dependencies.libraries.yml @@ -1,6 +1,7 @@ example: css: - css/example.js: {} + theme: + css/example.js: {} dependencies: - external/example_external - example_module/example