Loading core/modules/help_topics/src/FrontMatter.phpdeleted 100644 → 0 +0 −173 Original line number Diff line number Diff line <?php namespace Drupal\help_topics; /** * Extracts Front Matter from the beginning of a source. * * @internal * This front matter extractor only supports help topic discovery and is not * part of the public API. */ final class FrontMatter { /** * The separator used to indicate front matter data. * * @var string */ const FRONT_MATTER_SEPARATOR = '---'; /** * The regular expression used to extract the YAML front matter content. * * @var string */ const FRONT_MATTER_REGEXP = "{^(?:" . self::FRONT_MATTER_SEPARATOR . ")[\r\n|\n]*(.*?)[\r\n|\n]+(?:" . self::FRONT_MATTER_SEPARATOR . ")[\r\n|\n]*(.*)$}s"; /** * The parsed source. * * @var array */ protected $parsed; /** * A serializer class. * * @var string */ protected $serializer; /** * The source. * * @var string */ protected $source; /** * FrontMatter constructor. * * @param string $source * A string source. * @param string $serializer * A class that implements * \Drupal\Component\Serialization\SerializationInterface. */ public function __construct($source, $serializer = '\Drupal\Component\Serialization\Yaml') { assert(is_string($source), '$source must be a string'); assert(is_string($serializer), '$serializer must be a string'); if (!is_subclass_of($serializer, '\Drupal\Component\Serialization\SerializationInterface')) { throw new \InvalidArgumentException('The $serializer parameter must reference a class that implements \Drupal\Component\Serialization\SerializationInterface.'); } $this->serializer = $serializer; $this->source = $source; } /** * Creates a new FrontMatter instance. * * @param string $source * A string source. * @param string $serializer * A class that implements * \Drupal\Component\Serialization\SerializationInterface. * * @return static */ public static function load($source, $serializer = '\Drupal\Component\Serialization\Yaml') { return new static($source, $serializer); } /** * Parses the source. * * @return array * An associative array containing: * - code: The real source code. * - data: The front matter data extracted and decoded. * - line: The line number where the real source code starts. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ private function parse() { if (!$this->parsed) { $this->parsed = [ 'code' => $this->source, 'data' => [], 'line' => 1, ]; // Check for front matter data. $len = strlen(static::FRONT_MATTER_SEPARATOR); $matches = []; if (substr($this->parsed['code'], 0, $len + 1) === static::FRONT_MATTER_SEPARATOR . "\n" || substr($this->parsed['code'], 0, $len + 2) === static::FRONT_MATTER_SEPARATOR . "\r\n") { preg_match(static::FRONT_MATTER_REGEXP, $this->parsed['code'], $matches); $matches = array_map('trim', $matches); } // Immediately return if the code doesn't contain front matter data. if (empty($matches)) { return $this->parsed; } // Set the extracted source code. $this->parsed['code'] = $matches[2]; // Set the extracted front matter data. Do not catch any exceptions here // as doing so would only obfuscate any errors found in the front matter // data. Typecast to an array to ensure top level scalars are in an array. if ($matches[1]) { $this->parsed['data'] = (array) $this->serializer::decode($matches[1]); } // Determine the real source line by counting newlines from the data and // then adding 2 to account for the front matter separator (---) wrappers // and then adding 1 more for the actual line number after the data. $this->parsed['line'] = count(preg_split('/\r\n|\n/', $matches[1])) + 3; } return $this->parsed; } /** * Retrieves the extracted source code. * * @return string * The extracted source code. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ public function getCode() { return $this->parse()['code']; } /** * Retrieves the extracted front matter data. * * @return array * The extracted front matter data. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ public function getData() { return $this->parse()['data']; } /** * Retrieves the line where the source code starts, after any data. * * @return int * The source code line. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ public function getLine() { return $this->parse()['line']; } } core/modules/help_topics/src/HelpTopicDiscovery.php +2 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ use Drupal\Component\Discovery\DiscoveryException; use Drupal\Component\FileCache\FileCacheFactory; use Drupal\Component\FileSystem\RegexDirectoryIterator; use Drupal\Component\FrontMatter\FrontMatter; use Drupal\Component\Plugin\Discovery\DiscoveryInterface; use Drupal\Component\Plugin\Discovery\DiscoveryTrait; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; Loading Loading @@ -118,7 +119,7 @@ public function findAll() { // Get the rest of the plugin definition from front matter contained in // the help topic Twig file. try { $front_matter = FrontMatter::load(file_get_contents($file), Yaml::class)->getData(); $front_matter = FrontMatter::create(file_get_contents($file), Yaml::class)->getData(); } catch (InvalidDataTypeException $e) { throw new DiscoveryException(sprintf('Malformed YAML in help topic "%s": %s.', $file, $e->getMessage())); Loading core/modules/help_topics/src/HelpTopicTwigLoader.php +3 −2 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Drupal\help_topics; use Drupal\Component\FrontMatter\FrontMatter; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; Loading Loading @@ -77,14 +78,14 @@ public function getSourceContext($name) { // "serializer.yaml" service. This allows the core serializer to utilize // core related functionality which isn't available as the standalone // component based serializer. $front_matter = FrontMatter::load($contents, Yaml::class); $front_matter = new FrontMatter($contents, Yaml::class); // Reconstruct the content if there is front matter data detected. Prepend // the source with {% line \d+ %} to inform Twig that the source code // actually starts on a different line past the front matter data. This is // particularly useful when used in error reporting. if ($front_matter->getData() && ($line = $front_matter->getLine())) { $contents = "{% line $line %}" . $front_matter->getCode(); $contents = "{% line $line %}" . $front_matter->getContent(); } } catch (InvalidDataTypeException $e) { Loading Loading
core/modules/help_topics/src/FrontMatter.phpdeleted 100644 → 0 +0 −173 Original line number Diff line number Diff line <?php namespace Drupal\help_topics; /** * Extracts Front Matter from the beginning of a source. * * @internal * This front matter extractor only supports help topic discovery and is not * part of the public API. */ final class FrontMatter { /** * The separator used to indicate front matter data. * * @var string */ const FRONT_MATTER_SEPARATOR = '---'; /** * The regular expression used to extract the YAML front matter content. * * @var string */ const FRONT_MATTER_REGEXP = "{^(?:" . self::FRONT_MATTER_SEPARATOR . ")[\r\n|\n]*(.*?)[\r\n|\n]+(?:" . self::FRONT_MATTER_SEPARATOR . ")[\r\n|\n]*(.*)$}s"; /** * The parsed source. * * @var array */ protected $parsed; /** * A serializer class. * * @var string */ protected $serializer; /** * The source. * * @var string */ protected $source; /** * FrontMatter constructor. * * @param string $source * A string source. * @param string $serializer * A class that implements * \Drupal\Component\Serialization\SerializationInterface. */ public function __construct($source, $serializer = '\Drupal\Component\Serialization\Yaml') { assert(is_string($source), '$source must be a string'); assert(is_string($serializer), '$serializer must be a string'); if (!is_subclass_of($serializer, '\Drupal\Component\Serialization\SerializationInterface')) { throw new \InvalidArgumentException('The $serializer parameter must reference a class that implements \Drupal\Component\Serialization\SerializationInterface.'); } $this->serializer = $serializer; $this->source = $source; } /** * Creates a new FrontMatter instance. * * @param string $source * A string source. * @param string $serializer * A class that implements * \Drupal\Component\Serialization\SerializationInterface. * * @return static */ public static function load($source, $serializer = '\Drupal\Component\Serialization\Yaml') { return new static($source, $serializer); } /** * Parses the source. * * @return array * An associative array containing: * - code: The real source code. * - data: The front matter data extracted and decoded. * - line: The line number where the real source code starts. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ private function parse() { if (!$this->parsed) { $this->parsed = [ 'code' => $this->source, 'data' => [], 'line' => 1, ]; // Check for front matter data. $len = strlen(static::FRONT_MATTER_SEPARATOR); $matches = []; if (substr($this->parsed['code'], 0, $len + 1) === static::FRONT_MATTER_SEPARATOR . "\n" || substr($this->parsed['code'], 0, $len + 2) === static::FRONT_MATTER_SEPARATOR . "\r\n") { preg_match(static::FRONT_MATTER_REGEXP, $this->parsed['code'], $matches); $matches = array_map('trim', $matches); } // Immediately return if the code doesn't contain front matter data. if (empty($matches)) { return $this->parsed; } // Set the extracted source code. $this->parsed['code'] = $matches[2]; // Set the extracted front matter data. Do not catch any exceptions here // as doing so would only obfuscate any errors found in the front matter // data. Typecast to an array to ensure top level scalars are in an array. if ($matches[1]) { $this->parsed['data'] = (array) $this->serializer::decode($matches[1]); } // Determine the real source line by counting newlines from the data and // then adding 2 to account for the front matter separator (---) wrappers // and then adding 1 more for the actual line number after the data. $this->parsed['line'] = count(preg_split('/\r\n|\n/', $matches[1])) + 3; } return $this->parsed; } /** * Retrieves the extracted source code. * * @return string * The extracted source code. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ public function getCode() { return $this->parse()['code']; } /** * Retrieves the extracted front matter data. * * @return array * The extracted front matter data. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ public function getData() { return $this->parse()['data']; } /** * Retrieves the line where the source code starts, after any data. * * @return int * The source code line. * * @throws \Drupal\Component\Serialization\Exception\InvalidDataTypeException * Exception thrown when the Front Matter cannot be parsed. */ public function getLine() { return $this->parse()['line']; } }
core/modules/help_topics/src/HelpTopicDiscovery.php +2 −1 Original line number Diff line number Diff line Loading @@ -5,6 +5,7 @@ use Drupal\Component\Discovery\DiscoveryException; use Drupal\Component\FileCache\FileCacheFactory; use Drupal\Component\FileSystem\RegexDirectoryIterator; use Drupal\Component\FrontMatter\FrontMatter; use Drupal\Component\Plugin\Discovery\DiscoveryInterface; use Drupal\Component\Plugin\Discovery\DiscoveryTrait; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; Loading Loading @@ -118,7 +119,7 @@ public function findAll() { // Get the rest of the plugin definition from front matter contained in // the help topic Twig file. try { $front_matter = FrontMatter::load(file_get_contents($file), Yaml::class)->getData(); $front_matter = FrontMatter::create(file_get_contents($file), Yaml::class)->getData(); } catch (InvalidDataTypeException $e) { throw new DiscoveryException(sprintf('Malformed YAML in help topic "%s": %s.', $file, $e->getMessage())); Loading
core/modules/help_topics/src/HelpTopicTwigLoader.php +3 −2 Original line number Diff line number Diff line Loading @@ -2,6 +2,7 @@ namespace Drupal\help_topics; use Drupal\Component\FrontMatter\FrontMatter; use Drupal\Component\Serialization\Exception\InvalidDataTypeException; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\Core\Extension\ThemeHandlerInterface; Loading Loading @@ -77,14 +78,14 @@ public function getSourceContext($name) { // "serializer.yaml" service. This allows the core serializer to utilize // core related functionality which isn't available as the standalone // component based serializer. $front_matter = FrontMatter::load($contents, Yaml::class); $front_matter = new FrontMatter($contents, Yaml::class); // Reconstruct the content if there is front matter data detected. Prepend // the source with {% line \d+ %} to inform Twig that the source code // actually starts on a different line past the front matter data. This is // particularly useful when used in error reporting. if ($front_matter->getData() && ($line = $front_matter->getLine())) { $contents = "{% line $line %}" . $front_matter->getCode(); $contents = "{% line $line %}" . $front_matter->getContent(); } } catch (InvalidDataTypeException $e) { Loading