test: compiler integration tests
This commit is contained in:
parent
b5d21aeff7
commit
ac7587fdb5
@ -154,12 +154,11 @@ return function render() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`compiler: codegen module mode preamble 1`] = `
|
exports[`compiler: codegen module mode preamble 1`] = `
|
||||||
"import { helperOne, helperTwo } from 'vue'
|
"import { helperOne, helperTwo } from \\"vue\\"
|
||||||
|
|
||||||
export default function render() {
|
export default function render() {
|
||||||
with (this) {
|
const _ctx = this
|
||||||
return null
|
return null
|
||||||
}
|
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`function mode 1`] = `
|
exports[`compiler: integration tests function mode 1`] = `
|
||||||
"const _Vue = Vue
|
"const _Vue = Vue
|
||||||
return function render() {
|
return function render() {
|
||||||
with (this) {
|
with (this) {
|
||||||
@ -13,10 +13,50 @@ return function render() {
|
|||||||
ok
|
ok
|
||||||
? _createVNode(\\"div\\", 0, \\"yes\\")
|
? _createVNode(\\"div\\", 0, \\"yes\\")
|
||||||
: \\"no\\",
|
: \\"no\\",
|
||||||
_renderList(list, (i, j) => {
|
_renderList(list, (value, index) => {
|
||||||
return _createVNode(\\"div\\", 0, [_createVNode(\\"span\\", 0, _toString(i + j))])
|
return _createVNode(\\"div\\", 0, [_createVNode(\\"span\\", 0, _toString(value + index))])
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: integration tests function mode w/ prefixIdentifiers: true 1`] = `
|
||||||
|
"const { createVNode, toString, renderList } = Vue
|
||||||
|
|
||||||
|
return function render() {
|
||||||
|
const _ctx = this
|
||||||
|
return createVNode(\\"div\\", {
|
||||||
|
id: \\"foo\\",
|
||||||
|
class: _ctx.bar
|
||||||
|
}, [
|
||||||
|
toString(_ctx.world),
|
||||||
|
(_ctx.ok)
|
||||||
|
? createVNode(\\"div\\", 0, \\"yes\\")
|
||||||
|
: \\"no\\",
|
||||||
|
renderList(_ctx.list, (value, index) => {
|
||||||
|
return createVNode(\\"div\\", 0, [createVNode(\\"span\\", 0, toString(value + index))])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`compiler: integration tests module mode 1`] = `
|
||||||
|
"import { createVNode, toString, renderList } from \\"vue\\"
|
||||||
|
|
||||||
|
export default function render() {
|
||||||
|
const _ctx = this
|
||||||
|
return createVNode(\\"div\\", {
|
||||||
|
id: \\"foo\\",
|
||||||
|
class: _ctx.bar
|
||||||
|
}, [
|
||||||
|
_toString(_ctx.world),
|
||||||
|
(_ctx.ok)
|
||||||
|
? createVNode(\\"div\\", 0, \\"yes\\")
|
||||||
|
: \\"no\\",
|
||||||
|
_renderList(_ctx.list, (value, index) => {
|
||||||
|
return createVNode(\\"div\\", 0, [createVNode(\\"span\\", 0, _toString(value + index))])
|
||||||
|
})
|
||||||
|
])
|
||||||
|
}"
|
||||||
|
`;
|
||||||
|
@ -51,7 +51,7 @@ describe('compiler: codegen', () => {
|
|||||||
imports: [`helperOne`, `helperTwo`]
|
imports: [`helperOne`, `helperTwo`]
|
||||||
})
|
})
|
||||||
const { code } = generate(root, { mode: 'module' })
|
const { code } = generate(root, { mode: 'module' })
|
||||||
expect(code).toMatch(`import { helperOne, helperTwo } from 'vue'`)
|
expect(code).toMatch(`import { helperOne, helperTwo } from "vue"`)
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,139 +1,227 @@
|
|||||||
import { compile } from '../src'
|
import { compile } from '../src'
|
||||||
import { SourceMapConsumer, RawSourceMap } from 'source-map'
|
import { SourceMapConsumer, RawSourceMap } from 'source-map'
|
||||||
|
|
||||||
// Integration tests for parser + transform + codegen
|
describe('compiler: integration tests', () => {
|
||||||
test('function mode', async () => {
|
|
||||||
const source = `
|
const source = `
|
||||||
<div id="foo" :class="bar">
|
<div id="foo" :class="bar">
|
||||||
{{ world }}
|
{{ world }}
|
||||||
<div v-if="ok">yes</div>
|
<div v-if="ok">yes</div>
|
||||||
<template v-else>no</template>
|
<template v-else>no</template>
|
||||||
<div v-for="(i, j) in list"><span>{{ i + j }}</span></div>
|
<div v-for="(value, index) in list"><span>{{ value + index }}</span></div>
|
||||||
</div>
|
</div>
|
||||||
`.trim()
|
`.trim()
|
||||||
|
|
||||||
|
function getPositionInCode(code: string, token: string) {
|
||||||
|
const generatedOffset = code.indexOf(token)
|
||||||
|
let line = 1
|
||||||
|
let lastNewLinePos = -1
|
||||||
|
for (let i = 0; i < generatedOffset; i++) {
|
||||||
|
if (code.charCodeAt(i) === 10 /* newline char code */) {
|
||||||
|
line++
|
||||||
|
lastNewLinePos = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
line,
|
||||||
|
column:
|
||||||
|
lastNewLinePos === -1
|
||||||
|
? generatedOffset
|
||||||
|
: generatedOffset - lastNewLinePos - 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('function mode', async () => {
|
||||||
const { code, map } = compile(source, {
|
const { code, map } = compile(source, {
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
filename: `foo.vue`
|
filename: `foo.vue`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
expect(code).toMatch(
|
||||||
|
`const { createVNode: _createVNode, toString: _toString, renderList: _renderList } = _Vue`
|
||||||
|
)
|
||||||
|
|
||||||
expect(code).toMatchSnapshot()
|
expect(code).toMatchSnapshot()
|
||||||
expect(map!.sources).toEqual([`foo.vue`])
|
expect(map!.sources).toEqual([`foo.vue`])
|
||||||
expect(map!.sourcesContent).toEqual([source])
|
expect(map!.sourcesContent).toEqual([source])
|
||||||
|
|
||||||
const consumer = await new SourceMapConsumer(map as RawSourceMap)
|
const consumer = await new SourceMapConsumer(map as RawSourceMap)
|
||||||
|
|
||||||
// id=
|
|
||||||
expect(
|
expect(
|
||||||
consumer.originalPositionFor({
|
consumer.originalPositionFor(getPositionInCode(code, `id`))
|
||||||
line: 6,
|
).toMatchObject(getPositionInCode(source, `id`))
|
||||||
column: 6
|
|
||||||
})
|
expect(
|
||||||
).toMatchObject({
|
consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
|
||||||
line: 1,
|
).toMatchObject(getPositionInCode(source, `"foo"`))
|
||||||
column: 5
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `class:`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `class=`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `bar`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `bar`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `world`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `{{ world }}`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `ok`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `ok`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `list`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `list`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `value`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `value`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `index`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `index`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `value + index`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `{{ value + index }}`))
|
||||||
})
|
})
|
||||||
|
|
||||||
// "foo"
|
test('function mode w/ prefixIdentifiers: true', async () => {
|
||||||
expect(
|
const { code, map } = compile(source, {
|
||||||
consumer.originalPositionFor({
|
sourceMap: true,
|
||||||
line: 6,
|
filename: `foo.vue`,
|
||||||
column: 10
|
prefixIdentifiers: true
|
||||||
})
|
|
||||||
).toMatchObject({
|
|
||||||
line: 1,
|
|
||||||
column: 8
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// :class=
|
expect(code).toMatch(`const { createVNode, toString, renderList } = Vue`)
|
||||||
|
|
||||||
|
expect(code).toMatchSnapshot()
|
||||||
|
expect(map!.sources).toEqual([`foo.vue`])
|
||||||
|
expect(map!.sourcesContent).toEqual([source])
|
||||||
|
|
||||||
|
const consumer = await new SourceMapConsumer(map as RawSourceMap)
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
consumer.originalPositionFor({
|
consumer.originalPositionFor(getPositionInCode(code, `id`))
|
||||||
line: 7,
|
).toMatchObject(getPositionInCode(source, `id`))
|
||||||
column: 6
|
|
||||||
})
|
|
||||||
).toMatchObject({
|
|
||||||
line: 1,
|
|
||||||
column: 15
|
|
||||||
})
|
|
||||||
// bar
|
|
||||||
expect(
|
expect(
|
||||||
consumer.originalPositionFor({
|
consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
|
||||||
line: 7,
|
).toMatchObject(getPositionInCode(source, `"foo"`))
|
||||||
column: 13
|
|
||||||
})
|
expect(
|
||||||
).toMatchObject({
|
consumer.originalPositionFor(getPositionInCode(code, `class:`))
|
||||||
line: 1,
|
).toMatchObject(getPositionInCode(source, `class=`))
|
||||||
column: 22
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `bar`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `bar`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `bar`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `world`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `{{ world }}`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.world`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `{{ world }}`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `ok`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `ok`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `ok`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `list`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `list`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.list`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `list`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `value`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `value`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `index`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `index`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `value + index`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `value + index`))
|
||||||
})
|
})
|
||||||
|
|
||||||
// {{ world }}
|
test('module mode', async () => {
|
||||||
expect(
|
const { code, map } = compile(source, {
|
||||||
consumer.originalPositionFor({
|
mode: 'module',
|
||||||
line: 9,
|
sourceMap: true,
|
||||||
column: 16
|
filename: `foo.vue`
|
||||||
})
|
|
||||||
).toMatchObject({
|
|
||||||
line: 2,
|
|
||||||
column: 2
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// ok
|
expect(code).toMatch(
|
||||||
expect(
|
`import { createVNode, toString, renderList } from "vue"`
|
||||||
consumer.originalPositionFor({
|
)
|
||||||
line: 10,
|
|
||||||
column: 6
|
|
||||||
})
|
|
||||||
).toMatchObject({
|
|
||||||
line: 3,
|
|
||||||
column: 13
|
|
||||||
})
|
|
||||||
|
|
||||||
// i
|
expect(code).toMatchSnapshot()
|
||||||
expect(
|
expect(map!.sources).toEqual([`foo.vue`])
|
||||||
consumer.originalPositionFor({
|
expect(map!.sourcesContent).toEqual([source])
|
||||||
line: 13,
|
|
||||||
column: 25
|
|
||||||
})
|
|
||||||
).toMatchObject({
|
|
||||||
line: 5,
|
|
||||||
column: 15
|
|
||||||
})
|
|
||||||
|
|
||||||
// j
|
const consumer = await new SourceMapConsumer(map as RawSourceMap)
|
||||||
expect(
|
|
||||||
consumer.originalPositionFor({
|
|
||||||
line: 13,
|
|
||||||
column: 28
|
|
||||||
})
|
|
||||||
).toMatchObject({
|
|
||||||
line: 5,
|
|
||||||
column: 18
|
|
||||||
})
|
|
||||||
|
|
||||||
// list
|
|
||||||
expect(
|
expect(
|
||||||
consumer.originalPositionFor({
|
consumer.originalPositionFor(getPositionInCode(code, `id`))
|
||||||
line: 13,
|
).toMatchObject(getPositionInCode(source, `id`))
|
||||||
column: 18
|
|
||||||
})
|
|
||||||
).toMatchObject({
|
|
||||||
line: 5,
|
|
||||||
column: 24
|
|
||||||
})
|
|
||||||
|
|
||||||
// i + j
|
|
||||||
expect(
|
expect(
|
||||||
consumer.originalPositionFor({
|
consumer.originalPositionFor(getPositionInCode(code, `"foo"`))
|
||||||
line: 14,
|
).toMatchObject(getPositionInCode(source, `"foo"`))
|
||||||
column: 81
|
|
||||||
})
|
expect(
|
||||||
).toMatchObject({
|
consumer.originalPositionFor(getPositionInCode(code, `class:`))
|
||||||
line: 5,
|
).toMatchObject(getPositionInCode(source, `class=`))
|
||||||
column: 36
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `bar`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `bar`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.bar`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `bar`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `world`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `{{ world }}`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.world`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `{{ world }}`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `ok`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `ok`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.ok`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `ok`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `list`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `list`))
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `_ctx.list`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `list`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `value`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `value`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `index`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `index`))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
consumer.originalPositionFor(getPositionInCode(code, `value + index`))
|
||||||
|
).toMatchObject(getPositionInCode(source, `value + index`))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
test.todo('function mode w/ prefixIdentifiers: true')
|
|
||||||
|
|
||||||
test.todo('module mode')
|
|
||||||
|
|
||||||
test.todo('module mode w/ prefixIdentifiers: true')
|
|
||||||
|
@ -29,26 +29,17 @@ function parseWithExpressionTransform(
|
|||||||
describe('compiler: expression transform', () => {
|
describe('compiler: expression transform', () => {
|
||||||
test('interpolation (root)', () => {
|
test('interpolation (root)', () => {
|
||||||
const node = parseWithExpressionTransform(`{{ foo }}`) as ExpressionNode
|
const node = parseWithExpressionTransform(`{{ foo }}`) as ExpressionNode
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toBeUndefined()
|
||||||
`_ctx.`,
|
expect(node.content).toBe(`_ctx.foo`)
|
||||||
{
|
|
||||||
content: `foo`,
|
|
||||||
loc: node.loc
|
|
||||||
}
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('interpolation (children)', () => {
|
test('interpolation (children)', () => {
|
||||||
const node = parseWithExpressionTransform(
|
const el = parseWithExpressionTransform(
|
||||||
`<div>{{ foo }}</div>`
|
`<div>{{ foo }}</div>`
|
||||||
) as ElementNode
|
) as ElementNode
|
||||||
expect((node.children[0] as ExpressionNode).children).toMatchObject([
|
const node = el.children[0] as ExpressionNode
|
||||||
`_ctx.`,
|
expect(node.children).toBeUndefined()
|
||||||
{
|
expect(node.content).toBe(`_ctx.foo`)
|
||||||
content: `foo`,
|
|
||||||
loc: node.children[0].loc
|
|
||||||
}
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('directive value', () => {
|
test('directive value', () => {
|
||||||
@ -57,13 +48,8 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ElementNode
|
) as ElementNode
|
||||||
expect((node.props[0] as DirectiveNode).arg!.children).toBeUndefined()
|
expect((node.props[0] as DirectiveNode).arg!.children).toBeUndefined()
|
||||||
const exp = (node.props[0] as DirectiveNode).exp!
|
const exp = (node.props[0] as DirectiveNode).exp!
|
||||||
expect(exp.children).toMatchObject([
|
expect(exp.children).toBeUndefined()
|
||||||
`_ctx.`,
|
expect(exp.content).toBe(`_ctx.baz`)
|
||||||
{
|
|
||||||
content: `baz`,
|
|
||||||
loc: exp.loc
|
|
||||||
}
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('dynamic directive arg', () => {
|
test('dynamic directive arg', () => {
|
||||||
@ -72,20 +58,10 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ElementNode
|
) as ElementNode
|
||||||
const arg = (node.props[0] as DirectiveNode).arg!
|
const arg = (node.props[0] as DirectiveNode).arg!
|
||||||
const exp = (node.props[0] as DirectiveNode).exp!
|
const exp = (node.props[0] as DirectiveNode).exp!
|
||||||
expect(arg.children).toMatchObject([
|
expect(arg.children).toBeUndefined()
|
||||||
`_ctx.`,
|
expect(arg.content).toBe(`_ctx.arg`)
|
||||||
{
|
expect(exp.children).toBeUndefined()
|
||||||
content: `arg`,
|
expect(exp.content).toBe(`_ctx.baz`)
|
||||||
loc: arg.loc
|
|
||||||
}
|
|
||||||
])
|
|
||||||
expect(exp.children).toMatchObject([
|
|
||||||
`_ctx.`,
|
|
||||||
{
|
|
||||||
content: `baz`,
|
|
||||||
loc: exp.loc
|
|
||||||
}
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should prefix complex expressions', () => {
|
test('should prefix complex expressions', () => {
|
||||||
@ -94,9 +70,8 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
// should parse into compound expression
|
// should parse into compound expression
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`_ctx.`,
|
|
||||||
{
|
{
|
||||||
content: `foo`,
|
content: `_ctx.foo`,
|
||||||
loc: {
|
loc: {
|
||||||
source: `foo`,
|
source: `foo`,
|
||||||
start: {
|
start: {
|
||||||
@ -111,9 +86,9 @@ describe('compiler: expression transform', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
`(_ctx.`,
|
`(`,
|
||||||
{
|
{
|
||||||
content: `baz`,
|
content: `_ctx.baz`,
|
||||||
loc: {
|
loc: {
|
||||||
source: `baz`,
|
source: `baz`,
|
||||||
start: {
|
start: {
|
||||||
@ -128,9 +103,9 @@ describe('compiler: expression transform', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
` + 1, { key: _ctx.`,
|
` + 1, { key: `,
|
||||||
{
|
{
|
||||||
content: `kuz`,
|
content: `_ctx.kuz`,
|
||||||
loc: {
|
loc: {
|
||||||
source: `kuz`,
|
source: `kuz`,
|
||||||
start: {
|
start: {
|
||||||
@ -151,17 +126,16 @@ describe('compiler: expression transform', () => {
|
|||||||
|
|
||||||
test('should prefix v-if condition', () => {
|
test('should prefix v-if condition', () => {
|
||||||
const node = parseWithExpressionTransform(`<div v-if="ok"/>`) as IfNode
|
const node = parseWithExpressionTransform(`<div v-if="ok"/>`) as IfNode
|
||||||
expect(node.branches[0].condition!.children).toMatchObject([
|
expect(node.branches[0].condition!.children).toBeUndefined()
|
||||||
`_ctx.`,
|
expect(node.branches[0].condition!.content).toBe(`_ctx.ok`)
|
||||||
{ content: `ok` }
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should prefix v-for source', () => {
|
test('should prefix v-for source', () => {
|
||||||
const node = parseWithExpressionTransform(
|
const node = parseWithExpressionTransform(
|
||||||
`<div v-for="i in list"/>`
|
`<div v-for="i in list"/>`
|
||||||
) as ForNode
|
) as ForNode
|
||||||
expect(node.source.children).toMatchObject([`_ctx.`, { content: `list` }])
|
expect(node.source.children).toBeUndefined()
|
||||||
|
expect(node.source.content).toBe(`_ctx.list`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should not prefix v-for alias', () => {
|
test('should not prefix v-for alias', () => {
|
||||||
@ -177,7 +151,8 @@ describe('compiler: expression transform', () => {
|
|||||||
|
|
||||||
const j = div.children[1] as ExpressionNode
|
const j = div.children[1] as ExpressionNode
|
||||||
expect(j.type).toBe(NodeTypes.EXPRESSION)
|
expect(j.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(j.children).toMatchObject([`_ctx.`, { content: `j` }])
|
expect(j.children).toBeUndefined()
|
||||||
|
expect(j.content).toBe(`_ctx.j`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should not prefix v-for aliases (multiple)', () => {
|
test('should not prefix v-for aliases (multiple)', () => {
|
||||||
@ -188,12 +163,19 @@ describe('compiler: expression transform', () => {
|
|||||||
|
|
||||||
const exp = div.children[0] as ExpressionNode
|
const exp = div.children[0] as ExpressionNode
|
||||||
expect(exp.type).toBe(NodeTypes.EXPRESSION)
|
expect(exp.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(exp.content).toBe(`i + j + k`)
|
// parsed for better source-map support
|
||||||
expect(exp.children).toBeUndefined()
|
expect(exp.children).toMatchObject([
|
||||||
|
{ content: `i` },
|
||||||
|
` + `,
|
||||||
|
{ content: `j` },
|
||||||
|
` + `,
|
||||||
|
{ content: `k` }
|
||||||
|
])
|
||||||
|
|
||||||
const l = div.children[1] as ExpressionNode
|
const l = div.children[1] as ExpressionNode
|
||||||
expect(l.type).toBe(NodeTypes.EXPRESSION)
|
expect(l.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(l.children).toMatchObject([`_ctx.`, { content: `l` }])
|
expect(l.children).toBeUndefined()
|
||||||
|
expect(l.content).toBe(`_ctx.l`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should prefix id outside of v-for', () => {
|
test('should prefix id outside of v-for', () => {
|
||||||
@ -202,8 +184,8 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ElementNode
|
) as ElementNode
|
||||||
const exp = node.children[1] as ExpressionNode
|
const exp = node.children[1] as ExpressionNode
|
||||||
expect(exp.type).toBe(NodeTypes.EXPRESSION)
|
expect(exp.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(exp.content).toBe(`i`)
|
expect(exp.children).toBeUndefined()
|
||||||
expect(exp.children).toMatchObject([`_ctx.`, { content: `i` }])
|
expect(exp.content).toBe(`_ctx.i`)
|
||||||
})
|
})
|
||||||
|
|
||||||
test('nested v-for', () => {
|
test('nested v-for', () => {
|
||||||
@ -217,7 +199,11 @@ describe('compiler: expression transform', () => {
|
|||||||
const innerExp = (innerFor.children[0] as ElementNode)
|
const innerExp = (innerFor.children[0] as ElementNode)
|
||||||
.children[0] as ExpressionNode
|
.children[0] as ExpressionNode
|
||||||
expect(innerExp.type).toBe(NodeTypes.EXPRESSION)
|
expect(innerExp.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(innerExp.children).toMatchObject([`i + _ctx.`, { content: `j` }])
|
expect(innerExp.children).toMatchObject([
|
||||||
|
{ content: 'i' },
|
||||||
|
` + `,
|
||||||
|
{ content: `_ctx.j` }
|
||||||
|
])
|
||||||
|
|
||||||
// when an inner v-for shadows a variable of an outer v-for and exit,
|
// when an inner v-for shadows a variable of an outer v-for and exit,
|
||||||
// it should not cause the outer v-for's alias to be removed from known ids
|
// it should not cause the outer v-for's alias to be removed from known ids
|
||||||
@ -232,8 +218,12 @@ describe('compiler: expression transform', () => {
|
|||||||
`{{ Math.max(1, 2) }}`
|
`{{ Math.max(1, 2) }}`
|
||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(node.content).toBe(`Math.max(1, 2)`)
|
expect(node.children).toMatchObject([
|
||||||
expect(node.children).toBeUndefined()
|
{ content: `Math` },
|
||||||
|
`.`,
|
||||||
|
{ content: `max` },
|
||||||
|
`(1, 2)`
|
||||||
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should not prefix id of a function declaration', () => {
|
test('should not prefix id of a function declaration', () => {
|
||||||
@ -242,8 +232,10 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`function foo() { return _ctx.`,
|
`function `,
|
||||||
{ content: `bar` },
|
{ content: `foo` },
|
||||||
|
`() { return `,
|
||||||
|
{ content: `_ctx.bar` },
|
||||||
` }`
|
` }`
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@ -254,8 +246,11 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`foo => foo + _ctx.`,
|
{ content: `foo` },
|
||||||
{ content: `bar` }
|
` => `,
|
||||||
|
{ content: `foo` },
|
||||||
|
` + `,
|
||||||
|
{ content: `_ctx.bar` }
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -265,8 +260,8 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`{ foo: _ctx.`,
|
`{ foo: `,
|
||||||
{ content: `bar` },
|
{ content: `_ctx.bar` },
|
||||||
` }`
|
` }`
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@ -277,10 +272,10 @@ describe('compiler: expression transform', () => {
|
|||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
expect(node.type).toBe(NodeTypes.EXPRESSION)
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`{ [_ctx.`,
|
`{ [`,
|
||||||
{ content: `foo` },
|
{ content: `_ctx.foo` },
|
||||||
`]: _ctx.`,
|
`]: `,
|
||||||
{ content: `bar` },
|
{ content: `_ctx.bar` },
|
||||||
` }`
|
` }`
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@ -288,8 +283,8 @@ describe('compiler: expression transform', () => {
|
|||||||
test('should prefix object property shorthand value', () => {
|
test('should prefix object property shorthand value', () => {
|
||||||
const node = parseWithExpressionTransform(`{{ { foo } }}`) as ExpressionNode
|
const node = parseWithExpressionTransform(`{{ { foo } }}`) as ExpressionNode
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`{ foo: _ctx.`,
|
`{ foo: `,
|
||||||
{ content: `foo` },
|
{ content: `_ctx.foo` },
|
||||||
` }`
|
` }`
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
@ -299,9 +294,11 @@ describe('compiler: expression transform', () => {
|
|||||||
`{{ foo.bar.baz }}`
|
`{{ foo.bar.baz }}`
|
||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`_ctx.`,
|
{ content: `_ctx.foo` },
|
||||||
{ content: `foo` },
|
`.`,
|
||||||
`.bar.baz`
|
{ content: `bar` },
|
||||||
|
`.`,
|
||||||
|
{ content: `baz` }
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -310,12 +307,11 @@ describe('compiler: expression transform', () => {
|
|||||||
`{{ foo[bar][baz] }}`
|
`{{ foo[bar][baz] }}`
|
||||||
) as ExpressionNode
|
) as ExpressionNode
|
||||||
expect(node.children).toMatchObject([
|
expect(node.children).toMatchObject([
|
||||||
`_ctx.`,
|
{ content: `_ctx.foo` },
|
||||||
{ content: `foo` },
|
`[`,
|
||||||
`[_ctx.`,
|
{ content: `_ctx.bar` },
|
||||||
{ content: `bar` },
|
`][`,
|
||||||
`][_ctx.`,
|
{ content: '_ctx.baz' },
|
||||||
{ content: 'baz' },
|
|
||||||
`]`
|
`]`
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
@ -25,7 +25,7 @@ function parseWithVOn(
|
|||||||
return ast.children[0] as ElementNode
|
return ast.children[0] as ElementNode
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('compiler: transform v-bind', () => {
|
describe('compiler: transform v-on', () => {
|
||||||
test('basic', () => {
|
test('basic', () => {
|
||||||
const node = parseWithVOn(`<div v-on:click="onClick"/>`)
|
const node = parseWithVOn(`<div v-on:click="onClick"/>`)
|
||||||
const props = node.codegenNode!.arguments[1] as ObjectExpression
|
const props = node.codegenNode!.arguments[1] as ObjectExpression
|
||||||
@ -76,8 +76,8 @@ describe('compiler: transform v-bind', () => {
|
|||||||
const props = node.codegenNode!.arguments[1] as ObjectExpression
|
const props = node.codegenNode!.arguments[1] as ObjectExpression
|
||||||
expect(props.properties[0]).toMatchObject({
|
expect(props.properties[0]).toMatchObject({
|
||||||
key: {
|
key: {
|
||||||
content: `"on" + event`,
|
isStatic: false,
|
||||||
isStatic: false
|
children: [`"on" + `, { content: `event` }]
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
content: `handler`,
|
content: `handler`,
|
||||||
@ -94,10 +94,10 @@ describe('compiler: transform v-bind', () => {
|
|||||||
expect(props.properties[0]).toMatchObject({
|
expect(props.properties[0]).toMatchObject({
|
||||||
key: {
|
key: {
|
||||||
isStatic: false,
|
isStatic: false,
|
||||||
children: [`"on" + `, `_ctx.`, { content: `event` }]
|
children: [`"on" + `, { content: `_ctx.event` }]
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
content: `handler`,
|
content: `_ctx.handler`,
|
||||||
isStatic: false
|
isStatic: false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -150,6 +150,7 @@ export function generate(
|
|||||||
const context = createCodegenContext(ast, options)
|
const context = createCodegenContext(ast, options)
|
||||||
const { mode, push, prefixIdentifiers, indent, deindent, newline } = context
|
const { mode, push, prefixIdentifiers, indent, deindent, newline } = context
|
||||||
const hasImports = ast.imports.length
|
const hasImports = ast.imports.length
|
||||||
|
const useWithBlock = !prefixIdentifiers && mode !== 'module'
|
||||||
|
|
||||||
// preambles
|
// preambles
|
||||||
if (mode === 'function') {
|
if (mode === 'function') {
|
||||||
@ -170,7 +171,7 @@ export function generate(
|
|||||||
} else {
|
} else {
|
||||||
// generate import statements for helpers
|
// generate import statements for helpers
|
||||||
if (hasImports) {
|
if (hasImports) {
|
||||||
push(`import { ${ast.imports.join(', ')} } from 'vue'\n`)
|
push(`import { ${ast.imports.join(', ')} } from "vue"\n`)
|
||||||
}
|
}
|
||||||
genHoists(ast.hoists, context)
|
genHoists(ast.hoists, context)
|
||||||
push(`export default `)
|
push(`export default `)
|
||||||
@ -180,12 +181,12 @@ export function generate(
|
|||||||
push(`function render() {`)
|
push(`function render() {`)
|
||||||
indent()
|
indent()
|
||||||
|
|
||||||
if (!prefixIdentifiers) {
|
if (useWithBlock) {
|
||||||
push(`with (this) {`)
|
push(`with (this) {`)
|
||||||
indent()
|
indent()
|
||||||
// function mode const declarations should be inside with block
|
// function mode const declarations should be inside with block
|
||||||
// also they should be renamed to avoid collision with user properties
|
// also they should be renamed to avoid collision with user properties
|
||||||
if (mode === 'function' && hasImports) {
|
if (hasImports) {
|
||||||
push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
|
push(`const { ${ast.imports.map(n => `${n}: _${n}`).join(', ')} } = _Vue`)
|
||||||
newline()
|
newline()
|
||||||
}
|
}
|
||||||
@ -206,10 +207,12 @@ export function generate(
|
|||||||
// generate the VNode tree expression
|
// generate the VNode tree expression
|
||||||
push(`return `)
|
push(`return `)
|
||||||
genChildren(ast.children, context, true)
|
genChildren(ast.children, context, true)
|
||||||
if (!prefixIdentifiers) {
|
|
||||||
|
if (useWithBlock) {
|
||||||
deindent()
|
deindent()
|
||||||
push(`}`)
|
push(`}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
deindent()
|
deindent()
|
||||||
push(`}`)
|
push(`}`)
|
||||||
return {
|
return {
|
||||||
|
@ -70,7 +70,8 @@ export const enum ErrorCodes {
|
|||||||
X_V_ON_NO_EXPRESSION,
|
X_V_ON_NO_EXPRESSION,
|
||||||
|
|
||||||
// generic errors
|
// generic errors
|
||||||
X_PREFIX_ID_NOT_SUPPORTED
|
X_PREFIX_ID_NOT_SUPPORTED,
|
||||||
|
X_MODULE_MODE_NOT_SUPPORTED
|
||||||
}
|
}
|
||||||
|
|
||||||
export const errorMessages: { [code: number]: string } = {
|
export const errorMessages: { [code: number]: string } = {
|
||||||
@ -138,5 +139,6 @@ export const errorMessages: { [code: number]: string } = {
|
|||||||
[ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression`,
|
[ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression`,
|
||||||
|
|
||||||
// generic errors
|
// generic errors
|
||||||
[ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler because it is optimized for payload size.`
|
[ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED]: `"prefixIdentifiers" option is not supported in this build of compiler.`,
|
||||||
|
[ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED]: `ES module mode is not supported in this build of compiler.`
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,21 @@ export function compile(
|
|||||||
template: string | RootNode,
|
template: string | RootNode,
|
||||||
options: CompilerOptions = {}
|
options: CompilerOptions = {}
|
||||||
): CodegenResult {
|
): CodegenResult {
|
||||||
if (__BROWSER__ && options.prefixIdentifiers === false) {
|
if (__BROWSER__) {
|
||||||
;(options.onError || defaultOnError)(
|
const onError = options.onError || defaultOnError
|
||||||
createCompilerError(ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED)
|
if (options.prefixIdentifiers === true) {
|
||||||
)
|
onError(createCompilerError(ErrorCodes.X_PREFIX_ID_NOT_SUPPORTED))
|
||||||
|
} else if (options.mode === 'module') {
|
||||||
|
onError(createCompilerError(ErrorCodes.X_MODULE_MODE_NOT_SUPPORTED))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ast = isString(template) ? parse(template, options) : template
|
const ast = isString(template) ? parse(template, options) : template
|
||||||
|
|
||||||
const prefixIdentifiers = !__BROWSER__ && options.prefixIdentifiers === true
|
const prefixIdentifiers =
|
||||||
|
!__BROWSER__ &&
|
||||||
|
(options.prefixIdentifiers === true || options.mode === 'module')
|
||||||
|
|
||||||
transform(ast, {
|
transform(ast, {
|
||||||
...options,
|
...options,
|
||||||
prefixIdentifiers,
|
prefixIdentifiers,
|
||||||
|
@ -12,7 +12,7 @@ import { parseScript } from 'meriyah'
|
|||||||
import { walk } from 'estree-walker'
|
import { walk } from 'estree-walker'
|
||||||
import { NodeTransform, TransformContext } from '../transform'
|
import { NodeTransform, TransformContext } from '../transform'
|
||||||
import { NodeTypes, createExpression, ExpressionNode } from '../ast'
|
import { NodeTypes, createExpression, ExpressionNode } from '../ast'
|
||||||
import { Node, Function, Identifier } from 'estree'
|
import { Node, Function, Identifier, Property } from 'estree'
|
||||||
import { advancePositionWithClone } from '../utils'
|
import { advancePositionWithClone } from '../utils'
|
||||||
export const transformExpression: NodeTransform = (node, context) => {
|
export const transformExpression: NodeTransform = (node, context) => {
|
||||||
if (node.type === NodeTypes.EXPRESSION && !node.isStatic) {
|
if (node.type === NodeTypes.EXPRESSION && !node.isStatic) {
|
||||||
@ -43,12 +43,15 @@ const simpleIdRE = /^[a-zA-Z$_][\w$]*$/
|
|||||||
const isFunction = (node: Node): node is Function =>
|
const isFunction = (node: Node): node is Function =>
|
||||||
/Function(Expression|Declaration)$/.test(node.type)
|
/Function(Expression|Declaration)$/.test(node.type)
|
||||||
|
|
||||||
|
const isPropertyKey = (node: Node, parent: Node) =>
|
||||||
|
parent.type === 'Property' && parent.key === node && !parent.computed
|
||||||
|
|
||||||
// cache node requires
|
// cache node requires
|
||||||
let _parseScript: typeof parseScript
|
let _parseScript: typeof parseScript
|
||||||
let _walk: typeof walk
|
let _walk: typeof walk
|
||||||
|
|
||||||
interface PrefixMeta {
|
interface PrefixMeta {
|
||||||
prefix: string
|
prefix?: string
|
||||||
start: number
|
start: number
|
||||||
end: number
|
end: number
|
||||||
}
|
}
|
||||||
@ -72,7 +75,7 @@ export function processExpression(
|
|||||||
// fast path if expression is a simple identifier.
|
// fast path if expression is a simple identifier.
|
||||||
if (simpleIdRE.test(node.content)) {
|
if (simpleIdRE.test(node.content)) {
|
||||||
if (!context.identifiers[node.content]) {
|
if (!context.identifiers[node.content]) {
|
||||||
node.children = [`_ctx.`, createExpression(node.content, false, node.loc)]
|
node.content = `_ctx.${node.content}`
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -92,23 +95,23 @@ export function processExpression(
|
|||||||
walk(ast, {
|
walk(ast, {
|
||||||
enter(node: Node & PrefixMeta, parent) {
|
enter(node: Node & PrefixMeta, parent) {
|
||||||
if (node.type === 'Identifier') {
|
if (node.type === 'Identifier') {
|
||||||
|
if (!ids.includes(node)) {
|
||||||
|
if (!knownIds[node.name] && shouldPrefix(node, parent)) {
|
||||||
if (
|
if (
|
||||||
!ids.includes(node) &&
|
isPropertyKey(node, parent) &&
|
||||||
!knownIds[node.name] &&
|
(parent as Property).value === node
|
||||||
shouldPrefix(node, parent)
|
|
||||||
) {
|
|
||||||
if (
|
|
||||||
parent.type === 'Property' &&
|
|
||||||
parent.value === node &&
|
|
||||||
parent.key === node
|
|
||||||
) {
|
) {
|
||||||
// property shorthand like { foo }, we need to add the key since we
|
// property shorthand like { foo }, we need to add the key since we
|
||||||
// rewrite the value
|
// rewrite the value
|
||||||
node.prefix = `${node.name}: _ctx.`
|
node.prefix = `${node.name}: `
|
||||||
} else {
|
|
||||||
node.prefix = `_ctx.`
|
|
||||||
}
|
}
|
||||||
|
node.name = `_ctx.${node.name}`
|
||||||
ids.push(node)
|
ids.push(node)
|
||||||
|
} else if (!isPropertyKey(node, parent)) {
|
||||||
|
// also generate sub-expressioms for other identifiers for better
|
||||||
|
// source map support. (except for property keys which are static)
|
||||||
|
ids.push(node)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (isFunction(node)) {
|
} else if (isFunction(node)) {
|
||||||
// walk function expressions and add its arguments to known identifiers
|
// walk function expressions and add its arguments to known identifiers
|
||||||
@ -147,7 +150,9 @@ export function processExpression(
|
|||||||
ids.forEach((id, i) => {
|
ids.forEach((id, i) => {
|
||||||
const last = ids[i - 1] as any
|
const last = ids[i - 1] as any
|
||||||
const leadingText = full.slice(last ? last.end - 1 : 0, id.start - 1)
|
const leadingText = full.slice(last ? last.end - 1 : 0, id.start - 1)
|
||||||
children.push(leadingText + id.prefix)
|
if (leadingText.length || id.prefix) {
|
||||||
|
children.push(leadingText + (id.prefix || ``))
|
||||||
|
}
|
||||||
const source = full.slice(id.start - 1, id.end - 1)
|
const source = full.slice(id.start - 1, id.end - 1)
|
||||||
children.push(
|
children.push(
|
||||||
createExpression(id.name, false, {
|
createExpression(id.name, false, {
|
||||||
@ -191,12 +196,9 @@ function shouldPrefix(identifier: Identifier, parent: Node) {
|
|||||||
) &&
|
) &&
|
||||||
// not a key of Property
|
// not a key of Property
|
||||||
!(
|
!(
|
||||||
parent.type === 'Property' &&
|
isPropertyKey(identifier, parent) &&
|
||||||
parent.key === identifier &&
|
|
||||||
// computed keys should be prefixed
|
|
||||||
!parent.computed &&
|
|
||||||
// shorthand keys should be prefixed
|
// shorthand keys should be prefixed
|
||||||
!(parent.value === identifier)
|
!((parent as Property).value === identifier)
|
||||||
) &&
|
) &&
|
||||||
// not a property of a MemberExpression
|
// not a property of a MemberExpression
|
||||||
!(
|
!(
|
||||||
|
@ -2,7 +2,6 @@ import { DirectiveTransform } from '../transform'
|
|||||||
import { createObjectProperty, createExpression, ExpressionNode } from '../ast'
|
import { createObjectProperty, createExpression, ExpressionNode } from '../ast'
|
||||||
import { capitalize } from '@vue/shared'
|
import { capitalize } from '@vue/shared'
|
||||||
import { createCompilerError, ErrorCodes } from '../errors'
|
import { createCompilerError, ErrorCodes } from '../errors'
|
||||||
import { isSimpleIdentifier } from '../utils'
|
|
||||||
|
|
||||||
// v-on without arg is handled directly in ./element.ts due to it affecting
|
// v-on without arg is handled directly in ./element.ts due to it affecting
|
||||||
// codegen for the entire props object. This transform here is only for v-on
|
// codegen for the entire props object. This transform here is only for v-on
|
||||||
@ -14,22 +13,18 @@ export const transformOn: DirectiveTransform = (
|
|||||||
if (!exp && !modifiers.length) {
|
if (!exp && !modifiers.length) {
|
||||||
context.onError(createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc))
|
context.onError(createCompilerError(ErrorCodes.X_V_ON_NO_EXPRESSION, loc))
|
||||||
}
|
}
|
||||||
const { content, children, isStatic, loc: argLoc } = arg!
|
const { content, isStatic, loc: argLoc } = arg!
|
||||||
let eventName: ExpressionNode
|
let eventName: ExpressionNode
|
||||||
if (isStatic) {
|
if (isStatic) {
|
||||||
// static arg
|
// static arg
|
||||||
eventName = createExpression(`on${capitalize(content)}`, true, argLoc)
|
eventName = createExpression(`on${capitalize(content)}`, true, argLoc)
|
||||||
} else if (!children) {
|
|
||||||
// dynamic arg with no rewrite
|
|
||||||
eventName = createExpression(
|
|
||||||
`"on" + ${isSimpleIdentifier(content) ? content : `(${content})`}`,
|
|
||||||
false,
|
|
||||||
argLoc
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// dynamic arg with ctx prefixing
|
// dynamic arg. turn it into a compound expression.
|
||||||
eventName = arg!
|
eventName = arg!
|
||||||
children.unshift(`"on" + `)
|
;(
|
||||||
|
eventName.children ||
|
||||||
|
(eventName.children = [{ ...eventName, children: undefined }])
|
||||||
|
).unshift(`"on" + `)
|
||||||
}
|
}
|
||||||
// TODO .once modifier handling since it is platform agnostic
|
// TODO .once modifier handling since it is platform agnostic
|
||||||
// other modifiers are handled in compiler-dom
|
// other modifiers are handled in compiler-dom
|
||||||
|
Loading…
Reference in New Issue
Block a user