]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: use const enums for flags
authorEvan You <yyx990803@gmail.com>
Thu, 22 Aug 2019 15:12:37 +0000 (11:12 -0400)
committerEvan You <yyx990803@gmail.com>
Thu, 22 Aug 2019 15:12:37 +0000 (11:12 -0400)
packages/runtime-core/__tests__/vdomComponent.spec.ts
packages/runtime-core/__tests__/vdomOptimizedMode.spec.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentSlots.ts
packages/runtime-core/src/createRenderer.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/patchFlags.ts
packages/runtime-core/src/shapeFlags.ts [new file with mode: 0644]
packages/runtime-core/src/typeFlags.ts [deleted file]
packages/runtime-core/src/vnode.ts

index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..70b786d12ed055a08b57f5cf47f717bf6a266301 100644 (file)
@@ -0,0 +1 @@
+// TODO
index b4008d7e63bba7663dc4337f5f95742d1ae5b04a..9353681c84b150d8919a609946eedaf60e0d600d 100644 (file)
@@ -3,9 +3,9 @@ import { ReactiveEffect, UnwrapRef, reactive, immutable } from '@vue/reactivity'
 import { EMPTY_OBJ, isFunction, capitalize, invokeHandlers } from '@vue/shared'
 import { RenderProxyHandlers } from './componentProxy'
 import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
-import { PROPS, DYNAMIC_SLOTS, FULL_PROPS } from './patchFlags'
 import { Slots } from './componentSlots'
-import { STATEFUL_COMPONENT } from './typeFlags'
+import { PatchFlags } from './patchFlags'
+import { ShapeFlags } from './shapeFlags'
 
 export type Data = { [key: string]: unknown }
 
@@ -302,7 +302,7 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
     parent,
     root
   } = instance
