diff --git a/components/BlockParser/class-wp-block-parser-block.php b/components/BlockParser/class-wp-block-parser-block.php index b5be53a0..0399d3b9 100644 --- a/components/BlockParser/class-wp-block-parser-block.php +++ b/components/BlockParser/class-wp-block-parser-block.php @@ -1,4 +1,5 @@ original_html ) as $block ) { if ( $block['blockName'] === null ) { - $html_converter = new MarkupProcessorConsumer( WP_HTML_Processor::create_fragment( $block['innerHTML'] ) ); + $html_converter = new MarkupProcessorConsumer( \WordPress\HTML\WP_HTML_Processor::create_fragment( $block['innerHTML'] ) ); $result = $html_converter->consume(); $block_markup .= $result->get_block_markup() . "\n"; $metadata = array_merge( $metadata, $result->get_all_metadata() ); diff --git a/components/DataLiberation/DataFormatConsumer/MarkupProcessorConsumer.php b/components/DataLiberation/DataFormatConsumer/MarkupProcessorConsumer.php index 8073c8da..219e03fa 100644 --- a/components/DataLiberation/DataFormatConsumer/MarkupProcessorConsumer.php +++ b/components/DataLiberation/DataFormatConsumer/MarkupProcessorConsumer.php @@ -6,8 +6,8 @@ use WordPress\DataLiberation\DataLiberationException; use WordPress\DataLiberation\Importer\ImportUtils; use WordPress\XML\XMLProcessor; -use WP_HTML_Processor; -use WP_HTML_Tag_Processor; +use WordPress\HTML\WP_HTML_Processor; +use WordPress\HTML\WP_HTML_Tag_Processor; /** * Creates block markup from a WP_HTML_Processor or WP_XML_Processor instance. diff --git a/components/DataLiberation/DataFormatProducer/AnnotatedBlockMarkupProducer.php b/components/DataLiberation/DataFormatProducer/AnnotatedBlockMarkupProducer.php index b340b28f..90b6bca0 100644 --- a/components/DataLiberation/DataFormatProducer/AnnotatedBlockMarkupProducer.php +++ b/components/DataLiberation/DataFormatProducer/AnnotatedBlockMarkupProducer.php @@ -3,7 +3,7 @@ namespace WordPress\DataLiberation\DataFormatProducer; use WordPress\DataLiberation\DataFormatConsumer\BlocksWithMetadata; -use WP_HTML_Tag_Processor; +use WordPress\HTML\WP_HTML_Tag_Processor; /** * Turns Block Markup + Metadata into a metadata-annotated Block Markup. diff --git a/components/DataLiberation/DataLiberationHTMLProcessor.php b/components/DataLiberation/DataLiberationHTMLProcessor.php index 2b05376a..782b0da3 100644 --- a/components/DataLiberation/DataLiberationHTMLProcessor.php +++ b/components/DataLiberation/DataLiberationHTMLProcessor.php @@ -2,8 +2,8 @@ namespace WordPress\DataLiberation; -use WP_HTML_Processor; -use WP_HTML_Tag_Processor; +use WordPress\HTML\WP_HTML_Processor; +use WordPress\HTML\WP_HTML_Tag_Processor; class DataLiberationHTMLProcessor extends WP_HTML_Processor { diff --git a/components/DataLiberation/EntityReader/EPubEntityReader.php b/components/DataLiberation/EntityReader/EPubEntityReader.php index 9f93d96e..7bfa47a6 100644 --- a/components/DataLiberation/EntityReader/EPubEntityReader.php +++ b/components/DataLiberation/EntityReader/EPubEntityReader.php @@ -8,6 +8,7 @@ use WordPress\XML\XMLProcessor; use function WordPress\Filesystem\wp_join_unix_paths; +use function WordPress\Polyfill\_doing_it_wrong; /** * https://www.w3.org/AudioVideo/ebook/ diff --git a/components/DataLiberation/EntityReader/FilesystemEntityReader.php b/components/DataLiberation/EntityReader/FilesystemEntityReader.php index 7b175e0c..c00f5b57 100644 --- a/components/DataLiberation/EntityReader/FilesystemEntityReader.php +++ b/components/DataLiberation/EntityReader/FilesystemEntityReader.php @@ -12,7 +12,7 @@ use WordPress\Filesystem\Visitor\FilesystemVisitor; use WordPress\Markdown\MarkdownConsumer; use WordPress\XML\XMLProcessor; -use WP_HTML_Processor; +use WordPress\HTML\WP_HTML_Processor; use function WordPress\Filesystem\wp_join_unix_paths; @@ -277,7 +277,7 @@ public function next_entity(): bool { $result = $converter->consume(); break; case 'html': - $converter = new MarkupProcessorConsumer( WP_HTML_Processor::create_fragment( $content ) ); + $converter = new MarkupProcessorConsumer( \WordPress\HTML\WP_HTML_Processor::create_fragment( $content ) ); $result = $converter->consume(); break; default: diff --git a/components/DataLiberation/EntityReader/WXREntityReader.php b/components/DataLiberation/EntityReader/WXREntityReader.php index 0d5d8622..2c5c51ed 100644 --- a/components/DataLiberation/EntityReader/WXREntityReader.php +++ b/components/DataLiberation/EntityReader/WXREntityReader.php @@ -6,6 +6,7 @@ use WordPress\DataLiberation\ImportEntity; use WordPress\XML\XMLProcessor; use WordPress\XML\XMLUnsupportedException; +use function WordPress\Polyfill\_doing_it_wrong; /** * Data Liberation API: WP_WXR_Entity_Reader class diff --git a/components/DataLiberation/Importer/AttachmentDownloader.php b/components/DataLiberation/Importer/AttachmentDownloader.php index 055f44bc..a4d18737 100644 --- a/components/DataLiberation/Importer/AttachmentDownloader.php +++ b/components/DataLiberation/Importer/AttachmentDownloader.php @@ -8,6 +8,7 @@ use WordPress\HttpClient\Request; use function WordPress\Filesystem\wp_join_unix_paths; +use function WordPress\Polyfill\_doing_it_wrong; class AttachmentDownloader { private $client; diff --git a/components/DataLiberation/Importer/EntityImporter.php b/components/DataLiberation/Importer/EntityImporter.php index 21d94b2d..d17548d2 100644 --- a/components/DataLiberation/Importer/EntityImporter.php +++ b/components/DataLiberation/Importer/EntityImporter.php @@ -24,6 +24,10 @@ use InvalidArgumentException; use WordPress\DataLiberation\DataLiberationException; use WordPress\DataLiberation\ImportEntity; +use function WordPress\Polyfill\_doing_it_wrong; +use function WordPress\Polyfill\__; +use function WordPress\Polyfill\apply_filters; +use function WordPress\Polyfill\do_action; class EntityImporter { diff --git a/components/DataLiberation/Importer/ImportSession.php b/components/DataLiberation/Importer/ImportSession.php index 8874e145..1d108c94 100644 --- a/components/DataLiberation/Importer/ImportSession.php +++ b/components/DataLiberation/Importer/ImportSession.php @@ -7,6 +7,7 @@ use function get_all_post_meta_flat; use function is_wp_error; +use function WordPress\Polyfill\_doing_it_wrong; /** * Manages import session data in the WordPress database. diff --git a/components/DataLiberation/Importer/StreamImporter.php b/components/DataLiberation/Importer/StreamImporter.php index cbf86b62..335645c3 100644 --- a/components/DataLiberation/Importer/StreamImporter.php +++ b/components/DataLiberation/Importer/StreamImporter.php @@ -11,6 +11,9 @@ use WordPress\HttpClient\ByteStream\RequestReadStream; use function WordPress\DataLiberation\URL\is_child_url_of; +use function WordPress\Polyfill\_doing_it_wrong; +use function WordPress\Polyfill\apply_filters; +use function WordPress\Polyfill\do_action; /** * Idea: diff --git a/components/DataLiberation/Tests/FilesystemEntityReaderTest.php b/components/DataLiberation/Tests/FilesystemEntityReaderTest.php index 0631acfb..b1edcc97 100644 --- a/components/DataLiberation/Tests/FilesystemEntityReaderTest.php +++ b/components/DataLiberation/Tests/FilesystemEntityReaderTest.php @@ -153,7 +153,7 @@ private function assertMarkupMatches( $markup, $expected ) { } private function normalize_markup( $markup ) { - return WP_HTML_Processor::create_fragment( + return \WordPress\HTML\WP_HTML_Processor::create_fragment( preg_replace( '/\s+/', ' ', trim( $markup ) ) )->serialize(); } diff --git a/components/DataLiberation/Tests/HTMLEntityReaderTest.php b/components/DataLiberation/Tests/HTMLEntityReaderTest.php index 71c2fefe..b1ad623d 100644 --- a/components/DataLiberation/Tests/HTMLEntityReaderTest.php +++ b/components/DataLiberation/Tests/HTMLEntityReaderTest.php @@ -15,7 +15,7 @@ public function test_entity_reader() {

It is our pleasure to announce that WordPress 6.8 was released

Last week, WordPress 6.8 was released.

HTML; - $html_processor = WP_HTML_Processor::create_fragment( $html ); + $html_processor = \WordPress\HTML\WP_HTML_Processor::create_fragment( $html ); $producer = new MarkupProcessorConsumer( $html_processor ); $blocks_with_meta = $producer->consume(); @@ -70,7 +70,7 @@ public function test_entity_reader() { } private function normalize_markup( $markup ) { - $processor = WP_HTML_Processor::create_fragment( $markup ); + $processor = \WordPress\HTML\WP_HTML_Processor::create_fragment( $markup ); $serialized = $processor->serialize(); return $serialized; diff --git a/components/DataLiberation/Tests/MarkupProcessorConsumerTest.php b/components/DataLiberation/Tests/MarkupProcessorConsumerTest.php index 348968ce..d0153ad2 100644 --- a/components/DataLiberation/Tests/MarkupProcessorConsumerTest.php +++ b/components/DataLiberation/Tests/MarkupProcessorConsumerTest.php @@ -18,7 +18,7 @@ public function test_metadata_extraction() {

WordPress 6.8 was released

Last week, WordPress 6.8 was released. This release includes a new default theme, a new block editor experience, and a new block library. It also includes a new block editor experience, and a new block library.

HTML; - $consumer = new MarkupProcessorConsumer( new WP_HTML_Processor( $html ) ); + $consumer = new MarkupProcessorConsumer( \WordPress\HTML\WP_HTML_Processor::create_fragment( $html ) ); $blocks_with_meta = $consumer->consume(); $metadata = $blocks_with_meta->get_all_metadata(); $expected_metadata = array( @@ -37,14 +37,14 @@ public function test_metadata_extraction() { * @dataProvider provider_test_conversion */ public function test_html_to_blocks_conversion( $html, $expected ) { - $consumer = new MarkupProcessorConsumer( new WP_HTML_Processor( $html ) ); + $consumer = new MarkupProcessorConsumer( \WordPress\HTML\WP_HTML_Processor::create_fragment( $html ) ); $blocks_with_meta = $consumer->consume(); $this->assertEquals( $this->normalize_markup( $expected ), $this->normalize_markup( $blocks_with_meta->get_block_markup() ) ); } private function normalize_markup( $markup ) { - $processor = WP_HTML_Processor::create_fragment( $markup ); + $processor = \WordPress\HTML\WP_HTML_Processor::create_fragment( $markup ); $serialized = $processor->serialize(); $serialized = trim( str_replace( @@ -137,7 +137,7 @@ public static function provider_test_conversion() { public function test_html_to_blocks_excerpt() { $this->markTestSkipped( 'Skipping this test because of outdated fixture.' ); - // $consumer = new MarkupProcessorConsumer( WP_HTML_Processor::create_fragment( $input ) ); + // $consumer = new MarkupProcessorConsumer( \WordPress\HTML\WP_HTML_Processor::create_fragment( $input ) ); // $blocks_with_meta = $consumer->consume(); // $blocks = $blocks_with_meta->get_block_markup(); diff --git a/components/DataLiberation/URL/URLInTextProcessor.php b/components/DataLiberation/URL/URLInTextProcessor.php index 3311cf07..76faaaea 100644 --- a/components/DataLiberation/URL/URLInTextProcessor.php +++ b/components/DataLiberation/URL/URLInTextProcessor.php @@ -3,7 +3,7 @@ namespace WordPress\DataLiberation\URL; use WordPress\DataLiberation\BlockMarkup\URL; -use WP_HTML_Text_Replacement; +use WordPress\HTML\WP_HTML_Text_Replacement; /** * Finds string fragments that look like URLs and allow replacing them. @@ -278,7 +278,7 @@ public function set_raw_url( $new_url ) { $new_url = substr( $new_url, strpos( $new_url, '://' ) + 3 ); } $this->raw_url = $new_url; - $this->lexical_updates[ $this->url_starts_at ] = new WP_HTML_Text_Replacement( + $this->lexical_updates[ $this->url_starts_at ] = new \WordPress\HTML\WP_HTML_Text_Replacement( $this->url_starts_at, $this->url_length, $new_url diff --git a/components/Filesystem/Tests/FunctionsTest.php b/components/Filesystem/Tests/FunctionsTest.php index 05431e97..1b0f9a81 100644 --- a/components/Filesystem/Tests/FunctionsTest.php +++ b/components/Filesystem/Tests/FunctionsTest.php @@ -4,7 +4,6 @@ use function WordPress\Filesystem\wp_join_unix_paths; use function WordPress\Filesystem\wp_unix_dirname; -use ValueError; class FunctionsTest extends TestCase { public function testBasicPathJoining() { diff --git a/components/Git/GitRemote.php b/components/Git/GitRemote.php index e5677534..af08935e 100644 --- a/components/Git/GitRemote.php +++ b/components/Git/GitRemote.php @@ -242,10 +242,42 @@ private function resolve_missing_blobs_oids( $remote_commit_hash, $options ) { $commit = $this->repository->read_object( $remote_commit_hash )->as_commit(); $subpath = trim( $path, '/' ); - $requested_tree_oid = $this->repository->find_hash_by_path( $subpath, $commit->hash ); + $parent_path = dirname( $subpath ); + if( $parent_path === '.' || $parent_path === '' ) { + $parent_path = '/'; + } + + $descentant_blobs_oids = []; + if( $parent_path !== '/' ) { + $parent_tree_oid = $this->repository->find_hash_by_path( $parent_path, $commit->hash ); + $parent_tree = $this->repository->read_object( $parent_tree_oid )->as_tree(); + $parent_tree_entries = $parent_tree->entries; + $object_name = basename( $subpath ); + foreach( $parent_tree_entries as $entry ) { + if( $entry->name === $object_name ) { + $requested_object_oid = $entry->hash; + break; + } + } + + // If the object is not found, it is a blob. Trees are always fetched. + if ( ! $this->repository->has_object( $requested_object_oid ) ) { + return [$requested_object_oid]; + } + + $object = $this->repository->read_object( $requested_object_oid ); + if( $object->get_object_type_name() === 'blob' ) { + // Requested object is a blob and, since we've just read it, it isn't + // missing. We're done. + return []; + } + } + + // Requested object is a tree, we need to compute all its descendants + $requested_object_oid = $this->repository->find_hash_by_path( $subpath, $commit->hash ); $descentant_blobs_oids = get_all_descendant_oids_in_tree( $this->repository, - $requested_tree_oid, + $requested_object_oid, array( 'object_types' => array( TreeEntry::FILE_MODE_REGULAR_EXECUTABLE, @@ -365,7 +397,7 @@ public function fetch( $full_branch_name, $options = array() ) { // Make double sure we have all the relevant objects from the remote commit. // @TODO: investigate why sometimes the root tree is missing and address the // root cause instead of plugging the hole with a bandaid. - if ( ! isset( $options['path'] ) || $options['path'] === '/' || $options['path'] === '' ) { + if ( ! isset( $options['path'] ) || $options['path'] === '/' || $options['path'] === '' ) { if ( ! $this->repository->has_all_objects_from_commit( $remote_head ) ) { $this->git_upload_pack( array( diff --git a/components/Git/GitRepository.php b/components/Git/GitRepository.php index 3efb4b1d..089bc484 100644 --- a/components/Git/GitRepository.php +++ b/components/Git/GitRepository.php @@ -14,6 +14,7 @@ use function WordPress\Filesystem\wp_unix_dirname; use function WordPress\Filesystem\wp_join_unix_paths; use function WordPress\Filesystem\wp_unix_path_resolve_dots; +use function WordPress\Polyfill\_doing_it_wrong; class GitRepository { @@ -356,6 +357,7 @@ private function resolve_branch_file_path( $branch_name ) { if ( strpos( $branch_name, '/' ) !== false && strncmp( $branch_name, 'refs/heads/', strlen( 'refs/heads/' ) ) !== 0 && + strncmp( $branch_name, 'refs/tags/', strlen( 'refs/tags/' ) ) !== 0 && strncmp( $branch_name, 'refs/remotes/', strlen( 'refs/remotes/' ) ) !== 0 ) { _doing_it_wrong( __METHOD__, 'Invalid ref name: ' . $branch_name, '1.0.0' ); diff --git a/components/HTML/class-wp-html-active-formatting-elements.php b/components/HTML/class-wp-html-active-formatting-elements.php index 317f4089..2bbed0c1 100644 --- a/components/HTML/class-wp-html-active-formatting-elements.php +++ b/components/HTML/class-wp-html-active-formatting-elements.php @@ -1,4 +1,6 @@ walk_up() as $item ) { @@ -65,9 +66,9 @@ public function contains_node( WP_HTML_Token $token ) { /** * Returns how many nodes are currently in the stack of active formatting elements. * - * @return int How many node are in the stack of active formatting elements. * @since 6.4.0 * + * @return int How many node are in the stack of active formatting elements. */ public function count() { return count( $this->stack ); @@ -77,9 +78,9 @@ public function count() { * Returns the node at the end of the stack of active formatting elements, * if one exists. If the stack is empty, returns null. * - * @return WP_HTML_Token|null Last node in the stack of active formatting elements, if one exists, otherwise null. * @since 6.4.0 * + * @return WP_HTML_Token|null Last node in the stack of active formatting elements, if one exists, otherwise null. */ public function current_node() { $current_node = end( $this->stack ); @@ -106,12 +107,11 @@ public function insert_marker(): void { /** * Pushes a node onto the stack of active formatting elements. * - * @param WP_HTML_Token $token Push this node onto the stack. + * @since 6.4.0 * * @see https://html.spec.whatwg.org/#push-onto-the-list-of-active-formatting-elements * - * @since 6.4.0 - * + * @param WP_HTML_Token $token Push this node onto the stack. */ public function push( WP_HTML_Token $token ) { /* @@ -132,11 +132,10 @@ public function push( WP_HTML_Token $token ) { /** * Removes a node from the stack of active formatting elements. * - * @param WP_HTML_Token $token Remove this node from the stack, if it's there already. - * - * @return bool Whether the node was found and removed from the stack of active formatting elements. * @since 6.4.0 * + * @param WP_HTML_Token $token Remove this node from the stack, if it's there already. + * @return bool Whether the node was found and removed from the stack of active formatting elements. */ public function remove_node( WP_HTML_Token $token ) { foreach ( $this->walk_up() as $position_from_end => $item ) { @@ -146,7 +145,6 @@ public function remove_node( WP_HTML_Token $token ) { $position_from_start = $this->count() - $position_from_end - 1; array_splice( $this->stack, $position_from_start, 1 ); - return true; } @@ -175,7 +173,7 @@ public function remove_node( WP_HTML_Token $token ) { public function walk_down() { $count = count( $this->stack ); - for ( $i = 0; $i < $count; $i ++ ) { + for ( $i = 0; $i < $count; $i++ ) { yield $this->stack[ $i ]; } } @@ -200,7 +198,7 @@ public function walk_down() { * @since 6.4.0 */ public function walk_up() { - for ( $i = count( $this->stack ) - 1; $i >= 0; $i -- ) { + for ( $i = count( $this->stack ) - 1; $i >= 0; $i-- ) { yield $this->stack[ $i ]; } } diff --git a/components/HTML/class-wp-html-attribute-token.php b/components/HTML/class-wp-html-attribute-token.php index 4bb582cf..ccd92175 100644 --- a/components/HTML/class-wp-html-attribute-token.php +++ b/components/HTML/class-wp-html-attribute-token.php @@ -1,4 +1,6 @@ name = $name; diff --git a/components/HTML/class-wp-html-decoder.php b/components/HTML/class-wp-html-decoder.php index 6f6f2e53..f03d0a15 100644 --- a/components/HTML/class-wp-html-decoder.php +++ b/components/HTML/class-wp-html-decoder.php @@ -1,5 +1,7 @@ $max_digits ) { $match_byte_length = $end_of_span - $at; - return 'οΏ½'; } @@ -356,7 +351,6 @@ public static function read_character_reference( $context, $text, $at = 0, &$mat } $match_byte_length = $end_of_span - $at; - return self::code_point_to_utf8_bytes( $code_point ); } @@ -378,7 +372,6 @@ public static function read_character_reference( $context, $text, $at = 0, &$mat // If the match ended with a semicolon then it should always be decoded. if ( ';' === $text[ $name_at + $name_length - 1 ] ) { $match_byte_length = $after_name - $at; - return $replacement; } @@ -399,7 +392,6 @@ public static function read_character_reference( $context, $text, $at = 0, &$mat // It's non-ambiguous, safe to leave it in. if ( ! $ambiguous_follower ) { $match_byte_length = $after_name - $at; - return $replacement; } @@ -409,7 +401,6 @@ public static function read_character_reference( $context, $text, $at = 0, &$mat } $match_byte_length = $after_name - $at; - return $replacement; } @@ -427,13 +418,12 @@ public static function read_character_reference( $context, $text, $at = 0, &$mat * // Half of a surrogate pair is an invalid code point. * 'οΏ½' === WP_HTML_Decoder::code_point_to_utf8_bytes( 0xd83c ); * - * @param int $code_point Which code point to convert. - * - * @return string Converted code point, or `οΏ½` if invalid. * @since 6.6.0 * * @see https://www.rfc-editor.org/rfc/rfc3629 For the UTF-8 standard. * + * @param int $code_point Which code point to convert. + * @return string Converted code point, or `οΏ½` if invalid. */ public static function code_point_to_utf8_bytes( $code_point ): string { // Pre-check to ensure a valid code point. diff --git a/components/HTML/class-wp-html-doctype-info.php b/components/HTML/class-wp-html-doctype-info.php index 33099400..42211eff 100644 --- a/components/HTML/class-wp-html-doctype-info.php +++ b/components/HTML/class-wp-html-doctype-info.php @@ -1,4 +1,6 @@ indicated_compatability_mode = 'quirks'; - return; } @@ -203,7 +204,6 @@ private function __construct( */ if ( 'html' === $name && null === $public_identifier && null === $system_identifier ) { $this->indicated_compatability_mode = 'no-quirks'; - return; } @@ -215,7 +215,6 @@ private function __construct( */ if ( 'html' !== $name ) { $this->indicated_compatability_mode = 'quirks'; - return; } @@ -244,7 +243,6 @@ private function __construct( 'html' === $public_identifier ) { $this->indicated_compatability_mode = 'quirks'; - return; } @@ -253,7 +251,6 @@ private function __construct( */ if ( 'http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd' === $system_identifier ) { $this->indicated_compatability_mode = 'quirks'; - return; } @@ -263,7 +260,6 @@ private function __construct( */ if ( '' === $public_identifier ) { $this->indicated_compatability_mode = 'no-quirks'; - return; } @@ -275,87 +271,63 @@ private function __construct( * and normative documents will have exited before reaching this condition. */ if ( - strncmp( $public_identifier, '+//silmaril//dtd html pro v0r11 19970101//', - strlen( '+//silmaril//dtd html pro v0r11 19970101//' ) ) === 0 || - strncmp( $public_identifier, '-//as//dtd html 3.0 aswedit + extensions//', - strlen( '-//as//dtd html 3.0 aswedit + extensions//' ) ) === 0 || - strncmp( $public_identifier, '-//advasoft ltd//dtd html 3.0 aswedit + extensions//', - strlen( '-//advasoft ltd//dtd html 3.0 aswedit + extensions//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 2.0 level 1//', strlen( '-//ietf//dtd html 2.0 level 1//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 2.0 level 2//', strlen( '-//ietf//dtd html 2.0 level 2//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 2.0 strict level 1//', - strlen( '-//ietf//dtd html 2.0 strict level 1//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 2.0 strict level 2//', - strlen( '-//ietf//dtd html 2.0 strict level 2//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 2.0 strict//', strlen( '-//ietf//dtd html 2.0 strict//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 2.0//', strlen( '-//ietf//dtd html 2.0//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 2.1e//', strlen( '-//ietf//dtd html 2.1e//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 3.0//', strlen( '-//ietf//dtd html 3.0//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 3.2 final//', strlen( '-//ietf//dtd html 3.2 final//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 3.2//', strlen( '-//ietf//dtd html 3.2//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html 3//', strlen( '-//ietf//dtd html 3//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html level 0//', strlen( '-//ietf//dtd html level 0//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html level 1//', strlen( '-//ietf//dtd html level 1//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html level 2//', strlen( '-//ietf//dtd html level 2//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html level 3//', strlen( '-//ietf//dtd html level 3//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html strict level 0//', strlen( '-//ietf//dtd html strict level 0//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html strict level 1//', strlen( '-//ietf//dtd html strict level 1//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html strict level 2//', strlen( '-//ietf//dtd html strict level 2//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html strict level 3//', strlen( '-//ietf//dtd html strict level 3//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html strict//', strlen( '-//ietf//dtd html strict//' ) ) === 0 || - strncmp( $public_identifier, '-//ietf//dtd html//', strlen( '-//ietf//dtd html//' ) ) === 0 || - strncmp( $public_identifier, '-//metrius//dtd metrius presentational//', - strlen( '-//metrius//dtd metrius presentational//' ) ) === 0 || - strncmp( $public_identifier, '-//microsoft//dtd internet explorer 2.0 html strict//', - strlen( '-//microsoft//dtd internet explorer 2.0 html strict//' ) ) === 0 || - strncmp( $public_identifier, '-//microsoft//dtd internet explorer 2.0 html//', - strlen( '-//microsoft//dtd internet explorer 2.0 html//' ) ) === 0 || - strncmp( $public_identifier, '-//microsoft//dtd internet explorer 2.0 tables//', - strlen( '-//microsoft//dtd internet explorer 2.0 tables//' ) ) === 0 || - strncmp( $public_identifier, '-//microsoft//dtd internet explorer 3.0 html strict//', - strlen( '-//microsoft//dtd internet explorer 3.0 html strict//' ) ) === 0 || - strncmp( $public_identifier, '-//microsoft//dtd internet explorer 3.0 html//', - strlen( '-//microsoft//dtd internet explorer 3.0 html//' ) ) === 0 || - strncmp( $public_identifier, '-//microsoft//dtd internet explorer 3.0 tables//', - strlen( '-//microsoft//dtd internet explorer 3.0 tables//' ) ) === 0 || - strncmp( $public_identifier, '-//netscape comm. corp.//dtd html//', strlen( '-//netscape comm. corp.//dtd html//' ) ) === 0 || - strncmp( $public_identifier, '-//netscape comm. corp.//dtd strict html//', - strlen( '-//netscape comm. corp.//dtd strict html//' ) ) === 0 || - strncmp( $public_identifier, "-//o'reilly and associates//dtd html 2.0//", - strlen( "-//o'reilly and associates//dtd html 2.0//" ) ) === 0 || - strncmp( $public_identifier, "-//o'reilly and associates//dtd html extended 1.0//", - strlen( "-//o'reilly and associates//dtd html extended 1.0//" ) ) === 0 || - strncmp( $public_identifier, "-//o'reilly and associates//dtd html extended relaxed 1.0//", - strlen( "-//o'reilly and associates//dtd html extended relaxed 1.0//" ) ) === 0 || - strncmp( $public_identifier, '-//sq//dtd html 2.0 hotmetal + extensions//', - strlen( '-//sq//dtd html 2.0 hotmetal + extensions//' ) ) === 0 || - strncmp( $public_identifier, '-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//', - strlen( '-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//' ) ) === 0 || - strncmp( $public_identifier, '-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//', - strlen( '-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//' ) ) === 0 || - strncmp( $public_identifier, '-//spyglass//dtd html 2.0 extended//', strlen( '-//spyglass//dtd html 2.0 extended//' ) ) === 0 || - strncmp( $public_identifier, '-//sun microsystems corp.//dtd hotjava html//', - strlen( '-//sun microsystems corp.//dtd hotjava html//' ) ) === 0 || - strncmp( $public_identifier, '-//sun microsystems corp.//dtd hotjava strict html//', - strlen( '-//sun microsystems corp.//dtd hotjava strict html//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 3 1995-03-24//', strlen( '-//w3c//dtd html 3 1995-03-24//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 3.2 draft//', strlen( '-//w3c//dtd html 3.2 draft//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 3.2 final//', strlen( '-//w3c//dtd html 3.2 final//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 3.2//', strlen( '-//w3c//dtd html 3.2//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 3.2s draft//', strlen( '-//w3c//dtd html 3.2s draft//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 4.0 frameset//', strlen( '-//w3c//dtd html 4.0 frameset//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 4.0 transitional//', strlen( '-//w3c//dtd html 4.0 transitional//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html experimental 19960712//', - strlen( '-//w3c//dtd html experimental 19960712//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html experimental 970421//', - strlen( '-//w3c//dtd html experimental 970421//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd w3 html//', strlen( '-//w3c//dtd w3 html//' ) ) === 0 || - strncmp( $public_identifier, '-//w3o//dtd w3 html 3.0//', strlen( '-//w3o//dtd w3 html 3.0//' ) ) === 0 || - strncmp( $public_identifier, '-//webtechs//dtd mozilla html 2.0//', strlen( '-//webtechs//dtd mozilla html 2.0//' ) ) === 0 || - strncmp( $public_identifier, '-//webtechs//dtd mozilla html//', strlen( '-//webtechs//dtd mozilla html//' ) ) === 0 + str_starts_with( $public_identifier, '+//silmaril//dtd html pro v0r11 19970101//' ) || + str_starts_with( $public_identifier, '-//as//dtd html 3.0 aswedit + extensions//' ) || + str_starts_with( $public_identifier, '-//advasoft ltd//dtd html 3.0 aswedit + extensions//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 2.0 level 1//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 2.0 level 2//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 2.0 strict level 1//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 2.0 strict level 2//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 2.0 strict//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 2.0//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 2.1e//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 3.0//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 3.2 final//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 3.2//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html 3//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html level 0//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html level 1//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html level 2//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html level 3//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html strict level 0//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html strict level 1//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html strict level 2//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html strict level 3//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html strict//' ) || + str_starts_with( $public_identifier, '-//ietf//dtd html//' ) || + str_starts_with( $public_identifier, '-//metrius//dtd metrius presentational//' ) || + str_starts_with( $public_identifier, '-//microsoft//dtd internet explorer 2.0 html strict//' ) || + str_starts_with( $public_identifier, '-//microsoft//dtd internet explorer 2.0 html//' ) || + str_starts_with( $public_identifier, '-//microsoft//dtd internet explorer 2.0 tables//' ) || + str_starts_with( $public_identifier, '-//microsoft//dtd internet explorer 3.0 html strict//' ) || + str_starts_with( $public_identifier, '-//microsoft//dtd internet explorer 3.0 html//' ) || + str_starts_with( $public_identifier, '-//microsoft//dtd internet explorer 3.0 tables//' ) || + str_starts_with( $public_identifier, '-//netscape comm. corp.//dtd html//' ) || + str_starts_with( $public_identifier, '-//netscape comm. corp.//dtd strict html//' ) || + str_starts_with( $public_identifier, "-//o'reilly and associates//dtd html 2.0//" ) || + str_starts_with( $public_identifier, "-//o'reilly and associates//dtd html extended 1.0//" ) || + str_starts_with( $public_identifier, "-//o'reilly and associates//dtd html extended relaxed 1.0//" ) || + str_starts_with( $public_identifier, '-//sq//dtd html 2.0 hotmetal + extensions//' ) || + str_starts_with( $public_identifier, '-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//' ) || + str_starts_with( $public_identifier, '-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//' ) || + str_starts_with( $public_identifier, '-//spyglass//dtd html 2.0 extended//' ) || + str_starts_with( $public_identifier, '-//sun microsystems corp.//dtd hotjava html//' ) || + str_starts_with( $public_identifier, '-//sun microsystems corp.//dtd hotjava strict html//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 3 1995-03-24//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 3.2 draft//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 3.2 final//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 3.2//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 3.2s draft//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 4.0 frameset//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 4.0 transitional//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html experimental 19960712//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html experimental 970421//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd w3 html//' ) || + str_starts_with( $public_identifier, '-//w3o//dtd w3 html 3.0//' ) || + str_starts_with( $public_identifier, '-//webtechs//dtd mozilla html 2.0//' ) || + str_starts_with( $public_identifier, '-//webtechs//dtd mozilla html//' ) ) { $this->indicated_compatability_mode = 'quirks'; - return; } @@ -364,13 +336,11 @@ private function __construct( */ if ( $system_identifier_is_missing && ( - strncmp( $public_identifier, '-//w3c//dtd html 4.01 frameset//', strlen( '-//w3c//dtd html 4.01 frameset//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 4.01 transitional//', - strlen( '-//w3c//dtd html 4.01 transitional//' ) ) === 0 + str_starts_with( $public_identifier, '-//w3c//dtd html 4.01 frameset//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 4.01 transitional//' ) ) ) { $this->indicated_compatability_mode = 'quirks'; - return; } @@ -383,11 +353,10 @@ private function __construct( * > The public identifier starts with… */ if ( - strncmp( $public_identifier, '-//w3c//dtd xhtml 1.0 frameset//', strlen( '-//w3c//dtd xhtml 1.0 frameset//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd xhtml 1.0 transitional//', strlen( '-//w3c//dtd xhtml 1.0 transitional//' ) ) === 0 + str_starts_with( $public_identifier, '-//w3c//dtd xhtml 1.0 frameset//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd xhtml 1.0 transitional//' ) ) { $this->indicated_compatability_mode = 'limited-quirks'; - return; } @@ -396,13 +365,11 @@ private function __construct( */ if ( ! $system_identifier_is_missing && ( - strncmp( $public_identifier, '-//w3c//dtd html 4.01 frameset//', strlen( '-//w3c//dtd html 4.01 frameset//' ) ) === 0 || - strncmp( $public_identifier, '-//w3c//dtd html 4.01 transitional//', - strlen( '-//w3c//dtd html 4.01 transitional//' ) ) === 0 + str_starts_with( $public_identifier, '-//w3c//dtd html 4.01 frameset//' ) || + str_starts_with( $public_identifier, '-//w3c//dtd html 4.01 transitional//' ) ) ) { $this->indicated_compatability_mode = 'limited-quirks'; - return; } @@ -437,12 +404,12 @@ private function __construct( * null === WP_HTML_Doctype_Info::from_doctype_token( 'html' ); * null === WP_HTML_Doctype_Info::from_doctype_token( '' ); * - * @param string $doctype_html The complete raw DOCTYPE HTML string, e.g. ``. + * @since 6.7.0 + * + * @param string $doctype_html The complete raw DOCTYPE HTML string, e.g. ``. * * @return WP_HTML_Doctype_Info|null A WP_HTML_Doctype_Info instance will be returned if the * provided DOCTYPE HTML is a valid DOCTYPE. Otherwise, null. - * @since 6.7.0 - * */ public static function from_doctype_token( string $doctype_html ): ?self { $doctype_name = null; @@ -572,7 +539,6 @@ public static function from_doctype_token( string $doctype_html ): ?self { * > Set the current DOCTYPE token's force-quirks flag to on. Reconsume in the bogus * > DOCTYPE state. */ - return new self( $doctype_name, $doctype_public_id, $doctype_system_id, true ); parse_doctype_public_identifier: @@ -594,7 +560,7 @@ public static function from_doctype_token( string $doctype_html ): ?self { return new self( $doctype_name, $doctype_public_id, $doctype_system_id, true ); } - ++ $at; + ++$at; $identifier_length = strcspn( $doctype_html, $closer_quote, $at, $end - $at ); $doctype_public_id = str_replace( "\0", "\u{FFFD}", substr( $doctype_html, $at, $identifier_length ) ); @@ -604,7 +570,7 @@ public static function from_doctype_token( string $doctype_html ): ?self { return new self( $doctype_name, $doctype_public_id, $doctype_system_id, true ); } - ++ $at; + ++$at; /* * "Between DOCTYPE public and system identifiers state" @@ -637,7 +603,7 @@ public static function from_doctype_token( string $doctype_html ): ?self { return new self( $doctype_name, $doctype_public_id, $doctype_system_id, true ); } - ++ $at; + ++$at; $identifier_length = strcspn( $doctype_html, $closer_quote, $at, $end - $at ); $doctype_system_id = str_replace( "\0", "\u{FFFD}", substr( $doctype_html, $at, $identifier_length ) ); diff --git a/components/HTML/class-wp-html-open-elements.php b/components/HTML/class-wp-html-open-elements.php index ad5d34f9..05c01fca 100644 --- a/components/HTML/class-wp-html-open-elements.php +++ b/components/HTML/class-wp-html-open-elements.php @@ -1,4 +1,7 @@ pop_handler = $handler; @@ -94,10 +96,9 @@ public function set_pop_handler( Closure $handler ): void { * * The function will be called with the pushed item as its argument. * - * @param Closure $handler The handler function. - * * @since 6.6.0 * + * @param Closure $handler The handler function. */ public function set_push_handler( Closure $handler ): void { $this->push_handler = $handler; @@ -111,17 +112,16 @@ public function set_push_handler( Closure $handler ): void { * "nth item" on the stack, counting from the top, where the * top-most element is the 1st, the second is the 2nd, etc... * - * @param int $nth Retrieve the nth item on the stack, with 1 being - * the top element, 2 being the second, etc... + * @since 6.7.0 * + * @param int $nth Retrieve the nth item on the stack, with 1 being + * the top element, 2 being the second, etc... * @return WP_HTML_Token|null Name of the node on the stack at the given location, * or `null` if the location isn't on the stack. - * @since 6.7.0 - * */ public function at( int $nth ): ?WP_HTML_Token { foreach ( $this->walk_down() as $item ) { - if ( 0 === -- $nth ) { + if ( 0 === --$nth ) { return $item; } } @@ -132,11 +132,10 @@ public function at( int $nth ): ?WP_HTML_Token { /** * Reports if a node of a given name is in the stack of open elements. * - * @param string $node_name Name of node for which to check. - * - * @return bool Whether a node of the given name is in the stack of open elements. * @since 6.7.0 * + * @param string $node_name Name of node for which to check. + * @return bool Whether a node of the given name is in the stack of open elements. */ public function contains( string $node_name ): bool { foreach ( $this->walk_up() as $item ) { @@ -151,11 +150,10 @@ public function contains( string $node_name ): bool { /** * Reports if a specific node is in the stack of open elements. * - * @param WP_HTML_Token $token Look for this node in the stack. - * - * @return bool Whether the referenced node is in the stack of open elements. * @since 6.4.0 * + * @param WP_HTML_Token $token Look for this node in the stack. + * @return bool Whether the referenced node is in the stack of open elements. */ public function contains_node( WP_HTML_Token $token ): bool { foreach ( $this->walk_up() as $item ) { @@ -170,9 +168,9 @@ public function contains_node( WP_HTML_Token $token ): bool { /** * Returns how many nodes are currently in the stack of open elements. * - * @return int How many node are in the stack of open elements. * @since 6.4.0 * + * @return int How many node are in the stack of open elements. */ public function count(): int { return count( $this->stack ); @@ -182,9 +180,9 @@ public function count(): int { * Returns the node at the end of the stack of open elements, * if one exists. If the stack is empty, returns null. * - * @return WP_HTML_Token|null Last node in the stack of open elements, if one exists, otherwise null. * @since 6.4.0 * + * @return WP_HTML_Token|null Last node in the stack of open elements, if one exists, otherwise null. */ public function current_node(): ?WP_HTML_Token { $current_node = end( $this->stack ); @@ -209,16 +207,15 @@ public function current_node(): ?WP_HTML_Token { * // Is the current node any element/tag? * $stack->current_node_is( '#tag' ); * - * @param string $identity Check if the current node has this name or type (depending on what is provided). + * @see WP_HTML_Tag_Processor::get_token_type + * @see WP_HTML_Tag_Processor::get_token_name * - * @return bool Whether there is a current element that matches the given identity, whether a token name or type. * @since 6.7.0 * * @access private * - * @see WP_HTML_Tag_Processor::get_token_type - * @see WP_HTML_Tag_Processor::get_token_name - * + * @param string $identity Check if the current node has this name or type (depending on what is provided). + * @return bool Whether there is a current element that matches the given identity, whether a token name or type. */ public function current_node_is( string $identity ): bool { $current_node = end( $this->stack ); @@ -238,14 +235,13 @@ public function current_node_is( string $identity ): bool { /** * Returns whether an element is in a specific scope. * - * @param string $tag_name Name of tag check. - * @param string[] $termination_list List of elements that terminate the search. + * @since 6.4.0 * - * @return bool Whether the element was found in a specific scope. * @see https://html.spec.whatwg.org/#has-an-element-in-the-specific-scope * - * @since 6.4.0 - * + * @param string $tag_name Name of tag check. + * @param string[] $termination_list List of elements that terminate the search. + * @return bool Whether the element was found in a specific scope. */ public function has_element_in_specific_scope( string $tag_name, $termination_list ): bool { foreach ( $this->walk_up() as $node ) { @@ -298,14 +294,13 @@ public function has_element_in_specific_scope( string $tag_name, $termination_li * > - SVG desc * > - SVG title * - * @param string $tag_name Name of tag to check. - * - * @return bool Whether given element is in scope. - * @see https://html.spec.whatwg.org/#has-an-element-in-scope - * * @since 6.4.0 * @since 6.7.0 Full support. * + * @see https://html.spec.whatwg.org/#has-an-element-in-scope + * + * @param string $tag_name Name of tag to check. + * @return bool Whether given element is in scope. */ public function has_element_in_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( @@ -346,15 +341,14 @@ public function has_element_in_scope( string $tag_name ): bool { * > - ol in the HTML namespace * > - ul in the HTML namespace * - * @param string $tag_name Name of tag to check. - * - * @return bool Whether given element is in scope. + * @since 6.4.0 + * @since 6.5.0 Implemented: no longer throws on every invocation. * @since 6.7.0 Supports all required HTML elements. * * @see https://html.spec.whatwg.org/#has-an-element-in-list-item-scope * - * @since 6.4.0 - * @since 6.5.0 Implemented: no longer throws on every invocation. + * @param string $tag_name Name of tag to check. + * @return bool Whether given element is in scope. */ public function has_element_in_list_item_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( @@ -397,14 +391,13 @@ public function has_element_in_list_item_scope( string $tag_name ): bool { * > - All the element types listed above for the has an element in scope algorithm. * > - button in the HTML namespace * - * @param string $tag_name Name of tag to check. - * - * @return bool Whether given element is in scope. - * @see https://html.spec.whatwg.org/#has-an-element-in-button-scope - * * @since 6.4.0 * @since 6.7.0 Supports all required HTML elements. * + * @see https://html.spec.whatwg.org/#has-an-element-in-button-scope + * + * @param string $tag_name Name of tag to check. + * @return bool Whether given element is in scope. */ public function has_element_in_button_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( @@ -446,14 +439,13 @@ public function has_element_in_button_scope( string $tag_name ): bool { * > - table in the HTML namespace * > - template in the HTML namespace * - * @param string $tag_name Name of tag to check. - * - * @return bool Whether given element is in scope. - * @see https://html.spec.whatwg.org/#has-an-element-in-table-scope - * * @since 6.4.0 * @since 6.7.0 Full implementation. * + * @see https://html.spec.whatwg.org/#has-an-element-in-table-scope + * + * @param string $tag_name Name of tag to check. + * @return bool Whether given element is in scope. */ public function has_element_in_table_scope( string $tag_name ): bool { return $this->has_element_in_specific_scope( @@ -478,14 +470,13 @@ public function has_element_in_table_scope( string $tag_name ): bool { * > - optgroup in the HTML namespace * > - option in the HTML namespace * - * @param string $tag_name Name of tag to check. - * - * @return bool Whether the given element is in SELECT scope. - * @see https://html.spec.whatwg.org/#has-an-element-in-select-scope - * * @since 6.4.0 Stub implementation (throws). * @since 6.7.0 Full implementation. * + * @see https://html.spec.whatwg.org/#has-an-element-in-select-scope + * + * @param string $tag_name Name of tag to check. + * @return bool Whether the given element is in SELECT scope. */ public function has_element_in_select_scope( string $tag_name ): bool { foreach ( $this->walk_up() as $node ) { @@ -507,11 +498,11 @@ public function has_element_in_select_scope( string $tag_name ): bool { /** * Returns whether a P is in BUTTON scope. * - * @return bool Whether a P is in BUTTON scope. - * @see https://html.spec.whatwg.org/#has-an-element-in-button-scope - * * @since 6.4.0 * + * @see https://html.spec.whatwg.org/#has-an-element-in-button-scope + * + * @return bool Whether a P is in BUTTON scope. */ public function has_p_in_button_scope(): bool { return $this->has_p_in_button_scope; @@ -520,11 +511,11 @@ public function has_p_in_button_scope(): bool { /** * Pops a node off of the stack of open elements. * - * @return bool Whether a node was popped off of the stack. - * @see https://html.spec.whatwg.org/#stack-of-open-elements - * * @since 6.4.0 * + * @see https://html.spec.whatwg.org/#stack-of-open-elements + * + * @return bool Whether a node was popped off of the stack. */ public function pop(): bool { $item = array_pop( $this->stack ); @@ -532,27 +523,19 @@ public function pop(): bool { return false; } - if ( 'context-node' === $item->bookmark_name ) { - $this->stack[] = $item; - - return false; - } - $this->after_element_pop( $item ); - return true; } /** * Pops nodes off of the stack of open elements until an HTML tag with the given name has been popped. * - * @param string $html_tag_name Name of tag that needs to be popped off of the stack of open elements. - * - * @return bool Whether a tag of the given name was found and popped off of the stack of open elements. * @since 6.4.0 * * @see WP_HTML_Open_Elements::pop * + * @param string $html_tag_name Name of tag that needs to be popped off of the stack of open elements. + * @return bool Whether a tag of the given name was found and popped off of the stack of open elements. */ public function pop_until( string $html_tag_name ): bool { foreach ( $this->walk_up() as $item ) { @@ -580,12 +563,11 @@ public function pop_until( string $html_tag_name ): bool { /** * Pushes a node onto the stack of open elements. * - * @param WP_HTML_Token $stack_item Item to add onto stack. + * @since 6.4.0 * * @see https://html.spec.whatwg.org/#stack-of-open-elements * - * @since 6.4.0 - * + * @param WP_HTML_Token $stack_item Item to add onto stack. */ public function push( WP_HTML_Token $stack_item ): void { $this->stack[] = $stack_item; @@ -595,17 +577,12 @@ public function push( WP_HTML_Token $stack_item ): void { /** * Removes a specific node from the stack of open elements. * - * @param WP_HTML_Token $token The node to remove from the stack of open elements. - * - * @return bool Whether the node was found and removed from the stack of open elements. * @since 6.4.0 * + * @param WP_HTML_Token $token The node to remove from the stack of open elements. + * @return bool Whether the node was found and removed from the stack of open elements. */ public function remove_node( WP_HTML_Token $token ): bool { - if ( 'context-node' === $token->bookmark_name ) { - return false; - } - foreach ( $this->walk_up() as $position_from_end => $item ) { if ( $token->bookmark_name !== $item->bookmark_name ) { continue; @@ -614,7 +591,6 @@ public function remove_node( WP_HTML_Token $token ): bool { $position_from_start = $this->count() - $position_from_end - 1; array_splice( $this->stack, $position_from_start, 1 ); $this->after_element_pop( $item ); - return true; } @@ -644,7 +620,7 @@ public function remove_node( WP_HTML_Token $token ): bool { public function walk_down() { $count = count( $this->stack ); - for ( $i = 0; $i < $count; $i ++ ) { + for ( $i = 0; $i < $count; $i++ ) { yield $this->stack[ $i ]; } } @@ -666,17 +642,16 @@ public function walk_down() { * To start with the first added element and walk towards the bottom, * see WP_HTML_Open_Elements::walk_down(). * - * @param WP_HTML_Token|null $above_this_node Optional. Start traversing above this node, - * if provided and if the node exists. - * + * @since 6.4.0 * @since 6.5.0 Accepts $above_this_node to start traversal above a given node, if it exists. * - * @since 6.4.0 + * @param WP_HTML_Token|null $above_this_node Optional. Start traversing above this node, + * if provided and if the node exists. */ public function walk_up( ?WP_HTML_Token $above_this_node = null ) { $has_found_node = null === $above_this_node; - for ( $i = count( $this->stack ) - 1; $i >= 0; $i -- ) { + for ( $i = count( $this->stack ) - 1; $i >= 0; $i-- ) { $node = $this->stack[ $i ]; if ( ! $has_found_node ) { @@ -701,10 +676,9 @@ public function walk_up( ?WP_HTML_Token $above_this_node = null ) { * over the open stack elements upon each new tag it encounters. These flags, * however, need to be maintained as items are added and removed from the stack. * - * @param WP_HTML_Token $item Element that was added to the stack of open elements. - * * @since 6.4.0 * + * @param WP_HTML_Token $item Element that was added to the stack of open elements. */ public function after_element_push( WP_HTML_Token $item ): void { $namespaced_name = 'html' === $item->namespace @@ -757,10 +731,9 @@ public function after_element_push( WP_HTML_Token $item ): void { * over the open stack elements upon each new tag it encounters. These flags, * however, need to be maintained as items are added and removed from the stack. * - * @param WP_HTML_Token $item Element that was removed from the stack of open elements. - * * @since 6.4.0 * + * @param WP_HTML_Token $item Element that was removed from the stack of open elements. */ public function after_element_pop( WP_HTML_Token $item ): void { /* @@ -877,6 +850,6 @@ public function clear_to_table_row_context(): void { * @since 6.6.0 */ public function __wakeup() { - throw new LogicException( __CLASS__ . ' should never be unserialized' ); + throw new \LogicException( __CLASS__ . ' should never be unserialized' ); } } diff --git a/components/HTML/class-wp-html-processor-state.php b/components/HTML/class-wp-html-processor-state.php index b7cdd347..b61064e6 100644 --- a/components/HTML/class-wp-html-processor-state.php +++ b/components/HTML/class-wp-html-processor-state.php @@ -1,4 +1,6 @@ `, which is the default value. * - The only supported document encoding is `UTF-8`, which is the default value. * - * @param string $html Input HTML fragment to process. - * @param string $context Context element for the fragment, must be default of ``. - * @param string $encoding Text encoding of the document; must be default of 'UTF-8'. - * - * @return static|null The created processor if successful, otherwise null. * @since 6.4.0 * @since 6.6.0 Returns `static` instead of `self` so it can create subclass instances. * + * @param string $html Input HTML fragment to process. + * @param string $context Context element for the fragment, must be default of ``. + * @param string $encoding Text encoding of the document; must be default of 'UTF-8'. + * @return static|null The created processor if successful, otherwise null. */ public static function create_fragment( $html, $context = '', $encoding = 'UTF-8' ) { if ( '' !== $context || 'UTF-8' !== $encoding ) { return null; } - $processor = new static( $html, self::CONSTRUCTOR_UNLOCK_CODE ); - $processor->state->context_node = array( 'BODY', array() ); - $processor->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - $processor->state->encoding = $encoding; - $processor->state->encoding_confidence = 'certain'; - - // @todo Create "fake" bookmarks for non-existent but implied nodes. - $processor->bookmarks['root-node'] = new WP_HTML_Span( 0, 0 ); - $processor->bookmarks['context-node'] = new WP_HTML_Span( 0, 0 ); - - $root_node = new WP_HTML_Token( - 'root-node', - 'HTML', - false - ); - - $processor->state->stack_of_open_elements->push( $root_node ); + $context_processor = static::create_full_parser( "{$context}", $encoding ); + if ( null === $context_processor ) { + return null; + } - $context_node = new WP_HTML_Token( - 'context-node', - $processor->state->context_node[0], - false - ); + while ( $context_processor->next_tag() ) { + if ( ! $context_processor->is_virtual() ) { + $context_processor->set_bookmark( 'final_node' ); + } + } - $processor->context_node = $context_node; - $processor->breadcrumbs = array( 'HTML', $context_node->node_name ); + if ( + ! $context_processor->has_bookmark( 'final_node' ) || + ! $context_processor->seek( 'final_node' ) + ) { + _doing_it_wrong( __METHOD__, __( 'No valid context element was detected.' ), '6.8.0' ); + return null; + } - return $processor; + return $context_processor->create_fragment_at_current_node( $html ); } /** @@ -335,14 +333,13 @@ public static function create_fragment( $html, $context = '', $encoding = * entire HTML document from start to finish. Consider a fragment parser with * a context node of ``. * - * Since UTF-8 is the only currently-accepted charset, if working with a - * document that isn't UTF-8, it's important to convert the document before - * creating the processor: pass in the converted HTML. + * UTF-8 is the only allowed encoding. If working with a document that + * isn't UTF-8, first convert the document to UTF-8, then pass in the + * converted HTML. * - * @param string $html Input HTML document to process. - * @param string|null $known_definite_encoding Optional. If provided, specifies the charset used + * @param string $html Input HTML document to process. + * @param string|null $known_definite_encoding Optional. If provided, specifies the charset used * in the input byte stream. Currently must be UTF-8. - * * @return static|null The created processor if successful, otherwise null. */ public static function create_full_parser( $html, $known_definite_encoding = 'UTF-8' ) { @@ -364,13 +361,12 @@ public static function create_full_parser( $html, $known_definite_encoding = 'UT * * @access private * - * @param string $html HTML to process. - * @param string|null $use_the_static_create_methods_instead This constructor should not be called manually. - * * @since 6.4.0 * * @see WP_HTML_Processor::create_fragment() * + * @param string $html HTML to process. + * @param string|null $use_the_static_create_methods_instead This constructor should not be called manually. */ public function __construct( $html, $use_the_static_create_methods_instead = null ) { parent::__construct( $html ); @@ -379,7 +375,7 @@ public function __construct( $html, $use_the_static_create_methods_instead = nul _doing_it_wrong( __METHOD__, sprintf( - /* translators: %s: WP_HTML_Processor::create_fragment(). */ + /* translators: %s: WP_HTML_Processor::create_fragment(). */ __( 'Call %s to create an HTML Processor instead of calling the constructor directly.' ), 'WP_HTML_Processor::create_fragment()' ), @@ -428,14 +424,155 @@ function ( WP_HTML_Token $token ): void { } /** - * Stops the parser and terminates its execution when encountering unsupported markup. + * Creates a fragment processor at the current node. + * + * HTML Fragment parsing always happens with a context node. HTML Fragment Processors can be + * instantiated with a `BODY` context node via `WP_HTML_Processor::create_fragment( $html )`. + * + * The context node may impact how a fragment of HTML is parsed. For example, consider the HTML + * fragment `Inside TD?`. + * + * A BODY context node will produce the following tree: + * + * └─#text Inside TD? + * + * Notice that the `` tags are completely ignored. + * + * Compare that with an SVG context node that produces the following tree: + * + * β”œβ”€svg:td + * └─#text Inside TD? + * + * Here, a `td` node in the `svg` namespace is created, and its self-closing flag is respected. + * This is a peculiarity of parsing HTML in foreign content like SVG. * - * @param string $message Explains support is missing in order to parse the current node. + * Finally, consider the tree produced with a TABLE context node: + * + * └─TBODY + * └─TR + * └─TD + * └─#text Inside TD? + * + * These examples demonstrate how important the context node may be when processing an HTML + * fragment. Special care must be taken when processing fragments that are expected to appear + * in specific contexts. SVG and TABLE are good examples, but there are others. + * + * @see https://html.spec.whatwg.org/multipage/parsing.html#html-fragment-parsing-algorithm + * + * @since 6.8.0 + * + * @param string $html Input HTML fragment to process. + * @return static|null The created processor if successful, otherwise null. + */ + private function create_fragment_at_current_node( string $html ) { + if ( $this->get_token_type() !== '#tag' || $this->is_tag_closer() ) { + _doing_it_wrong( + __METHOD__, + __( 'The context element must be a start tag.' ), + '6.8.0' + ); + return null; + } + + $tag_name = $this->current_element->token->node_name; + $namespace = $this->current_element->token->namespace; + + if ( 'html' === $namespace && self::is_void( $tag_name ) ) { + _doing_it_wrong( + __METHOD__, + sprintf( + // translators: %s: A tag name like INPUT or BR. + __( 'The context element cannot be a void element, found "%s".' ), + $tag_name + ), + '6.8.0' + ); + return null; + } + + /* + * Prevent creating fragments at nodes that require a special tokenizer state. + * This is unsupported by the HTML Processor. + */ + if ( + 'html' === $namespace && + in_array( $tag_name, array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP', 'PLAINTEXT' ), true ) + ) { + _doing_it_wrong( + __METHOD__, + sprintf( + // translators: %s: A tag name like IFRAME or TEXTAREA. + __( 'The context element "%s" is not supported.' ), + $tag_name + ), + '6.8.0' + ); + return null; + } + + $fragment_processor = new static( $html, self::CONSTRUCTOR_UNLOCK_CODE ); + + $fragment_processor->compat_mode = $this->compat_mode; + + // @todo Create "fake" bookmarks for non-existent but implied nodes. + $fragment_processor->bookmarks['root-node'] = new WP_HTML_Span( 0, 0 ); + $root_node = new WP_HTML_Token( + 'root-node', + 'HTML', + false + ); + $fragment_processor->state->stack_of_open_elements->push( $root_node ); + + $fragment_processor->bookmarks['context-node'] = new WP_HTML_Span( 0, 0 ); + $fragment_processor->context_node = clone $this->current_element->token; + $fragment_processor->context_node->bookmark_name = 'context-node'; + $fragment_processor->context_node->on_destroy = null; + + $fragment_processor->breadcrumbs = array( 'HTML', $fragment_processor->context_node->node_name ); + + if ( 'TEMPLATE' === $fragment_processor->context_node->node_name ) { + $fragment_processor->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_TEMPLATE; + } + + $fragment_processor->reset_insertion_mode_appropriately(); + + /* + * > Set the parser's form element pointer to the nearest node to the context element that + * > is a form element (going straight up the ancestor chain, and including the element + * > itself, if it is a form element), if any. (If there is no such form element, the + * > form element pointer keeps its initial value, null.) + */ + foreach ( $this->state->stack_of_open_elements->walk_up() as $element ) { + if ( 'FORM' === $element->node_name && 'html' === $element->namespace ) { + $fragment_processor->state->form_element = clone $element; + $fragment_processor->state->form_element->bookmark_name = null; + $fragment_processor->state->form_element->on_destroy = null; + break; + } + } + + $fragment_processor->state->encoding_confidence = 'irrelevant'; + + /* + * Update the parsing namespace near the end of the process. + * This is important so that any push/pop from the stack of open + * elements does not change the parsing namespace. + */ + $fragment_processor->change_parsing_namespace( + $this->current_element->token->integration_node_type ? 'html' : $namespace + ); + + return $fragment_processor; + } + + /** + * Stops the parser and terminates its execution when encountering unsupported markup. * * @throws WP_HTML_Unsupported_Exception Halts execution of the parser. * * @since 6.7.0 * + * @param string $message Explains support is missing in order to parse the current node. */ private function bail( string $message ) { $here = $this->bookmarks[ $this->state->current_token->bookmark_name ]; @@ -481,12 +618,12 @@ private function bail( string $message ) { * false === $processor->next_tag(); * WP_HTML_Processor::ERROR_UNSUPPORTED === $processor->get_last_error(); * - * @return string|null The last error, if one exists, otherwise null. + * @since 6.4.0 + * * @see self::ERROR_UNSUPPORTED * @see self::ERROR_EXCEEDED_MAX_BOOKMARKS * - * @since 6.4.0 - * + * @return string|null The last error, if one exists, otherwise null. */ public function get_last_error(): ?string { return $this->last_error; @@ -497,11 +634,11 @@ public function get_last_error(): ?string { * * This is meant for debugging purposes, not for production use. * - * @return WP_HTML_Unsupported_Exception|null - * @see self::$unsupported_exception - * * @since 6.7.0 * + * @see self::$unsupported_exception + * + * @return WP_HTML_Unsupported_Exception|null */ public function get_unsupported_exception() { return $this->unsupported_exception; @@ -510,26 +647,26 @@ public function get_unsupported_exception() { /** * Finds the next tag matching the $query. * - * @param array|string|null $query { + * @todo Support matching the class name and tag name. + * + * @since 6.4.0 + * @since 6.6.0 Visits all tokens, including virtual ones. + * + * @throws Exception When unable to allocate a bookmark for the next token in the input HTML document. + * + * @param array|string|null $query { * Optional. Which tag name to find, having which class, etc. Default is to find any tag. * - * @type string|null $tag_name Which tag to find, or `null` for "any tag." - * @type string $tag_closers 'visit' to pause at tag closers, 'skip' or unset to only visit openers. - * @type int|null $match_offset Find the Nth tag matching all search criteria. + * @type string|null $tag_name Which tag to find, or `null` for "any tag." + * @type string $tag_closers 'visit' to pause at tag closers, 'skip' or unset to only visit openers. + * @type int|null $match_offset Find the Nth tag matching all search criteria. * 1 for "first" tag, 3 for "third," etc. * Defaults to first tag. - * @type string|null $class_name Tag must contain this whole class name to match. - * @type string[] $breadcrumbs DOM sub-path at which element is found, e.g. `array( 'FIGURE', 'IMG' )`. + * @type string|null $class_name Tag must contain this whole class name to match. + * @type string[] $breadcrumbs DOM sub-path at which element is found, e.g. `array( 'FIGURE', 'IMG' )`. * May also contain the wildcard `*` which matches a single element, e.g. `array( 'SECTION', '*' )`. * } * @return bool Whether a tag was matched. - * @throws Exception When unable to allocate a bookmark for the next token in the input HTML document. - * - * @todo Support matching the class name and tag name. - * - * @since 6.4.0 - * @since 6.6.0 Visits all tokens, including virtual ones. - * */ public function next_tag( $query = null ): bool { $visit_closers = isset( $query['tag_closers'] ) && 'visit' === $query['tag_closers']; @@ -558,10 +695,13 @@ public function next_tag( $query = null ): bool { __( 'Please pass a query array to this function.' ), '6.4.0' ); - return false; } + if ( isset( $query['tag_name'] ) ) { + $query['tag_name'] = strtoupper( $query['tag_name'] ); + } + $needs_class = ( isset( $query['class_name'] ) && is_string( $query['class_name'] ) ) ? $query['class_name'] : null; @@ -600,7 +740,7 @@ public function next_tag( $query = null ): bool { continue; } - if ( $this->matches_breadcrumbs( $breadcrumbs ) && 0 === -- $match_offset ) { + if ( $this->matches_breadcrumbs( $breadcrumbs ) && 0 === --$match_offset ) { return true; } } @@ -608,6 +748,22 @@ public function next_tag( $query = null ): bool { return false; } + /** + * Finds the next token in the HTML document. + * + * This doesn't currently have a way to represent non-tags and doesn't process + * semantic rules for text nodes. For access to the raw tokens consider using + * WP_HTML_Tag_Processor instead. + * + * @since 6.5.0 Added for internal support; do not use. + * @since 6.7.2 Refactored so subclasses may extend. + * + * @return bool Whether a token was parsed. + */ + public function next_token(): bool { + return $this->next_visitable_token(); + } + /** * Ensures internal accounting is maintained for HTML semantic rules while * the underlying Tag Processor class is seeking to a bookmark. @@ -616,13 +772,18 @@ public function next_tag( $query = null ): bool { * semantic rules for text nodes. For access to the raw tokens consider using * WP_HTML_Tag_Processor instead. * - * @return bool - * @since 6.5.0 Added for internal support; do not use. + * Note that this method may call itself recursively. This is why it is not + * implemented as {@see WP_HTML_Processor::next_token()}, which instead calls + * this method similarly to how {@see WP_HTML_Tag_Processor::next_token()} + * calls the {@see WP_HTML_Tag_Processor::base_class_next_token()} method. + * + * @since 6.7.2 Added for internal support. * * @access private * + * @return bool */ - public function next_token(): bool { + private function next_visitable_token(): bool { $this->current_element = null; if ( isset( $this->last_error ) ) { @@ -640,7 +801,7 @@ public function next_token(): bool { * tokens works in the meantime and isn't obviously wrong. */ if ( empty( $this->element_queue ) && $this->step() ) { - return $this->next_token(); + return $this->next_visitable_token(); } // Process the next event on the queue. @@ -651,7 +812,7 @@ public function next_token(): bool { continue; } - return empty( $this->element_queue ) ? false : $this->next_token(); + return empty( $this->element_queue ) ? false : $this->next_visitable_token(); } $is_pop = WP_HTML_Stack_Event::POP === $this->current_element->operation; @@ -662,7 +823,7 @@ public function next_token(): bool { * the breadcrumbs. */ if ( 'root-node' === $this->current_element->token->bookmark_name ) { - return $this->next_token(); + return $this->next_visitable_token(); } // Adjust the breadcrumbs for this event. @@ -674,7 +835,7 @@ public function next_token(): bool { // Avoid sending close events for elements which don't expect a closing. if ( $is_pop && ! $this->expects_closer( $this->current_element->token ) ) { - return $this->next_token(); + return $this->next_visitable_token(); } return true; @@ -692,9 +853,9 @@ public function next_token(): bool { * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); * $p->is_tag_closer() === true; * - * @return bool Whether the current tag is a tag closer. * @since 6.6.0 Subclassed for HTML Processor. * + * @return bool Whether the current tag is a tag closer. */ public function is_tag_closer(): bool { return $this->is_virtual() @@ -706,11 +867,11 @@ public function is_tag_closer(): bool { * Indicates if the currently-matched token is virtual, created by a stack operation * while processing HTML, rather than a token found in the HTML text itself. * - * @return bool Whether the current token is virtual. * @since 6.6.0 * + * @return bool Whether the current token is virtual. */ - public function is_virtual(): bool { + private function is_virtual(): bool { return ( isset( $this->current_element->provenance ) && 'virtual' === $this->current_element->provenance @@ -736,12 +897,11 @@ public function is_virtual(): bool { * false === $processor->matches_breadcrumbs( array( 'span', 'img' ) ); * true === $processor->matches_breadcrumbs( array( 'span', '*', 'img' ) ); * - * @param string[] $breadcrumbs DOM sub-path at which element is found, e.g. `array( 'FIGURE', 'IMG' )`. - * May also contain the wildcard `*` which matches a single element, e.g. `array( 'SECTION', '*' )`. - * - * @return bool Whether the currently-matched tag is found at the given nested structure. * @since 6.4.0 * + * @param string[] $breadcrumbs DOM sub-path at which element is found, e.g. `array( 'FIGURE', 'IMG' )`. + * May also contain the wildcard `*` which matches a single element, e.g. `array( 'SECTION', '*' )`. + * @return bool Whether the currently-matched tag is found at the given nested structure. */ public function matches_breadcrumbs( $breadcrumbs ): bool { // Everything matches when there are zero constraints. @@ -756,7 +916,7 @@ public function matches_breadcrumbs( $breadcrumbs ): bool { return false; } - for ( $i = count( $this->breadcrumbs ) - 1; $i >= 0; $i -- ) { + for ( $i = count( $this->breadcrumbs ) - 1; $i >= 0; $i-- ) { $node = $this->breadcrumbs[ $i ]; $crumb = strtoupper( current( $breadcrumbs ) ); @@ -783,13 +943,12 @@ public function matches_breadcrumbs( $breadcrumbs ): bool { * foreign content will also act just like a void tag, immediately * closing as soon as the processor advances to the next token. * - * @param WP_HTML_Token|null $node Optional. Node to examine, if provided. - * Default is to examine current node. + * @since 6.6.0 * + * @param WP_HTML_Token|null $node Optional. Node to examine, if provided. + * Default is to examine current node. * @return bool|null Whether to expect a closer for the currently-matched node, * or `null` if not matched on any token. - * @since 6.6.0 - * */ public function expects_closer( ?WP_HTML_Token $node = null ): ?bool { $token_name = $node->node_name ?? $this->get_token_name(); @@ -807,10 +966,9 @@ public function expects_closer( ?WP_HTML_Token $node = null ): ?bool { // Doctype declarations. 'html' === $token_name || // Void elements. - self::is_void( $token_name ) || + ( 'html' === $token_namespace && self::is_void( $token_name ) ) || // Special atomic elements. - ( 'html' === $token_namespace && in_array( $token_name, - array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) ) || + ( 'html' === $token_namespace && in_array( $token_name, array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) ) || // Self-closing elements in foreign content. ( 'html' !== $token_namespace && $token_has_self_closing ) ); @@ -819,16 +977,15 @@ public function expects_closer( ?WP_HTML_Token $node = null ): ?bool { /** * Steps through the HTML document and stop at the next tag, if any. * - * @param string $node_to_process Whether to parse the next node or reprocess the current node. + * @since 6.4.0 * - * @return bool Whether a tag was matched. * @throws Exception When unable to allocate a bookmark for the next token in the input HTML document. * + * @see self::PROCESS_NEXT_NODE * @see self::REPROCESS_CURRENT_NODE * - * @since 6.4.0 - * - * @see self::PROCESS_NEXT_NODE + * @param string $node_to_process Whether to parse the next node or reprocess the current node. + * @return bool Whether a tag was matched. */ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { // Refuse to proceed if there was a previous error. @@ -993,21 +1150,17 @@ public function step( $node_to_process = self::PROCESS_NEXT_NODE ): bool { * Breadcrumbs start at the outermost parent and descend toward the matched element. * They always include the entire path from the root HTML node to the matched element. * - * @return string[]|null Array of tag names representing path to matched node, if matched, otherwise NULL. - * @since 6.4.0 - * - * @todo It could be more efficient to expose a generator-based version of this function - * to avoid creating the array copy on tag iteration. If this is done, it would likely - * be more useful to walk up the stack when yielding instead of starting at the top. - * - * Example + * Example: * * $processor = WP_HTML_Processor::create_fragment( '

' ); * $processor->next_tag( 'IMG' ); * $processor->get_breadcrumbs() === array( 'HTML', 'BODY', 'P', 'STRONG', 'EM', 'IMG' ); * + * @since 6.4.0 + * + * @return string[] Array of tag names representing path to matched node. */ - public function get_breadcrumbs(): ?array { + public function get_breadcrumbs(): array { return $this->breadcrumbs; } @@ -1032,9 +1185,9 @@ public function get_breadcrumbs(): ?array { * $processor->next_token(); * 3 === $processor->get_current_depth(); * - * @return int Nesting-depth of current location in the document. * @since 6.6.0 * + * @return int Nesting-depth of current location in the document. */ public function get_current_depth(): int { return count( $this->breadcrumbs ); @@ -1072,11 +1225,11 @@ public function get_current_depth(): int { * echo WP_HTML_Processor::normalize( ' syntax < <> "oddities"' ); * // syntax < <> "oddities" * - * @param string $html Input HTML to normalize. - * - * @return string|null Normalized output, or `null` if unable to normalize. * @since 6.7.0 * + * @param string $html Input HTML to normalize. + * + * @return string|null Normalized output, or `null` if unable to normalize. */ public static function normalize( string $html ): ?string { return static::create_fragment( $html )->serialize(); @@ -1116,10 +1269,10 @@ public static function normalize( string $html ): ?string { * echo $processor->serialize(); * // syntax < <> "oddities" * - * @return string|null Normalized HTML markup represented by processor, - * or `null` if unable to generate serialization. * @since 6.7.0 * + * @return string|null Normalized HTML markup represented by processor, + * or `null` if unable to generate serialization. */ public function serialize(): ?string { if ( WP_HTML_Tag_Processor::STATE_READY !== $this->parser_state ) { @@ -1128,7 +1281,6 @@ public function serialize(): ?string { 'An HTML Processor which has already started processing cannot serialize its contents. Serialize immediately after creating the instance.', E_USER_WARNING ); - return null; } @@ -1143,7 +1295,6 @@ public function serialize(): ?string { "Cannot serialize HTML Processor with parsing error: {$this->get_last_error()}.", E_USER_WARNING ); - return null; } @@ -1157,11 +1308,11 @@ public function serialize(): ?string { * if able. If not matched at any token or if the token doesn't correspond to any HTML * it will return an empty string (for example, presumptuous end tags are ignored). * - * @return string Serialization of token, or empty string if no serialization exists. - * @since 6.7.0 - * * @see static::serialize() * + * @since 6.7.0 + * + * @return string Serialization of token, or empty string if no serialization exists. */ protected function serialize_token(): string { $html = ''; @@ -1181,15 +1332,15 @@ protected function serialize_token(): string { } if ( null !== $doctype->public_identifier ) { - $quote = strpos( $doctype->public_identifier, '"' ) !== false ? "'" : '"'; - $html .= " PUBLIC {$quote}{$doctype->public_identifier}{$quote}"; + $quote = str_contains( $doctype->public_identifier, '"' ) ? "'" : '"'; + $html .= " PUBLIC {$quote}{$doctype->public_identifier}{$quote}"; } if ( null !== $doctype->system_identifier ) { if ( null === $doctype->public_identifier ) { $html .= ' SYSTEM'; } - $quote = strpos( $doctype->system_identifier, '"' ) !== false ? "'" : '"'; - $html .= " {$quote}{$doctype->system_identifier}{$quote}"; + $quote = str_contains( $doctype->system_identifier, '"' ) ? "'" : '"'; + $html .= " {$quote}{$doctype->system_identifier}{$quote}"; } $html .= '>'; @@ -1223,20 +1374,18 @@ protected function serialize_token(): string { if ( $this->is_tag_closer() ) { $html .= ""; - return $html; } $attribute_names = $this->get_attribute_names_with_prefix( '' ); if ( ! isset( $attribute_names ) ) { $html .= "<{$qualified_name}>"; - return $html; } $html .= "<{$qualified_name}"; foreach ( $attribute_names as $attribute_name ) { - $html .= " {$this->get_qualified_attribute_name( $attribute_name )}"; + $html .= " {$this->get_qualified_attribute_name( $attribute_name )}"; $value = $this->get_attribute( $attribute_name ); if ( is_string( $value ) ) { @@ -1253,8 +1402,7 @@ protected function serialize_token(): string { $html .= '>'; // Flush out self-contained elements. - if ( $in_html && in_array( $tag_name, array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), - true ) ) { + if ( $in_html && in_array( $tag_name, array( 'IFRAME', 'NOEMBED', 'NOFRAMES', 'SCRIPT', 'STYLE', 'TEXTAREA', 'TITLE', 'XMP' ), true ) ) { $text = $this->get_modifiable_text(); switch ( $tag_name ) { @@ -1284,14 +1432,14 @@ protected function serialize_token(): string { * This internal function performs the 'initial' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#the-initial-insertion-mode * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_initial(): bool { $token_name = $this->get_token_name(); @@ -1321,7 +1469,6 @@ private function step_initial(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1338,7 +1485,6 @@ private function step_initial(): bool { */ $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_BEFORE_HTML; $this->insert_html_element( $this->state->current_token ); - return true; } @@ -1348,7 +1494,6 @@ private function step_initial(): bool { initial_anything_else: $this->compat_mode = WP_HTML_Tag_Processor::QUIRKS_MODE; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_BEFORE_HTML; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -1358,14 +1503,14 @@ private function step_initial(): bool { * This internal function performs the 'before html' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#the-before-html-insertion-mode * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_before_html(): bool { $token_name = $this->get_token_name(); @@ -1389,7 +1534,6 @@ private function step_before_html(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1412,7 +1556,6 @@ private function step_before_html(): bool { case '+HTML': $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_BEFORE_HEAD; - return true; /* @@ -1448,7 +1591,6 @@ private function step_before_html(): bool { before_html_anything_else: $this->insert_virtual_node( 'HTML' ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_BEFORE_HEAD; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -1458,14 +1600,14 @@ private function step_before_html(): bool { * This internal function performs the 'before head' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#the-before-head-insertion-mode * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_before_head(): bool { $token_name = $this->get_token_name(); @@ -1496,7 +1638,6 @@ private function step_before_head(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1519,7 +1660,6 @@ private function step_before_head(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->head_element = $this->state->current_token; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD; - return true; /* @@ -1548,7 +1688,6 @@ private function step_before_head(): bool { before_head_anything_else: $this->state->head_element = $this->insert_virtual_node( 'HEAD' ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -1558,14 +1697,14 @@ private function step_before_head(): bool { * This internal function performs the 'in head' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inhead * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_head(): bool { $token_name = $this->get_token_name(); @@ -1584,7 +1723,6 @@ private function step_in_head(): bool { if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) { // Insert the character. $this->insert_html_element( $this->state->current_token ); - return true; } @@ -1598,7 +1736,6 @@ private function step_in_head(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1622,7 +1759,6 @@ private function step_in_head(): bool { case '+BGSOUND': case '+LINK': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1668,7 +1804,6 @@ private function step_in_head(): bool { */ case '+TITLE': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1680,7 +1815,6 @@ private function step_in_head(): bool { case '+NOFRAMES': case '+STYLE': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1689,7 +1823,6 @@ private function step_in_head(): bool { case '+NOSCRIPT': $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD_NOSCRIPT; - return true; /* @@ -1699,7 +1832,6 @@ private function step_in_head(): bool { */ case '+SCRIPT': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1708,7 +1840,6 @@ private function step_in_head(): bool { case '-HEAD': $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_HEAD; - return true; /* @@ -1737,7 +1868,6 @@ private function step_in_head(): bool { $this->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_TEMPLATE; $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1758,7 +1888,6 @@ private function step_in_head(): bool { $this->state->active_formatting_elements->clear_up_to_last_marker(); array_pop( $this->state->stack_of_template_insertion_modes ); $this->reset_insertion_mode_appropriately(); - return true; } @@ -1777,7 +1906,6 @@ private function step_in_head(): bool { in_head_anything_else: $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_HEAD; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -1787,14 +1915,14 @@ private function step_in_head(): bool { * This internal function performs the 'in head noscript' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-inheadnoscript * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_in_head_noscript(): bool { $token_name = $this->get_token_name(); @@ -1838,7 +1966,6 @@ private function step_in_head_noscript(): bool { case '-NOSCRIPT': $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD; - return true; /* @@ -1857,6 +1984,7 @@ private function step_in_head_noscript(): bool { case '+NOFRAMES': case '+STYLE': return $this->step_in_head(); + /* * > An end tag whose tag name is "br" * @@ -1881,7 +2009,6 @@ private function step_in_head_noscript(): bool { in_head_noscript_anything_else: $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -1891,14 +2018,14 @@ private function step_in_head_noscript(): bool { * This internal function performs the 'after head' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#the-after-head-insertion-mode * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_after_head(): bool { $token_name = $this->get_token_name(); @@ -1917,7 +2044,6 @@ private function step_after_head(): bool { if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) { // Insert the character. $this->insert_html_element( $this->state->current_token ); - return true; } goto after_head_anything_else; @@ -1930,7 +2056,6 @@ private function step_after_head(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -1953,7 +2078,6 @@ private function step_after_head(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->frameset_ok = false; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - return true; /* @@ -1962,7 +2086,6 @@ private function step_after_head(): bool { case '+FRAMESET': $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_FRAMESET; - return true; /* @@ -2030,7 +2153,6 @@ private function step_after_head(): bool { after_head_anything_else: $this->insert_virtual_node( 'BODY' ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -2040,14 +2162,14 @@ private function step_after_head(): bool { * This internal function performs the 'in body' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.4.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-inbody * @see WP_HTML_Processor::step * - * @since 6.4.0 - * + * @return bool Whether an element was found. */ private function step_in_body(): bool { $token_name = $this->get_token_name(); @@ -2083,14 +2205,12 @@ private function step_in_body(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; case '#comment': case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2160,7 +2280,6 @@ private function step_in_body(): bool { * This parser does not currently support this behavior: ignore the token. */ $this->state->frameset_ok = false; - return $this->step(); /* @@ -2204,8 +2323,14 @@ private function step_in_body(): bool { */ $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_BODY; - - return true; + /* + * The BODY element is not removed from the stack of open elements. + * Only internal state has changed, this does not qualify as a "step" + * in terms of advancing through the document to another token. + * Nothing has been pushed or popped. + * Proceed to parse the next item. + */ + return $this->step(); /* * > An end tag whose tag name is "html" @@ -2227,7 +2352,6 @@ private function step_in_body(): bool { */ $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -2266,7 +2390,6 @@ private function step_in_body(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2294,7 +2417,6 @@ private function step_in_body(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2316,7 +2438,6 @@ private function step_in_body(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->frameset_ok = false; - return true; /* @@ -2397,7 +2518,6 @@ private function step_in_body(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; case '+PLAINTEXT': @@ -2473,7 +2593,6 @@ private function step_in_body(): bool { // @todo Record parse error: this error doesn't impact parsing. } $this->state->stack_of_open_elements->pop_until( $token_name ); - return true; /* @@ -2506,7 +2625,6 @@ private function step_in_body(): bool { } $this->state->stack_of_open_elements->remove_node( $node ); - return true; } else { /* @@ -2527,7 +2645,6 @@ private function step_in_body(): bool { } $this->state->stack_of_open_elements->pop_until( 'FORM' ); - return true; } break; @@ -2541,7 +2658,6 @@ private function step_in_body(): bool { } $this->close_a_p_element(); - return true; /* @@ -2587,7 +2703,6 @@ private function step_in_body(): bool { } $this->state->stack_of_open_elements->pop_until( $token_name ); - return true; /* @@ -2615,7 +2730,6 @@ private function step_in_body(): bool { } $this->state->stack_of_open_elements->pop_until( '(internal: H1 through H6 - do not use)' ); - return true; /* @@ -2638,7 +2752,6 @@ private function step_in_body(): bool { $this->reconstruct_active_formatting_elements(); $this->insert_html_element( $this->state->current_token ); $this->state->active_formatting_elements->push( $this->state->current_token ); - return true; /* @@ -2660,7 +2773,6 @@ private function step_in_body(): bool { $this->reconstruct_active_formatting_elements(); $this->insert_html_element( $this->state->current_token ); $this->state->active_formatting_elements->push( $this->state->current_token ); - return true; /* @@ -2677,7 +2789,6 @@ private function step_in_body(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->active_formatting_elements->push( $this->state->current_token ); - return true; /* @@ -2699,7 +2810,6 @@ private function step_in_body(): bool { case '-TT': case '-U': $this->run_adoption_agency_algorithm(); - return true; /* @@ -2712,7 +2822,6 @@ private function step_in_body(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->active_formatting_elements->insert_marker(); $this->state->frameset_ok = false; - return true; /* @@ -2733,7 +2842,6 @@ private function step_in_body(): bool { $this->state->stack_of_open_elements->pop_until( $token_name ); $this->state->active_formatting_elements->clear_up_to_last_marker(); - return true; /* @@ -2754,7 +2862,6 @@ private function step_in_body(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->frameset_ok = false; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; - return true; /* @@ -2776,7 +2883,6 @@ private function step_in_body(): bool { $this->reconstruct_active_formatting_elements(); $this->insert_html_element( $this->state->current_token ); $this->state->frameset_ok = false; - return true; /* @@ -2805,7 +2911,6 @@ private function step_in_body(): bool { case '+SOURCE': case '+TRACK': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2817,7 +2922,6 @@ private function step_in_body(): bool { } $this->insert_html_element( $this->state->current_token ); $this->state->frameset_ok = false; - return true; /* @@ -2853,7 +2957,6 @@ private function step_in_body(): bool { * * As a self-contained node, this behavior is handled in the Tag Processor. */ - return true; /* @@ -2873,7 +2976,6 @@ private function step_in_body(): bool { * As a self-contained node, this behavior is handled in the Tag Processor. */ $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2888,7 +2990,6 @@ private function step_in_body(): bool { * As a self-contained node, this behavior is handled in the Tag Processor. */ $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2899,7 +3000,6 @@ private function step_in_body(): bool { */ case '+NOEMBED': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2930,7 +3030,6 @@ private function step_in_body(): bool { $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT; break; } - return true; /* @@ -2943,7 +3042,6 @@ private function step_in_body(): bool { } $this->reconstruct_active_formatting_elements(); $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2960,7 +3058,6 @@ private function step_in_body(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2978,7 +3075,6 @@ private function step_in_body(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -2998,7 +3094,6 @@ private function step_in_body(): bool { if ( $this->state->current_token->has_self_closing_flag ) { $this->state->stack_of_open_elements->pop(); } - return true; /* @@ -3018,7 +3113,6 @@ private function step_in_body(): bool { if ( $this->state->current_token->has_self_closing_flag ) { $this->state->stack_of_open_elements->pop(); } - return true; /* @@ -3046,7 +3140,6 @@ private function step_in_body(): bool { */ $this->reconstruct_active_formatting_elements(); $this->insert_html_element( $this->state->current_token ); - return true; } else { /* @@ -3084,7 +3177,6 @@ private function step_in_body(): bool { } $this->bail( 'Should not have been able to reach end of IN BODY processing. Check HTML API code.' ); - // This unnecessary return prevents tools from inaccurately reporting type errors. return false; } @@ -3095,14 +3187,14 @@ private function step_in_body(): bool { * This internal function performs the 'in table' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-intable * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_table(): bool { $token_name = $this->get_token_name(); @@ -3157,7 +3249,6 @@ private function step_in_table(): bool { */ if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) { $this->insert_html_element( $this->state->current_token ); - return true; } @@ -3174,7 +3265,6 @@ private function step_in_table(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -3192,7 +3282,6 @@ private function step_in_table(): bool { $this->state->active_formatting_elements->insert_marker(); $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_CAPTION; - return true; /* @@ -3202,7 +3291,6 @@ private function step_in_table(): bool { $this->state->stack_of_open_elements->clear_to_table_context(); $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP; - return true; /* @@ -3217,7 +3305,6 @@ private function step_in_table(): bool { */ $this->insert_virtual_node( 'COLGROUP' ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3229,7 +3316,6 @@ private function step_in_table(): bool { $this->state->stack_of_open_elements->clear_to_table_context(); $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; - return true; /* @@ -3245,7 +3331,6 @@ private function step_in_table(): bool { */ $this->insert_virtual_node( 'TBODY' ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3260,7 +3345,6 @@ private function step_in_table(): bool { $this->state->stack_of_open_elements->pop_until( 'TABLE' ); $this->reset_insertion_mode_appropriately(); - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3274,7 +3358,6 @@ private function step_in_table(): bool { $this->state->stack_of_open_elements->pop_until( 'TABLE' ); $this->reset_insertion_mode_appropriately(); - return true; /* @@ -3321,7 +3404,6 @@ private function step_in_table(): bool { } // @todo Indicate a parse error once it's possible. $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -3341,7 +3423,6 @@ private function step_in_table(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->form_element = $this->state->current_token; $this->state->stack_of_open_elements->pop(); - return true; } @@ -3362,14 +3443,14 @@ private function step_in_table(): bool { * This internal function performs the 'in table text' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-intabletext * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_in_table_text(): bool { $this->bail( 'No support for parsing in the ' . WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_TEXT . ' state.' ); @@ -3381,14 +3462,14 @@ private function step_in_table_text(): bool { * This internal function performs the 'in caption' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-incaption * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_caption(): bool { $tag_name = $this->get_tag(); @@ -3433,7 +3514,6 @@ private function step_in_caption(): bool { if ( '-CAPTION' === $op ) { return true; } - return $this->step( self::REPROCESS_CURRENT_NODE ); /** @@ -3466,14 +3546,14 @@ private function step_in_caption(): bool { * This internal function performs the 'in column group' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-incolgroup * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_column_group(): bool { $token_name = $this->get_token_name(); @@ -3490,7 +3570,6 @@ private function step_in_column_group(): bool { if ( parent::TEXT_IS_WHITESPACE === $this->text_node_classification ) { // Insert the character. $this->insert_html_element( $this->state->current_token ); - return true; } @@ -3504,7 +3583,6 @@ private function step_in_column_group(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -3526,7 +3604,6 @@ private function step_in_column_group(): bool { case '+COL': $this->insert_html_element( $this->state->current_token ); $this->state->stack_of_open_elements->pop(); - return true; /* @@ -3539,7 +3616,6 @@ private function step_in_column_group(): bool { } $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; - return true; /* @@ -3568,7 +3644,6 @@ private function step_in_column_group(): bool { } $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -3578,14 +3653,14 @@ private function step_in_column_group(): bool { * This internal function performs the 'in table body' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-intbody * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_table_body(): bool { $tag_name = $this->get_tag(); @@ -3600,7 +3675,6 @@ private function step_in_table_body(): bool { $this->state->stack_of_open_elements->clear_to_table_body_context(); $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW; - return true; /* @@ -3612,7 +3686,6 @@ private function step_in_table_body(): bool { $this->state->stack_of_open_elements->clear_to_table_body_context(); $this->insert_virtual_node( 'TR' ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3629,7 +3702,6 @@ private function step_in_table_body(): bool { $this->state->stack_of_open_elements->clear_to_table_body_context(); $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; - return true; /* @@ -3654,7 +3726,6 @@ private function step_in_table_body(): bool { $this->state->stack_of_open_elements->clear_to_table_body_context(); $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3676,7 +3747,6 @@ private function step_in_table_body(): bool { * > Anything else * > Process the token using the rules for the "in table" insertion mode. */ - return $this->step_in_table(); } @@ -3686,14 +3756,14 @@ private function step_in_table_body(): bool { * This internal function performs the 'in row' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-intr * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_row(): bool { $tag_name = $this->get_tag(); @@ -3710,7 +3780,6 @@ private function step_in_row(): bool { $this->insert_html_element( $this->state->current_token ); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_CELL; $this->state->active_formatting_elements->insert_marker(); - return true; /* @@ -3725,7 +3794,6 @@ private function step_in_row(): bool { $this->state->stack_of_open_elements->clear_to_table_row_context(); $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; - return true; /* @@ -3748,7 +3816,6 @@ private function step_in_row(): bool { $this->state->stack_of_open_elements->clear_to_table_row_context(); $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3770,7 +3837,6 @@ private function step_in_row(): bool { $this->state->stack_of_open_elements->clear_to_table_row_context(); $this->state->stack_of_open_elements->pop(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3791,7 +3857,6 @@ private function step_in_row(): bool { * > Anything else * > Process the token using the rules for the "in table" insertion mode. */ - return $this->step_in_table(); } @@ -3801,14 +3866,14 @@ private function step_in_row(): bool { * This internal function performs the 'in cell' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-intd * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_cell(): bool { $tag_name = $this->get_tag(); @@ -3841,7 +3906,6 @@ private function step_in_cell(): bool { $this->state->stack_of_open_elements->pop_until( $tag_name ); $this->state->active_formatting_elements->clear_up_to_last_marker(); $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW; - return true; /* @@ -3864,7 +3928,6 @@ private function step_in_cell(): bool { */ $this->close_cell(); - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -3891,7 +3954,6 @@ private function step_in_cell(): bool { return $this->step(); } $this->close_cell(); - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -3899,7 +3961,6 @@ private function step_in_cell(): bool { * > Anything else * > Process the token using the rules for the "in body" insertion mode. */ - return $this->step_in_body(); } @@ -3909,14 +3970,14 @@ private function step_in_cell(): bool { * This internal function performs the 'in select' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inselect * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_select(): bool { $token_name = $this->get_token_name(); @@ -3941,7 +4002,6 @@ private function step_in_select(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -3951,7 +4011,6 @@ private function step_in_select(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -3975,7 +4034,6 @@ private function step_in_select(): bool { $this->state->stack_of_open_elements->pop(); } $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -3996,7 +4054,6 @@ private function step_in_select(): bool { } $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -4015,7 +4072,6 @@ private function step_in_select(): bool { if ( $this->state->stack_of_open_elements->current_node_is( 'OPTGROUP' ) ) { $this->state->stack_of_open_elements->pop(); - return true; } @@ -4028,7 +4084,6 @@ private function step_in_select(): bool { case '-OPTION': if ( $this->state->stack_of_open_elements->current_node_is( 'OPTION' ) ) { $this->state->stack_of_open_elements->pop(); - return true; } @@ -4049,7 +4104,6 @@ private function step_in_select(): bool { } $this->state->stack_of_open_elements->pop_until( 'SELECT' ); $this->reset_insertion_mode_appropriately(); - return true; /* @@ -4066,7 +4120,6 @@ private function step_in_select(): bool { } $this->state->stack_of_open_elements->pop_until( 'SELECT' ); $this->reset_insertion_mode_appropriately(); - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -4083,7 +4136,6 @@ private function step_in_select(): bool { * > Anything else * > Parse error: ignore the token. */ - return $this->step(); } @@ -4093,14 +4145,14 @@ private function step_in_select(): bool { * This internal function performs the 'in select in table' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-inselectintable * @see WP_HTML_Processor::step * - * @since 6.7.0 - * + * @return bool Whether an element was found. */ private function step_in_select_in_table(): bool { $token_name = $this->get_token_name(); @@ -4123,7 +4175,6 @@ private function step_in_select_in_table(): bool { // @todo Indicate a parse error once it's possible. $this->state->stack_of_open_elements->pop_until( 'SELECT' ); $this->reset_insertion_mode_appropriately(); - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -4143,14 +4194,12 @@ private function step_in_select_in_table(): bool { } $this->state->stack_of_open_elements->pop_until( 'SELECT' ); $this->reset_insertion_mode_appropriately(); - return $this->step( self::REPROCESS_CURRENT_NODE ); } /* * > Anything else */ - return $this->step_in_select(); } @@ -4160,14 +4209,14 @@ private function step_in_select_in_table(): bool { * This internal function performs the 'in template' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-intemplate * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_in_template(): bool { $token_name = $this->get_token_name(); @@ -4218,7 +4267,6 @@ private function step_in_template(): bool { array_pop( $this->state->stack_of_template_insertion_modes ); $this->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -4228,7 +4276,6 @@ private function step_in_template(): bool { array_pop( $this->state->stack_of_template_insertion_modes ); $this->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -4238,7 +4285,6 @@ private function step_in_template(): bool { array_pop( $this->state->stack_of_template_insertion_modes ); $this->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); /* @@ -4249,7 +4295,6 @@ private function step_in_template(): bool { array_pop( $this->state->stack_of_template_insertion_modes ); $this->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -4260,7 +4305,6 @@ private function step_in_template(): bool { array_pop( $this->state->stack_of_template_insertion_modes ); $this->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -4285,7 +4329,6 @@ private function step_in_template(): bool { $this->state->active_formatting_elements->clear_up_to_last_marker(); array_pop( $this->state->stack_of_template_insertion_modes ); $this->reset_insertion_mode_appropriately(); - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -4295,14 +4338,14 @@ private function step_in_template(): bool { * This internal function performs the 'after body' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-afterbody * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_after_body(): bool { $tag_name = $this->get_token_name(); @@ -4360,8 +4403,14 @@ private function step_after_body(): bool { } $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_AFTER_BODY; - - return true; + /* + * The HTML element is not removed from the stack of open elements. + * Only internal state has changed, this does not qualify as a "step" + * in terms of advancing through the document to another token. + * Nothing has been pushed or popped. + * Proceed to parse the next item. + */ + return $this->step(); } /* @@ -4369,7 +4418,6 @@ private function step_after_body(): bool { */ after_body_anything_else: $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -4379,14 +4427,14 @@ private function step_after_body(): bool { * This internal function performs the 'in frameset' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-inframeset * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_in_frameset(): bool { $tag_name = $this->get_token_name(); @@ -4418,7 +4466,6 @@ private function step_in_frameset(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -4439,7 +4486,6 @@ private function step_in_frameset(): bool { */ case '+FRAMESET': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -4481,7 +4527,6 @@ private function step_in_frameset(): bool { case '+FRAME': $this->insert_html_element( $this->state->current_token ); $this->state->stack_of_open_elements->pop(); - return true; /* @@ -4501,14 +4546,14 @@ private function step_in_frameset(): bool { * This internal function performs the 'after frameset' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-afterframeset * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_after_frameset(): bool { $tag_name = $this->get_token_name(); @@ -4540,7 +4585,6 @@ private function step_after_frameset(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_html_element( $this->state->current_token ); - return true; /* @@ -4561,8 +4605,14 @@ private function step_after_frameset(): bool { */ case '-HTML': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_AFTER_AFTER_FRAMESET; - - return true; + /* + * The HTML element is not removed from the stack of open elements. + * Only internal state has changed, this does not qualify as a "step" + * in terms of advancing through the document to another token. + * Nothing has been pushed or popped. + * Proceed to parse the next item. + */ + return $this->step(); /* * > A start tag whose tag name is "noframes" @@ -4581,14 +4631,14 @@ private function step_after_frameset(): bool { * This internal function performs the 'after after body' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#the-after-after-body-insertion-mode * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_after_after_body(): bool { $tag_name = $this->get_token_name(); @@ -4635,7 +4685,6 @@ private function step_after_after_body(): bool { */ after_after_body_anything_else: $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - return $this->step( self::REPROCESS_CURRENT_NODE ); } @@ -4645,14 +4694,14 @@ private function step_after_after_body(): bool { * This internal function performs the 'after after frameset' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#the-after-after-frameset-insertion-mode * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_after_after_frameset(): bool { $tag_name = $this->get_token_name(); @@ -4713,14 +4762,14 @@ private function step_after_after_frameset(): bool { * This internal function performs the 'in foreign content' insertion mode * logic for the generalized WP_HTML_Processor::step() function. * - * @return bool Whether an element was found. + * @since 6.7.0 Stub implementation. + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#parsing-main-inforeign * @see WP_HTML_Processor::step * - * @since 6.7.0 Stub implementation. - * + * @return bool Whether an element was found. */ private function step_in_foreign_content(): bool { $tag_name = $this->get_token_name(); @@ -4763,7 +4812,6 @@ private function step_in_foreign_content(): bool { } $this->insert_foreign_element( $this->state->current_token, false ); - return true; /* @@ -4782,7 +4830,6 @@ private function step_in_foreign_content(): bool { } $this->insert_foreign_element( $this->state->current_token, false ); - return true; /* @@ -4792,7 +4839,6 @@ private function step_in_foreign_content(): bool { case '#funky-comment': case '#presumptuous-tag': $this->insert_foreign_element( $this->state->current_token, false ); - return true; /* @@ -4903,7 +4949,6 @@ private function step_in_foreign_content(): bool { if ( $this->state->current_token->has_self_closing_flag ) { $this->state->stack_of_open_elements->pop(); } - return true; } @@ -4912,7 +4957,6 @@ private function step_in_foreign_content(): bool { */ if ( $this->is_tag_closer() && 'SCRIPT' === $this->state->current_token->node_name && 'svg' === $this->state->current_token->namespace ) { $this->state->stack_of_open_elements->pop(); - return true; } @@ -5027,7 +5071,6 @@ private function step_in_foreign_content(): bool { } $this->bail( 'Should not have been able to reach end of IN FOREIGN CONTENT processing. Check HTML API code.' ); - // This unnecessary return prevents tools from inaccurately reporting type errors. return false; } @@ -5039,15 +5082,15 @@ private function step_in_foreign_content(): bool { /** * Creates a new bookmark for the currently-matched token and returns the generated name. * - * @return string|false Name of created bookmark, or false if unable to create. - * @throws Exception When unable to allocate requested bookmark. - * * @since 6.4.0 * @since 6.5.0 Renamed from bookmark_tag() to bookmark_token(). * + * @throws Exception When unable to allocate requested bookmark. + * + * @return string|false Name of created bookmark, or false if unable to create. */ private function bookmark_token() { - if ( ! parent::set_bookmark( ++ $this->bookmark_counter ) ) { + if ( ! parent::set_bookmark( ++$this->bookmark_counter ) ) { $this->last_error = self::ERROR_EXCEEDED_MAX_BOOKMARKS; throw new Exception( 'could not allocate bookmark' ); } @@ -5089,9 +5132,9 @@ public function get_namespace(): string { * $processor->next_tag() === false; * $processor->get_tag() === null; * - * @return string|null Name of currently matched tag in input HTML, or `null` if none found. * @since 6.4.0 * + * @return string|null Name of currently matched tag in input HTML, or `null` if none found. */ public function get_tag(): ?string { if ( null !== $this->last_error ) { @@ -5108,7 +5151,6 @@ public function get_tag(): ?string { * > A start tag whose tag name is "image" * > Change the token's tag name to "img" and reprocess it. (Don't ask.) */ - return ( 'IMAGE' === $tag_name && 'html' === $this->get_namespace() ) ? 'IMG' : $tag_name; @@ -5127,9 +5169,9 @@ public function get_tag(): ?string { * This function does not determine if a tag is self-closing, * but only if the self-closing flag is present in the syntax. * - * @return bool Whether the currently matched tag contains the self-closing flag. * @since 6.6.0 Subclassed for the HTML Processor. * + * @return bool Whether the currently matched tag contains the self-closing flag. */ public function has_self_closing_flag(): bool { return $this->is_virtual() ? false : parent::has_self_closing_flag(); @@ -5151,9 +5193,9 @@ public function has_self_closing_flag(): bool { * hasn't yet found a token or because it reached the end * of the document without matching a token. * - * @return string|null Name of the matched token. * @since 6.6.0 Subclassed for the HTML Processor. * + * @return string|null Name of the matched token. */ public function get_token_name(): ?string { return $this->is_virtual() @@ -5179,9 +5221,9 @@ public function get_token_name(): ?string { * - `#presumptuous-tag` when matched on an empty tag closer. * - `#funky-comment` when matched on a funky comment. * - * @return string|null What kind of token is matched, or null. * @since 6.6.0 Subclassed for the HTML Processor. * + * @return string|null What kind of token is matched, or null. */ public function get_token_type(): ?string { if ( $this->is_virtual() ) { @@ -5221,11 +5263,10 @@ public function get_token_type(): ?string { * $p->next_tag() === false; * $p->get_attribute( 'class' ) === null; * - * @param string $name Name of attribute whose value is requested. - * - * @return string|true|null Value of attribute or `null` if not available. Boolean attributes return `true`. * @since 6.6.0 Subclassed for HTML Processor. * + * @param string $name Name of attribute whose value is requested. + * @return string|true|null Value of attribute or `null` if not available. Boolean attributes return `true`. */ public function get_attribute( $name ) { return $this->is_virtual() ? null : parent::get_attribute( $name ); @@ -5240,12 +5281,11 @@ public function get_attribute( $name ) { * * For string attributes, the value is escaped using the `esc_attr` function. * - * @param string $name The attribute name to target. - * @param string|bool $value The new attribute value. - * - * @return bool Whether an attribute value was set. * @since 6.6.0 Subclassed for the HTML Processor. * + * @param string $name The attribute name to target. + * @param string|bool $value The new attribute value. + * @return bool Whether an attribute value was set. */ public function set_attribute( $name, $value ): bool { return $this->is_virtual() ? false : parent::set_attribute( $name, $value ); @@ -5254,11 +5294,10 @@ public function set_attribute( $name, $value ): bool { /** * Remove an attribute from the currently-matched tag. * - * @param string $name The attribute name to remove. - * - * @return bool Whether an attribute was removed. * @since 6.6.0 Subclassed for HTML Processor. * + * @param string $name The attribute name to remove. + * @return bool Whether an attribute was removed. */ public function remove_attribute( $name ): bool { return $this->is_virtual() ? false : parent::remove_attribute( $name ); @@ -5283,13 +5322,12 @@ public function remove_attribute( $name ): bool { * $p->next_tag() === false; * $p->get_attribute_names_with_prefix( 'data-' ) === null; * - * @param string $prefix Prefix of requested attribute names. - * - * @return array|null List of attribute names, or `null` when no tag opener is matched. * @since 6.6.0 Subclassed for the HTML Processor. * * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2:ascii-case-insensitive * + * @param string $prefix Prefix of requested attribute names. + * @return array|null List of attribute names, or `null` when no tag opener is matched. */ public function get_attribute_names_with_prefix( $prefix ): ?array { return $this->is_virtual() ? null : parent::get_attribute_names_with_prefix( $prefix ); @@ -5298,11 +5336,10 @@ public function get_attribute_names_with_prefix( $prefix ): ?array { /** * Adds a new class name to the currently matched tag. * - * @param string $class_name The class name to add. - * - * @return bool Whether the class was set to be added. * @since 6.6.0 Subclassed for the HTML Processor. * + * @param string $class_name The class name to add. + * @return bool Whether the class was set to be added. */ public function add_class( $class_name ): bool { return $this->is_virtual() ? false : parent::add_class( $class_name ); @@ -5311,11 +5348,10 @@ public function add_class( $class_name ): bool { /** * Removes a class name from the currently matched tag. * - * @param string $class_name The class name to remove. - * - * @return bool Whether the class was set to be removed. * @since 6.6.0 Subclassed for the HTML Processor. * + * @param string $class_name The class name to remove. + * @return bool Whether the class was set to be removed. */ public function remove_class( $class_name ): bool { return $this->is_virtual() ? false : parent::remove_class( $class_name ); @@ -5324,15 +5360,14 @@ public function remove_class( $class_name ): bool { /** * Returns if a matched tag contains the given ASCII case-insensitive class name. * - * @param string $wanted_class Look for this CSS class name, ASCII case-insensitive. - * - * @return bool|null Whether the matched tag contains the given class name, or null if not matched. * @since 6.6.0 Subclassed for the HTML Processor. * * @todo When reconstructing active formatting elements with attributes, find a way * to indicate if the virtually-reconstructed formatting elements contain the * wanted class name. * + * @param string $wanted_class Look for this CSS class name, ASCII case-insensitive. + * @return bool|null Whether the matched tag contains the given class name, or null if not matched. */ public function has_class( $wanted_class ): ?bool { return $this->is_virtual() ? null : parent::has_class( $wanted_class ); @@ -5374,9 +5409,9 @@ public function class_list() { * that a token has modifiable text, and a token with modifiable text may * have an empty string (e.g. a comment with no contents). * - * @return string * @since 6.6.0 Subclassed for the HTML Processor. * + * @return string */ public function get_modifiable_text(): string { return $this->is_virtual() ? '' : parent::get_modifiable_text(); @@ -5391,7 +5426,7 @@ public function get_modifiable_text(): string { * they are commonly known, but a number of unrelated syntax errors * also produce comments. * - * @return string|null + * @see self::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT * @see self::COMMENT_AS_CDATA_LOOKALIKE * @see self::COMMENT_AS_INVALID_HTML * @see self::COMMENT_AS_HTML_COMMENT @@ -5399,7 +5434,7 @@ public function get_modifiable_text(): string { * * @since 6.6.0 Subclassed for the HTML Processor. * - * @see self::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT + * @return string|null */ public function get_comment_type(): ?string { return $this->is_virtual() ? null : parent::get_comment_type(); @@ -5411,11 +5446,10 @@ public function get_comment_type(): ?string { * Releasing a bookmark frees up the small * performance overhead it requires. * - * @param string $bookmark_name Name of the bookmark to remove. - * - * @return bool Whether the bookmark already existed before removal. * @since 6.4.0 * + * @param string $bookmark_name Name of the bookmark to remove. + * @return bool Whether the bookmark already existed before removal. */ public function release_bookmark( $bookmark_name ): bool { return parent::release_bookmark( "_{$bookmark_name}" ); @@ -5431,13 +5465,12 @@ public function release_bookmark( $bookmark_name ): bool { * In order to prevent accidental infinite loops, there's a * maximum limit on the number of times seek() can be called. * - * @param string $bookmark_name Jump to the place in the document identified by this bookmark name. - * - * @return bool Whether the internal cursor was successfully moved to the bookmark's location. * @throws Exception When unable to allocate a bookmark for the next token in the input HTML document. * * @since 6.4.0 * + * @param string $bookmark_name Jump to the place in the document identified by this bookmark name. + * @return bool Whether the internal cursor was successfully moved to the bookmark's location. */ public function seek( $bookmark_name ): bool { // Flush any pending updates to the document before beginning. @@ -5480,54 +5513,93 @@ public function seek( $bookmark_name ): bool { * and computation time. */ if ( 'backward' === $direction ) { + /* - * Instead of clearing the parser state and starting fresh, calling the stack methods - * maintains the proper flags in the parser. + * When moving backward, stateful stacks should be cleared. */ foreach ( $this->state->stack_of_open_elements->walk_up() as $item ) { - if ( 'context-node' === $item->bookmark_name ) { - break; - } - $this->state->stack_of_open_elements->remove_node( $item ); } foreach ( $this->state->active_formatting_elements->walk_up() as $item ) { - if ( 'context-node' === $item->bookmark_name ) { - break; - } - $this->state->active_formatting_elements->remove_node( $item ); } - parent::seek( 'context-node' ); - $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - $this->state->frameset_ok = true; - $this->element_queue = array(); - $this->current_element = null; + /* + * **After** clearing stacks, more processor state can be reset. + * This must be done after clearing the stack because those stacks generate events that + * would appear on a subsequent call to `next_token()`. + */ + $this->state->frameset_ok = true; + $this->state->stack_of_template_insertion_modes = array(); + $this->state->head_element = null; + $this->state->form_element = null; + $this->state->current_token = null; + $this->current_element = null; + $this->element_queue = array(); + + /* + * The absence of a context node indicates a full parse. + * The presence of a context node indicates a fragment parser. + */ + if ( null === $this->context_node ) { + $this->change_parsing_namespace( 'html' ); + $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_INITIAL; + $this->breadcrumbs = array(); - if ( isset( $this->context_node ) ) { - $this->breadcrumbs = array_slice( $this->breadcrumbs, 0, 2 ); + $this->bookmarks['initial'] = new WP_HTML_Span( 0, 0 ); + parent::seek( 'initial' ); + unset( $this->bookmarks['initial'] ); } else { - $this->breadcrumbs = array(); - } - } - // When moving forwards, reparse the document until reaching the same location as the original bookmark. - if ( $bookmark_starts_at === $this->bookmarks[ $this->state->current_token->bookmark_name ]->start ) { - return true; - } + /* + * Push the root-node (HTML) back onto the stack of open elements. + * + * Fragment parsers require this extra bit of setup. + * It's handled in full parsers by advancing the processor state. + */ + $this->state->stack_of_open_elements->push( + new WP_HTML_Token( + 'root-node', + 'HTML', + false + ) + ); - while ( $this->next_token() ) { - if ( $bookmark_starts_at === $this->bookmarks[ $this->state->current_token->bookmark_name ]->start ) { - while ( isset( $this->current_element ) && WP_HTML_Stack_Event::POP === $this->current_element->operation ) { - $this->current_element = array_shift( $this->element_queue ); + $this->change_parsing_namespace( + $this->context_node->integration_node_type + ? 'html' + : $this->context_node->namespace + ); + + if ( 'TEMPLATE' === $this->context_node->node_name ) { + $this->state->stack_of_template_insertion_modes[] = WP_HTML_Processor_State::INSERTION_MODE_IN_TEMPLATE; } - return true; + $this->reset_insertion_mode_appropriately(); + $this->breadcrumbs = array_slice( $this->breadcrumbs, 0, 2 ); + parent::seek( $this->context_node->bookmark_name ); } } + /* + * Here, the processor moves forward through the document until it matches the bookmark. + * do-while is used here because the processor is expected to already be stopped on + * a token than may match the bookmarked location. + */ + do { + /* + * The processor will stop on virtual tokens, but bookmarks may not be set on them. + * They should not be matched when seeking a bookmark, skip them. + */ + if ( $this->is_virtual() ) { + continue; + } + if ( $bookmark_starts_at === $this->bookmarks[ $this->state->current_token->bookmark_name ]->start ) { + return true; + } + } while ( $this->next_token() ); + return false; } @@ -5606,24 +5678,35 @@ public function seek( $bookmark_name ): bool { * reaching for it, as inappropriate use could lead to broken * HTML structure or unwanted processing overhead. * - * @param string $bookmark_name Identifies this particular bookmark. + * Bookmarks cannot be set on tokens that do no appear in the original + * HTML text. For example, the HTML `
` stops at tags `TABLE`, + * `TBODY`, `TR`, and `TD`. The `TBODY` and `TR` tags do not appear in + * the original HTML and cannot be used as bookmarks. * - * @return bool Whether the bookmark was successfully created. * @since 6.4.0 * + * @param string $bookmark_name Identifies this particular bookmark. + * @return bool Whether the bookmark was successfully created. */ public function set_bookmark( $bookmark_name ): bool { + if ( $this->is_virtual() ) { + _doing_it_wrong( + __METHOD__, + __( 'Cannot set bookmarks on tokens that do no appear in the original HTML text.' ), + '6.8.0' + ); + return false; + } return parent::set_bookmark( "_{$bookmark_name}" ); } /** * Checks whether a bookmark with the given name exists. * - * @param string $bookmark_name Name to identify a bookmark that potentially exists. - * - * @return bool Whether that bookmark exists. * @since 6.5.0 * + * @param string $bookmark_name Name to identify a bookmark that potentially exists. + * @return bool Whether that bookmark exists. */ public function has_bookmark( $bookmark_name ): bool { return parent::has_bookmark( "_{$bookmark_name}" ); @@ -5636,10 +5719,10 @@ public function has_bookmark( $bookmark_name ): bool { /** * Closes a P element. * - * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. - * * @since 6.4.0 * + * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. + * * @see https://html.spec.whatwg.org/#close-a-p-element */ private function close_a_p_element(): void { @@ -5650,13 +5733,12 @@ private function close_a_p_element(): void { /** * Closes elements that have implied end tags. * - * @param string|null $except_for_this_element Perform as if this element doesn't exist in the stack of open elements. - * + * @since 6.4.0 * @since 6.7.0 Full spec support. * * @see https://html.spec.whatwg.org/#generate-implied-end-tags * - * @since 6.4.0 + * @param string|null $except_for_this_element Perform as if this element doesn't exist in the stack of open elements. */ private function generate_implied_end_tags( ?string $except_for_this_element = null ): void { $elements_with_implied_end_tags = array( @@ -5750,13 +5832,13 @@ private function get_adjusted_current_node(): ?WP_HTML_Token { * > in the current body, cell, or caption (whichever is youngest) that haven't * > been explicitly closed. * - * @return bool Whether any formatting elements needed to be reconstructed. + * @since 6.4.0 + * * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. * * @see https://html.spec.whatwg.org/#reconstruct-the-active-formatting-elements * - * @since 6.4.0 - * + * @return bool Whether any formatting elements needed to be reconstructed. */ private function reconstruct_active_formatting_elements(): bool { /* @@ -5861,13 +5943,11 @@ private function reset_insertion_mode_appropriately(): void { */ case 'TABLE': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT_IN_TABLE; - return; } } } $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_SELECT; - return; /* @@ -5878,18 +5958,16 @@ private function reset_insertion_mode_appropriately(): void { case 'TH': if ( ! $last ) { $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_CELL; - return; } break; - /* - * > 6. If _node_ is a `tr` element, then switch the insertion mode to "in row" - * > and return. - */ + /* + * > 6. If _node_ is a `tr` element, then switch the insertion mode to "in row" + * > and return. + */ case 'TR': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_ROW; - return; /* @@ -5900,7 +5978,6 @@ private function reset_insertion_mode_appropriately(): void { case 'THEAD': case 'TFOOT': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE_BODY; - return; /* @@ -5909,7 +5986,6 @@ private function reset_insertion_mode_appropriately(): void { */ case 'CAPTION': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_CAPTION; - return; /* @@ -5918,7 +5994,6 @@ private function reset_insertion_mode_appropriately(): void { */ case 'COLGROUP': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_COLUMN_GROUP; - return; /* @@ -5927,7 +6002,6 @@ private function reset_insertion_mode_appropriately(): void { */ case 'TABLE': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_TABLE; - return; /* @@ -5936,7 +6010,6 @@ private function reset_insertion_mode_appropriately(): void { */ case 'TEMPLATE': $this->state->insertion_mode = end( $this->state->stack_of_template_insertion_modes ); - return; /* @@ -5946,7 +6019,6 @@ private function reset_insertion_mode_appropriately(): void { case 'HEAD': if ( ! $last ) { $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_HEAD; - return; } break; @@ -5957,7 +6029,6 @@ private function reset_insertion_mode_appropriately(): void { */ case 'BODY': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_BODY; - return; /* @@ -5966,7 +6037,6 @@ private function reset_insertion_mode_appropriately(): void { */ case 'FRAMESET': $this->state->insertion_mode = WP_HTML_Processor_State::INSERTION_MODE_IN_FRAMESET; - return; /* @@ -5980,7 +6050,6 @@ private function reset_insertion_mode_appropriately(): void { $this->state->insertion_mode = isset( $this->state->head_element ) ? WP_HTML_Processor_State::INSERTION_MODE_AFTER_HEAD : WP_HTML_Processor_State::INSERTION_MODE_BEFORE_HEAD; - return; } } @@ -5997,10 +6066,10 @@ private function reset_insertion_mode_appropriately(): void { /** * Runs the adoption agency algorithm. * - * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. - * * @since 6.4.0 * + * @throws WP_HTML_Unsupported_Exception When encountering unsupported HTML input. + * * @see https://html.spec.whatwg.org/#adoption-agency-algorithm */ private function run_adoption_agency_algorithm(): void { @@ -6015,13 +6084,12 @@ private function run_adoption_agency_algorithm(): void { ! $this->state->active_formatting_elements->contains_node( $current_node ) ) { $this->state->stack_of_open_elements->pop(); - return; } $outer_loop_counter = 0; - while ( $budget -- > 0 ) { - if ( $outer_loop_counter ++ >= 8 ) { + while ( $budget-- > 0 ) { + if ( $outer_loop_counter++ >= 8 ) { return; } @@ -6051,7 +6119,6 @@ private function run_adoption_agency_algorithm(): void { // > If formatting element is not in the stack of open elements, then this is a parse error; remove the element from the list, and return. if ( ! $this->state->stack_of_open_elements->contains_node( $formatting_element ) ) { $this->state->active_formatting_elements->remove_node( $formatting_element ); - return; } @@ -6093,7 +6160,6 @@ private function run_adoption_agency_algorithm(): void { if ( $formatting_element->bookmark_name === $item->bookmark_name ) { $this->state->active_formatting_elements->remove_node( $formatting_element ); - return; } } @@ -6135,12 +6201,11 @@ private function close_cell(): void { /** * Inserts an HTML element on the stack of open elements. * - * @param WP_HTML_Token $token Name of bookmark pointing to element in original input HTML. + * @since 6.4.0 * * @see https://html.spec.whatwg.org/#insert-a-foreign-element * - * @since 6.4.0 - * + * @param WP_HTML_Token $token Name of bookmark pointing to element in original input HTML. */ private function insert_html_element( WP_HTML_Token $token ): void { $this->state->stack_of_open_elements->push( $token ); @@ -6149,15 +6214,14 @@ private function insert_html_element( WP_HTML_Token $token ): void { /** * Inserts a foreign element on to the stack of open elements. * - * @param WP_HTML_Token $token Insert this token. The token's namespace and - * insertion point will be updated correctly. - * @param bool $only_add_to_element_stack Whether to skip the "insert an element at the adjusted - * insertion location" algorithm when adding this element. - * * @since 6.7.0 * * @see https://html.spec.whatwg.org/#insert-a-foreign-element * + * @param WP_HTML_Token $token Insert this token. The token's namespace and + * insertion point will be updated correctly. + * @param bool $only_add_to_element_stack Whether to skip the "insert an element at the adjusted + * insertion location" algorithm when adding this element. */ private function insert_foreign_element( WP_HTML_Token $token, bool $only_add_to_element_stack ): void { $adjusted_current_node = $this->get_adjusted_current_node(); @@ -6189,13 +6253,12 @@ private function insert_foreign_element( WP_HTML_Token $token, bool $only_add_to /** * Inserts a virtual element on the stack of open elements. * - * @param string $token_name Name of token to create and insert into the stack of open elements. - * @param string|null $bookmark_name Optional. Name to give bookmark for created virtual node. - * Defaults to auto-creating a bookmark name. - * - * @return WP_HTML_Token Newly-created virtual token. * @since 6.7.0 * + * @param string $token_name Name of token to create and insert into the stack of open elements. + * @param string|null $bookmark_name Optional. Name to give bookmark for created virtual node. + * Defaults to auto-creating a bookmark name. + * @return WP_HTML_Token Newly-created virtual token. */ private function insert_virtual_node( $token_name, $bookmark_name = null ): WP_HTML_Token { $here = $this->bookmarks[ $this->state->current_token->bookmark_name ]; @@ -6205,7 +6268,6 @@ private function insert_virtual_node( $token_name, $bookmark_name = null ): WP_H $token = new WP_HTML_Token( $name, $token_name, false ); $this->insert_html_element( $token ); - return $token; } @@ -6216,11 +6278,11 @@ private function insert_virtual_node( $token_name, $bookmark_name = null ): WP_H /** * Indicates if the current token is a MathML integration point. * - * @return bool Whether the current token is a MathML integration point. - * @see https://html.spec.whatwg.org/#mathml-text-integration-point - * * @since 6.7.0 * + * @see https://html.spec.whatwg.org/#mathml-text-integration-point + * + * @return bool Whether the current token is a MathML integration point. */ private function is_mathml_integration_point(): bool { $current_token = $this->state->current_token; @@ -6252,11 +6314,11 @@ private function is_mathml_integration_point(): bool { * Otherwise it would be required to scan the HTML and ensure that * no other accounting is overlooked. * - * @return bool Whether the current token is an HTML integration point. - * @see https://html.spec.whatwg.org/#html-integration-point - * * @since 6.7.0 * + * @see https://html.spec.whatwg.org/#html-integration-point + * + * @return bool Whether the current token is an HTML integration point. */ private function is_html_integration_point(): bool { $current_token = $this->state->current_token; @@ -6295,7 +6357,6 @@ private function is_html_integration_point(): bool { } $this->bail( 'Should not have reached end of HTML Integration Point detection: check HTML API code.' ); - // This unnecessary return prevents tools from inaccurately reporting type errors. return false; } @@ -6303,13 +6364,12 @@ private function is_html_integration_point(): bool { /** * Returns whether an element of a given name is in the HTML special category. * - * @param WP_HTML_Token|string $tag_name Node to check, or only its name if in the HTML namespace. - * - * @return bool Whether the element of the given name is in the special category. * @since 6.4.0 * * @see https://html.spec.whatwg.org/#special * + * @param WP_HTML_Token|string $tag_name Node to check, or only its name if in the HTML namespace. + * @return bool Whether the element of the given name is in the special category. */ public static function is_special( $tag_name ): bool { if ( is_string( $tag_name ) ) { @@ -6425,13 +6485,12 @@ public static function is_special( $tag_name ): bool { * * > area, base, br, col, embed, hr, img, input, link, meta, source, track, wbr * - * @param string $tag_name Name of HTML tag to check. - * - * @return bool Whether the given tag is an HTML Void Element. * @since 6.4.0 * * @see https://html.spec.whatwg.org/#void-elements * + * @param string $tag_name Name of HTML tag to check. + * @return bool Whether the given tag is an HTML Void Element. */ public static function is_void( $tag_name ): bool { $tag_name = strtoupper( $tag_name ); @@ -6478,8 +6537,7 @@ public static function is_void( $tag_name ): bool { * * @since 6.7.0 * - * @param string $label A string which may specify a known encoding. - * + * @param string $label A string which may specify a known encoding. * @return string|null Known encoding if matched, otherwise null. */ protected static function get_encoding( string $label ): ?string { diff --git a/components/HTML/class-wp-html-span.php b/components/HTML/class-wp-html-span.php index 44fefe82..c8ba9ecd 100644 --- a/components/HTML/class-wp-html-span.php +++ b/components/HTML/class-wp-html-span.php @@ -1,4 +1,6 @@ start = $start; diff --git a/components/HTML/class-wp-html-stack-event.php b/components/HTML/class-wp-html-stack-event.php index 5c8db013..8e329272 100644 --- a/components/HTML/class-wp-html-stack-event.php +++ b/components/HTML/class-wp-html-stack-event.php @@ -1,4 +1,6 @@ token = $token; diff --git a/components/HTML/class-wp-html-tag-processor.php b/components/HTML/class-wp-html-tag-processor.php index 309ed364..995feaa9 100644 --- a/components/HTML/class-wp-html-tag-processor.php +++ b/components/HTML/class-wp-html-tag-processor.php @@ -1,4 +1,11 @@ html = $html; @@ -842,12 +848,11 @@ public function __construct( $html ) { * Switches parsing mode into a new namespace, such as when * encountering an SVG tag and entering foreign content. * - * @param string $new_namespace One of 'html', 'svg', or 'math' indicating into what - * namespace the next tokens will be processed. - * - * @return bool Whether the namespace was valid and changed. * @since 6.7.0 * + * @param string $new_namespace One of 'html', 'svg', or 'math' indicating into what + * namespace the next tokens will be processed. + * @return bool Whether the namespace was valid and changed. */ public function change_parsing_namespace( string $new_namespace ): bool { if ( ! in_array( $new_namespace, array( 'html', 'math', 'svg' ), true ) ) { @@ -855,27 +860,26 @@ public function change_parsing_namespace( string $new_namespace ): bool { } $this->parsing_namespace = $new_namespace; - return true; } /** * Finds the next tag matching the $query. * - * @param array|string|null $query { + * @since 6.2.0 + * @since 6.5.0 No longer processes incomplete tokens at end of document; pauses the processor at start of token. + * + * @param array|string|null $query { * Optional. Which tag name to find, having which class, etc. Default is to find any tag. * - * @type string|null $tag_name Which tag to find, or `null` for "any tag." - * @type int|null $match_offset Find the Nth tag matching all search criteria. + * @type string|null $tag_name Which tag to find, or `null` for "any tag." + * @type int|null $match_offset Find the Nth tag matching all search criteria. * 1 for "first" tag, 3 for "third," etc. * Defaults to first tag. - * @type string|null $class_name Tag must contain this whole class name to match. - * @type string|null $tag_closers "visit" or "skip": whether to stop on tag closers, e.g. . + * @type string|null $class_name Tag must contain this whole class name to match. + * @type string|null $tag_closers "visit" or "skip": whether to stop on tag closers, e.g. . * } * @return bool Whether a tag was matched. - * @since 6.2.0 - * @since 6.5.0 No longer processes incomplete tokens at end of document; pauses the processor at start of token. - * */ public function next_tag( $query = null ): bool { $this->parse_query( $query ); @@ -891,7 +895,7 @@ public function next_tag( $query = null ): bool { } if ( $this->matches() ) { - ++ $already_found; + ++$already_found; } } while ( $already_found < $this->sought_match_offset ); @@ -921,10 +925,10 @@ public function next_tag( $query = null ): bool { * * The Tag Processor currently only supports the tag token. * - * @return bool Whether a token was parsed. + * @since 6.5.0 * @since 6.7.0 Recognizes CDATA sections within foreign content. * - * @since 6.5.0 + * @return bool Whether a token was parsed. */ public function next_token(): bool { return $this->base_class_next_token(); @@ -939,11 +943,11 @@ public function next_token(): bool { * without triggering subclass methods for things like `next_token()`, e.g. when * applying patches before searching for the next token. * - * @return bool Whether a token was parsed. * @since 6.5.0 * * @access private * + * @return bool Whether a token was parsed. */ private function base_class_next_token(): bool { $was_at = $this->bytes_already_parsed; @@ -965,7 +969,6 @@ private function base_class_next_token(): bool { if ( $this->bytes_already_parsed >= strlen( $this->html ) ) { $this->parser_state = self::STATE_COMPLETE; - return false; } @@ -1053,7 +1056,6 @@ private function base_class_next_token(): bool { */ if ( 'LISTING' === $tag_name || 'PRE' === $tag_name ) { $this->skip_newline_at = $this->bytes_already_parsed; - return true; } @@ -1116,7 +1118,6 @@ private function base_class_next_token(): bool { if ( ! $found_closer ) { $this->parser_state = self::STATE_INCOMPLETE_INPUT; $this->bytes_already_parsed = $was_at; - return false; } @@ -1149,9 +1150,9 @@ private function base_class_next_token(): bool { * false === $processor->get_next_tag(); * true === $processor->paused_at_incomplete_token(); * - * @return bool Whether the parse paused at the start of an incomplete token. * @since 6.5.0 * + * @return bool Whether the parse paused at the start of an incomplete token. */ public function paused_at_incomplete_token(): bool { return self::STATE_INCOMPLETE_INPUT === $this->parser_state; @@ -1227,11 +1228,10 @@ public function class_list() { /** * Returns if a matched tag contains the given ASCII case-insensitive class name. * - * @param string $wanted_class Look for this CSS class name, ASCII case-insensitive. - * - * @return bool|null Whether the matched tag contains the given class name, or null if not matched. * @since 6.4.0 * + * @param string $wanted_class Look for this CSS class name, ASCII case-insensitive. + * @return bool|null Whether the matched tag contains the given class name, or null if not matched. */ public function has_class( $wanted_class ): ?bool { if ( self::STATE_MATCHED_TAG !== $this->parser_state ) { @@ -1329,11 +1329,10 @@ public function has_class( $wanted_class ): ?bool { * reaching for it, as inappropriate use could lead to broken * HTML structure or unwanted processing overhead. * - * @param string $name Identifies this particular bookmark. - * - * @return bool Whether the bookmark was successfully created. * @since 6.2.0 * + * @param string $name Identifies this particular bookmark. + * @return bool Whether the bookmark was successfully created. */ public function set_bookmark( $name ): bool { // It only makes sense to set a bookmark if the parser has paused on a concrete token. @@ -1350,7 +1349,6 @@ public function set_bookmark( $name ): bool { __( 'Too many bookmarks: cannot create any more.' ), '6.2.0' ); - return false; } @@ -1366,8 +1364,7 @@ public function set_bookmark( $name ): bool { * Releasing a bookmark frees up the small * performance overhead it requires. * - * @param string $name Name of the bookmark to remove. - * + * @param string $name Name of the bookmark to remove. * @return bool Whether the bookmark already existed before removal. */ public function release_bookmark( $name ): bool { @@ -1383,13 +1380,12 @@ public function release_bookmark( $name ): bool { /** * Skips contents of generic rawtext elements. * - * @param string $tag_name The uppercase tag name which will close the RAWTEXT region. - * - * @return bool Whether an end to the RAWTEXT region was found before the end of the document. * @since 6.3.2 * * @see https://html.spec.whatwg.org/#generic-raw-text-element-parsing-algorithm * + * @param string $tag_name The uppercase tag name which will close the RAWTEXT region. + * @return bool Whether an end to the RAWTEXT region was found before the end of the document. */ private function skip_rawtext( string $tag_name ): bool { /* @@ -1403,13 +1399,12 @@ private function skip_rawtext( string $tag_name ): bool { /** * Skips contents of RCDATA elements, namely title and textarea tags. * - * @param string $tag_name The uppercase tag name which will close the RCDATA region. - * - * @return bool Whether an end to the RCDATA region was found before the end of the document. * @since 6.2.0 * * @see https://html.spec.whatwg.org/multipage/parsing.html#rcdata-state * + * @param string $tag_name The uppercase tag name which will close the RCDATA region. + * @return bool Whether an end to the RCDATA region was found before the end of the document. */ private function skip_rcdata( string $tag_name ): bool { $html = $this->html; @@ -1437,7 +1432,7 @@ private function skip_rcdata( string $tag_name ): bool { * comparing; any character which could be impacted by such * normalization could not be part of a tag name. */ - for ( $i = 0; $i < $tag_length; $i ++ ) { + for ( $i = 0; $i < $tag_length; $i++ ) { $tag_char = $tag_name[ $i ]; $html_char = $html[ $at + $i ]; @@ -1447,7 +1442,7 @@ private function skip_rcdata( string $tag_name ): bool { } } - $at += $tag_length; + $at += $tag_length; $this->bytes_already_parsed = $at; if ( $at >= strlen( $html ) ) { @@ -1476,7 +1471,6 @@ private function skip_rcdata( string $tag_name ): bool { if ( '>' === $html[ $at ] ) { $this->bytes_already_parsed = $at + 1; - return true; } @@ -1486,7 +1480,6 @@ private function skip_rcdata( string $tag_name ): bool { if ( '/' === $html[ $at ] && '>' === $html[ $at + 1 ] ) { $this->bytes_already_parsed = $at + 2; - return true; } } @@ -1497,9 +1490,9 @@ private function skip_rcdata( string $tag_name ): bool { /** * Skips contents of script tags. * - * @return bool Whether the script tag was closed before the end of the document. * @since 6.2.0 * + * @return bool Whether the script tag was closed before the end of the document. */ private function skip_script_data(): bool { $state = 'unescaped'; @@ -1521,7 +1514,7 @@ private function skip_script_data(): bool { '-' === $html[ $at + 1 ] && '>' === $html[ $at + 2 ] ) { - $at += 3; + $at += 3; $state = 'unescaped'; continue; } @@ -1534,7 +1527,7 @@ private function skip_script_data(): bool { * Everything of interest past here starts with "<". * Check this character and advance position regardless. */ - if ( '<' !== $html[ $at ++ ] ) { + if ( '<' !== $html[ $at++ ] ) { continue; } @@ -1556,7 +1549,7 @@ private function skip_script_data(): bool { '-' === $html[ $at + 1 ] && '-' === $html[ $at + 2 ] ) { - $at += 3; + $at += 3; $state = 'unescaped' === $state ? 'escaped' : $state; continue; } @@ -1564,7 +1557,7 @@ private function skip_script_data(): bool { if ( '/' === $html[ $at ] ) { $closer_potentially_starts_at = $at - 1; $is_closing = true; - ++ $at; + ++$at; } else { $is_closing = false; } @@ -1583,7 +1576,7 @@ private function skip_script_data(): bool { ( 'p' === $html[ $at + 4 ] || 'P' === $html[ $at + 4 ] ) && ( 't' === $html[ $at + 5 ] || 'T' === $html[ $at + 5 ] ) ) ) { - ++ $at; + ++$at; continue; } @@ -1597,9 +1590,9 @@ private function skip_script_data(): bool { continue; } $at += 6; - $c = $html[ $at ]; + $c = $html[ $at ]; if ( ' ' !== $c && "\t" !== $c && "\r" !== $c && "\n" !== $c && '/' !== $c && '>' !== $c ) { - ++ $at; + ++$at; continue; } @@ -1631,13 +1624,12 @@ private function skip_script_data(): bool { } if ( '>' === $html[ $this->bytes_already_parsed ] ) { - ++ $this->bytes_already_parsed; - + ++$this->bytes_already_parsed; return true; } } - ++ $at; + ++$at; } return false; @@ -1651,10 +1643,10 @@ private function skip_script_data(): bool { * name. It does not parse the attributes or scan to the * closing `>`; these are left for other methods. * - * @return bool Whether a tag was found before the end of the document. + * @since 6.2.0 * @since 6.2.1 Support abruptly-closed comments, invalid-tag-closer-comments, and empty elements. * - * @since 6.2.0 + * @return bool Whether a tag was found before the end of the document. */ private function parse_next_tag(): bool { $this->after_tag(); @@ -1683,8 +1675,8 @@ private function parse_next_tag(): bool { * * @see https://html.spec.whatwg.org/#tag-open-state */ - if ( 1 !== strspn( $html, '!/?abcdefghijklmnopqrstuvwxyzABCEFGHIJKLMNOPQRSTUVWXYZ', $at + 1, 1 ) ) { - ++ $at; + if ( 1 !== strspn( $html, '!/?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', $at + 1, 1 ) ) { + ++$at; continue; } @@ -1694,7 +1686,6 @@ private function parse_next_tag(): bool { $this->text_starts_at = $was_at; $this->text_length = $this->token_length; $this->bytes_already_parsed = $at; - return true; } @@ -1702,7 +1693,7 @@ private function parse_next_tag(): bool { if ( $at + 1 < $doc_length && '/' === $this->html[ $at + 1 ] ) { $this->is_closing_tag = true; - ++ $at; + ++$at; } else { $this->is_closing_tag = false; } @@ -1723,12 +1714,11 @@ private function parse_next_tag(): bool { */ $tag_name_prefix_length = strspn( $html, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', $at + 1 ); if ( $tag_name_prefix_length > 0 ) { - ++ $at; + ++$at; $this->parser_state = self::STATE_MATCHED_TAG; $this->tag_name_starts_at = $at; $this->tag_name_length = $tag_name_prefix_length + strcspn( $html, " \t\f\r\n/>", $at + $tag_name_prefix_length ); $this->bytes_already_parsed = $at + $this->tag_name_length; - return true; } @@ -1783,7 +1773,6 @@ private function parse_next_tag(): bool { } $this->bytes_already_parsed = $closer_at + $span_of_dashes + 1; - return true; } @@ -1793,8 +1782,8 @@ private function parse_next_tag(): bool { * * See https://html.spec.whatwg.org/#parse-error-incorrectly-closed-comment */ - -- $closer_at; // Pre-increment inside condition below reduces risk of accidental infinite looping. - while ( ++ $closer_at < $doc_length ) { + --$closer_at; // Pre-increment inside condition below reduces risk of accidental infinite looping. + while ( ++$closer_at < $doc_length ) { $closer_at = strpos( $html, '--', $closer_at ); if ( false === $closer_at ) { $this->parser_state = self::STATE_INCOMPLETE_INPUT; @@ -1809,7 +1798,6 @@ private function parse_next_tag(): bool { $this->text_starts_at = $this->token_starts_at + 4; $this->text_length = $closer_at - $this->text_starts_at; $this->bytes_already_parsed = $closer_at + 3; - return true; } @@ -1824,7 +1812,6 @@ private function parse_next_tag(): bool { $this->text_starts_at = $this->token_starts_at + 4; $this->text_length = $closer_at - $this->text_starts_at; $this->bytes_already_parsed = $closer_at + 4; - return true; } } @@ -1857,7 +1844,6 @@ private function parse_next_tag(): bool { $this->text_starts_at = $this->token_starts_at + 9; $this->text_length = $closer_at - $this->text_starts_at; $this->bytes_already_parsed = $closer_at + 1; - return true; } @@ -1884,7 +1870,6 @@ private function parse_next_tag(): bool { $this->text_length = $closer_at - $this->text_starts_at; $this->token_length = $closer_at + 3 - $this->token_starts_at; $this->bytes_already_parsed = $closer_at + 3; - return true; } @@ -1934,8 +1919,8 @@ private function parse_next_tag(): bool { ']' === $html[ $closer_at - 1 ] && ']' === $html[ $closer_at - 2 ] ) { - $this->parser_state = self::STATE_COMMENT; - $this->comment_type = self::COMMENT_AS_CDATA_LOOKALIKE; + $this->parser_state = self::STATE_COMMENT; + $this->comment_type = self::COMMENT_AS_CDATA_LOOKALIKE; $this->text_starts_at += 7; $this->text_length -= 9; } @@ -1955,14 +1940,13 @@ private function parse_next_tag(): bool { if ( '>' === $html[ $at + 1 ] ) { // `<>` is interpreted as plaintext. if ( ! $this->is_closing_tag ) { - ++ $at; + ++$at; continue; } $this->parser_state = self::STATE_PRESUMPTUOUS_TAG; $this->token_length = $at + 2 - $this->token_starts_at; $this->bytes_already_parsed = $at + 2; - return true; } @@ -2017,14 +2001,13 @@ private function parse_next_tag(): bool { $pi_target_length = strspn( $comment_text, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ:_' ); if ( 0 < $pi_target_length ) { - $pi_target_length += strspn( $comment_text, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:_-.', - $pi_target_length ); + $pi_target_length += strspn( $comment_text, 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789:_-.', $pi_target_length ); $this->comment_type = self::COMMENT_AS_PI_NODE_LOOKALIKE; $this->tag_name_starts_at = $this->token_starts_at + 2; $this->tag_name_length = $pi_target_length; - $this->text_starts_at += $pi_target_length; - $this->text_length -= $pi_target_length + 1; + $this->text_starts_at += $pi_target_length; + $this->text_length -= $pi_target_length + 1; } } @@ -2060,11 +2043,10 @@ private function parse_next_tag(): bool { $this->text_starts_at = $this->token_starts_at + 2; $this->text_length = $closer_at - $this->text_starts_at; $this->bytes_already_parsed = $closer_at + 1; - return true; } - ++ $at; + ++$at; } /* @@ -2077,16 +2059,15 @@ private function parse_next_tag(): bool { $this->text_starts_at = $was_at; $this->text_length = $this->token_length; $this->bytes_already_parsed = $doc_length; - return true; } /** * Parses the next attribute. * - * @return bool Whether an attribute was found before the end of the document. * @since 6.2.0 * + * @return bool Whether an attribute was found before the end of the document. */ private function parse_next_attribute(): bool { $doc_length = strlen( $this->html ); @@ -2114,8 +2095,8 @@ private function parse_next_attribute(): bool { return false; } - $attribute_start = $this->bytes_already_parsed; - $attribute_name = substr( $this->html, $attribute_start, $name_length ); + $attribute_start = $this->bytes_already_parsed; + $attribute_name = substr( $this->html, $attribute_start, $name_length ); $this->bytes_already_parsed += $name_length; if ( $this->bytes_already_parsed >= $doc_length ) { $this->parser_state = self::STATE_INCOMPLETE_INPUT; @@ -2132,7 +2113,7 @@ private function parse_next_attribute(): bool { $has_value = '=' === $this->html[ $this->bytes_already_parsed ]; if ( $has_value ) { - ++ $this->bytes_already_parsed; + ++$this->bytes_already_parsed; $this->skip_whitespace(); if ( $this->bytes_already_parsed >= $doc_length ) { $this->parser_state = self::STATE_INCOMPLETE_INPUT; @@ -2323,6 +2304,7 @@ private function class_name_updates_to_attributes_updates(): void { * attribute, skipping removed classes on the way, and then appending * added classes at the end. Only when finished processing will the * value contain the final new value. + * @var string $class */ $class = ''; @@ -2377,7 +2359,7 @@ private function class_name_updates_to_attributes_updates(): void { // Skip to the first non-whitespace character. $ws_at = $at; $ws_length = strspn( $existing_class, " \t\f\r\n", $ws_at ); - $at += $ws_length; + $at += $ws_length; // Capture the class name – it's everything until the next whitespace. $name_length = strcspn( $existing_class, " \t\f\r\n", $at ); @@ -2388,7 +2370,7 @@ private function class_name_updates_to_attributes_updates(): void { $name = substr( $existing_class, $at, $name_length ); $comparable_class_name = $is_quirks ? strtolower( $name ) : $name; - $at += $name_length; + $at += $name_length; // If this class is marked for removal, remove it and move on to the next one. if ( in_array( $comparable_class_name, $to_remove, true ) ) { @@ -2447,13 +2429,12 @@ private function class_name_updates_to_attributes_updates(): void { /** * Applies attribute updates to HTML document. * - * @param int $shift_this_point Accumulate and return shift for this position. - * - * @return int How many bytes the given pointer moved in response to the updates. - * @since 6.3.0 Invalidate any bookmarks whose targets are overwritten. - * * @since 6.2.0 * @since 6.2.1 Accumulates shift for internal cursor and passed pointer. + * @since 6.3.0 Invalidate any bookmarks whose targets are overwritten. + * + * @param int $shift_this_point Accumulate and return shift for this position. + * @return int How many bytes the given pointer moved in response to the updates. */ private function apply_attributes_updates( int $shift_this_point ): int { if ( ! count( $this->lexical_updates ) ) { @@ -2489,8 +2470,8 @@ private function apply_attributes_updates( int $shift_this_point ): int { $accumulated_shift_for_given_point += $shift; } - $output_buffer .= substr( $this->html, $bytes_already_copied, $diff->start - $bytes_already_copied ); - $output_buffer .= $diff->text; + $output_buffer .= substr( $this->html, $bytes_already_copied, $diff->start - $bytes_already_copied ); + $output_buffer .= $diff->text; $bytes_already_copied = $diff->start + $diff->length; } @@ -2547,11 +2528,10 @@ private function apply_attributes_updates( int $shift_this_point ): int { /** * Checks whether a bookmark with the given name exists. * - * @param string $bookmark_name Name to identify a bookmark that potentially exists. - * - * @return bool Whether that bookmark exists. * @since 6.3.0 * + * @param string $bookmark_name Name to identify a bookmark that potentially exists. + * @return bool Whether that bookmark exists. */ public function has_bookmark( $bookmark_name ): bool { return array_key_exists( $bookmark_name, $this->bookmarks ); @@ -2563,11 +2543,10 @@ public function has_bookmark( $bookmark_name ): bool { * In order to prevent accidental infinite loops, there's a * maximum limit on the number of times seek() can be called. * - * @param string $bookmark_name Jump to the place in the document identified by this bookmark name. - * - * @return bool Whether the internal cursor was successfully moved to the bookmark's location. * @since 6.2.0 * + * @param string $bookmark_name Jump to the place in the document identified by this bookmark name. + * @return bool Whether the internal cursor was successfully moved to the bookmark's location. */ public function seek( $bookmark_name ): bool { if ( ! array_key_exists( $bookmark_name, $this->bookmarks ) ) { @@ -2576,17 +2555,24 @@ public function seek( $bookmark_name ): bool { __( 'Unknown bookmark name.' ), '6.2.0' ); - return false; } - if ( ++ $this->seek_count > static::MAX_SEEK_OPS ) { + $existing_bookmark = $this->bookmarks[ $bookmark_name ]; + + if ( + $this->token_starts_at === $existing_bookmark->start && + $this->token_length === $existing_bookmark->length + ) { + return true; + } + + if ( ++$this->seek_count > static::MAX_SEEK_OPS ) { _doing_it_wrong( __METHOD__, __( 'Too many calls to seek() - this can lead to performance issues.' ), '6.2.0' ); - return false; } @@ -2596,19 +2582,17 @@ public function seek( $bookmark_name ): bool { // Point this tag processor before the sought tag opener and consume it. $this->bytes_already_parsed = $this->bookmarks[ $bookmark_name ]->start; $this->parser_state = self::STATE_READY; - return $this->next_token(); } /** * Compare two WP_HTML_Text_Replacement objects. * - * @param WP_HTML_Text_Replacement $a First attribute update. - * @param WP_HTML_Text_Replacement $b Second attribute update. - * - * @return int Comparison value for string order. * @since 6.2.0 * + * @param WP_HTML_Text_Replacement $a First attribute update. + * @param WP_HTML_Text_Replacement $b Second attribute update. + * @return int Comparison value for string order. */ private static function sort_start_ascending( WP_HTML_Text_Replacement $a, WP_HTML_Text_Replacement $b ): int { $by_start = $a->start - $b->start; @@ -2625,7 +2609,6 @@ private static function sort_start_ascending( WP_HTML_Text_Replacement $a, WP_HT * This code should be unreachable, because it implies the two replacements * start at the same location and contain the same text. */ - return $a->length - $b->length; } @@ -2638,11 +2621,10 @@ private static function sort_start_ascending( WP_HTML_Text_Replacement $a, WP_HT * - If an attribute is enqueued to be removed, the return will be `null` to indicate that. * - If no updates are enqueued, the return will be `false` to differentiate from "removed." * - * @param string $comparable_name The attribute name in its comparable form. - * - * @return string|boolean|null Value of enqueued update if present, otherwise false. * @since 6.2.0 * + * @param string $comparable_name The attribute name in its comparable form. + * @return string|boolean|null Value of enqueued update if present, otherwise false. */ private function get_enqueued_attribute_value( string $comparable_name ) { if ( self::STATE_MATCHED_TAG !== $this->parser_state ) { @@ -2692,8 +2674,7 @@ private function get_enqueued_attribute_value( string $comparable_name ) { * 2. Double-quoting starts one after the equals sign. * 3. Double-quoting ends at the last character in the update. */ - $enqueued_value = substr( $enqueued_text, $equals_at + 2, - 1 ); - + $enqueued_value = substr( $enqueued_text, $equals_at + 2, -1 ); return WP_HTML_Decoder::decode_attribute( $enqueued_value ); } @@ -2711,11 +2692,10 @@ private function get_enqueued_attribute_value( string $comparable_name ) { * $p->next_tag() === false; * $p->get_attribute( 'class' ) === null; * - * @param string $name Name of attribute whose value is requested. - * - * @return string|true|null Value of attribute or `null` if not available. Boolean attributes return `true`. * @since 6.2.0 * + * @param string $name Name of attribute whose value is requested. + * @return string|true|null Value of attribute or `null` if not available. Boolean attributes return `true`. */ public function get_attribute( $name ) { if ( self::STATE_MATCHED_TAG !== $this->parser_state ) { @@ -2790,13 +2770,12 @@ public function get_attribute( $name ) { * $p->next_tag() === false; * $p->get_attribute_names_with_prefix( 'data-' ) === null; * - * @param string $prefix Prefix of requested attribute names. - * - * @return array|null List of attribute names, or `null` when no tag opener is matched. * @since 6.2.0 * * @see https://html.spec.whatwg.org/multipage/syntax.html#attributes-2:ascii-case-insensitive * + * @param string $prefix Prefix of requested attribute names. + * @return array|null List of attribute names, or `null` when no tag opener is matched. */ public function get_attribute_names_with_prefix( $prefix ): ?array { if ( @@ -2810,20 +2789,19 @@ public function get_attribute_names_with_prefix( $prefix ): ?array { $matches = array(); foreach ( array_keys( $this->attributes ) as $attr_name ) { - if ( strncmp( $attr_name, $comparable, strlen( $comparable ) ) === 0 ) { + if ( str_starts_with( $attr_name, $comparable ) ) { $matches[] = $attr_name; } } - return $matches; } /** * Returns the namespace of the matched token. * - * @return string One of 'html', 'math', or 'svg'. * @since 6.7.0 * + * @return string One of 'html', 'math', or 'svg'. */ public function get_namespace(): string { return $this->parsing_namespace; @@ -2841,9 +2819,9 @@ public function get_namespace(): string { * $p->next_tag() === false; * $p->get_tag() === null; * - * @return string|null Name of currently matched tag in input HTML, or `null` if none found. * @since 6.2.0 * + * @return string|null Name of currently matched tag in input HTML, or `null` if none found. */ public function get_tag(): ?string { if ( null === $this->tag_name_starts_at ) { @@ -2870,9 +2848,9 @@ public function get_tag(): ?string { * Returns the adjusted tag name for a given token, taking into * account the current parsing context, whether HTML, SVG, or MathML. * - * @return string|null Name of current tag name. * @since 6.7.0 * + * @return string|null Name of current tag name. */ public function get_qualified_tag_name(): ?string { $tag_name = $this->get_tag(); @@ -3015,11 +2993,11 @@ public function get_qualified_tag_name(): ?string { * Returns the adjusted attribute name for a given attribute, taking into * account the current parsing context, whether HTML, SVG, or MathML. * - * @param string $attribute_name Which attribute to adjust. - * - * @return string|null * @since 6.7.0 * + * @param string $attribute_name Which attribute to adjust. + * + * @return string|null */ public function get_qualified_attribute_name( $attribute_name ): ?string { if ( self::STATE_MATCHED_TAG !== $this->parser_state ) { @@ -3264,9 +3242,9 @@ public function get_qualified_attribute_name( $attribute_name ): ?string { * This function does not determine if a tag is self-closing, * but only if the self-closing flag is present in the syntax. * - * @return bool Whether the currently matched tag contains the self-closing flag. * @since 6.3.0 * + * @return bool Whether the currently matched tag contains the self-closing flag. */ public function has_self_closing_flag(): bool { if ( self::STATE_MATCHED_TAG !== $this->parser_state ) { @@ -3281,7 +3259,6 @@ public function has_self_closing_flag(): bool { *
* ^ this appears one character before the end of the closing ">". */ - return '/' === $this->html[ $this->token_starts_at + $this->token_length - 2 ]; } @@ -3297,10 +3274,10 @@ public function has_self_closing_flag(): bool { * $p->next_tag( array( 'tag_name' => 'div', 'tag_closers' => 'visit' ) ); * $p->is_tag_closer() === true; * - * @return bool Whether the current tag is a tag closer. + * @since 6.2.0 * @since 6.7.0 Reports all BR tags as opening tags. * - * @since 6.2.0 + * @return bool Whether the current tag is a tag closer. */ public function is_tag_closer(): bool { return ( @@ -3336,9 +3313,9 @@ public function is_tag_closer(): bool { * - `#presumptuous-tag` when matched on an empty tag closer. * - `#funky-comment` when matched on a funky comment. * - * @return string|null What kind of token is matched, or null. * @since 6.5.0 * + * @return string|null What kind of token is matched, or null. */ public function get_token_type(): ?string { switch ( $this->parser_state ) { @@ -3369,9 +3346,9 @@ public function get_token_type(): ?string { * hasn't yet found a token or because it reached the end * of the document without matching a token. * - * @return string|null Name of the matched token. * @since 6.5.0 * + * @return string|null Name of the matched token. */ public function get_token_name(): ?string { switch ( $this->parser_state ) { @@ -3409,7 +3386,7 @@ public function get_token_name(): ?string { * they are commonly known, but a number of unrelated syntax errors * also produce comments. * - * @return string|null + * @see self::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT * @see self::COMMENT_AS_CDATA_LOOKALIKE * @see self::COMMENT_AS_INVALID_HTML * @see self::COMMENT_AS_HTML_COMMENT @@ -3417,7 +3394,7 @@ public function get_token_name(): ?string { * * @since 6.5.0 * - * @see self::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT + * @return string|null */ public function get_comment_type(): ?string { if ( self::STATE_COMMENT !== $this->parser_state ) { @@ -3440,10 +3417,10 @@ public function get_comment_type(): ?string { * that character were modified, it would be possible to change the node * type. * - * @return string|null The comment text as it would appear in the browser or null - * if not on a comment type node. * @since 6.7.0 * + * @return string|null The comment text as it would appear in the browser or null + * if not on a comment type node. */ public function get_full_comment_text(): ?string { if ( self::STATE_FUNKY_COMMENT === $this->parser_state ) { @@ -3473,7 +3450,6 @@ public function get_full_comment_text(): ?string { case self::COMMENT_AS_INVALID_HTML: $preceding_character = $this->html[ $this->text_starts_at - 1 ]; $comment_start = '?' === $preceding_character ? '?' : ''; - return "{$comment_start}{$this->get_modifiable_text()}"; } @@ -3507,9 +3483,9 @@ public function get_full_comment_text(): ?string { * true === $processor->next_token(); // Text is "More". * false === $processor->subdivide_text_appropriately(); * - * @return bool Whether the text node was subdivided. * @since 6.7.0 * + * @return bool Whether the text node was subdivided. */ public function subdivide_text_appropriately(): bool { if ( self::STATE_TEXT_NODE !== $this->parser_state ) { @@ -3528,7 +3504,6 @@ public function subdivide_text_appropriately(): bool { $this->text_length = $leading_nulls; $this->bytes_already_parsed = $this->token_starts_at + $leading_nulls; $this->text_node_classification = self::TEXT_IS_NULL_SEQUENCE; - return true; } @@ -3541,7 +3516,7 @@ public function subdivide_text_appropriately(): bool { $end = $this->text_starts_at + $this->text_length; while ( $at < $end ) { $skipped = strspn( $this->html, " \t\f\r\n", $at, $end - $at ); - $at += $skipped; + $at += $skipped; if ( $at < $end && '&' === $this->html[ $at ] ) { $matched_byte_length = null; @@ -3561,7 +3536,6 @@ public function subdivide_text_appropriately(): bool { $this->token_length = $new_length; $this->bytes_already_parsed = $at; $this->text_node_classification = self::TEXT_IS_WHITESPACE; - return true; } @@ -3591,10 +3565,10 @@ public function subdivide_text_appropriately(): bool { * newline is treated properly, seek to the LISTING or PRE opening * tag instead of to the first text node inside the element. * - * @return string + * @since 6.5.0 * @since 6.7.0 Replaces NULL bytes (U+0000) and newlines appropriately. * - * @since 6.5.0 + * @return string */ public function get_modifiable_text(): string { $has_enqueued_update = isset( $this->lexical_updates['modifiable text'] ); @@ -3671,7 +3645,6 @@ public function get_modifiable_text(): string { * text is processed according to the insertion mode, not according * to the foreign content rules. This should strip the NULL bytes. */ - return ( '#text' === $tag_name && 'html' === $this->get_namespace() ) ? str_replace( "\x00", '', $decoded ) : str_replace( "\x00", "\u{FFFD}", $decoded ); @@ -3717,11 +3690,11 @@ public function get_modifiable_text(): string { * $processor->set_modifiable_text( str_replace( ':)', 'πŸ™‚', $chunk ) ); * } * - * @param string $plaintext_content New text content to represent in the matched token. - * - * @return bool Whether the text was able to update. * @since 6.7.0 * + * @param string $plaintext_content New text content to represent in the matched token. + * + * @return bool Whether the text was able to update. */ public function set_modifiable_text( string $plaintext_content ): bool { if ( self::STATE_TEXT_NODE === $this->parser_state ) { @@ -3837,13 +3810,12 @@ static function ( $tag_match ) { * * For string attributes, the value is escaped using the `esc_attr` function. * - * @param string $name The attribute name to target. - * @param string|bool $value The new attribute value. - * - * @return bool Whether an attribute value was set. + * @since 6.2.0 * @since 6.2.1 Fix: Only create a single update for multiple calls with case-variant attribute names. * - * @since 6.2.0 + * @param string $name The attribute name to target. + * @param string|bool $value The new attribute value. + * @return bool Whether an attribute value was set. */ public function set_attribute( $name, $value ): bool { if ( @@ -3874,17 +3846,17 @@ public function set_attribute( $name, $value ): bool { */ if ( preg_match( '~[' . - // Syntax-like characters. - '"\'>&&lexical_updates[ $name ] ) ) { unset( $this->lexical_updates[ $name ] ); } - return false; } @@ -4069,11 +4039,10 @@ public function remove_attribute( $name ): bool { /** * Adds a new class name to the currently matched tag. * - * @param string $class_name The class name to add. - * - * @return bool Whether the class was set to be added. * @since 6.2.0 * + * @param string $class_name The class name to add. + * @return bool Whether the class was set to be added. */ public function add_class( $class_name ): bool { if ( @@ -4085,7 +4054,6 @@ public function add_class( $class_name ): bool { if ( self::QUIRKS_MODE !== $this->compat_mode ) { $this->classname_updates[ $class_name ] = self::ADD_CLASS; - return true; } @@ -4102,24 +4070,21 @@ public function add_class( $class_name ): bool { 0 === substr_compare( $updated_name, $class_name, 0, $class_name_length, true ) ) { $this->classname_updates[ $updated_name ] = self::ADD_CLASS; - return true; } } $this->classname_updates[ $class_name ] = self::ADD_CLASS; - return true; } /** * Removes a class name from the currently matched tag. * - * @param string $class_name The class name to remove. - * - * @return bool Whether the class was set to be removed. * @since 6.2.0 * + * @param string $class_name The class name to remove. + * @return bool Whether the class was set to be removed. */ public function remove_class( $class_name ): bool { if ( @@ -4131,7 +4096,6 @@ public function remove_class( $class_name ): bool { if ( self::QUIRKS_MODE !== $this->compat_mode ) { $this->classname_updates[ $class_name ] = self::REMOVE_CLASS; - return true; } @@ -4148,24 +4112,22 @@ public function remove_class( $class_name ): bool { 0 === substr_compare( $updated_name, $class_name, 0, $class_name_length, true ) ) { $this->classname_updates[ $updated_name ] = self::REMOVE_CLASS; - return true; } } $this->classname_updates[ $class_name ] = self::REMOVE_CLASS; - return true; } /** * Returns the string representation of the HTML Tag Processor. * - * @return string The processed HTML. - * @see WP_HTML_Tag_Processor::get_updated_html() - * * @since 6.2.0 * + * @see WP_HTML_Tag_Processor::get_updated_html() + * + * @return string The processed HTML. */ public function __toString(): string { return $this->get_updated_html(); @@ -4174,11 +4136,11 @@ public function __toString(): string { /** * Returns the string representation of the HTML Tag Processor. * - * @return string The processed HTML. + * @since 6.2.0 * @since 6.2.1 Shifts the internal cursor corresponding to the applied updates. * @since 6.4.0 No longer calls subclass method `next_tag()` after updating HTML. * - * @since 6.2.0 + * @return string The processed HTML. */ public function get_updated_html(): string { $requires_no_updating = 0 === count( $this->classname_updates ) && 0 === count( $this->lexical_updates ); @@ -4232,18 +4194,18 @@ public function get_updated_html(): string { /** * Parses tag query input into internal search criteria. * - * @param array|string|null $query { + * @since 6.2.0 + * + * @param array|string|null $query { * Optional. Which tag name to find, having which class, etc. Default is to find any tag. * - * @type string|null $tag_name Which tag to find, or `null` for "any tag." - * @type int|null $match_offset Find the Nth tag matching all search criteria. + * @type string|null $tag_name Which tag to find, or `null` for "any tag." + * @type int|null $match_offset Find the Nth tag matching all search criteria. * 1 for "first" tag, 3 for "third," etc. * Defaults to first tag. - * @type string|null $class_name Tag must contain this class name to match. - * @type string $tag_closers "visit" or "skip": whether to stop on tag closers, e.g. . + * @type string|null $class_name Tag must contain this class name to match. + * @type string $tag_closers "visit" or "skip": whether to stop on tag closers, e.g. . * } - * @since 6.2.0 - * */ private function parse_query( $query ) { if ( null !== $query && $query === $this->last_query ) { @@ -4259,7 +4221,6 @@ private function parse_query( $query ) { // A single string value means "find the tag of this name". if ( is_string( $query ) ) { $this->sought_tag_name = $query; - return; } @@ -4275,7 +4236,6 @@ private function parse_query( $query ) { __( 'The query argument must be an array or a tag name.' ), '6.2.0' ); - return; } @@ -4300,9 +4260,9 @@ private function parse_query( $query ) { /** * Checks whether a given tag and its attributes match the search criteria. * - * @return bool Whether the given tag and its attribute match the search criteria. * @since 6.2.0 * + * @return bool Whether the given tag and its attribute match the search criteria. */ private function matches(): bool { if ( $this->is_closing_tag && ! $this->stop_on_tag_closers ) { diff --git a/components/HTML/class-wp-html-text-replacement.php b/components/HTML/class-wp-html-text-replacement.php index e94d271e..dd19ebc7 100644 --- a/components/HTML/class-wp-html-text-replacement.php +++ b/components/HTML/class-wp-html-text-replacement.php @@ -1,4 +1,6 @@ start = $start; diff --git a/components/HTML/class-wp-html-token.php b/components/HTML/class-wp-html-token.php index dc6bbe63..370dd0e4 100644 --- a/components/HTML/class-wp-html-token.php +++ b/components/HTML/class-wp-html-token.php @@ -1,4 +1,6 @@ bookmark_name = $bookmark_name; @@ -122,6 +123,6 @@ public function __destruct() { * @since 6.4.2 */ public function __wakeup() { - throw new LogicException( __CLASS__ . ' should never be unserialized' ); + throw new \LogicException( __CLASS__ . ' should never be unserialized' ); } } diff --git a/components/HTML/class-wp-html-unsupported-exception.php b/components/HTML/class-wp-html-unsupported-exception.php index f20e436d..43cb4dd2 100644 --- a/components/HTML/class-wp-html-unsupported-exception.php +++ b/components/HTML/class-wp-html-unsupported-exception.php @@ -1,4 +1,7 @@ token_name = $token_name; $this->token_at = $token_at; $this->token = $token; - $this->stack_of_open_elements = $stack_of_open_elements; + $this->stack_of_open_elements = $stack_of_open_elements; $this->active_formatting_elements = $active_formatting_elements; } } diff --git a/components/HTML/class-wp-token-map.php b/components/HTML/class-wp-token-map.php index 0687a34d..946b7a7f 100644 --- a/components/HTML/class-wp-token-map.php +++ b/components/HTML/class-wp-token-map.php @@ -1,5 +1,9 @@ 'πŸ˜•', * ) ); * - * @param array $mappings The keys transform into the values, both are strings. - * @param int $key_length Determines the group key length. Leave at the default value + * @since 6.6.0 + * + * @param array $mappings The keys transform into the values, both are strings. + * @param int $key_length Determines the group key length. Leave at the default value * of 2 unless there's an empirical reason to change it. * * @return WP_Token_Map|null Token map, unless unable to create it. - * @since 6.6.0 - * */ public static function from_array( array $mappings, int $key_length = 2 ): ?WP_Token_Map { $map = new WP_Token_Map(); @@ -296,13 +300,12 @@ public static function from_array( array $mappings, int $key_length = 2 ): ?WP_T _doing_it_wrong( __METHOD__, sprintf( - /* translators: 1: maximum byte length (a count) */ + /* translators: 1: maximum byte length (a count) */ __( 'Token Map tokens and substitutions must all be shorter than %1$d bytes.' ), self::MAX_LENGTH ), '6.6.0' ); - return null; } @@ -338,7 +341,7 @@ static function ( array $a, array $b ): int { // Finally construct the optimized lookups. foreach ( $shorts as $word ) { - $map->small_words .= str_pad( $word, $key_length + 1, "\x00", STR_PAD_RIGHT ); + $map->small_words .= str_pad( $word, $key_length + 1, "\x00", STR_PAD_RIGHT ); $map->small_mappings[] = $mappings[ $word ]; } @@ -355,7 +358,7 @@ static function ( array $a, array $b ): int { $word_length = pack( 'C', strlen( $word ) ); $mapping_length = pack( 'C', strlen( $mapping ) ); - $group_string .= "{$word_length}{$word}{$mapping_length}{$mapping}"; + $group_string .= "{$word_length}{$word}{$mapping_length}{$mapping}"; } $map->large_words[] = $group_string; @@ -371,20 +374,20 @@ static function ( array $a, array $b ): int { * This function should only be used to load data created with * WP_Token_Map::precomputed_php_source_tag(). * - * @param array $state { + * @since 6.6.0 + * + * @param array $state { * Stores pre-computed state for directly loading into a Token Map. * - * @type string $storage_version Which version of the code produced this state. - * @type int $key_length Group key length. - * @type string $groups Group lookup index. - * @type array $large_words Large word groups and packed strings. - * @type string $small_words Small words packed string. - * @type array $small_mappings Small word mappings. + * @type string $storage_version Which version of the code produced this state. + * @type int $key_length Group key length. + * @type string $groups Group lookup index. + * @type array $large_words Large word groups and packed strings. + * @type string $small_words Small words packed string. + * @type array $small_mappings Small word mappings. * } * * @return WP_Token_Map Map with precomputed data loaded. - * @since 6.6.0 - * */ public static function from_precomputed_table( $state ): ?WP_Token_Map { $has_necessary_state = isset( @@ -402,7 +405,6 @@ public static function from_precomputed_table( $state ): ?WP_Token_Map { __( 'Missing required inputs to pre-computed WP_Token_Map.' ), '6.6.0' ); - return null; } @@ -410,11 +412,9 @@ public static function from_precomputed_table( $state ): ?WP_Token_Map { _doing_it_wrong( __METHOD__, /* translators: 1: version string, 2: version string. */ - sprintf( __( 'Loaded version \'%1$s\' incompatible with expected version \'%2$s\'.' ), $state['storage_version'], - self::STORAGE_VERSION ), + sprintf( __( 'Loaded version \'%1$s\' incompatible with expected version \'%2$s\'.' ), $state['storage_version'], self::STORAGE_VERSION ), '6.6.0' ); - return null; } @@ -437,12 +437,11 @@ public static function from_precomputed_table( $state ): ?WP_Token_Map { * true === $smilies->contains( ':)' ); * false === $smilies->contains( 'simile' ); * - * @param string $word Determine if this word is a lookup key in the map. - * @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'. - * - * @return bool Whether there's an entry for the given word in the map. * @since 6.6.0 * + * @param string $word Determine if this word is a lookup key in the map. + * @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'. + * @return bool Whether there's an entry for the given word in the map. */ public function contains( string $word, string $case_sensitivity = 'case-sensitive' ): bool { $ignore_case = 'ascii-case-insensitive' === $case_sensitivity; @@ -473,10 +472,10 @@ public function contains( string $word, string $case_sensitivity = 'case-sensiti $at = 0; while ( $at < $group_length ) { - $token_length = unpack( 'C', $group[ $at ++ ] )[1]; + $token_length = unpack( 'C', $group[ $at++ ] )[1]; $token_at = $at; - $at += $token_length; - $mapping_length = unpack( 'C', $group[ $at ++ ] )[1]; + $at += $token_length; + $mapping_length = unpack( 'C', $group[ $at++ ] )[1]; $mapping_at = $at; if ( $token_length === $length && 0 === substr_compare( $group, $slug, $token_at, $token_length, $ignore_case ) ) { @@ -523,21 +522,16 @@ public function contains( string $word, string $case_sensitivity = 'case-sensiti * $output .= "{$prefix}{$smily}"; * } * - * @param string $text String in which to search for a lookup key. - * @param int $offset Optional. How many bytes into the string where the lookup key ought to start. Default 0. - * @param int|null &$matched_token_byte_length Optional. Holds byte-length of found token matched, otherwise not set. Default null. - * @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'. - * - * @return string|null Mapped value of lookup key if found, otherwise `null`. * @since 6.6.0 * + * @param string $text String in which to search for a lookup key. + * @param int $offset Optional. How many bytes into the string where the lookup key ought to start. Default 0. + * @param int|null &$matched_token_byte_length Optional. Holds byte-length of found token matched, otherwise not set. Default null. + * @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'. + * + * @return string|null Mapped value of lookup key if found, otherwise `null`. */ - public function read_token( - string $text, - int $offset = 0, - &$matched_token_byte_length = null, - $case_sensitivity = 'case-sensitive' - ): ?string { + public function read_token( string $text, int $offset = 0, &$matched_token_byte_length = null, $case_sensitivity = 'case-sensitive' ): ?string { $ignore_case = 'ascii-case-insensitive' === $case_sensitivity; $text_length = strlen( $text ); @@ -557,15 +551,14 @@ public function read_token( $group_length = strlen( $group ); $at = 0; while ( $at < $group_length ) { - $token_length = unpack( 'C', $group[ $at ++ ] )[1]; + $token_length = unpack( 'C', $group[ $at++ ] )[1]; $token = substr( $group, $at, $token_length ); - $at += $token_length; - $mapping_length = unpack( 'C', $group[ $at ++ ] )[1]; + $at += $token_length; + $mapping_length = unpack( 'C', $group[ $at++ ] )[1]; $mapping_at = $at; if ( 0 === substr_compare( $text, $token, $offset + $this->key_length, $token_length, $ignore_case ) ) { $matched_token_byte_length = $this->key_length + $token_length; - return substr( $group, $mapping_at, $mapping_length ); } @@ -582,21 +575,16 @@ public function read_token( /** * Finds a match for a short word at the index. * - * @param string $text String in which to search for a lookup key. - * @param int $offset Optional. How many bytes into the string where the lookup key ought to start. Default 0. - * @param int|null &$matched_token_byte_length Optional. Holds byte-length of found lookup key if matched, otherwise not set. Default null. - * @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'. - * - * @return string|null Mapped value of lookup key if found, otherwise `null`. * @since 6.6.0 * + * @param string $text String in which to search for a lookup key. + * @param int $offset Optional. How many bytes into the string where the lookup key ought to start. Default 0. + * @param int|null &$matched_token_byte_length Optional. Holds byte-length of found lookup key if matched, otherwise not set. Default null. + * @param string $case_sensitivity Optional. Pass 'ascii-case-insensitive' to ignore ASCII case when matching. Default 'case-sensitive'. + * + * @return string|null Mapped value of lookup key if found, otherwise `null`. */ - private function read_small_token( - string $text, - int $offset = 0, - &$matched_token_byte_length = null, - $case_sensitivity = 'case-sensitive' - ): ?string { + private function read_small_token( string $text, int $offset = 0, &$matched_token_byte_length = null, $case_sensitivity = 'case-sensitive' ): ?string { $ignore_case = 'ascii-case-insensitive' === $case_sensitivity; $small_length = strlen( $this->small_words ); $search_text = substr( $text, $offset, $this->key_length ); @@ -615,10 +603,9 @@ private function read_small_token( continue; } - for ( $adjust = 1; $adjust < $this->key_length; $adjust ++ ) { + for ( $adjust = 1; $adjust < $this->key_length; $adjust++ ) { if ( "\x00" === $this->small_words[ $at + $adjust ] ) { $matched_token_byte_length = $adjust; - return $this->small_mappings[ $at / ( $this->key_length + 1 ) ]; } @@ -632,7 +619,6 @@ private function read_small_token( } $matched_token_byte_length = $adjust; - return $this->small_mappings[ $at / ( $this->key_length + 1 ) ]; } @@ -661,7 +647,7 @@ public function to_array(): array { $small_length = strlen( $this->small_words ); while ( $at < $small_length ) { $key = rtrim( substr( $this->small_words, $at, $this->key_length + 1 ), "\x00" ); - $value = $this->small_mappings[ $small_mapping ++ ]; + $value = $this->small_mappings[ $small_mapping++ ]; $tokens[ $key ] = $value; $at += $this->key_length + 1; @@ -672,15 +658,15 @@ public function to_array(): array { $group_length = strlen( $group ); $at = 0; while ( $at < $group_length ) { - $length = unpack( 'C', $group[ $at ++ ] )[1]; + $length = unpack( 'C', $group[ $at++ ] )[1]; $key = $prefix . substr( $group, $at, $length ); - $at += $length; - $length = unpack( 'C', $group[ $at ++ ] )[1]; + $at += $length; + $length = unpack( 'C', $group[ $at++ ] )[1]; $value = substr( $group, $at, $length ); $tokens[ $key ] = $value; - $at += $length; + $at += $length; } } @@ -710,11 +696,10 @@ public function to_array(): array { * ) * ); * - * @param string $indent Optional. Use this string for indentation, or rely on the default horizontal tab character. Default "\t". - * - * @return string Value which can be pasted into a PHP source file for quick loading of table. * @since 6.6.0 * + * @param string $indent Optional. Use this string for indentation, or rely on the default horizontal tab character. Default "\t". + * @return string Value which can be pasted into a PHP source file for quick loading of table. */ public function precomputed_php_source_table( string $indent = "\t" ): string { $i1 = $indent; @@ -723,13 +708,13 @@ public function precomputed_php_source_table( string $indent = "\t" ): string { $class_version = self::STORAGE_VERSION; - $output = self::class . "::from_precomputed_table(\n"; + $output = self::class . "::from_precomputed_table(\n"; $output .= "{$i1}array(\n"; $output .= "{$i2}\"storage_version\" => \"{$class_version}\",\n"; $output .= "{$i2}\"key_length\" => {$this->key_length},\n"; $group_line = str_replace( "\x00", "\\x00", $this->groups ); - $output .= "{$i2}\"groups\" => \"{$group_line}\",\n"; + $output .= "{$i2}\"groups\" => \"{$group_line}\",\n"; $output .= "{$i2}\"large_words\" => array(\n"; @@ -744,12 +729,12 @@ public function precomputed_php_source_table( string $indent = "\t" ): string { $data_line = "{$i3}\""; $at = 0; while ( $at < $group_length ) { - $token_length = unpack( 'C', $group[ $at ++ ] )[1]; + $token_length = unpack( 'C', $group[ $at++ ] )[1]; $token = substr( $group, $at, $token_length ); - $at += $token_length; - $mapping_length = unpack( 'C', $group[ $at ++ ] )[1]; + $at += $token_length; + $mapping_length = unpack( 'C', $group[ $at++ ] )[1]; $mapping = substr( $group, $at, $mapping_length ); - $at += $mapping_length; + $at += $mapping_length; $token_digits = str_pad( dechex( $token_length ), 2, '0', STR_PAD_LEFT ); $mapping_digits = str_pad( dechex( $mapping_length ), 2, '0', STR_PAD_LEFT ); @@ -766,7 +751,6 @@ static function ( $match_result ) { default: $hex = dechex( ord( $match_result[0] ) ); - return "\\x{$hex}"; } }, @@ -790,11 +774,11 @@ static function ( $match_result ) { $at = 0; while ( $at < $small_length ) { $small_words[] = substr( $this->small_words, $at, $this->key_length + 1 ); - $at += $this->key_length + 1; + $at += $this->key_length + 1; } $small_text = str_replace( "\x00", '\x00', implode( '', $small_words ) ); - $output .= "{$i2}\"small_words\" => \"{$small_text}\",\n"; + $output .= "{$i2}\"small_words\" => \"{$small_text}\",\n"; $output .= "{$i2}\"small_mappings\" => array(\n"; foreach ( $this->small_mappings as $mapping ) { @@ -816,12 +800,11 @@ static function ( $match_result ) { * match. For example, it should not detect `Cap` when matching * against the string `CapitalDifferentialD`. * - * @param string $a First string to compare. - * @param string $b Second string to compare. - * - * @return int -1 or lower if `$a` is less than `$b`; 1 or greater if `$a` is greater than `$b`, and 0 if they are equal. * @since 6.6.0 * + * @param string $a First string to compare. + * @param string $b Second string to compare. + * @return int -1 or lower if `$a` is less than `$b`; 1 or greater if `$a` is greater than `$b`, and 0 if they are equal. */ private static function longest_first_then_alphabetical( string $a, string $b ): int { if ( $a === $b ) { diff --git a/components/HTML/composer.json b/components/HTML/composer.json index d4fc89c0..4595f56b 100644 --- a/components/HTML/composer.json +++ b/components/HTML/composer.json @@ -1,29 +1,33 @@ { - "name": "wordpress/html", - "description": "HTML component for WordPress.", - "type": "library", - "authors": [ - { - "name": "Adam Zielinski", - "email": "adam@adamziel.com" - }, - { - "name": "WordPress Team", - "email": "wordpress@wordpress.org" - } - ], - "require": { - "php": ">=7.2" - }, - "autoload": { - "classmap": [ - "./" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "require-dev": { - "phpunit/phpunit": "^9.5" - } -} + "name": "wordpress\/html", + "description": "HTML component for WordPress.", + "type": "library", + "authors": [ + { + "name": "Adam Zielinski", + "email": "adam@adamziel.com" + }, + { + "name": "WordPress Team", + "email": "wordpress@wordpress.org" + } + ], + "require": { + "php": ">=7.2" + }, + "autoload": { + "psr-4": { + "WordPress\\HTML\\": "." + }, + "classmap": [ + ".\/" + ], + "exclude-from-classmap": [ + "\/Tests\/" + ] + }, + "require-dev": { + "phpunit\/phpunit": "^9.5" + }, + "version": "6.8" +} \ No newline at end of file diff --git a/components/HTML/html5-named-character-references.php b/components/HTML/html5-named-character-references.php index 53b773d6..f57deb90 100644 --- a/components/HTML/html5-named-character-references.php +++ b/components/HTML/html5-named-character-references.php @@ -1,5 +1,7 @@ "6.6.0-trunk", - "key_length" => 2, - "groups" => "AE\x00AM\x00Aa\x00Ab\x00Ac\x00Af\x00Ag\x00Al\x00Am\x00An\x00Ao\x00Ap\x00Ar\x00As\x00At\x00Au\x00Ba\x00Bc\x00Be\x00Bf\x00Bo\x00Br\x00Bs\x00Bu\x00CH\x00CO\x00Ca\x00Cc\x00Cd\x00Ce\x00Cf\x00Ch\x00Ci\x00Cl\x00Co\x00Cr\x00Cs\x00Cu\x00DD\x00DJ\x00DS\x00DZ\x00Da\x00Dc\x00De\x00Df\x00Di\x00Do\x00Ds\x00EN\x00ET\x00Ea\x00Ec\x00Ed\x00Ef\x00Eg\x00El\x00Em\x00Eo\x00Ep\x00Eq\x00Es\x00Et\x00Eu\x00Ex\x00Fc\x00Ff\x00Fi\x00Fo\x00Fs\x00GJ\x00GT\x00Ga\x00Gb\x00Gc\x00Gd\x00Gf\x00Gg\x00Go\x00Gr\x00Gs\x00Gt\x00HA\x00Ha\x00Hc\x00Hf\x00Hi\x00Ho\x00Hs\x00Hu\x00IE\x00IJ\x00IO\x00Ia\x00Ic\x00Id\x00If\x00Ig\x00Im\x00In\x00Io\x00Is\x00It\x00Iu\x00Jc\x00Jf\x00Jo\x00Js\x00Ju\x00KH\x00KJ\x00Ka\x00Kc\x00Kf\x00Ko\x00Ks\x00LJ\x00LT\x00La\x00Lc\x00Le\x00Lf\x00Ll\x00Lm\x00Lo\x00Ls\x00Lt\x00Ma\x00Mc\x00Me\x00Mf\x00Mi\x00Mo\x00Ms\x00Mu\x00NJ\x00Na\x00Nc\x00Ne\x00Nf\x00No\x00Ns\x00Nt\x00Nu\x00OE\x00Oa\x00Oc\x00Od\x00Of\x00Og\x00Om\x00Oo\x00Op\x00Or\x00Os\x00Ot\x00Ou\x00Ov\x00Pa\x00Pc\x00Pf\x00Ph\x00Pi\x00Pl\x00Po\x00Pr\x00Ps\x00QU\x00Qf\x00Qo\x00Qs\x00RB\x00RE\x00Ra\x00Rc\x00Re\x00Rf\x00Rh\x00Ri\x00Ro\x00Rr\x00Rs\x00Ru\x00SH\x00SO\x00Sa\x00Sc\x00Sf\x00Sh\x00Si\x00Sm\x00So\x00Sq\x00Ss\x00St\x00Su\x00TH\x00TR\x00TS\x00Ta\x00Tc\x00Tf\x00Th\x00Ti\x00To\x00Tr\x00Ts\x00Ua\x00Ub\x00Uc\x00Ud\x00Uf\x00Ug\x00Um\x00Un\x00Uo\x00Up\x00Ur\x00Us\x00Ut\x00Uu\x00VD\x00Vb\x00Vc\x00Vd\x00Ve\x00Vf\x00Vo\x00Vs\x00Vv\x00Wc\x00We\x00Wf\x00Wo\x00Ws\x00Xf\x00Xi\x00Xo\x00Xs\x00YA\x00YI\x00YU\x00Ya\x00Yc\x00Yf\x00Yo\x00Ys\x00Yu\x00ZH\x00Za\x00Zc\x00Zd\x00Ze\x00Zf\x00Zo\x00Zs\x00aa\x00ab\x00ac\x00ae\x00af\x00ag\x00al\x00am\x00an\x00ao\x00ap\x00ar\x00as\x00at\x00au\x00aw\x00bN\x00ba\x00bb\x00bc\x00bd\x00be\x00bf\x00bi\x00bk\x00bl\x00bn\x00bo\x00bp\x00br\x00bs\x00bu\x00ca\x00cc\x00cd\x00ce\x00cf\x00ch\x00ci\x00cl\x00co\x00cr\x00cs\x00ct\x00cu\x00cw\x00cy\x00dA\x00dH\x00da\x00db\x00dc\x00dd\x00de\x00df\x00dh\x00di\x00dj\x00dl\x00do\x00dr\x00ds\x00dt\x00du\x00dw\x00dz\x00eD\x00ea\x00ec\x00ed\x00ee\x00ef\x00eg\x00el\x00em\x00en\x00eo\x00ep\x00eq\x00er\x00es\x00et\x00eu\x00ex\x00fa\x00fc\x00fe\x00ff\x00fi\x00fj\x00fl\x00fn\x00fo\x00fp\x00fr\x00fs\x00gE\x00ga\x00gb\x00gc\x00gd\x00ge\x00gf\x00gg\x00gi\x00gj\x00gl\x00gn\x00go\x00gr\x00gs\x00gt\x00gv\x00hA\x00ha\x00hb\x00hc\x00he\x00hf\x00hk\x00ho\x00hs\x00hy\x00ia\x00ic\x00ie\x00if\x00ig\x00ii\x00ij\x00im\x00in\x00io\x00ip\x00iq\x00is\x00it\x00iu\x00jc\x00jf\x00jm\x00jo\x00js\x00ju\x00ka\x00kc\x00kf\x00kg\x00kh\x00kj\x00ko\x00ks\x00lA\x00lB\x00lE\x00lH\x00la\x00lb\x00lc\x00ld\x00le\x00lf\x00lg\x00lh\x00lj\x00ll\x00lm\x00ln\x00lo\x00lp\x00lr\x00ls\x00lt\x00lu\x00lv\x00mD\x00ma\x00mc\x00md\x00me\x00mf\x00mh\x00mi\x00ml\x00mn\x00mo\x00mp\x00ms\x00mu\x00nG\x00nL\x00nR\x00nV\x00na\x00nb\x00nc\x00nd\x00ne\x00nf\x00ng\x00nh\x00ni\x00nj\x00nl\x00nm\x00no\x00np\x00nr\x00ns\x00nt\x00nu\x00nv\x00nw\x00oS\x00oa\x00oc\x00od\x00oe\x00of\x00og\x00oh\x00oi\x00ol\x00om\x00oo\x00op\x00or\x00os\x00ot\x00ou\x00ov\x00pa\x00pc\x00pe\x00pf\x00ph\x00pi\x00pl\x00pm\x00po\x00pr\x00ps\x00pu\x00qf\x00qi\x00qo\x00qp\x00qs\x00qu\x00rA\x00rB\x00rH\x00ra\x00rb\x00rc\x00rd\x00re\x00rf\x00rh\x00ri\x00rl\x00rm\x00rn\x00ro\x00rp\x00rr\x00rs\x00rt\x00ru\x00rx\x00sa\x00sb\x00sc\x00sd\x00se\x00sf\x00sh\x00si\x00sl\x00sm\x00so\x00sp\x00sq\x00sr\x00ss\x00st\x00su\x00sw\x00sz\x00ta\x00tb\x00tc\x00td\x00te\x00tf\x00th\x00ti\x00to\x00tp\x00tr\x00ts\x00tw\x00uA\x00uH\x00ua\x00ub\x00uc\x00ud\x00uf\x00ug\x00uh\x00ul\x00um\x00uo\x00up\x00ur\x00us\x00ut\x00uu\x00uw\x00vA\x00vB\x00vD\x00va\x00vc\x00vd\x00ve\x00vf\x00vl\x00vn\x00vo\x00vp\x00vr\x00vs\x00vz\x00wc\x00we\x00wf\x00wo\x00wp\x00wr\x00ws\x00xc\x00xd\x00xf\x00xh\x00xi\x00xl\x00xm\x00xn\x00xo\x00xr\x00xs\x00xu\x00xv\x00xw\x00ya\x00yc\x00ye\x00yf\x00yi\x00yo\x00ys\x00yu\x00za\x00zc\x00zd\x00ze\x00zf\x00zh\x00zi\x00zo\x00zs\x00zw\x00", - "large_words" => array( + "key_length" => 2, + "groups" => "AE\x00AM\x00Aa\x00Ab\x00Ac\x00Af\x00Ag\x00Al\x00Am\x00An\x00Ao\x00Ap\x00Ar\x00As\x00At\x00Au\x00Ba\x00Bc\x00Be\x00Bf\x00Bo\x00Br\x00Bs\x00Bu\x00CH\x00CO\x00Ca\x00Cc\x00Cd\x00Ce\x00Cf\x00Ch\x00Ci\x00Cl\x00Co\x00Cr\x00Cs\x00Cu\x00DD\x00DJ\x00DS\x00DZ\x00Da\x00Dc\x00De\x00Df\x00Di\x00Do\x00Ds\x00EN\x00ET\x00Ea\x00Ec\x00Ed\x00Ef\x00Eg\x00El\x00Em\x00Eo\x00Ep\x00Eq\x00Es\x00Et\x00Eu\x00Ex\x00Fc\x00Ff\x00Fi\x00Fo\x00Fs\x00GJ\x00GT\x00Ga\x00Gb\x00Gc\x00Gd\x00Gf\x00Gg\x00Go\x00Gr\x00Gs\x00Gt\x00HA\x00Ha\x00Hc\x00Hf\x00Hi\x00Ho\x00Hs\x00Hu\x00IE\x00IJ\x00IO\x00Ia\x00Ic\x00Id\x00If\x00Ig\x00Im\x00In\x00Io\x00Is\x00It\x00Iu\x00Jc\x00Jf\x00Jo\x00Js\x00Ju\x00KH\x00KJ\x00Ka\x00Kc\x00Kf\x00Ko\x00Ks\x00LJ\x00LT\x00La\x00Lc\x00Le\x00Lf\x00Ll\x00Lm\x00Lo\x00Ls\x00Lt\x00Ma\x00Mc\x00Me\x00Mf\x00Mi\x00Mo\x00Ms\x00Mu\x00NJ\x00Na\x00Nc\x00Ne\x00Nf\x00No\x00Ns\x00Nt\x00Nu\x00OE\x00Oa\x00Oc\x00Od\x00Of\x00Og\x00Om\x00Oo\x00Op\x00Or\x00Os\x00Ot\x00Ou\x00Ov\x00Pa\x00Pc\x00Pf\x00Ph\x00Pi\x00Pl\x00Po\x00Pr\x00Ps\x00QU\x00Qf\x00Qo\x00Qs\x00RB\x00RE\x00Ra\x00Rc\x00Re\x00Rf\x00Rh\x00Ri\x00Ro\x00Rr\x00Rs\x00Ru\x00SH\x00SO\x00Sa\x00Sc\x00Sf\x00Sh\x00Si\x00Sm\x00So\x00Sq\x00Ss\x00St\x00Su\x00TH\x00TR\x00TS\x00Ta\x00Tc\x00Tf\x00Th\x00Ti\x00To\x00Tr\x00Ts\x00Ua\x00Ub\x00Uc\x00Ud\x00Uf\x00Ug\x00Um\x00Un\x00Uo\x00Up\x00Ur\x00Us\x00Ut\x00Uu\x00VD\x00Vb\x00Vc\x00Vd\x00Ve\x00Vf\x00Vo\x00Vs\x00Vv\x00Wc\x00We\x00Wf\x00Wo\x00Ws\x00Xf\x00Xi\x00Xo\x00Xs\x00YA\x00YI\x00YU\x00Ya\x00Yc\x00Yf\x00Yo\x00Ys\x00Yu\x00ZH\x00Za\x00Zc\x00Zd\x00Ze\x00Zf\x00Zo\x00Zs\x00aa\x00ab\x00ac\x00ae\x00af\x00ag\x00al\x00am\x00an\x00ao\x00ap\x00ar\x00as\x00at\x00au\x00aw\x00bN\x00ba\x00bb\x00bc\x00bd\x00be\x00bf\x00bi\x00bk\x00bl\x00bn\x00bo\x00bp\x00br\x00bs\x00bu\x00ca\x00cc\x00cd\x00ce\x00cf\x00ch\x00ci\x00cl\x00co\x00cr\x00cs\x00ct\x00cu\x00cw\x00cy\x00dA\x00dH\x00da\x00db\x00dc\x00dd\x00de\x00df\x00dh\x00di\x00dj\x00dl\x00do\x00dr\x00ds\x00dt\x00du\x00dw\x00dz\x00eD\x00ea\x00ec\x00ed\x00ee\x00ef\x00eg\x00el\x00em\x00en\x00eo\x00ep\x00eq\x00er\x00es\x00et\x00eu\x00ex\x00fa\x00fc\x00fe\x00ff\x00fi\x00fj\x00fl\x00fn\x00fo\x00fp\x00fr\x00fs\x00gE\x00ga\x00gb\x00gc\x00gd\x00ge\x00gf\x00gg\x00gi\x00gj\x00gl\x00gn\x00go\x00gr\x00gs\x00gt\x00gv\x00hA\x00ha\x00hb\x00hc\x00he\x00hf\x00hk\x00ho\x00hs\x00hy\x00ia\x00ic\x00ie\x00if\x00ig\x00ii\x00ij\x00im\x00in\x00io\x00ip\x00iq\x00is\x00it\x00iu\x00jc\x00jf\x00jm\x00jo\x00js\x00ju\x00ka\x00kc\x00kf\x00kg\x00kh\x00kj\x00ko\x00ks\x00lA\x00lB\x00lE\x00lH\x00la\x00lb\x00lc\x00ld\x00le\x00lf\x00lg\x00lh\x00lj\x00ll\x00lm\x00ln\x00lo\x00lp\x00lr\x00ls\x00lt\x00lu\x00lv\x00mD\x00ma\x00mc\x00md\x00me\x00mf\x00mh\x00mi\x00ml\x00mn\x00mo\x00mp\x00ms\x00mu\x00nG\x00nL\x00nR\x00nV\x00na\x00nb\x00nc\x00nd\x00ne\x00nf\x00ng\x00nh\x00ni\x00nj\x00nl\x00nm\x00no\x00np\x00nr\x00ns\x00nt\x00nu\x00nv\x00nw\x00oS\x00oa\x00oc\x00od\x00oe\x00of\x00og\x00oh\x00oi\x00ol\x00om\x00oo\x00op\x00or\x00os\x00ot\x00ou\x00ov\x00pa\x00pc\x00pe\x00pf\x00ph\x00pi\x00pl\x00pm\x00po\x00pr\x00ps\x00pu\x00qf\x00qi\x00qo\x00qp\x00qs\x00qu\x00rA\x00rB\x00rH\x00ra\x00rb\x00rc\x00rd\x00re\x00rf\x00rh\x00ri\x00rl\x00rm\x00rn\x00ro\x00rp\x00rr\x00rs\x00rt\x00ru\x00rx\x00sa\x00sb\x00sc\x00sd\x00se\x00sf\x00sh\x00si\x00sl\x00sm\x00so\x00sp\x00sq\x00sr\x00ss\x00st\x00su\x00sw\x00sz\x00ta\x00tb\x00tc\x00td\x00te\x00tf\x00th\x00ti\x00to\x00tp\x00tr\x00ts\x00tw\x00uA\x00uH\x00ua\x00ub\x00uc\x00ud\x00uf\x00ug\x00uh\x00ul\x00um\x00uo\x00up\x00ur\x00us\x00ut\x00uu\x00uw\x00vA\x00vB\x00vD\x00va\x00vc\x00vd\x00ve\x00vf\x00vl\x00vn\x00vo\x00vp\x00vr\x00vs\x00vz\x00wc\x00we\x00wf\x00wo\x00wp\x00wr\x00ws\x00xc\x00xd\x00xf\x00xh\x00xi\x00xl\x00xm\x00xn\x00xo\x00xr\x00xs\x00xu\x00xv\x00xw\x00ya\x00yc\x00ye\x00yf\x00yi\x00yo\x00ys\x00yu\x00za\x00zc\x00zd\x00ze\x00zf\x00zh\x00zi\x00zo\x00zs\x00zw\x00", + "large_words" => array( // AElig;[Γ†] AElig[Γ†]. "\x04lig;\x02Γ†\x03lig\x02Γ†", // AMP;[&] AMP[&]. @@ -1302,12 +1304,12 @@ // zwnj;[β€Œ] zwj;[‍]. "\x03nj;\x03β€Œ\x02j;\x03‍", ), - "small_words" => "GT\x00LT\x00gt\x00lt\x00", - "small_mappings" => array( + "small_words" => "GT\x00LT\x00gt\x00lt\x00", + "small_mappings" => array( ">", "<", ">", "<", - ), + ) ) ); diff --git a/components/HttpClient/Middleware/HttpMiddleware.php b/components/HttpClient/Middleware/HttpMiddleware.php index b86e13ee..a5835ece 100644 --- a/components/HttpClient/Middleware/HttpMiddleware.php +++ b/components/HttpClient/Middleware/HttpMiddleware.php @@ -4,13 +4,12 @@ use WordPress\HttpClient\Client; use WordPress\HttpClient\ClientState; -use WordPress\HttpClient\HttpClientException; use WordPress\HttpClient\Request; use WordPress\HttpClient\Connection; -use WordPress\HttpClient\Transport\CurlTransport; -use WordPress\HttpClient\Transport\SocketTransport; use WordPress\HttpClient\Transport\TransportInterface; +use function WordPress\Polyfill\apply_filters; + class HttpMiddleware implements MiddlewareInterface { const EVENT_GOT_HEADERS = 'EVENT_GOT_HEADERS'; diff --git a/components/Markdown/MarkdownConsumer.php b/components/Markdown/MarkdownConsumer.php index 7a8dcecb..128aced1 100644 --- a/components/Markdown/MarkdownConsumer.php +++ b/components/Markdown/MarkdownConsumer.php @@ -18,7 +18,7 @@ use WordPress\DataLiberation\DataFormatConsumer\BlocksWithMetadata; use WordPress\DataLiberation\DataFormatConsumer\DataFormatConsumer; use WordPress\DataLiberation\Importer\ImportUtils; -use WP_HTML_Tag_Processor; +use WordPress\HTML\WP_HTML_Tag_Processor; /** * Transforms markdown with frontmatter into a block markup and metadata pair. diff --git a/components/Markdown/MarkdownImporter.php b/components/Markdown/MarkdownImporter.php index 405adfea..a5d34b12 100644 --- a/components/Markdown/MarkdownImporter.php +++ b/components/Markdown/MarkdownImporter.php @@ -7,6 +7,8 @@ use WordPress\DataLiberation\Importer\StreamImporter; use WordPress\Filesystem\LocalFilesystem; +use function WordPress\Polyfill\_doing_it_wrong; + class MarkdownImporter extends StreamImporter { public static function create_for_markdown_directory( $markdown_directory, $options = array(), $cursor = null ) { diff --git a/components/Markdown/MarkdownProducer.php b/components/Markdown/MarkdownProducer.php index a1b9c511..6b8f3d9b 100644 --- a/components/Markdown/MarkdownProducer.php +++ b/components/Markdown/MarkdownProducer.php @@ -5,6 +5,8 @@ use WordPress\DataLiberation\DataFormatConsumer\BlocksWithMetadata; use WordPress\DataLiberation\DataFormatProducer\DataFormatProducer; use WordPress\DataLiberation\DataLiberationHTMLProcessor; +use function WordPress\Polyfill\parse_blocks; +use function WordPress\Polyfill\serialize_block; /** * Converts WordPress blocks and metadata to Markdown with frontmatter. @@ -283,7 +285,7 @@ function ( $cell, $width ) { $markdown = array(); $markdown[] = ''; $markdown[] = '```block'; - $markdown[] = \serialize_block( $block ); + $markdown[] = serialize_block( $block ); $markdown[] = '```'; $markdown[] = ''; return implode( "\n", $markdown ); diff --git a/components/Markdown/Tests/MarkdownConsumerTest.php b/components/Markdown/Tests/MarkdownConsumerTest.php index 1283d72f..15bc9a33 100644 --- a/components/Markdown/Tests/MarkdownConsumerTest.php +++ b/components/Markdown/Tests/MarkdownConsumerTest.php @@ -67,7 +67,7 @@ public function test_markdown_to_blocks_conversion( $markdown, $expected ) { } private function normalize_markup( $markup ) { - $processor = WP_HTML_Processor::create_fragment( $markup ); + $processor = \WordPress\HTML\WP_HTML_Processor::create_fragment( $markup ); $serialized = $processor->serialize(); $serialized = trim( str_replace( diff --git a/components/Merge/Validate/BlockMarkupMergeValidator.php b/components/Merge/Validate/BlockMarkupMergeValidator.php index ca17be17..9ff62238 100644 --- a/components/Merge/Validate/BlockMarkupMergeValidator.php +++ b/components/Merge/Validate/BlockMarkupMergeValidator.php @@ -4,7 +4,7 @@ use ReflectionClass; use WordPress\DataLiberation\BlockMarkup\BlockMarkupProcessor; -use WP_HTML_Processor; +use WordPress\HTML\WP_HTML_Processor; class BlockMarkupMergeValidator implements MergeValidator { @@ -55,7 +55,7 @@ public function validate( $html ) { private function assert_html_is_structurally_sound( $html ) { $html .= ''; - $html_processor = WP_HTML_Processor::create_fragment( $html ); + $html_processor = \WordPress\HTML\WP_HTML_Processor::create_fragment( $html ); /** * Make the is_virtual() method public to enable deeper inspection. diff --git a/components/Polyfill/wordpress.php b/components/Polyfill/wordpress.php index 5bc8773c..7084c089 100644 --- a/components/Polyfill/wordpress.php +++ b/components/Polyfill/wordpress.php @@ -2,7 +2,10 @@ /** * Polyfills WordPress core functions for running in non-WordPress environments */ +namespace WordPress\Polyfill; +// This may be loaded twice if Polyfills are included before WordPress, but that's fine. +// There are no function declarations in that file, only a global variable. if ( ! isset( $html5_named_character_references ) && file_exists( __DIR__ . '/../HTML/html5-named-character-references.php' ) @@ -10,213 +13,233 @@ require_once __DIR__ . '/../HTML/html5-named-character-references.php'; } +// @TODO: Wrap in namespaces before merging: if ( ! class_exists( 'WP_Block_Parser' ) ) { require_once __DIR__ . '/../BlockParser/class-wp-block-parser-block.php'; require_once __DIR__ . '/../BlockParser/class-wp-block-parser-frame.php'; require_once __DIR__ . '/../BlockParser/class-wp-block-parser.php'; } -if ( ! function_exists( '_doing_it_wrong' ) ) { - $GLOBALS['_doing_it_wrong_messages'] = array(); - function _doing_it_wrong( $method, $message, $version ) { - $GLOBALS['_doing_it_wrong_messages'][] = $message; +$GLOBALS['_doing_it_wrong_messages'] = array(); +function _doing_it_wrong( $method, $message, $version ) { + if ( function_exists( '\\_doing_it_wrong' ) ) { + return call_user_func_array( '\\_doing_it_wrong', func_get_args() ); } + $GLOBALS['_doing_it_wrong_messages'][] = $message; } -if ( ! class_exists( 'WP_Exception' ) ) { - class WP_Exception extends Exception { +function wp_trigger_error( $function_name, $message, $error_level = E_USER_NOTICE ) { + if ( function_exists( '\\wp_trigger_error' ) ) { + return call_user_func_array( '\\wp_trigger_error', func_get_args() ); } -} -if ( ! function_exists( 'wp_trigger_error' ) ) { - function wp_trigger_error( $function_name, $message, $error_level = E_USER_NOTICE ) { - if ( ! empty( $function_name ) ) { - $message = sprintf( '%s(): %s', $function_name, $message ); - } + if ( ! empty( $function_name ) ) { + $message = sprintf( '%s(): %s', $function_name, $message ); + } - if ( E_USER_ERROR === $error_level ) { - throw new WP_Exception( $message ); + if ( E_USER_ERROR === $error_level ) { + if ( ! class_exists( '\WP_Exception' ) ) { + class WP_Exception extends \Exception { + } } - - trigger_error( $message, $error_level ); + throw new WP_Exception( $message ); } + + trigger_error( $message, $error_level ); } -if ( ! function_exists( 'wp_kses_uri_attributes' ) ) { - function wp_kses_uri_attributes() { - return array(); +function wp_kses_uri_attributes() { + if ( function_exists( '\\wp_kses_uri_attributes' ) ) { + return call_user_func_array( '\\wp_kses_uri_attributes', func_get_args() ); } + return array(); } -if ( ! function_exists( '__' ) ) { - function __( $input ) { - return $input; +function __( $input ) { + if ( function_exists( '\\__' ) ) { + return call_user_func_array( '\\__', func_get_args() ); } + return $input; } -if ( ! function_exists( 'esc_attr' ) ) { - function esc_attr( $input ) { - return htmlspecialchars( $input ); +function esc_attr( $input ) { + if ( function_exists( '\\esc_attr' ) ) { + return call_user_func_array( '\\esc_attr', func_get_args() ); } + return htmlspecialchars( $input ); } -if ( ! function_exists( 'esc_html' ) ) { - function esc_html( $input ) { - return htmlspecialchars( $input ); +function esc_html( $input ) { + if ( function_exists( '\\esc_html' ) ) { + return call_user_func_array( '\\esc_html', func_get_args() ); } + return htmlspecialchars( $input ); } -if ( ! function_exists( 'esc_url' ) ) { - function esc_url( $url ) { - return htmlspecialchars( $url ); +function esc_url( $url ) { + if ( function_exists( '\\esc_url' ) ) { + return call_user_func_array( '\\esc_url', func_get_args() ); } + return htmlspecialchars( $url ); } -if ( ! function_exists( 'add_filter' ) ) { - function add_filter( $hook_name, $callback, $priority = 10, $accepted_args = 1 ) { - global $wp_filter; - if ( ! isset( $wp_filter ) ) { - $wp_filter = array(); - } - if ( ! isset( $wp_filter[ $hook_name ] ) ) { - $wp_filter[ $hook_name ] = array(); - } - if ( ! isset( $wp_filter[ $hook_name ][ $priority ] ) ) { - $wp_filter[ $hook_name ][ $priority ] = array(); - } - $wp_filter[ $hook_name ][ $priority ][] = array( - 'function' => $callback, - 'accepted_args' => $accepted_args, - ); +function add_filter( $hook_name, $callback, $priority = 10, $accepted_args = 1 ) { + global $wp_filter; + if ( function_exists( '\\add_filter' ) ) { + return call_user_func_array( '\\add_filter', func_get_args() ); + } - return true; + if ( ! isset( $wp_filter ) ) { + $wp_filter = array(); + } + if ( ! isset( $wp_filter[ $hook_name ] ) ) { + $wp_filter[ $hook_name ] = array(); + } + if ( ! isset( $wp_filter[ $hook_name ][ $priority ] ) ) { + $wp_filter[ $hook_name ][ $priority ] = array(); } + $wp_filter[ $hook_name ][ $priority ][] = array( + 'function' => $callback, + 'accepted_args' => $accepted_args, + ); + + return true; } -if ( ! function_exists( 'add_action' ) ) { - function add_action( $hook_name, $callback, $priority = 10, $accepted_args = 1 ) { - return add_filter( $hook_name, $callback, $priority, $accepted_args ); +function add_action( $hook_name, $callback, $priority = 10, $accepted_args = 1 ) { + if ( function_exists( '\\add_action' ) ) { + return call_user_func_array( '\\add_action', func_get_args() ); } + return add_filter( $hook_name, $callback, $priority, $accepted_args ); } -if ( ! function_exists( 'apply_filters' ) ) { - function apply_filters( $hook_name, $value ) { - global $wp_filter; - if ( ! isset( $wp_filter[ $hook_name ] ) ) { - return $value; - } - $args = func_get_args(); - array_shift( $args ); // Remove hook name - - ksort( $wp_filter[ $hook_name ] ); - foreach ( $wp_filter[ $hook_name ] as $priority => $functions ) { - foreach ( $functions as $function ) { - $args[0] = $value; - $value = call_user_func_array( $function['function'], array_slice( $args, 0, $function['accepted_args'] ) ); - } - } +function apply_filters( $hook_name, $value ) { + global $wp_filter; + if ( function_exists( '\\apply_filters' ) ) { + return call_user_func_array( '\\apply_filters', func_get_args() ); + } + if ( ! isset( $wp_filter[ $hook_name ] ) ) { return $value; } -} + $args = func_get_args(); + array_shift( $args ); // Remove hook name -if ( ! function_exists( 'do_action' ) ) { - function do_action( $hook_name ) { - global $wp_filter; - if ( ! isset( $wp_filter[ $hook_name ] ) ) { - return; - } - $args = func_get_args(); - array_shift( $args ); // Remove hook name - - ksort( $wp_filter[ $hook_name ] ); - foreach ( $wp_filter[ $hook_name ] as $priority => $functions ) { - foreach ( $functions as $function ) { - call_user_func_array( $function['function'], array_slice( $args, 0, $function['accepted_args'] ) ); - } + ksort( $wp_filter[ $hook_name ] ); + foreach ( $wp_filter[ $hook_name ] as $priority => $functions ) { + foreach ( $functions as $function ) { + $args[0] = $value; + $value = call_user_func_array( $function['function'], array_slice( $args, 0, $function['accepted_args'] ) ); } } + + return $value; } -if ( ! function_exists( 'parse_blocks' ) ) { - function parse_blocks( $input ) { - $parser = new WP_Block_Parser(); +function do_action( $hook_name ) { + global $wp_filter; + if ( function_exists( '\\do_action' ) ) { + return call_user_func_array( '\\do_action', func_get_args() ); + } - return $parser->parse( $input ); + if ( ! isset( $wp_filter[ $hook_name ] ) ) { + return; } -} + $args = func_get_args(); + array_shift( $args ); // Remove hook name -if ( ! function_exists( 'serialize_blocks' ) ) { - function serialize_blocks( $blocks ) { - return implode( '', array_map( 'serialize_block', $blocks ) ); + ksort( $wp_filter[ $hook_name ] ); + foreach ( $wp_filter[ $hook_name ] as $priority => $functions ) { + foreach ( $functions as $function ) { + call_user_func_array( $function['function'], array_slice( $args, 0, $function['accepted_args'] ) ); + } } } -if ( ! function_exists( 'serialize_block' ) ) { - function serialize_block( $block ) { - $block_content = ''; - - $index = 0; - foreach ( $block['innerContent'] as $chunk ) { - $block_content .= is_string( $chunk ) ? $chunk : serialize_block( $block['innerBlocks'][ $index ++ ] ); - } +function parse_blocks( $input ) { + if ( function_exists( '\\parse_blocks' ) ) { + return call_user_func_array( '\\parse_blocks', func_get_args() ); + } + $parser = new \WordPress\BlockParser\WP_Block_Parser(); - if ( ! is_array( $block['attrs'] ) ) { - $block['attrs'] = array(); - } + return $parser->parse( $input ); +} - return get_comment_delimited_block_content( - $block['blockName'], - $block['attrs'], - $block_content - ); +function serialize_blocks( $blocks ) { + if ( function_exists( '\\serialize_blocks' ) ) { + return call_user_func_array( '\\serialize_blocks', func_get_args() ); } + return implode( '', array_map( 'serialize_block', $blocks ) ); } -if ( ! function_exists( 'get_comment_delimited_block_content' ) ) { - function get_comment_delimited_block_content( $block_name, $block_attributes, $block_content ) { - if ( is_null( $block_name ) ) { - return $block_content; - } - - $serialized_block_name = strip_core_block_namespace( $block_name ); - $serialized_attributes = empty( $block_attributes ) ? '' : serialize_block_attributes( $block_attributes ) . ' '; +function serialize_block( $block ) { + if ( function_exists( '\\serialize_block' ) ) { + return call_user_func_array( '\\serialize_block', func_get_args() ); + } + $block_content = ''; - if ( empty( $block_content ) ) { - return sprintf( '', $serialized_block_name, $serialized_attributes ); - } + $index = 0; + foreach ( $block['innerContent'] as $chunk ) { + $block_content .= is_string( $chunk ) ? $chunk : serialize_block( $block['innerBlocks'][ $index ++ ] ); + } - return sprintf( - '%s', - $serialized_block_name, - $serialized_attributes, - $block_content, - $serialized_block_name - ); + if ( ! is_array( $block['attrs'] ) ) { + $block['attrs'] = array(); } + + return get_comment_delimited_block_content( + $block['blockName'], + $block['attrs'], + $block_content + ); } -if ( ! function_exists( 'strip_core_block_namespace' ) ) { - function strip_core_block_namespace( $block_name = null ) { - if ( is_string( $block_name ) && strncmp( $block_name, 'core/', strlen( 'core/' ) ) === 0 ) { - return substr( $block_name, 5 ); - } +function get_comment_delimited_block_content( $block_name, $block_attributes, $block_content ) { + if ( function_exists( '\\get_comment_delimited_block_content' ) ) { + return call_user_func_array( '\\get_comment_delimited_block_content', func_get_args() ); + } + if ( is_null( $block_name ) ) { + return $block_content; + } + + $serialized_block_name = strip_core_block_namespace( $block_name ); + $serialized_attributes = empty( $block_attributes ) ? '' : serialize_block_attributes( $block_attributes ) . ' '; - return $block_name; + if ( empty( $block_content ) ) { + return sprintf( '', $serialized_block_name, $serialized_attributes ); } + + return sprintf( + '%s', + $serialized_block_name, + $serialized_attributes, + $block_content, + $serialized_block_name + ); } +function strip_core_block_namespace( $block_name = null ) { + if ( function_exists( '\\strip_core_block_namespace' ) ) { + return call_user_func_array( '\\strip_core_block_namespace', func_get_args() ); + } + if ( is_string( $block_name ) && strncmp( $block_name, 'core/', strlen( 'core/' ) ) === 0 ) { + return substr( $block_name, 5 ); + } -if ( ! function_exists( 'serialize_block_attributes' ) ) { - function serialize_block_attributes( $block_attributes ) { - $encoded_attributes = json_encode( $block_attributes, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); - $encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes ); - $encoded_attributes = preg_replace( '//', '\\u003e', $encoded_attributes ); - $encoded_attributes = preg_replace( '/&/', '\\u0026', $encoded_attributes ); - // Regex: /\\"/ - $encoded_attributes = preg_replace( '/\\\\"/', '\\u0022', $encoded_attributes ); + return $block_name; +} - return $encoded_attributes; +function serialize_block_attributes( $block_attributes ) { + if ( function_exists( '\\serialize_block_attributes' ) ) { + return call_user_func_array( '\\serialize_block_attributes', func_get_args() ); } + $encoded_attributes = json_encode( $block_attributes, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); + $encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes ); + $encoded_attributes = preg_replace( '//', '\\u003e', $encoded_attributes ); + $encoded_attributes = preg_replace( '/&/', '\\u0026', $encoded_attributes ); + // Regex: /\\"/ + $encoded_attributes = preg_replace( '/\\\\"/', '\\u0022', $encoded_attributes ); + + return $encoded_attributes; } diff --git a/components/XML/Tests/XMLProcessorTest.php b/components/XML/Tests/XMLProcessorTest.php index cf20183e..3b00ca2d 100644 --- a/components/XML/Tests/XMLProcessorTest.php +++ b/components/XML/Tests/XMLProcessorTest.php @@ -1486,7 +1486,7 @@ public function __construct( $xml ) { */ public function insert_after( $new_xml ) { $this->set_bookmark( 'here' ); - $this->lexical_updates[] = new WP_HTML_Text_Replacement( + $this->lexical_updates[] = new \WordPress\HTML\WP_HTML_Text_Replacement( $this->bookmarks['here']->start + $this->bookmarks['here']->length, 0, $new_xml diff --git a/components/XML/XMLDecoder.php b/components/XML/XMLDecoder.php index a68f7bdf..524b28b8 100644 --- a/components/XML/XMLDecoder.php +++ b/components/XML/XMLDecoder.php @@ -2,7 +2,7 @@ namespace WordPress\XML; -use WP_HTML_Decoder; +use WordPress\HTML\WP_HTML_Decoder; /** * XML API: WP_XML_Decoder class diff --git a/components/XML/XMLProcessor.php b/components/XML/XMLProcessor.php index 3f70f707..639a8165 100644 --- a/components/XML/XMLProcessor.php +++ b/components/XML/XMLProcessor.php @@ -2,10 +2,12 @@ namespace WordPress\XML; -use WP_HTML_Span; -use WP_HTML_Text_Replacement; +use WordPress\HTML\WP_HTML_Span; +use WordPress\HTML\WP_HTML_Text_Replacement; use function WordPress\Encoding\utf8_codepoint_at; +use function WordPress\Polyfill\_doing_it_wrong; +use function WordPress\Polyfill\__; /** * XML API: XMLProcessor class @@ -624,7 +626,7 @@ class XMLProcessor { * // sourced from the lazily-parsed XML recognizer. * $start = $attributes['src']->start; * $length = $attributes['src']->length; - * $modifications[] = new WP_HTML_Text_Replacement( $start, $length, $new_value ); + * $modifications[] = new \WordPress\HTML\WP_HTML_Text_Replacement( $start, $length, $new_value ); * * // Correspondingly, something like this will appear in this array. * $lexical_updates = array( @@ -3491,7 +3493,7 @@ public function set_modifiable_text( $new_value ) { switch ( $this->parser_state ) { case self::STATE_TEXT_NODE: case self::STATE_COMMENT: - $this->lexical_updates[] = new WP_HTML_Text_Replacement( + $this->lexical_updates[] = new \WordPress\HTML\WP_HTML_Text_Replacement( $this->text_starts_at, $this->text_length, // @TODO: Audit this in details. Is this too naive? Or is it actually safe? @@ -3501,7 +3503,7 @@ public function set_modifiable_text( $new_value ) { return true; case self::STATE_CDATA_NODE: - $this->lexical_updates[] = new WP_HTML_Text_Replacement( + $this->lexical_updates[] = new \WordPress\HTML\WP_HTML_Text_Replacement( $this->text_starts_at, $this->text_length, // @TODO: Audit this in details. Is this too naive? Or is it actually safe? @@ -3598,7 +3600,7 @@ public function set_attribute( $namespace, $local_name, $value ) { * Result: */ $existing_attribute = $this->attributes[ $name ]; - $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( + $this->lexical_updates[ $name ] = new \WordPress\HTML\WP_HTML_Text_Replacement( $existing_attribute->start, $existing_attribute->length, $updated_attribute @@ -3616,7 +3618,7 @@ public function set_attribute( $namespace, $local_name, $value ) { * * Result: */ - $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( + $this->lexical_updates[ $name ] = new \WordPress\HTML\WP_HTML_Text_Replacement( $this->tag_name_starts_at + $this->tag_name_length, 0, ' ' . $updated_attribute @@ -3673,7 +3675,7 @@ public function remove_attribute( $namespace, $local_name ) { * * Result: */ - $this->lexical_updates[ $name ] = new WP_HTML_Text_Replacement( + $this->lexical_updates[ $name ] = new \WordPress\HTML\WP_HTML_Text_Replacement( $this->attributes[ $name ]->start, $this->attributes[ $name ]->length, '' @@ -4474,5 +4476,5 @@ private function bail( string $message, $reason = self::ERROR_UNSUPPORTED ) { * * @access private */ - const CONSTRUCTOR_UNLOCK_CODE = 'Use WP_HTML_Processor::create_fragment() instead of calling the class constructor directly.'; + const CONSTRUCTOR_UNLOCK_CODE = 'Use \WordPress\HTML\WP_HTML_Processor::create_fragment() instead of calling the class constructor directly.'; } diff --git a/composer.json b/composer.json index 51f88cf0..c87ad316 100644 --- a/composer.json +++ b/composer.json @@ -69,7 +69,9 @@ "WordPress\\Zip\\": "components/Zip/", "WordPress\\HttpServer\\": "components/HttpServer/", "WordPress\\CORSProxy\\": "components/CORSProxy/", - "WordPress\\Git\\": "components/Git/" + "WordPress\\Git\\": "components/Git/", + "WordPress\\HTML\\": "components/HTML/", + "WordPress\\BlockParser\\": "components/BlockParser/" } }, "scripts": { diff --git a/examples/create-wp-site/import-markdown-directory.php b/examples/create-wp-site/import-markdown-directory.php index 348737a2..27c6f805 100644 --- a/examples/create-wp-site/import-markdown-directory.php +++ b/examples/create-wp-site/import-markdown-directory.php @@ -19,6 +19,8 @@ use function WordPress\DataLiberation\URL\is_child_url_of; use function WordPress\Filesystem\wp_join_unix_paths; +use function WordPress\Polyfill\add_action; +use function WordPress\Polyfill\add_filter; if ( file_exists( '/wordpress/wp-load.php' ) ) { require_once '/wordpress/wp-load.php'; diff --git a/plugins/static-files-editor/plugin.php b/plugins/static-files-editor/plugin.php index fc954dba..dfd713e5 100644 --- a/plugins/static-files-editor/plugin.php +++ b/plugins/static-files-editor/plugin.php @@ -1072,7 +1072,7 @@ private static function parse_local_file( $content, $format ) { break; case 'html': $converter = new AnnotatedBlockMarkupConsumer( - WP_HTML_Processor::create_fragment( $content ) + \WordPress\HTML\WP_HTML_Processor::create_fragment( $content ) ); break; case 'md':