Skip to content

Commit

Permalink
feat: add model option
Browse files Browse the repository at this point in the history
  • Loading branch information
sxzz committed Apr 5, 2023
1 parent 75f3a47 commit 69da94c
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 101 deletions.
Expand Up @@ -658,8 +658,8 @@ exports[`SFC compile <script setup> > defineModel() > basic usage 1`] = `

export default {
props: {
\\"modelValue\\": Object.assign({ required: true }, { required: true }),
\\"count\\": { required: true },
\\"modelValue\\": Object.assign({ model: true }, { required: true }),
\\"count\\": { model: true },
},
emits: [\\"update:modelValue\\", \\"update:count\\"],
setup(__props, { expose: __expose }) {
Expand All @@ -679,7 +679,7 @@ exports[`SFC compile <script setup> > defineModel() > w/ array props 1`] = `

export default {
props: _mergeModels(['foo', 'bar'], {
\\"count\\": { required: true },
\\"count\\": { model: true },
}),
emits: [\\"update:count\\"],
setup(__props, { expose: __expose }) {
Expand All @@ -699,7 +699,7 @@ exports[`SFC compile <script setup> > defineModel() > w/ defineProps and defineE

export default {
props: _mergeModels({ foo: String }, {
\\"modelValue\\": Object.assign({ required: true }, { default: 0 }),
\\"modelValue\\": Object.assign({ model: true }, { default: 0 }),
}),
emits: _mergeModels(['change'], [\\"update:modelValue\\"]),
setup(__props, { expose: __expose }) {
Expand Down Expand Up @@ -1647,9 +1647,9 @@ exports[`SFC compile <script setup> > with TypeScript > defineModel() > basic us

export default /*#__PURE__*/_defineComponent({
props: {
\\"modelValue\\": { type: [Boolean, String], required: true },
\\"count\\": { type: Number, required: true },
\\"disabled\\": { type: Number, required: true, ...{ required: false } },
\\"modelValue\\": { model: true, type: [Boolean, String] },
\\"count\\": { model: true, type: Number },
\\"disabled\\": { model: true, type: Number, ...{ required: false } },
},
emits: [\\"update:modelValue\\", \\"update:count\\", \\"update:disabled\\"],
setup(__props, { expose: __expose }) {
Expand All @@ -1671,10 +1671,10 @@ exports[`SFC compile <script setup> > with TypeScript > defineModel() > w/ produ
export default /*#__PURE__*/_defineComponent({
props: {
\\"modelValue\\": Boolean,
\\"fn\\": { },
\\"fnWithDefault\\": { type: Function, ...{ default: () => null } },
\\"str\\": { },
\\"optional\\": { required: false },
\\"fn\\": { model: true },
\\"fnWithDefault\\": { model: true, type: Function, ...{ default: () => null } },
\\"str\\": { model: true },
\\"optional\\": { model: true, ...{ required: false } },
},
emits: [\\"update:modelValue\\", \\"update:fn\\", \\"update:fnWithDefault\\", \\"update:str\\", \\"update:optional\\"],
setup(__props, { expose: __expose }) {
Expand Down Expand Up @@ -2054,10 +2054,10 @@ import { defaults } from './foo'

export default /*#__PURE__*/_defineComponent({
props: _mergeDefaults({
foo: { type: Function },
bar: { type: Boolean },
baz: { type: [Boolean, Function] },
qux: null
foo: { type: Function, required: true },
bar: { type: Boolean, required: true },
baz: { type: [Boolean, Function], required: true },
qux: { required: true }
}, { ...defaults }),
setup(__props: any, { expose: __expose }) {
__expose();
Expand Down Expand Up @@ -2159,10 +2159,10 @@ exports[`SFC compile <script setup> > with TypeScript > withDefaults (static) w/

export default /*#__PURE__*/_defineComponent({
props: {
foo: null,
bar: { type: Boolean },
baz: { type: [Boolean, Function], default: true },
qux: { default: 'hi' }
foo: { required: true },
bar: { type: Boolean, required: true },
baz: { type: [Boolean, Function], required: true, default: true },
qux: { required: true, default: 'hi' }
},
setup(__props: any, { expose: __expose }) {
__expose();
Expand Down
Expand Up @@ -121,12 +121,12 @@ exports[`sfc props transform > default values w/ type declaration, prod mode 1`]
export default /*#__PURE__*/_defineComponent({
props: {
foo: { default: 1 },
bar: { default: () => ({}) },
baz: null,
boola: { type: Boolean },
boolb: { type: [Boolean, Number] },
func: { type: Function, default: () => {} }
foo: { required: false, default: 1 },
bar: { required: false, default: () => ({}) },
baz: { required: false },
boola: { type: Boolean, required: false },
boolb: { type: [Boolean, Number], required: false },
func: { type: Function, required: false, default: () => {} }
},
setup(__props: any) {
Expand Down
40 changes: 21 additions & 19 deletions packages/compiler-sfc/__tests__/compileScript.spec.ts
Expand Up @@ -378,9 +378,9 @@ defineExpose({ foo: 123 })
)
assertCode(content)
expect(content).toMatch(
'"modelValue": Object.assign({ required: true }, { required: true }),'
'"modelValue": Object.assign({ model: true }, { required: true }),'
)
expect(content).toMatch('"count": { required: true },')
expect(content).toMatch('"count": { model: true },')
expect(content).toMatch('emits: ["update:modelValue", "update:count"],')
expect(content).toMatch(`const modelValue = _useModel("modelValue")`)
expect(content).toMatch(`const c = _useModel("count")`)
Expand Down Expand Up @@ -408,7 +408,7 @@ defineExpose({ foo: 123 })
assertCode(content)
expect(content).toMatch(`props: _mergeModels({ foo: String }`)
expect(content).toMatch(
`"modelValue": Object.assign({ required: true }, { default: 0 })`
`"modelValue": Object.assign({ model: true }, { default: 0 })`
)
expect(content).toMatch(`const count = _useModel("modelValue")`)
expect(content).not.toMatch('defineModel')
Expand All @@ -431,7 +431,7 @@ defineExpose({ foo: 123 })
)
assertCode(content)
expect(content).toMatch(`_mergeModels(['foo', 'bar'], {`)
expect(content).toMatch(`"count": { required: true }`)
expect(content).toMatch(`"count": { model: true }`)
expect(content).toMatch(`const count = _useModel("count")`)
expect(content).not.toMatch('defineModel')
expect(bindings).toStrictEqual({
Expand Down Expand Up @@ -1510,12 +1510,12 @@ const emit = defineEmits(['a', 'b'])
expect(content).toMatch(`const props = __props`)

// foo has no default value, the Function can be dropped
expect(content).toMatch(`foo: null`)
expect(content).toMatch(`bar: { type: Boolean }`)
expect(content).toMatch(`foo: { required: true }`)
expect(content).toMatch(`bar: { type: Boolean, required: true }`)
expect(content).toMatch(
`baz: { type: [Boolean, Function], default: true }`
`baz: { type: [Boolean, Function], required: true, default: true }`
)
expect(content).toMatch(`qux: { default: 'hi' }`)
expect(content).toMatch(`qux: { required: true, default: 'hi' }`)
})

test('withDefaults (dynamic)', () => {
Expand Down Expand Up @@ -1585,10 +1585,10 @@ const emit = defineEmits(['a', 'b'])
expect(content).toMatch(
`
_mergeDefaults({
foo: { type: Function },
bar: { type: Boolean },
baz: { type: [Boolean, Function] },
qux: null
foo: { type: Function, required: true },
bar: { type: Boolean, required: true },
baz: { type: [Boolean, Function], required: true },
qux: { required: true }
}, { ...defaults })`.trim()
)
})
Expand Down Expand Up @@ -1801,11 +1801,11 @@ const emit = defineEmits(['a', 'b'])
)
assertCode(content)
expect(content).toMatch(
'"modelValue": { type: [Boolean, String], required: true }'
'"modelValue": { model: true, type: [Boolean, String] }'
)
expect(content).toMatch('"count": { type: Number, required: true }')
expect(content).toMatch('"count": { model: true, type: Number }')
expect(content).toMatch(
'"disabled": { type: Number, required: true, ...{ required: false } },'
'"disabled": { model: true, type: Number, ...{ required: false } },'
)
expect(content).toMatch(
'emits: ["update:modelValue", "update:count", "update:disabled"]'
Expand Down Expand Up @@ -1838,12 +1838,14 @@ const emit = defineEmits(['a', 'b'])
)
assertCode(content)
expect(content).toMatch('"modelValue": Boolean')
expect(content).toMatch('"fn": { }')
expect(content).toMatch('"fn": { model: true }')
expect(content).toMatch(
'"fnWithDefault": { type: Function, ...{ default: () => null } },'
'"fnWithDefault": { model: true, type: Function, ...{ default: () => null } },'
)
expect(content).toMatch('"str": { model: true }')
expect(content).toMatch(
'"optional": { model: true, ...{ required: false } }'
)
expect(content).toMatch('"str": { }')
expect(content).toMatch('"optional": { required: false }')
expect(content).toMatch(
'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]'
)
Expand Down
Expand Up @@ -133,15 +133,15 @@ describe('sfc props transform', () => {
)
// literals can be used as-is, non-literals are always returned from a
// function
assertCode(content)
expect(content).toMatch(`props: {
foo: { default: 1 },
bar: { default: () => ({}) },
baz: null,
boola: { type: Boolean },
boolb: { type: [Boolean, Number] },
func: { type: Function, default: () => {} }
foo: { required: false, default: 1 },
bar: { required: false, default: () => ({}) },
baz: { required: false },
boola: { type: Boolean, required: false },
boolb: { type: [Boolean, Number], required: false },
func: { type: Function, required: false, default: () => {} }
}`)
assertCode(content)
})

test('aliasing', () => {
Expand Down
21 changes: 11 additions & 10 deletions packages/compiler-sfc/src/compileScript.ts
Expand Up @@ -127,7 +127,7 @@ export interface SFCScriptCompileOptions {
*/
hoistStatic?: boolean
/**
* (Experimental) Enable macro `defineModel`
* (**Experimental**) Enable macro `defineModel`
*/
defineModel?: boolean
}
Expand Down Expand Up @@ -997,12 +997,16 @@ export function compileScript(
// #4783 for boolean, should keep the type
// #7111 for function, if default value exists or it's not static, should keep it
// in production
return `${key}: { type: ${toRuntimeTypeString(type)}${
return `${key}: { type: ${toRuntimeTypeString(
type
)}, required: ${required}${
defaultString ? `, ${defaultString}` : ``
} }`
} else {
// production: checks are useless
return `${key}: ${defaultString ? `{ ${defaultString} }` : 'null'}`
return `${key}: ${`{ required: ${required}${
defaultString ? `, ${defaultString}` : ``
} }`}`
}
})
.join(',\n ')}\n }`
Expand Down Expand Up @@ -1035,21 +1039,18 @@ export function compileScript(
undefined

let decl: string

if (runtimeType && isProd && !options) {
decl = runtimeType
} else {
const pairs: string[] = []
if (runtimeType) pairs.push(`type: ${runtimeType}`)
if (!isProd) pairs.push('required: true')
decl = pairs.join(', ')
decl = 'model: true'
if (runtimeType) decl += `, type: ${runtimeType}`

if (decl && options) {
if (options) {
decl = isTS
? `{ ${decl}, ...${options} }`
: `Object.assign({ ${decl} }, ${options})`
} else {
decl = options || `{ ${decl} }`
decl = `{ ${decl} }`
}
}

Expand Down

0 comments on commit 69da94c

Please sign in to comment.