diff --git a/lib/rules_block/table.js b/lib/rules_block/table.js
index 05fc2f360..c46d0c181 100644
--- a/lib/rules_block/table.js
+++ b/lib/rules_block/table.js
@@ -1,4 +1,4 @@
-// GFM table, non-standard
+// GFM table, https://github.github.com/gfm/#tables-extension-
'use strict';
@@ -17,56 +17,42 @@ function escapedSplit(str) {
pos = 0,
max = str.length,
ch,
- escapes = 0,
+ isEscaped = false,
lastPos = 0,
- backTicked = false,
- lastBackTick = 0;
+ current = '';
ch = str.charCodeAt(pos);
while (pos < max) {
- if (ch === 0x60/* ` */) {
- if (backTicked) {
- // make \` close code sequence, but not open it;
- // the reason is: `\` is correct code block
- backTicked = false;
- lastBackTick = pos;
- } else if (escapes % 2 === 0) {
- backTicked = true;
- lastBackTick = pos;
+ if (ch === 0x7c/* | */) {
+ if (!isEscaped) {
+ // pipe separating cells, '|'
+ result.push(current + str.substring(lastPos, pos));
+ current = '';
+ lastPos = pos + 1;
+ } else {
+ // escaped pipe, '\|'
+ current += str.substring(lastPos, pos - 1);
+ lastPos = pos;
}
- } else if (ch === 0x7c/* | */ && (escapes % 2 === 0) && !backTicked) {
- result.push(str.substring(lastPos, pos));
- lastPos = pos + 1;
- }
-
- if (ch === 0x5c/* \ */) {
- escapes++;
- } else {
- escapes = 0;
}
+ isEscaped = (ch === 0x5c/* \ */);
pos++;
- // If there was an un-closed backtick, go back to just after
- // the last backtick, but as if it was a normal character
- if (pos === max && backTicked) {
- backTicked = false;
- pos = lastBackTick + 1;
- }
-
ch = str.charCodeAt(pos);
}
- result.push(str.substring(lastPos));
+ result.push(current + str.substring(lastPos));
return result;
}
module.exports = function table(state, startLine, endLine, silent) {
- var ch, lineText, pos, i, nextLine, columns, columnCount, token,
- aligns, t, tableLines, tbodyLines;
+ var ch, lineText, pos, i, l, nextLine, columns, columnCount, token,
+ aligns, t, tableLines, tbodyLines, oldParentType, terminate,
+ terminatorRules;
// should have at least two lines
if (startLine + 2 > endLine) { return false; }
@@ -125,15 +111,24 @@ module.exports = function table(state, startLine, endLine, silent) {
lineText = getLine(state, startLine).trim();
if (lineText.indexOf('|') === -1) { return false; }
if (state.sCount[startLine] - state.blkIndent >= 4) { return false; }
- columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));
+ columns = escapedSplit(lineText);
+ if (columns.length && columns[0] === '') columns.shift();
+ if (columns.length && columns[columns.length - 1] === '') columns.pop();
// header row will define an amount of columns in the entire table,
- // and align row shouldn't be smaller than that (the rest of the rows can)
+ // and align row should be exactly the same (the rest of the rows can differ)
columnCount = columns.length;
- if (columnCount > aligns.length) { return false; }
+ if (columnCount !== aligns.length) { return false; }
if (silent) { return true; }
+ oldParentType = state.parentType;
+ state.parentType = 'table';
+
+ // use 'blockquote' lists for termination because it's
+ // the most similar to tables
+ terminatorRules = state.md.block.ruler.getRules('blockquote');
+
token = state.push('table_open', 'table', 1);
token.map = tableLines = [ startLine, 0 ];
@@ -161,16 +156,29 @@ module.exports = function table(state, startLine, endLine, silent) {
token = state.push('tr_close', 'tr', -1);
token = state.push('thead_close', 'thead', -1);
- token = state.push('tbody_open', 'tbody', 1);
- token.map = tbodyLines = [ startLine + 2, 0 ];
-
for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {
if (state.sCount[nextLine] < state.blkIndent) { break; }
+ terminate = false;
+ for (i = 0, l = terminatorRules.length; i < l; i++) {
+ if (terminatorRules[i](state, nextLine, endLine, true)) {
+ terminate = true;
+ break;
+ }
+ }
+
+ if (terminate) { break; }
lineText = getLine(state, nextLine).trim();
- if (lineText.indexOf('|') === -1) { break; }
+ if (!lineText) { break; }
if (state.sCount[nextLine] - state.blkIndent >= 4) { break; }
- columns = escapedSplit(lineText.replace(/^\||\|$/g, ''));
+ columns = escapedSplit(lineText);
+ if (columns.length && columns[0] === '') columns.shift();
+ if (columns.length && columns[columns.length - 1] === '') columns.pop();
+
+ if (nextLine === startLine + 2) {
+ token = state.push('tbody_open', 'tbody', 1);
+ token.map = tbodyLines = [ startLine + 2, 0 ];
+ }
token = state.push('tr_open', 'tr', 1);
for (i = 0; i < columnCount; i++) {
@@ -189,10 +197,16 @@ module.exports = function table(state, startLine, endLine, silent) {
}
token = state.push('tr_close', 'tr', -1);
}
- token = state.push('tbody_close', 'tbody', -1);
+
+ if (tbodyLines) {
+ token = state.push('tbody_close', 'tbody', -1);
+ tbodyLines[1] = nextLine;
+ }
+
token = state.push('table_close', 'table', -1);
+ tableLines[1] = nextLine;
- tableLines[1] = tbodyLines[1] = nextLine;
+ state.parentType = oldParentType;
state.line = nextLine;
return true;
};
diff --git a/test/fixtures/markdown-it/tables.txt b/test/fixtures/markdown-it/tables.txt
index dfd34601e..2ddf36772 100644
--- a/test/fixtures/markdown-it/tables.txt
+++ b/test/fixtures/markdown-it/tables.txt
@@ -273,106 +273,6 @@ bar|bar
.
-Should be terminated via row without "|" symbol:
-.
-foo|foo
----|---
-paragraph
-.
-
-paragraph
-.
-
-
-Delimiter escaping:
-.
-| Heading 1 \\\\| Heading 2
-| --------- | ---------
-| Cell\|1\|| Cell\|2
-\| Cell\\\|3 \\| Cell\|4
-.
-
-
-
-Heading 1 \\ |
-Heading 2 |
-
-
-
-
-Cell|1| |
-Cell|2 |
-
-
-| Cell\|3 \ |
-Cell|4 |
-
-
-
-.
-
-Pipes inside backticks don't split cells:
-.
-| Heading 1 | Heading 2
-| --------- | ---------
-| Cell 1 | Cell 2
-| `Cell|3` | Cell 4
-.
-
-
-
-Heading 1 |
-Heading 2 |
-
-
-
-
-Cell 1 |
-Cell 2 |
-
-
-Cell|3 |
-Cell 4 |
-
-
-
-.
-
-Unclosed backticks don't count
-.
-| Heading 1 | Heading 2
-| --------- | ---------
-| Cell 1 | Cell 2
-| `Cell 3| Cell 4
-.
-
-
-
-Heading 1 |
-Heading 2 |
-
-
-
-
-Cell 1 |
-Cell 2 |
-
-
-`Cell 3 |
-Cell 4 |
-
-
-
-.
-
Another complicated backticks case
.
| Heading 1 | Heading 2
@@ -452,7 +352,7 @@ x | \`\` | `x`
An amount of rows might be different across the table (issue #171):
.
| 1 | 2 |
-| :-----: | :-----: | :-----: |
+| :-----: | :-----: |
| 3 | 4 | 5 | 6 |
.
@@ -581,7 +481,6 @@ Tables should not be indented more than 4 spaces (3rd line):
Col2a |
-
| Col1b | Col2b |
@@ -600,7 +499,6 @@ Allow tables with empty body:
Col2a |
-
.
@@ -615,3 +513,234 @@ Col2a | Col2b | Col2c
----- | -----
Col2a | Col2b | Col2c
.
+
+Escaped pipes inside backticks don't split cells:
+.
+| Heading 1 | Heading 2
+| --------- | ---------
+| Cell 1 | Cell 2
+| `Cell 3\|` | Cell 4
+.
+
+
+
+Heading 1 |
+Heading 2 |
+
+
+
+
+Cell 1 |
+Cell 2 |
+
+
+Cell 3| |
+Cell 4 |
+
+
+
+.
+
+Escape before escaped Pipes inside backticks don't split cells:
+.
+| Heading 1 | Heading 2
+| --------- | ---------
+| Cell 1 | Cell 2
+| `Cell 3\\|` | Cell 4
+.
+
+
+
+Heading 1 |
+Heading 2 |
+
+
+
+
+Cell 1 |
+Cell 2 |
+
+
+Cell 3\| |
+Cell 4 |
+
+
+
+.
+
+GFM 4.10 Tables (extension), Example 198
+.
+| foo | bar |
+| --- | --- |
+| baz | bim |
+.
+
+
+
+foo |
+bar |
+
+
+
+
+baz |
+bim |
+
+
+
+.
+
+GFM 4.10 Tables (extension), Example 199
+.
+| abc | defghi |
+:-: | -----------:
+bar | baz
+.
+
+
+
+abc |
+defghi |
+
+
+
+
+bar |
+baz |
+
+
+
+.
+
+GFM 4.10 Tables (extension), Example 200
+.
+| f\|oo |
+| ------ |
+| b `\|` az |
+| b **\|** im |
+.
+
+
+
+f|oo |
+
+
+
+
+b | az |
+
+
+b | im |
+
+
+
+.
+
+GFM 4.10 Tables (extension), Example 201
+.
+| abc | def |
+| --- | --- |
+| bar | baz |
+> bar
+.
+
+
+
+abc |
+def |
+
+
+
+
+bar |
+baz |
+
+
+
+
+bar
+
+.
+
+GFM 4.10 Tables (extension), Example 202
+.
+| abc | def |
+| --- | --- |
+| bar | baz |
+bar
+
+bar
+.
+
+
+
+abc |
+def |
+
+
+
+
+bar |
+baz |
+
+
+bar |
+ |
+
+
+
+bar
+.
+
+GFM 4.10 Tables (extension), Example 203
+.
+| abc | def |
+| --- |
+| bar |
+.
+| abc | def |
+| — |
+| bar |
+.
+
+GFM 4.10 Tables (extension), Example 204
+.
+| abc | def |
+| --- | --- |
+| bar |
+| bar | baz | boo |
+.
+
+
+
+abc |
+def |
+
+
+
+
+bar |
+ |
+
+
+bar |
+baz |
+
+
+
+.
+
+GFM 4.10 Tables (extension), Example 205
+.
+| abc | def |
+| --- | --- |
+.
+
+.