jenkins-bot has submitted this change and it was merged.

Change subject: Suppress newlines before category links
......................................................................


Suppress newlines before category links

* itwiki:Melampyrum now RTs without semantic errors because the
  duplicate args category links no longer ends up on a new line.

* http://localhost:8000/enwiki/Taiko?oldid=665356368 now renders
  as expected as well.

* Parsoid now renders enwiki:User:SSastry_%28WMF%29/Category_Test
  identically to the PHP parser output. The list tests will not RT
  back the newlines because of newline suppression in list context.
  RTing of that test case will not be supported (see parser tests).

* We continue to treat category links as SOL-transparent, because
  that is their "true nature" in scenarios where newlines aren't
  stripped (when found at start of text -- they aren't usually, but
  that is besides the point).

* Added 2 new parser tests that spec this newline-stripping behavior.

* Updated wt2html output of 1 parser test. This will no longer wt2wt
  now because we are not really suppressing the newlines. I am not
  interested in adding special cases for rting this edge case.

  An alternative would be to actually suppress the newlines in
  parse output using some special meta-tag like mw:Placeholder or
  mw:SuppressNewlines or something that is not editable but can
  be deleted.

Bug: T2087
Bug: T95988

Change-Id: I507dcefcca5a4ee22fb9f9bf0cfe678f14d64991
---
M lib/ext.core.TokenStreamPatcher.js
M tests/parserTests-blacklist.js
M tests/parserTests.txt
3 files changed, 118 insertions(+), 11 deletions(-)

Approvals:
  Arlolra: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/lib/ext.core.TokenStreamPatcher.js 
b/lib/ext.core.TokenStreamPatcher.js
index e27cc71..69be60c 100644
--- a/lib/ext.core.TokenStreamPatcher.js
+++ b/lib/ext.core.TokenStreamPatcher.js
@@ -18,6 +18,7 @@
 
 // define some constructor shortcuts
 var CommentTk = defines.CommentTk;
+var NlTk = defines.NlTk;
 var TagTk = defines.TagTk;
 var SelfclosingTagTk = defines.SelfclosingTagTk;
 var EndTagTk = defines.EndTagTk;
@@ -34,8 +35,8 @@
 // FIXME: At this point, it probably deserves a refactor.
 coreutil.inherits(TokenStreamPatcher, TemplateHandler);
 
