diff --git a/src/Tokenizer.js b/src/Tokenizer.js index 56656f52f9..38f1328bc9 100644 --- a/src/Tokenizer.js +++ b/src/Tokenizer.js @@ -29,6 +29,34 @@ function outputLink(cap, link, raw) { } } +function indentCodeCompensation(raw, text) { + const matchIndentToCode = raw.match(/^(\s+)(?:```)/); + + if (matchIndentToCode === null) { + return text; + } + + const indentToCode = matchIndentToCode[1]; + + return text + .split('\n') + .map(node => { + const matchIndentInNode = node.match(/^\s+/); + if (matchIndentInNode === null) { + return node; + } + + const [indentInNode] = matchIndentInNode; + + if (indentInNode.length >= indentToCode.length) { + return node.slice(indentToCode.length); + } + + return node; + }) + .join('\n'); +} + /** * Tokenizer */ @@ -77,11 +105,14 @@ module.exports = class Tokenizer { fences(src) { const cap = this.rules.block.fences.exec(src); if (cap) { + const raw = cap[0]; + const text = indentCodeCompensation(raw, cap[3] || ''); + return { type: 'code', - raw: cap[0], + raw, lang: cap[2] ? cap[2].trim() : cap[2], - text: cap[3] || '' + text }; } } diff --git a/test/helpers/helpers.js b/test/helpers/helpers.js index 477f936300..4bb1ecaf99 100644 --- a/test/helpers/helpers.js +++ b/test/helpers/helpers.js @@ -1,5 +1,6 @@ const marked = require('../../src/marked.js'); const htmlDiffer = require('./html-differ.js'); +const assert = require('assert'); beforeEach(() => { marked.setOptions(marked.getDefaults()); @@ -37,6 +38,16 @@ beforeEach(() => { return result; } }; - } + }, + toRenderExact: () => ({ + compare: async(spec, expected) => { + const result = {}; + const actual = marked(spec.markdown, spec.options); + + result.pass = assert.strictEqual(expected, actual) === undefined; + + return result; + } + }) }); }); diff --git a/test/specs/new/code_compensation_indent.html b/test/specs/new/code_compensation_indent.html new file mode 100644 index 0000000000..7b3be00fa9 --- /dev/null +++ b/test/specs/new/code_compensation_indent.html @@ -0,0 +1,6 @@ +

This is some text.

+
    +
  1. This is a list element.

    +
    const x = 5;
    +const y = x + 5;
  2. +
diff --git a/test/specs/new/code_compensation_indent.md b/test/specs/new/code_compensation_indent.md new file mode 100644 index 0000000000..911868e5ae --- /dev/null +++ b/test/specs/new/code_compensation_indent.md @@ -0,0 +1,11 @@ +--- +renderExact: true +--- +This is some text. + +1. This is a list element. + + ``` + const x = 5; + const y = x + 5; + ``` \ No newline at end of file diff --git a/test/specs/run-spec.js b/test/specs/run-spec.js index a9fe3d72c8..5fb5651b6d 100644 --- a/test/specs/run-spec.js +++ b/test/specs/run-spec.js @@ -16,17 +16,22 @@ function runSpecs(title, dir, showCompletionTable, options) { spec.options = Object.assign({}, options, (spec.options || {})); const example = (spec.example ? ' example ' + spec.example : ''); const passFail = (spec.shouldFail ? 'fail' : 'pass'); + if (typeof spec.options.silent === 'undefined') { spec.options.silent = true; } + if (spec.options.sanitizer) { // eslint-disable-next-line no-eval spec.options.sanitizer = eval(spec.options.sanitizer); } + (spec.only ? fit : (spec.skip ? xit : it))('should ' + passFail + example, async() => { const before = process.hrtime(); if (spec.shouldFail) { await expectAsync(spec).not.toRender(spec.html); + } else if (spec.options.renderExact) { + await expectAsync(spec).toRenderExact(spec.html); } else { await expectAsync(spec).toRender(spec.html); }