]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compiler-sfc): check binding is prop before erroring
authorEvan You <yyx990803@gmail.com>
Tue, 4 Apr 2023 10:10:13 +0000 (18:10 +0800)
committerEvan You <yyx990803@gmail.com>
Tue, 4 Apr 2023 10:10:13 +0000 (18:10 +0800)
fix #8017

packages/compiler-sfc/__tests__/compileScriptPropsDestructure.spec.ts
packages/compiler-sfc/src/compileScriptPropsDestructure.ts

index 8487270c265f4da8ba7a0075df1b8cb53236ad67..193b3e5a1af589d54e8d6763ebc093de5e966fe8 100644 (file)
@@ -354,5 +354,20 @@ describe('sfc props transform', () => {
         )
       ).toThrow(`Default value of prop "foo" does not match declared type.`)
     })
+
+    // #8017
+    test('should not throw an error if the variable is not a props', () => {
+      expect(() =>
+        compile(
+          `<script setup lang='ts'>
+        import { watch } from 'vue'
+        const { userId } = defineProps({ userId: Number })
+        const { error: e, info } = useRequest();
+        watch(e, () => {});
+        watch(info, () => {});
+        </script>`
+        )
+      ).not.toThrowError()
+    })
   })
 })
index 4ee09070d76d306c355b0bd8e04701a2c51892ce..d0addf6fcbce7e916499e66638dd85d338236f9d 100644 (file)
@@ -17,7 +17,7 @@ import {
   isCallOf,
   unwrapTSNode
 } from '@vue/compiler-core'
-import { hasOwn, genPropsAccessExp } from '@vue/shared'
+import { genPropsAccessExp } from '@vue/shared'
 import { PropsDestructureBindings } from './compileScript'
 
 /**
@@ -47,6 +47,15 @@ export function transformDestructuredProps(
     propsLocalToPublicMap[local] = key
   }
 
+  function pushScope() {
+    scopeStack.push((currentScope = Object.create(currentScope)))
+  }
+
+  function popScope() {
+    scopeStack.pop()
+    currentScope = scopeStack[scopeStack.length - 1] || null
+  }
+
   function registerLocalBinding(id: Identifier) {
     excludedIds.add(id)
     if (currentScope) {
@@ -108,54 +117,41 @@ export function transformDestructuredProps(
     }
   }
 
-  function rewriteId(
-    scope: Scope,
-    id: Identifier,
-    parent: Node,
-    parentStack: Node[]
-  ): boolean {
-    if (hasOwn(scope, id.name)) {
-      const binding = scope[id.name]
-
-      if (binding) {
-        if (
-          (parent.type === 'AssignmentExpression' && id === parent.left) ||
-          parent.type === 'UpdateExpression'
-        ) {
-          error(`Cannot assign to destructured props as they are readonly.`, id)
-        }
+  function rewriteId(id: Identifier, parent: Node, parentStack: Node[]) {
+    if (
+      (parent.type === 'AssignmentExpression' && id === parent.left) ||
+      parent.type === 'UpdateExpression'
+    ) {
+      error(`Cannot assign to destructured props as they are readonly.`, id)
+    }
 
-        if (isStaticProperty(parent) && parent.shorthand) {
-          // let binding used in a property shorthand
-          // skip for destructure patterns
-          if (
-            !(parent as any).inPattern ||
-            isInDestructureAssignment(parent, parentStack)
-          ) {
-            // { prop } -> { prop: __props.prop }
-            s.appendLeft(
-              id.end! + offset,
-              `: ${genPropsAccessExp(propsLocalToPublicMap[id.name])}`
-            )
-          }
-        } else {
-          // x --> __props.x
-          s.overwrite(
-            id.start! + offset,
-            id.end! + offset,
-            genPropsAccessExp(propsLocalToPublicMap[id.name])
-          )
-        }
+    if (isStaticProperty(parent) && parent.shorthand) {
+      // let binding used in a property shorthand
+      // skip for destructure patterns
+      if (
+        !(parent as any).inPattern ||
+        isInDestructureAssignment(parent, parentStack)
+      ) {
+        // { prop } -> { prop: __props.prop }
+        s.appendLeft(
+          id.end! + offset,
+          `: ${genPropsAccessExp(propsLocalToPublicMap[id.name])}`
+        )
       }
-      return true
+    } else {
+      // x --> __props.x
+      s.overwrite(
+        id.start! + offset,
+        id.end! + offset,
+        genPropsAccessExp(propsLocalToPublicMap[id.name])
+      )
     }
-    return false
   }
 
   function checkUsage(node: Node, method: string, alias = method) {
     if (isCallOf(node, alias)) {
       const arg = unwrapTSNode(node.arguments[0])
-      if (arg.type === 'Identifier') {
+      if (arg.type === 'Identifier' && currentScope[arg.name]) {
         error(
           `"${arg.name}" is a destructured prop and should not be passed directly to ${method}(). ` +
             `Pass a getter () => ${arg.name} instead.`,
@@ -187,7 +183,7 @@ export function transformDestructuredProps(
 
       // function scopes
       if (isFunctionType(node)) {
-        scopeStack.push((currentScope = {}))
+        pushScope()
         walkFunctionParams(node, registerLocalBinding)
         if (node.body.type === 'BlockStatement') {
           walkScope(node.body)
@@ -197,7 +193,7 @@ export function transformDestructuredProps(
 
       // catch param
       if (node.type === 'CatchClause') {
-        scopeStack.push((currentScope = {}))
+        pushScope()
         if (node.param && node.param.type === 'Identifier') {
           registerLocalBinding(node.param)
         }
@@ -207,7 +203,7 @@ export function transformDestructuredProps(
 
       // non-function block scopes
       if (node.type === 'BlockStatement' && !isFunctionType(parent!)) {
-        scopeStack.push((currentScope = {}))
+        pushScope()
         walkScope(node)
         return
       }
@@ -217,12 +213,8 @@ export function transformDestructuredProps(
           isReferencedIdentifier(node, parent!, parentStack) &&
           !excludedIds.has(node)
         ) {
-          // walk up the scope chain to check if id should be appended .value
-          let i = scopeStack.length
-          while (i--) {
-            if (rewriteId(scopeStack[i], node, parent!, parentStack)) {
-              return
-            }
+          if (currentScope[node.name]) {
+            rewriteId(node, parent!, parentStack)
           }
         }
       }
@@ -233,8 +225,7 @@ export function transformDestructuredProps(
         (node.type === 'BlockStatement' && !isFunctionType(parent!)) ||
         isFunctionType(node)
       ) {
-        scopeStack.pop()
-        currentScope = scopeStack[scopeStack.length - 1] || null
+        popScope()
       }
     }
   })