From 597ada36ed1c5da8d9ba922c4514b4e384671020 Mon Sep 17 00:00:00 2001 From: Evan You Date: Tue, 24 Sep 2019 22:03:28 -0400 Subject: [PATCH] test: tests for v-bind transform --- .../__tests__/transforms/vBind.spec.ts | 121 +++++++++++++++++- .../compiler-core/src/runtimeConstants.ts | 1 - .../src/transforms/transformExpression.ts | 4 +- .../compiler-core/src/transforms/vBind.ts | 25 ++-- packages/compiler-core/src/transforms/vOn.ts | 14 +- packages/runtime-core/src/index.ts | 1 - 6 files changed, 143 insertions(+), 23 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/vBind.spec.ts b/packages/compiler-core/__tests__/transforms/vBind.spec.ts index e2e611375..e804d1a11 100644 --- a/packages/compiler-core/__tests__/transforms/vBind.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vBind.spec.ts @@ -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(`
`) + 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(`
`) + 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(`
`, { 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(`
`) + const props = node.codegenNode!.arguments[1] as ObjectExpression + expect(props.properties[0]).toMatchObject({ + key: { + content: `fooBar`, + isStatic: true + }, + value: { + content: `id`, + isStatic: false + } + }) + }) +}) diff --git a/packages/compiler-core/src/runtimeConstants.ts b/packages/compiler-core/src/runtimeConstants.ts index 2423c7d73..a253b0966 100644 --- a/packages/compiler-core/src/runtimeConstants.ts +++ b/packages/compiler-core/src/runtimeConstants.ts @@ -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` diff --git a/packages/compiler-core/src/transforms/transformExpression.ts b/packages/compiler-core/src/transforms/transformExpression.ts index dbb905ae0..feee19423 100644 --- a/packages/compiler-core/src/transforms/transformExpression.ts +++ b/packages/compiler-core/src/transforms/transformExpression.ts @@ -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 !( diff --git a/packages/compiler-core/src/transforms/vBind.ts b/packages/compiler-core/src/transforms/vBind.ts index d8a3894a0..acfff0f48 100644 --- a/packages/compiler-core/src/transforms/vBind.ts +++ b/packages/compiler-core/src/transforms/vBind.ts @@ -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 } diff --git a/packages/compiler-core/src/transforms/vOn.ts b/packages/compiler-core/src/transforms/vOn.ts index 24e2eab83..a7e38b99a 100644 --- a/packages/compiler-core/src/transforms/vOn.ts +++ b/packages/compiler-core/src/transforms/vOn.ts @@ -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 } diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 3f0896d7d..0844627ba 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -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'