Просмотр исходного кода

dx(defineModel): warn against reference of setup scope variables in defineModel options

close #10093
Evan You 2 лет назад
Родитель
Сommit
c60479146a

+ 1 - 1
packages/compiler-core/src/babelUtils.ts

@@ -50,7 +50,7 @@ export function walkIdentifiers(
         }
       } else if (
         node.type === 'ObjectProperty' &&
-        parent!.type === 'ObjectPattern'
+        parent?.type === 'ObjectPattern'
       ) {
         // mark property in destructure pattern
         ;(node as any).inPattern = true

+ 32 - 0
packages/compiler-sfc/__tests__/compileScript.spec.ts

@@ -953,6 +953,38 @@ describe('SFC compile <script setup>', () => {
         </script>`).content,
       )
     })
+
+    test('defineModel() referencing local var', () => {
+      expect(() =>
+        compile(`<script setup>
+        let bar = 1
+        defineModel({
+          default: () => bar
+        })
+        </script>`),
+      ).toThrow(`cannot reference locally declared variables`)
+
+      // allow const
+      expect(() =>
+        compile(`<script setup>
+        const bar = 1
+        defineModel({
+          default: () => bar
+        })
+        </script>`),
+      ).not.toThrow(`cannot reference locally declared variables`)
+
+      // allow in get/set
+      expect(() =>
+        compile(`<script setup>
+        let bar = 1
+        defineModel({
+          get: () => bar,
+          set: () => bar
+        })
+        </script>`),
+      ).not.toThrow(`cannot reference locally declared variables`)
+    })
   })
 })
 

+ 5 - 0
packages/compiler-sfc/src/compileScript.ts

@@ -671,6 +671,11 @@ export function compileScript(
   checkInvalidScopeReference(ctx.propsDestructureDecl, DEFINE_PROPS)
   checkInvalidScopeReference(ctx.emitsRuntimeDecl, DEFINE_EMITS)
   checkInvalidScopeReference(ctx.optionsRuntimeDecl, DEFINE_OPTIONS)
+  for (const { runtimeOptionNodes } of Object.values(ctx.modelDecls)) {
+    for (const node of runtimeOptionNodes) {
+      checkInvalidScopeReference(node, DEFINE_MODEL)
+    }
+  }
 
   // 5. remove non-script content
   if (script) {

+ 5 - 0
packages/compiler-sfc/src/script/defineModel.ts

@@ -15,6 +15,7 @@ export interface ModelDecl {
   type: TSType | undefined
   options: string | undefined
   identifier: string | undefined
+  runtimeOptionNodes: Node[]
 }
 
 export function processDefineModel(
@@ -48,6 +49,7 @@ export function processDefineModel(
 
   let optionsString = options && ctx.getString(options)
   let optionsRemoved = !options
+  const runtimeOptionNodes: Node[] = []
 
   if (
     options &&
@@ -75,6 +77,8 @@ export function processDefineModel(
         // remove prop options from runtime options
         removed++
         ctx.s.remove(ctx.startOffset! + start, ctx.startOffset! + end)
+        // record prop options for invalid scope var reference check
+        runtimeOptionNodes.push(p)
       }
     }
     if (removed === options.properties.length) {
@@ -89,6 +93,7 @@ export function processDefineModel(
   ctx.modelDecls[modelName] = {
     type,
     options: optionsString,
+    runtimeOptionNodes,
     identifier:
       declId && declId.type === 'Identifier' ? declId.name : undefined,
   }