test: test transformElements
This commit is contained in:
parent
c20975ec68
commit
dcf4764360
@ -1,3 +0,0 @@
|
||||
describe('compiler: element transform', () => {
|
||||
test.todo('should work')
|
||||
})
|
@ -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)
|
||||
})
|
@ -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')
|
||||
})
|
@ -0,0 +1,8 @@
|
||||
import { compile } from '../../src'
|
||||
|
||||
test(`should work`, () => {
|
||||
const { code } = compile(`<div>{{ foo }} bar</div>`, {
|
||||
prefixIdentifiers: true
|
||||
})
|
||||
expect(code).toContain(`foo`)
|
||||
})
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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 */)
|
||||
|
@ -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'
|
||||
|
@ -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`
|
||||
|
@ -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)
|
@ -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) {
|
@ -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 = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/
|
||||
|
@ -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)$/,
|
||||
|
Loading…
x
Reference in New Issue
Block a user