test: test transformElements

This commit is contained in:
Evan You 2019-09-23 20:45:40 -04:00
parent c20975ec68
commit dcf4764360
13 changed files with 433 additions and 71 deletions

View File

@ -1,3 +0,0 @@
describe('compiler: element transform', () => {
test.todo('should work')
})

View File

@ -1,15 +0,0 @@
import { SourceMapConsumer } from 'source-map'
import { compile } from '../../src'
test(`should work`, async () => {
const { code, map } = compile(`<div>{{ foo }} bar</div>`, {
prefixIdentifiers: true
})
console.log(code)
const consumer = await new SourceMapConsumer(map!)
const pos = consumer.originalPositionFor({
line: 4,
column: 31
})
console.log(pos)
})

View File

@ -0,0 +1,359 @@
import {
ElementNode,
CompilerOptions,
parse,
transform,
ErrorCodes
} from '../../src'
import { transformElement } from '../../src/transforms/transformElement'
import {
RESOLVE_COMPONENT,
CREATE_VNODE,
MERGE_PROPS,
RESOLVE_DIRECTIVE,
APPLY_DIRECTIVES
} from '../../src/runtimeConstants'
import {
CallExpression,
NodeTypes,
createObjectProperty,
DirectiveNode,
RootNode
} from '../../src/ast'
function parseWithElementTransform(
template: string,
options: CompilerOptions = {}
): {
root: RootNode
node: CallExpression
} {
const ast = parse(template, options)
transform(ast, {
nodeTransforms: [transformElement],
...options
})
const codegenNode = (ast.children[0] as ElementNode)
.codegenNode as CallExpression
expect(codegenNode.type).toBe(NodeTypes.JS_CALL_EXPRESSION)
return {
root: ast,
node: codegenNode
}
}
function createStaticObjectMatcher(obj: any) {
return {
type: NodeTypes.JS_OBJECT_EXPRESSION,
properties: Object.keys(obj).map(key => ({
type: NodeTypes.JS_PROPERTY,
key: {
type: NodeTypes.EXPRESSION,
content: key,
isStatic: true
},
value: {
type: NodeTypes.EXPRESSION,
content: obj[key],
isStatic: true
}
}))
}
}
describe('compiler: element transform', () => {
test('import + resovle component', () => {
const { root } = parseWithElementTransform(`<Foo/>`)
expect(root.imports).toContain(RESOLVE_COMPONENT)
expect(root.statements[0]).toMatch(`${RESOLVE_COMPONENT}("Foo")`)
})
test('static props', () => {
const { node } = parseWithElementTransform(`<div id="foo" class="bar" />`)
expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments).toMatchObject([
`"div"`,
createStaticObjectMatcher({
id: 'foo',
class: 'bar'
})
])
})
test('v-bind="obj"', () => {
const { root, node } = parseWithElementTransform(`<div v-bind="obj" />`)
// single v-bind doesn't need mergeProps
expect(root.imports).not.toContain(MERGE_PROPS)
expect(node.callee).toBe(CREATE_VNODE)
// should directly use `obj` in props position
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.EXPRESSION,
content: `obj`
})
})
test('v-bind="obj" after static prop', () => {
const { root, node } = parseWithElementTransform(
`<div id="foo" v-bind="obj" />`
)
expect(root.imports).toContain(MERGE_PROPS)
expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: MERGE_PROPS,
arguments: [
createStaticObjectMatcher({
id: 'foo'
}),
{
type: NodeTypes.EXPRESSION,
content: `obj`
}
]
})
})
test('v-bind="obj" before static prop', () => {
const { root, node } = parseWithElementTransform(
`<div v-bind="obj" id="foo" />`
)
expect(root.imports).toContain(MERGE_PROPS)
expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: MERGE_PROPS,
arguments: [
{
type: NodeTypes.EXPRESSION,
content: `obj`
},
createStaticObjectMatcher({
id: 'foo'
})
]
})
})
test('v-bind="obj" between static props', () => {
const { root, node } = parseWithElementTransform(
`<div id="foo" v-bind="obj" class="bar" />`
)
expect(root.imports).toContain(MERGE_PROPS)
expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_CALL_EXPRESSION,
callee: MERGE_PROPS,
arguments: [
createStaticObjectMatcher({
id: 'foo'
}),
{
type: NodeTypes.EXPRESSION,
content: `obj`
},
createStaticObjectMatcher({
class: 'bar'
})
]
})
})
test('error on v-bind with no argument', () => {
const onError = jest.fn()
parseWithElementTransform(`<div v-bind/>`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_V_BIND_NO_EXPRESSION
}
])
})
test('directiveTransforms', () => {
let _dir: DirectiveNode
const { node } = parseWithElementTransform(`<div v-foo:bar="hello" />`, {
directiveTransforms: {
foo(dir) {
_dir = dir
return {
props: createObjectProperty(dir.arg!, dir.exp!, dir.loc),
needRuntime: false
}
}
}
})
expect(node.callee).toBe(CREATE_VNODE)
expect(node.arguments[1]).toMatchObject({
type: NodeTypes.JS_OBJECT_EXPRESSION,
properties: [
{
type: NodeTypes.JS_PROPERTY,
key: _dir!.arg,
value: _dir!.exp
}
]
})
})
test('directiveTransform with needRuntime: true', () => {
let _dir: DirectiveNode
const { root, node } = parseWithElementTransform(
`<div v-foo:bar="hello" />`,
{
directiveTransforms: {
foo(dir) {
_dir = dir
return {
props: [
createObjectProperty(dir.arg!, dir.exp!, dir.loc),
createObjectProperty(dir.arg!, dir.exp!, dir.loc)
],
needRuntime: true
}
}
}
}
)
expect(root.imports).toContain(RESOLVE_DIRECTIVE)
expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
expect(node.callee).toBe(APPLY_DIRECTIVES)
expect(node.arguments).toMatchObject([
{
type: NodeTypes.JS_CALL_EXPRESSION,
callee: CREATE_VNODE,
arguments: [
`"div"`,
{
type: NodeTypes.JS_OBJECT_EXPRESSION,
properties: [
{
type: NodeTypes.JS_PROPERTY,
key: _dir!.arg,
value: _dir!.exp
},
{
type: NodeTypes.JS_PROPERTY,
key: _dir!.arg,
value: _dir!.exp
}
]
}
]
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
elements: [
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
elements: [
`_directive_foo`,
// exp
{
type: NodeTypes.EXPRESSION,
content: `hello`,
isStatic: false,
isInterpolation: false
},
// arg
{
type: NodeTypes.EXPRESSION,
content: `bar`,
isStatic: true
}
]
}
]
}
])
})
test('runtime directives', () => {
const { root, node } = parseWithElementTransform(
`<div v-foo v-bar="x" v-baz:[arg].mod.mad="y" />`
)
expect(root.imports).toContain(RESOLVE_DIRECTIVE)
expect(root.statements[0]).toMatch(`${RESOLVE_DIRECTIVE}("foo")`)
expect(root.statements[1]).toMatch(`${RESOLVE_DIRECTIVE}("bar")`)
expect(root.statements[2]).toMatch(`${RESOLVE_DIRECTIVE}("baz")`)
expect(node.callee).toBe(APPLY_DIRECTIVES)
expect(node.arguments).toMatchObject([
{
type: NodeTypes.JS_CALL_EXPRESSION
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
elements: [
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
elements: [`_directive_foo`]
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
elements: [
`_directive_bar`,
// exp
{
type: NodeTypes.EXPRESSION,
content: `x`
}
]
},
{
type: NodeTypes.JS_ARRAY_EXPRESSION,
elements: [
`_directive_baz`,
// exp
{
type: NodeTypes.EXPRESSION,
content: `y`,
isStatic: false,
isInterpolation: false
},
// arg
{
type: NodeTypes.EXPRESSION,
content: `arg`,
isStatic: false
},
// modifiers
{
type: NodeTypes.JS_OBJECT_EXPRESSION,
properties: [
{
type: NodeTypes.JS_PROPERTY,
key: {
type: NodeTypes.EXPRESSION,
content: `mod`,
isStatic: true
},
value: {
type: NodeTypes.EXPRESSION,
content: `true`,
isStatic: false
}
},
{
type: NodeTypes.JS_PROPERTY,
key: {
type: NodeTypes.EXPRESSION,
content: `mad`,
isStatic: true
},
value: {
type: NodeTypes.EXPRESSION,
content: `true`,
isStatic: false
}
}
]
}
]
}
]
}
])
})
test.todo('slot outlets')
})

