Parcourir la source

fix(lists): enforce 4 space indentation in sublists

Acording to the spec, multi paragraph (or block) list item requires subblocks
to be indented 4 spaces (or 1 tab). Although, this is mentioned in the documentation,
Showdown didn't enforce this rule in sublists because other implementations,
such as GFM also didn't. However, in some edge cases, this led to inconsistent behavior,
as shown in issue #299. This commit makes 4 space indentation in sublists
mandatory.

BREAKING CHANGE: syntax for sublists is more restrictive. Before, sublists SHOULD be
indented by 4 spaces, but indenting 2 spaces would work. Now, sublists MUST be
indented 4 spaces or they won't work.

With this input:
```md
* one
  * two
    * three
```

Before (ouput):
```html
<ul>
  <li>one
    <ul>
      <li>two
        <ul><li>three</li></ul>
      <li>
    </ul>
  </li>
<ul>
```

After (output):
```html
<ul>
  <li>one</li>
  <li>two
    <ul><li>three</li></ul>
  </li>
</ul>
```

To migrate either fix source md files or activate the option `disableForced4SpacesIndentedSublists` (coming in v1.5.0):

```md
showdown.setOption('disableForced4SpacesIndentedSublists', true);
```
Estevao Soares dos Santos il y a 8 ans
Parent
commit
d51be6e0b4

+ 21 - 18
dist/showdown.js

