]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(reactivity-transform): fix props access codegen for non-identifier prop names...
authoredison <daiwei521@126.com>
Fri, 13 May 2022 02:38:46 +0000 (10:38 +0800)
committerGitHub <noreply@github.com>
Fri, 13 May 2022 02:38:46 +0000 (22:38 -0400)
fix #5425

packages/compiler-core/src/transforms/transformExpression.ts
packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap
packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts
packages/compiler-sfc/src/compileScript.ts
packages/reactivity-transform/src/reactivityTransform.ts
packages/shared/src/index.ts

index a3a48be61835e0bf178fc85aeb2c03edb5635e76..e4311ad4f880f3a6aa6a15da1b1678a071a212a6 100644 (file)
@@ -24,7 +24,13 @@ import {
   walkIdentifiers
 } from '../babelUtils'
 import { advancePositionWithClone, isSimpleIdentifier } from '../utils'
-import { isGloballyWhitelisted, makeMap, hasOwn, isString } from '@vue/shared'
+import {
+  isGloballyWhitelisted,
+  makeMap,
+  hasOwn,
+  isString,
+  genPropsAccessExp
+} from '@vue/shared'
 import { createCompilerError, ErrorCodes } from '../errors'
 import {
   Node,
@@ -185,17 +191,17 @@ export function processExpression(
       } else if (type === BindingTypes.PROPS) {
         // use __props which is generated by compileScript so in ts mode
         // it gets correct type
-        return `__props.${raw}`
+        return genPropsAccessExp(raw)
       } else if (type === BindingTypes.PROPS_ALIASED) {
         // prop with a different local alias (from defineProps() destructure)
-        return `__props.${bindingMetadata.__propsAliases![raw]}`
+        return genPropsAccessExp(bindingMetadata.__propsAliases![raw])
       }
     } else {
       if (type && type.startsWith('setup')) {
         // setup bindings in non-inline mode
         return `$setup.${raw}`
       } else if (type === BindingTypes.PROPS_ALIASED) {
-        return `$props.${bindingMetadata.__propsAliases![raw]}`
+        return `$props['${bindingMetadata.__propsAliases![raw]}']`
       } else if (type) {
         return `$${type}.${raw}`
       }
index 8a7359420bb799adf3676f8a8ad63a742d8c5e25..cfde6700dba94e5b48770dd6b7e3a55b6800a4b7 100644 (file)
@@ -134,6 +134,25 @@ return () => {}
 }"
 `;
 
+exports[`sfc props transform non-identifier prop names 1`] = `
+"import { toDisplayString as _toDisplayString } from \\"vue\\"
+
+
+export default {
+  props: { 'foo.bar': Function },
+  setup(__props) {
+
+      
+      let x = __props[\\"foo.bar\\"]
+      
+return (_ctx, _cache) => {
+  return _toDisplayString(__props[\\"foo.bar\\"])
+}
+}
+
+}"
+`;
+
 exports[`sfc props transform rest spread 1`] = `
 "import { createPropsRestProxy as _createPropsRestProxy } from 'vue'
 
index 0dafc0200dd77ee21102b1a57b5efd1267a28a31..25fb4bed2800cf64076b5731229be9cb2b6d75fb 100644 (file)
@@ -127,6 +127,28 @@ describe('sfc props transform', () => {
     })
   })
 
+  // #5425
+  test('non-identifier prop names', () => {
+    const { content, bindings } = compile(`
+      <script setup>
+      const { 'foo.bar': fooBar } = defineProps({ 'foo.bar': Function })
+      let x = fooBar
+      </script>
+      <template>{{ fooBar }}</template>
+    `)
+    expect(content).toMatch(`x = __props["foo.bar"]`)
+    expect(content).toMatch(`toDisplayString(__props["foo.bar"])`)
+    assertCode(content)
+    expect(bindings).toStrictEqual({
+      x: BindingTypes.SETUP_LET,
+      'foo.bar': BindingTypes.PROPS,
+      fooBar: BindingTypes.PROPS_ALIASED,
+      __propsAliases: {
+        fooBar: 'foo.bar'
+      }
+    })
+  })
+
   test('rest spread', () => {
     const { content, bindings } = compile(`
       <script setup>
index ed993521fc52a7111e205a9218ebceaa49c062bd..d3edd9fac411cf1d8c65337be8c3320f6ae25cec 100644 (file)
@@ -431,7 +431,11 @@ export function compileScript(
                 prop.key
               )
             }
-            const propKey = (prop.key as Identifier).name
+            
+            const propKey = prop.key.type === 'StringLiteral'
+              ? prop.key.value
+              : (prop.key as Identifier).name
+            
             if (prop.value.type === 'AssignmentPattern') {
               // default value { foo = 123 }
               const { left, right } = prop.value
index 809e3e4e246b2b6205f90de8199bb8c8dbf1ca3c..34d537d221becd5f8d24e16f8595c256a7f67a24 100644 (file)
@@ -21,7 +21,7 @@ import {
   walkFunctionParams
 } from '@vue/compiler-core'
 import { parse, ParserPlugin } from '@babel/parser'
-import { hasOwn, isArray, isString } from '@vue/shared'
+import { hasOwn, isArray, isString, genPropsAccessExp } from '@vue/shared'
 
 const CONVERT_SYMBOL = '$'
 const ESCAPE_SYMBOL = '$$'
@@ -489,17 +489,17 @@ export function transformAST(
             if (isProp) {
               if (escapeScope) {
                 // prop binding in $$()
-                // { prop } -> { prop: __prop_prop }
+                // { prop } -> { prop: __props_prop }
                 registerEscapedPropBinding(id)
                 s.appendLeft(
                   id.end! + offset,
                   `: __props_${propsLocalToPublicMap[id.name]}`
                 )
               } else {
-                // { prop } -> { prop: __prop.prop }
+                // { prop } -> { prop: __props.prop }
                 s.appendLeft(
                   id.end! + offset,
-                  `: __props.${propsLocalToPublicMap[id.name]}`
+                  `: ${genPropsAccessExp(propsLocalToPublicMap[id.name])}`
                 )
               }
             } else {
@@ -522,7 +522,7 @@ export function transformAST(
               s.overwrite(
                 id.start! + offset,
                 id.end! + offset,
-                `__props.${propsLocalToPublicMap[id.name]}`
+                genPropsAccessExp(propsLocalToPublicMap[id.name])
               )
             }
           } else {
index e47cb5cd673d28256b06b5fbb0b242f961df7264..63aa9a37c2aa61f60ccf9afb9cec94af9fb3536d 100644 (file)
@@ -171,3 +171,11 @@ export const getGlobalThis = (): any => {
         : {})
   )
 }
+
+const identRE = /^[_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*$/
+
+export function genPropsAccessExp(name: string) {
+  return identRE.test(name)
+    ? `__props.${name}`
+    : `__props[${JSON.stringify(name)}]`
+}