test: split compileScript macro tests

This commit is contained in:
Evan You 2023-04-12 16:46:26 +08:00
parent b2cdb2645f
commit a6dedc33ba
21 changed files with 2104 additions and 2294 deletions

View File

@ -44,21 +44,6 @@ return { a }
})" })"
`; `;
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`] = ` exports[`SFC compile <script setup> > <script> and <script setup> co-usage > export call expression as default 1`] = `
"function fn() { "function fn() {
return \\"hello, world\\"; return \\"hello, world\\";
@ -627,207 +612,6 @@ return { foo, bar, baz, y, z }
}" }"
`; `;
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`] = ` exports[`SFC compile <script setup> > defineProps/defineEmits in multi-variable declaration (full removal) 1`] = `
"export default { "export default {
props: ['item'], props: ['item'],
@ -1489,522 +1273,6 @@ return { Foo }
})" })"
`; `;
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`] = `
"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[`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 }) {
__expose();
return { emit }
}
})"
`;
exports[`SFC compile <script setup> > with TypeScript > 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[`SFC compile <script setup> > with TypeScript > 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[`SFC compile <script setup> > with TypeScript > 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[`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 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`] = ` exports[`SFC compile <script setup> > with TypeScript > hoist type declarations 1`] = `
"import { defineComponent as _defineComponent } from 'vue' "import { defineComponent as _defineComponent } from 'vue'
export interface Foo {} export interface Foo {}
@ -2071,171 +1339,6 @@ return { D, C, B, Foo }
})" })"
`; `;
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`] = ` exports[`SFC genDefaultAs > <script setup> only 1`] = `
"const a = 1 "const a = 1

View File

@ -1,230 +0,0 @@
// 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 () => {}
}
}"
`;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,232 @@
// 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 }
}
})"
`;

View File

@ -0,0 +1,28 @@
// 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 { }
}
}"
`;

View File

@ -0,0 +1,147 @@
// 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 }
}
})"
`;

View File

@ -0,0 +1,27 @@
// 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 { }
}
}"
`;

View File

@ -0,0 +1,437 @@
// 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 }
}
})"
`;

View File

@ -0,0 +1,46 @@
// 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 { }
}
})"
`;

View File

@ -0,0 +1,204 @@
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.`
)
})
})
})

View File

@ -0,0 +1,26 @@
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)
})

View File

@ -0,0 +1,179 @@
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
})
})
})

View File

@ -0,0 +1,149 @@
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'
)
})
})

View File

@ -0,0 +1,583 @@
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`)
})
})
})

View File

@ -1,6 +1,6 @@
import { BindingTypes } from '@vue/compiler-core' import { BindingTypes } from '@vue/compiler-core'
import { SFCScriptCompileOptions } from '../src' import { SFCScriptCompileOptions } from '../../src'
import { compileSFCScript, assertCode } from './utils' import { compileSFCScript, assertCode } from '../utils'
describe('sfc props transform', () => { describe('sfc props transform', () => {
function compile(src: string, options?: Partial<SFCScriptCompileOptions>) { function compile(src: string, options?: Partial<SFCScriptCompileOptions>) {

View File

@ -0,0 +1,40 @@
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')
})
})

View File

@ -1,6 +1,6 @@
import { BindingTypes } from '@vue/compiler-core' import { BindingTypes } from '@vue/compiler-core'
import { SFCScriptCompileOptions } from '../src' import { SFCScriptCompileOptions } from '../../src'
import { compileSFCScript, assertCode } from './utils' import { compileSFCScript, assertCode } from '../utils'
describe('sfc hoist static', () => { describe('sfc hoist static', () => {
function compile(src: string, options?: Partial<SFCScriptCompileOptions>) { function compile(src: string, options?: Partial<SFCScriptCompileOptions>) {

View File

@ -1,5 +1,6 @@
// TODO remove in 3.4
import { BindingTypes } from '@vue/compiler-core' 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 // this file only tests integration with SFC - main test case for the ref
// transform can be found in <root>/packages/reactivity-transform/__tests__ // transform can be found in <root>/packages/reactivity-transform/__tests__