Use Remex/HtmlHelper to implement Parser::replaceTableOfContents

This is more robust and secure than the regular expression previously
used to extract the <meta> tag.

We also improve HtmlHelper slightly be adding the ability to replace
an element with an 'outerHTML' string.

Because our output is being run through Remex, there is a slightly
larger degree of HTML normalization in the output than previously,
which is visible in some small tweaks to test case outputs.

Bug: T381617
Depends-On: I2712e0fa9272106e8cd686980f847ee7f6385b6f
Change-Id: I4cb2f29cf890af90f295624c586d9e1eb1939b95
(cherry picked from commit 7ebd8034b54495f28f4c5583d4fa55071634b593)
This commit is contained in:
C. Scott Ananian 2024-12-06 15:53:20 -05:00 committed by jenkins-bot
parent 1f51ebac15
commit a6739e066e
11 changed files with 49 additions and 47 deletions

View file

@ -23,7 +23,8 @@ class HtmlHelper {
* RemexHtml\Serializer\SerializerNode argument, and returns true if it should be modified.
* @param callable $modifyCallback A callback which takes a single
* RemexHtml\Serializer\SerializerNode argument and actually performs the modification on it.
* It must return the new node (which can be the original node object).
* It must return the new node (which can be the original node object)
* or a string, which is treated as the outerHTML of a replacement.
* @param bool $html5format Defaults to true, which uses standard HTML5
* serialization for the parsed HTML. If set to false, uses a
* serialization which is more compatible with the output of the

View file

@ -34,7 +34,11 @@ trait HtmlHelperTrait {
$node = clone $node;
$node->attrs = clone $node->attrs;
$newNode = ( $this->modifyCallback )( $node );
Assert::parameterType( SerializerNode::class, $newNode, 'return value' );
Assert::parameterType( [ SerializerNode::class, 'string' ], $newNode, 'return value' );
if ( is_string( $newNode ) ) {
// Replace this element with an "outerHTML" string.
return $newNode;
}
return parent::element( $parent, $newNode, $contents );
} else {
return parent::element( $parent, $node, $contents );

View file

@ -42,6 +42,7 @@ use MediaWiki\Debug\DeprecationHelper;
use MediaWiki\HookContainer\HookContainer;
use MediaWiki\HookContainer\HookRunner;
use MediaWiki\Html\Html;
use MediaWiki\Html\HtmlHelper;
use MediaWiki\Http\HttpRequestFactory;
use MediaWiki\Language\ILanguageConverter;
use MediaWiki\Language\Language;
@ -97,6 +98,7 @@ use Wikimedia\Parsoid\DOM\Element;
use Wikimedia\Parsoid\DOM\Node;
use Wikimedia\Parsoid\Utils\DOMCompat;
use Wikimedia\Parsoid\Utils\DOMUtils;
use Wikimedia\RemexHtml\Serializer\SerializerNode;
use Wikimedia\ScopedCallback;
/**
@ -225,15 +227,6 @@ class Parser {
*/
public const TOC_PLACEHOLDER = '<meta property="mw:PageProp/toc" />';
/**
* Permissive regexp matching TOC_PLACEHOLDER. This allows for some
* minor modifications to the placeholder to be made by extensions
* without breaking the TOC (T317857); note also that Parsoid's version
* of the placeholder might include additional attributes.
* @var string
*/
private const TOC_PLACEHOLDER_REGEX = '/<meta\\b[^>]*\\bproperty\\s*=\\s*"mw:PageProp\\/toc"[^>]*>/';
# Persistent:
/** @var array<string,callable> */
private array $mTagHooks = [];
@ -4878,20 +4871,24 @@ class Parser {
*/
public static function replaceTableOfContentsMarker( $text, $toc ) {
$replaced = false;
// remove the additional metas. while not strictly necessary, this also ensures idempotence if we run
// the pass more than once on a given content and TOC markers are not inserted by $toc. At the same time,
// if $toc inserts TOC markers (which, as of 2024-05, it shouldn't be able to), these are preserved by the
// fact that we run a single pass with a callback (rather than doing a first replacement with the $toc and
// a replacement of leftover markers as a second pass).
$callback = static function ( array $matches ) use( &$replaced, $toc ): string {
if ( !$replaced ) {
return HtmlHelper::modifyElements(
$text,
static function ( SerializerNode $node ): bool {
$prop = $node->attrs['property'] ?? '';
return $node->name === 'meta' && $prop === 'mw:PageProp/toc';
},
static function ( SerializerNode $node ) use ( &$replaced, $toc ) {
if ( $replaced ) {
// Remove the additional metas. While not strictly
// necessary, this also ensures idempotence if we
// run the pass more than once on a given content.
return '';
}
$replaced = true;
return $toc;
}
return '';
};
return preg_replace_callback( self::TOC_PLACEHOLDER_REGEX, $callback, $text );
return $toc; // outerHTML replacement.
},
false /* use legacy-compatible serialization */
);
}
/**

View file

@ -1860,7 +1860,7 @@ section 5
<div class="mw-heading mw-heading2"><h2 id="text_.26_text">text &amp; text</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: text &amp; text">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<p>section 3
</p>
<div class="mw-heading mw-heading2"><h2 id="text_.27_text">text ' text</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: text &#039; text">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="text_.27_text">text ' text</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: text &#39; text">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<p>section 4
</p>
<div class="mw-heading mw-heading2"><h2 id="text_.22_text">text " text</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: text &quot; text">edit</a><span class="mw-editsection-bracket">]</span></span></div>
@ -2444,7 +2444,7 @@ wgParserEnableLegacyHeadingDOM=false
!! wikitext
== &nbsp; A &nbsp; B &nbsp; ==
!! html/php
<div class="mw-heading mw-heading2"><h2 id="_A_B">&#160; A &#160; B &#160;</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section:   A   B  ">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="_A_B">&#160; A &#160; B &#160;</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: &#160; A &#160; B &#160;">edit</a><span class="mw-editsection-bracket">]</span></span></div>
!! html/parsoid
<h2 id="_A_B"><span typeof="mw:Entity"> </span> A <span typeof="mw:Entity"> </span> B <span typeof="mw:Entity"> </span></h2>
!! end
@ -2690,7 +2690,7 @@ wgParserEnableLegacyHeadingDOM=false
<div class="mw-heading mw-heading2"><h2 id="Тест"><span id=".D0.A2.D0.B5.D1.81.D1.82"></span>Тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Тест_2"><span id=".D0.A2.D0.B5.D1.81.D1.82_2"></span>Тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="тест"><span id=".D1.82.D0.B5.D1.81.D1.82"></span>тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Hey_&lt;_#_&quot;_&gt;_%_:_'"><span id="Hey_.3C_.23_.22_.3E_.25_:_.27"></span>Hey &lt; # " &gt;&#160;%&#160;: '</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Hey_&lt;_#_&quot;_&gt;_%_:_'"><span id="Hey_.3C_.23_.22_.3E_.25_:_.27"></span>Hey &lt; # " &gt;&#160;%&#160;: '</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt;&#160;%&#160;: &#39;">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
</p><p>💩 <span id="💩"></span>
</p><p><a href="#啤酒">#啤酒</a> <a href="#啤酒">#啤酒</a>
@ -2757,7 +2757,7 @@ wgParserEnableLegacyHeadingDOM=false
<div class="mw-heading mw-heading2"><h2 id=".D0.A2.D0.B5.D1.81.D1.82"><span id="Тест"></span>Тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id=".D0.A2.D0.B5.D1.81.D1.82_2"><span id="Тест_2"></span>Тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id=".D1.82.D0.B5.D1.81.D1.82"><span id="тест"></span>тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Hey_.3C_.23_.22_.3E_.25_:_.27"><span id="Hey_&lt;_#_&quot;_&gt;_%_:_'"></span>Hey &lt; # " &gt;&#160;%&#160;: '</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Hey_.3C_.23_.22_.3E_.25_:_.27"><span id="Hey_&lt;_#_&quot;_&gt;_%_:_'"></span>Hey &lt; # " &gt;&#160;%&#160;: '</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt;&#160;%&#160;: &#39;">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#.D0.A2.D0.B5.D1.81.D1.82">#Тест</a> <a href="#.D1.82.D0.B5.D1.81.D1.82">#тест</a> <a href="#Hey_.3C_.23_.22_.3E_.25_:_.27">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
</p><p>.F0.9F.92.A9 <span id=".F0.9F.92.A9"></span>
</p><p><a href="#.E5.95.A4.E9.85.92">#啤酒</a> <a href="#.E5.95.A4.E9.85.92">#啤酒</a>
@ -2806,7 +2806,7 @@ wgParserEnableLegacyHeadingDOM=false
<div class="mw-heading mw-heading2"><h2 id="Тест">Тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Тест_2">Тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="тест">тест</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt;&#160;%&#160;: &#39;">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
</p><p>💩 <span id="💩"></span>
</p><p><a href="#啤酒">#啤酒</a> <a href="#啤酒">#啤酒</a>
@ -2823,7 +2823,7 @@ wgParserEnableLegacyHeadingDOM=false
[[#Foo&nbsp;bar]]
!! html/php
<div class="mw-heading mw-heading2"><h2 id="Foo_bar">Foo&#160;bar</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Foo bar">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<div class="mw-heading mw-heading2"><h2 id="Foo_bar">Foo&#160;bar</h2><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Foo&#160;bar">edit</a><span class="mw-editsection-bracket">]</span></span></div>
<p><a href="#Foo_bar">#Foo&#160;bar</a>
</p>
!! html/parsoid

View file

@ -1857,7 +1857,7 @@ section 5
<h2><span class="mw-headline" id="text_.26_text">text &amp; text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: text &amp; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<p>section 3
</p>
<h2><span class="mw-headline" id="text_.27_text">text ' text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: text &#039; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span class="mw-headline" id="text_.27_text">text ' text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: text &#39; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<p>section 4
</p>
<h2><span class="mw-headline" id="text_.22_text">text " text</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: text &quot; text">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
@ -2441,7 +2441,7 @@ wgParserEnableLegacyHeadingDOM=true
!! wikitext
== &nbsp; A &nbsp; B &nbsp; ==
!! html/php
<h2><span class="mw-headline" id="_A_B">&#160; A &#160; B &#160;</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section:   A   B  ">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span class="mw-headline" id="_A_B">&#160; A &#160; B &#160;</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: &#160; A &#160; B &#160;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
!! html/parsoid
<h2 id="_A_B"><span typeof="mw:Entity"> </span> A <span typeof="mw:Entity"> </span> B <span typeof="mw:Entity"> </span></h2>
!! end
@ -2686,7 +2686,7 @@ wgParserEnableLegacyHeadingDOM=true
<h2><span id=".D0.A2.D0.B5.D1.81.D1.82"></span><span class="mw-headline" id="Тест">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id=".D0.A2.D0.B5.D1.81.D1.82_2"></span><span class="mw-headline" id="Тест_2">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id=".D1.82.D0.B5.D1.81.D1.82"></span><span class="mw-headline" id="тест">тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id="Hey_.3C_.23_.22_.3E_.25_:_.27"></span><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id="Hey_.3C_.23_.22_.3E_.25_:_.27"></span><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt;&#160;%&#160;: &#39;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
</p><p>💩 <span id="💩"></span>
</p><p><a href="#啤酒">#啤酒</a> <a href="#啤酒">#啤酒</a>
@ -2753,7 +2753,7 @@ wgParserEnableLegacyHeadingDOM=true
<h2><span id="Тест"></span><span class="mw-headline" id=".D0.A2.D0.B5.D1.81.D1.82">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id="Тест_2"></span><span class="mw-headline" id=".D0.A2.D0.B5.D1.81.D1.82_2">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id="тест"></span><span class="mw-headline" id=".D1.82.D0.B5.D1.81.D1.82">тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id="Hey_&lt;_#_&quot;_&gt;_%_:_'"></span><span class="mw-headline" id="Hey_.3C_.23_.22_.3E_.25_:_.27">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span id="Hey_&lt;_#_&quot;_&gt;_%_:_'"></span><span class="mw-headline" id="Hey_.3C_.23_.22_.3E_.25_:_.27">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt;&#160;%&#160;: &#39;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#.D0.A2.D0.B5.D1.81.D1.82">#Тест</a> <a href="#.D1.82.D0.B5.D1.81.D1.82">#тест</a> <a href="#Hey_.3C_.23_.22_.3E_.25_:_.27">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
</p><p>.F0.9F.92.A9 <span id=".F0.9F.92.A9"></span>
</p><p><a href="#.E5.95.A4.E9.85.92">#啤酒</a> <a href="#.E5.95.A4.E9.85.92">#啤酒</a>
@ -2802,7 +2802,7 @@ wgParserEnableLegacyHeadingDOM=true
<h2><span class="mw-headline" id="Тест">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=3" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span class="mw-headline" id="Тест_2">Тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=4" title="Edit section: Тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span class="mw-headline" id="тест">тест</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=5" title="Edit section: тест">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt; % : &#039;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span class="mw-headline" id="Hey_&lt;_#_&quot;_&gt;_%_:_'">Hey &lt; # " &gt;&#160;%&#160;: '</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=6" title="Edit section: Hey &lt; # &quot; &gt;&#160;%&#160;: &#39;">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<p><a href="#Foo_bar">#Foo bar</a> <a href="#foo_Bar">#foo Bar</a> <a href="#Тест">#Тест</a> <a href="#тест">#тест</a> <a href="#Hey_&lt;_#_&quot;_&gt;_%_:_&#39;">#Hey &lt; # " &gt;&#160;%&#160;: '</a>
</p><p>💩 <span id="💩"></span>
</p><p><a href="#啤酒">#啤酒</a> <a href="#啤酒">#啤酒</a>
@ -2819,7 +2819,7 @@ wgParserEnableLegacyHeadingDOM=true
[[#Foo&nbsp;bar]]
!! html/php
<h2><span class="mw-headline" id="Foo_bar">Foo&#160;bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Foo bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<h2><span class="mw-headline" id="Foo_bar">Foo&#160;bar</span><span class="mw-editsection"><span class="mw-editsection-bracket">[</span><a href="/index.php?title=Parser_test&amp;action=edit&amp;section=1" title="Edit section: Foo&#160;bar">edit</a><span class="mw-editsection-bracket">]</span></span></h2>
<p><a href="#Foo_bar">#Foo&#160;bar</a>
</p>
!! html/parsoid

View file

@ -11090,7 +11090,7 @@ parsoid={ "modes": ["wt2html","html2html"], "normalizePhp": true }
<dt>This is an okay multi-codepoint HTML5 entity</dt>
<dd>&#8766;&#819;</dd>
<dt>This are valid wikitext-specific entities</dt>
<dd>&rlm; &rlm;</dd>
<dd>&#8207; &#8207;</dd>
<dt>Highest valid characters</dt>
<dd>&#x10fffd; &#x10fffe; &#x10ffff;</dd></dl>
!! end

View file

@ -12,7 +12,7 @@ class CssContentHandlerIntegrationTest extends TextContentHandlerIntegrationTest
'title' => 'MediaWiki:Test.css',
'model' => null,
'text' => "hello <world>x\n",
'expectedHtml' => "<pre class=\"mw-code mw-css\" dir=\"ltr\">\nhello &lt;world>x\n\n</pre>",
'expectedHtml' => "<pre class=\"mw-code mw-css\" dir=\"ltr\">hello &lt;world&gt;x\n\n</pre>",
'expectedFields' => [
'Links' => [
],
@ -24,7 +24,7 @@ class CssContentHandlerIntegrationTest extends TextContentHandlerIntegrationTest
'title' => 'MediaWiki:Test.css',
'model' => null,
'text' => "/* hello [[world]] */\n",
'expectedHtml' => "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n/* hello [[world]] */\n\n</pre>",
'expectedHtml' => "<pre class=\"mw-code mw-css\" dir=\"ltr\">/* hello [[world]] */\n\n</pre>",
'expectedFields' => [
'Links' => [
[ 'World' => 0, ],
@ -37,7 +37,7 @@ class CssContentHandlerIntegrationTest extends TextContentHandlerIntegrationTest
'title' => 'MediaWiki:Test.css',
'model' => null,
'text' => "==One==\n<h2>Two</h2>",
'expectedHtml' => "<pre class=\"mw-code mw-css\" dir=\"ltr\">\n==One==\n&lt;h2>Two&lt;/h2>\n</pre>",
'expectedHtml' => "<pre class=\"mw-code mw-css\" dir=\"ltr\">==One==\n&lt;h2&gt;Two&lt;/h2&gt;\n</pre>",
'expectedFields' => [
'Links' => [
],

View file

@ -12,7 +12,7 @@ class JavaScriptContentHandlerIntegrationTest extends TextContentHandlerIntegrat
'title' => 'MediaWiki:Test.js',
'model' => null,
'text' => "hello <world>\n",
'expectedHtml' => "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello &lt;world>\n\n</pre>",
'expectedHtml' => "<pre class=\"mw-code mw-js\" dir=\"ltr\">hello &lt;world&gt;\n\n</pre>",
'expectedFields' => [
'Links' => [
],
@ -24,7 +24,7 @@ class JavaScriptContentHandlerIntegrationTest extends TextContentHandlerIntegrat
'title' => 'MediaWiki:Test.js',
'model' => null,
'text' => "hello(); // [[world]]\n",
'expectedHtml' => "<pre class=\"mw-code mw-js\" dir=\"ltr\">\nhello(); // [[world]]\n\n</pre>",
'expectedHtml' => "<pre class=\"mw-code mw-js\" dir=\"ltr\">hello(); // [[world]]\n\n</pre>",
'expectedFields' => [
'Links' => [
[ 'World' => 0, ],
@ -37,7 +37,7 @@ class JavaScriptContentHandlerIntegrationTest extends TextContentHandlerIntegrat
'title' => 'MediaWiki:Test.js',
'model' => null,
'text' => "==One==\n<h2>Two</h2>",
'expectedHtml' => "<pre class=\"mw-code mw-js\" dir=\"ltr\">\n==One==\n&lt;h2>Two&lt;/h2>\n</pre>",
'expectedHtml' => "<pre class=\"mw-code mw-js\" dir=\"ltr\">==One==\n&lt;h2&gt;Two&lt;/h2&gt;\n</pre>",
'expectedFields' => [
'Links' => [
],

View file

@ -54,7 +54,7 @@ class JsonContentHandlerIntegrationTest extends MediaWikiLangTestCase {
[
(object)[ '<script>alert("evil!")</script>' ],
'<div class="noresize"><table class="mw-json"><tbody><tr><th><span>0</span></th><td class="mw-json-value">"' .
'&lt;script>alert("evil!")&lt;/script>"' .
'&lt;script&gt;alert("evil!")&lt;/script&gt;"' .
'</td></tr></tbody></table></div>',
],
[

View file

@ -99,7 +99,7 @@ class WikitextContentHandlerIntegrationTest extends TextContentHandlerIntegratio
'title' => 'WikitextContentTest_testGetParserOutput',
'model' => CONTENT_MODEL_WIKITEXT,
'text' => "#REDIRECT [[Main Page]]",
'expectedHtml' => "<div class=\"mw-content-ltr mw-parser-output\" lang=\"en\" dir=\"ltr\" $parsoidVersion><div class=\"redirectMsg\"><p>Redirect to:</p><ul class=\"redirectText\"><li><a href=\"/w/index.php?title=Main_Page&amp;action=edit&amp;redlink=1\" class=\"new\" title=\"Main Page (page does not exist)\">Main Page</a></li></ul></div><section data-mw-section-id=\"0\" id=\"mwAQ\"><link rel=\"mw:PageProp/redirect\" href=\"./Main_Page\" id=\"mwAg\"/></section></div>",
'expectedHtml' => "<div class=\"mw-content-ltr mw-parser-output\" lang=\"en\" dir=\"ltr\" $parsoidVersion><div class=\"redirectMsg\"><p>Redirect to:</p><ul class=\"redirectText\"><li><a href=\"/w/index.php?title=Main_Page&amp;action=edit&amp;redlink=1\" class=\"new\" title=\"Main Page (page does not exist)\">Main Page</a></li></ul></div><section data-mw-section-id=\"0\" id=\"mwAQ\"><link rel=\"mw:PageProp/redirect\" href=\"./Main_Page\" id=\"mwAg\" /></section></div>",
'expectedFields' => [
'Links' => [
[ 'Main_Page' => 0 ],

View file

@ -926,12 +926,12 @@ class WikiPageDbTest extends MediaWikiLangTestCase {
[
CONTENT_MODEL_JAVASCRIPT,
"var test='<h2>not really a heading</h2>';",
"<pre class=\"mw-code mw-js\" dir=\"ltr\">\nvar test='&lt;h2>not really a heading&lt;/h2>';\n</pre>",
"<pre class=\"mw-code mw-js\" dir=\"ltr\">var test='&lt;h2&gt;not really a heading&lt;/h2&gt;';\n</pre>",
],
[
CONTENT_MODEL_CSS,
"/* Not ''wikitext'' */",
"<pre class=\"mw-code mw-css\" dir=\"ltr\">\n/* Not ''wikitext'' */\n</pre>",
"<pre class=\"mw-code mw-css\" dir=\"ltr\">/* Not ''wikitext'' */\n</pre>",
],
// @todo more...?
];