Преглед изворни кода

fix(compiler-core): allow multiline expression on v-model and v-on (#1234)

Carlos Rodrigues пре 5 година
родитељ
комит
958b6c80cf

+ 19 - 0
packages/compiler-core/__tests__/transforms/__snapshots__/vModel.spec.ts.snap

@@ -26,6 +26,25 @@ return function render(_ctx, _cache) {
 }"
 `;
 
+exports[`compiler: transform v-model simple expression (with multilines) 1`] = `
+"const _Vue = Vue
+
+return function render(_ctx, _cache) {
+  with (_ctx) {
+    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 simple expression (with prefixIdentifiers) 1`] = `
 "import { createVNode as _createVNode, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
 

+ 37 - 0
packages/compiler-core/__tests__/transforms/vModel.spec.ts

@@ -115,6 +115,43 @@ describe('compiler: transform v-model', () => {
     expect(generate(root, { mode: 'module' }).code).toMatchSnapshot()
   })
 
+  test('simple expression (with multilines)', () => {
+    const root = parseWithVModel('<input v-model="\n model \n" />')
+    const node = root.children[0] as ElementNode
+    const props = ((node.codegenNode as VNodeCall).props as ObjectExpression)
+      .properties
+
+    expect(props[0]).toMatchObject({
+      key: {
+        content: 'modelValue',
+        isStatic: true
+      },
+      value: {
+        content: '\n model \n',
+        isStatic: false
+      }
+    })
+
+    expect(props[1]).toMatchObject({
+      key: {
+        content: 'onUpdate:modelValue',
+        isStatic: true
+      },
+      value: {
+        children: [
+          '$event => (',
+          {
+            content: '\n model \n',
+            isStatic: false
+          },
+          ' = $event)'
+        ]
+      }
+    })
+
+    expect(generate(root).code).toMatchSnapshot()
+  })
+
   test('compound expression', () => {
     const root = parseWithVModel('<input v-model="model[index]" />')
     const node = root.children[0] as ElementNode

+ 18 - 0
packages/compiler-core/__tests__/transforms/vOn.spec.ts

@@ -167,6 +167,24 @@ describe('compiler: transform v-on', () => {
     })
   })
 
+  test('should handle multiple line statement', () => {
+    const { node } = parseWithVOn(`<div @click="\nfoo();\nbar()\n"/>`)
+    expect((node.codegenNode as VNodeCall).props).toMatchObject({
+      properties: [
+        {
+          key: { content: `onClick` },
+          value: {
+            type: NodeTypes.COMPOUND_EXPRESSION,
+            // should wrap with `{` for multiple statements
+            // in this case the return value is discarded and the behavior is
+            // consistent with 2.x
+            children: [`$event => {`, { content: `\nfoo();\nbar()\n` }, `}`]
+          }
+        }
+      ]
+    })
+  })
+
   test('inline statement w/ prefixIdentifiers: true', () => {
     const { node } = parseWithVOn(`<div @click="foo($event)"/>`, {
       prefixIdentifiers: true

+ 1 - 0
packages/compiler-core/src/transforms/vModel.ts

@@ -21,6 +21,7 @@ export const transformModel: DirectiveTransform = (dir, node, context) => {
 
   const expString =
     exp.type === NodeTypes.SIMPLE_EXPRESSION ? exp.content : exp.loc.source
+
   if (!isMemberExpression(expString)) {
     context.onError(
       createCompilerError(ErrorCodes.X_V_MODEL_MALFORMED_EXPRESSION, exp.loc)

+ 4 - 2
packages/compiler-core/src/utils.ts

@@ -84,8 +84,10 @@ export const isSimpleIdentifier = (name: string): boolean =>
   !nonIdentifierRE.test(name)
 
 const memberExpRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\[[^\]]+\])*$/
-export const isMemberExpression = (path: string): boolean =>
-  memberExpRE.test(path)
+export const isMemberExpression = (path: string): boolean => {
+  if (!path) return false
+  return memberExpRE.test(path.trim())
+}
 
 export function getInnerRange(
   loc: SourceLocation,