test: tests for v-bind transform

This commit is contained in:
Evan You 2019-09-24 22:03:28 -04:00
parent 6ad84614f7
commit 597ada36ed
6 changed files with 143 additions and 23 deletions

View File

@ -1 +1,120 @@
test.todo('v-bind')
import {
parse,
transform,
ElementNode,
ObjectExpression,
CompilerOptions,
ErrorCodes
} from '../../src'
import { transformBind } from '../../src/transforms/vBind'
import { transformElement } from '../../src/transforms/transformElement'
function parseWithVBind(
template: string,
options: CompilerOptions = {}
): ElementNode {
const ast = parse(template)
transform(ast, {
nodeTransforms: [transformElement],
directiveTransforms: {
bind: transformBind
},
...options
})
return ast.children[0] as ElementNode
}
describe('compiler: transform v-bind', () => {
test('basic', () => {
const node = parseWithVBind(`<div v-bind:id="id"/>`)
const props = node.codegenNode!.arguments[1] as ObjectExpression
expect(props.properties[0]).toMatchObject({
key: {
content: `id`,
isStatic: true,
loc: {
start: {
line: 1,
column: 13
},
end: {
line: 1,
column: 15
}
}
},
value: {
content: `id`,
isStatic: false,
loc: {
start: {
line: 1,
column: 16
},
end: {
line: 1,
column: 20
}
}
},
loc: {
start: {
line: 1,
column: 6
},
end: {
line: 1,
column: 20
}
}
})
})
test('dynamic arg', () => {
const node = parseWithVBind(`<div v-bind:[id]="id"/>`)
const props = node.codegenNode!.arguments[1] as ObjectExpression
expect(props.properties[0]).toMatchObject({
key: {
content: `id`,
isStatic: false
},
value: {
content: `id`,
isStatic: false
}
})
})
test('should error if no expression', () => {
const onError = jest.fn()
parseWithVBind(`<div v-bind />`, { onError })
expect(onError.mock.calls[0][0]).toMatchObject({
code: ErrorCodes.X_V_BIND_NO_EXPRESSION,
loc: {
start: {
line: 1,
column: 6
},
end: {
line: 1,
column: 12
}
}
})
})
test('.camel modifier', () => {
const node = parseWithVBind(`<div v-bind:foo-bar.camel="id"/>`)
const props = node.codegenNode!.arguments[1] as ObjectExpression
expect(props.properties[0]).toMatchObject({
key: {
content: `fooBar`,
isStatic: true
},
value: {
content: `id`,
isStatic: false
}
})
})
})

View File

@ -10,7 +10,6 @@ export const RESOLVE_COMPONENT = `resolveComponent`
export const RESOLVE_DIRECTIVE = `resolveDirective`
export const APPLY_DIRECTIVES = `applyDirectives`
export const RENDER_LIST = `renderList`
export const CAPITALIZE = `capitalize`
export const TO_STRING = `toString`
export const MERGE_PROPS = `mergeProps`
export const TO_HANDLERS = `toHandlers`

View File

@ -86,7 +86,7 @@ export function processExpression(
enter(node: Node & PrefixMeta, parent) {
if (node.type === 'Identifier') {
if (
ids.indexOf(node) === -1 &&
!ids.includes(node) &&
!knownIds[node.name] &&
shouldPrefix(node, parent)
) {
@ -177,7 +177,7 @@ function shouldPrefix(identifier: Identifier, parent: Node) {
// not id of a FunctionDeclaration
((parent as any).id === identifier ||
// not a params of a function
parent.params.indexOf(identifier) > -1)
parent.params.includes(identifier))
) &&
// not a key of Property
!(

View File

@ -1,23 +1,28 @@
import { DirectiveTransform } from '../transform'
import { createObjectProperty, createExpression } from '../ast'
import { createCompilerError, ErrorCodes } from '../errors'
import { camelize } from '@vue/shared'
// v-bind 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-bind
// *with* args.
export const transformBind: DirectiveTransform = (dir, context) => {
if (!dir.exp) {
context.onError(
createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, dir.loc)
)
export const transformBind: DirectiveTransform = (
{ exp, arg, modifiers, loc },
context
) => {
if (!exp) {
context.onError(createCompilerError(ErrorCodes.X_V_BIND_NO_EXPRESSION, loc))
}
// .prop is no longer necessary due to new patch behavior
// .sync is replced by v-model:arg
if (modifiers.includes('camel')) {
arg!.content = camelize(arg!.content)
}
// TODO handle .prop modifier
// TODO handle .camel modifier
return {
props: createObjectProperty(
dir.arg!,
dir.exp || createExpression('', true, dir.loc),
dir.loc
arg!,
exp || createExpression('', true, loc),
loc
),
needRuntime: false
}

View File

@ -1,23 +1,21 @@
import { DirectiveTransform } from '../transform'
import { createObjectProperty, createExpression } from '../ast'
import { capitalize } from '@vue/shared'
import { CAPITALIZE } from '../runtimeConstants'
// 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
// *with* args.
export const transformOn: DirectiveTransform = (dir, context) => {
const arg = dir.arg!
const eventName = arg.isStatic
? createExpression(`on${capitalize(arg.content)}`, true, arg.loc)
: createExpression(`'on' + ${CAPITALIZE}(${arg.content})`, false, arg.loc)
export const transformOn: DirectiveTransform = ({ arg, exp, loc }) => {
const eventName = arg!.isStatic
? createExpression(`on${capitalize(arg!.content)}`, true, arg!.loc)
: createExpression(`'on' + (${arg!.content})`, false, arg!.loc)
// TODO .once modifier handling since it is platform agnostic
// other modifiers are handled in compiler-dom
return {
props: createObjectProperty(
eventName,
dir.exp || createExpression(`() => {}`, false, dir.loc),
dir.loc
exp || createExpression(`() => {}`, false, loc),
loc
),
needRuntime: false
}

View File

@ -42,7 +42,6 @@ export { resolveComponent, resolveDirective } from './helpers/resolveAssets'
export { renderList } from './helpers/renderList'
export { toString } from './helpers/toString'
export { toHandlers } from './helpers/toHandlers'
export { capitalize } from '@vue/shared'
// Internal, for integration with runtime compiler
export { registerRuntimeCompiler } from './component'