Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/minor'
Browse files Browse the repository at this point in the history
  • Loading branch information
sxzz committed Dec 1, 2023
2 parents 0d9f086 + f8b74dc commit d28d57b
Show file tree
Hide file tree
Showing 14 changed files with 1,044 additions and 988 deletions.
1,488 changes: 744 additions & 744 deletions packages/compiler-core/__tests__/__snapshots__/parse.spec.ts.snap

Large diffs are not rendered by default.

281 changes: 141 additions & 140 deletions packages/compiler-core/__tests__/parse.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1796,166 +1796,167 @@ describe('compiler: parse', () => {
})
})

test('self closing single tag', () => {
const ast = baseParse('<div :class="{ some: condition }" />')
describe('Edge Cases', () => {
test('self closing single tag', () => {
const ast = baseParse('<div :class="{ some: condition }" />')

expect(ast.children).toHaveLength(1)
expect(ast.children[0]).toMatchObject({ tag: 'div' })
})
expect(ast.children).toHaveLength(1)
expect(ast.children[0]).toMatchObject({ tag: 'div' })
})

test('self closing multiple tag', () => {
const ast = baseParse(
`<div :class="{ some: condition }" />\n` +
`<p v-bind:style="{ color: 'red' }"/>`
)
test('self closing multiple tag', () => {
const ast = baseParse(
`<div :class="{ some: condition }" />\n` +
`<p v-bind:style="{ color: 'red' }"/>`
)

expect(ast).toMatchSnapshot()
expect(ast).toMatchSnapshot()

expect(ast.children).toHaveLength(2)
expect(ast.children[0]).toMatchObject({ tag: 'div' })
expect(ast.children[1]).toMatchObject({ tag: 'p' })
})
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(
`<div :class="{ some: condition }">\n` +
` <p v-bind:style="{ color: 'red' }"/>\n` +
` <!-- a comment with <html> inside it -->\n` +
`</div>`
)
test('valid html', () => {
const ast = baseParse(
`<div :class="{ some: condition }">\n` +
` <p v-bind:style="{ color: 'red' }"/>\n` +
` <!-- a comment with <html> inside it -->\n` +
`</div>`
)

expect(ast).toMatchSnapshot()
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
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(`<div>\n<span>\n</div>\n</span>`)
}).toThrow('Element is missing end tag.')
test('invalid html', () => {
expect(() => {
baseParse(`<div>\n<span>\n</div>\n</span>`)
}).toThrow('Element is missing end tag.')

const spy = vi.fn()
const ast = baseParse(`<div>\n<span>\n</div>\n</span>`, {
onError: spy
})
const spy = vi.fn()
const ast = baseParse(`<div>\n<span>\n</div>\n</span>`, {
onError: spy
})

expect(spy.mock.calls).toMatchObject([
[
{
code: ErrorCodes.X_MISSING_END_TAG,
loc: {
start: {
offset: 6,
line: 2,
column: 1
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
],
[
{
code: ErrorCodes.X_INVALID_END_TAG,
loc: {
start: {
offset: 20,
line: 4,
column: 1
}
}
}
}
]
])

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

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 })

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(but.loc.start).toEqual({ line: 2, column: 14, offset })
offset += butSrc.length
expect(but.loc.end).toEqual({ line: 2, column: 19, offset })

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 })
})
]
])

// With standard HTML parsing, the following input would ignore the slash
// and treat "<" and "template" as attributes on the open tag of "Hello",
// causing `<template>` to fail to close, and `<script>` being parsed as its
// child. This is would never be intended in actual templates, but is a common
// intermediate state from user input when parsing for IDE support. We want
// the `<script>` to be at root-level to keep the SFC structure stable for
// Volar to do incremental computations.
test('tag termination handling for IDE', () => {
const spy = vi.fn()
const ast = baseParse(
`<template><Hello\n</template><script>console.log(1)</script>`,
{
onError: spy
}
)
//
expect(ast.children.length).toBe(2)
expect(ast.children[1]).toMatchObject({
type: NodeTypes.ELEMENT,
tag: 'script'
expect(ast).toMatchSnapshot()
})

test('parse with correct location info', () => {
const fooSrc = `foo\n is `
const barSrc = `{{ bar }}`
const butSrc = ` but `
const bazSrc = `{{ baz }}`
const [foo, bar, but, baz] = baseParse(
fooSrc + barSrc + butSrc + bazSrc
).children

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 })

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(but.loc.start).toEqual({ line: 2, column: 14, offset })
offset += butSrc.length
expect(but.loc.end).toEqual({ line: 2, column: 19, offset })

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 })
})

