test('should remove leading newline character immediately following the pre element start tag', () => {
const ast = parse(`<pre>\n foo bar </pre>`, {
isPreTag: tag => tag === 'pre',
+ isIgnoreNewlineTag: tag => tag === 'pre',
})
expect(ast.children).toHaveLength(1)
const preElement = ast.children[0] as ElementNode
* e.g. elements that should preserve whitespace inside, e.g. `<pre>`
*/
isPreTag?: (tag: string) => boolean
+ /**
+ * Elements that should ignore the first newline token per parinsg spec
+ * e.g. `<textarea>` and `<pre>`
+ */
+ isIgnoreNewlineTag?: (tag: string) => boolean
/**
* Platform-specific built-in components e.g. `<Transition>`
*/
getNamespace: () => Namespaces.HTML,
isVoidTag: NO,
isPreTag: NO,
+ isIgnoreNewlineTag: NO,
isCustomElement: NO,
onError: defaultOnError,
onWarn: defaultOnWarn,
}
// refine element type
- const { tag, ns } = el
+ const { tag, ns, children } = el
if (!inVPre) {
if (tag === 'slot') {
el.tagType = ElementTypes.SLOT
// whitespace management
if (!tokenizer.inRCDATA) {
- el.children = condenseWhitespace(el.children, el.tag)
+ el.children = condenseWhitespace(children, tag)
}
+
+ if (ns === Namespaces.HTML && currentOptions.isIgnoreNewlineTag(tag)) {
+ // remove leading newline for <textarea> and <pre> per html spec
+ // https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody
+ const first = children[0]
+ if (first && first.type === NodeTypes.TEXT) {
+ first.content = first.content.replace(/^\r?\n/, '')
+ }
+ }
+
if (ns === Namespaces.HTML && currentOptions.isPreTag(tag)) {
inPre--
}
}
}
}
- if (inPre && tag && currentOptions.isPreTag(tag)) {
- // remove leading newline per html spec
- // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element
- const first = nodes[0]
- if (first && first.type === NodeTypes.TEXT) {
- first.content = first.content.replace(/^\r?\n/, '')
- }
- }
return removedWhitespace ? nodes.filter(Boolean) : nodes
}
})
})
+ test('<textarea> should remove leading newline', () => {
+ const ast = parse('<textarea>\nhello</textarea>', parserOptions)
+ const element = ast.children[0] as ElementNode
+ const text = element.children[0] as TextNode
+ expect(element.children.length).toBe(1)
+ expect(text).toStrictEqual({
+ type: NodeTypes.TEXT,
+ content: 'hello',
+ loc: {
+ start: { offset: 10, line: 1, column: 11 },
+ end: { offset: 16, line: 2, column: 6 },
+ source: '\nhello',
+ },
+ })
+ })
+
test('should not treat Uppercase component as special tag', () => {
const ast = parse(
'<TextArea>some<div>text</div>and<!--comment--></TextArea>',
isVoidTag,
isNativeTag: tag => isHTMLTag(tag) || isSVGTag(tag) || isMathMLTag(tag),
isPreTag: tag => tag === 'pre',
+ isIgnoreNewlineTag: tag => tag === 'pre' || tag === 'textarea',
decodeEntities: __BROWSER__ ? decodeHtmlBrowser : undefined,
isBuiltInComponent: tag => {