From c60479146aad8c0c33a6e4be186b1cff45bd1871 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 12 Jan 2024 22:06:46 +0800 Subject: [PATCH] dx(defineModel): warn against reference of setup scope variables in defineModel options close #10093 --- packages/compiler-core/src/babelUtils.ts | 2 +- .../__tests__/compileScript.spec.ts | 32 +++++++++++++++++++ packages/compiler-sfc/src/compileScript.ts | 5 +++ .../compiler-sfc/src/script/defineModel.ts | 5 +++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/packages/compiler-core/src/babelUtils.ts b/packages/compiler-core/src/babelUtils.ts index 0a7f48af9..b12a6d9b4 100644 --- a/packages/compiler-core/src/babelUtils.ts +++ b/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 diff --git a/packages/compiler-sfc/__tests__/compileScript.spec.ts b/packages/compiler-sfc/__tests__/compileScript.spec.ts index 7c21816eb..2b9acbc7f 100644 --- a/packages/compiler-sfc/__tests__/compileScript.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript.spec.ts @@ -953,6 +953,38 @@ describe('SFC compile `).content, ) }) + + test('defineModel() referencing local var', () => { + expect(() => + compile(``), + ).toThrow(`cannot reference locally declared variables`) + + // allow const + expect(() => + compile(``), + ).not.toThrow(`cannot reference locally declared variables`) + + // allow in get/set + expect(() => + compile(``), + ).not.toThrow(`cannot reference locally declared variables`) + }) }) }) diff --git a/packages/compiler-sfc/src/compileScript.ts b/packages/compiler-sfc/src/compileScript.ts index b0b79f8c8..69beb2af7 100644 --- a/packages/compiler-sfc/src/compileScript.ts +++ b/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) { diff --git a/packages/compiler-sfc/src/script/defineModel.ts b/packages/compiler-sfc/src/script/defineModel.ts index b94b79946..24fd0780e 100644 --- a/packages/compiler-sfc/src/script/defineModel.ts +++ b/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, }