-TokenStreamPatcher.prototype.anyRank  = 2.001;
-TokenStreamPatcher.prototype.nlRank   = 2.002;
+TokenStreamPatcher.prototype.nlRank   = 2.001;
+TokenStreamPatcher.prototype.anyRank  = 2.002;
 TokenStreamPatcher.prototype.endRank  = 2.003;
 
 TokenStreamPatcher.prototype.register = function() {
@@ -56,12 +57,15 @@
        this.wikiTableNesting = 0;
        this.srcOffset = 0;
        this.sol = true;
+       this.tokenBuf = [];
 };
 
 TokenStreamPatcher.prototype.onNewline = function(token) {
+       this.manager.env.log("trace/tsp", this.manager.pipelineId, function() { 
return JSON.stringify(token); } );
        this.srcOffset = (token.dataAttribs.tsr || [null, null])[1];
        this.sol = true;
-       return {tokens: [token]};
+       this.tokenBuf.push(token);
+       return {tokens: []};
 };
 
 TokenStreamPatcher.prototype.onEnd = function(token) {
@@ -135,6 +139,14 @@
        var tokens = [token];
        switch (token.constructor) {
                case String:
+                       // While we are buffering newlines to suppress them
+                       // in case we see a category, buffer all intervening
+                       // white-space as well.
+                       if (this.tokenBuf.length > 0 && /^\s*$/.test(token)) {
+                               this.tokenBuf.push(token);
+                               return {tokens: []};
+                       }
+
                        // TRICK #1:
                        // Attempt to match "{|" after a newline and convert
                        // it to a table token.
@@ -164,8 +176,48 @@
                        break;
 
                case SelfclosingTagTk:
-                       if (token.name === "meta" && token.dataAttribs.stx !== 
"html") {
+                       if (token.name === 'meta' && token.dataAttribs.stx !== 
'html') {
                                this.srcOffset = (token.dataAttribs.tsr || 
[null, null])[1];
+                               // If we have buffered newlines, we might very 
well encounter
+                               // a category link, so continue buffering.
+                               if (this.tokenBuf.length > 0 && token.name === 
'meta' &&
+                                       token.getAttribute('typeof') === 
'mw:Transclusion') {
+                                       this.tokenBuf.push(token);
+                                       return {tokens: []};
+                               }
+                       } else if (token.name === 'link' &&
+                               token.getAttribute('rel') === 
'mw:PageProp/Category') {
+                               // Replace buffered newline & whitespace tokens 
with mw:EmptyLine
+                               // meta-tokens. This tunnels them through the 
rest of the transformations
+                               // without affecting them. During HTML 
building, they are expanded
+                               // back to newlines / whitespace.
+                               var n = this.tokenBuf.length;
+                               if (n > 0) {
+                                       var i = 0;
+                                       while (i < n && 
this.tokenBuf[i].constructor !== SelfclosingTagTk) {
+                                               i++;
+                                       }
+
+                                       var toks = [
+                                               new SelfclosingTagTk("meta",
+                                                       [new KV('typeof', 
'mw:EmptyLine')], {
+                                                               tokens: 
this.tokenBuf.slice(0, i)
+                                                       })
+                                       ];
+                                       if (i < n) {
+                                               toks.push(this.tokenBuf[i]);
+                                               if (i + 1 < n) {
+                                                       toks.push(new 
SelfclosingTagTk("meta",
+                                                               [new 
KV('typeof', 'mw:EmptyLine')], {
+                                                                       tokens: 
this.tokenBuf.slice(i + 1)
+                                                               })
+                                                       );
+                                               }
+                                       }
+                                       tokens = toks.concat(tokens);
+                                       this.tokenBuf = [];
+                               }
+                               this.clearSOL();
                        } else {
                                this.clearSOL();
                        }
@@ -203,6 +255,11 @@
                        break;
        }
 
+       // Emit buffered newlines (and a transclusion meta-token, if any)
+       if (this.tokenBuf.length > 0) {
+               tokens = this.tokenBuf.concat(tokens);
+               this.tokenBuf = [];
+       }
        return {tokens: tokens};
 };
 
diff --git a/tests/parserTests-blacklist.js b/tests/parserTests-blacklist.js
index 3ee3c06..c97e1a6 100644
--- a/tests/parserTests-blacklist.js
+++ b/tests/parserTests-blacklist.js
@@ -186,7 +186,7 @@
 add("wt2html", "Category with template", "<link typeof=\"mw:ExpandedAttrs\" 
about=\"#mwt2\" rel=\"mw:PageProp/Category\" href=\"./Category:Foo\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Foo\"},\"sa\":{\"href\":\"Category:{{echo|Foo}}\"},\"dsr\":[0,25,null,null]}'
 data-mw='{\"attribs\":[[{\"txt\":\"href\"},{\"html\":\"Category:&lt;span 
about=\\\"#mwt1\\\" typeof=\\\"mw:Transclusion\\\" 
data-parsoid=\\\"{&amp;quot;pi&amp;quot;:[[{&amp;quot;k&amp;quot;:&amp;quot;1&amp;quot;,&amp;quot;spc&amp;quot;:[&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;]}]],&amp;quot;dsr&amp;quot;:[11,23,null,null]}\\\"
 
data-mw=\\\"{&amp;quot;parts&amp;quot;:[{&amp;quot;template&amp;quot;:{&amp;quot;target&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;echo&amp;quot;,&amp;quot;href&amp;quot;:&amp;quot;./Template:Echo&amp;quot;},&amp;quot;params&amp;quot;:{&amp;quot;1&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;Foo&amp;quot;}},&amp;quot;i&amp;quot;:0}}]}\\\">Foo&lt;/span>\"}]]}'/>");
 add("wt2html", "Category with template in sort key", "<link 
rel=\"mw:PageProp/Category\" href=\"./Category:Foo#Bar\" about=\"#mwt2\" 
typeof=\"mw:ExpandedAttrs\" 
data-parsoid='{\"stx\":\"piped\",\"a\":{\"href\":\"./Category:Foo\"},\"sa\":{\"href\":\"Category:Foo\"},\"dsr\":[0,29,null,null]}'
 data-mw='{\"attribs\":[[{\"txt\":\"mw:sortKey\"},{\"html\":\"&lt;span 
about=\\\"#mwt1\\\" typeof=\\\"mw:Transclusion\\\" 
data-parsoid=\\\"{&amp;quot;pi&amp;quot;:[[{&amp;quot;k&amp;quot;:&amp;quot;1&amp;quot;,&amp;quot;spc&amp;quot;:[&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;]}]],&amp;quot;dsr&amp;quot;:[15,27,null,null]}\\\"
 
data-mw=\\\"{&amp;quot;parts&amp;quot;:[{&amp;quot;template&amp;quot;:{&amp;quot;target&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;echo&amp;quot;,&amp;quot;href&amp;quot;:&amp;quot;./Template:Echo&amp;quot;},&amp;quot;params&amp;quot;:{&amp;quot;1&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;Bar&amp;quot;}},&amp;quot;i&amp;quot;:0}}]}\\\">Bar&lt;/span>\"}]]}'/>");
 add("wt2html", "Category with template in sort key and title", "<link 
typeof=\"mw:ExpandedAttrs\" about=\"#mwt4\" rel=\"mw:PageProp/Category\" 
href=\"./Category:Foo#Bar\" 
data-parsoid='{\"stx\":\"piped\",\"a\":{\"href\":\"./Category:Foo\"},\"sa\":{\"href\":\"Category:{{echo|Foo}}\"},\"dsr\":[0,38,null,null]}'
 data-mw='{\"attribs\":[[{\"txt\":\"href\"},{\"html\":\"Category:&lt;span 
about=\\\"#mwt1\\\" typeof=\\\"mw:Transclusion\\\" 
data-parsoid=\\\"{&amp;quot;pi&amp;quot;:[[{&amp;quot;k&amp;quot;:&amp;quot;1&amp;quot;,&amp;quot;spc&amp;quot;:[&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;]}]],&amp;quot;dsr&amp;quot;:[11,23,null,null]}\\\"
 
data-mw=\\\"{&amp;quot;parts&amp;quot;:[{&amp;quot;template&amp;quot;:{&amp;quot;target&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;echo&amp;quot;,&amp;quot;href&amp;quot;:&amp;quot;./Template:Echo&amp;quot;},&amp;quot;params&amp;quot;:{&amp;quot;1&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;Foo&amp;quot;}},&amp;quot;i&amp;quot;:0}}]}\\\">Foo&lt;/span>\"}],[{\"txt\":\"mw:sortKey\"},{\"html\":\"&lt;span
 about=\\\"#mwt2\\\" typeof=\\\"mw:Transclusion\\\" 
data-parsoid=\\\"{&amp;quot;pi&amp;quot;:[[{&amp;quot;k&amp;quot;:&amp;quot;1&amp;quot;,&amp;quot;spc&amp;quot;:[&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;,&amp;quot;&amp;quot;]}]],&amp;quot;dsr&amp;quot;:[24,36,null,null]}\\\"
 
data-mw=\\\"{&amp;quot;parts&amp;quot;:[{&amp;quot;template&amp;quot;:{&amp;quot;target&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;echo&amp;quot;,&amp;quot;href&amp;quot;:&amp;quot;./Template:Echo&amp;quot;},&amp;quot;params&amp;quot;:{&amp;quot;1&amp;quot;:{&amp;quot;wt&amp;quot;:&amp;quot;Bar&amp;quot;}},&amp;quot;i&amp;quot;:0}}]}\\\">Bar&lt;/span>\"}]]}'/>");
-add("wt2html", "Category / paragraph interactions", "<p 
data-parsoid='{\"dsr\":[0,24,0,0]}'>Foo <link rel=\"mw:PageProp/Category\" 
href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[4,20,null,null]}'/>
 Bar</p>\n\n<p data-parsoid='{\"dsr\":[26,50,0,0]}'>Foo <link 
rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[30,46,null,null]}'/>\nBar</p>\n\n<p
 data-parsoid='{\"dsr\":[52,76,0,0]}'>Foo\n<link rel=\"mw:PageProp/Category\" 
