diff --git a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap index 924038450..8886ce337 100644 --- a/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap +++ b/packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap @@ -1,5 +1,501 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`compiler: parse > Edge Cases > invalid html 1`] = ` +{ + "cached": 0, + "children": [ + { + "children": [ + { + "children": [], + "codegenNode": undefined, + "loc": { + "end": { + "column": 1, + "line": 3, + "offset": 13, + }, + "source": " +", + "start": { + "column": 1, + "line": 2, + "offset": 6, + }, + }, + "ns": 0, + "props": [], + "tag": "span", + "tagType": 0, + "type": 1, + }, + ], + "codegenNode": undefined, + "loc": { + "end": { + "column": 7, + "line": 3, + "offset": 19, + }, + "source": "
+ +
", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "ns": 0, + "props": [], + "tag": "div", + "tagType": 0, + "type": 1, + }, + ], + "codegenNode": undefined, + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { + "column": 8, + "line": 4, + "offset": 27, + }, + "source": "
+ +
+
", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "source": "
+ +
+", + "temps": 0, + "type": 0, +} +`; + +exports[`compiler: parse > Edge Cases > self closing multiple tag 1`] = ` +{ + "cached": 0, + "children": [ + { + "children": [], + "codegenNode": undefined, + "isSelfClosing": true, + "loc": { + "end": { + "column": 37, + "line": 1, + "offset": 36, + }, + "source": "
", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "ns": 0, + "props": [ + { + "arg": { + "constType": 3, + "content": "class", + "isStatic": true, + "loc": { + "end": { + "column": 12, + "line": 1, + "offset": 11, + }, + "source": "class", + "start": { + "column": 7, + "line": 1, + "offset": 6, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ some: condition }", + "isStatic": false, + "loc": { + "end": { + "column": 33, + "line": 1, + "offset": 32, + }, + "source": "{ some: condition }", + "start": { + "column": 14, + "line": 1, + "offset": 13, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 34, + "line": 1, + "offset": 33, + }, + "source": ":class=\\"{ some: condition }\\"", + "start": { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": ":class", + "type": 7, + }, + ], + "tag": "div", + "tagType": 0, + "type": 1, + }, + { + "children": [], + "codegenNode": undefined, + "isSelfClosing": true, + "loc": { + "end": { + "column": 37, + "line": 2, + "offset": 73, + }, + "source": "

", + "start": { + "column": 1, + "line": 2, + "offset": 37, + }, + }, + "ns": 0, + "props": [ + { + "arg": { + "constType": 3, + "content": "style", + "isStatic": true, + "loc": { + "end": { + "column": 16, + "line": 2, + "offset": 52, + }, + "source": "style", + "start": { + "column": 11, + "line": 2, + "offset": 47, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ color: 'red' }", + "isStatic": false, + "loc": { + "end": { + "column": 34, + "line": 2, + "offset": 70, + }, + "source": "{ color: 'red' }", + "start": { + "column": 18, + "line": 2, + "offset": 54, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 35, + "line": 2, + "offset": 71, + }, + "source": "v-bind:style=\\"{ color: 'red' }\\"", + "start": { + "column": 4, + "line": 2, + "offset": 40, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": "v-bind:style", + "type": 7, + }, + ], + "tag": "p", + "tagType": 0, + "type": 1, + }, + ], + "codegenNode": undefined, + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { + "column": 37, + "line": 2, + "offset": 73, + }, + "source": "

+

", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "source": "

+

", + "temps": 0, + "type": 0, +} +`; + +exports[`compiler: parse > Edge Cases > valid html 1`] = ` +{ + "cached": 0, + "children": [ + { + "children": [ + { + "children": [], + "codegenNode": undefined, + "isSelfClosing": true, + "loc": { + "end": { + "column": 39, + "line": 2, + "offset": 73, + }, + "source": "

", + "start": { + "column": 3, + "line": 2, + "offset": 37, + }, + }, + "ns": 0, + "props": [ + { + "arg": { + "constType": 3, + "content": "style", + "isStatic": true, + "loc": { + "end": { + "column": 18, + "line": 2, + "offset": 52, + }, + "source": "style", + "start": { + "column": 13, + "line": 2, + "offset": 47, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ color: 'red' }", + "isStatic": false, + "loc": { + "end": { + "column": 36, + "line": 2, + "offset": 70, + }, + "source": "{ color: 'red' }", + "start": { + "column": 20, + "line": 2, + "offset": 54, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 37, + "line": 2, + "offset": 71, + }, + "source": "v-bind:style=\\"{ color: 'red' }\\"", + "start": { + "column": 6, + "line": 2, + "offset": 40, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": "v-bind:style", + "type": 7, + }, + ], + "tag": "p", + "tagType": 0, + "type": 1, + }, + { + "content": " a comment with inside it ", + "loc": { + "end": { + "column": 43, + "line": 3, + "offset": 116, + }, + "source": "", + "start": { + "column": 3, + "line": 3, + "offset": 76, + }, + }, + "type": 3, + }, + ], + "codegenNode": undefined, + "loc": { + "end": { + "column": 7, + "line": 4, + "offset": 123, + }, + "source": "

+

+ +

", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "ns": 0, + "props": [ + { + "arg": { + "constType": 3, + "content": "class", + "isStatic": true, + "loc": { + "end": { + "column": 12, + "line": 1, + "offset": 11, + }, + "source": "class", + "start": { + "column": 7, + "line": 1, + "offset": 6, + }, + }, + "type": 4, + }, + "exp": { + "constType": 0, + "content": "{ some: condition }", + "isStatic": false, + "loc": { + "end": { + "column": 33, + "line": 1, + "offset": 32, + }, + "source": "{ some: condition }", + "start": { + "column": 14, + "line": 1, + "offset": 13, + }, + }, + "type": 4, + }, + "loc": { + "end": { + "column": 34, + "line": 1, + "offset": 33, + }, + "source": ":class=\\"{ some: condition }\\"", + "start": { + "column": 6, + "line": 1, + "offset": 5, + }, + }, + "modifiers": [], + "name": "bind", + "rawName": ":class", + "type": 7, + }, + ], + "tag": "div", + "tagType": 0, + "type": 1, + }, + ], + "codegenNode": undefined, + "components": [], + "directives": [], + "helpers": Set {}, + "hoists": [], + "imports": [], + "loc": { + "end": { + "column": 7, + "line": 4, + "offset": 123, + }, + "source": "
+

+ +

", + "start": { + "column": 1, + "line": 1, + "offset": 0, + }, + }, + "source": "
+

+ +

", + "temps": 0, + "type": 0, +} +`; + exports[`compiler: parse > Errors > CDATA_IN_HTML_CONTENT > 1`] = ` { "cached": 0, @@ -4326,499 +4822,3 @@ exports[`compiler: parse > Errors > X_MISSING_INTERPOLATION_END > {{}} 1`] = ` "type": 0, } `; - -exports[`compiler: parse > invalid html 1`] = ` -{ - "cached": 0, - "children": [ - { - "children": [ - { - "children": [], - "codegenNode": undefined, - "loc": { - "end": { - "column": 1, - "line": 3, - "offset": 13, - }, - "source": " -", - "start": { - "column": 1, - "line": 2, - "offset": 6, - }, - }, - "ns": 0, - "props": [], - "tag": "span", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "loc": { - "end": { - "column": 7, - "line": 3, - "offset": 19, - }, - "source": "
- -
", - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "ns": 0, - "props": [], - "tag": "div", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "components": [], - "directives": [], - "helpers": Set {}, - "hoists": [], - "imports": [], - "loc": { - "end": { - "column": 8, - "line": 4, - "offset": 27, - }, - "source": "
- -
-
", - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "source": "
- -
-", - "temps": 0, - "type": 0, -} -`; - -exports[`compiler: parse > self closing multiple tag 1`] = ` -{ - "cached": 0, - "children": [ - { - "children": [], - "codegenNode": undefined, - "isSelfClosing": true, - "loc": { - "end": { - "column": 37, - "line": 1, - "offset": 36, - }, - "source": "
", - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "ns": 0, - "props": [ - { - "arg": { - "constType": 3, - "content": "class", - "isStatic": true, - "loc": { - "end": { - "column": 12, - "line": 1, - "offset": 11, - }, - "source": "class", - "start": { - "column": 7, - "line": 1, - "offset": 6, - }, - }, - "type": 4, - }, - "exp": { - "constType": 0, - "content": "{ some: condition }", - "isStatic": false, - "loc": { - "end": { - "column": 33, - "line": 1, - "offset": 32, - }, - "source": "{ some: condition }", - "start": { - "column": 14, - "line": 1, - "offset": 13, - }, - }, - "type": 4, - }, - "loc": { - "end": { - "column": 34, - "line": 1, - "offset": 33, - }, - "source": ":class=\\"{ some: condition }\\"", - "start": { - "column": 6, - "line": 1, - "offset": 5, - }, - }, - "modifiers": [], - "name": "bind", - "rawName": ":class", - "type": 7, - }, - ], - "tag": "div", - "tagType": 0, - "type": 1, - }, - { - "children": [], - "codegenNode": undefined, - "isSelfClosing": true, - "loc": { - "end": { - "column": 37, - "line": 2, - "offset": 73, - }, - "source": "

", - "start": { - "column": 1, - "line": 2, - "offset": 37, - }, - }, - "ns": 0, - "props": [ - { - "arg": { - "constType": 3, - "content": "style", - "isStatic": true, - "loc": { - "end": { - "column": 16, - "line": 2, - "offset": 52, - }, - "source": "style", - "start": { - "column": 11, - "line": 2, - "offset": 47, - }, - }, - "type": 4, - }, - "exp": { - "constType": 0, - "content": "{ color: 'red' }", - "isStatic": false, - "loc": { - "end": { - "column": 34, - "line": 2, - "offset": 70, - }, - "source": "{ color: 'red' }", - "start": { - "column": 18, - "line": 2, - "offset": 54, - }, - }, - "type": 4, - }, - "loc": { - "end": { - "column": 35, - "line": 2, - "offset": 71, - }, - "source": "v-bind:style=\\"{ color: 'red' }\\"", - "start": { - "column": 4, - "line": 2, - "offset": 40, - }, - }, - "modifiers": [], - "name": "bind", - "rawName": "v-bind:style", - "type": 7, - }, - ], - "tag": "p", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "components": [], - "directives": [], - "helpers": Set {}, - "hoists": [], - "imports": [], - "loc": { - "end": { - "column": 37, - "line": 2, - "offset": 73, - }, - "source": "

-

", - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "source": "

-

", - "temps": 0, - "type": 0, -} -`; - -exports[`compiler: parse > valid html 1`] = ` -{ - "cached": 0, - "children": [ - { - "children": [ - { - "children": [], - "codegenNode": undefined, - "isSelfClosing": true, - "loc": { - "end": { - "column": 39, - "line": 2, - "offset": 73, - }, - "source": "

", - "start": { - "column": 3, - "line": 2, - "offset": 37, - }, - }, - "ns": 0, - "props": [ - { - "arg": { - "constType": 3, - "content": "style", - "isStatic": true, - "loc": { - "end": { - "column": 18, - "line": 2, - "offset": 52, - }, - "source": "style", - "start": { - "column": 13, - "line": 2, - "offset": 47, - }, - }, - "type": 4, - }, - "exp": { - "constType": 0, - "content": "{ color: 'red' }", - "isStatic": false, - "loc": { - "end": { - "column": 36, - "line": 2, - "offset": 70, - }, - "source": "{ color: 'red' }", - "start": { - "column": 20, - "line": 2, - "offset": 54, - }, - }, - "type": 4, - }, - "loc": { - "end": { - "column": 37, - "line": 2, - "offset": 71, - }, - "source": "v-bind:style=\\"{ color: 'red' }\\"", - "start": { - "column": 6, - "line": 2, - "offset": 40, - }, - }, - "modifiers": [], - "name": "bind", - "rawName": "v-bind:style", - "type": 7, - }, - ], - "tag": "p", - "tagType": 0, - "type": 1, - }, - { - "content": " a comment with inside it ", - "loc": { - "end": { - "column": 43, - "line": 3, - "offset": 116, - }, - "source": "", - "start": { - "column": 3, - "line": 3, - "offset": 76, - }, - }, - "type": 3, - }, - ], - "codegenNode": undefined, - "loc": { - "end": { - "column": 7, - "line": 4, - "offset": 123, - }, - "source": "

-

- -

", - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "ns": 0, - "props": [ - { - "arg": { - "constType": 3, - "content": "class", - "isStatic": true, - "loc": { - "end": { - "column": 12, - "line": 1, - "offset": 11, - }, - "source": "class", - "start": { - "column": 7, - "line": 1, - "offset": 6, - }, - }, - "type": 4, - }, - "exp": { - "constType": 0, - "content": "{ some: condition }", - "isStatic": false, - "loc": { - "end": { - "column": 33, - "line": 1, - "offset": 32, - }, - "source": "{ some: condition }", - "start": { - "column": 14, - "line": 1, - "offset": 13, - }, - }, - "type": 4, - }, - "loc": { - "end": { - "column": 34, - "line": 1, - "offset": 33, - }, - "source": ":class=\\"{ some: condition }\\"", - "start": { - "column": 6, - "line": 1, - "offset": 5, - }, - }, - "modifiers": [], - "name": "bind", - "rawName": ":class", - "type": 7, - }, - ], - "tag": "div", - "tagType": 0, - "type": 1, - }, - ], - "codegenNode": undefined, - "components": [], - "directives": [], - "helpers": Set {}, - "hoists": [], - "imports": [], - "loc": { - "end": { - "column": 7, - "line": 4, - "offset": 123, - }, - "source": "
-

- -

", - "start": { - "column": 1, - "line": 1, - "offset": 0, - }, - }, - "source": "
-

- -

", - "temps": 0, - "type": 0, -} -`; diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts index 4e6c80b38..05a2afcdc 100644 --- a/packages/compiler-core/__tests__/parse.spec.ts +++ b/packages/compiler-core/__tests__/parse.spec.ts @@ -1796,166 +1796,167 @@ describe('compiler: parse', () => { }) }) - test('self closing single tag', () => { - const ast = baseParse('
') + describe('Edge Cases', () => { + test('self closing single tag', () => { + const ast = baseParse('
') - expect(ast.children).toHaveLength(1) - expect(ast.children[0]).toMatchObject({ tag: 'div' }) - }) - - test('self closing multiple tag', () => { - const ast = baseParse( - `
\n` + - `

` - ) - - expect(ast).toMatchSnapshot() - - expect(ast.children).toHaveLength(2) - expect(ast.children[0]).toMatchObject({ tag: 'div' }) - expect(ast.children[1]).toMatchObject({ tag: 'p' }) - }) - - test('valid html', () => { - const ast = baseParse( - `

\n` + - `

\n` + - ` \n` + - `

` - ) - - expect(ast).toMatchSnapshot() - - expect(ast.children).toHaveLength(1) - const el = ast.children[0] as any - expect(el).toMatchObject({ - tag: 'div' - }) - expect(el.children).toHaveLength(2) - expect(el.children[0]).toMatchObject({ - tag: 'p' - }) - expect(el.children[1]).toMatchObject({ - type: NodeTypes.COMMENT - }) - }) - - test('invalid html', () => { - expect(() => { - baseParse(`
\n\n
\n`) - }).toThrow('Element is missing end tag.') - - const spy = vi.fn() - const ast = baseParse(`
\n\n
\n`, { - onError: spy + expect(ast.children).toHaveLength(1) + expect(ast.children[0]).toMatchObject({ tag: 'div' }) }) - expect(spy.mock.calls).toMatchObject([ - [ - { - code: ErrorCodes.X_MISSING_END_TAG, - loc: { - start: { - offset: 6, - line: 2, - column: 1 - } - } - } - ], - [ - { - code: ErrorCodes.X_INVALID_END_TAG, - loc: { - start: { - offset: 20, - line: 4, - column: 1 - } - } - } - ] - ]) + test('self closing multiple tag', () => { + const ast = baseParse( + `
\n` + + `

` + ) - expect(ast).toMatchSnapshot() - }) + expect(ast).toMatchSnapshot() - test('parse with correct location info', () => { - const fooSrc = `foo - is ` - const barSrc = `{{ bar }}` - const butSrc = ` but ` - const bazSrc = `{{ baz }}` - const [foo, bar, but, baz] = baseParse( - fooSrc + barSrc + butSrc + bazSrc - ).children + expect(ast.children).toHaveLength(2) + expect(ast.children[0]).toMatchObject({ tag: 'div' }) + expect(ast.children[1]).toMatchObject({ tag: 'p' }) + }) - let offset = 0 - expect(foo.loc.start).toEqual({ line: 1, column: 1, offset }) - offset += fooSrc.length - expect(foo.loc.end).toEqual({ line: 2, column: 5, offset }) + test('valid html', () => { + const ast = baseParse( + `

\n` + + `

\n` + + ` \n` + + `

` + ) - expect(bar.loc.start).toEqual({ line: 2, column: 5, offset }) - const barInner = (bar as InterpolationNode).content - offset += 3 - expect(barInner.loc.start).toEqual({ line: 2, column: 8, offset }) - offset += 3 - expect(barInner.loc.end).toEqual({ line: 2, column: 11, offset }) - offset += 3 - expect(bar.loc.end).toEqual({ line: 2, column: 14, offset }) + expect(ast).toMatchSnapshot() - expect(but.loc.start).toEqual({ line: 2, column: 14, offset }) - offset += butSrc.length - expect(but.loc.end).toEqual({ line: 2, column: 19, offset }) + expect(ast.children).toHaveLength(1) + const el = ast.children[0] as any + expect(el).toMatchObject({ + tag: 'div' + }) + expect(el.children).toHaveLength(2) + expect(el.children[0]).toMatchObject({ + tag: 'p' + }) + expect(el.children[1]).toMatchObject({ + type: NodeTypes.COMMENT + }) + }) - expect(baz.loc.start).toEqual({ line: 2, column: 19, offset }) - const bazInner = (baz as InterpolationNode).content - offset += 3 - expect(bazInner.loc.start).toEqual({ line: 2, column: 22, offset }) - offset += 3 - expect(bazInner.loc.end).toEqual({ line: 2, column: 25, offset }) - offset += 3 - expect(baz.loc.end).toEqual({ line: 2, column: 28, offset }) - }) + test('invalid html', () => { + expect(() => { + baseParse(`
\n\n
\n`) + }).toThrow('Element is missing end tag.') - // With standard HTML parsing, the following input would ignore the slash - // and treat "<" and "template" as attributes on the open tag of "Hello", - // causing `