})"
`;
-exports[`SFC compile <script setup> > <script> after <script setup> the script content not end with \`\\n\` 1`] = `
-"import { x } from './x'
- const n = 1
-
-export default {
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-return { n, get x() { return x } }
-}
-
-}"
-`;
-
exports[`SFC compile <script setup> > <script> and <script setup> co-usage > export call expression as default 1`] = `
"function fn() {
return \\"hello, world\\";
}"
`;
-exports[`SFC compile <script setup> > defineEmits() 1`] = `
-"export default {
- emits: ['foo', 'bar'],
- setup(__props, { expose: __expose, emit: myEmit }) {
- __expose();
-
-
-
-return { myEmit }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineExpose() 1`] = `
-"export default {
- setup(__props, { expose: __expose }) {
-
-__expose({ foo: 123 })
-
-return { }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineModel() > basic usage 1`] = `
-"import { useModel as _useModel } from 'vue'
-
-export default {
- props: {
- \\"modelValue\\": { required: true },
- \\"count\\": {},
- },
- emits: [\\"update:modelValue\\", \\"update:count\\"],
- setup(__props, { expose: __expose }) {
- __expose();
-
- const modelValue = _useModel(__props, \\"modelValue\\")
- const c = _useModel(__props, \\"count\\")
-
-return { modelValue, c }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineModel() > w/ array props 1`] = `
-"import { useModel as _useModel, mergeModels as _mergeModels } from 'vue'
-
-export default {
- props: _mergeModels(['foo', 'bar'], {
- \\"count\\": {},
- }),
- emits: [\\"update:count\\"],
- setup(__props, { expose: __expose }) {
- __expose();
-
-
- const count = _useModel(__props, \\"count\\")
-
-return { count }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineModel() > w/ defineProps and defineEmits 1`] = `
-"import { useModel as _useModel, mergeModels as _mergeModels } from 'vue'
-
-export default {
- props: _mergeModels({ foo: String }, {
- \\"modelValue\\": { default: 0 },
- }),
- emits: _mergeModels(['change'], [\\"update:modelValue\\"]),
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-
- const count = _useModel(__props, \\"modelValue\\")
-
-return { count }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineModel() > w/ local flag 1`] = `
-"import { useModel as _useModel } from 'vue'
-const local = true
-
-export default {
- props: {
- \\"modelValue\\": { local: true, default: 1 },
- \\"bar\\": { [key]: true },
- \\"baz\\": { ...x },
- \\"qux\\": x,
- \\"foo2\\": { local: true, ...x },
- \\"hoist\\": { local },
- },
- emits: [\\"update:modelValue\\", \\"update:bar\\", \\"update:baz\\", \\"update:qux\\", \\"update:foo2\\", \\"update:hoist\\"],
- setup(__props, { expose: __expose }) {
- __expose();
-
- const foo = _useModel(__props, \\"modelValue\\", { local: true })
- const bar = _useModel(__props, \\"bar\\", { [key]: true })
- const baz = _useModel(__props, \\"baz\\", { ...x })
- const qux = _useModel(__props, \\"qux\\", x)
-
- const foo2 = _useModel(__props, \\"foo2\\", { local: true })
-
- const hoist = _useModel(__props, \\"hoist\\", { local })
-
-return { foo, bar, baz, qux, foo2, local, hoist }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineOptions() > basic usage 1`] = `
-"export default /*#__PURE__*/Object.assign({ name: 'FooApp' }, {
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > defineOptions() > empty argument 1`] = `
-"export default {
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineProps w/ external definition 1`] = `
-"import { propsModel } from './props'
-
-export default {
- props: propsModel,
- setup(__props, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props, get propsModel() { return propsModel } }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineProps w/ leading code 1`] = `
-"import { x } from './x'
-
-export default {
- props: {},
- setup(__props, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-return { props, get x() { return x } }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineProps() 1`] = `
-"const bar = 1
-
-export default {
- props: {
- foo: String
-},
- setup(__props, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props, bar }
-}
-
-}"
-`;
-
exports[`SFC compile <script setup> > defineProps/defineEmits in multi-variable declaration (full removal) 1`] = `
"export default {
props: ['item'],
})"
`;
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (exported interface) 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-export interface Emits { (e: 'foo' | 'bar'): void }
-
-export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (exported type alias) 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-export type Emits = { (e: 'foo' | 'bar'): void }
-
-export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (interface ts type) 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-interface Emits { (e: 'foo'): void }
-
-export default /*#__PURE__*/_defineComponent({
- emits: ['foo'],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (interface) 1`] = `
+exports[`SFC compile <script setup> > with TypeScript > hoist type declarations 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
-interface Emits { (e: 'foo' | 'bar'): void }
-
-export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
+export interface Foo {}
+ type Bar = {}
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (property syntax string literal) 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo:bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose }) {
__expose();
-
-
-return { emit }
+
+return { }
}
})"
`;
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (property syntax) 1`] = `
+exports[`SFC compile <script setup> > with TypeScript > import type 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
-
+import type { Foo } from './main.ts'
+ import { type Bar, Baz } from './main.ts'
+
export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose }) {
__expose();
-
-
-return { emit }
+
+return { get Baz() { return Baz } }
}
})"
`;
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (referenced exported function type) 1`] = `
+exports[`SFC compile <script setup> > with TypeScript > runtime Enum 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
-export type Emits = (e: 'foo' | 'bar') => void
-
+enum Foo { A = 123 }
+
export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose }) {
__expose();
-
-
-return { emit }
+
+return { Foo }
}
})"
`;
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (referenced function type) 1`] = `
+exports[`SFC compile <script setup> > with TypeScript > runtime Enum in normal script 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
-type Emits = (e: 'foo' | 'bar') => void
-
-export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (type alias) 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-type Emits = { (e: 'foo' | 'bar'): void }
-
+ export enum D { D = \\"D\\" }
+ const enum C { C = \\"C\\" }
+ enum B { B = \\"B\\" }
+
export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type (type literal w/ call signatures) 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\", \\"baz\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineEmits w/ type from normal script 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
- export interface Emits { (e: 'foo' | 'bar'): void }
-
-export default /*#__PURE__*/_defineComponent({
- emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-
-
-return { emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineModel() > basic usage 1`] = `
-"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- \\"modelValue\\": { type: [Boolean, String] },
- \\"count\\": { type: Number },
- \\"disabled\\": { type: Number, ...{ required: false } },
- \\"any\\": { type: Boolean, skipCheck: true },
- },
- emits: [\\"update:modelValue\\", \\"update:count\\", \\"update:disabled\\", \\"update:any\\"],
- 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\\")
-
-return { modelValue, count, disabled, any }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineModel() > w/ production mode 1`] = `
-"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- \\"modelValue\\": { type: Boolean },
- \\"fn\\": {},
- \\"fnWithDefault\\": { type: Function, ...{ default: () => null } },
- \\"str\\": {},
- \\"optional\\": { required: false },
- },
- emits: [\\"update:modelValue\\", \\"update:fn\\", \\"update:fnWithDefault\\", \\"update:str\\", \\"update:optional\\"],
- 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\\")
-
-return { modelValue, fn, fnWithDefault, str, optional }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ TS assertion 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: ['foo'],
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ exported interface 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-export interface Props { x?: number }
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- x: { type: Number, required: false }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ exported interface in normal script 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
- export interface Props { x?: number }
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- x: { type: Number, required: false }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ exported type alias 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-export type Props = { x?: number }
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- x: { type: Number, required: false }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ extends interface 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-interface Bar extends Foo { y?: number }
- interface Props extends Bar {
- z: number
- y: string
- }
-
- interface Foo { x?: number }
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- z: { type: Number, required: true },
- y: { type: String, required: true },
- x: { type: Number, required: false }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ interface 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-interface Props { x?: number }
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- x: { type: Number, required: false }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ type 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-interface Test {}
-
- type Alias = number[]
-
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- string: { type: String, required: true },
- number: { type: Number, required: true },
- boolean: { type: Boolean, required: true },
- object: { type: Object, required: true },
- objectLiteral: { type: Object, required: true },
- fn: { type: Function, required: true },
- functionRef: { type: Function, required: true },
- objectRef: { type: Object, required: true },
- dateTime: { type: Date, required: true },
- array: { type: Array, required: true },
- arrayRef: { type: Array, required: true },
- tuple: { type: Array, required: true },
- set: { type: Set, required: true },
- literal: { type: String, required: true },
- optional: { type: null, required: false },
- recordRef: { type: Object, required: true },
- interface: { type: Object, required: true },
- alias: { type: Array, required: true },
- method: { type: Function, required: true },
- symbol: { type: Symbol, required: true },
- extract: { type: Number, required: true },
- exclude: { type: [Number, Boolean], required: true },
- uppercase: { type: String, required: true },
- params: { type: Array, required: true },
- nonNull: { type: String, required: true },
- objectOrFn: { type: [Function, Object], required: true },
- union: { type: [String, Number], required: true },
- literalUnion: { type: String, required: true },
- literalUnionNumber: { type: Number, required: true },
- literalUnionMixed: { type: [String, Number, Boolean], required: true },
- intersection: { type: Object, required: true },
- intersection2: { type: String, required: true },
- foo: { type: [Function, null], required: true },
- unknown: { type: null, required: true },
- unknownUnion: { type: null, required: true },
- unknownIntersection: { type: Object, required: true },
- unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },
- unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps w/ type alias 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-type Props = { x?: number }
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- x: { type: Number, required: false }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineProps/Emit w/ runtime options 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: { foo: String },
- emits: ['a', 'b'],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-const props = __props;
-
-
-
-
-return { props, emit }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineSlots() > basic usage 1`] = `
-"import { useSlots as _useSlots, defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- setup(__props, { expose: __expose }) {
- __expose();
-
- const slots = _useSlots()
-
-return { slots }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineSlots() > w/o generic params 1`] = `
-"import { useSlots as _useSlots } from 'vue'
-
-export default {
- setup(__props, { expose: __expose }) {
- __expose();
-
- const slots = _useSlots()
-
-return { slots }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > defineSlots() > w/o return value 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > hoist type declarations 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-export interface Foo {}
- type Bar = {}
-
-export default /*#__PURE__*/_defineComponent({
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-return { }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > import type 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-import type { Foo } from './main.ts'
- import { type Bar, Baz } from './main.ts'
-
-export default /*#__PURE__*/_defineComponent({
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-return { get Baz() { return Baz } }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > runtime Enum 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-enum Foo { A = 123 }
-
-export default /*#__PURE__*/_defineComponent({
- setup(__props, { expose: __expose }) {
- __expose();
-
-
-return { Foo }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > runtime Enum in normal script 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
- export enum D { D = \\"D\\" }
- const enum C { C = \\"C\\" }
- enum B { B = \\"B\\" }
-
-export default /*#__PURE__*/_defineComponent({
- setup(__props, { expose: __expose }) {
+ setup(__props, { expose: __expose }) {
__expose();
enum Foo { A = 123 }
})"
`;
-exports[`SFC compile <script setup> > with TypeScript > withDefaults (dynamic) 1`] = `
-"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
-import { defaults } from './foo'
-
-export default /*#__PURE__*/_defineComponent({
- props: _mergeDefaults({
- foo: { type: String, required: false },
- bar: { type: Number, required: false },
- baz: { type: Boolean, required: true }
- }, { ...defaults }),
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props, get defaults() { return defaults } }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > withDefaults (dynamic) w/ production mode 1`] = `
-"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
-import { defaults } from './foo'
-
-export default /*#__PURE__*/_defineComponent({
- props: _mergeDefaults({
- foo: { type: Function },
- bar: { type: Boolean },
- baz: { type: [Boolean, Function] },
- qux: {}
- }, { ...defaults }),
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props, get defaults() { return defaults } }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > withDefaults (reference) 1`] = `
-"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
-import { defaults } from './foo'
-
-export default /*#__PURE__*/_defineComponent({
- props: _mergeDefaults({
- foo: { type: String, required: false },
- bar: { type: Number, required: false },
- baz: { type: Boolean, required: true }
- }, defaults),
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props, get defaults() { return defaults } }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > withDefaults (static) + normal script 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
- interface Props {
- a?: string;
- }
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- a: { type: String, required: false, default: \\"a\\" }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > withDefaults (static) 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- foo: { type: String, required: false, default: 'hi' },
- bar: { type: Number, required: false },
- baz: { type: Boolean, required: true },
- qux: { type: Function, required: false, default() { return 1 } },
- quux: { type: Function, required: false, default() { } },
- quuxx: { type: Promise, required: false, async default() { return await Promise.resolve('hi') } },
- fred: { type: String, required: false, get default() { return 'fred' } }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > withDefaults (static) w/ production mode 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- foo: {},
- bar: { type: Boolean },
- baz: { type: [Boolean, Function], default: true },
- qux: { default: 'hi' }
- },
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props }
-}
-
-})"
-`;
-
-exports[`SFC compile <script setup> > with TypeScript > withDefaults w/ dynamic object method 1`] = `
-"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: _mergeDefaults({
- foo: { type: Function, required: false }
- }, {
- ['fo' + 'o']() { return 'foo' }
- }),
- setup(__props: any, { expose: __expose }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props }
-}
-
-})"
-`;
-
exports[`SFC genDefaultAs > <script setup> only 1`] = `
"const a = 1
+++ /dev/null
-// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
-
-exports[`sfc props transform > $$() escape 1`] = `
-"import { toRef as _toRef } from 'vue'
-
-export default {
- props: ['foo'],
- setup(__props) {
-const __props_bar = _toRef(__props, 'bar');
-const __props_foo = _toRef(__props, 'foo');
-
-
- console.log((__props_foo))
- console.log((__props_bar))
- ;({ foo: __props_foo, baz: __props_bar })
-
-return () => {}
-}
-
-}"
-`;
-
-exports[`sfc props transform > aliasing 1`] = `
-"import { toDisplayString as _toDisplayString } from \\"vue\\"
-
-
-export default {
- props: ['foo'],
- setup(__props) {
-
-
- let x = foo
- let y = __props.foo
-
-return (_ctx, _cache) => {
- return _toDisplayString(__props.foo + __props.foo)
-}
-}
-
-}"
-`;
-
-exports[`sfc props transform > basic usage 1`] = `
-"import { toDisplayString as _toDisplayString } from \\"vue\\"
-
-
-export default {
- props: ['foo'],
- setup(__props) {
-
-
- console.log(__props.foo)
-
-return (_ctx, _cache) => {
- return _toDisplayString(__props.foo)
-}
-}
-
-}"
-`;
-
-exports[`sfc props transform > computed static key 1`] = `
-"import { toDisplayString as _toDisplayString } from \\"vue\\"
-
-
-export default {
- props: ['foo'],
- setup(__props) {
-
-
- console.log(__props.foo)
-
-return (_ctx, _cache) => {
- return _toDisplayString(__props.foo)
-}
-}
-
-}"
-`;
-
-exports[`sfc props transform > default values w/ array runtime declaration 1`] = `
-"import { mergeDefaults as _mergeDefaults } from 'vue'
-
-export default {
- props: _mergeDefaults(['foo', 'bar', 'baz'], {
- foo: 1,
- bar: () => ({}),
- func: () => {}, __skip_func: true
-}),
- setup(__props) {
-
-
-
-return () => {}
-}
-
-}"
-`;
-
-exports[`sfc props transform > default values w/ object runtime declaration 1`] = `
-"import { mergeDefaults as _mergeDefaults } from 'vue'
-
-export default {
- props: _mergeDefaults({ foo: Number, bar: Object, func: Function, ext: null }, {
- foo: 1,
- bar: () => ({}),
- func: () => {}, __skip_func: true,
- ext: x, __skip_ext: true
-}),
- setup(__props) {
-
-
-
-return () => {}
-}
-
-}"
-`;
-
-exports[`sfc props transform > default values w/ type declaration 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- foo: { type: Number, required: false, default: 1 },
- bar: { type: Object, required: false, default: () => ({}) },
- func: { type: Function, required: false, default: () => {} }
- },
- setup(__props: any) {
-
-
-
-return () => {}
-}
-
-})"
-`;
-
-exports[`sfc props transform > default values w/ type declaration, prod mode 1`] = `
-"import { defineComponent as _defineComponent } from 'vue'
-
-export default /*#__PURE__*/_defineComponent({
- props: {
- foo: { default: 1 },
- bar: { default: () => ({}) },
- baz: null,
- boola: { type: Boolean },
- boolb: { type: [Boolean, Number] },
- func: { type: Function, default: () => {} }
- },
- setup(__props: any) {
-
-
-
-return () => {}
-}
-
-})"
-`;
-
-exports[`sfc props transform > multiple variable declarations 1`] = `
-"import { toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
-
-
-export default {
- props: ['foo'],
- setup(__props) {
-
- const bar = 'fish', hello = 'world'
-
-return (_ctx, _cache) => {
- return (_openBlock(), _createElementBlock(\\"div\\", null, _toDisplayString(__props.foo) + \\" \\" + _toDisplayString(hello) + \\" \\" + _toDisplayString(bar), 1 /* TEXT */))
-}
-}
-
-}"
-`;
-
-exports[`sfc props transform > nested scope 1`] = `
-"export default {
- props: ['foo', 'bar'],
- setup(__props) {
-
-
- function test(foo) {
- console.log(foo)
- console.log(__props.bar)
- }
-
-return () => {}
-}
-
-}"
-`;
-
-exports[`sfc props transform > non-identifier prop names 1`] = `
-"import { toDisplayString as _toDisplayString } from \\"vue\\"
-
-
-export default {
- props: { 'foo.bar': Function },
- setup(__props) {
-
-
- let x = __props[\\"foo.bar\\"]
-
-return (_ctx, _cache) => {
- return _toDisplayString(__props[\\"foo.bar\\"])
-}
-}
-
-}"
-`;
-
-exports[`sfc props transform > rest spread 1`] = `
-"import { createPropsRestProxy as _createPropsRestProxy } from 'vue'
-
-export default {
- props: ['foo', 'bar', 'baz'],
- setup(__props) {
-
-const rest = _createPropsRestProxy(__props, [\\"foo\\",\\"bar\\"]);
-
-
-
-return () => {}
-}
-
-}"
-`;
assertCode(content)
})
- test('defineProps()', () => {
- const { content, bindings } = compile(`
-<script setup>
-const props = defineProps({
- foo: String
-})
-const bar = 1
-</script>
- `)
- // should generate working code
- assertCode(content)
- // should analyze bindings
- expect(bindings).toStrictEqual({
- foo: BindingTypes.PROPS,
- bar: BindingTypes.LITERAL_CONST,
- props: BindingTypes.SETUP_REACTIVE_CONST
- })
-
- // should remove defineOptions import and call
- expect(content).not.toMatch('defineProps')
- // should generate correct setup signature
- expect(content).toMatch(`setup(__props, { expose: __expose }) {`)
- // should assign user identifier to it
- expect(content).toMatch(`const props = __props`)
- // should include context options in default export
- expect(content).toMatch(`export default {
- props: {
- foo: String
-},`)
- })
-
- test('defineProps w/ external definition', () => {
- const { content } = compile(`
- <script setup>
- import { propsModel } from './props'
- const props = defineProps(propsModel)
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`export default {
- props: propsModel,`)
- })
-
- // #4764
- test('defineProps w/ leading code', () => {
- const { content } = compile(`
- <script setup>import { x } from './x'
- const props = defineProps({})
- </script>
- `)
- // props declaration should be inside setup, not moved along with the import
- expect(content).not.toMatch(`const props = __props\nimport`)
- assertCode(content)
- })
-
- test('defineEmits()', () => {
- const { content, bindings } = compile(`
-<script setup>
-const myEmit = defineEmits(['foo', 'bar'])
-</script>
- `)
- assertCode(content)
- expect(bindings).toStrictEqual({
- myEmit: BindingTypes.SETUP_CONST
- })
- // should remove defineEmits import and call
- expect(content).not.toMatch('defineEmits')
- // should generate correct setup signature
- expect(content).toMatch(
- `setup(__props, { expose: __expose, emit: myEmit }) {`
- )
- // should include context options in default export
- expect(content).toMatch(`export default {
- emits: ['foo', 'bar'],`)
- })
-
test('defineProps/defineEmits in multi-variable declaration', () => {
const { content } = compile(`
<script setup>
expect(content).toMatch(`emits: ['a'],`)
})
- describe('defineOptions()', () => {
- test('basic usage', () => {
- const { content } = compile(`
- <script setup>
- defineOptions({ name: 'FooApp' })
- </script>
- `)
- assertCode(content)
- // should remove defineOptions import and call
- expect(content).not.toMatch('defineOptions')
- // should include context options in default export
- expect(content).toMatch(
- `export default /*#__PURE__*/Object.assign({ name: 'FooApp' }, `
- )
- })
-
- test('empty argument', () => {
- const { content } = compile(`
- <script setup>
- defineOptions()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`export default {`)
- // should remove defineOptions import and call
- expect(content).not.toMatch('defineOptions')
- })
-
- it('should emit an error with two defineProps', () => {
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ name: 'FooApp' })
- defineOptions({ name: 'BarApp' })
- </script>
- `)
- ).toThrowError('[@vue/compiler-sfc] duplicate defineOptions() call')
- })
-
- it('should emit an error with props or emits property', () => {
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ props: { foo: String } })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.'
- )
-
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ emits: ['update'] })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead.'
- )
-
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ expose: ['foo'] })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead.'
- )
-
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ slots: ['foo'] })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead.'
- )
- })
-
- it('should emit an error with type generic', () => {
- expect(() =>
- compile(`
- <script setup lang="ts">
- defineOptions<{ name: 'FooApp' }>()
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot accept type arguments'
- )
- })
-
- it('should emit an error with type assertion', () => {
- expect(() =>
- compile(`
- <script setup lang="ts">
- defineOptions({ props: [] } as any)
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.'
- )
- })
-
- it('should emit an error with declaring props/emits/slots/expose', () => {
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ props: ['foo'] })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead'
- )
-
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ emits: ['update'] })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead'
- )
-
- expect(() =>
- compile(`
- <script setup>
- defineOptions({ expose: ['foo'] })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead'
- )
-
- expect(() =>
- compile(`
- <script setup lang="ts">
- defineOptions({ slots: Object })
- </script>
- `)
- ).toThrowError(
- '[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead'
- )
- })
- })
-
- test('defineExpose()', () => {
- const { content } = compile(`
-<script setup>
-defineExpose({ foo: 123 })
-</script>
- `)
- assertCode(content)
- // should remove defineOptions import and call
- expect(content).not.toMatch('defineExpose')
- // should generate correct setup signature
- expect(content).toMatch(`setup(__props, { expose: __expose }) {`)
- // should replace callee
- expect(content).toMatch(/\b__expose\(\{ foo: 123 \}\)/)
- })
-
- describe('defineModel()', () => {
- test('basic usage', () => {
- const { content, bindings } = compile(
- `
- <script setup>
- const modelValue = defineModel({ required: true })
- const c = defineModel('count')
- </script>
- `,
- { defineModel: true }
- )
- assertCode(content)
- expect(content).toMatch('props: {')
- expect(content).toMatch('"modelValue": { required: true },')
- expect(content).toMatch('"count": {},')
- expect(content).toMatch('emits: ["update:modelValue", "update:count"],')
- expect(content).toMatch(
- `const modelValue = _useModel(__props, "modelValue")`
- )
- expect(content).toMatch(`const c = _useModel(__props, "count")`)
- expect(content).toMatch(`return { modelValue, c }`)
- expect(content).not.toMatch('defineModel')
-
- expect(bindings).toStrictEqual({
- modelValue: BindingTypes.SETUP_REF,
- count: BindingTypes.PROPS,
- c: BindingTypes.SETUP_REF
- })
- })
-
- test('w/ defineProps and defineEmits', () => {
- const { content, bindings } = compile(
- `
- <script setup>
- defineProps({ foo: String })
- defineEmits(['change'])
- const count = defineModel({ default: 0 })
- </script>
- `,
- { defineModel: true }
- )
- assertCode(content)
- expect(content).toMatch(`props: _mergeModels({ foo: String }`)
- expect(content).toMatch(`"modelValue": { default: 0 }`)
- expect(content).toMatch(`const count = _useModel(__props, "modelValue")`)
- expect(content).not.toMatch('defineModel')
- expect(bindings).toStrictEqual({
- count: BindingTypes.SETUP_REF,
- foo: BindingTypes.PROPS,
- modelValue: BindingTypes.PROPS
- })
- })
-
- test('w/ array props', () => {
- const { content, bindings } = compile(
- `
- <script setup>
- defineProps(['foo', 'bar'])
- const count = defineModel('count')
- </script>
- `,
- { defineModel: true }
- )
- assertCode(content)
- expect(content).toMatch(`props: _mergeModels(['foo', 'bar'], {
- "count": {},
- })`)
- expect(content).toMatch(`const count = _useModel(__props, "count")`)
- expect(content).not.toMatch('defineModel')
- expect(bindings).toStrictEqual({
- foo: BindingTypes.PROPS,
- bar: BindingTypes.PROPS,
- count: BindingTypes.SETUP_REF
- })
- })
-
- test('w/ local flag', () => {
- const { content } = compile(
- `<script setup>
- const foo = defineModel({ local: true, default: 1 })
- const bar = defineModel('bar', { [key]: true })
- const baz = defineModel('baz', { ...x })
- const qux = defineModel('qux', x)
-
- const foo2 = defineModel('foo2', { local: true, ...x })
-
- const local = true
- const hoist = defineModel('hoist', { local })
- </script>`,
- { defineModel: true }
- )
- assertCode(content)
- expect(content).toMatch(
- `_useModel(__props, "modelValue", { local: true })`
- )
- expect(content).toMatch(`_useModel(__props, "bar", { [key]: true })`)
- expect(content).toMatch(`_useModel(__props, "baz", { ...x })`)
- expect(content).toMatch(`_useModel(__props, "qux", x)`)
- expect(content).toMatch(`_useModel(__props, "foo2", { local: true })`)
- expect(content).toMatch(`_useModel(__props, "hoist", { local })`)
- })
- })
-
- test('<script> after <script setup> the script content not end with `\\n`', () => {
- const { content } = compile(`
- <script setup>
- import { x } from './x'
- </script>
- <script>const n = 1</script>
- `)
- assertCode(content)
- })
-
describe('<script> and <script setup> co-usage', () => {
test('script first', () => {
const { content } = compile(`
assertCode(content)
})
- test('defineProps/Emit w/ runtime options', () => {
- const { content } = compile(`
-<script setup lang="ts">
-const props = defineProps({ foo: String })
-const emit = defineEmits(['a', 'b'])
-</script>
- `)
- assertCode(content)
- expect(content).toMatch(`export default /*#__PURE__*/_defineComponent({
- props: { foo: String },
- emits: ['a', 'b'],
- setup(__props, { expose: __expose, emit }) {`)
- })
-
- test('defineProps w/ type', () => {
- const { content, bindings } = compile(`
- <script setup lang="ts">
- interface Test {}
-
- type Alias = number[]
-
- defineProps<{
- string: string
- number: number
- boolean: boolean
- object: object
- objectLiteral: { a: number }
- fn: (n: number) => void
- functionRef: Function
- objectRef: Object
- dateTime: Date
- array: string[]
- arrayRef: Array<any>
- tuple: [number, number]
- set: Set<string>
- literal: 'foo'
- optional?: any
- recordRef: Record<string, null>
- interface: Test
- alias: Alias
- method(): void
- symbol: symbol
- extract: Extract<1 | 2 | boolean, 2>
- exclude: Exclude<1 | 2 | boolean, 2>
- uppercase: Uppercase<'foo'>
- params: Parameters<(foo: any) => void>
- nonNull: NonNullable<string | null>
- objectOrFn: {
- (): void
- foo: string
- }
-
- union: string | number
- literalUnion: 'foo' | 'bar'
- literalUnionNumber: 1 | 2 | 3 | 4 | 5
- literalUnionMixed: 'foo' | 1 | boolean
- intersection: Test & {}
- intersection2: 'foo' & ('foo' | 'bar')
- foo: ((item: any) => boolean) | null
-
- unknown: UnknownType
- unknownUnion: UnknownType | string
- unknownIntersection: UnknownType & Object
- unknownUnionWithBoolean: UnknownType | boolean
- unknownUnionWithFunction: UnknownType | (() => any)
- }>()
- </script>`)
- assertCode(content)
- expect(content).toMatch(`string: { type: String, required: true }`)
- expect(content).toMatch(`number: { type: Number, required: true }`)
- expect(content).toMatch(`boolean: { type: Boolean, required: true }`)
- expect(content).toMatch(`object: { type: Object, required: true }`)
- expect(content).toMatch(`objectLiteral: { type: Object, required: true }`)
- expect(content).toMatch(`fn: { type: Function, required: true }`)
- expect(content).toMatch(`functionRef: { type: Function, required: true }`)
- expect(content).toMatch(`objectRef: { type: Object, required: true }`)
- expect(content).toMatch(`dateTime: { type: Date, required: true }`)
- expect(content).toMatch(`array: { type: Array, required: true }`)
- expect(content).toMatch(`arrayRef: { type: Array, required: true }`)
- expect(content).toMatch(`tuple: { type: Array, required: true }`)
- expect(content).toMatch(`set: { type: Set, required: true }`)
- expect(content).toMatch(`literal: { type: String, required: true }`)
- expect(content).toMatch(`optional: { type: null, required: false }`)
- expect(content).toMatch(`recordRef: { type: Object, required: true }`)
- expect(content).toMatch(`interface: { type: Object, required: true }`)
- expect(content).toMatch(`alias: { type: Array, required: true }`)
- expect(content).toMatch(`method: { type: Function, required: true }`)
- expect(content).toMatch(`symbol: { type: Symbol, required: true }`)
- expect(content).toMatch(
- `objectOrFn: { type: [Function, Object], required: true },`
- )
- expect(content).toMatch(`extract: { type: Number, required: true }`)
- expect(content).toMatch(
- `exclude: { type: [Number, Boolean], required: true }`
- )
- expect(content).toMatch(`uppercase: { type: String, required: true }`)
- expect(content).toMatch(`params: { type: Array, required: true }`)
- expect(content).toMatch(`nonNull: { type: String, required: true }`)
- expect(content).toMatch(
- `union: { type: [String, Number], required: true }`
- )
- expect(content).toMatch(`literalUnion: { type: String, required: true }`)
- expect(content).toMatch(
- `literalUnionNumber: { type: Number, required: true }`
- )
- expect(content).toMatch(
- `literalUnionMixed: { type: [String, Number, Boolean], required: true }`
- )
- expect(content).toMatch(`intersection: { type: Object, required: true }`)
- expect(content).toMatch(`intersection2: { type: String, required: true }`)
- expect(content).toMatch(`foo: { type: [Function, null], required: true }`)
- expect(content).toMatch(`unknown: { type: null, required: true }`)
- // uninon containing unknown type: skip check
- expect(content).toMatch(`unknownUnion: { type: null, required: true }`)
- // intersection containing unknown type: narrow to the known types
- expect(content).toMatch(
- `unknownIntersection: { type: Object, required: true },`
- )
- expect(content).toMatch(
- `unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },`
- )
- expect(content).toMatch(
- `unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }`
- )
- expect(bindings).toStrictEqual({
- string: BindingTypes.PROPS,
- number: BindingTypes.PROPS,
- boolean: BindingTypes.PROPS,
- object: BindingTypes.PROPS,
- objectLiteral: BindingTypes.PROPS,
- fn: BindingTypes.PROPS,
- functionRef: BindingTypes.PROPS,
- objectRef: BindingTypes.PROPS,
- dateTime: BindingTypes.PROPS,
- array: BindingTypes.PROPS,
- arrayRef: BindingTypes.PROPS,
- tuple: BindingTypes.PROPS,
- set: BindingTypes.PROPS,
- literal: BindingTypes.PROPS,
- optional: BindingTypes.PROPS,
- recordRef: BindingTypes.PROPS,
- interface: BindingTypes.PROPS,
- alias: BindingTypes.PROPS,
- method: BindingTypes.PROPS,
- symbol: BindingTypes.PROPS,
- objectOrFn: BindingTypes.PROPS,
- extract: BindingTypes.PROPS,
- exclude: BindingTypes.PROPS,
- union: BindingTypes.PROPS,
- literalUnion: BindingTypes.PROPS,
- literalUnionNumber: BindingTypes.PROPS,
- literalUnionMixed: BindingTypes.PROPS,
- intersection: BindingTypes.PROPS,
- intersection2: BindingTypes.PROPS,
- foo: BindingTypes.PROPS,
- uppercase: BindingTypes.PROPS,
- params: BindingTypes.PROPS,
- nonNull: BindingTypes.PROPS,
- unknown: BindingTypes.PROPS,
- unknownUnion: BindingTypes.PROPS,
- unknownIntersection: BindingTypes.PROPS,
- unknownUnionWithBoolean: BindingTypes.PROPS,
- unknownUnionWithFunction: BindingTypes.PROPS
- })
- })
-
- test('defineProps w/ interface', () => {
- const { content, bindings } = compile(`
- <script setup lang="ts">
- interface Props { x?: number }
- defineProps<Props>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`x: { type: Number, required: false }`)
- expect(bindings).toStrictEqual({
- x: BindingTypes.PROPS
- })
- })
-
- test('defineProps w/ extends interface', () => {
- const { content, bindings } = compile(`
- <script lang="ts">
- interface Foo { x?: number }
- </script>
- <script setup lang="ts">
- interface Bar extends Foo { y?: number }
- interface Props extends Bar {
- z: number
- y: string
- }
- defineProps<Props>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`z: { type: Number, required: true }`)
- expect(content).toMatch(`y: { type: String, required: true }`)
- expect(content).toMatch(`x: { type: Number, required: false }`)
- expect(bindings).toStrictEqual({
- x: BindingTypes.PROPS,
- y: BindingTypes.PROPS,
- z: BindingTypes.PROPS
- })
- })
-
- test('defineProps w/ exported interface', () => {
- const { content, bindings } = compile(`
- <script setup lang="ts">
- export interface Props { x?: number }
- defineProps<Props>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`x: { type: Number, required: false }`)
- expect(bindings).toStrictEqual({
- x: BindingTypes.PROPS
- })
- })
-
- test('defineProps w/ exported interface in normal script', () => {
- const { content, bindings } = compile(`
- <script lang="ts">
- export interface Props { x?: number }
- </script>
- <script setup lang="ts">
- defineProps<Props>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`x: { type: Number, required: false }`)
- expect(bindings).toStrictEqual({
- x: BindingTypes.PROPS
- })
- })
-
- test('defineProps w/ type alias', () => {
- const { content, bindings } = compile(`
- <script setup lang="ts">
- type Props = { x?: number }
- defineProps<Props>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`x: { type: Number, required: false }`)
- expect(bindings).toStrictEqual({
- x: BindingTypes.PROPS
- })
- })
-
- test('defineProps w/ exported type alias', () => {
- const { content, bindings } = compile(`
- <script setup lang="ts">
- export type Props = { x?: number }
- defineProps<Props>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`x: { type: Number, required: false }`)
- expect(bindings).toStrictEqual({
- x: BindingTypes.PROPS
- })
- })
-
- test('defineProps w/ TS assertion', () => {
- const { content, bindings } = compile(`
- <script setup lang="ts">
- defineProps(['foo'])! as any
- </script>
- `)
- expect(content).toMatch(`props: ['foo']`)
- assertCode(content)
- expect(bindings).toStrictEqual({
- foo: BindingTypes.PROPS
- })
- })
-
- test('withDefaults (static)', () => {
- const { content, bindings } = compile(`
- <script setup lang="ts">
- const props = withDefaults(defineProps<{
- foo?: string
- bar?: number;
- baz: boolean;
- qux?(): number;
- quux?(): void
- quuxx?: Promise<string>;
- fred?: string
- }>(), {
- foo: 'hi',
- qux() { return 1 },
- ['quux']() { },
- async quuxx() { return await Promise.resolve('hi') },
- get fred() { return 'fred' }
- })
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(
- `foo: { type: String, required: false, default: 'hi' }`
- )
- expect(content).toMatch(`bar: { type: Number, required: false }`)
- expect(content).toMatch(`baz: { type: Boolean, required: true }`)
- expect(content).toMatch(
- `qux: { type: Function, required: false, default() { return 1 } }`
- )
- expect(content).toMatch(
- `quux: { type: Function, required: false, default() { } }`
- )
- expect(content).toMatch(
- `quuxx: { type: Promise, required: false, async default() { return await Promise.resolve('hi') } }`
- )
- expect(content).toMatch(
- `fred: { type: String, required: false, get default() { return 'fred' } }`
- )
- expect(content).toMatch(`const props = __props`)
- expect(bindings).toStrictEqual({
- foo: BindingTypes.PROPS,
- bar: BindingTypes.PROPS,
- baz: BindingTypes.PROPS,
- qux: BindingTypes.PROPS,
- quux: BindingTypes.PROPS,
- quuxx: BindingTypes.PROPS,
- fred: BindingTypes.PROPS,
- props: BindingTypes.SETUP_CONST
- })
- })
-
- test('withDefaults (static) + normal script', () => {
- const { content } = compile(`
- <script lang="ts">
- interface Props {
- a?: string;
- }
- </script>
- <script setup lang="ts">
- const props = withDefaults(defineProps<Props>(), {
- a: "a",
- });
- </script>
- `)
- assertCode(content)
- })
-
- // #7111
- test('withDefaults (static) w/ production mode', () => {
- const { content } = compile(
- `
- <script setup lang="ts">
- const props = withDefaults(defineProps<{
- foo: () => void
- bar: boolean
- baz: boolean | (() => void)
- qux: string | number
- }>(), {
- baz: true,
- qux: 'hi'
- })
- </script>
- `,
- { isProd: true }
- )
- assertCode(content)
- expect(content).toMatch(`const props = __props`)
-
- // foo has no default value, the Function can be dropped
- expect(content).toMatch(`foo: {}`)
- expect(content).toMatch(`bar: { type: Boolean }`)
- expect(content).toMatch(
- `baz: { type: [Boolean, Function], default: true }`
- )
- expect(content).toMatch(`qux: { default: 'hi' }`)
- })
-
- test('withDefaults (dynamic)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- import { defaults } from './foo'
- const props = withDefaults(defineProps<{
- foo?: string
- bar?: number
- baz: boolean
- }>(), { ...defaults })
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
- expect(content).toMatch(
- `
- _mergeDefaults({
- foo: { type: String, required: false },
- bar: { type: Number, required: false },
- baz: { type: Boolean, required: true }
- }, { ...defaults })`.trim()
- )
- })
-
- test('withDefaults (reference)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- import { defaults } from './foo'
- const props = withDefaults(defineProps<{
- foo?: string
- bar?: number
- baz: boolean
- }>(), defaults)
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
- expect(content).toMatch(
- `
- _mergeDefaults({
- foo: { type: String, required: false },
- bar: { type: Number, required: false },
- baz: { type: Boolean, required: true }
- }, defaults)`.trim()
- )
- })
-
- // #7111
- test('withDefaults (dynamic) w/ production mode', () => {
- const { content } = compile(
- `
- <script setup lang="ts">
- import { defaults } from './foo'
- const props = withDefaults(defineProps<{
- foo: () => void
- bar: boolean
- baz: boolean | (() => void)
- qux: string | number
- }>(), { ...defaults })
- </script>
- `,
- { isProd: true }
- )
- assertCode(content)
- expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
- expect(content).toMatch(
- `
- _mergeDefaults({
- foo: { type: Function },
- bar: { type: Boolean },
- baz: { type: [Boolean, Function] },
- qux: {}
- }, { ...defaults })`.trim()
- )
- })
-
- test('withDefaults w/ dynamic object method', () => {
- const { content } = compile(`
- <script setup lang="ts">
- const props = withDefaults(defineProps<{
- foo?: () => 'string'
- }>(), {
- ['fo' + 'o']() { return 'foo' }
- })
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
- expect(content).toMatch(
- `
- _mergeDefaults({
- foo: { type: Function, required: false }
- }, {
- ['fo' + 'o']() { return 'foo' }
- })`.trim()
- )
- })
-
- test('defineEmits w/ type', () => {
- const { content } = compile(`
- <script setup lang="ts">
- const emit = defineEmits<(e: 'foo' | 'bar') => void>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- test('defineEmits w/ type (union)', () => {
- const type = `((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void)`
- expect(() =>
- compile(`
- <script setup lang="ts">
- const emit = defineEmits<${type}>()
- </script>
- `)
- ).toThrow()
- })
-
- test('defineEmits w/ type (type literal w/ call signatures)', () => {
- const type = `{(e: 'foo' | 'bar'): void; (e: 'baz', id: number): void;}`
- const { content } = compile(`
- <script setup lang="ts">
- const emit = defineEmits<${type}>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar", "baz"]`)
- })
-
- test('defineEmits w/ type (interface)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- interface Emits { (e: 'foo' | 'bar'): void }
- const emit = defineEmits<Emits>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- test('defineEmits w/ type (exported interface)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- export interface Emits { (e: 'foo' | 'bar'): void }
- const emit = defineEmits<Emits>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- test('defineEmits w/ type from normal script', () => {
- const { content } = compile(`
- <script lang="ts">
- export interface Emits { (e: 'foo' | 'bar'): void }
- </script>
- <script setup lang="ts">
- const emit = defineEmits<Emits>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- test('defineEmits w/ type (type alias)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- type Emits = { (e: 'foo' | 'bar'): void }
- const emit = defineEmits<Emits>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- test('defineEmits w/ type (exported type alias)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- export type Emits = { (e: 'foo' | 'bar'): void }
- const emit = defineEmits<Emits>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- test('defineEmits w/ type (referenced function type)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- type Emits = (e: 'foo' | 'bar') => void
- const emit = defineEmits<Emits>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- test('defineEmits w/ type (referenced exported function type)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- export type Emits = (e: 'foo' | 'bar') => void
- const emit = defineEmits<Emits>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- })
-
- // #5393
- test('defineEmits w/ type (interface ts type)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- interface Emits { (e: 'foo'): void }
- const emit: Emits = defineEmits(['foo'])
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`emits: ['foo']`)
- })
-
- test('defineEmits w/ type (property syntax)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- const emit = defineEmits<{ foo: [], bar: [] }>()
- </script>
- `)
- expect(content).toMatch(`emits: ["foo", "bar"]`)
- assertCode(content)
- })
-
- // #8040
- test('defineEmits w/ type (property syntax string literal)', () => {
- const { content } = compile(`
- <script setup lang="ts">
- const emit = defineEmits<{ 'foo:bar': [] }>()
- </script>
- `)
- expect(content).toMatch(`emits: ["foo:bar"]`)
- assertCode(content)
- })
-
- describe('defineSlots()', () => {
- test('basic usage', () => {
- const { content } = compile(`
- <script setup lang="ts">
- const slots = defineSlots<{
- default: { msg: string }
- }>()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`const slots = _useSlots()`)
- expect(content).not.toMatch('defineSlots')
- })
-
- test('w/o return value', () => {
- const { content } = compile(`
- <script setup lang="ts">
- defineSlots<{
- default: { msg: string }
- }>()
- </script>
- `)
- assertCode(content)
- expect(content).not.toMatch('defineSlots')
- expect(content).not.toMatch(`_useSlots`)
- })
-
- test('w/o generic params', () => {
- const { content } = compile(`
- <script setup>
- const slots = defineSlots()
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`const slots = _useSlots()`)
- expect(content).not.toMatch('defineSlots')
- })
- })
-
- describe('defineModel()', () => {
- test('basic usage', () => {
- const { content, bindings } = compile(
- `
- <script setup lang="ts">
- const modelValue = defineModel<boolean | string>()
- const count = defineModel<number>('count')
- const disabled = defineModel<number>('disabled', { required: false })
- const any = defineModel<any | boolean>('any')
- </script>
- `,
- { defineModel: true }
- )
- assertCode(content)
- expect(content).toMatch('"modelValue": { type: [Boolean, String] }')
- expect(content).toMatch('"count": { type: Number }')
- expect(content).toMatch(
- '"disabled": { type: Number, ...{ required: false } }'
- )
- expect(content).toMatch('"any": { type: Boolean, skipCheck: true }')
- expect(content).toMatch(
- 'emits: ["update:modelValue", "update:count", "update:disabled", "update:any"]'
- )
-
- expect(content).toMatch(
- `const modelValue = _useModel(__props, "modelValue")`
- )
- 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,
- count: BindingTypes.SETUP_REF,
- disabled: BindingTypes.SETUP_REF,
- any: BindingTypes.SETUP_REF
- })
- })
-
- test('w/ production mode', () => {
- const { content, bindings } = compile(
- `
- <script setup lang="ts">
- const modelValue = defineModel<boolean>()
- const fn = defineModel<() => void>('fn')
- const fnWithDefault = defineModel<() => void>('fnWithDefault', { default: () => null })
- const str = defineModel<string>('str')
- const optional = defineModel<string>('optional', { required: false })
- </script>
- `,
- { defineModel: true, isProd: true }
- )
- assertCode(content)
- expect(content).toMatch('"modelValue": { type: Boolean }')
- expect(content).toMatch('"fn": {}')
- expect(content).toMatch(
- '"fnWithDefault": { type: Function, ...{ default: () => null } },'
- )
- expect(content).toMatch('"str": {}')
- expect(content).toMatch('"optional": { required: false }')
- expect(content).toMatch(
- 'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]'
- )
- expect(content).toMatch(
- `const modelValue = _useModel(__props, "modelValue")`
- )
- expect(content).toMatch(`const fn = _useModel(__props, "fn")`)
- expect(content).toMatch(`const str = _useModel(__props, "str")`)
- expect(bindings).toStrictEqual({
- modelValue: BindingTypes.SETUP_REF,
- fn: BindingTypes.SETUP_REF,
- fnWithDefault: BindingTypes.SETUP_REF,
- str: BindingTypes.SETUP_REF,
- optional: BindingTypes.SETUP_REF
- })
- })
- })
-
test('runtime Enum', () => {
const { content, bindings } = compile(
`<script setup lang="ts">
})
})
- test('runtime inference for Enum in defineProps', () => {
- expect(
- compile(
- `<script setup lang="ts">
- const enum Foo { A = 123 }
- defineProps<{
- foo: Foo
- }>()
- </script>`,
- { hoistStatic: true }
- ).content
- ).toMatch(`foo: { type: Number`)
-
- expect(
- compile(
- `<script setup lang="ts">
- const enum Foo { A = '123' }
- defineProps<{
- foo: Foo
- }>()
- </script>`,
- { hoistStatic: true }
- ).content
- ).toMatch(`foo: { type: String`)
-
- expect(
- compile(
- `<script setup lang="ts">
- const enum Foo { A = '123', B = 123 }
- defineProps<{
- foo: Foo
- }>()
- </script>`,
- { hoistStatic: true }
- ).content
- ).toMatch(`foo: { type: [String, Number]`)
-
- expect(
- compile(
- `<script setup lang="ts">
- const enum Foo { A, B }
- defineProps<{
- foo: Foo
- }>()
- </script>`,
- { hoistStatic: true }
- ).content
- ).toMatch(`foo: { type: Number`)
- })
-
test('import type', () => {
const { content } = compile(
`<script setup lang="ts">
).toThrow(moduleErrorMsg)
})
- test('defineProps/Emit() w/ both type and non-type args', () => {
- expect(() => {
- compile(`<script setup lang="ts">
- defineProps<{}>({})
- </script>`)
- }).toThrow(`cannot accept both type and non-type arguments`)
-
- expect(() => {
- compile(`<script setup lang="ts">
- defineEmits<{}>({})
- </script>`)
- }).toThrow(`cannot accept both type and non-type arguments`)
- })
-
test('defineProps/Emit() referencing local var', () => {
expect(() =>
compile(`<script setup>
</script>`).content
)
})
-
- test('mixed usage of property / call signature in defineEmits', () => {
- expect(() =>
- compile(`<script setup lang="ts">
- defineEmits<{
- foo: []
- (e: 'hi'): void
- }>()
- </script>`)
- ).toThrow(
- `defineEmits() type cannot mixed call signature and property syntax.`
- )
- })
})
})
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`defineEmits > basic usage 1`] = `
+"export default {
+ emits: ['foo', 'bar'],
+ setup(__props, { expose: __expose, emit: myEmit }) {
+ __expose();
+
+
+
+return { myEmit }
+}
+
+}"
+`;
+
+exports[`defineEmits > w/ runtime options 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ emits: ['a', 'b'],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (exported interface) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+export interface Emits { (e: 'foo' | 'bar'): void }
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (exported type alias) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+export type Emits = { (e: 'foo' | 'bar'): void }
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (interface ts type) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+interface Emits { (e: 'foo'): void }
+
+export default /*#__PURE__*/_defineComponent({
+ emits: ['foo'],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (interface) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+interface Emits { (e: 'foo' | 'bar'): void }
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (property syntax string literal) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo:bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (property syntax) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (referenced exported function type) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+export type Emits = (e: 'foo' | 'bar') => void
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (referenced function type) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+type Emits = (e: 'foo' | 'bar') => void
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (type alias) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+type Emits = { (e: 'foo' | 'bar'): void }
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type (type literal w/ call signatures) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\", \\"baz\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
+
+exports[`defineEmits > w/ type from normal script 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+ export interface Emits { (e: 'foo' | 'bar'): void }
+
+export default /*#__PURE__*/_defineComponent({
+ emits: [\\"foo\\", \\"bar\\"],
+ setup(__props, { expose: __expose, emit }) {
+ __expose();
+
+
+
+return { emit }
+}
+
+})"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`<script> after <script setup> the script content not end with \`\\n\` 1`] = `
+"import { x } from './x'
+ const n = 1
+
+export default {
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+return { n, get x() { return x } }
+}
+
+}"
+`;
+
+exports[`defineExpose() 1`] = `
+"export default {
+ setup(__props, { expose: __expose }) {
+
+__expose({ foo: 123 })
+
+return { }
+}
+
+}"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`defineModel() > basic usage 1`] = `
+"import { useModel as _useModel } from 'vue'
+
+export default {
+ props: {
+ \\"modelValue\\": { required: true },
+ \\"count\\": {},
+ },
+ emits: [\\"update:modelValue\\", \\"update:count\\"],
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+ const modelValue = _useModel(__props, \\"modelValue\\")
+ const c = _useModel(__props, \\"count\\")
+
+return { modelValue, c }
+}
+
+}"
+`;
+
+exports[`defineModel() > w/ array props 1`] = `
+"import { useModel as _useModel, mergeModels as _mergeModels } from 'vue'
+
+export default {
+ props: _mergeModels(['foo', 'bar'], {
+ \\"count\\": {},
+ }),
+ emits: [\\"update:count\\"],
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+ const count = _useModel(__props, \\"count\\")
+
+return { count }
+}
+
+}"
+`;
+
+exports[`defineModel() > w/ defineProps and defineEmits 1`] = `
+"import { useModel as _useModel, mergeModels as _mergeModels } from 'vue'
+
+export default {
+ props: _mergeModels({ foo: String }, {
+ \\"modelValue\\": { default: 0 },
+ }),
+ emits: _mergeModels(['change'], [\\"update:modelValue\\"]),
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+
+ const count = _useModel(__props, \\"modelValue\\")
+
+return { count }
+}
+
+}"
+`;
+
+exports[`defineModel() > w/ local flag 1`] = `
+"import { useModel as _useModel } from 'vue'
+const local = true
+
+export default {
+ props: {
+ \\"modelValue\\": { local: true, default: 1 },
+ \\"bar\\": { [key]: true },
+ \\"baz\\": { ...x },
+ \\"qux\\": x,
+ \\"foo2\\": { local: true, ...x },
+ \\"hoist\\": { local },
+ },
+ emits: [\\"update:modelValue\\", \\"update:bar\\", \\"update:baz\\", \\"update:qux\\", \\"update:foo2\\", \\"update:hoist\\"],
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+ const foo = _useModel(__props, \\"modelValue\\", { local: true })
+ const bar = _useModel(__props, \\"bar\\", { [key]: true })
+ const baz = _useModel(__props, \\"baz\\", { ...x })
+ const qux = _useModel(__props, \\"qux\\", x)
+
+ const foo2 = _useModel(__props, \\"foo2\\", { local: true })
+
+ const hoist = _useModel(__props, \\"hoist\\", { local })
+
+return { foo, bar, baz, qux, foo2, local, hoist }
+}
+
+}"
+`;
+
+exports[`defineModel() > w/ types, basic usage 1`] = `
+"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ \\"modelValue\\": { type: [Boolean, String] },
+ \\"count\\": { type: Number },
+ \\"disabled\\": { type: Number, ...{ required: false } },
+ \\"any\\": { type: Boolean, skipCheck: true },
+ },
+ emits: [\\"update:modelValue\\", \\"update:count\\", \\"update:disabled\\", \\"update:any\\"],
+ 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\\")
+
+return { modelValue, count, disabled, any }
+}
+
+})"
+`;
+
+exports[`defineModel() > w/ types, production mode 1`] = `
+"import { useModel as _useModel, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ \\"modelValue\\": { type: Boolean },
+ \\"fn\\": {},
+ \\"fnWithDefault\\": { type: Function, ...{ default: () => null } },
+ \\"str\\": {},
+ \\"optional\\": { required: false },
+ },
+ emits: [\\"update:modelValue\\", \\"update:fn\\", \\"update:fnWithDefault\\", \\"update:str\\", \\"update:optional\\"],
+ 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\\")
+
+return { modelValue, fn, fnWithDefault, str, optional }
+}
+
+})"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`defineOptions() > basic usage 1`] = `
+"export default /*#__PURE__*/Object.assign({ name: 'FooApp' }, {
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineOptions() > empty argument 1`] = `
+"export default {
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+}"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`defineProps > basic usage 1`] = `
+"const bar = 1
+
+export default {
+ props: {
+ foo: String
+},
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props, bar }
+}
+
+}"
+`;
+
+exports[`defineProps > defineProps w/ runtime options 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: { foo: String },
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ TS assertion 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: ['foo'],
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ exported interface 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+export interface Props { x?: number }
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ x: { type: Number, required: false }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ exported interface in normal script 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+ export interface Props { x?: number }
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ x: { type: Number, required: false }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ exported type alias 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+export type Props = { x?: number }
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ x: { type: Number, required: false }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ extends interface 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+interface Bar extends Foo { y?: number }
+ interface Props extends Bar {
+ z: number
+ y: string
+ }
+
+ interface Foo { x?: number }
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ z: { type: Number, required: true },
+ y: { type: String, required: true },
+ x: { type: Number, required: false }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ external definition 1`] = `
+"import { propsModel } from './props'
+
+export default {
+ props: propsModel,
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props, get propsModel() { return propsModel } }
+}
+
+}"
+`;
+
+exports[`defineProps > w/ interface 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+interface Props { x?: number }
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ x: { type: Number, required: false }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ leading code 1`] = `
+"import { x } from './x'
+
+export default {
+ props: {},
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+return { props, get x() { return x } }
+}
+
+}"
+`;
+
+exports[`defineProps > w/ type 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+interface Test {}
+
+ type Alias = number[]
+
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ string: { type: String, required: true },
+ number: { type: Number, required: true },
+ boolean: { type: Boolean, required: true },
+ object: { type: Object, required: true },
+ objectLiteral: { type: Object, required: true },
+ fn: { type: Function, required: true },
+ functionRef: { type: Function, required: true },
+ objectRef: { type: Object, required: true },
+ dateTime: { type: Date, required: true },
+ array: { type: Array, required: true },
+ arrayRef: { type: Array, required: true },
+ tuple: { type: Array, required: true },
+ set: { type: Set, required: true },
+ literal: { type: String, required: true },
+ optional: { type: null, required: false },
+ recordRef: { type: Object, required: true },
+ interface: { type: Object, required: true },
+ alias: { type: Array, required: true },
+ method: { type: Function, required: true },
+ symbol: { type: Symbol, required: true },
+ extract: { type: Number, required: true },
+ exclude: { type: [Number, Boolean], required: true },
+ uppercase: { type: String, required: true },
+ params: { type: Array, required: true },
+ nonNull: { type: String, required: true },
+ objectOrFn: { type: [Function, Object], required: true },
+ union: { type: [String, Number], required: true },
+ literalUnion: { type: String, required: true },
+ literalUnionNumber: { type: Number, required: true },
+ literalUnionMixed: { type: [String, Number, Boolean], required: true },
+ intersection: { type: Object, required: true },
+ intersection2: { type: String, required: true },
+ foo: { type: [Function, null], required: true },
+ unknown: { type: null, required: true },
+ unknownUnion: { type: null, required: true },
+ unknownIntersection: { type: Object, required: true },
+ unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },
+ unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ type alias 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+type Props = { x?: number }
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ x: { type: Number, required: false }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
+
+exports[`defineProps > withDefaults (dynamic) 1`] = `
+"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
+import { defaults } from './foo'
+
+export default /*#__PURE__*/_defineComponent({
+ props: _mergeDefaults({
+ foo: { type: String, required: false },
+ bar: { type: Number, required: false },
+ baz: { type: Boolean, required: true }
+ }, { ...defaults }),
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props, get defaults() { return defaults } }
+}
+
+})"
+`;
+
+exports[`defineProps > withDefaults (dynamic) w/ production mode 1`] = `
+"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
+import { defaults } from './foo'
+
+export default /*#__PURE__*/_defineComponent({
+ props: _mergeDefaults({
+ foo: { type: Function },
+ bar: { type: Boolean },
+ baz: { type: [Boolean, Function] },
+ qux: {}
+ }, { ...defaults }),
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props, get defaults() { return defaults } }
+}
+
+})"
+`;
+
+exports[`defineProps > withDefaults (reference) 1`] = `
+"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
+import { defaults } from './foo'
+
+export default /*#__PURE__*/_defineComponent({
+ props: _mergeDefaults({
+ foo: { type: String, required: false },
+ bar: { type: Number, required: false },
+ baz: { type: Boolean, required: true }
+ }, defaults),
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props, get defaults() { return defaults } }
+}
+
+})"
+`;
+
+exports[`defineProps > withDefaults (static) + normal script 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+ interface Props {
+ a?: string;
+ }
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ a: { type: String, required: false, default: \\"a\\" }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props }
+}
+
+})"
+`;
+
+exports[`defineProps > withDefaults (static) 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ foo: { type: String, required: false, default: 'hi' },
+ bar: { type: Number, required: false },
+ baz: { type: Boolean, required: true },
+ qux: { type: Function, required: false, default() { return 1 } },
+ quux: { type: Function, required: false, default() { } },
+ quuxx: { type: Promise, required: false, async default() { return await Promise.resolve('hi') } },
+ fred: { type: String, required: false, get default() { return 'fred' } }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props }
+}
+
+})"
+`;
+
+exports[`defineProps > withDefaults (static) w/ production mode 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: {
+ foo: {},
+ bar: { type: Boolean },
+ baz: { type: [Boolean, Function], default: true },
+ qux: { default: 'hi' }
+ },
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props }
+}
+
+})"
+`;
+
+exports[`defineProps > withDefaults w/ dynamic object method 1`] = `
+"import { mergeDefaults as _mergeDefaults, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ props: _mergeDefaults({
+ foo: { type: Function, required: false }
+ }, {
+ ['fo' + 'o']() { return 'foo' }
+ }),
+ setup(__props: any, { expose: __expose }) {
+ __expose();
+
+const props = __props;
+
+
+
+return { props }
+}
+
+})"
+`;
--- /dev/null
+// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
+
+exports[`defineSlots() > basic usage 1`] = `
+"import { useSlots as _useSlots, defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+ const slots = _useSlots()
+
+return { slots }
+}
+
+})"
+`;
+
+exports[`defineSlots() > w/o generic params 1`] = `
+"import { useSlots as _useSlots } from 'vue'
+
+export default {
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+ const slots = _useSlots()
+
+return { slots }
+}
+
+}"
+`;
+
+exports[`defineSlots() > w/o return value 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+
+export default /*#__PURE__*/_defineComponent({
+ setup(__props, { expose: __expose }) {
+ __expose();
+
+
+
+return { }
+}
+
+})"
+`;
--- /dev/null
+import { BindingTypes } from '@vue/compiler-core'
+import { compileSFCScript as compile, assertCode } from '../utils'
+
+describe('defineEmits', () => {
+ test('basic usage', () => {
+ const { content, bindings } = compile(`
+<script setup>
+const myEmit = defineEmits(['foo', 'bar'])
+</script>
+ `)
+ assertCode(content)
+ expect(bindings).toStrictEqual({
+ myEmit: BindingTypes.SETUP_CONST
+ })
+ // should remove defineEmits import and call
+ expect(content).not.toMatch('defineEmits')
+ // should generate correct setup signature
+ expect(content).toMatch(
+ `setup(__props, { expose: __expose, emit: myEmit }) {`
+ )
+ // should include context options in default export
+ expect(content).toMatch(`export default {
+ emits: ['foo', 'bar'],`)
+ })
+
+ test('w/ runtime options', () => {
+ const { content } = compile(`
+<script setup lang="ts">
+const emit = defineEmits(['a', 'b'])
+</script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`export default /*#__PURE__*/_defineComponent({
+ emits: ['a', 'b'],
+ setup(__props, { expose: __expose, emit }) {`)
+ })
+
+ test('w/ type', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ const emit = defineEmits<(e: 'foo' | 'bar') => void>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ test('w/ type (union)', () => {
+ const type = `((e: 'foo' | 'bar') => void) | ((e: 'baz', id: number) => void)`
+ expect(() =>
+ compile(`
+ <script setup lang="ts">
+ const emit = defineEmits<${type}>()
+ </script>
+ `)
+ ).toThrow()
+ })
+
+ test('w/ type (type literal w/ call signatures)', () => {
+ const type = `{(e: 'foo' | 'bar'): void; (e: 'baz', id: number): void;}`
+ const { content } = compile(`
+ <script setup lang="ts">
+ const emit = defineEmits<${type}>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar", "baz"]`)
+ })
+
+ test('w/ type (interface)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ interface Emits { (e: 'foo' | 'bar'): void }
+ const emit = defineEmits<Emits>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ test('w/ type (exported interface)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ export interface Emits { (e: 'foo' | 'bar'): void }
+ const emit = defineEmits<Emits>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ test('w/ type from normal script', () => {
+ const { content } = compile(`
+ <script lang="ts">
+ export interface Emits { (e: 'foo' | 'bar'): void }
+ </script>
+ <script setup lang="ts">
+ const emit = defineEmits<Emits>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ test('w/ type (type alias)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ type Emits = { (e: 'foo' | 'bar'): void }
+ const emit = defineEmits<Emits>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ test('w/ type (exported type alias)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ export type Emits = { (e: 'foo' | 'bar'): void }
+ const emit = defineEmits<Emits>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ test('w/ type (referenced function type)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ type Emits = (e: 'foo' | 'bar') => void
+ const emit = defineEmits<Emits>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ test('w/ type (referenced exported function type)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ export type Emits = (e: 'foo' | 'bar') => void
+ const emit = defineEmits<Emits>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ })
+
+ // #5393
+ test('w/ type (interface ts type)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ interface Emits { (e: 'foo'): void }
+ const emit: Emits = defineEmits(['foo'])
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`emits: ['foo']`)
+ })
+
+ test('w/ type (property syntax)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ const emit = defineEmits<{ foo: [], bar: [] }>()
+ </script>
+ `)
+ expect(content).toMatch(`emits: ["foo", "bar"]`)
+ assertCode(content)
+ })
+
+ // #8040
+ test('w/ type (property syntax string literal)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ const emit = defineEmits<{ 'foo:bar': [] }>()
+ </script>
+ `)
+ expect(content).toMatch(`emits: ["foo:bar"]`)
+ assertCode(content)
+ })
+
+ describe('errors', () => {
+ test('w/ both type and non-type args', () => {
+ expect(() => {
+ compile(`<script setup lang="ts">
+ defineEmits<{}>({})
+ </script>`)
+ }).toThrow(`cannot accept both type and non-type arguments`)
+ })
+
+ test('mixed usage of property / call signature', () => {
+ expect(() =>
+ compile(`<script setup lang="ts">
+ defineEmits<{
+ foo: []
+ (e: 'hi'): void
+ }>()
+ </script>`)
+ ).toThrow(
+ `defineEmits() type cannot mixed call signature and property syntax.`
+ )
+ })
+ })
+})
--- /dev/null
+import { compileSFCScript as compile, assertCode } from '../utils'
+
+test('defineExpose()', () => {
+ const { content } = compile(`
+<script setup>
+defineExpose({ foo: 123 })
+</script>
+`)
+ assertCode(content)
+ // should remove defineOptions import and call
+ expect(content).not.toMatch('defineExpose')
+ // should generate correct setup signature
+ expect(content).toMatch(`setup(__props, { expose: __expose }) {`)
+ // should replace callee
+ expect(content).toMatch(/\b__expose\(\{ foo: 123 \}\)/)
+})
+
+test('<script> after <script setup> the script content not end with `\\n`', () => {
+ const { content } = compile(`
+ <script setup>
+ import { x } from './x'
+ </script>
+ <script>const n = 1</script>
+ `)
+ assertCode(content)
+})
--- /dev/null
+import { BindingTypes } from '@vue/compiler-core'
+import { compileSFCScript as compile, assertCode } from '../utils'
+
+describe('defineModel()', () => {
+ test('basic usage', () => {
+ const { content, bindings } = compile(
+ `
+ <script setup>
+ const modelValue = defineModel({ required: true })
+ const c = defineModel('count')
+ </script>
+ `,
+ { defineModel: true }
+ )
+ assertCode(content)
+ expect(content).toMatch('props: {')
+ expect(content).toMatch('"modelValue": { required: true },')
+ expect(content).toMatch('"count": {},')
+ expect(content).toMatch('emits: ["update:modelValue", "update:count"],')
+ expect(content).toMatch(
+ `const modelValue = _useModel(__props, "modelValue")`
+ )
+ expect(content).toMatch(`const c = _useModel(__props, "count")`)
+ expect(content).toMatch(`return { modelValue, c }`)
+ expect(content).not.toMatch('defineModel')
+
+ expect(bindings).toStrictEqual({
+ modelValue: BindingTypes.SETUP_REF,
+ count: BindingTypes.PROPS,
+ c: BindingTypes.SETUP_REF
+ })
+ })
+
+ test('w/ defineProps and defineEmits', () => {
+ const { content, bindings } = compile(
+ `
+ <script setup>
+ defineProps({ foo: String })
+ defineEmits(['change'])
+ const count = defineModel({ default: 0 })
+ </script>
+ `,
+ { defineModel: true }
+ )
+ assertCode(content)
+ expect(content).toMatch(`props: _mergeModels({ foo: String }`)
+ expect(content).toMatch(`"modelValue": { default: 0 }`)
+ expect(content).toMatch(`const count = _useModel(__props, "modelValue")`)
+ expect(content).not.toMatch('defineModel')
+ expect(bindings).toStrictEqual({
+ count: BindingTypes.SETUP_REF,
+ foo: BindingTypes.PROPS,
+ modelValue: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ array props', () => {
+ const { content, bindings } = compile(
+ `
+ <script setup>
+ defineProps(['foo', 'bar'])
+ const count = defineModel('count')
+ </script>
+ `,
+ { defineModel: true }
+ )
+ assertCode(content)
+ expect(content).toMatch(`props: _mergeModels(['foo', 'bar'], {
+ "count": {},
+ })`)
+ expect(content).toMatch(`const count = _useModel(__props, "count")`)
+ expect(content).not.toMatch('defineModel')
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.PROPS,
+ bar: BindingTypes.PROPS,
+ count: BindingTypes.SETUP_REF
+ })
+ })
+
+ test('w/ local flag', () => {
+ const { content } = compile(
+ `<script setup>
+ const foo = defineModel({ local: true, default: 1 })
+ const bar = defineModel('bar', { [key]: true })
+ const baz = defineModel('baz', { ...x })
+ const qux = defineModel('qux', x)
+
+ const foo2 = defineModel('foo2', { local: true, ...x })
+
+ const local = true
+ const hoist = defineModel('hoist', { local })
+ </script>`,
+ { defineModel: true }
+ )
+ assertCode(content)
+ expect(content).toMatch(`_useModel(__props, "modelValue", { local: true })`)
+ expect(content).toMatch(`_useModel(__props, "bar", { [key]: true })`)
+ expect(content).toMatch(`_useModel(__props, "baz", { ...x })`)
+ expect(content).toMatch(`_useModel(__props, "qux", x)`)
+ expect(content).toMatch(`_useModel(__props, "foo2", { local: true })`)
+ expect(content).toMatch(`_useModel(__props, "hoist", { local })`)
+ })
+
+ test('w/ types, basic usage', () => {
+ const { content, bindings } = compile(
+ `
+ <script setup lang="ts">
+ const modelValue = defineModel<boolean | string>()
+ const count = defineModel<number>('count')
+ const disabled = defineModel<number>('disabled', { required: false })
+ const any = defineModel<any | boolean>('any')
+ </script>
+ `,
+ { defineModel: true }
+ )
+ assertCode(content)
+ expect(content).toMatch('"modelValue": { type: [Boolean, String] }')
+ expect(content).toMatch('"count": { type: Number }')
+ expect(content).toMatch(
+ '"disabled": { type: Number, ...{ required: false } }'
+ )
+ expect(content).toMatch('"any": { type: Boolean, skipCheck: true }')
+ expect(content).toMatch(
+ 'emits: ["update:modelValue", "update:count", "update:disabled", "update:any"]'
+ )
+
+ expect(content).toMatch(
+ `const modelValue = _useModel(__props, "modelValue")`
+ )
+ 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,
+ count: BindingTypes.SETUP_REF,
+ disabled: BindingTypes.SETUP_REF,
+ any: BindingTypes.SETUP_REF
+ })
+ })
+
+ test('w/ types, production mode', () => {
+ const { content, bindings } = compile(
+ `
+ <script setup lang="ts">
+ const modelValue = defineModel<boolean>()
+ const fn = defineModel<() => void>('fn')
+ const fnWithDefault = defineModel<() => void>('fnWithDefault', { default: () => null })
+ const str = defineModel<string>('str')
+ const optional = defineModel<string>('optional', { required: false })
+ </script>
+ `,
+ { defineModel: true, isProd: true }
+ )
+ assertCode(content)
+ expect(content).toMatch('"modelValue": { type: Boolean }')
+ expect(content).toMatch('"fn": {}')
+ expect(content).toMatch(
+ '"fnWithDefault": { type: Function, ...{ default: () => null } },'
+ )
+ expect(content).toMatch('"str": {}')
+ expect(content).toMatch('"optional": { required: false }')
+ expect(content).toMatch(
+ 'emits: ["update:modelValue", "update:fn", "update:fnWithDefault", "update:str", "update:optional"]'
+ )
+ expect(content).toMatch(
+ `const modelValue = _useModel(__props, "modelValue")`
+ )
+ expect(content).toMatch(`const fn = _useModel(__props, "fn")`)
+ expect(content).toMatch(`const str = _useModel(__props, "str")`)
+ expect(bindings).toStrictEqual({
+ modelValue: BindingTypes.SETUP_REF,
+ fn: BindingTypes.SETUP_REF,
+ fnWithDefault: BindingTypes.SETUP_REF,
+ str: BindingTypes.SETUP_REF,
+ optional: BindingTypes.SETUP_REF
+ })
+ })
+})
--- /dev/null
+import { compileSFCScript as compile, assertCode } from '../utils'
+
+describe('defineOptions()', () => {
+ test('basic usage', () => {
+ const { content } = compile(`
+ <script setup>
+ defineOptions({ name: 'FooApp' })
+ </script>
+ `)
+ assertCode(content)
+ // should remove defineOptions import and call
+ expect(content).not.toMatch('defineOptions')
+ // should include context options in default export
+ expect(content).toMatch(
+ `export default /*#__PURE__*/Object.assign({ name: 'FooApp' }, `
+ )
+ })
+
+ test('empty argument', () => {
+ const { content } = compile(`
+ <script setup>
+ defineOptions()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`export default {`)
+ // should remove defineOptions import and call
+ expect(content).not.toMatch('defineOptions')
+ })
+
+ it('should emit an error with two defineProps', () => {
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ name: 'FooApp' })
+ defineOptions({ name: 'BarApp' })
+ </script>
+ `)
+ ).toThrowError('[@vue/compiler-sfc] duplicate defineOptions() call')
+ })
+
+ it('should emit an error with props or emits property', () => {
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ props: { foo: String } })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.'
+ )
+
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ emits: ['update'] })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead.'
+ )
+
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ expose: ['foo'] })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead.'
+ )
+
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ slots: ['foo'] })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead.'
+ )
+ })
+
+ it('should emit an error with type generic', () => {
+ expect(() =>
+ compile(`
+ <script setup lang="ts">
+ defineOptions<{ name: 'FooApp' }>()
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot accept type arguments'
+ )
+ })
+
+ it('should emit an error with type assertion', () => {
+ expect(() =>
+ compile(`
+ <script setup lang="ts">
+ defineOptions({ props: [] } as any)
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead.'
+ )
+ })
+
+ it('should emit an error with declaring props/emits/slots/expose', () => {
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ props: ['foo'] })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare props. Use defineProps() instead'
+ )
+
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ emits: ['update'] })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare emits. Use defineEmits() instead'
+ )
+
+ expect(() =>
+ compile(`
+ <script setup>
+ defineOptions({ expose: ['foo'] })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare expose. Use defineExpose() instead'
+ )
+
+ expect(() =>
+ compile(`
+ <script setup lang="ts">
+ defineOptions({ slots: Object })
+ </script>
+ `)
+ ).toThrowError(
+ '[@vue/compiler-sfc] defineOptions() cannot be used to declare slots. Use defineSlots() instead'
+ )
+ })
+})
--- /dev/null
+import { BindingTypes } from '@vue/compiler-core'
+import { compileSFCScript as compile, assertCode } from '../utils'
+
+describe('defineProps', () => {
+ test('basic usage', () => {
+ const { content, bindings } = compile(`
+<script setup>
+const props = defineProps({
+ foo: String
+})
+const bar = 1
+</script>
+ `)
+ // should generate working code
+ assertCode(content)
+ // should analyze bindings
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.PROPS,
+ bar: BindingTypes.LITERAL_CONST,
+ props: BindingTypes.SETUP_REACTIVE_CONST
+ })
+
+ // should remove defineOptions import and call
+ expect(content).not.toMatch('defineProps')
+ // should generate correct setup signature
+ expect(content).toMatch(`setup(__props, { expose: __expose }) {`)
+ // should assign user identifier to it
+ expect(content).toMatch(`const props = __props`)
+ // should include context options in default export
+ expect(content).toMatch(`export default {
+ props: {
+ foo: String
+},`)
+ })
+
+ test('w/ external definition', () => {
+ const { content } = compile(`
+ <script setup>
+ import { propsModel } from './props'
+ const props = defineProps(propsModel)
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`export default {
+ props: propsModel,`)
+ })
+
+ // #4764
+ test('w/ leading code', () => {
+ const { content } = compile(`
+ <script setup>import { x } from './x'
+ const props = defineProps({})
+ </script>
+ `)
+ // props declaration should be inside setup, not moved along with the import
+ expect(content).not.toMatch(`const props = __props\nimport`)
+ assertCode(content)
+ })
+
+ test('defineProps w/ runtime options', () => {
+ const { content } = compile(`
+<script setup lang="ts">
+const props = defineProps({ foo: String })
+</script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`export default /*#__PURE__*/_defineComponent({
+ props: { foo: String },
+ setup(__props, { expose: __expose }) {`)
+ })
+
+ test('w/ type', () => {
+ const { content, bindings } = compile(`
+ <script setup lang="ts">
+ interface Test {}
+
+ type Alias = number[]
+
+ defineProps<{
+ string: string
+ number: number
+ boolean: boolean
+ object: object
+ objectLiteral: { a: number }
+ fn: (n: number) => void
+ functionRef: Function
+ objectRef: Object
+ dateTime: Date
+ array: string[]
+ arrayRef: Array<any>
+ tuple: [number, number]
+ set: Set<string>
+ literal: 'foo'
+ optional?: any
+ recordRef: Record<string, null>
+ interface: Test
+ alias: Alias
+ method(): void
+ symbol: symbol
+ extract: Extract<1 | 2 | boolean, 2>
+ exclude: Exclude<1 | 2 | boolean, 2>
+ uppercase: Uppercase<'foo'>
+ params: Parameters<(foo: any) => void>
+ nonNull: NonNullable<string | null>
+ objectOrFn: {
+ (): void
+ foo: string
+ }
+
+ union: string | number
+ literalUnion: 'foo' | 'bar'
+ literalUnionNumber: 1 | 2 | 3 | 4 | 5
+ literalUnionMixed: 'foo' | 1 | boolean
+ intersection: Test & {}
+ intersection2: 'foo' & ('foo' | 'bar')
+ foo: ((item: any) => boolean) | null
+
+ unknown: UnknownType
+ unknownUnion: UnknownType | string
+ unknownIntersection: UnknownType & Object
+ unknownUnionWithBoolean: UnknownType | boolean
+ unknownUnionWithFunction: UnknownType | (() => any)
+ }>()
+ </script>`)
+ assertCode(content)
+ expect(content).toMatch(`string: { type: String, required: true }`)
+ expect(content).toMatch(`number: { type: Number, required: true }`)
+ expect(content).toMatch(`boolean: { type: Boolean, required: true }`)
+ expect(content).toMatch(`object: { type: Object, required: true }`)
+ expect(content).toMatch(`objectLiteral: { type: Object, required: true }`)
+ expect(content).toMatch(`fn: { type: Function, required: true }`)
+ expect(content).toMatch(`functionRef: { type: Function, required: true }`)
+ expect(content).toMatch(`objectRef: { type: Object, required: true }`)
+ expect(content).toMatch(`dateTime: { type: Date, required: true }`)
+ expect(content).toMatch(`array: { type: Array, required: true }`)
+ expect(content).toMatch(`arrayRef: { type: Array, required: true }`)
+ expect(content).toMatch(`tuple: { type: Array, required: true }`)
+ expect(content).toMatch(`set: { type: Set, required: true }`)
+ expect(content).toMatch(`literal: { type: String, required: true }`)
+ expect(content).toMatch(`optional: { type: null, required: false }`)
+ expect(content).toMatch(`recordRef: { type: Object, required: true }`)
+ expect(content).toMatch(`interface: { type: Object, required: true }`)
+ expect(content).toMatch(`alias: { type: Array, required: true }`)
+ expect(content).toMatch(`method: { type: Function, required: true }`)
+ expect(content).toMatch(`symbol: { type: Symbol, required: true }`)
+ expect(content).toMatch(
+ `objectOrFn: { type: [Function, Object], required: true },`
+ )
+ expect(content).toMatch(`extract: { type: Number, required: true }`)
+ expect(content).toMatch(
+ `exclude: { type: [Number, Boolean], required: true }`
+ )
+ expect(content).toMatch(`uppercase: { type: String, required: true }`)
+ expect(content).toMatch(`params: { type: Array, required: true }`)
+ expect(content).toMatch(`nonNull: { type: String, required: true }`)
+ expect(content).toMatch(`union: { type: [String, Number], required: true }`)
+ expect(content).toMatch(`literalUnion: { type: String, required: true }`)
+ expect(content).toMatch(
+ `literalUnionNumber: { type: Number, required: true }`
+ )
+ expect(content).toMatch(
+ `literalUnionMixed: { type: [String, Number, Boolean], required: true }`
+ )
+ expect(content).toMatch(`intersection: { type: Object, required: true }`)
+ expect(content).toMatch(`intersection2: { type: String, required: true }`)
+ expect(content).toMatch(`foo: { type: [Function, null], required: true }`)
+ expect(content).toMatch(`unknown: { type: null, required: true }`)
+ // uninon containing unknown type: skip check
+ expect(content).toMatch(`unknownUnion: { type: null, required: true }`)
+ // intersection containing unknown type: narrow to the known types
+ expect(content).toMatch(
+ `unknownIntersection: { type: Object, required: true },`
+ )
+ expect(content).toMatch(
+ `unknownUnionWithBoolean: { type: Boolean, required: true, skipCheck: true },`
+ )
+ expect(content).toMatch(
+ `unknownUnionWithFunction: { type: Function, required: true, skipCheck: true }`
+ )
+ expect(bindings).toStrictEqual({
+ string: BindingTypes.PROPS,
+ number: BindingTypes.PROPS,
+ boolean: BindingTypes.PROPS,
+ object: BindingTypes.PROPS,
+ objectLiteral: BindingTypes.PROPS,
+ fn: BindingTypes.PROPS,
+ functionRef: BindingTypes.PROPS,
+ objectRef: BindingTypes.PROPS,
+ dateTime: BindingTypes.PROPS,
+ array: BindingTypes.PROPS,
+ arrayRef: BindingTypes.PROPS,
+ tuple: BindingTypes.PROPS,
+ set: BindingTypes.PROPS,
+ literal: BindingTypes.PROPS,
+ optional: BindingTypes.PROPS,
+ recordRef: BindingTypes.PROPS,
+ interface: BindingTypes.PROPS,
+ alias: BindingTypes.PROPS,
+ method: BindingTypes.PROPS,
+ symbol: BindingTypes.PROPS,
+ objectOrFn: BindingTypes.PROPS,
+ extract: BindingTypes.PROPS,
+ exclude: BindingTypes.PROPS,
+ union: BindingTypes.PROPS,
+ literalUnion: BindingTypes.PROPS,
+ literalUnionNumber: BindingTypes.PROPS,
+ literalUnionMixed: BindingTypes.PROPS,
+ intersection: BindingTypes.PROPS,
+ intersection2: BindingTypes.PROPS,
+ foo: BindingTypes.PROPS,
+ uppercase: BindingTypes.PROPS,
+ params: BindingTypes.PROPS,
+ nonNull: BindingTypes.PROPS,
+ unknown: BindingTypes.PROPS,
+ unknownUnion: BindingTypes.PROPS,
+ unknownIntersection: BindingTypes.PROPS,
+ unknownUnionWithBoolean: BindingTypes.PROPS,
+ unknownUnionWithFunction: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ interface', () => {
+ const { content, bindings } = compile(`
+ <script setup lang="ts">
+ interface Props { x?: number }
+ defineProps<Props>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`x: { type: Number, required: false }`)
+ expect(bindings).toStrictEqual({
+ x: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ extends interface', () => {
+ const { content, bindings } = compile(`
+ <script lang="ts">
+ interface Foo { x?: number }
+ </script>
+ <script setup lang="ts">
+ interface Bar extends Foo { y?: number }
+ interface Props extends Bar {
+ z: number
+ y: string
+ }
+ defineProps<Props>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`z: { type: Number, required: true }`)
+ expect(content).toMatch(`y: { type: String, required: true }`)
+ expect(content).toMatch(`x: { type: Number, required: false }`)
+ expect(bindings).toStrictEqual({
+ x: BindingTypes.PROPS,
+ y: BindingTypes.PROPS,
+ z: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ exported interface', () => {
+ const { content, bindings } = compile(`
+ <script setup lang="ts">
+ export interface Props { x?: number }
+ defineProps<Props>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`x: { type: Number, required: false }`)
+ expect(bindings).toStrictEqual({
+ x: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ exported interface in normal script', () => {
+ const { content, bindings } = compile(`
+ <script lang="ts">
+ export interface Props { x?: number }
+ </script>
+ <script setup lang="ts">
+ defineProps<Props>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`x: { type: Number, required: false }`)
+ expect(bindings).toStrictEqual({
+ x: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ type alias', () => {
+ const { content, bindings } = compile(`
+ <script setup lang="ts">
+ type Props = { x?: number }
+ defineProps<Props>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`x: { type: Number, required: false }`)
+ expect(bindings).toStrictEqual({
+ x: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ exported type alias', () => {
+ const { content, bindings } = compile(`
+ <script setup lang="ts">
+ export type Props = { x?: number }
+ defineProps<Props>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`x: { type: Number, required: false }`)
+ expect(bindings).toStrictEqual({
+ x: BindingTypes.PROPS
+ })
+ })
+
+ test('w/ TS assertion', () => {
+ const { content, bindings } = compile(`
+ <script setup lang="ts">
+ defineProps(['foo'])! as any
+ </script>
+ `)
+ expect(content).toMatch(`props: ['foo']`)
+ assertCode(content)
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.PROPS
+ })
+ })
+
+ test('withDefaults (static)', () => {
+ const { content, bindings } = compile(`
+ <script setup lang="ts">
+ const props = withDefaults(defineProps<{
+ foo?: string
+ bar?: number;
+ baz: boolean;
+ qux?(): number;
+ quux?(): void
+ quuxx?: Promise<string>;
+ fred?: string
+ }>(), {
+ foo: 'hi',
+ qux() { return 1 },
+ ['quux']() { },
+ async quuxx() { return await Promise.resolve('hi') },
+ get fred() { return 'fred' }
+ })
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(
+ `foo: { type: String, required: false, default: 'hi' }`
+ )
+ expect(content).toMatch(`bar: { type: Number, required: false }`)
+ expect(content).toMatch(`baz: { type: Boolean, required: true }`)
+ expect(content).toMatch(
+ `qux: { type: Function, required: false, default() { return 1 } }`
+ )
+ expect(content).toMatch(
+ `quux: { type: Function, required: false, default() { } }`
+ )
+ expect(content).toMatch(
+ `quuxx: { type: Promise, required: false, async default() { return await Promise.resolve('hi') } }`
+ )
+ expect(content).toMatch(
+ `fred: { type: String, required: false, get default() { return 'fred' } }`
+ )
+ expect(content).toMatch(`const props = __props`)
+ expect(bindings).toStrictEqual({
+ foo: BindingTypes.PROPS,
+ bar: BindingTypes.PROPS,
+ baz: BindingTypes.PROPS,
+ qux: BindingTypes.PROPS,
+ quux: BindingTypes.PROPS,
+ quuxx: BindingTypes.PROPS,
+ fred: BindingTypes.PROPS,
+ props: BindingTypes.SETUP_CONST
+ })
+ })
+
+ test('withDefaults (static) + normal script', () => {
+ const { content } = compile(`
+ <script lang="ts">
+ interface Props {
+ a?: string;
+ }
+ </script>
+ <script setup lang="ts">
+ const props = withDefaults(defineProps<Props>(), {
+ a: "a",
+ });
+ </script>
+ `)
+ assertCode(content)
+ })
+
+ // #7111
+ test('withDefaults (static) w/ production mode', () => {
+ const { content } = compile(
+ `
+ <script setup lang="ts">
+ const props = withDefaults(defineProps<{
+ foo: () => void
+ bar: boolean
+ baz: boolean | (() => void)
+ qux: string | number
+ }>(), {
+ baz: true,
+ qux: 'hi'
+ })
+ </script>
+ `,
+ { isProd: true }
+ )
+ assertCode(content)
+ expect(content).toMatch(`const props = __props`)
+
+ // foo has no default value, the Function can be dropped
+ expect(content).toMatch(`foo: {}`)
+ expect(content).toMatch(`bar: { type: Boolean }`)
+ expect(content).toMatch(`baz: { type: [Boolean, Function], default: true }`)
+ expect(content).toMatch(`qux: { default: 'hi' }`)
+ })
+
+ test('withDefaults (dynamic)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ import { defaults } from './foo'
+ const props = withDefaults(defineProps<{
+ foo?: string
+ bar?: number
+ baz: boolean
+ }>(), { ...defaults })
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
+ expect(content).toMatch(
+ `
+ _mergeDefaults({
+ foo: { type: String, required: false },
+ bar: { type: Number, required: false },
+ baz: { type: Boolean, required: true }
+ }, { ...defaults })`.trim()
+ )
+ })
+
+ test('withDefaults (reference)', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ import { defaults } from './foo'
+ const props = withDefaults(defineProps<{
+ foo?: string
+ bar?: number
+ baz: boolean
+ }>(), defaults)
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
+ expect(content).toMatch(
+ `
+ _mergeDefaults({
+ foo: { type: String, required: false },
+ bar: { type: Number, required: false },
+ baz: { type: Boolean, required: true }
+ }, defaults)`.trim()
+ )
+ })
+
+ // #7111
+ test('withDefaults (dynamic) w/ production mode', () => {
+ const { content } = compile(
+ `
+ <script setup lang="ts">
+ import { defaults } from './foo'
+ const props = withDefaults(defineProps<{
+ foo: () => void
+ bar: boolean
+ baz: boolean | (() => void)
+ qux: string | number
+ }>(), { ...defaults })
+ </script>
+ `,
+ { isProd: true }
+ )
+ assertCode(content)
+ expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
+ expect(content).toMatch(
+ `
+ _mergeDefaults({
+ foo: { type: Function },
+ bar: { type: Boolean },
+ baz: { type: [Boolean, Function] },
+ qux: {}
+ }, { ...defaults })`.trim()
+ )
+ })
+
+ test('withDefaults w/ dynamic object method', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ const props = withDefaults(defineProps<{
+ foo?: () => 'string'
+ }>(), {
+ ['fo' + 'o']() { return 'foo' }
+ })
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`)
+ expect(content).toMatch(
+ `
+ _mergeDefaults({
+ foo: { type: Function, required: false }
+ }, {
+ ['fo' + 'o']() { return 'foo' }
+ })`.trim()
+ )
+ })
+
+ test('runtime inference for Enum', () => {
+ expect(
+ compile(
+ `<script setup lang="ts">
+ const enum Foo { A = 123 }
+ defineProps<{
+ foo: Foo
+ }>()
+ </script>`,
+ { hoistStatic: true }
+ ).content
+ ).toMatch(`foo: { type: Number`)
+
+ expect(
+ compile(
+ `<script setup lang="ts">
+ const enum Foo { A = '123' }
+ defineProps<{
+ foo: Foo
+ }>()
+ </script>`,
+ { hoistStatic: true }
+ ).content
+ ).toMatch(`foo: { type: String`)
+
+ expect(
+ compile(
+ `<script setup lang="ts">
+ const enum Foo { A = '123', B = 123 }
+ defineProps<{
+ foo: Foo
+ }>()
+ </script>`,
+ { hoistStatic: true }
+ ).content
+ ).toMatch(`foo: { type: [String, Number]`)
+
+ expect(
+ compile(
+ `<script setup lang="ts">
+ const enum Foo { A, B }
+ defineProps<{
+ foo: Foo
+ }>()
+ </script>`,
+ { hoistStatic: true }
+ ).content
+ ).toMatch(`foo: { type: Number`)
+ })
+
+ describe('errors', () => {
+ test('w/ both type and non-type args', () => {
+ expect(() => {
+ compile(`<script setup lang="ts">
+ defineProps<{}>({})
+ </script>`)
+ }).toThrow(`cannot accept both type and non-type arguments`)
+ })
+ })
+})
import { BindingTypes } from '@vue/compiler-core'
-import { SFCScriptCompileOptions } from '../src'
-import { compileSFCScript, assertCode } from './utils'
+import { SFCScriptCompileOptions } from '../../src'
+import { compileSFCScript, assertCode } from '../utils'
describe('sfc props transform', () => {
function compile(src: string, options?: Partial<SFCScriptCompileOptions>) {
--- /dev/null
+import { compileSFCScript as compile, assertCode } from '../utils'
+
+describe('defineSlots()', () => {
+ test('basic usage', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ const slots = defineSlots<{
+ default: { msg: string }
+ }>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`const slots = _useSlots()`)
+ expect(content).not.toMatch('defineSlots')
+ })
+
+ test('w/o return value', () => {
+ const { content } = compile(`
+ <script setup lang="ts">
+ defineSlots<{
+ default: { msg: string }
+ }>()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).not.toMatch('defineSlots')
+ expect(content).not.toMatch(`_useSlots`)
+ })
+
+ test('w/o generic params', () => {
+ const { content } = compile(`
+ <script setup>
+ const slots = defineSlots()
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`const slots = _useSlots()`)
+ expect(content).not.toMatch('defineSlots')
+ })
+})
import { BindingTypes } from '@vue/compiler-core'
-import { SFCScriptCompileOptions } from '../src'
-import { compileSFCScript, assertCode } from './utils'
+import { SFCScriptCompileOptions } from '../../src'
+import { compileSFCScript, assertCode } from '../utils'
describe('sfc hoist static', () => {
function compile(src: string, options?: Partial<SFCScriptCompileOptions>) {
+// TODO remove in 3.4
import { BindingTypes } from '@vue/compiler-core'
-import { compileSFCScript as compile, assertCode } from './utils'
+import { compileSFCScript as compile, assertCode } from '../utils'
// this file only tests integration with SFC - main test case for the ref
// transform can be found in <root>/packages/reactivity-transform/__tests__