@@ -1,4 +1,4 @@
-;/*! showdown 09-11-2016 */
+;/*! showdown 11-11-2016 */
 (function(){
 /**
  * Created by Tivie on 13-07-2015.
@@ -1951,11 +1951,12 @@ showdown.subParser('lists', function (text, options, globals) {
     // attacklab: add sentinel to emulate \z
     listStr += '~0';
 
-    var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
+    var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,
         isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
 
     listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
       checked = (checked && checked.trim() !== '');
+
       var item = showdown.subParser('outdent')(m4, options, globals),
           bulletStyle = '';
 
@@ -1971,6 +1972,7 @@ showdown.subParser('lists', function (text, options, globals) {
           return otp;
         });
       }
+
       // m1 - Leading line or
       // Has a double return (multi paragraph) or
       // Has sublist
@@ -2013,8 +2015,10 @@ showdown.subParser('lists', function (text, options, globals) {
   function parseConsecutiveLists(list, listType, trimTrailing) {
     // check if we caught 2 or more consecutive lists by mistake
     // we use the counterRgx, meaning if listType is UL we look for OL and vice versa
-    var counterRxg = (listType === 'ul') ? /^\d+\.[ \t]/gm : /^[*+-][ \t]/gm,
-      result = '';
+    var olRgx = /^ {0,3}\d+\.[ \t]/gm,
+        ulRgx = /^ {0,3}[*+-][ \t]/gm,
+        counterRxg = (listType === 'ul') ? olRgx : ulRgx,
+        result = '';
 
     if (list.search(counterRxg) !== -1) {
       (function parseCL(txt) {
@@ -2025,7 +2029,7 @@ showdown.subParser('lists', function (text, options, globals) {
 
           // invert counterType and listType
           listType = (listType === 'ul') ? 'ol' : 'ul';
-          counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
+          counterRxg = (listType === 'ul') ? olRgx : ulRgx;
 
           //recurse
           parseCL(txt.slice(pos));
@@ -2044,21 +2048,20 @@ showdown.subParser('lists', function (text, options, globals) {
   // http://bugs.webkit.org/show_bug.cgi?id=11231
   text += '~0';
 
-  // Re-usable pattern to match any entire ul or ol list:
-  var wholeList = /^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
-
   if (globals.gListLevel) {
-    text = text.replace(wholeList, function (wholeMatch, list, m2) {
-      var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
-      return parseConsecutiveLists(list, listType, true);
-    });
+    text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
+      function (wholeMatch, list, m2) {
+        var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
+        return parseConsecutiveLists(list, listType, true);
+      }
+    );
   } else {
-    wholeList = /(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
-    text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
-
-      var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
-      return parseConsecutiveLists(list, listType, false);
-    });
+    text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
+      function (wholeMatch, m1, list, m3) {
+        var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
+        return parseConsecutiveLists(list, listType, false);
+      }
+    );
   }
 
   // strip sentinel

Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
dist/showdown.js.map


Fichier diff supprimé car celui-ci est trop grand
+ 1 - 1
dist/showdown.min.js


Fichier diff supprimé car celui-ci est trop grand
+ 0 - 0
dist/showdown.min.js.map


+ 20 - 17
src/subParsers/lists.js

@@ -41,11 +41,12 @@ showdown.subParser('lists', function (text, options, globals) {
     // attacklab: add sentinel to emulate \z
     listStr += '~0';
 
-    var rgx = /(\n)?(^[ \t]*)([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0|\2([*+-]|\d+[.])[ \t]+))/gm,
+    var rgx = /(\n)?(^ {0,3})([*+-]|\d+[.])[ \t]+((\[(x|X| )?])?[ \t]*[^\r]+?(\n{1,2}))(?=\n*(~0| {0,3}([*+-]|\d+[.])[ \t]+))/gm,
         isParagraphed = (/\n[ \t]*\n(?!~0)/.test(listStr));
 
     listStr = listStr.replace(rgx, function (wholeMatch, m1, m2, m3, m4, taskbtn, checked) {
       checked = (checked && checked.trim() !== '');
+
       var item = showdown.subParser('outdent')(m4, options, globals),
           bulletStyle = '';
 
@@ -61,6 +62,7 @@ showdown.subParser('lists', function (text, options, globals) {
           return otp;
         });
       }
+
       // m1 - Leading line or
       // Has a double return (multi paragraph) or
       // Has sublist
@@ -103,8 +105,10 @@ showdown.subParser('lists', function (text, options, globals) {
   function parseConsecutiveLists(list, listType, trimTrailing) {
     // check if we caught 2 or more consecutive lists by mistake
     // we use the counterRgx, meaning if listType is UL we look for OL and vice versa
-    var counterRxg = (listType === 'ul') ? /^\d+\.[ \t]/gm : /^[*+-][ \t]/gm,
-      result = '';
+    var olRgx = /^ {0,3}\d+\.[ \t]/gm,
+        ulRgx = /^ {0,3}[*+-][ \t]/gm,
+        counterRxg = (listType === 'ul') ? olRgx : ulRgx,
+        result = '';
 
     if (list.search(counterRxg) !== -1) {
       (function parseCL(txt) {
@@ -115,7 +119,7 @@ showdown.subParser('lists', function (text, options, globals) {
 
           // invert counterType and listType
           listType = (listType === 'ul') ? 'ol' : 'ul';
-          counterRxg = (listType === 'ul') ? /^ {0,2}\d+\.[ \t]/gm : /^ {0,2}[*+-][ \t]/gm;
+          counterRxg = (listType === 'ul') ? olRgx : ulRgx;
 
           //recurse
           parseCL(txt.slice(pos));
@@ -134,21 +138,20 @@ showdown.subParser('lists', function (text, options, globals) {
   // http://bugs.webkit.org/show_bug.cgi?id=11231
   text += '~0';
 
-  // Re-usable pattern to match any entire ul or ol list:
-  var wholeList = /^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
-
   if (globals.gListLevel) {
-    text = text.replace(wholeList, function (wholeMatch, list, m2) {
-      var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
-      return parseConsecutiveLists(list, listType, true);
-    });
+    text = text.replace(/^(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
+      function (wholeMatch, list, m2) {
+        var listType = (m2.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
+        return parseConsecutiveLists(list, listType, true);
+      }
+    );
   } else {
-    wholeList = /(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm;
-    text = text.replace(wholeList, function (wholeMatch, m1, list, m3) {
-
-      var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
-      return parseConsecutiveLists(list, listType, false);
-    });
+    text = text.replace(/(\n\n|^\n?)(( {0,3}([*+-]|\d+[.])[ \t]+)[^\r]+?(~0|\n{2,}(?=\S)(?![ \t]*(?:[*+-]|\d+[.])[ \t]+)))/gm,
+      function (wholeMatch, m1, list, m3) {
+        var listType = (m3.search(/[*+-]/g) > -1) ? 'ul' : 'ol';
+        return parseConsecutiveLists(list, listType, false);
+      }
+    );
   }
 
   // strip sentinel

+ 4 - 4
test/cases/paragraphed-list-with-sublists.md

@@ -1,13 +1,13 @@
  - foo
  
-   - bazinga
+    - bazinga
     
-   - yeah
+    - yeah
  
  - bar
  
-   1. damn
+    1. damn
     
-   2. so many paragraphs
+    2. so many paragraphs
  
  - baz

+ 6 - 6
test/issues/#196.entity-in-code-block-in-nested-list.md

@@ -2,9 +2,9 @@ Test pre in a list
 
 - & <
 - `& <` 
-   - & <
-   - `& <`
-      - & <
-      - `& <`
-         - & <
-         - `& <`
+    - & <
+    - `& <`
+        - & <
+        - `& <`
+            - & <
+            - `& <`

+ 54 - 0
test/issues/#299.nested-ordered-unordered-list-inconsistent-behavior-2.html

@@ -0,0 +1,54 @@
+<ul>
+    <li>one</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>
+<p>foo</p>
+<ul>
+    <li>one</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>
+<p>foo</p>
+<ul>
+    <li>one</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>
+<p>foo</p>
+<ul>
+    <li>one
+
+        <ol>
+            <li>two</li></ol></li>
+</ul>
+<p>foo</p>
+<ul>
+    <li>one</li>
+    <li>two</li>
+</ul>
+<p>foo</p>
+<ul>
+    <li>one</li>
+    <li>two</li>
+</ul>
+<p>foo</p>
+<ul>
+    <li>one</li>
+    <li>two</li>
+</ul>
+<p>foo</p>
+<ul>
+    <li>one</li>
+    <li>two</li>
+</ul>
+<p>foo</p>
+<ul>
+    <li>one
+
+        <ul>
+            <li>two</li></ul></li>
+</ul>

+ 42 - 0
test/issues/#299.nested-ordered-unordered-list-inconsistent-behavior-2.md

@@ -0,0 +1,42 @@
+ * one
+ 1. two
+
+foo
+
+  * one
+  1. two
+
+foo
+
+   * one
+   1. two
+
+foo
+
+   * one
+     1. two
+
+foo
+
+ * one
+ * two
+
+foo
+
+  * one
+  * two
+
+foo
+
+   * one
+   * two
+
+foo
+
+   * one
+* two
+
+foo
+
+   * one
+    * two

+ 15 - 0
test/issues/#299.nested-ordered-unordered-list-inconsistent-behavior-3.html

@@ -0,0 +1,15 @@
+<ul>
+    <li>one long paragraph of
+text</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>
+<p>foo</p>
+<ul>
+    <li>one long paragraph of
+text</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>

+ 9 - 0
test/issues/#299.nested-ordered-unordered-list-inconsistent-behavior-3.md

@@ -0,0 +1,9 @@
+ * one long paragraph of
+text
+ 1. two
+
+foo
+
+  * one long paragraph of
+text
+   1. two

+ 35 - 8
test/issues/#299.nested-ordered-unordered-list-inconsistent-behavior.html

@@ -6,15 +6,42 @@
 </ol>
 <p>foo</p>
 <ul>
-    <li>one
-
-        <ol>
-            <li>two</li></ol></li>
+    <li>one</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>
+<p>foo</p>
+<ul>
+    <li>one</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>
+<p>foo</p>
+<ul>
+    <li>one</li>
+</ul>
+<ol>
+    <li>two</li>
+</ol>
+<p>foo</p>
+<ul>
+    <li>uli one</li>
+    <li>uli two</li>
+</ul>
+<p>foo</p>
+<ul>
+    <li>uli one</li>
+    <li>uli two</li>
+</ul>
+<p>foo</p>
+<ul>
+    <li>uli one</li>
+    <li>uli two</li>
 </ul>
 <p>foo</p>
 <ul>
-    <li>one
-
-        <ul>
-            <li>two</li></ul></li>
+    <li>uli one</li>
+    <li>uli two</li>
 </ul>

+ 26 - 1
test/issues/#299.nested-ordered-unordered-list-inconsistent-behavior.md

@@ -9,4 +9,29 @@ foo
 foo
 
 * one
- * two
+  1. two
+
+foo
+
+* one
+   1. two
+
+foo
+
+* uli one
+* uli two
+
+foo
+
+* uli one
+ * uli two
+
+foo
+
+* uli one
+  * uli two
+
+foo
+
+* uli one
+   * uli two

Certains fichiers n'ont pas été affichés car il y a eu trop de fichiers modifiés dans ce diff