diff --git a/lib/lexer_block/fences.js b/lib/lexer_block/fences.js index 8bd246a..4cba9ab 100644 --- a/lib/lexer_block/fences.js +++ b/lib/lexer_block/fences.js @@ -3,11 +3,13 @@ 'use strict'; -var skipEmptyLines = require('../helpers').skipEmptyLines; +var skipEmptyLines = require('../helpers').skipEmptyLines; +var skipSpaces = require('../helpers').skipSpaces; +var skipChars = require('../helpers').skipChars; module.exports =function fences(state, startLine, endLine, silent) { - var marker, len, params, nextLine, + var marker, len, params, nextLine, mem, pos = state.bMarks[startLine] + state.tShift[startLine], max = state.eMarks[startLine]; @@ -20,43 +22,41 @@ module.exports =function fences(state, startLine, endLine, silent) { } // scan marker length - len = 1; - while (state.src.charCodeAt(++pos) === marker) { - len++; - } + mem = pos; + pos = skipChars(state, pos, marker); + + len = pos - mem; if (len < 3) { return false; } params = state.src.slice(pos, max).trim(); - if (!/\S/.test(params)) { return false; } - // search end of block nextLine = startLine; do { nextLine++; - if (nextLine > endLine) { return false; } + if (nextLine >= endLine) { + // unclosed block should be autoclosed by end of document. + if (state.blkLevel === 0) { + break; + } + return false; + } - pos = state.bMarks[nextLine] + state.tShift[nextLine]; + pos = mem = state.bMarks[nextLine] + state.tShift[nextLine]; max = state.eMarks[nextLine]; - if (pos + 3 > max) { continue; } + if (state.src.charCodeAt(pos) !== marker) { continue; } - // check markers - if (state.src.charCodeAt(pos) !== marker && - state.src.charCodeAt(pos + 1) !== marker && - state.src.charCodeAt(pos + 2) !== marker) { - continue; - } + pos = skipChars(state, pos, marker); - pos += 3; + // closing code fence must be at least as long as the opening one + if (pos - mem < len) { continue; } // make sure tail has spaces only - //pos = pos < max ? skipSpaces(state, pos) : pos; - - // stmd allow any combonation of markers and spaces in tail + pos = skipSpaces(state, pos); if (pos < max) { continue; } @@ -69,7 +69,7 @@ module.exports =function fences(state, startLine, endLine, silent) { state.tokens.push({ type: 'fence', - params: params.split(/\s+/g), + params: params ? params.split(/\s+/g) : [], startLine: startLine + 1, endLine: nextLine }); diff --git a/lib/renderer.js b/lib/renderer.js index 4cf477f..a1ab94d 100644 --- a/lib/renderer.js +++ b/lib/renderer.js @@ -1,13 +1,16 @@ 'use strict'; -function escapeHTML(str) { - return str.replace(/&/g, '&').replace(//g, '>'); +function escapeHtml(str) { + return str.replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"'); } var MD_UNESCAPE_RE = /\\([!"#$%&\'()*+,.\/:;<=>?@[\\\]^_`{|}~-])/g; -function unescapeMD(str) { +function unescapeMd(str) { return str.replace(MD_UNESCAPE_RE, '$1'); } @@ -40,19 +43,20 @@ rules.bullet_list_close = function (state, token) { rules.code = function (state, token) { var content = joinLines(state, token.startLine, token.endLine).replace(/^ {4}/gm, ''); - state.result += '
' + escapeHTML(content) + '
\n'; + state.result += '
' + escapeHtml(content) + '
\n'; }; rules.fence = function (state, token) { var content = joinLines(state, token.startLine, token.endLine); var langMark = ''; + var langPrefix = state.options.codeLangPrefix || ''; if (token.params.length) { - langMark = ' class="language-' + escapeHTML(token.params[0]) + '"'; + langMark = ' class="' + langPrefix + escapeHtml(token.params[0]) + '"'; } - state.result += '
' + escapeHTML(content) + '
\n'; + state.result += '
' + escapeHtml(content) + '
\n'; }; @@ -86,7 +90,7 @@ rules.paragraph_close = function (state, token) { rules.text = function (state, token) { - state.result += escapeHTML(unescapeMD(state.src.slice(token.begin, token.end))); + state.result += escapeHtml(unescapeMd(state.src.slice(token.begin, token.end))); }; diff --git a/test/fixtures/remarkable/code/fence_matching.html b/test/fixtures/remarkable/code/fence_matching.html new file mode 100644 index 0000000..5c8833a --- /dev/null +++ b/test/fixtures/remarkable/code/fence_matching.html @@ -0,0 +1,8 @@ +
```
+
+

+`````
+
+````
+
+
diff --git a/test/fixtures/stmd_pending/Code/FenceMatching.markdown b/test/fixtures/remarkable/code/fence_matching.md similarity index 100% rename from test/fixtures/stmd_pending/Code/FenceMatching.markdown rename to test/fixtures/remarkable/code/fence_matching.md diff --git a/test/fixtures/remarkable/code/fenced_code_blocks.html b/test/fixtures/remarkable/code/fenced_code_blocks.html new file mode 100644 index 0000000..5452844 --- /dev/null +++ b/test/fixtures/remarkable/code/fenced_code_blocks.html @@ -0,0 +1,24 @@ +

This is a fenced code block:

+
pairs :: [(Int,Char)]
+pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']]
+
+

Here is one with tildes:

+
pairs :: [(Int,Char)]
+pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']]
+
+

More metadata:

+
pairs :: [(Int,Char)]
+pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']]
+
+

More backticks:

+
pairs :: [(Int,Char)]
+pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']]
+
+backticks :: String
+backticks = "`````"
+
+

Without an end:

+
code with
+no end
+
+
diff --git a/test/fixtures/stmd_pending/Code/FencedCodeBlocks.markdown b/test/fixtures/remarkable/code/fenced_code_blocks.md similarity index 100% rename from test/fixtures/stmd_pending/Code/FencedCodeBlocks.markdown rename to test/fixtures/remarkable/code/fenced_code_blocks.md diff --git a/test/fixtures/remarked_pending/gfm_code.html b/test/fixtures/remarked_conflicting/code/gfm_code.html similarity index 100% rename from test/fixtures/remarked_pending/gfm_code.html rename to test/fixtures/remarked_conflicting/code/gfm_code.html diff --git a/test/fixtures/remarked_pending/gfm_code.md b/test/fixtures/remarked_conflicting/code/gfm_code.md similarity index 100% rename from test/fixtures/remarked_pending/gfm_code.md rename to test/fixtures/remarked_conflicting/code/gfm_code.md diff --git a/test/fixtures/stmd_pending/Code/FenceMatching.html b/test/fixtures/stmd_conflicting/Code/FenceMatching.html similarity index 100% rename from test/fixtures/stmd_pending/Code/FenceMatching.html rename to test/fixtures/stmd_conflicting/Code/FenceMatching.html diff --git a/test/fixtures/stmd_conflicting/Code/FenceMatching.markdown b/test/fixtures/stmd_conflicting/Code/FenceMatching.markdown new file mode 100644 index 0000000..d86169a --- /dev/null +++ b/test/fixtures/stmd_conflicting/Code/FenceMatching.markdown @@ -0,0 +1,10 @@ +````abc +``` +```` +``````blah + +````` + +```` + +``````````` diff --git a/test/fixtures/stmd_pending/Code/FencedCodeBlocks.html b/test/fixtures/stmd_conflicting/Code/FencedCodeBlocks.html similarity index 100% rename from test/fixtures/stmd_pending/Code/FencedCodeBlocks.html rename to test/fixtures/stmd_conflicting/Code/FencedCodeBlocks.html diff --git a/test/fixtures/stmd_conflicting/Code/FencedCodeBlocks.markdown b/test/fixtures/stmd_conflicting/Code/FencedCodeBlocks.markdown new file mode 100644 index 0000000..6ccc6be --- /dev/null +++ b/test/fixtures/stmd_conflicting/Code/FencedCodeBlocks.markdown @@ -0,0 +1,35 @@ +This is a fenced code block: +```haskell +pairs :: [(Int,Char)] +pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']] +``` +Here is one with tildes: + +~~~ haskell +pairs :: [(Int,Char)] +pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']] +~~~ + +More metadata: + +```haskell numberLines start=50 +pairs :: [(Int,Char)] +pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']] +``` + +More backticks: + +```````` haskell +pairs :: [(Int,Char)] +pairs = [(x,y) | x <- [0..10], y <- ['a'..'z']] + +backticks :: String +backticks = "`````" +````````````` + +Without an end: + +``` +code with +no end + diff --git a/test/remarked.js b/test/remarked.js index 3a5634c..9a21f30 100644 --- a/test/remarked.js +++ b/test/remarked.js @@ -12,6 +12,11 @@ var Remarked = require('../'); describe('remarked', function () { var md = new Remarked(); + // Set options, to give output more close to remarked + md.set({ + codeLangPrefix: 'lang-' + }); + utils.addTests(path.join(__dirname, 'fixtures/remarked_ok'), md); }); diff --git a/test/utils.js b/test/utils.js index 8ece3cb..b32a63a 100644 --- a/test/utils.js +++ b/test/utils.js @@ -41,11 +41,11 @@ function addTests(dir, md, skip) { if (!skip) { it(base, function () { - assert.strictEqual(right, md.render(src)); + assert.strictEqual(md.render(src), right); }); } else { it.skip(base, function () { - assert.strictEqual(right, md.render(src)); + assert.strictEqual(md.render(src), right); }); } }