Skip to content

Commit

Permalink
HTML API: Add get_full_comment_text() method.
Browse files Browse the repository at this point in the history
Previously, there were a few cases where the modifiable text read from an HTML comment differs slightly from the parsed value of its inner text in a browser. This is due to the specific way that invalid HTML syntax tokens become "bogus comments."

This patch introduces a new method to the Tag Processor to allow differentiating these specific cases, such as when copying or serializing HTML from one source to another. Similar code has already been in use in the html5lib tests, and this patch simplifies the test runner, evidencing the fact that this method was already needed.

Developed in #7342
Discussed in https://core.trac.wordpress.org/ticket/62036

Props dmsnell, jonsurrell.
See #62036.


git-svn-id: https://develop.svn.wordpress.org/trunk@59075 602fd350-edb4-49c9-b593-d223f7449a82
  • Loading branch information
dmsnell committed Sep 20, 2024
1 parent 1eb5f61 commit 675a1aa
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 33 deletions.
52 changes: 52 additions & 0 deletions src/wp-includes/html-api/class-wp-html-tag-processor.php
Original file line number Diff line number Diff line change
Expand Up @@ -3385,6 +3385,58 @@ public function get_comment_type(): ?string {
return $this->comment_type;
}

/**
* Returns the text of a matched comment or null if not on a comment type node.
*
* This method returns the entire text content of a comment node as it
* would appear in the browser.
*
* This differs from {@see ::get_modifiable_text()} in that certain comment
* types in the HTML API cannot allow their entire comment text content to
* be modified. Namely, "bogus comments" of the form `<?not allowed in html>`
* will create a comment whose text content starts with `?`. Note that if
* that character were modified, it would be possible to change the node
* type.
*
* @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 ) {
return $this->get_modifiable_text();
}

if ( self::STATE_COMMENT !== $this->parser_state ) {
return null;
}

switch ( $this->get_comment_type() ) {
case self::COMMENT_AS_HTML_COMMENT:
case self::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT:
return $this->get_modifiable_text();

case self::COMMENT_AS_CDATA_LOOKALIKE:
return "[CDATA[{$this->get_modifiable_text()}]]";

case self::COMMENT_AS_PI_NODE_LOOKALIKE:
return "?{$this->get_tag()}{$this->get_modifiable_text()}?";

/*
* This represents "bogus comments state" from HTML tokenization.
* This can be entered by `<?` or `<!`, where `?` is included in
* the comment text but `!` is not.
*/
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()}";
}

return null;
}

/**
* Subdivides a matched text node, splitting NULL byte sequences and decoded whitespace as
* distinct nodes prefixes.
Expand Down
45 changes: 12 additions & 33 deletions tests/phpunit/tests/html-api/wpHtmlProcessorHtml5lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,17 @@ class Tests_HtmlApi_Html5lib extends WP_UnitTestCase {
* Skip specific tests that may not be supported or have known issues.
*/
const SKIP_TESTS = array(
'comments01/line0155' => 'Unimplemented: Need to access raw comment text on non-normative comments.',
'comments01/line0169' => 'Unimplemented: Need to access raw comment text on non-normative comments.',
'html5test-com/line0129' => 'Unimplemented: Need to access raw comment text on non-normative comments.',
'noscript01/line0014' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests14/line0022' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests14/line0055' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests19/line0488' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests19/line0500' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests19/line1079' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0207' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0686' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0697' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0709' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'webkit01/line0231' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'noscript01/line0014' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests14/line0022' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests14/line0055' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests19/line0488' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests19/line0500' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests19/line1079' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0207' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0686' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0697' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'tests2/line0709' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
'webkit01/line0231' => 'Unimplemented: This parser does not add missing attributes to existing HTML or BODY tags.',
);

/**
Expand Down Expand Up @@ -315,26 +312,8 @@ static function ( $a, $b ) {
break;

case '#comment':
switch ( $processor->get_comment_type() ) {
case WP_HTML_Processor::COMMENT_AS_ABRUPTLY_CLOSED_COMMENT:
case WP_HTML_Processor::COMMENT_AS_HTML_COMMENT:
case WP_HTML_Processor::COMMENT_AS_INVALID_HTML:
$comment_text_content = $processor->get_modifiable_text();
break;

case WP_HTML_Processor::COMMENT_AS_CDATA_LOOKALIKE:
$comment_text_content = "[CDATA[{$processor->get_modifiable_text()}]]";
break;

case WP_HTML_Processor::COMMENT_AS_PI_NODE_LOOKALIKE:
$comment_text_content = "?{$processor->get_tag()}{$processor->get_modifiable_text()}?";
break;

default:
throw new Error( "Unhandled comment type for tree construction: {$processor->get_comment_type()}" );
}
// Comments must be "<" then "!-- " then the data then " -->".
$output .= str_repeat( self::TREE_INDENT, $indent_level ) . "<!-- {$comment_text_content} -->\n";
$output .= str_repeat( self::TREE_INDENT, $indent_level ) . "<!-- {$processor->get_full_comment_text()} -->\n";
break;

default:
Expand Down

0 comments on commit 675a1aa

Please sign in to comment.