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

close #10093
This commit is contained in:
Evan You 2024-01-12 22:06:46 +08:00
parent d35b87725a
commit c60479146a
4 changed files with 43 additions and 1 deletions

View File

@ -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

View File

@ -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`)
})
})
})

View File

@ -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) {

View File

@ -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,
}