2023-03-30 19:24:32 +08:00
|
|
|
import {
|
|
|
|
isArray,
|
|
|
|
isPromise,
|
|
|
|
isFunction,
|
|
|
|
Prettify,
|
2023-04-08 12:13:05 +08:00
|
|
|
UnionToIntersection,
|
2023-11-09 14:52:28 +08:00
|
|
|
extend,
|
2023-12-12 16:47:34 +08:00
|
|
|
LooseRequired,
|
|
|
|
hasChanged
|
2023-03-30 19:24:32 +08:00
|
|
|
} from '@vue/shared'
|
2020-11-26 22:25:35 +08:00
|
|
|
import {
|
|
|
|
getCurrentInstance,
|
2021-07-07 02:31:53 +08:00
|
|
|
setCurrentInstance,
|
2020-11-26 22:25:35 +08:00
|
|
|
SetupContext,
|
2021-07-07 21:07:19 +08:00
|
|
|
createSetupContext,
|
|
|
|
unsetCurrentInstance
|
2020-11-26 22:25:35 +08:00
|
|
|
} from './component'
|
2023-04-08 12:13:05 +08:00
|
|
|
import { EmitFn, EmitsOptions, ObjectEmitsOptions } from './componentEmits'
|
2023-03-28 10:43:51 +08:00
|
|
|
import {
|
|
|
|
ComponentOptionsMixin,
|
|
|
|
ComponentOptionsWithoutProps,
|
|
|
|
ComputedOptions,
|
|
|
|
MethodOptions
|
|
|
|
} from './componentOptions'
|
2023-02-03 17:10:31 +08:00
|
|
|
import {
|
|
|
|
ComponentPropsOptions,
|
|
|
|
ComponentObjectPropsOptions,
|
2023-04-08 12:13:05 +08:00
|
|
|
ExtractPropTypes,
|
|
|
|
NormalizedProps,
|
|
|
|
PropOptions
|
2023-02-03 17:10:31 +08:00
|
|
|
} from './componentProps'
|
2020-11-25 04:12:59 +08:00
|
|
|
import { warn } from './warning'
|
2023-05-08 11:53:49 +08:00
|
|
|
import { SlotsType, StrictUnwrapSlotsType } from './componentSlots'
|
2023-12-12 16:47:34 +08:00
|
|
|
import { Ref, customRef, ref } from '@vue/reactivity'
|
|
|
|
import { watchSyncEffect } from '.'
|
2020-11-25 04:12:59 +08:00
|
|
|
|
2021-06-27 09:11:57 +08:00
|
|
|
// dev only
|
|
|
|
const warnRuntimeUsage = (method: string) =>
|
|
|
|
warn(
|
|
|
|
`${method}() is a compiler-hint helper that is only usable inside ` +
|
|
|
|
`<script setup> of a single file component. Its arguments should be ` +
|
|
|
|
`compiled away and passing it at runtime has no effect.`
|
|
|
|
)
|
2021-06-26 07:31:47 +08:00
|
|
|
|
2020-11-25 04:12:59 +08:00
|
|
|
/**
|
2021-06-27 09:11:57 +08:00
|
|
|
* Vue `<script setup>` compiler macro for declaring component props. The
|
|
|
|
* expected argument is the same as the component `props` option.
|
|
|
|
*
|
|
|
|
* Example runtime declaration:
|
|
|
|
* ```js
|
|
|
|
* // using Array syntax
|
|
|
|
* const props = defineProps(['foo', 'bar'])
|
|
|
|
* // using Object syntax
|
|
|
|
* const props = defineProps({
|
|
|
|
* foo: String,
|
|
|
|
* bar: {
|
|
|
|
* type: Number,
|
|
|
|
* required: true
|
|
|
|
* }
|
|
|
|
* })
|
|
|
|
* ```
|
|
|
|
*
|
2021-09-06 06:02:50 +08:00
|
|
|
* Equivalent type-based declaration:
|
2021-06-27 09:11:57 +08:00
|
|
|
* ```ts
|
|
|
|
* // will be compiled into equivalent runtime declarations
|
|
|
|
* const props = defineProps<{
|
|
|
|
* foo?: string
|
|
|
|
* bar: number
|
|
|
|
* }>()
|
2023-12-07 14:30:32 +08:00
|
|
|
* ```
|
2023-04-02 10:02:33 +08:00
|
|
|
*
|
|
|
|
* @see {@link https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits}
|
2021-06-27 09:11:57 +08:00
|
|
|
*
|
|
|
|
* This is only usable inside `<script setup>`, is compiled away in the
|
|
|
|
* output and should **not** be actually called at runtime.
|
2020-11-25 04:12:59 +08:00
|
|
|
*/
|
2021-06-27 09:11:57 +08:00
|
|
|
// overload 1: runtime props w/ array
|
|
|
|
export function defineProps<PropNames extends string = string>(
|
|
|
|
props: PropNames[]
|
2023-03-24 15:06:43 +08:00
|
|
|
): Prettify<Readonly<{ [key in PropNames]?: any }>>
|
2021-06-27 09:11:57 +08:00
|
|
|
// overload 2: runtime props w/ object
|
2020-11-25 04:12:59 +08:00
|
|
|
export function defineProps<
|
2021-06-27 09:11:57 +08:00
|
|
|
PP extends ComponentObjectPropsOptions = ComponentObjectPropsOptions
|
2023-03-24 15:06:43 +08:00
|
|
|
>(props: PP): Prettify<Readonly<ExtractPropTypes<PP>>>
|
2021-06-27 09:11:57 +08:00
|
|
|
// overload 3: typed-based declaration
|
2023-05-17 09:25:48 +08:00
|
|
|
export function defineProps<TypeProps>(): DefineProps<
|
2023-11-09 14:52:28 +08:00
|
|
|
LooseRequired<TypeProps>,
|
2023-05-17 09:25:48 +08:00
|
|
|
BooleanKey<TypeProps>
|
|
|
|
>
|
2020-11-25 04:12:59 +08:00
|
|
|
// implementation
|
2020-11-26 23:01:36 +08:00
|
|
|
export function defineProps() {
|
|
|
|
if (__DEV__) {
|
2021-06-27 09:11:57 +08:00
|
|
|
warnRuntimeUsage(`defineProps`)
|
2020-11-25 04:12:59 +08:00
|
|
|
}
|
2020-11-25 05:55:43 +08:00
|
|
|
return null as any
|
2020-11-25 04:12:59 +08:00
|
|
|
}
|
|
|
|
|
2023-12-09 00:34:28 +08:00
|
|
|
export type DefineProps<T, BKeys extends keyof T> = Readonly<T> & {
|
2023-05-17 09:25:48 +08:00
|
|
|
readonly [K in BKeys]-?: boolean
|
2023-04-05 17:18:11 +08:00
|
|
|
}
|
2023-03-26 15:58:04 +08:00
|
|
|
|
|
|
|
type BooleanKey<T, K extends keyof T = keyof T> = K extends any
|
|
|
|
? [T[K]] extends [boolean | undefined]
|
|
|
|
? K
|
|
|
|
: never
|
|
|
|
: never
|
|
|
|
|
2021-06-27 09:11:57 +08:00
|
|
|
/**
|
|
|
|
* Vue `<script setup>` compiler macro for declaring a component's emitted
|
|
|
|
* events. The expected argument is the same as the component `emits` option.
|
|
|
|
*
|
|
|
|
* Example runtime declaration:
|
|
|
|
* ```js
|
|
|
|
* const emit = defineEmits(['change', 'update'])
|
|
|
|
* ```
|
|
|
|
*
|
2021-09-06 06:02:50 +08:00
|
|
|
* Example type-based declaration:
|
2021-06-27 09:11:57 +08:00
|
|
|
* ```ts
|
|
|
|
* const emit = defineEmits<{
|
2023-12-07 14:30:32 +08:00
|
|
|
* // <eventName>: <expected arguments>
|
|
|
|
* change: []
|
|
|
|
* update: [value: string] // named tuple syntax
|
2021-06-27 09:11:57 +08:00
|
|
|
* }>()
|
|
|
|
*
|
|
|
|
* emit('change')
|
|
|
|
* emit('update', 1)
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* This is only usable inside `<script setup>`, is compiled away in the
|
|
|
|
* output and should **not** be actually called at runtime.
|
2023-04-02 10:02:33 +08:00
|
|
|
*
|
|
|
|
* @see {@link https://vuejs.org/api/sfc-script-setup.html#defineprops-defineemits}
|
2021-06-27 09:11:57 +08:00
|
|
|
*/
|
|
|
|
// overload 1: runtime emits w/ array
|
|
|
|
export function defineEmits<EE extends string = string>(
|
|
|
|
emitOptions: EE[]
|
|
|
|
): EmitFn<EE[]>
|
|
|
|
export function defineEmits<E extends EmitsOptions = EmitsOptions>(
|
|
|
|
emitOptions: E
|
|
|
|
): EmitFn<E>
|
2023-03-30 19:24:32 +08:00
|
|
|
export function defineEmits<
|
|
|
|
T extends ((...args: any[]) => any) | Record<string, any[]>
|
|
|
|
>(): T extends (...args: any[]) => any ? T : ShortEmits<T>
|
2020-11-25 04:12:59 +08:00
|
|
|
// implementation
|
2021-06-23 03:02:56 +08:00
|
|
|
export function defineEmits() {
|
2020-11-26 23:01:36 +08:00
|
|
|
if (__DEV__) {
|
2021-06-27 09:11:57 +08:00
|
|
|
warnRuntimeUsage(`defineEmits`)
|
2020-11-25 04:12:59 +08:00
|
|
|
}
|
2020-11-25 05:55:43 +08:00
|
|
|
return null as any
|
2020-11-25 04:12:59 +08:00
|
|
|
}
|
|
|
|
|
2023-03-30 19:24:32 +08:00
|
|
|
type RecordToUnion<T extends Record<string, any>> = T[keyof T]
|
|
|
|
|
|
|
|
type ShortEmits<T extends Record<string, any>> = UnionToIntersection<
|
|
|
|
RecordToUnion<{
|
|
|
|
[K in keyof T]: (evt: K, ...args: T[K]) => void
|
|
|
|
}>
|
|
|
|
>
|
|
|
|
|
2021-06-27 09:11:57 +08:00
|
|
|
/**
|
|
|
|
* Vue `<script setup>` compiler macro for declaring a component's exposed
|
|
|
|
* instance properties when it is accessed by a parent component via template
|
|
|
|
* refs.
|
|
|
|
*
|
2022-01-21 14:18:34 +08:00
|
|
|
* `<script setup>` components are closed by default - i.e. variables inside
|
2021-06-27 09:11:57 +08:00
|
|
|
* the `<script setup>` scope is not exposed to parent unless explicitly exposed
|
|
|
|
* via `defineExpose`.
|
|
|
|
*
|
|
|
|
* This is only usable inside `<script setup>`, is compiled away in the
|
|
|
|
* output and should **not** be actually called at runtime.
|
2023-04-02 10:02:33 +08:00
|
|
|
*
|
|
|
|
* @see {@link https://vuejs.org/api/sfc-script-setup.html#defineexpose}
|
2021-06-27 09:11:57 +08:00
|
|
|
*/
|
2022-01-21 14:18:34 +08:00
|
|
|
export function defineExpose<
|
|
|
|
Exposed extends Record<string, any> = Record<string, any>
|
|
|
|
>(exposed?: Exposed) {
|
2021-06-26 04:18:21 +08:00
|
|
|
if (__DEV__) {
|
2021-06-27 09:11:57 +08:00
|
|
|
warnRuntimeUsage(`defineExpose`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-02 10:02:33 +08:00
|
|
|
/**
|
|
|
|
* Vue `<script setup>` compiler macro for declaring a component's additional
|
|
|
|
* options. This should be used only for options that cannot be expressed via
|
2023-05-11 19:34:27 +08:00
|
|
|
* Composition API - e.g. `inheritAttrs`.
|
2023-04-02 10:02:33 +08:00
|
|
|
*
|
|
|
|
* @see {@link https://vuejs.org/api/sfc-script-setup.html#defineoptions}
|
|
|
|
*/
|
2023-03-28 10:43:51 +08:00
|
|
|
export function defineOptions<
|
|
|
|
RawBindings = {},
|
|
|
|
D = {},
|
|
|
|
C extends ComputedOptions = {},
|
|
|
|
M extends MethodOptions = {},
|
|
|
|
Mixin extends ComponentOptionsMixin = ComponentOptionsMixin,
|
2023-04-03 16:49:16 +08:00
|
|
|
Extends extends ComponentOptionsMixin = ComponentOptionsMixin
|
2023-03-28 10:43:51 +08:00
|
|
|
>(
|
|
|
|
options?: ComponentOptionsWithoutProps<
|
|
|
|
{},
|
|
|
|
RawBindings,
|
|
|
|
D,
|
|
|
|
C,
|
|
|
|
M,
|
|
|
|
Mixin,
|
2023-04-03 16:49:16 +08:00
|
|
|
Extends
|
|
|
|
> & { emits?: undefined; expose?: undefined; slots?: undefined }
|
2023-03-28 10:43:51 +08:00
|
|
|
): void {
|
|
|
|
if (__DEV__) {
|
|
|
|
warnRuntimeUsage(`defineOptions`)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-03 16:49:16 +08:00
|
|
|
export function defineSlots<
|
|
|
|
S extends Record<string, any> = Record<string, any>
|
2023-05-08 11:53:49 +08:00
|
|
|
>(): StrictUnwrapSlotsType<SlotsType<S>> {
|
2023-04-03 16:49:16 +08:00
|
|
|
if (__DEV__) {
|
|
|
|
warnRuntimeUsage(`defineSlots`)
|
|
|
|
}
|
2023-04-08 12:13:05 +08:00
|
|
|
return null as any
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-12-12 17:28:40 +08:00
|
|
|
* Vue `<script setup>` compiler macro for declaring a
|
2023-04-08 12:13:05 +08:00
|
|
|
* two-way binding prop that can be consumed via `v-model` from the parent
|
|
|
|
* component. This will declare a prop with the same name and a corresponding
|
|
|
|
* `update:propName` event.
|
|
|
|
*
|
|
|
|
* If the first argument is a string, it will be used as the prop name;
|
|
|
|
* Otherwise the prop name will default to "modelValue". In both cases, you
|
|
|
|
* can also pass an additional object which will be used as the prop's options.
|
|
|
|
*
|
2023-12-12 17:04:16 +08:00
|
|
|
* The the returned ref behaves differently depending on whether the parent
|
|
|
|
* provided the corresponding v-model props or not:
|
|
|
|
* - If yes, the returned ref's value will always be in sync with the parent
|
|
|
|
* prop.
|
|
|
|
* - If not, the returned ref will behave like a normal local ref.
|
2023-04-08 12:13:05 +08:00
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* ```ts
|
|
|
|
* // default model (consumed via `v-model`)
|
|
|
|
* const modelValue = defineModel<string>()
|
|
|
|
* modelValue.value = "hello"
|
|
|
|
*
|
|
|
|
* // default model with options
|
2023-05-19 07:59:09 +08:00
|
|
|
* const modelValue = defineModel<string>({ required: true })
|
2023-04-08 12:13:05 +08:00
|
|
|
*
|
|
|
|
* // with specified name (consumed via `v-model:count`)
|
|
|
|
* const count = defineModel<number>('count')
|
|
|
|
* count.value++
|
|
|
|
*
|
|
|
|
* // with specified name and default value
|
|
|
|
* const count = defineModel<number>('count', { default: 0 })
|
|
|
|
* ```
|
|
|
|
*/
|
|
|
|
export function defineModel<T>(
|
2023-12-12 16:47:34 +08:00
|
|
|
options: { required: true } & PropOptions<T>
|
2023-04-08 12:13:05 +08:00
|
|
|
): Ref<T>
|
|
|
|
export function defineModel<T>(
|
2023-12-12 16:47:34 +08:00
|
|
|
options: { default: any } & PropOptions<T>
|
2023-04-08 12:13:05 +08:00
|
|
|
): Ref<T>
|
2023-12-12 16:47:34 +08:00
|
|
|
export function defineModel<T>(options?: PropOptions<T>): Ref<T | undefined>
|
2023-04-08 12:13:05 +08:00
|
|
|
export function defineModel<T>(
|
|
|
|
name: string,
|
2023-12-12 16:47:34 +08:00
|
|
|
options: { required: true } & PropOptions<T>
|
2023-04-08 12:13:05 +08:00
|
|
|
): Ref<T>
|
|
|
|
export function defineModel<T>(
|
|
|
|
name: string,
|
2023-12-12 16:47:34 +08:00
|
|
|
options: { default: any } & PropOptions<T>
|
2023-04-08 12:13:05 +08:00
|
|
|
): Ref<T>
|
|
|
|
export function defineModel<T>(
|
|
|
|
name: string,
|
2023-12-12 16:47:34 +08:00
|
|
|
options?: PropOptions<T>
|
2023-04-08 12:13:05 +08:00
|
|
|
): Ref<T | undefined>
|
|
|
|
export function defineModel(): any {
|
|
|
|
if (__DEV__) {
|
|
|
|
warnRuntimeUsage('defineModel')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-27 09:11:57 +08:00
|
|
|
type NotUndefined<T> = T extends undefined ? never : T
|
|
|
|
|
|
|
|
type InferDefaults<T> = {
|
2023-05-17 09:25:48 +08:00
|
|
|
[K in keyof T]?: InferDefault<T, T[K]>
|
2021-06-27 09:11:57 +08:00
|
|
|
}
|
|
|
|
|
2023-05-17 09:25:48 +08:00
|
|
|
type NativeType = null | number | string | boolean | symbol | Function
|
|
|
|
|
|
|
|
type InferDefault<P, T> =
|
|
|
|
| ((props: P) => T & {})
|
|
|
|
| (T extends NativeType ? T : never)
|
2021-11-15 11:09:00 +08:00
|
|
|
|
2023-05-17 09:25:48 +08:00
|
|
|
type PropsWithDefaults<
|
|
|
|
T,
|
|
|
|
Defaults extends InferDefaults<T>,
|
|
|
|
BKeys extends keyof T
|
2023-11-10 15:20:02 +08:00
|
|
|
> = Readonly<Omit<T, keyof Defaults>> & {
|
|
|
|
readonly [K in keyof Defaults]-?: K extends keyof T
|
2022-11-08 10:59:31 +08:00
|
|
|
? Defaults[K] extends undefined
|
2023-05-17 09:25:48 +08:00
|
|
|
? T[K]
|
|
|
|
: NotUndefined<T[K]>
|
2022-11-08 10:59:31 +08:00
|
|
|
: never
|
2023-07-11 18:35:22 +08:00
|
|
|
} & {
|
|
|
|
readonly [K in BKeys]-?: K extends keyof Defaults
|
|
|
|
? Defaults[K] extends undefined
|
|
|
|
? boolean | undefined
|
|
|
|
: boolean
|
|
|
|
: boolean
|
|
|
|
}
|
2023-05-17 09:25:48 +08:00
|
|
|
|
2021-06-27 09:11:57 +08:00
|
|
|
/**
|
|
|
|
* Vue `<script setup>` compiler macro for providing props default values when
|
2021-09-06 06:02:50 +08:00
|
|
|
* using type-based `defineProps` declaration.
|
2021-06-27 09:11:57 +08:00
|
|
|
*
|
|
|
|
* Example usage:
|
|
|
|
* ```ts
|
|
|
|
* withDefaults(defineProps<{
|
|
|
|
* size?: number
|
|
|
|
* labels?: string[]
|
|
|
|
* }>(), {
|
|
|
|
* size: 3,
|
|
|
|
* labels: () => ['default label']
|
|
|
|
* })
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* This is only usable inside `<script setup>`, is compiled away in the output
|
|
|
|
* and should **not** be actually called at runtime.
|
2023-04-02 10:02:33 +08:00
|
|
|
*
|
|
|
|
* @see {@link https://vuejs.org/guide/typescript/composition-api.html#typing-component-props}
|
2021-06-27 09:11:57 +08:00
|
|
|
*/
|
2023-05-17 09:25:48 +08:00
|
|
|
export function withDefaults<
|
|
|
|
T,
|
|
|
|
BKeys extends keyof T,
|
|
|
|
Defaults extends InferDefaults<T>
|
|
|
|
>(
|
|
|
|
props: DefineProps<T, BKeys>,
|
2021-06-27 09:11:57 +08:00
|
|
|
defaults: Defaults
|
2023-05-17 09:25:48 +08:00
|
|
|
): PropsWithDefaults<T, Defaults, BKeys> {
|
2021-06-27 09:11:57 +08:00
|
|
|
if (__DEV__) {
|
|
|
|
warnRuntimeUsage(`withDefaults`)
|
2021-06-26 04:18:21 +08:00
|
|
|
}
|
2021-06-27 09:11:57 +08:00
|
|
|
return null as any
|
2021-06-26 04:18:21 +08:00
|
|
|
}
|
|
|
|
|
2021-06-27 09:11:57 +08:00
|
|
|
export function useSlots(): SetupContext['slots'] {
|
|
|
|
return getContext().slots
|
|
|
|
}
|
|
|
|
|
|
|
|
export function useAttrs(): SetupContext['attrs'] {
|
|
|
|
return getContext().attrs
|
|
|
|
}
|
|
|
|
|
2023-04-08 12:13:05 +08:00
|
|
|
export function useModel<T extends Record<string, any>, K extends keyof T>(
|
|
|
|
props: T,
|
2023-12-12 16:47:34 +08:00
|
|
|
name: K
|
2023-04-08 12:13:05 +08:00
|
|
|
): Ref<T[K]>
|
2023-12-12 16:47:34 +08:00
|
|
|
export function useModel(props: Record<string, any>, name: string): Ref {
|
2023-04-08 12:13:05 +08:00
|
|
|
const i = getCurrentInstance()!
|
|
|
|
if (__DEV__ && !i) {
|
|
|
|
warn(`useModel() called without active instance.`)
|
|
|
|
return ref() as any
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__DEV__ && !(i.propsOptions[0] as NormalizedProps)[name]) {
|
|
|
|
warn(`useModel() called with prop "${name}" which is not declared.`)
|
|
|
|
return ref() as any
|
|
|
|
}
|
|
|
|
|
2023-12-16 12:15:30 +08:00
|
|
|
return customRef((track, trigger) => {
|
|
|
|
let localValue: any
|
|
|
|
watchSyncEffect(() => {
|
|
|
|
const propValue = props[name]
|
|
|
|
if (hasChanged(localValue, propValue)) {
|
|
|
|
localValue = propValue
|
2023-12-12 16:47:34 +08:00
|
|
|
trigger()
|
2023-04-08 12:13:05 +08:00
|
|
|
}
|
2023-12-16 12:15:30 +08:00
|
|
|
})
|
|
|
|
return {
|
|
|
|
get() {
|
|
|
|
track()
|
|
|
|
return localValue
|
|
|
|
},
|
|
|
|
set(value) {
|
|
|
|
const rawProps = i.vnode!.props
|
|
|
|
if (!(rawProps && name in rawProps) && hasChanged(value, localValue)) {
|
|
|
|
localValue = value
|
|
|
|
trigger()
|
|
|
|
}
|
|
|
|
i.emit(`update:${name}`, value)
|
|
|
|
}
|
2023-12-12 16:47:34 +08:00
|
|
|
}
|
2023-12-16 12:15:30 +08:00
|
|
|
})
|
2023-04-08 12:13:05 +08:00
|
|
|
}
|
|
|
|
|
2021-06-23 22:31:32 +08:00
|
|
|
function getContext(): SetupContext {
|
2020-11-26 22:25:35 +08:00
|
|
|
const i = getCurrentInstance()!
|
|
|
|
if (__DEV__ && !i) {
|
|
|
|
warn(`useContext() called without active instance.`)
|
|
|
|
}
|
|
|
|
return i.setupContext || (i.setupContext = createSetupContext(i))
|
2020-11-25 04:12:59 +08:00
|
|
|
}
|
2021-06-23 09:00:26 +08:00
|
|
|
|
2023-04-10 15:06:21 +08:00
|
|
|
/**
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
export function normalizePropsOrEmits(
|
|
|
|
props: ComponentPropsOptions | EmitsOptions
|
|
|
|
) {
|
2023-04-08 12:13:05 +08:00
|
|
|
return isArray(props)
|
|
|
|
? props.reduce(
|
2023-04-10 15:06:21 +08:00
|
|
|
(normalized, p) => ((normalized[p] = null), normalized),
|
2023-04-08 12:13:05 +08:00
|
|
|
{} as ComponentObjectPropsOptions | ObjectEmitsOptions
|
|
|
|
)
|
|
|
|
: props
|
|
|
|
}
|
|
|
|
|
2021-06-27 09:11:57 +08:00
|
|
|
/**
|
|
|
|
* Runtime helper for merging default declarations. Imported by compiled code
|
|
|
|
* only.
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
export function mergeDefaults(
|
2021-09-28 02:24:21 +08:00
|
|
|
raw: ComponentPropsOptions,
|
2021-06-27 09:11:57 +08:00
|
|
|
defaults: Record<string, any>
|
2021-09-28 02:24:21 +08:00
|
|
|
): ComponentObjectPropsOptions {
|
2023-04-08 12:13:05 +08:00
|
|
|
const props = normalizePropsOrEmits(raw)
|
2021-06-27 09:11:57 +08:00
|
|
|
for (const key in defaults) {
|
2023-03-29 22:21:27 +08:00
|
|
|
if (key.startsWith('__skip')) continue
|
|
|
|
let opt = props[key]
|
2021-09-28 02:24:21 +08:00
|
|
|
if (opt) {
|
|
|
|
if (isArray(opt) || isFunction(opt)) {
|
2023-03-29 22:21:27 +08:00
|
|
|
opt = props[key] = { type: opt, default: defaults[key] }
|
2021-09-28 02:24:21 +08:00
|
|
|
} else {
|
|
|
|
opt.default = defaults[key]
|
|
|
|
}
|
|
|
|
} else if (opt === null) {
|
2023-03-29 22:21:27 +08:00
|
|
|
opt = props[key] = { default: defaults[key] }
|
2021-06-27 09:11:57 +08:00
|
|
|
} else if (__DEV__) {
|
|
|
|
warn(`props default key "${key}" has no corresponding declaration.`)
|
|
|
|
}
|
2023-03-29 22:21:27 +08:00
|
|
|
if (opt && defaults[`__skip_${key}`]) {
|
|
|
|
opt.skipFactory = true
|
|
|
|
}
|
2021-06-27 09:11:57 +08:00
|
|
|
}
|
|
|
|
return props
|
2021-06-23 09:00:26 +08:00
|
|
|
}
|
2021-06-29 21:24:12 +08:00
|
|
|
|
2023-04-08 12:13:05 +08:00
|
|
|
/**
|
|
|
|
* Runtime helper for merging model declarations.
|
|
|
|
* Imported by compiled code only.
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
export function mergeModels(
|
|
|
|
a: ComponentPropsOptions | EmitsOptions,
|
|
|
|
b: ComponentPropsOptions | EmitsOptions
|
|
|
|
) {
|
|
|
|
if (!a || !b) return a || b
|
|
|
|
if (isArray(a) && isArray(b)) return a.concat(b)
|
|
|
|
return extend({}, normalizePropsOrEmits(a), normalizePropsOrEmits(b))
|
|
|
|
}
|
|
|
|
|
2021-09-28 02:24:21 +08:00
|
|
|
/**
|
|
|
|
* Used to create a proxy for the rest element when destructuring props with
|
|
|
|
* defineProps().
|
|
|
|
* @internal
|
|
|
|
*/
|
|
|
|
export function createPropsRestProxy(
|
|
|
|
props: any,
|
|
|
|
excludedKeys: string[]
|
|
|
|
): Record<string, any> {
|
|
|
|
const ret: Record<string, any> = {}
|
|
|
|
for (const key in props) {
|
|
|
|
if (!excludedKeys.includes(key)) {
|
|
|
|
Object.defineProperty(ret, key, {
|
|
|
|
enumerable: true,
|
|
|
|
get: () => props[key]
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
2021-06-29 21:24:12 +08:00
|
|
|
/**
|
2021-07-07 02:31:53 +08:00
|
|
|
* `<script setup>` helper for persisting the current instance context over
|
|
|
|
* async/await flows.
|
|
|
|
*
|
|
|
|
* `@vue/compiler-sfc` converts the following:
|
|
|
|
*
|
|
|
|
* ```ts
|
|
|
|
* const x = await foo()
|
|
|
|
* ```
|
|
|
|
*
|
|
|
|
* into:
|
|
|
|
*
|
|
|
|
* ```ts
|
|
|
|
* let __temp, __restore
|
|
|
|
* const x = (([__temp, __restore] = withAsyncContext(() => foo())),__temp=await __temp,__restore(),__temp)
|
|
|
|
* ```
|
|
|
|
* @internal
|
2021-06-29 21:24:12 +08:00
|
|
|
*/
|
2021-07-07 02:31:53 +08:00
|
|
|
export function withAsyncContext(getAwaitable: () => any) {
|
2021-07-07 21:07:19 +08:00
|
|
|
const ctx = getCurrentInstance()!
|
|
|
|
if (__DEV__ && !ctx) {
|
|
|
|
warn(
|
|
|
|
`withAsyncContext called without active current instance. ` +
|
|
|
|
`This is likely a bug.`
|
|
|
|
)
|
|
|
|
}
|
2021-07-07 02:31:53 +08:00
|
|
|
let awaitable = getAwaitable()
|
2021-07-07 21:07:19 +08:00
|
|
|
unsetCurrentInstance()
|
2021-07-07 02:31:53 +08:00
|
|
|
if (isPromise(awaitable)) {
|
|
|
|
awaitable = awaitable.catch(e => {
|
|
|
|
setCurrentInstance(ctx)
|
|
|
|
throw e
|
|
|
|
})
|
2021-06-30 02:21:31 +08:00
|
|
|
}
|
2021-07-07 02:31:53 +08:00
|
|
|
return [awaitable, () => setCurrentInstance(ctx)]
|
2021-06-29 21:24:12 +08:00
|
|
|
}
|