import { ShapeFlags, extend } from '@vue/shared' import type { ComponentInternalInstance, ComponentOptions } from '../component' import { ErrorCodes, callWithErrorHandling } from '../errorHandling' import type { VNode } from '../vnode' import { popWarningContext, pushWarningContext } from '../warning' import { DeprecationTypes, isCompatEnabled, warnDeprecation, } from './compatConfig' export const compatModelEventPrefix = `onModelCompat:` const warnedTypes = new WeakSet() export function convertLegacyVModelProps(vnode: VNode): void { const { type, shapeFlag, props, dynamicProps } = vnode const comp = type as ComponentOptions if (shapeFlag & ShapeFlags.COMPONENT && props && 'modelValue' in props) { if ( !isCompatEnabled( DeprecationTypes.COMPONENT_V_MODEL, // this is a special case where we want to use the vnode component's // compat config instead of the current rendering instance (which is the // parent of the component that exposes v-model) { type } as any, ) ) { return } if (__DEV__ && !warnedTypes.has(comp)) { pushWarningContext(vnode) warnDeprecation(DeprecationTypes.COMPONENT_V_MODEL, { type } as any, comp) popWarningContext() warnedTypes.add(comp) } // v3 compiled model code -> v2 compat props // modelValue -> value // onUpdate:modelValue -> onModelCompat:input const model = comp.model || {} applyModelFromMixins(model, comp.mixins) const { prop = 'value', event = 'input' } = model if (prop !== 'modelValue') { props[prop] = props.modelValue delete props.modelValue } // important: update dynamic props if (dynamicProps) { dynamicProps[dynamicProps.indexOf('modelValue')] = prop } props[compatModelEventPrefix + event] = props['onUpdate:modelValue'] delete props['onUpdate:modelValue'] } } function applyModelFromMixins(model: any, mixins?: ComponentOptions[]) { if (mixins) { mixins.forEach(m => { if (m.model) extend(model, m.model) if (m.mixins) applyModelFromMixins(model, m.mixins) }) } } export function compatModelEmit( instance: ComponentInternalInstance, event: string, args: any[], ): void { if (!isCompatEnabled(DeprecationTypes.COMPONENT_V_MODEL, instance)) { return } const props = instance.vnode.props const modelHandler = props && props[compatModelEventPrefix + event] if (modelHandler) { callWithErrorHandling( modelHandler, instance, ErrorCodes.COMPONENT_EVENT_HANDLER, args, ) } }