__expose();
const modelValue = _useModel(__props, "modelValue")
- const c = _useModel(__props, "count")
- const toString = _useModel(__props, "toString")
+ const c = _useModel(__props, 'count')
+ const toString = _useModel(__props, 'toString')
return { modelValue, c, toString }
}
setup(__props, { expose: __expose }) {
__expose();
- const modelValue = _useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })
+ const modelValue = _useModel(__props, "modelValue", {
+ get(v) { return v - 1 },
+ set: (v) => { return v + 1 },
+ })
return { modelValue }
}
setup(__props, { expose: __expose }) {
__expose();
- const modelValue = _useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })
+ const modelValue = _useModel(__props, "modelValue", {
+ get(v) { return v - 1 },
+ set: (v) => { return v + 1 },
+ })
+
+return { modelValue }
+}
+
+})"
+`;
+
+exports[`defineModel() > usage w/ props destructure 1`] = `
+"import { useModel as _useModel, mergeModels as _mergeModels, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: /*#__PURE__*/_mergeModels({
+ x: { type: Number, required: true }
+ }, {
+ "modelValue": {
+ },
+ "modelModifiers": {},
+ }),
+ emits: ["update:modelValue"],
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+ const modelValue = _useModel(__props, "modelValue", {
+ set: (v) => { return v + __props.x }
+ })
return { modelValue }
}
__expose();
- const count = _useModel(__props, "count")
+ const count = _useModel(__props, 'count')
return { count }
}
setup(__props, { expose: __expose }) {
__expose();
- const modelValue = _useModel(__props, "modelValue")
- const count = _useModel(__props, "count")
- const disabled = _useModel(__props, "disabled")
- const any = _useModel(__props, "any")
+ const modelValue = _useModel<boolean | string>(__props, "modelValue")
+ const count = _useModel<number>(__props, 'count')
+ const disabled = _useModel<number>(__props, 'disabled')
+ const any = _useModel<any | boolean>(__props, 'any')
return { modelValue, count, disabled, any }
}
setup(__props, { expose: __expose }) {
__expose();
- const modelValue = _useModel(__props, "modelValue")
- const fn = _useModel(__props, "fn")
- const fnWithDefault = _useModel(__props, "fnWithDefault")
- const str = _useModel(__props, "str")
- const optional = _useModel(__props, "optional")
+ const modelValue = _useModel<boolean>(__props, "modelValue")
+ const fn = _useModel<() => void>(__props, 'fn')
+ const fnWithDefault = _useModel<() => void>(__props, 'fnWithDefault')
+ const str = _useModel<string>(__props, 'str')
+ const optional = _useModel<string>(__props, 'optional')
return { modelValue, fn, fnWithDefault, str, optional }
}
expect(content).toMatch(
`const modelValue = _useModel(__props, "modelValue")`,
)
- expect(content).toMatch(`const c = _useModel(__props, "count")`)
+ expect(content).toMatch(`const c = _useModel(__props, 'count')`)
+ expect(content).toMatch(`const toString = _useModel(__props, 'toString')`)
expect(content).toMatch(`return { modelValue, c, toString }`)
expect(content).not.toMatch('defineModel')
"count": {},
"countModifiers": {},
})`)
- expect(content).toMatch(`const count = _useModel(__props, "count")`)
+ expect(content).toMatch(`const count = _useModel(__props, 'count')`)
expect(content).not.toMatch('defineModel')
expect(bindings).toStrictEqual({
foo: BindingTypes.PROPS,
)
expect(content).toMatch(
- `const modelValue = _useModel(__props, "modelValue")`,
+ `const modelValue = _useModel<boolean | string>(__props, "modelValue")`,
+ )
+ expect(content).toMatch(`const count = _useModel<number>(__props, 'count')`)
+ expect(content).toMatch(
+ `const disabled = _useModel<number>(__props, 'disabled')`,
+ )
+ expect(content).toMatch(
+ `const any = _useModel<any | boolean>(__props, 'any')`,
)
- expect(content).toMatch(`const count = _useModel(__props, "count")`)
- expect(content).toMatch(`const disabled = _useModel(__props, "disabled")`)
- expect(content).toMatch(`const any = _useModel(__props, "any")`)
expect(bindings).toStrictEqual({
modelValue: BindingTypes.SETUP_REF,
'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]',
)
expect(content).toMatch(
- `const modelValue = _useModel(__props, "modelValue")`,
+ `const modelValue = _useModel<boolean>(__props, "modelValue")`,
)
- expect(content).toMatch(`const fn = _useModel(__props, "fn")`)
- expect(content).toMatch(`const str = _useModel(__props, "str")`)
+ expect(content).toMatch(`const fn = _useModel<() => void>(__props, 'fn')`)
+ expect(content).toMatch(`const str = _useModel<string>(__props, 'str')`)
expect(bindings).toStrictEqual({
modelValue: BindingTypes.SETUP_REF,
fn: BindingTypes.SETUP_REF,
assertCode(content)
expect(content).toMatch(/"modelValue": {\s+required: true,?\s+}/m)
expect(content).toMatch(
- `_useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })`,
+ `_useModel(__props, "modelValue", {
+ get(v) { return v - 1 },
+ set: (v) => { return v + 1 },
+ })`,
)
const { content: content2 } = compile(
/"modelValue": {\s+default: 0,\s+required: true,?\s+}/m,
)
expect(content2).toMatch(
- `_useModel(__props, "modelValue", { get(v) { return v - 1 }, set: (v) => { return v + 1 }, })`,
+ `_useModel(__props, "modelValue", {
+ get(v) { return v - 1 },
+ set: (v) => { return v + 1 },
+ })`,
)
})
+
+ test('usage w/ props destructure', () => {
+ const { content } = compile(
+ `
+ <script setup lang="ts">
+ const { x } = defineProps<{ x: number }>()
+ const modelValue = defineModel({
+ set: (v) => { return v + x }
+ })
+ </script>
+ `,
+ { propsDestructure: true },
+ )
+ assertCode(content)
+ expect(content).toMatch(`set: (v) => { return v + __props.x }`)
+ })
})
let modelName: string
let options: Node | undefined
const arg0 = node.arguments[0] && unwrapTSNode(node.arguments[0])
- if (arg0 && arg0.type === 'StringLiteral') {
+ const hasName = arg0 && arg0.type === 'StringLiteral'
+ if (hasName) {
modelName = arg0.value
options = node.arguments[1]
} else {
}
let optionsString = options && ctx.getString(options)
- let runtimeOptions = ''
- let transformOptions = ''
-
- if (options) {
- if (options.type === 'ObjectExpression') {
- for (let i = options.properties.length - 1; i >= 0; i--) {
- const p = options.properties[i]
- if (p.type === 'SpreadElement' || p.computed) {
- runtimeOptions = optionsString!
- break
- }
- if (
- (p.type === 'ObjectProperty' || p.type === 'ObjectMethod') &&
- ((p.key.type === 'Identifier' &&
- (p.key.name === 'get' || p.key.name === 'set')) ||
- (p.key.type === 'StringLiteral' &&
- (p.key.value === 'get' || p.key.value === 'set')))
- ) {
- transformOptions = ctx.getString(p) + ', ' + transformOptions
-
- // remove transform option from prop options to avoid duplicates
- const offset = p.start! - options.start!
- const next = options.properties[i + 1]
- const end = (next ? next.start! : options.end! - 1) - options.start!
- optionsString =
- optionsString.slice(0, offset) + optionsString.slice(end)
- }
+ let optionsRemoved = !options
+
+ if (
+ options &&
+ options.type === 'ObjectExpression' &&
+ !options.properties.some(p => p.type === 'SpreadElement' || p.computed)
+ ) {
+ let removed = 0
+ for (let i = options.properties.length - 1; i >= 0; i--) {
+ const p = options.properties[i]
+ const next = options.properties[i + 1]
+ const start = p.start!
+ const end = next ? next.start! : options.end! - 1
+ if (
+ (p.type === 'ObjectProperty' || p.type === 'ObjectMethod') &&
+ ((p.key.type === 'Identifier' &&
+ (p.key.name === 'get' || p.key.name === 'set')) ||
+ (p.key.type === 'StringLiteral' &&
+ (p.key.value === 'get' || p.key.value === 'set')))
+ ) {
+ // remove runtime-only options from prop options to avoid duplicates
+ optionsString =
+ optionsString.slice(0, start - options.start!) +
+ optionsString.slice(end - options.start!)
+ } else {
+ // remove prop options from runtime options
+ removed++
+ ctx.s.remove(ctx.startOffset! + start, ctx.startOffset! + end)
}
- if (!runtimeOptions && transformOptions) {
- runtimeOptions = `{ ${transformOptions} }`
- }
- } else {
- runtimeOptions = optionsString!
+ }
+ if (removed === options.properties.length) {
+ optionsRemoved = true
+ ctx.s.remove(
+ ctx.startOffset! + (hasName ? arg0.end! : options.start!),
+ ctx.startOffset! + options.end!,
+ )
}
}
// register binding type
ctx.bindingMetadata[modelName] = BindingTypes.PROPS
+ // defineModel -> useModel
ctx.s.overwrite(
- ctx.startOffset! + node.start!,
- ctx.startOffset! + node.end!,
- `${ctx.helper('useModel')}(__props, ${JSON.stringify(modelName)}${
- runtimeOptions ? `, ${runtimeOptions}` : ``
- })`,
+ ctx.startOffset! + node.callee.start!,
+ ctx.startOffset! + node.callee.end!,
+ ctx.helper('useModel'),
+ )
+ // inject arguments
+ ctx.s.appendLeft(
+ ctx.startOffset! +
+ (node.arguments.length ? node.arguments[0].start! : node.end! - 1),
+ `__props, ` +
+ (hasName
+ ? ``
+ : `${JSON.stringify(modelName)}${optionsRemoved ? `` : `, `}`),
)
return true