-  if (vnode.shapeFlag & STATEFUL_COMPONENT) {
+  if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
     return normalizeVNode(
       (instance.render as RenderFunction).call(renderProxy, props, setupContext)
     )
@@ -332,15 +332,15 @@ export function shouldUpdateComponent(
   const { props: prevProps, children: prevChildren } = prevVNode
   const { props: nextProps, children: nextChildren, patchFlag } = nextVNode
   if (patchFlag) {
-    if (patchFlag & DYNAMIC_SLOTS) {
+    if (patchFlag & PatchFlags.DYNAMIC_SLOTS) {
       // slot content that references values that might have changed,
       // e.g. in a v-for
       return true
     }
-    if (patchFlag & FULL_PROPS) {
+    if (patchFlag & PatchFlags.FULL_PROPS) {
       // presence of this flag indicates props are always non-null
       return hasPropsChanged(prevProps as Data, nextProps as Data)
-    } else if (patchFlag & PROPS) {
+    } else if (patchFlag & PatchFlags.PROPS) {
       const dynamicProps = nextVNode.dynamicProps as string[]
       for (let i = 0; i < dynamicProps.length; i++) {
         const key = dynamicProps[i]
index cb8ebb2cbd6fd150ce1f91af373857aa721d2ad2..1ef1f3d90ffd56d34d678950804e18b8aa866ed3 100644 (file)
@@ -12,7 +12,7 @@ import {
 } from '@vue/shared'
 import { warn } from './warning'
 import { Data, ComponentInstance } from './component'
-import { FULL_PROPS } from './patchFlags'
+import { PatchFlags } from './patchFlags'
 
 export type ComponentPropsOptions<P = Data> = {
   [K in keyof P]: Prop<P[K]> | null
@@ -167,7 +167,10 @@ export function resolveProps(
   // in case of dynamic props, check if we need to delete keys from
   // the props proxy
   const { patchFlag } = instance.vnode
-  if (propsProxy !== null && (patchFlag === 0 || patchFlag & FULL_PROPS)) {
+  if (
+    propsProxy !== null &&
+    (patchFlag === 0 || patchFlag & PatchFlags.FULL_PROPS)
+  ) {
     const rawInitialProps = toRaw(propsProxy)
     for (const key in rawInitialProps) {
       if (!props.hasOwnProperty(key)) {
index 32f71e7b2bad2d46b2db28d652160917bc8684a5..377832b418903323b62b962937157c142cc28314 100644 (file)
@@ -1,7 +1,7 @@
 import { ComponentInstance } from './component'
 import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode'
 import { isArray, isFunction } from '@vue/shared'
-import { SLOTS_CHILDREN } from './typeFlags'
+import { ShapeFlags } from './shapeFlags'
 
 export type Slot = (...args: any[]) => VNode[]
 export type Slots = Readonly<{
@@ -24,7 +24,7 @@ export function resolveSlots(
   children: NormalizedChildren
 ) {
   let slots: Slots | void
-  if (instance.vnode.shapeFlag & SLOTS_CHILDREN) {
+  if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
     if ((children as any)._normalized) {
       // pre-normalized slots object generated by compiler
       slots = children as Slots
index 565e5728863e6aca7b7af3cc726aeb12faa22ae6..864148291fdd76efe92cd00db841e83e8dc3830c 100644 (file)
@@ -21,15 +21,6 @@ import {
   isReservedProp,
   isFunction
 } from '@vue/shared'
-import {
-  TEXT,
-  CLASS,
-  STYLE,
-  PROPS,
-  KEYED,
-  UNKEYED,
-  FULL_PROPS
-} from './patchFlags'
 import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler'
 import {
   effect,
@@ -41,13 +32,8 @@ import {
 } from '@vue/reactivity'
 import { resolveProps } from './componentProps'
 import { resolveSlots } from './componentSlots'
-import {
-  ELEMENT,
-  STATEFUL_COMPONENT,
-  FUNCTIONAL_COMPONENT,
-  TEXT_CHILDREN,
-  ARRAY_CHILDREN
-} from './typeFlags'
+import { PatchFlags } from './patchFlags'
+import { ShapeFlags } from './shapeFlags'
 
 const prodEffectOptions = {
   scheduler: queueJob
@@ -167,7 +153,7 @@ export function createRenderer(options: RendererOptions) {
         )
         break
       default:
-        if (shapeFlag & ELEMENT) {
+        if (shapeFlag & ShapeFlags.ELEMENT) {
           processElement(
             n1,
             n2,
@@ -180,8 +166,8 @@ export function createRenderer(options: RendererOptions) {
         } else {
           if (
             __DEV__ &&
-            !(shapeFlag & STATEFUL_COMPONENT) &&
-            !(shapeFlag & FUNCTIONAL_COMPONENT)
+            !(shapeFlag & ShapeFlags.STATEFUL_COMPONENT) &&
+            !(shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
           ) {
             // TODO warn invalid node type
             debugger
@@ -269,9 +255,9 @@ export function createRenderer(options: RendererOptions) {
         hostPatchProp(el, key, props[key], null, isSVG)
       }
     }
-    if (shapeFlag & TEXT_CHILDREN) {
+    if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
       hostSetElementText(el, vnode.children as string)
-    } else if (shapeFlag & ARRAY_CHILDREN) {
+    } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
       mountChildren(
         vnode.children as VNodeChildren,
         el,
@@ -315,13 +301,13 @@ export function createRenderer(options: RendererOptions) {
       // in this path old node and new node are guaranteed to have the same shape
       // (i.e. at the exact same position in the source template)
 
-      if (patchFlag & FULL_PROPS) {
+      if (patchFlag & PatchFlags.FULL_PROPS) {
         // element props contain dynamic keys, full diff needed
         patchProps(el, n2, oldProps, newProps, parentComponent, isSVG)
       } else {
         // class
         // this flag is matched when the element has dynamic class bindings.
-        if (patchFlag & CLASS) {
+        if (patchFlag & PatchFlags.CLASS) {
           if (oldProps.class !== newProps.class) {
             hostPatchProp(el, 'class', newProps.class, null, isSVG)
           }
@@ -329,7 +315,7 @@ export function createRenderer(options: RendererOptions) {
 
         // style
         // this flag is matched when the element has dynamic style bindings
-        if (patchFlag & STYLE) {
+        if (patchFlag & PatchFlags.STYLE) {
           hostPatchProp(el, 'style', newProps.style, oldProps.style, isSVG)
         }
 
@@ -339,7 +325,7 @@ export function createRenderer(options: RendererOptions) {
         // faster iteration.
         // Note dynamic keys like :[foo]="bar" will cause this optimization to
         // bail out and go through a full diff because we need to unset the old key
-        if (patchFlag & PROPS) {
+        if (patchFlag & PatchFlags.PROPS) {
           // if the flag is present then dynamicProps must be non-null
           const propsToUpdate = n2.dynamicProps as string[]
           for (let i = 0; i < propsToUpdate.length; i++) {
@@ -365,7 +351,7 @@ export function createRenderer(options: RendererOptions) {
       // text
       // This flag is matched when the element has only dynamic text children.
       // this flag is terminal (i.e. skips children diffing).
-      if (patchFlag & TEXT) {
+      if (patchFlag & PatchFlags.TEXT) {
         if (n1.children !== n2.children) {
           hostSetElementText(el, n2.children as string)
         }
@@ -495,9 +481,9 @@ export function createRenderer(options: RendererOptions) {
         ? hostQuerySelector(targetSelector)
         : null)
       if (target != null) {
-        if (shapeFlag & TEXT_CHILDREN) {
+        if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
           hostSetElementText(target, children as string)
-        } else if (shapeFlag & ARRAY_CHILDREN) {
+        } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
           mountChildren(
             children as VNodeChildren,
             target,
@@ -512,7 +498,7 @@ export function createRenderer(options: RendererOptions) {
     } else {
       // update content
       const target = (n2.target = n1.target)
-      if (patchFlag === TEXT) {
+      if (patchFlag === PatchFlags.TEXT) {
         hostSetElementText(target, children as string)
       } else if (!optimized) {
         patchChildren(n1, n2, target, null, parentComponent, isSVG)
@@ -524,10 +510,10 @@ export function createRenderer(options: RendererOptions) {
           : null)
         if (nextTarget != null) {
           // move content
-          if (shapeFlag & TEXT_CHILDREN) {
+          if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
             hostSetElementText(target, '')
             hostSetElementText(nextTarget, children as string)
-          } else if (shapeFlag & ARRAY_CHILDREN) {
+          } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
             for (let i = 0; i < (children as VNode[]).length; i++) {
               move((children as VNode[])[i], nextTarget, null)
             }
@@ -591,7 +577,7 @@ export function createRenderer(options: RendererOptions) {
         resolveProps(instance, initialVNode.props, Component.props)
         resolveSlots(instance, initialVNode.children)
         // setup stateful
-        if (initialVNode.shapeFlag & STATEFUL_COMPONENT) {
+        if (initialVNode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
           setupStatefulComponent(instance)
         }
         const subTree = (instance.subTree = renderComponentRoot(instance))
@@ -675,7 +661,7 @@ export function createRenderer(options: RendererOptions) {
     // fast path
     const { patchFlag, shapeFlag } = n2
     if (patchFlag) {
-      if (patchFlag & KEYED) {
+      if (patchFlag & PatchFlags.KEYED) {
         // this could be either fully-keyed or mixed (some keyed some not)
         // presence of patchFlag means children are guaranteed to be arrays
         patchKeyedChildren(
@@ -688,7 +674,7 @@ export function createRenderer(options: RendererOptions) {
           optimized
         )
         return
-      } else if (patchFlag & UNKEYED) {
+      } else if (patchFlag & PatchFlags.UNKEYED) {
         // unkeyed
         patchUnkeyedChildren(
           c1 as VNode[],
@@ -703,16 +689,16 @@ export function createRenderer(options: RendererOptions) {
       }
     }
 
-    if (shapeFlag & TEXT_CHILDREN) {
+    if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
       // text children fast path
-      if (prevShapeFlag & ARRAY_CHILDREN) {
+      if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
         unmountChildren(c1 as VNode[], parentComponent)
       }
       hostSetElementText(container, c2 as string)
     } else {
-      if (prevShapeFlag & TEXT_CHILDREN) {
+      if (prevShapeFlag & ShapeFlags.TEXT_CHILDREN) {
         hostSetElementText(container, '')
-        if (shapeFlag & ARRAY_CHILDREN) {
+        if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
           mountChildren(
             c2 as VNodeChildren,
             container,
@@ -721,8 +707,8 @@ export function createRenderer(options: RendererOptions) {
             isSVG
           )
         }
-      } else if (prevShapeFlag & ARRAY_CHILDREN) {
-        if (shapeFlag & ARRAY_CHILDREN) {
+      } else if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
+        if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
           // two arrays, cannot assume anything, do full diff
           patchKeyedChildren(
             c1 as VNode[],
@@ -1020,7 +1006,7 @@ export function createRenderer(options: RendererOptions) {
         parentComponent,
         shouldRemoveChildren
       )
-    } else if (vnode.shapeFlag & ARRAY_CHILDREN) {
+    } else if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
       unmountChildren(
         vnode.children as VNode[],
         parentComponent,
index ee92001a4ae5a35ab10164a0d043f9ed1ca193a0..4a30c80ad9d2452dbb09a3ecc138fc04f760aa88 100644 (file)
@@ -1,5 +1,12 @@
+// Types
+export { VNode } from './vnode'
+export { FunctionalComponent } from './component'
+export { RendererOptions } from './createRenderer'
+export { Slot, Slots } from './componentSlots'
+export { PropType, ComponentPropsOptions } from './componentProps'
+
+// API
 export {
-  VNode,
   openBlock,
   createBlock,
   createVNode,
@@ -8,20 +15,14 @@ export {
   Fragment,
   Portal
 } from './vnode'
-
+export { createComponent, getCurrentInstance } from './component'
+export { createRenderer } from './createRenderer'
 export { nextTick } from './scheduler'
-export {
-  createComponent,
-  getCurrentInstance,
-  FunctionalComponent
-} from './component'
-export { createRenderer, RendererOptions } from './createRenderer'
-export { Slot, Slots } from './componentSlots'
-export { PropType, ComponentPropsOptions } from './componentProps'
-
 export * from './apiReactivity'
 export * from './apiWatch'
 export * from './apiLifecycle'
 export * from './apiInject'
-export * from './patchFlags'
-export * from './typeFlags'
+
+// Flags
+export { PublicPatchFlags as PatchFlags } from './patchFlags'
+export { PublicShapeFlags as ShapeFlags } from './shapeFlags'
index 119111f1c9d852b7890fd3be768bb8671f8fd634..279a00194f34f310ca3073ea5484d61af62449dd 100644 (file)
 // Check the `patchElement` function in './createRednerer.ts' to see how the
 // flags are handled during diff.
 
-// Indicates an element with dynamic textContent (children fast path)
-export const TEXT = 1
-
-// Indicates an element with dynamic class.
-// The compiler also pre-normalizes the :class binding:
-// - b -> normalize(b)
-// - ['foo', b] -> 'foo' + normalize(b)
-// - { a, b: c } -> (a ? a : '') + (b ? c : '')
-// - ['a', b, { c }] -> 'a' + normalize(b) + (c ? c : '')
-export const CLASS = 1 << 1
-
-// Indicates an element with dynamic style
-// The compiler pre-compiles static string styles into static objects
-// + detects and hoists inline static objects
-// e.g. style="color: red" and :style="{ color: 'red' }" both get hoisted as
-//   const style = { color: 'red' }
-//   render() { return e('div', { style }) }
-export const STYLE = 1 << 2
-
-// Indicates an element that has non-class/style dynamic props.
-// Can also be on a component that has any dynamic props (includes class/style).
-// when this flag is present, the vnode also has a dynamicProps array that
-// contains the keys of the props that may change so the runtime can diff
-// them faster (without having to worry about removed props)
-export const PROPS = 1 << 3
-
-// Indicates an element with props with dynamic keys. When keys change, a full
-// diff is always needed to remove the old key. This flag is mutually exclusive
-// with CLASS, STYLE and PROPS.
-export const FULL_PROPS = 1 << 4
-
-// Indicates a fragment or element with keyed or partially-keyed v-for children
-export const KEYED = 1 << 5
-
-// Indicates a fragment or element that contains unkeyed v-for children
-export const UNKEYED = 1 << 6
-
-// Indicates a component with dynamic slots (e.g. slot that references a v-for
-// iterated value, or dynamic slot names).
-// Components with this flag are always force updated.
-export const DYNAMIC_SLOTS = 1 << 7
-
-// Indicates an element with ref. This includes static string refs because the
-// refs object is refreshed on each update and all refs need to set again.
-export const REF = 1 << 8
+export const enum PatchFlags {
+  // Indicates an element with dynamic textContent (children fast path)
+  TEXT = 1,
+
+  // Indicates an element with dynamic class.
+  // The compiler also pre-normalizes the :class binding:
+  // - b -> normalize(b)
+  // - ['foo', b] -> 'foo' + normalize(b)
+  // - { a, b: c } -> (a ? a : '') + (b ? c : '')
+  // - ['a', b, { c }] -> 'a' + normalize(b) + (c ? c : '')
+  CLASS = 1 << 1,
+
+  // Indicates an element with dynamic style
+  // The compiler pre-compiles static string styles into static objects
+  // + detects and hoists inline static objects
+  // e.g. style="color: red" and :style="{ color: 'red' }" both get hoisted as
+  //   const style = { color: 'red' }
+  //   render() { return e('div', { style }) }
+  STYLE = 1 << 2,
+
+  // Indicates an element that has non-class/style dynamic props.
+  // Can also be on a component that has any dynamic props (includes
+  // class/style). when this flag is present, the vnode also has a dynamicProps
+  // array that contains the keys of the props that may change so the runtime
+  // can diff them faster (without having to worry about removed props)
+  PROPS = 1 << 3,
+
+  // Indicates an element with props with dynamic keys. When keys change, a full
+  // diff is always needed to remove the old key. This flag is mutually
+  // exclusive with CLASS, STYLE and PROPS.
+  FULL_PROPS = 1 << 4,
+
+  // Indicates a fragment or element with keyed or partially-keyed v-for
+  // children
+  KEYED = 1 << 5,
+
+  // Indicates a fragment or element that contains unkeyed v-for children
+  UNKEYED = 1 << 6,
+
+  // Indicates a component with dynamic slots (e.g. slot that references a v-for
+  // iterated value, or dynamic slot names).
+  // Components with this flag are always force updated.
+  DYNAMIC_SLOTS = 1 << 7,
+
+  // Indicates an element with ref. This includes static string refs because the
+  // refs object is refreshed on each update and all refs need to set again.
+  REF = 1 << 8
+}
+
+// runtime object for public consumption
+export const PublicPatchFlags = {
+  TEXT: PatchFlags.TEXT,
+  CLASS: PatchFlags.CLASS,
+  STYLE: PatchFlags.STYLE,
+  PROPS: PatchFlags.PROPS,
+  FULL_PROPS: PatchFlags.FULL_PROPS,
+  KEYED: PatchFlags.KEYED,
+  UNKEYED: PatchFlags.UNKEYED,
+  REF: PatchFlags.REF
+}
diff --git a/packages/runtime-core/src/shapeFlags.ts b/packages/runtime-core/src/shapeFlags.ts
new file mode 100644 (file)
index 0000000..173aa90
--- /dev/null
@@ -0,0 +1,20 @@
+// internally the const enum flags are used to avoid overhead of property
+// access
+export const enum ShapeFlags {
+  ELEMENT = 1,
+  FUNCTIONAL_COMPONENT = 1 << 1,
+  STATEFUL_COMPONENT = 1 << 2,
+  TEXT_CHILDREN = 1 << 3,
+  ARRAY_CHILDREN = 1 << 4,
+  SLOTS_CHILDREN = 1 << 5
+}
+
+// but the flags are also exported as an actual object for external use
+export const PublicShapeFlags = {
+  ELEMENT: ShapeFlags.ELEMENT,
+  FUNCTIONAL_COMPONENT: ShapeFlags.FUNCTIONAL_COMPONENT,
+  STATEFUL_COMPONENT: ShapeFlags.STATEFUL_COMPONENT,
+  TEXT_CHILDREN: ShapeFlags.TEXT_CHILDREN,
+  ARRAY_CHILDREN: ShapeFlags.ARRAY_CHILDREN,
+  SLOTS_CHILDREN: ShapeFlags.SLOTS_CHILDREN
+}
diff --git a/packages/runtime-core/src/typeFlags.ts b/packages/runtime-core/src/typeFlags.ts
deleted file mode 100644 (file)
index 14a1931..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-export const ELEMENT = 1
-export const FUNCTIONAL_COMPONENT = 1 << 1
-export const STATEFUL_COMPONENT = 1 << 2
-export const TEXT_CHILDREN = 1 << 3
-export const ARRAY_CHILDREN = 1 << 4
-export const SLOTS_CHILDREN = 1 << 5
index 862bded0368b7455befad4b5f582989cb51f6202..0a07918c3ee749e98dc8cc5ed91a6bee8a888bb5 100644 (file)
@@ -1,16 +1,9 @@
 import { isArray, isFunction, isString, isObject, EMPTY_ARR } from '@vue/shared'
-import { ComponentInstance } from './component'
+import { ComponentInstance, Data } from './component'
 import { HostNode } from './createRenderer'
 import { RawSlots } from './componentSlots'
-import { CLASS } from './patchFlags'
-import {
-  ELEMENT,
-  FUNCTIONAL_COMPONENT,
-  STATEFUL_COMPONENT,
-  TEXT_CHILDREN,
-  ARRAY_CHILDREN,
-  SLOTS_CHILDREN
-} from './typeFlags'
+import { PatchFlags } from './patchFlags'
+import { ShapeFlags } from './shapeFlags'
 
 export const Fragment = Symbol('Fragment')
 export const Text = Symbol('Text')
@@ -108,12 +101,12 @@ export function createVNode(
   props = props || null
 
   // encode the vnode type information into a bitmap
-  const typeFlag = isString(type)
-    ? ELEMENT
+  const shapeFlag = isString(type)
+    ? ShapeFlags.ELEMENT
     : isObject(type)
-      ? STATEFUL_COMPONENT
+      ? ShapeFlags.STATEFUL_COMPONENT
       : isFunction(type)
-        ? FUNCTIONAL_COMPONENT
+        ? ShapeFlags.FUNCTIONAL_COMPONENT
         : 0
 
   const vnode: VNode = {
@@ -126,7 +119,7 @@ export function createVNode(
     el: null,
     anchor: null,
     target: null,
-    shapeFlag: typeFlag,
+    shapeFlag,
     patchFlag,
     dynamicProps,
     dynamicChildren: null
@@ -138,7 +131,7 @@ export function createVNode(
   if (props !== null) {
     // class normalization only needed if the vnode isn't generated by
     // compiler-optimized code
-    if (props.class != null && !(patchFlag & CLASS)) {
+    if (props.class != null && !(patchFlag & PatchFlags.CLASS)) {
       props.class = normalizeClass(props.class)
     }
     if (props.style != null) {
@@ -153,8 +146,8 @@ export function createVNode(
   if (
     shouldTrack &&
     (patchFlag ||
-      typeFlag & STATEFUL_COMPONENT ||
-      typeFlag & FUNCTIONAL_COMPONENT)
+      shapeFlag & ShapeFlags.STATEFUL_COMPONENT ||
+      shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
   ) {
     trackDynamicNode(vnode)
   }
@@ -169,7 +162,7 @@ function trackDynamicNode(vnode: VNode) {
   }
 }
 
-export function cloneVNode(vnode: VNode): VNode {
+export function cloneVNode(vnode: VNode, extraProps?: Data): VNode {
   // TODO
   return vnode
 }
@@ -196,15 +189,15 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
   if (children == null) {
     children = null
   } else if (isArray(children)) {
-    type = ARRAY_CHILDREN
+    type = ShapeFlags.ARRAY_CHILDREN
   } else if (typeof children === 'object') {
-    type = SLOTS_CHILDREN
+    type = ShapeFlags.SLOTS_CHILDREN
   } else if (isFunction(children)) {
     children = { default: children }
-    type = SLOTS_CHILDREN
+    type = ShapeFlags.SLOTS_CHILDREN
   } else {
     children = isString(children) ? children : children + ''
-    type = TEXT_CHILDREN
+    type = ShapeFlags.TEXT_CHILDREN
   }
   vnode.children = children as NormalizedChildren
   vnode.shapeFlag |= type