Skip to content

Commit bd7eef0

Browse files
authored
fix(compiler-sfc): support template literal as defineModel name (#14622)
close #14621
1 parent 862f11e commit bd7eef0

3 files changed

Lines changed: 87 additions & 2 deletions

File tree

packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineModel.spec.ts.snap

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,50 @@ return { count }
166166
}"
167167
`;
168168

169+
exports[`defineModel() > w/ template literal name 1`] = `
170+
"import { useModel as _useModel } from 'vue'
171+
172+
export default {
173+
props: {
174+
"x": { default: 100 },
175+
"xModifiers": {},
176+
"y": { default: 200 },
177+
"yModifiers": {},
178+
},
179+
emits: ["update:x", "update:y"],
180+
setup(__props, { expose: __expose }) {
181+
__expose();
182+
183+
const x = _useModel(__props, \`x\`)
184+
const y = _useModel(__props, \`y\`)
185+
186+
return { x, y }
187+
}
188+
189+
}"
190+
`;
191+
192+
exports[`defineModel() > w/ template literal name with expressions falls back to modelValue 1`] = `
193+
"import { useModel as _useModel } from 'vue'
194+
const name = 'x'
195+
196+
export default {
197+
props: {
198+
"modelValue": \`\${name}\`,
199+
"modelModifiers": {},
200+
},
201+
emits: ["update:modelValue"],
202+
setup(__props, { expose: __expose }) {
203+
__expose();
204+
205+
const m = _useModel(__props, "modelValue", \`\${name}\`)
206+
207+
return { name, m }
208+
}
209+
210+
}"
211+
`;
212+
169213
exports[`defineModel() > w/ types, basic usage 1`] = `
170214
"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
171215

packages/compiler-sfc/__tests__/compileScript/defineModel.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,43 @@ describe('defineModel()', () => {
3636
})
3737
})
3838

39+
test('w/ template literal name', () => {
40+
const { content, bindings } = compile(
41+
`
42+
<script setup>
43+
const x = defineModel(\`x\`, { default: 100 })
44+
const y = defineModel(\`y\`, { default: 200 })
45+
</script>
46+
`,
47+
)
48+
assertCode(content)
49+
expect(content).toMatch('"x": { default: 100 },')
50+
expect(content).toMatch('"y": { default: 200 },')
51+
expect(content).toMatch('emits: ["update:x", "update:y"],')
52+
expect(content).toMatch('const x = _useModel(__props, `x`)')
53+
expect(content).toMatch('const y = _useModel(__props, `y`)')
54+
expect(content).not.toMatch('defineModel')
55+
56+
expect(bindings).toStrictEqual({
57+
x: BindingTypes.SETUP_REF,
58+
y: BindingTypes.SETUP_REF,
59+
})
60+
})
61+
62+
test('w/ template literal name with expressions falls back to modelValue', () => {
63+
const { content } = compile(
64+
`
65+
<script setup>
66+
const name = 'x'
67+
const m = defineModel(\`\${name}\`)
68+
</script>
69+
`,
70+
)
71+
assertCode(content)
72+
expect(content).toMatch('"modelValue":')
73+
expect(content).toMatch('_useModel(__props, "modelValue",')
74+
})
75+
3976
test('w/ defineProps and defineEmits', () => {
4077
const { content, bindings } = compile(
4178
`

packages/compiler-sfc/src/script/defineModel.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,13 @@ export function processDefineModel(
2929
let modelName: string
3030
let options: Node | undefined
3131
const arg0 = node.arguments[0] && unwrapTSNode(node.arguments[0])
32-
const hasName = arg0 && arg0.type === 'StringLiteral'
32+
const hasName =
33+
arg0 &&
34+
(arg0.type === 'StringLiteral' ||
35+
(arg0.type === 'TemplateLiteral' && arg0.expressions.length === 0))
3336
if (hasName) {
34-
modelName = arg0.value
37+
modelName =
38+
arg0.type === 'StringLiteral' ? arg0.value : arg0.quasis[0].value.cooked!
3539
options = node.arguments[1]
3640
} else {
3741
modelName = 'modelValue'

0 commit comments

Comments
 (0)