// With standard HTML parsing, the following input would ignore the slash
// and treat "<" and "template" as attributes on the open tag of "Hello",
// causing `<template>` to fail to close, and `<script>` being parsed as its
// child. This is would never be intended in actual templates, but is a common
// intermediate state from user input when parsing for IDE support. We want
// the `<script>` to be at root-level to keep the SFC structure stable for
// Volar to do incremental computations.
test('tag termination handling for IDE', () => {
const spy = vi.fn()
const ast = baseParse(
`<template><Hello\n</template><script>console.log(1)</script>`,
{
onError: spy
}
)
//
expect(ast.children.length).toBe(2)
expect(ast.children[1]).toMatchObject({
type: NodeTypes.ELEMENT,
tag: 'script'
})
})
})

test('arg should be undefined on shorthand dirs with no arg', () => {
const ast = baseParse(`<template #></template>`)
const el = ast.children[0] as ElementNode
expect(el.props[0]).toMatchObject({
type: NodeTypes.DIRECTIVE,
name: 'slot',
exp: undefined,
arg: undefined
test('arg should be undefined on shorthand dirs with no arg', () => {
const ast = baseParse(`<template #></template>`)
const el = ast.children[0] as ElementNode
expect(el.props[0]).toMatchObject({
type: NodeTypes.DIRECTIVE,
name: 'slot',
exp: undefined,
arg: undefined
})
})
})

// edge case found in vue-macros where the input is TS or JSX
test('should reset inRCDATA state', () => {
baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
expect(() => baseParse(`{ foo }`)).not.toThrow()
// edge case found in vue-macros where the input is TS or JSX
test('should reset inRCDATA state', () => {
baseParse(`<Foo>`, { parseMode: 'sfc', onError() {} })
expect(() => baseParse(`{ foo }`)).not.toThrow()
})
})

describe('decodeEntities option', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,14 @@ describe('compiler: expression transform', () => {
type: NodeTypes.COMPOUND_EXPRESSION,
children: [{ content: `Math` }, `.`, { content: `max` }, `(1, 2)`]
})

expect(
(parseWithExpressionTransform(`{{ new Error() }}`) as InterpolationNode)
.content
).toMatchObject({
type: NodeTypes.COMPOUND_EXPRESSION,
children: ['new ', { content: 'Error' }, '()']
})
})

test('should not prefix reserved literals', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/compiler-sfc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"lru-cache": "^10.1.0",
"merge-source-map": "^1.1.0",
"minimatch": "^9.0.3",
"postcss-modules": "^4.3.1",
"postcss-modules": "^6.0.0",
"postcss-selector-parser": "^6.0.13",
"pug": "^3.0.2",
"sass": "^1.69.5"
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/src/globalsAllowList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { makeMap } from './makeMap'
const GLOBALS_ALLOWED =
'Infinity,undefined,NaN,isFinite,isNaN,parseFloat,parseInt,decodeURI,' +
'decodeURIComponent,encodeURI,encodeURIComponent,Math,Number,Date,Array,' +
'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console'
'Object,Boolean,String,RegExp,Map,Set,JSON,Intl,BigInt,console,Error'

export const isGloballyAllowed = /*#__PURE__*/ makeMap(GLOBALS_ALLOWED)

Expand Down
14 changes: 5 additions & 9 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit d28d57b

Please sign in to comment.