href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[56,72,null,null]}'/>\nBar</p>\n\n<p
 data-parsoid='{\"dsr\":[78,81,0,0]}'>Foo</p>\n<link 
rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[82,98,null,null]}'/><pre
 data-parsoid='{\"dsr\":[98,102,1,0]}'>Bar</pre>\n\n<p 
data-parsoid='{\"dsr\":[104,163,0,0]}'>Foo\n<link rel=\"mw:PageProp/Category\" 
href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[108,124,null,null]}'/>\n
 <link rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[126,142,null,null]}'/>\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[143,159,null,null]}'/>\nBar</p>\n\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[165,181,null,null]}'/>\n
 <link rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[183,199,null,null]}'/>\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[200,216,null,null]}'/>\n\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[218,234,null,null]}'/>\n
 <link rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" about=\"#mwt1\" 
typeof=\"mw:Transclusion\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[236,261,null,null],\"pi\":[[{\"k\":\"1\",\"spc\":[\"\",\"\",\"\",\"\"]}]]}'
 
data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"[[Category:Baz]]\"}},\"i\":0}}]}'/>\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[262,278,null,null]}'/>");
+add("wt2html", "Category / paragraph interactions", "<p 
data-parsoid='{\"dsr\":[0,24,0,0]}'>Foo <link rel=\"mw:PageProp/Category\" 
href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[4,20,null,null]}'/>
 Bar</p>\n\n<p data-parsoid='{\"dsr\":[26,50,0,0]}'>Foo <link 
rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[30,46,null,null]}'/>\nBar</p>\n\n<p
 data-parsoid='{\"dsr\":[52,76,0,0]}'>Foo\n<link rel=\"mw:PageProp/Category\" 
href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[56,72,null,null]}'/>\nBar</p>\n\n<p
 data-parsoid='{\"dsr\":[78,102,0,0]}'>Foo\n<link rel=\"mw:PageProp/Category\" 
href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[82,98,null,null]}'/>
 Bar</p>\n\n<p data-parsoid='{\"dsr\":[104,261,0,0]}'>Foo\n<link 
rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[108,124,null,null]}'/>\n
 <link rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[126,142,null,null]}'/>\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[143,159,null,null]}'/>\nBar\n\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[165,181,null,null]}'/>\n
 <link rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[183,199,null,null]}'/>\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[200,216,null,null]}'/>\n\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[218,234,null,null]}'/>\n
 <link rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" about=\"#mwt1\" 
typeof=\"mw:Transclusion\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[236,261,null,null],\"pi\":[[{\"k\":\"1\",\"spc\":[\"\",\"\",\"\",\"\"]}]]}'
 
data-mw='{\"parts\":[{\"template\":{\"target\":{\"wt\":\"echo\",\"href\":\"./Template:Echo\"},\"params\":{\"1\":{\"wt\":\"[[Category:Baz]]\"}},\"i\":0}}]}'/></p>\n<link
 rel=\"mw:PageProp/Category\" href=\"./Category:Baz\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Category:Baz\"},\"sa\":{\"href\":\"Category:Baz\"},\"dsr\":[262,278,null,null]}'/>");
 add("wt2html", "Short headings with trailing space should match behavior of 
Parser::doHeadings (bug 19910)", "<p data-parsoid='{\"dsr\":[0,100,0,0]}'>=== 
\nThe line above must have a trailing space!\n=== <!--\n--> <!-- -->\nBut just 
in case it doesn't...</p>");
 add("wt2html", "Header with space, plus and underscore as entity", "<p 
data-parsoid='{\"dsr\":[0,34,0,0]}'>Id should not contain + for 
spaces</p>\n\n<h2 data-parsoid='{\"dsr\":[36,60,2,2]}'> Space between Text 
</h2>\n<p data-parsoid='{\"dsr\":[61,70,0,0]}'>section 1</p>\n\n<h2 
data-parsoid='{\"dsr\":[72,111,2,2]}'> Space-Entity<span typeof=\"mw:Entity\" 
data-parsoid='{\"src\":\"&amp;#32;\",\"srcContent\":\" 
\",\"dsr\":[87,92,null,null]}'> </span>between<span typeof=\"mw:Entity\" 
data-parsoid='{\"src\":\"&amp;#32;\",\"srcContent\":\" 
\",\"dsr\":[99,104,null,null]}'> </span>Text </h2>\n<p 
data-parsoid='{\"dsr\":[112,121,0,0]}'>section 2</p>\n\n<h2 
data-parsoid='{\"dsr\":[123,146,2,2]}'> Plus+between+Text </h2>\n<p 
data-parsoid='{\"dsr\":[147,156,0,0]}'>section 3</p>\n\n<h2 
data-parsoid='{\"dsr\":[158,196,2,2]}'> Plus-Entity<span typeof=\"mw:Entity\" 
data-parsoid='{\"src\":\"&amp;#43;\",\"srcContent\":\"+\",\"dsr\":[172,177,null,null]}'>+</span>between<span
 typeof=\"mw:Entity\" 
data-parsoid='{\"src\":\"&amp;#43;\",\"srcContent\":\"+\",\"dsr\":[184,189,null,null]}'>+</span>Text
 </h2>\n<p data-parsoid='{\"dsr\":[197,206,0,0]}'>section 4</p>\n\n<h2 
data-parsoid='{\"dsr\":[208,237,2,2]}'> Underscore_between_Text </h2>\n<p 
data-parsoid='{\"dsr\":[238,247,0,0]}'>section 5</p>\n\n<h2 
data-parsoid='{\"dsr\":[249,293,2,2]}'> Underscore-Entity<span 
typeof=\"mw:Entity\" 
data-parsoid='{\"src\":\"&amp;#95;\",\"srcContent\":\"_\",\"dsr\":[269,274,null,null]}'>_</span>between<span
 typeof=\"mw:Entity\" 
data-parsoid='{\"src\":\"&amp;#95;\",\"srcContent\":\"_\",\"dsr\":[281,286,null,null]}'>_</span>Text
 </h2>\n<p data-parsoid='{\"dsr\":[294,303,0,0]}'>section 6</p>\n\n<p 
data-parsoid='{\"dsr\":[305,501,0,0]}'><a rel=\"mw:WikiLink\" 
href=\"./Main%20Page#Space_between_Text\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Main%20Page#Space_between_Text\"},\"sa\":{\"href\":\"#Space
 between Text\"},\"dsr\":[305,328,2,2]}'>#Space between Text</a>\n<a 
rel=\"mw:WikiLink\" href=\"./Main%20Page#Space-Entity_between_Text\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Main%20Page#Space-Entity_between_Text\"},\"sa\":{\"href\":\"#Space-Entity&amp;#32;between&amp;#32;Text\"},\"dsr\":[329,367,2,2]}'>#Space-Entity
 between Text</a>\n<a rel=\"mw:WikiLink\" 
href=\"./Main%20Page#Plus+between+Text\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Main%20Page#Plus+between+Text\"},\"sa\":{\"href\":\"#Plus+between+Text\"},\"dsr\":[368,390,2,2]}'>#Plus+between+Text</a>\n<a
 rel=\"mw:WikiLink\" href=\"./Main%20Page#Plus-Entity+between+Text\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Main%20Page#Plus-Entity+between+Text\"},\"sa\":{\"href\":\"#Plus-Entity&amp;#43;between&amp;#43;Text\"},\"dsr\":[391,428,2,2]}'>#Plus-Entity+between+Text</a>\n<a
 rel=\"mw:WikiLink\" href=\"./Main%20Page#Underscore_between_Text\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Main%20Page#Underscore_between_Text\"},\"sa\":{\"href\":\"#Underscore_between_Text\"},\"dsr\":[429,457,2,2]}'>#Underscore_between_Text</a>\n<a
 rel=\"mw:WikiLink\" href=\"./Main%20Page#Underscore-Entity_between_Text\" 
data-parsoid='{\"stx\":\"simple\",\"a\":{\"href\":\"./Main%20Page#Underscore-Entity_between_Text\"},\"sa\":{\"href\":\"#Underscore-Entity&amp;#95;between&amp;#95;Text\"},\"dsr\":[458,501,2,2]}'>#Underscore-Entity_between_Text</a></p>");
 add("wt2html", "Single-line or multiline-comments can follow headings", "<h2 
data-parsoid='{\"dsr\":[0,7,2,2]}'>foo</h2><!---->\n<h2 
data-parsoid='{\"dsr\":[15,22,2,2]}'>bar</h2><!--c1-->\n<h2 
data-parsoid='{\"dsr\":[32,39,2,2]}'>baz</h2><!--\nc2\nc3-->");
@@ -425,6 +425,7 @@
 add("wt2wt", "Templates: Indent-Pre: 1f: Wrapping should be based on expanded 
content", "{{echo| }}a\n\n{{echo|\n }}a\n\n{{echo|\n b}}\n\n{{echo|a\n 
}}b\n\n{{echo|a\n}}\n b\n");
 add("wt2wt", "Templates: Handle comments in the target", "{{echo\n<!-- should 
be ignored -->\n|foo}}\n\n{{echo<!-- should be ignored 
-->\n|foo}}\n\n{{echo<!-- should be ignored -->|foo}}\n\n{{echo|foo}}");
 add("wt2wt", "4. Indent-Pre and extension tags", " a <gallery>\n 
File:foobar.jpg\n </gallery>\n");
+add("wt2wt", "7b. Indent-pre and category links", " [[Category:foo]] a\n  
[[Category:foo]] {{echo|b}}\n");
 add("wt2wt", "Definition lists: self-closed tag", ";one<br />two : two-line 
fun");
 add("wt2wt", "Definition Lists: colons occurring in tags", 
";a:b\n;'''a:b'''\n;<i>a:b</i>\n;<span>a:b</span>\n;<div>a:b</div>\n;<div>a\n:b\n;{{echo|a:b}}\n;{{echo|''a:b''}}\n;;;''a:b''\n");
 add("wt2wt", "BUG 289: \">\"-token in bracketed URL", 
"[http://www.example.com/ <hello> stuff]\n");
@@ -1825,6 +1826,7 @@
 add("selser", "5a. White-space in indent-pre [[2,0,4]]", " d3ppdqvqzdxi529a<br 
/>\n 82567nb6q9hbmx6r");
 add("selser", "5a. White-space in indent-pre [[2,0,0]]", " 9blj98gpz0py14ia<br 
/>\n \n \n b");
 add("selser", "5a. White-space in indent-pre [[0,2,0]]", " 
am3m3vd8oxzu84cxr<br />\n \n \n b");
+add("selser", "7b. Indent-pre and category links [2]", "yml0m6jz2j32qpvi\n 
[[Category:foo]] a\n [[Category:foo]] {{echo|b}}");
 add("selser", "Definition lists: self-closed tag [2]", 
"x14l42v2vh392j4i\n;one<br/>two : two-line fun");
 add("selser", "Definition lists: self-closed tag [1]", ";one<br/>two : 
two-line fun");
 add("selser", "Definition lists: self-closed tag [[[4,2,4,0],[2]]]", 
";hfmudey4je6u5wmi18aco6b1yahy3nmi<br/>199ekjza5e7phkt9 :b3ubf9dln2x7ds4i 
two-line fun");
@@ -2227,9 +2229,7 @@
 add("selser", "Render invalid page names as plain text (bug 51090) [2,4,3]", 
"x280lbt0x9smunmi\n\n[[./../foo|bar]]\n[[foo�|bar]]\n[[foo/.|bar]]\n[[foo/..|bar]]\n[[foo~~~bar]]\n[[foo>bar]]\n[[foo[bar]]\n[[.]]\n[[..]]\n[[foo././bar]]\n\n9zekc2ruir0h33di\n");
 add("selser", "Render invalid page names as plain text (bug 51090) [2,0,3]", 
"uy7lbslcu8mvaemi\n\n[[./../foo|bar]]\n[[foo�|bar]]\n[[foo/.|bar]]\n[[foo/..|bar]]\n[[foo~~~bar]]\n[[foo>bar]]\n[[foo[bar]]\n[[.]]\n[[..]]\n[[foo././bar]]\n");
 add("selser", "Render invalid page names as plain text (bug 51090) 
[2,0,[2,0,0,0,4,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,3,0,2]]", 
"ixtw0uq17iqtcsor\n\n[[./../foo|bar]]\n[[foo�|bar]]\n[[foo/.|bar]]\n[[foo/..|bar]]\n[[foo~~~bar]]\n[[foo>bar]]\n[[foo[bar]]\n[[.]]\n[[..]]\n[[foo././bar]]\n\ncjgyt6cnj124kj4i[[{{echo|./../foo}}|bar]]\n[[{{echo|foo/.}}4i3f1qev8b5u3di{{echo|foo/..}}t26yvjmagszl4n29{{echo|foo~~~~bar}}]]\n[[{{echo|foo>bar}}3vx6jfw5gbvs4i{{echo|foo././bar}}]]\n[[{{echo|foo{bar}}]]\n[[{{echo|foo}bar}}]]\n[[{{echo|foo[bar}}]]\n[[{{echo|foo]bar}}{{echo|foo<bar}}<nowiki>3vz7g6pd5lzhncdi]]</nowiki>");
-add("selser", "Category / paragraph interactions 
[[0,3,2],0,2,4,[3,2,0],0,[2],3,0,[3],0,[3,3,4,1,4,2,3],0,3,4,0,4,3,0,0,2,0,0,0]",
 "Foo 83zrad4tpxxkcsor Bar\n\nysekf8brayr885mi\n\nFoo 
[[Category:Baz]]\nBar\n\nduknjpcnvnyzxgvi\n\nhroyapi5paqhncdi[[Category:Baz]]\nBar\n\nmsiv1cjc1q8e61orFoo\n[[Category:Baz]]
 
\n\nljrvpzob03tedn29[[Category:Baz]]6bqrn9ug03npcik95jcarnywu55klnmi[[Category:Baz]]\n\nik3u2lqitfomkj4i[[Category:Baz]]\nn8wwykwa78f72e29\n\n[[Category:Baz]]\n9dl89xg0l57phkt9\n
 {{echo|[[Category:Baz]]}}\n[[Category:Baz]]");
-add("selser", "Category / paragraph interactions 
[4,0,0,0,[4,1,0],3,3,0,0,0,2,[2,0,0,1,3,0,0],0,1,3,0,2,0,2,0,0,0,4,2]", 
"y2ksxygpidn7y14i\n\nFoo 
[[Category:Baz]]\nBar\n\ntqcbbea7bmiy66r[[Category:Baz]]\nBar\n[[Category:Baz]] 
Bar\nc42dqedyb3u6usor\n\ndjmvd61k80kymn29Foo\n[[Category:Baz]]\n 
[[Category:Baz]][[Category:Baz]]\nBar\n\n[[Category:Baz]]\n 
[[Category:Baz]]\nvyv3u18bgs4z33di\n[[Category:Baz]]\ne98vfkx1eqld6lxr\n\n[[Category:Baz]]\n
 
{{echo|[[Category:Baz]]}}\nviznyhgcd9muz0k9\n\nd830mwe1qg1oflxr[[Category:Baz]]");
-add("selser", "Category / paragraph interactions 
[1,0,1,0,1,0,1,0,0,0,2,[4,0,0,0,0,4,0],3,0,4,0,0,1,4,4,0,0,3,0]", "Foo 
[[Category:Baz]] Bar\n\nFoo 
[[Category:Baz]]\nBar\n\nFoo\n[[Category:Baz]]\nBar\n\nFoo\n[[Category:Baz]] 
Bar\nqyq2tw4tbcjfko6r\n\n8rsqjn6ahwoecdi[[Category:Baz]]\n 
[[Category:Baz]]\n7qub38k3od0od2t9\nBar\n\n[[Category:Baz]]\njml3cn3gxdt5ipb9[[Category:Baz]]\n[[Category:Baz]]\n7www48dkmtg74x6r\n\nfddlp7i37zwr8uxr\n
 {{echo|[[Category:Baz]]}}[[Category:Baz]]");
+add("selser", "Category / paragraph interactions [3,2,1,3,0,4,1,2,1,3,0]", 
"x7ixp2jr6ir4quxr\n\nFoo 
[[Category:Baz]]\nBar\n\nFoo\n[[Category:Baz]]\nBar\n\nwvsxizohr6hia4i\n\nFoo\n[[Category:Baz]]
 Bar\n\nykmlq9svazzd7vi\n\nFoo\n[[Category:Baz]]\n 
[[Category:Baz]]\n[[Category:Baz]]\nBar\n\n[[Category:Baz]]\n 
[[Category:Baz]]\n[[Category:Baz]]\n\n[[Category:Baz]]\n 
{{echo|[[Category:Baz]]}}\n[[Category:Baz]]");
 add("selser", "Section headings with TOC [3,4,0,0,3,2,[3],3,0,4,3,3,0]", 
"px8b3ng5n4lpu8fr\n\n=== Subheadline 1 
===\np64mngpetwfm9529\n\n======<nowiki/>======\n\n== Headline 2 
==\nzvfwz386e7xbhuxr\n\n===Another headline===");
 add("selser", "Handling of sections up to level 6 and beyond 
[1,2,1,2,1,0,[3],2,2,4,[2],4,0,0,1,0,0,3,1]", "= Level 1 
Heading=\n7e043zzvvtzf47vi\n\n== Level 2 Heading==\n0pp0pcwrmkakyb9\n\n=== 
Level 3 
Heading===\n====<nowiki/>====\n253vnq49otg9zfr\nmncpvxste96vquxr\n\n===== Level 
5 Heading=====\n91qmbb1e2vlpu8fr\n\n======ohqkkrlkoqi79zfr Level 6 
Heading======\n6hv8gbhdqngn9udi\n\n======= Level 7 
Heading=======\n======<nowiki>== Level 8 Heading==</nowiki>======\n========= 
Level 9 Heading=========\n======<nowiki>==== Level 10 
Heading====</nowiki>======");
 add("selser", "Handling of sections up to level 6 and beyond 
[1,0,1,0,0,3,2,3,0,0,4,0,[4],0,1,0,0,4,0]", "= Level 1 Heading=\n== Level 2 
Heading==\n=== Level 3 Heading===\n6fs6ykhv45nrk9\n\n==== Level 4 
Heading====\n===== Level 5 
Heading=====\njkvm1xjd1mw2vs4i\n\n======lrcthal0ujwnrk9======\n======<nowiki>== 
Level 8 Heading==</nowiki>======\n========= Level 9 
Heading=========\n6uicqh73ey5bfbt9\n\n========== Level 10 Heading==========");
diff --git a/tests/parserTests.txt b/tests/parserTests.txt
index 1a9fb3f..2396c33 100644
--- a/tests/parserTests.txt
+++ b/tests/parserTests.txt
@@ -3245,9 +3245,8 @@
  [[Category:foo]] a
  [[Category:foo]] {{echo|b}}
 !! html
-<pre>
-<link rel="mw:PageProp/Category" href="./Category:Foo"> a
-<link rel="mw:PageProp/Category" href="./Category:Foo"> <span about="#mwt1" 
typeof="mw:Transclusion" 
data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b"}},"i":0}}]}'>b</span></pre>
+<pre><link rel="mw:PageProp/Category" href="./Category:Foo"> a
+ <link rel="mw:PageProp/Category" href="./Category:Foo"> <span about="#mwt1" 
typeof="mw:Transclusion" 
data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"b"}},"i":0}}]}'>b</span></pre>
 !! end
 
 !! test
@@ -13676,6 +13675,57 @@
 </p>
 !! end
 
+## The whitespace on the empty line is part of the test. Please do not delete
+!! test
+1. Categories and newlines: All preceding newlines should be suppressed 
(courtesy bug 87)
+!! options
+parsoid=wt2html,wt2wt
+!! wikitext
+This
+   
+[[Category:Foo]] and this should be part of same paragraph (not an indent-pre)
+   
+{{echo|[[Category:Foo]] and so should this!}}
+!! html
+<p>This and this should be part of same paragraph (not an indent-pre) and so 
should this!
+</p>
+!! html/parsoid
+<p>This
+   
+<link rel="mw:PageProp/Category" href="./Category:Foo"/> and this should be 
part of same paragraph (not an indent-pre)
+   
+<link rel="mw:PageProp/Category" href="./Category:Foo" about="#mwt1" 
typeof="mw:Transclusion" 
data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[[Category:Foo]]
 and so should this!"}},"i":0}}]}'/><span about="#mwt1"> and so should 
this!</span></p>
+!! end
+
+## Parsoid will not try to wt2wt this while preserving newlines because
+## it suppresses excess newlines within list items -- and we don't want to
+## introduce a special case just for categories, which is, in reality somewhat
+## odd behavior -- categories are unlikely to be used in list items like this
+## in top-level pages and are only likely to show up in template-generated
+## list items where this RT-ing is a non-issue.
+##
+## The whitespace on the empty line is part of the test. Please do not delete
+!! test
+2. Categories and newlines: All preceding newlines should be suppressed 
(courtesy bug 87)
+!! options
+parsoid=wt2html
+!! wikitext
+* This
+   
+[[Category:Foo]] and this should be part of the same list item
+* So should this
+
+{{echo|[[Category:Foo]] and this should be part of the same list item}}
+!! html
+<ul><li>This and this should be part of the same list item</li>
+<li>So should this and this should be part of the same list item</li></ul>
+!! html/parsoid
+<ul>
+<li>This <link rel="mw:PageProp/Category" href="./Category:Foo"/> and this 
should be part of the same list item</li>
+<li>So should this <link rel="mw:PageProp/Category" href="Category:Foo" 
typeof="mw:Transclusion" 
data-mw='{"parts":[{"template":{"target":{"wt":"echo","href":"./Template:Echo"},"params":{"1":{"wt":"[[Category:Foo]]
 and this should be part of the same list item"}},"i":0}}]}'/><span> and this 
should be part of the same list item</span></li>
+</ul>
+!! end
+
 !! test
 Parsoid: Serialize link to category page with colon escape
 !! options

-- 
To view, visit https://gerrit.wikimedia.org/r/216136
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I507dcefcca5a4ee22fb9f9bf0cfe678f14d64991
Gerrit-PatchSet: 9
Gerrit-Project: mediawiki/services/parsoid
Gerrit-Branch: master
Gerrit-Owner: Subramanya Sastry <[email protected]>
Gerrit-Reviewer: Arlolra <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Cscott <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: GWicke <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: Subramanya Sastry <[email protected]>
Gerrit-Reviewer: Tim Starling <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to