\/)?wp:(?P[a-z][a-z0-9_-]*\/)?(?P[a-z][a-z0-9_-]*)\s+' . '(?P{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*+)?}\s+)?(?P\/)?-->/s'; /** @throws MalformedMarkup */ public function parse(string $content): Document { $document = new Document(); /** @var list $stack */ $stack = []; $offset = 0; $length = strlen($content); while ($offset < $length) { $found = preg_match(self::TOKEN, $content, $match, PREG_OFFSET_CAPTURE, $offset); if ($found === false) { throw new MalformedMarkup('Block delimiters could not be scanned (PCRE error).'); } if ($found === 0) { break; } [$token, $start] = $match[0]; $container = $stack === [] ? $document : $stack[count($stack) - 1]; if ($start > $offset) { $container->append(substr($content, $offset, $start - $offset)); } $name = self::name($match); if (self::captured($match, 'closer')) { $open = array_pop($stack); if ($open === null || $open->name() !== $name) { throw new MalformedMarkup(sprintf('Closer of %s at byte %d has no opener.', $name, $start)); } $open->closeWith($token); } else { $json = self::captured($match, 'attrs') ? $match['attrs'][0] : ''; $attrs = $json === '' ? [] : Json::decodeObject($json); $void = self::captured($match, 'void'); $opaque = $attrs === null || $name === 'divi/global-layout' || array_key_exists('globalModule', $attrs); $block = Block::parsed($name, $attrs ?? [], $token, $void, $opaque); $container->append($block); if (! $void) { $stack[] = $block; } } $offset = $start + strlen($token); } if ($offset < $length) { ($stack === [] ? $document : $stack[count($stack) - 1])->append(substr($content, $offset)); } if ($stack !== []) { throw new MalformedMarkup(sprintf('Block %s is never closed.', $stack[count($stack) - 1]->name())); } return $document; } /** @param array $match */ private static function name(array $match): string { $namespace = self::captured($match, 'namespace') ? $match['namespace'][0] : 'core/'; return $namespace . $match['name'][0]; } /** @param array $match */ private static function captured(array $match, string $group): bool { return isset($match[$group]) && $match[$group][1] !== -1 && $match[$group][0] !== ''; } }