Skip to content

Commit

Permalink
fix(compiler-dom): should ignore leading newline in <textarea> per spec
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Sep 13, 2024
1 parent 10a2c60 commit 3c4bf76
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 10 deletions.
1 change: 1 addition & 0 deletions packages/compiler-core/__tests__/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2369,6 +2369,7 @@ describe('compiler: parse', () => {
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
Expand Down
5 changes: 5 additions & 0 deletions packages/compiler-core/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ export interface ParserOptions
* 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>`
*/
Expand Down
23 changes: 13 additions & 10 deletions packages/compiler-core/src/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const defaultParserOptions: MergedParserOptions = {
getNamespace: () => Namespaces.HTML,
isVoidTag: NO,
isPreTag: NO,
isIgnoreNewlineTag: NO,
isCustomElement: NO,
onError: defaultOnError,
onWarn: defaultOnWarn,
Expand Down Expand Up @@ -633,7 +634,7 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {
}

// refine element type
const { tag, ns } = el
const { tag, ns, children } = el
if (!inVPre) {
if (tag === 'slot') {
el.tagType = ElementTypes.SLOT
Expand All @@ -646,8 +647,18 @@ function onCloseTag(el: ElementNode, end: number, isImplied = false) {

// 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--
}
Expand Down Expand Up @@ -869,14 +880,6 @@ function condenseWhitespace(
}
}
}
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
}

Expand Down
16 changes: 16 additions & 0 deletions packages/compiler-dom/__tests__/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ describe('DOM parser', () => {
})
})

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>',
Expand Down
1 change: 1 addition & 0 deletions packages/compiler-dom/src/parserOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const parserOptions: ParserOptions = {
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 => {
Expand Down

0 comments on commit 3c4bf76

Please sign in to comment.