public function BlockParser::nextToken in Gutenberg 8.2
Scans the document from where we last left off.
And finds the next valid token to parse if it exists.
@since 3.8.0 @since 4.6.1 fixed a bug in attribute parsing which caused catastrophic backtracking on invalid block comments @internal
Return value
array The type of the find: kind of find, block information, attributes.
1 call to BlockParser::nextToken()
- BlockParser::proceed in src/
Parser/ BlockParser.php - Processes the next token from the input document.
File
- src/
Parser/ BlockParser.php, line 263
Class
- BlockParser
- Class BlockParser.
Namespace
Drupal\gutenberg\ParserCode
public function nextToken() {
$matches = NULL;
/*
* aye the magic
* we're using a single RegExp to tokenize the block comment delimiters
* we're also using a trick here because the only difference between a
* block opener and a block closer is the leading `/` before `wp:` (and
* a closer has no attributes). we can trap them both and process the
* match back in PHP to see which one it was.
*/
$has_match = preg_match('/<!--\\s+(?P<closer>\\/)?wp:(?P<namespace>[a-z][a-z0-9_-]*\\/)?(?P<name>[a-z][a-z0-9_-]*)\\s+(?P<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\\s+\\/?-->).)*+)?}\\s+)?(?P<void>\\/)?-->/s', $this->document, $matches, PREG_OFFSET_CAPTURE, $this->offset);
// If we get here we probably have catastrophic backtracking or
// out-of-memory in the PCRE.
if (FALSE === $has_match) {
return [
'no-more-tokens',
NULL,
NULL,
NULL,
NULL,
];
}
// We have no more tokens.
if (0 === $has_match) {
return [
'no-more-tokens',
NULL,
NULL,
NULL,
NULL,
];
}
list($match, $started_at) = $matches[0];
$length = strlen($match);
$is_closer = isset($matches['closer']) && -1 !== $matches['closer'][1];
$is_void = isset($matches['void']) && -1 !== $matches['void'][1];
$namespace = $matches['namespace'];
$namespace = isset($namespace) && -1 !== $namespace[1] ? $namespace[0] : 'core/';
$name = $namespace . $matches['name'][0];
$has_attrs = isset($matches['attrs']) && -1 !== $matches['attrs'][1];
/*
* Fun fact! It's not trivial in PHP to create "an empty associative array"
* since all arrays are associative arrays. If we use `array()` we get a
* JSON `[]`
*/
$attrs = $has_attrs ? json_decode($matches['attrs'][0], TRUE) : $this->emptyAttrs;
/*
* This state isn't allowed
* This is an error
*/
if ($is_closer && ($is_void || $has_attrs)) {
// We can ignore them since they don't hurt anything.
}
if ($is_void) {
return [
'void-block',
$name,
$attrs,
$started_at,
$length,
];
}
if ($is_closer) {
return [
'block-closer',
$name,
NULL,
$started_at,
$length,
];
}
return [
'block-opener',
$name,
$attrs,
$started_at,
$length,
];
}