diff --git a/src/rules.js b/src/rules.js index f64242a15f..d8b60c7d4b 100644 --- a/src/rules.js +++ b/src/rules.js @@ -30,7 +30,7 @@ export const block = { lheading: /^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/, // regex template, placeholders will be replaced according to different paragraph // interruption rules of commonmark and the original markdown spec: - _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/, + _paragraph: /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/, text: /^[^\n]+/ }; @@ -69,6 +69,7 @@ block.paragraph = edit(block._paragraph) .replace('hr', block.hr) .replace('heading', ' {0,3}#{1,6} ') .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs + .replace('|table', '') .replace('blockquote', ' {0,3}>') .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt @@ -107,6 +108,17 @@ block.gfm.table = edit(block.gfm.table) .replace('tag', block._tag) // tables can be interrupted by type (6) html blocks .getRegex(); +block.gfm.paragraph = edit(block._paragraph) + .replace('hr', block.hr) + .replace('heading', ' {0,3}#{1,6} ') + .replace('|lheading', '') // setex headings don't interrupt commonmark paragraphs + .replace('table', block.gfm.table) // interrupt paragraphs with table + .replace('blockquote', ' {0,3}>') + .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n') + .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt + .replace('html', ')|<(?:script|pre|style|textarea|!--)') + .replace('tag', block._tag) // pars can be interrupted by type (6) html blocks + .getRegex(); /** * Pedantic grammar (original John Gruber's loose markdown specification) */ diff --git a/test/specs/new/table_following_text.html b/test/specs/new/table_following_text.html new file mode 100644 index 0000000000..dbd675aff8 --- /dev/null +++ b/test/specs/new/table_following_text.html @@ -0,0 +1,38 @@ +

hello world

+ + + + + + + + + + + + + + + + + +
abcdef
barfoo
bazboo
+

hello world with empty line

+ + + + + + + + + + + + + + + + + +
abcdef
barfoo
bazboo
diff --git a/test/specs/new/table_following_text.md b/test/specs/new/table_following_text.md new file mode 100644 index 0000000000..876e8248ab --- /dev/null +++ b/test/specs/new/table_following_text.md @@ -0,0 +1,15 @@ +--- +gfm: true +--- +hello world +| abc | def | +| --- | --- | +| bar | foo | +| baz | boo | + +hello world with empty line + +| abc | def | +| --- | --- | +| bar | foo | +| baz | boo | diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js index 3ed6261a32..110b04d240 100644 --- a/test/unit/Lexer-spec.js +++ b/test/unit/Lexer-spec.js @@ -204,6 +204,52 @@ lheading 2 }); }); + it('table after para', () => { + expectTokens({ + md: ` +paragraph 1 +| a | b | +|---|---| +| 1 | 2 | +`, + tokens: [ + { + type: 'paragraph', + raw: 'paragraph 1', + text: 'paragraph 1', + tokens: [{ type: 'text', raw: 'paragraph 1', text: 'paragraph 1' }] + }, + { + type: 'table', + align: [null, null], + raw: '| a | b |\n|---|---|\n| 1 | 2 |\n', + header: [ + { + text: 'a', + tokens: [{ type: 'text', raw: 'a', text: 'a' }] + }, + { + text: 'b', + tokens: [{ type: 'text', raw: 'b', text: 'b' }] + } + ], + rows: [ + [ + { + text: '1', + tokens: [{ type: 'text', raw: '1', text: '1' }] + }, + { + text: '2', + tokens: [{ type: 'text', raw: '2', text: '2' }] + } + ] + ] + } + ] + }); + }); + it('align table', () => { expectTokens({ md: `