From 4d680794a5a345078827a3fee3db8658bd35ec3a Mon Sep 17 00:00:00 2001 From: chengchao Date: Mon, 10 Jul 2017 21:42:00 +0800 Subject: [PATCH] fix(parser): the first newline following pre and textarea tag should be ignored (#6022) fix #6022 --- src/compiler/parser/html-parser.js | 18 ++++++++++++++---- test/unit/modules/compiler/parser.spec.js | 18 ++++++++++++++++-- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/compiler/parser/html-parser.js b/src/compiler/parser/html-parser.js index b7c2f1d0e9..670ee3ddf1 100644 --- a/src/compiler/parser/html-parser.js +++ b/src/compiler/parser/html-parser.js @@ -59,6 +59,10 @@ const decodingMap = { const encodedAttr = /&(?:lt|gt|quot|amp);/g const encodedAttrWithNewLines = /&(?:lt|gt|quot|amp|#10);/g +// #5992 +const isIgnoreNewlineTag = makeMap('pre,textarea', true) +const shouldIgnoreFirstNewline = (tag, html) => tag && isIgnoreNewlineTag(tag) && html[0] === '\n' + function decodeAttr (value, shouldDecodeNewlines) { const re = shouldDecodeNewlines ? encodedAttrWithNewLines : encodedAttr return value.replace(re, match => decodingMap[match]) @@ -75,6 +79,9 @@ export function parseHTML (html, options) { last = html // Make sure we're not in a plaintext content element like script/style if (!lastTag || !isPlainTextElement(lastTag)) { + if (shouldIgnoreFirstNewline(lastTag, html)) { + advance(1) + } let textEnd = html.indexOf('<') if (textEnd === 0) { // Comment: @@ -152,16 +159,19 @@ export function parseHTML (html, options) { options.chars(text) } } else { - var stackedTag = lastTag.toLowerCase() - var reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(]*>)', 'i')) - var endTagLength = 0 - var rest = html.replace(reStackedTag, function (all, text, endTag) { + let endTagLength = 0 + const stackedTag = lastTag.toLowerCase() + const reStackedTag = reCache[stackedTag] || (reCache[stackedTag] = new RegExp('([\\s\\S]*?)(]*>)', 'i')) + const rest = html.replace(reStackedTag, function (all, text, endTag) { endTagLength = endTag.length if (!isPlainTextElement(stackedTag) && stackedTag !== 'noscript') { text = text .replace(//g, '$1') .replace(//g, '$1') } + if (shouldIgnoreFirstNewline(stackedTag, text)) { + text = text.slice(1) + } if (options.chars) { options.chars(text) } diff --git a/test/unit/modules/compiler/parser.spec.js b/test/unit/modules/compiler/parser.spec.js index 171faf6672..71e032f15b 100644 --- a/test/unit/modules/compiler/parser.spec.js +++ b/test/unit/modules/compiler/parser.spec.js @@ -495,6 +495,21 @@ describe('parser', () => { expect(span.children[0].text).toBe(' ') }) + // #5992 + it('ignore the first newline in
 tag', function () {
+    const options = extend({}, baseOptions)
+    const ast = parse('
\nabc
\ndef
\n\nabc
', options) + const pre = ast.children[0] + expect(pre.children[0].type).toBe(3) + expect(pre.children[0].text).toBe('abc') + const text = ast.children[1] + expect(text.type).toBe(3) + expect(text.text).toBe('\ndef') + const pre2 = ast.children[2] + expect(pre2.children[0].type).toBe(3) + expect(pre2.children[0].text).toBe('\nabc') + }) + it('forgivingly handle < in plain text', () => { const options = extend({}, baseOptions) const ast = parse('

1 < 2 < 3

', options) @@ -530,8 +545,7 @@ describe('parser', () => { expect(whitespace.children.length).toBe(1) expect(whitespace.children[0].type).toBe(3) // textarea is whitespace sensitive - expect(whitespace.children[0].text).toBe(` -

Test 1

+ expect(whitespace.children[0].text).toBe(`

Test 1

test2 `)