From 9777e232b1d1979097b64403beeb98a8aed28ee0 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Mon, 7 Oct 2019 15:09:07 +0530 Subject: [PATCH 1/8] feat(compiler-core): create transform for v-model --- packages/compiler-core/src/transforms/vModel.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index 70b786d12ed..57db43fa31f 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -1 +1,5 @@ -// TODO +import { DirectiveTransform } from '../transform' + +export const transformModel: DirectiveTransform = (node, context) => { + return { props: [], needRuntime: false } +} From 24b112b0fcdc4a9a6ce0626eb16e6e28c8ba5a90 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Tue, 8 Oct 2019 23:59:58 +0530 Subject: [PATCH 2/8] feat(compiler-core,v-model): transform v-model into props --- .../__snapshots__/vModel.spec.ts.snap | 97 +++++ .../__tests__/transforms/vModel.spec.ts | 350 ++++++++++++++++++ packages/compiler-core/src/errors.ts | 7 +- .../compiler-core/src/transforms/vModel.ts | 53 ++- packages/compiler-core/src/utils.ts | 7 +- 5 files changed, 508 insertions(+), 6 deletions(-) create mode 100644 packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap create mode 100644 packages/compiler-core/__tests__/transforms/vModel.spec.ts diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap new file mode 100644 index 00000000000..aeecf4da144 --- /dev/null +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -0,0 +1,97 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`compiler: transform v-model compound expression (with prefixIdentifiers) 1`] = ` +"import { createVNode, openBlock, createBlock } from \\"vue\\" + +export default function render() { + const _ctx = this + return (openBlock(), createBlock(\\"input\\", { + modelValue: _ctx.model[_ctx.index], + \\"onUpdate:modelValue\\": $event => (_ctx.model[_ctx.index] = $event) + }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) +}" +`; + +exports[`compiler: transform v-model compound expression 1`] = ` +"const _Vue = Vue + +return function render() { + with (this) { + const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + + return (_openBlock(), _createBlock(\\"input\\", { + modelValue: model[index], + \\"onUpdate:modelValue\\": $event => (model[index] = $event) + }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) + } +}" +`; + +exports[`compiler: transform v-model simple exprssion (with prefixIdentifiers) 1`] = ` +"import { createVNode, openBlock, createBlock } from \\"vue\\" + +export default function render() { + const _ctx = this + return (openBlock(), createBlock(\\"input\\", { + modelValue: _ctx.model, + \\"onUpdate:modelValue\\": $event => (_ctx.model = $event) + }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) +}" +`; + +exports[`compiler: transform v-model simple exprssion 1`] = ` +"const _Vue = Vue + +return function render() { + with (this) { + const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + + return (_openBlock(), _createBlock(\\"input\\", { + modelValue: model, + \\"onUpdate:modelValue\\": $event => (model = $event) + }, null, 8 /* PROPS */, [\\"modelValue\\", \\"onUpdate:modelValue\\"])) + } +}" +`; + +exports[`compiler: transform v-model with argument 1`] = ` +"const _Vue = Vue + +return function render() { + with (this) { + const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + + return (_openBlock(), _createBlock(\\"input\\", { + value: model, + \\"onUpdate:value\\": $event => (model = $event) + }, null, 8 /* PROPS */, [\\"value\\", \\"onUpdate:value\\"])) + } +}" +`; + +exports[`compiler: transform v-model with dynamic argument (with prefixIdentifiers) 1`] = ` +"import { createVNode, openBlock, createBlock } from \\"vue\\" + +export default function render() { + const _ctx = this + return (openBlock(), createBlock(\\"input\\", { + [_ctx.value]: _ctx.model, + [\\"onUpdate:\\"+_ctx.value]: $event => (_ctx.model = $event) + }, null, 16 /* FULL_PROPS */)) +}" +`; + +exports[`compiler: transform v-model with dynamic argument 1`] = ` +"const _Vue = Vue + +return function render() { + with (this) { + const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + + return (_openBlock(), _createBlock(\\"input\\", { + [value]: model, + [\\"onUpdate:\\"+value]: $event => (model = $event) + }, null, 16 /* FULL_PROPS */)) + } +}" +`; diff --git a/packages/compiler-core/__tests__/transforms/vModel.spec.ts b/packages/compiler-core/__tests__/transforms/vModel.spec.ts new file mode 100644 index 00000000000..a157b17f0f9 --- /dev/null +++ b/packages/compiler-core/__tests__/transforms/vModel.spec.ts @@ -0,0 +1,350 @@ +import { + parse, + transform, + generate, + ElementNode, + ObjectExpression, + CompilerOptions, + CallExpression +} from '../../src' +import { ErrorCodes } from '../../src/errors' +import { transformModel } from '../../src/transforms/vModel' +import { transformElement } from '../../src/transforms/transformElement' +import { transformExpression } from '../../src/transforms/transformExpression' + +function parseWithVModel(template: string, options: CompilerOptions = {}) { + const ast = parse(template) + + transform(ast, { + nodeTransforms: [transformExpression, transformElement], + directiveTransforms: { + ...options.directiveTransforms, + model: transformModel + }, + ...options + }) + + return ast +} + +describe('compiler: transform v-model', () => { + test('simple exprssion', () => { + const root = parseWithVModel('') + const node = root.children[0] as ElementNode + const props = ((node.codegenNode as CallExpression) + .arguments[1] as ObjectExpression).properties + + expect(props[0]).toMatchObject({ + key: { + content: 'modelValue', + isStatic: true + }, + value: { + content: 'model', + isStatic: false + } + }) + + expect(props[1]).toMatchObject({ + key: { + content: 'onUpdate:modelValue', + isStatic: true + }, + value: { + children: [ + '$event => (', + { + content: 'model', + isStatic: false + }, + ' = $event)' + ] + } + }) + + expect(generate(root).code).toMatchSnapshot() + }) + test('simple exprssion (with prefixIdentifiers)', () => { + const root = parseWithVModel('', { + prefixIdentifiers: true + }) + const node = root.children[0] as ElementNode + const props = ((node.codegenNode as CallExpression) + .arguments[1] as ObjectExpression).properties + + expect(props[0]).toMatchObject({ + key: { + content: 'modelValue', + isStatic: true + }, + value: { + content: '_ctx.model', + isStatic: false + } + }) + + expect(props[1]).toMatchObject({ + key: { + content: 'onUpdate:modelValue', + isStatic: true + }, + value: { + children: [ + '$event => (', + { + content: '_ctx.model', + isStatic: false + }, + ' = $event)' + ] + } + }) + + expect(generate(root, { mode: 'module' }).code).toMatchSnapshot() + }) + test('compound expression', () => { + const root = parseWithVModel('') + const node = root.children[0] as ElementNode + const props = ((node.codegenNode as CallExpression) + .arguments[1] as ObjectExpression).properties + + expect(props[0]).toMatchObject({ + key: { + content: 'modelValue', + isStatic: true + }, + value: { + content: 'model[index]', + isStatic: false + } + }) + + expect(props[1]).toMatchObject({ + key: { + content: 'onUpdate:modelValue', + isStatic: true + }, + value: { + children: [ + '$event => (', + { + content: 'model[index]', + isStatic: false + }, + ' = $event)' + ] + } + }) + + expect(generate(root).code).toMatchSnapshot() + }) + + test('compound expression (with prefixIdentifiers)', () => { + const root = parseWithVModel('', { + prefixIdentifiers: true + }) + const node = root.children[0] as ElementNode + const props = ((node.codegenNode as CallExpression) + .arguments[1] as ObjectExpression).properties + + expect(props[0]).toMatchObject({ + key: { + content: 'modelValue', + isStatic: true + }, + value: { + children: [ + { + content: '_ctx.model', + isStatic: false + }, + '[', + { + content: '_ctx.index', + isStatic: false + }, + ']' + ] + } + }) + + expect(props[1]).toMatchObject({ + key: { + content: 'onUpdate:modelValue', + isStatic: true + }, + value: { + children: [ + '$event => (', + { + content: '_ctx.model', + isStatic: false + }, + '[', + { + content: '_ctx.index', + isStatic: false + }, + ']', + ' = $event)' + ] + } + }) + + expect(generate(root, { mode: 'module' }).code).toMatchSnapshot() + }) + test('with argument', () => { + const root = parseWithVModel('') + const node = root.children[0] as ElementNode + const props = ((node.codegenNode as CallExpression) + .arguments[1] as ObjectExpression).properties + + expect(props[0]).toMatchObject({ + key: { + content: 'value', + isStatic: true + }, + value: { + content: 'model', + isStatic: false + } + }) + + expect(props[1]).toMatchObject({ + key: { + content: 'onUpdate:value', + isStatic: true + }, + value: { + children: [ + '$event => (', + { + content: 'model', + isStatic: false + }, + ' = $event)' + ] + } + }) + + expect(generate(root).code).toMatchSnapshot() + }) + test('with dynamic argument', () => { + const root = parseWithVModel('') + const node = root.children[0] as ElementNode + const props = ((node.codegenNode as CallExpression) + .arguments[1] as ObjectExpression).properties + + expect(props[0]).toMatchObject({ + key: { + content: 'value', + isStatic: false + }, + value: { + content: 'model', + isStatic: false + } + }) + + expect(props[1]).toMatchObject({ + key: { + children: [ + { + content: 'onUpdate:', + isStatic: true + }, + '+', + { + content: 'value', + isStatic: false + } + ] + }, + value: { + children: [ + '$event => (', + { + content: 'model', + isStatic: false + }, + ' = $event)' + ] + } + }) + + expect(generate(root).code).toMatchSnapshot() + }) + test('with dynamic argument (with prefixIdentifiers)', () => { + const root = parseWithVModel('', { + prefixIdentifiers: true + }) + const node = root.children[0] as ElementNode + const props = ((node.codegenNode as CallExpression) + .arguments[1] as ObjectExpression).properties + + expect(props[0]).toMatchObject({ + key: { + content: '_ctx.value', + isStatic: false + }, + value: { + content: '_ctx.model', + isStatic: false + } + }) + + expect(props[1]).toMatchObject({ + key: { + children: [ + { + content: 'onUpdate:', + isStatic: true + }, + '+', + { + content: '_ctx.value', + isStatic: false + } + ] + }, + value: { + children: [ + '$event => (', + { + content: '_ctx.model', + isStatic: false + }, + ' = $event)' + ] + } + }) + + expect(generate(root, { mode: 'module' }).code).toMatchSnapshot() + }) + + describe('errors', () => { + test('missing expression', () => { + const onError = jest.fn() + parseWithVModel('', { onError }) + + expect(onError).toHaveBeenCalledTimes(1) + expect(onError).toHaveBeenCalledWith( + expect.objectContaining({ + code: ErrorCodes.X_V_MODEL_NO_EXPRESSION + }) + ) + }) + + test('empty expression', () => { + const onError = jest.fn() + parseWithVModel('', { onError }) + + expect(onError).toHaveBeenCalledTimes(1) + expect(onError).toHaveBeenCalledWith( + expect.objectContaining({ + code: ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION + }) + ) + }) + }) +}) diff --git a/packages/compiler-core/src/errors.ts b/packages/compiler-core/src/errors.ts index e9c16bfcf27..7388df480a4 100644 --- a/packages/compiler-core/src/errors.ts +++ b/packages/compiler-core/src/errors.ts @@ -54,13 +54,11 @@ export const enum ErrorCodes { UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME, UNEXPECTED_SOLIDUS_IN_TAG, UNKNOWN_NAMED_CHARACTER_REFERENCE, - // Vue-specific parse errors X_INVALID_END_TAG, X_MISSING_END_TAG, X_MISSING_INTERPOLATION_END, X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END, - // transform errors X_IF_NO_EXPRESSION, X_ELSE_NO_ADJACENT_IF, @@ -76,7 +74,8 @@ export const enum ErrorCodes { X_DUPLICATE_SLOT_NAMES, X_EXTRANEOUS_NON_SLOT_CHILDREN, X_MISPLACED_V_SLOT, - + X_V_MODEL_NO_EXPRESSION, + X_V_MODEL_MALFORMED_EXPRESSION, // generic errors X_PREFIX_ID_NOT_SUPPORTED, X_MODULE_MODE_NOT_SUPPORTED @@ -148,6 +147,8 @@ export const errorMessages: { [code: number]: string } = { [ErrorCodes.X_V_ON_NO_EXPRESSION]: `v-on is missing expression.`, [ErrorCodes.X_V_HTML_NO_EXPRESSION]: `v-html is missing epxression.`, [ErrorCodes.X_V_HTML_WITH_CHILDREN]: `v-html will override element children.`, + [ErrorCodes.X_V_MODEL_NO_EXPRESSION]: `v-model is missing expression.`, + [ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION]: `v-model has invalid expression.`, [ErrorCodes.X_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET]: `Unexpected custom directive on outlet.`, [ErrorCodes.X_NAMED_SLOT_ON_COMPONENT]: `Named v-slot on component. ` + diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index 57db43fa31f..9e2bfa4016f 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -1,5 +1,54 @@ import { DirectiveTransform } from '../transform' +import { + createSimpleExpression, + createObjectProperty, + createCompoundExpression, + NodeTypes, + Property +} from '../ast' +import { createCompilerError, ErrorCodes } from '../errors' +import { isEmptyExpression } from '../utils' -export const transformModel: DirectiveTransform = (node, context) => { - return { props: [], needRuntime: false } +export const transformModel: DirectiveTransform = (dir, context) => { + const { exp, arg } = dir + if (!exp) { + context.onError(createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION)) + + return createTransformProps() + } else if (isEmptyExpression(exp)) { + context.onError( + createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION) + ) + + return createTransformProps() + } else { + const defaultPropName = createSimpleExpression('modelValue', true) + const defaultEventName = createSimpleExpression('onUpdate:modelValue', true) + const propName = arg ? arg : defaultPropName + const eventName = arg + ? arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic + ? createSimpleExpression('onUpdate:' + arg.content, true) + : createCompoundExpression([ + createSimpleExpression('onUpdate:', true), + '+', + ...(arg.type === NodeTypes.SIMPLE_EXPRESSION ? [arg] : arg.children) + ]) + : defaultEventName + + return createTransformProps([ + createObjectProperty(propName, dir.exp!), + createObjectProperty( + eventName, + createCompoundExpression([ + `$event => (`, + ...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children), + ` = $event)` + ]) + ) + ]) + } +} + +function createTransformProps(props: Property[] = []) { + return { props, needRuntime: false } } diff --git a/packages/compiler-core/src/utils.ts b/packages/compiler-core/src/utils.ts index 6ffae2caa5f..8ff7b2920b3 100644 --- a/packages/compiler-core/src/utils.ts +++ b/packages/compiler-core/src/utils.ts @@ -20,7 +20,8 @@ import { BlockCodegenNode, ElementCodegenNode, SlotOutletCodegenNode, - ComponentCodegenNode + ComponentCodegenNode, + ExpressionNode } from './ast' import { parse } from 'acorn' import { walk } from 'estree-walker' @@ -237,3 +238,7 @@ export function toValidAssetId( ): string { return `_${type}_${name.replace(/[^\w]/g, '')}` } + +export function isEmptyExpression(node: ExpressionNode) { + return node.type === NodeTypes.SIMPLE_EXPRESSION && !node.content.trim() +} From 7ac0aefbb79a8969cc1cbf4197117c84c887d3dc Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Wed, 9 Oct 2019 00:05:51 +0530 Subject: [PATCH 3/8] chore: revert unwanted changes --- packages/compiler-core/src/errors.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/compiler-core/src/errors.ts b/packages/compiler-core/src/errors.ts index 7388df480a4..58f3e9be557 100644 --- a/packages/compiler-core/src/errors.ts +++ b/packages/compiler-core/src/errors.ts @@ -54,11 +54,13 @@ export const enum ErrorCodes { UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME, UNEXPECTED_SOLIDUS_IN_TAG, UNKNOWN_NAMED_CHARACTER_REFERENCE, + // Vue-specific parse errors X_INVALID_END_TAG, X_MISSING_END_TAG, X_MISSING_INTERPOLATION_END, X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END, + // transform errors X_IF_NO_EXPRESSION, X_ELSE_NO_ADJACENT_IF, @@ -76,6 +78,7 @@ export const enum ErrorCodes { X_MISPLACED_V_SLOT, X_V_MODEL_NO_EXPRESSION, X_V_MODEL_MALFORMED_EXPRESSION, + // generic errors X_PREFIX_ID_NOT_SUPPORTED, X_MODULE_MODE_NOT_SUPPORTED From 4ceba96d94d0a5ac2cd5349bef6bd66af762733d Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Wed, 9 Oct 2019 00:11:55 +0530 Subject: [PATCH 4/8] test(compiler-core): isEmptyExpression for common scenarios --- .../compiler-core/__tests__/utils.spec.ts | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/compiler-core/__tests__/utils.spec.ts b/packages/compiler-core/__tests__/utils.spec.ts index b5d1bea04c9..417d0d18534 100644 --- a/packages/compiler-core/__tests__/utils.spec.ts +++ b/packages/compiler-core/__tests__/utils.spec.ts @@ -1,5 +1,9 @@ -import { Position } from '../src/ast' -import { getInnerRange, advancePositionWithClone } from '../src/utils' +import { Position, NodeTypes } from '../src/ast' +import { + getInnerRange, + advancePositionWithClone, + isEmptyExpression +} from '../src/utils' function p(line: number, column: number, offset: number): Position { return { column, line, offset } @@ -67,3 +71,38 @@ describe('getInnerRange', () => { expect(loc2.end.offset).toBe(7) }) }) + +describe('isEmptyExpression', () => { + test('empty', () => { + expect( + isEmptyExpression({ + content: '', + type: NodeTypes.SIMPLE_EXPRESSION, + isStatic: true, + loc: null as any + }) + ).toBe(true) + }) + + test('spaces', () => { + expect( + isEmptyExpression({ + content: ' \t ', + type: NodeTypes.SIMPLE_EXPRESSION, + isStatic: true, + loc: null as any + }) + ).toBe(true) + }) + + test('identifier', () => { + expect( + isEmptyExpression({ + content: 'foo', + type: NodeTypes.SIMPLE_EXPRESSION, + isStatic: true, + loc: null as any + }) + ).toBe(false) + }) +}) From 9c1e58f9d99fe8eb08b8cc05dd1cc084862d240a Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Wed, 9 Oct 2019 00:19:04 +0530 Subject: [PATCH 5/8] chore(snapshots): update snapshots post rebase --- .../transforms/__snapshots__/vModel.spec.ts.snap | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap b/packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap index aeecf4da144..ea11cf71519 100644 --- a/packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap +++ b/packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`compiler: transform v-model compound expression (with prefixIdentifiers) 1`] = ` -"import { createVNode, openBlock, createBlock } from \\"vue\\" +"import { createVNode, createBlock, openBlock } from \\"vue\\" export default function render() { const _ctx = this @@ -17,7 +17,7 @@ exports[`compiler: transform v-model compound expression 1`] = ` return function render() { with (this) { - const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + const { createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue return (_openBlock(), _createBlock(\\"input\\", { modelValue: model[index], @@ -28,7 +28,7 @@ return function render() { `; exports[`compiler: transform v-model simple exprssion (with prefixIdentifiers) 1`] = ` -"import { createVNode, openBlock, createBlock } from \\"vue\\" +"import { createVNode, createBlock, openBlock } from \\"vue\\" export default function render() { const _ctx = this @@ -44,7 +44,7 @@ exports[`compiler: transform v-model simple exprssion 1`] = ` return function render() { with (this) { - const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + const { createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue return (_openBlock(), _createBlock(\\"input\\", { modelValue: model, @@ -59,7 +59,7 @@ exports[`compiler: transform v-model with argument 1`] = ` return function render() { with (this) { - const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + const { createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue return (_openBlock(), _createBlock(\\"input\\", { value: model, @@ -70,7 +70,7 @@ return function render() { `; exports[`compiler: transform v-model with dynamic argument (with prefixIdentifiers) 1`] = ` -"import { createVNode, openBlock, createBlock } from \\"vue\\" +"import { createVNode, createBlock, openBlock } from \\"vue\\" export default function render() { const _ctx = this @@ -86,7 +86,7 @@ exports[`compiler: transform v-model with dynamic argument 1`] = ` return function render() { with (this) { - const { createVNode: _createVNode, openBlock: _openBlock, createBlock: _createBlock } = _Vue + const { createVNode: _createVNode, createBlock: _createBlock, openBlock: _openBlock } = _Vue return (_openBlock(), _createBlock(\\"input\\", { [value]: model, From 3cd61588926d49ec31d4da42a0e9118eeffad31a Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Wed, 9 Oct 2019 01:24:33 +0530 Subject: [PATCH 6/8] fix: update directive transform signature --- packages/compiler-core/src/transforms/vModel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index 9e2bfa4016f..91a4b0d8e9f 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -9,7 +9,7 @@ import { import { createCompilerError, ErrorCodes } from '../errors' import { isEmptyExpression } from '../utils' -export const transformModel: DirectiveTransform = (dir, context) => { +export const transformModel: DirectiveTransform = (dir, node, context) => { const { exp, arg } = dir if (!exp) { context.onError(createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION)) From 46ce67f6b36ceb5be9a7f810c282dec23cdb0ddc Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Thu, 10 Oct 2019 08:07:49 +0530 Subject: [PATCH 7/8] chore: Add blank lines between specs --- packages/compiler-core/__tests__/transforms/vModel.spec.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/compiler-core/__tests__/transforms/vModel.spec.ts b/packages/compiler-core/__tests__/transforms/vModel.spec.ts index a157b17f0f9..818076a5092 100644 --- a/packages/compiler-core/__tests__/transforms/vModel.spec.ts +++ b/packages/compiler-core/__tests__/transforms/vModel.spec.ts @@ -64,6 +64,7 @@ describe('compiler: transform v-model', () => { expect(generate(root).code).toMatchSnapshot() }) + test('simple exprssion (with prefixIdentifiers)', () => { const root = parseWithVModel('', { prefixIdentifiers: true @@ -102,6 +103,7 @@ describe('compiler: transform v-model', () => { expect(generate(root, { mode: 'module' }).code).toMatchSnapshot() }) + test('compound expression', () => { const root = parseWithVModel('') const node = root.children[0] as ElementNode @@ -193,6 +195,7 @@ describe('compiler: transform v-model', () => { expect(generate(root, { mode: 'module' }).code).toMatchSnapshot() }) + test('with argument', () => { const root = parseWithVModel('') const node = root.children[0] as ElementNode @@ -229,6 +232,7 @@ describe('compiler: transform v-model', () => { expect(generate(root).code).toMatchSnapshot() }) + test('with dynamic argument', () => { const root = parseWithVModel('') const node = root.children[0] as ElementNode @@ -274,6 +278,7 @@ describe('compiler: transform v-model', () => { expect(generate(root).code).toMatchSnapshot() }) + test('with dynamic argument (with prefixIdentifiers)', () => { const root = parseWithVModel('', { prefixIdentifiers: true From 8794a4ff61d9fd06a81f69d36ed9da8890c9f592 Mon Sep 17 00:00:00 2001 From: Rahul Kadyan Date: Thu, 10 Oct 2019 08:08:20 +0530 Subject: [PATCH 8/8] refactor: inline default values and remove unnecessary if/else --- .../compiler-core/src/transforms/vModel.ts | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/compiler-core/src/transforms/vModel.ts b/packages/compiler-core/src/transforms/vModel.ts index 91a4b0d8e9f..3be84226932 100644 --- a/packages/compiler-core/src/transforms/vModel.ts +++ b/packages/compiler-core/src/transforms/vModel.ts @@ -15,38 +15,38 @@ export const transformModel: DirectiveTransform = (dir, node, context) => { context.onError(createCompilerError(ErrorCodes.X_V_MODEL_NO_EXPRESSION)) return createTransformProps() - } else if (isEmptyExpression(exp)) { + } + + if (isEmptyExpression(exp)) { context.onError( createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION) ) return createTransformProps() - } else { - const defaultPropName = createSimpleExpression('modelValue', true) - const defaultEventName = createSimpleExpression('onUpdate:modelValue', true) - const propName = arg ? arg : defaultPropName - const eventName = arg - ? arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic - ? createSimpleExpression('onUpdate:' + arg.content, true) - : createCompoundExpression([ - createSimpleExpression('onUpdate:', true), - '+', - ...(arg.type === NodeTypes.SIMPLE_EXPRESSION ? [arg] : arg.children) - ]) - : defaultEventName + } - return createTransformProps([ - createObjectProperty(propName, dir.exp!), - createObjectProperty( - eventName, - createCompoundExpression([ - `$event => (`, - ...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children), - ` = $event)` + const propName = arg ? arg : createSimpleExpression('modelValue', true) + const eventName = arg + ? arg.type === NodeTypes.SIMPLE_EXPRESSION && arg.isStatic + ? createSimpleExpression('onUpdate:' + arg.content, true) + : createCompoundExpression([ + createSimpleExpression('onUpdate:', true), + '+', + ...(arg.type === NodeTypes.SIMPLE_EXPRESSION ? [arg] : arg.children) ]) - ) - ]) - } + : createSimpleExpression('onUpdate:modelValue', true) + + return createTransformProps([ + createObjectProperty(propName, dir.exp!), + createObjectProperty( + eventName, + createCompoundExpression([ + `$event => (`, + ...(exp.type === NodeTypes.SIMPLE_EXPRESSION ? [exp] : exp.children), + ` = $event)` + ]) + ) + ]) } function createTransformProps(props: Property[] = []) {