View File

@ -0,0 +1,8 @@
import { compile } from '../../src'
test(`should work`, () => {
const { code } = compile(`<div>{{ foo }} bar</div>`, {
prefixIdentifiers: true
})
expect(code).toContain(`foo`)
})

View File

@ -5,7 +5,7 @@ import { ForNode, NodeTypes } from '../../src/ast'
import { ErrorCodes } from '../../src/errors'
import { CompilerOptions } from '../../src'
function transformWithFor(
function parseWithForTransform(
template: string,
options: CompilerOptions = {}
): ForNode {
@ -20,7 +20,7 @@ function transformWithFor(
describe('compiler: transform v-for', () => {
test('number expression', () => {
const forNode = transformWithFor('<span v-for="index in 5" />')
const forNode = parseWithForTransform('<span v-for="index in 5" />')
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('index')
@ -28,7 +28,7 @@ describe('compiler: transform v-for', () => {
})
test('value', () => {
const forNode = transformWithFor('<span v-for="(item) in items" />')
const forNode = parseWithForTransform('<span v-for="(item) in items" />')
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('item')
@ -36,7 +36,7 @@ describe('compiler: transform v-for', () => {
})
test('object de-structured value', () => {
const forNode = transformWithFor(
const forNode = parseWithForTransform(
'<span v-for="({ id, value }) in items" />'
)
expect(forNode.keyAlias).toBeUndefined()
@ -46,7 +46,7 @@ describe('compiler: transform v-for', () => {
})
test('array de-structured value', () => {
const forNode = transformWithFor(
const forNode = parseWithForTransform(
'<span v-for="([ id, value ]) in items" />'
)
expect(forNode.keyAlias).toBeUndefined()
@ -56,7 +56,9 @@ describe('compiler: transform v-for', () => {
})
test('value and key', () => {
const forNode = transformWithFor('<span v-for="(item, key) in items" />')
const forNode = parseWithForTransform(
'<span v-for="(item, key) in items" />'
)
expect(forNode.keyAlias).not.toBeUndefined()
expect(forNode.keyAlias!.content).toBe('key')
expect(forNode.objectIndexAlias).toBeUndefined()
@ -65,7 +67,7 @@ describe('compiler: transform v-for', () => {
})
test('value, key and index', () => {
const forNode = transformWithFor(
const forNode = parseWithForTransform(
'<span v-for="(value, key, index) in items" />'
)
expect(forNode.keyAlias).not.toBeUndefined()
@ -77,7 +79,9 @@ describe('compiler: transform v-for', () => {
})
test('skipped key', () => {
const forNode = transformWithFor('<span v-for="(value,,index) in items" />')
const forNode = parseWithForTransform(
'<span v-for="(value,,index) in items" />'
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
@ -86,7 +90,7 @@ describe('compiler: transform v-for', () => {
})
test('skipped value and key', () => {
const forNode = transformWithFor('<span v-for="(,,index) in items" />')
const forNode = parseWithForTransform('<span v-for="(,,index) in items" />')
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
@ -95,7 +99,7 @@ describe('compiler: transform v-for', () => {
})
test('unbracketed value', () => {
const forNode = transformWithFor('<span v-for="item in items" />')
const forNode = parseWithForTransform('<span v-for="item in items" />')
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).toBeUndefined()
expect(forNode.valueAlias!.content).toBe('item')
@ -103,7 +107,7 @@ describe('compiler: transform v-for', () => {
})
test('unbracketed value and key', () => {
const forNode = transformWithFor('<span v-for="item, key in items" />')
const forNode = parseWithForTransform('<span v-for="item, key in items" />')
expect(forNode.keyAlias).not.toBeUndefined()
expect(forNode.keyAlias!.content).toBe('key')
expect(forNode.objectIndexAlias).toBeUndefined()
@ -112,7 +116,7 @@ describe('compiler: transform v-for', () => {
})
test('unbracketed value, key and index', () => {
const forNode = transformWithFor(
const forNode = parseWithForTransform(
'<span v-for="value, key, index in items" />'
)
expect(forNode.keyAlias).not.toBeUndefined()
@ -124,7 +128,9 @@ describe('compiler: transform v-for', () => {
})
test('unbracketed skipped key', () => {
const forNode = transformWithFor('<span v-for="value, , index in items" />')
const forNode = parseWithForTransform(
'<span v-for="value, , index in items" />'
)
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
@ -133,7 +139,7 @@ describe('compiler: transform v-for', () => {
})
test('unbracketed skipped value and key', () => {
const forNode = transformWithFor('<span v-for=", , index in items" />')
const forNode = parseWithForTransform('<span v-for=", , index in items" />')
expect(forNode.keyAlias).toBeUndefined()
expect(forNode.objectIndexAlias).not.toBeUndefined()
expect(forNode.objectIndexAlias!.content).toBe('index')
@ -143,7 +149,7 @@ describe('compiler: transform v-for', () => {
test('missing expression', () => {
const onError = jest.fn()
transformWithFor('<span v-for />', { onError })
parseWithForTransform('<span v-for />', { onError })
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
@ -155,7 +161,7 @@ describe('compiler: transform v-for', () => {
test('empty expression', () => {
const onError = jest.fn()
transformWithFor('<span v-for="" />', { onError })
parseWithForTransform('<span v-for="" />', { onError })
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
@ -167,7 +173,7 @@ describe('compiler: transform v-for', () => {
test('invalid expression', () => {
const onError = jest.fn()
transformWithFor('<span v-for="items" />', { onError })
parseWithForTransform('<span v-for="items" />', { onError })
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
@ -179,7 +185,7 @@ describe('compiler: transform v-for', () => {
test('missing source', () => {
const onError = jest.fn()
transformWithFor('<span v-for="item in" />', { onError })
parseWithForTransform('<span v-for="item in" />', { onError })
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
@ -191,7 +197,7 @@ describe('compiler: transform v-for', () => {
test('missing value', () => {
const onError = jest.fn()
transformWithFor('<span v-for="in items" />', { onError })
parseWithForTransform('<span v-for="in items" />', { onError })
expect(onError).toHaveBeenCalledTimes(1)
expect(onError).toHaveBeenCalledWith(
@ -204,7 +210,7 @@ describe('compiler: transform v-for', () => {
describe('source location', () => {
test('value & source', () => {
const source = '<span v-for="item in items" />'
const forNode = transformWithFor(source)
const forNode = parseWithForTransform(source)
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(
@ -227,7 +233,7 @@ describe('compiler: transform v-for', () => {
test('bracketed value', () => {
const source = '<span v-for="( item ) in items" />'
const forNode = transformWithFor(source)
const forNode = parseWithForTransform(source)
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(
@ -250,7 +256,7 @@ describe('compiler: transform v-for', () => {
test('de-structured value', () => {
const source = '<span v-for="( { id, key })in items" />'
const forNode = transformWithFor(source)
const forNode = parseWithForTransform(source)
expect(forNode.valueAlias!.content).toBe('{ id, key }')
expect(forNode.valueAlias!.loc.start.offset).toBe(
@ -275,7 +281,7 @@ describe('compiler: transform v-for', () => {
test('bracketed value, key, index', () => {
const source = '<span v-for="( item, key, index ) in items" />'
const forNode = transformWithFor(source)
const forNode = parseWithForTransform(source)
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(
@ -318,7 +324,7 @@ describe('compiler: transform v-for', () => {
test('skipped key', () => {
const source = '<span v-for="( item,, index ) in items" />'
const forNode = transformWithFor(source)
const forNode = parseWithForTransform(source)
expect(forNode.valueAlias!.content).toBe('item')
expect(forNode.valueAlias!.loc.start.offset).toBe(

View File

@ -11,7 +11,7 @@ import {
import { ErrorCodes } from '../../src/errors'
import { CompilerOptions } from '../../src'
function transformWithIf(
function parseWithIfTransform(
template: string,
options: CompilerOptions = {},
returnIndex: number = 0
@ -27,7 +27,7 @@ function transformWithIf(
describe('compiler: transform v-if', () => {
test('basic v-if', () => {
const node = transformWithIf(`<div v-if="ok"/>`)
const node = parseWithIfTransform(`<div v-if="ok"/>`)
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(1)
expect(node.branches[0].condition!.content).toBe(`ok`)
@ -37,7 +37,7 @@ describe('compiler: transform v-if', () => {
})
test('template v-if', () => {
const node = transformWithIf(
const node = parseWithIfTransform(
`<template v-if="ok"><div/>hello<p/></template>`
)
expect(node.type).toBe(NodeTypes.IF)
@ -53,7 +53,7 @@ describe('compiler: transform v-if', () => {
})
test('v-if + v-else', () => {
const node = transformWithIf(`<div v-if="ok"/><p v-else/>`)
const node = parseWithIfTransform(`<div v-if="ok"/><p v-else/>`)
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(2)
@ -71,7 +71,7 @@ describe('compiler: transform v-if', () => {
})
test('v-if + v-else-if', () => {
const node = transformWithIf(`<div v-if="ok"/><p v-else-if="orNot"/>`)
const node = parseWithIfTransform(`<div v-if="ok"/><p v-else-if="orNot"/>`)
expect(node.type).toBe(NodeTypes.IF)
expect(node.branches.length).toBe(2)
@ -89,7 +89,7 @@ describe('compiler: transform v-if', () => {
})
test('v-if + v-else-if + v-else', () => {
const node = transformWithIf(
const node = parseWithIfTransform(
`<div v-if="ok"/><p v-else-if="orNot"/><template v-else>fine</template>`
)
expect(node.type).toBe(NodeTypes.IF)
@ -115,7 +115,7 @@ describe('compiler: transform v-if', () => {
})
test('comment between branches', () => {
const node = transformWithIf(`
const node = parseWithIfTransform(`
<div v-if="ok"/>
<!--foo-->
<p v-else-if="orNot"/>
@ -151,7 +151,7 @@ describe('compiler: transform v-if', () => {
test('error on v-else missing adjacent v-if', () => {
const onError = jest.fn()
const node1 = transformWithIf(`<div v-else/>`, { onError })
const node1 = parseWithIfTransform(`<div v-else/>`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
@ -159,7 +159,7 @@ describe('compiler: transform v-if', () => {
}
])
const node2 = transformWithIf(`<div/><div v-else/>`, { onError }, 1)
const node2 = parseWithIfTransform(`<div/><div v-else/>`, { onError }, 1)
expect(onError.mock.calls[1]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
@ -167,7 +167,7 @@ describe('compiler: transform v-if', () => {
}
])
const node3 = transformWithIf(`<div/>foo<div v-else/>`, { onError }, 2)
const node3 = parseWithIfTransform(`<div/>foo<div v-else/>`, { onError }, 2)
expect(onError.mock.calls[2]).toMatchObject([
{
code: ErrorCodes.X_ELSE_NO_ADJACENT_IF,
@ -179,7 +179,7 @@ describe('compiler: transform v-if', () => {
test('error on v-else-if missing adjacent v-if', () => {
const onError = jest.fn()
const node1 = transformWithIf(`<div v-else-if="foo"/>`, { onError })
const node1 = parseWithIfTransform(`<div v-else-if="foo"/>`, { onError })
expect(onError.mock.calls[0]).toMatchObject([
{
code: ErrorCodes.X_ELSE_IF_NO_ADJACENT_IF,
@ -187,7 +187,7 @@ describe('compiler: transform v-if', () => {
}
])
const node2 = transformWithIf(
const node2 = parseWithIfTransform(
`<div/><div v-else-if="foo"/>`,
{ onError },
1
@ -199,7 +199,7 @@ describe('compiler: transform v-if', () => {
}
])
const node3 = transformWithIf(
const node3 = parseWithIfTransform(
`<div/>foo<div v-else-if="foo"/>`,
{ onError },
2

View File

@ -147,6 +147,9 @@ export function generate(
if (!prefixIdentifiers) {
push(`with (this) {`)
indent()
} else {
push(`const _ctx = this`)
newline()
}
push(`return `)
genChildren(ast.children, context, true /* asRoot */)

View File

@ -5,10 +5,10 @@ import { RootNode } from './ast'
import { isString } from '@vue/shared'
import { transformIf } from './transforms/vIf'
import { transformFor } from './transforms/vFor'
import { prepareElementForCodegen } from './transforms/element'
import { transformElement } from './transforms/transformElement'
import { transformOn } from './transforms/vOn'
import { transformBind } from './transforms/vBind'
import { expressionTransform } from './transforms/expression'
import { transformExpression } from './transforms/transformExpression'
import { defaultOnError, createCompilerError, ErrorCodes } from './errors'
export type CompilerOptions = ParserOptions & TransformOptions & CodegenOptions
@ -32,8 +32,8 @@ export function compile(
nodeTransforms: [
transformIf,
transformFor,
...(prefixIdentifiers ? [expressionTransform] : []),
prepareElementForCodegen,
...(prefixIdentifiers ? [transformExpression] : []),
transformElement,
...(options.nodeTransforms || []) // user transforms
],
directiveTransforms: {
@ -65,4 +65,6 @@ export { ErrorCodes, CompilerError, createCompilerError } from './errors'
export * from './ast'
// debug
export { prepareElementForCodegen } from './transforms/element'
export {
transformElement as prepareElementForCodegen
} from './transforms/transformElement'

View File

@ -7,3 +7,4 @@ export const APPLY_DIRECTIVES = `applyDirectives`
export const RENDER_LIST = `renderList`
export const CAPITALIZE = `capitalize`
export const TO_STRING = `toString`
export const MERGE_PROPS = `mergeProps`

View File

@ -20,13 +20,14 @@ import {
CREATE_VNODE,
APPLY_DIRECTIVES,
RESOLVE_DIRECTIVE,
RESOLVE_COMPONENT
RESOLVE_COMPONENT,
MERGE_PROPS
} from '../runtimeConstants'
const toValidId = (str: string): string => str.replace(/[^\w]/g, '')
// generate a JavaScript AST for this element's codegen
export const prepareElementForCodegen: NodeTransform = (node, context) => {
export const transformElement: NodeTransform = (node, context) => {
if (node.type === NodeTypes.ELEMENT) {
if (
node.tagType === ElementTypes.ELEMENT ||
@ -91,9 +92,8 @@ export const prepareElementForCodegen: NodeTransform = (node, context) => {
} else if (node.tagType === ElementTypes.SLOT) {
// <slot [name="xxx"]/>
// TODO
} else if (node.tagType === ElementTypes.TEMPLATE) {
// do nothing
}
// node.tagType can also be TEMPLATE, in which case nothing needs to be done
}
}
@ -101,7 +101,7 @@ function buildProps(
{ loc, props }: ElementNode,
context: TransformContext
): {
props: ObjectExpression | CallExpression
props: ObjectExpression | CallExpression | ExpressionNode
directives: DirectiveNode[]
} {
let properties: ObjectExpression['properties'] = []
@ -160,7 +160,7 @@ function buildProps(
}
}
let ret: ObjectExpression | CallExpression
let ret: ObjectExpression | CallExpression | ExpressionNode
// has v-bind="object", wrap with mergeProps
if (mergeArgs.length) {
@ -168,10 +168,11 @@ function buildProps(
mergeArgs.push(createObjectExpression(properties, loc))
}
if (mergeArgs.length > 1) {
ret = createCallExpression(`mergeProps`, mergeArgs, loc)
context.imports.add(MERGE_PROPS)
ret = createCallExpression(MERGE_PROPS, mergeArgs, loc)
} else {
// single v-bind with nothing else - no need for a mergeProps call
ret = createObjectExpression(properties, loc)
ret = mergeArgs[0]
}
} else {
ret = createObjectExpression(properties, loc)

View File

@ -15,7 +15,7 @@ import { NodeTypes, createExpression, ExpressionNode } from '../ast'
import { Node, Function, Identifier } from 'estree'
import { advancePositionWithClone } from '../utils'
export const expressionTransform: NodeTransform = (node, context) => {
export const transformExpression: NodeTransform = (node, context) => {
if (node.type === NodeTypes.EXPRESSION && !node.isStatic) {
processExpression(node, context)
} else if (node.type === NodeTypes.ELEMENT) {

View File

@ -11,7 +11,7 @@ import {
import { createCompilerError, ErrorCodes } from '../errors'
import { getInnerRange } from '../utils'
import { RENDER_LIST } from '../runtimeConstants'
import { processExpression } from './expression'
import { processExpression } from './transformExpression'
const forAliasRE = /([\s\S]*?)(?:(?<=\))|\s+)(?:in|of)\s+([\s\S]*)/
const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/

View File

@ -10,7 +10,7 @@ import {
IfBranchNode
} from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { processExpression } from './expression'
import { processExpression } from './transformExpression'
export const transformIf = createStructuralDirectiveTransform(
/^(if|else|else-if)$/,