|
|
@@ -1,8 +1,20 @@
|
|
|
-import { isArray, isObject } from '@vue/shared'
|
|
|
+import {
|
|
|
+ extend,
|
|
|
+ isArray,
|
|
|
+ isObject,
|
|
|
+ ShapeFlags,
|
|
|
+ toHandlerKey
|
|
|
+} from '@vue/shared'
|
|
|
import { Component, Data } from '../component'
|
|
|
+import { DirectiveArguments, withDirectives } from '../directives'
|
|
|
+import {
|
|
|
+ resolveDirective,
|
|
|
+ resolveDynamicComponent
|
|
|
+} from '../helpers/resolveAssets'
|
|
|
import {
|
|
|
createVNode,
|
|
|
isVNode,
|
|
|
+ normalizeChildren,
|
|
|
VNode,
|
|
|
VNodeArrayChildren,
|
|
|
VNodeProps
|
|
|
@@ -23,6 +35,8 @@ interface LegacyVNodeProps {
|
|
|
nativeOn?: Record<string, Function | Function[]>
|
|
|
directives?: LegacyVNodeDirective[]
|
|
|
|
|
|
+ // component only
|
|
|
+ props?: Record<string, unknown>
|
|
|
slot?: string
|
|
|
scopedSlots?: Record<string, Function>
|
|
|
}
|
|
|
@@ -56,6 +70,9 @@ export function compatH(
|
|
|
propsOrChildren?: any,
|
|
|
children?: any
|
|
|
): VNode {
|
|
|
+ // to support v2 string component name lookup
|
|
|
+ type = resolveDynamicComponent(type)
|
|
|
+
|
|
|
const l = arguments.length
|
|
|
if (l === 2) {
|
|
|
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
|
|
|
@@ -64,9 +81,11 @@ export function compatH(
|
|
|
return convertLegacySlots(createVNode(type, null, [propsOrChildren]))
|
|
|
}
|
|
|
// props without children
|
|
|
- return convertLegacyDirectives(
|
|
|
- createVNode(type, convertLegacyProps(propsOrChildren)),
|
|
|
- propsOrChildren
|
|
|
+ return convertLegacySlots(
|
|
|
+ convertLegacyDirectives(
|
|
|
+ createVNode(type, convertLegacyProps(propsOrChildren)),
|
|
|
+ propsOrChildren
|
|
|
+ )
|
|
|
)
|
|
|
} else {
|
|
|
// omit props
|
|
|
@@ -87,17 +106,87 @@ export function compatH(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-function convertLegacyProps(props: LegacyVNodeProps): Data & VNodeProps {
|
|
|
- // TODO
|
|
|
- return props as any
|
|
|
+function convertLegacyProps(legacyProps?: LegacyVNodeProps): Data & VNodeProps {
|
|
|
+ const converted: Data & VNodeProps = {}
|
|
|
+
|
|
|
+ for (const key in legacyProps) {
|
|
|
+ if (key === 'attrs' || key === 'domProps' || key === 'props') {
|
|
|
+ extend(converted, legacyProps[key])
|
|
|
+ } else if (key === 'on' || key === 'nativeOn') {
|
|
|
+ const listeners = legacyProps[key]
|
|
|
+ for (const event in listeners) {
|
|
|
+ const handlerKey = toHandlerKey(event)
|
|
|
+ const existing = converted[handlerKey]
|
|
|
+ const incoming = listeners[event]
|
|
|
+ if (existing !== incoming) {
|
|
|
+ converted[handlerKey] = existing
|
|
|
+ ? [].concat(existing as any, incoming as any)
|
|
|
+ : incoming
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ converted[key] = legacyProps[key as keyof LegacyVNodeProps]
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return converted
|
|
|
}
|
|
|
|
|
|
-function convertLegacyDirectives(vnode: VNode, props: LegacyVNodeProps): VNode {
|
|
|
- // TODO
|
|
|
+function convertLegacyDirectives(
|
|
|
+ vnode: VNode,
|
|
|
+ props?: LegacyVNodeProps
|
|
|
+): VNode {
|
|
|
+ if (props && props.directives) {
|
|
|
+ return withDirectives(
|
|
|
+ vnode,
|
|
|
+ props.directives.map(({ name, value, arg, modifiers }) => {
|
|
|
+ return [
|
|
|
+ resolveDirective(name)!,
|
|
|
+ value,
|
|
|
+ arg,
|
|
|
+ modifiers
|
|
|
+ ] as DirectiveArguments[number]
|
|
|
+ })
|
|
|
+ )
|
|
|
+ }
|
|
|
return vnode
|
|
|
}
|
|
|
|
|
|
function convertLegacySlots(vnode: VNode): VNode {
|
|
|
- // TODO
|
|
|
+ const { props, children } = vnode
|
|
|
+
|
|
|
+ let slots: Record<string, any> | undefined
|
|
|
+
|
|
|
+ if (vnode.shapeFlag & ShapeFlags.COMPONENT && isArray(children)) {
|
|
|
+ slots = {}
|
|
|
+ // check "slot" property on vnodes and turn them into v3 function slots
|
|
|
+ for (let i = 0; i < children.length; i++) {
|
|
|
+ const child = children[i]
|
|
|
+ const slotName =
|
|
|
+ (isVNode(child) && child.props && child.props.slot) || 'default'
|
|
|
+ ;(slots[slotName] || (slots[slotName] = [] as any[])).push(child)
|
|
|
+ }
|
|
|
+ if (slots) {
|
|
|
+ for (const key in slots) {
|
|
|
+ const slotChildren = slots[key]
|
|
|
+ slots[key] = () => slotChildren
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const scopedSlots = props && props.scopedSlots
|
|
|
+ if (scopedSlots) {
|
|
|
+ delete props!.scopedSlots
|
|
|
+ if (slots) {
|
|
|
+ extend(slots, scopedSlots)
|
|
|
+ } else {
|
|
|
+ slots = scopedSlots
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (slots) {
|
|
|
+ normalizeChildren(vnode, slots)
|
|
|
+ }
|
|
|
+
|
|
|
return vnode
|
|
|
}
|