refactor: use const enums for flags

This commit is contained in:
Evan You 2019-08-22 11:12:37 -04:00
parent f26cd5dfe4
commit f3e9848bb2
11 changed files with 144 additions and 130 deletions

View File

@ -0,0 +1 @@
// TODO

View File

@ -3,9 +3,9 @@ import { ReactiveEffect, UnwrapRef, reactive, immutable } from '@vue/reactivity'
import { EMPTY_OBJ, isFunction, capitalize, invokeHandlers } from '@vue/shared' import { EMPTY_OBJ, isFunction, capitalize, invokeHandlers } from '@vue/shared'
import { RenderProxyHandlers } from './componentProxy' import { RenderProxyHandlers } from './componentProxy'
import { ComponentPropsOptions, ExtractPropTypes } from './componentProps' import { ComponentPropsOptions, ExtractPropTypes } from './componentProps'
import { PROPS, DYNAMIC_SLOTS, FULL_PROPS } from './patchFlags'
import { Slots } from './componentSlots' import { Slots } from './componentSlots'
import { STATEFUL_COMPONENT } from './typeFlags' import { PatchFlags } from './patchFlags'
import { ShapeFlags } from './shapeFlags'
export type Data = { [key: string]: unknown } export type Data = { [key: string]: unknown }
@ -302,7 +302,7 @@ export function renderComponentRoot(instance: ComponentInstance): VNode {
parent, parent,
root root
} = instance } = instance
if (vnode.shapeFlag & STATEFUL_COMPONENT) { if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
return normalizeVNode( return normalizeVNode(
(instance.render as RenderFunction).call(renderProxy, props, setupContext) (instance.render as RenderFunction).call(renderProxy, props, setupContext)
) )
@ -332,15 +332,15 @@ export function shouldUpdateComponent(
const { props: prevProps, children: prevChildren } = prevVNode const { props: prevProps, children: prevChildren } = prevVNode
const { props: nextProps, children: nextChildren, patchFlag } = nextVNode const { props: nextProps, children: nextChildren, patchFlag } = nextVNode
if (patchFlag) { if (patchFlag) {
if (patchFlag & DYNAMIC_SLOTS) { if (patchFlag & PatchFlags.DYNAMIC_SLOTS) {
// slot content that references values that might have changed, // slot content that references values that might have changed,
// e.g. in a v-for // e.g. in a v-for
return true return true
} }
if (patchFlag & FULL_PROPS) { if (patchFlag & PatchFlags.FULL_PROPS) {
// presence of this flag indicates props are always non-null // presence of this flag indicates props are always non-null
return hasPropsChanged(prevProps as Data, nextProps as Data) return hasPropsChanged(prevProps as Data, nextProps as Data)
} else if (patchFlag & PROPS) { } else if (patchFlag & PatchFlags.PROPS) {
const dynamicProps = nextVNode.dynamicProps as string[] const dynamicProps = nextVNode.dynamicProps as string[]
for (let i = 0; i < dynamicProps.length; i++) { for (let i = 0; i < dynamicProps.length; i++) {
const key = dynamicProps[i] const key = dynamicProps[i]

View File

@ -12,7 +12,7 @@ import {
} from '@vue/shared' } from '@vue/shared'
import { warn } from './warning' import { warn } from './warning'
import { Data, ComponentInstance } from './component' import { Data, ComponentInstance } from './component'
import { FULL_PROPS } from './patchFlags' import { PatchFlags } from './patchFlags'
export type ComponentPropsOptions<P = Data> = { export type ComponentPropsOptions<P = Data> = {
[K in keyof P]: Prop<P[K]> | null [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 // in case of dynamic props, check if we need to delete keys from
// the props proxy // the props proxy
const { patchFlag } = instance.vnode 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) const rawInitialProps = toRaw(propsProxy)
for (const key in rawInitialProps) { for (const key in rawInitialProps) {
if (!props.hasOwnProperty(key)) { if (!props.hasOwnProperty(key)) {

View File

@ -1,7 +1,7 @@
import { ComponentInstance } from './component' import { ComponentInstance } from './component'
import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode' import { VNode, NormalizedChildren, normalizeVNode, VNodeChild } from './vnode'
import { isArray, isFunction } from '@vue/shared' import { isArray, isFunction } from '@vue/shared'
import { SLOTS_CHILDREN } from './typeFlags' import { ShapeFlags } from './shapeFlags'
export type Slot = (...args: any[]) => VNode[] export type Slot = (...args: any[]) => VNode[]
export type Slots = Readonly<{ export type Slots = Readonly<{
@ -24,7 +24,7 @@ export function resolveSlots(
children: NormalizedChildren children: NormalizedChildren
) { ) {
let slots: Slots | void let slots: Slots | void
if (instance.vnode.shapeFlag & SLOTS_CHILDREN) { if (instance.vnode.shapeFlag & ShapeFlags.SLOTS_CHILDREN) {
if ((children as any)._normalized) { if ((children as any)._normalized) {
// pre-normalized slots object generated by compiler // pre-normalized slots object generated by compiler
slots = children as Slots slots = children as Slots

View File

@ -21,15 +21,6 @@ import {
isReservedProp, isReservedProp,
isFunction isFunction
} from '@vue/shared' } from '@vue/shared'
import {
TEXT,
CLASS,
STYLE,
PROPS,
KEYED,
UNKEYED,
FULL_PROPS
} from './patchFlags'
import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler' import { queueJob, queuePostFlushCb, flushPostFlushCbs } from './scheduler'
import { import {
effect, effect,
@ -41,13 +32,8 @@ import {
} from '@vue/reactivity' } from '@vue/reactivity'
import { resolveProps } from './componentProps' import { resolveProps } from './componentProps'
import { resolveSlots } from './componentSlots' import { resolveSlots } from './componentSlots'
import { import { PatchFlags } from './patchFlags'
ELEMENT, import { ShapeFlags } from './shapeFlags'
STATEFUL_COMPONENT,
FUNCTIONAL_COMPONENT,
TEXT_CHILDREN,
ARRAY_CHILDREN
} from './typeFlags'
const prodEffectOptions = { const prodEffectOptions = {
scheduler: queueJob scheduler: queueJob
@ -167,7 +153,7 @@ export function createRenderer(options: RendererOptions) {
) )
break break
default: default:
if (shapeFlag & ELEMENT) { if (shapeFlag & ShapeFlags.ELEMENT) {
processElement( processElement(
n1, n1,
n2, n2,
@ -180,8 +166,8 @@ export function createRenderer(options: RendererOptions) {
} else { } else {
if ( if (
__DEV__ && __DEV__ &&
!(shapeFlag & STATEFUL_COMPONENT) && !(shapeFlag & ShapeFlags.STATEFUL_COMPONENT) &&
!(shapeFlag & FUNCTIONAL_COMPONENT) !(shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
) { ) {
// TODO warn invalid node type // TODO warn invalid node type
debugger debugger
@ -269,9 +255,9 @@ export function createRenderer(options: RendererOptions) {
hostPatchProp(el, key, props[key], null, isSVG) hostPatchProp(el, key, props[key], null, isSVG)
} }
} }
if (shapeFlag & TEXT_CHILDREN) { if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
hostSetElementText(el, vnode.children as string) hostSetElementText(el, vnode.children as string)
} else if (shapeFlag & ARRAY_CHILDREN) { } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
mountChildren( mountChildren(
vnode.children as VNodeChildren, vnode.children as VNodeChildren,
el, 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 // 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) // (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 // element props contain dynamic keys, full diff needed
patchProps(el, n2, oldProps, newProps, parentComponent, isSVG) patchProps(el, n2, oldProps, newProps, parentComponent, isSVG)
} else { } else {
// class // class
// this flag is matched when the element has dynamic class bindings. // this flag is matched when the element has dynamic class bindings.
if (patchFlag & CLASS) { if (patchFlag & PatchFlags.CLASS) {
if (oldProps.class !== newProps.class) { if (oldProps.class !== newProps.class) {
hostPatchProp(el, 'class', newProps.class, null, isSVG) hostPatchProp(el, 'class', newProps.class, null, isSVG)
} }
@ -329,7 +315,7 @@ export function createRenderer(options: RendererOptions) {
// style // style
// this flag is matched when the element has dynamic style bindings // 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) hostPatchProp(el, 'style', newProps.style, oldProps.style, isSVG)
} }
@ -339,7 +325,7 @@ export function createRenderer(options: RendererOptions) {
// faster iteration. // faster iteration.
// Note dynamic keys like :[foo]="bar" will cause this optimization to // 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 // 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 // if the flag is present then dynamicProps must be non-null
const propsToUpdate = n2.dynamicProps as string[] const propsToUpdate = n2.dynamicProps as string[]
for (let i = 0; i < propsToUpdate.length; i++) { for (let i = 0; i < propsToUpdate.length; i++) {
@ -365,7 +351,7 @@ export function createRenderer(options: RendererOptions) {
// text // text
// This flag is matched when the element has only dynamic text children. // This flag is matched when the element has only dynamic text children.
// this flag is terminal (i.e. skips children diffing). // this flag is terminal (i.e. skips children diffing).
if (patchFlag & TEXT) { if (patchFlag & PatchFlags.TEXT) {
if (n1.children !== n2.children) { if (n1.children !== n2.children) {
hostSetElementText(el, n2.children as string) hostSetElementText(el, n2.children as string)
} }
@ -495,9 +481,9 @@ export function createRenderer(options: RendererOptions) {
? hostQuerySelector(targetSelector) ? hostQuerySelector(targetSelector)
: null) : null)
if (target != null) { if (target != null) {
if (shapeFlag & TEXT_CHILDREN) { if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
hostSetElementText(target, children as string) hostSetElementText(target, children as string)
} else if (shapeFlag & ARRAY_CHILDREN) { } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
mountChildren( mountChildren(
children as VNodeChildren, children as VNodeChildren,
target, target,
@ -512,7 +498,7 @@ export function createRenderer(options: RendererOptions) {
} else { } else {
// update content // update content
const target = (n2.target = n1.target) const target = (n2.target = n1.target)
if (patchFlag === TEXT) { if (patchFlag === PatchFlags.TEXT) {
hostSetElementText(target, children as string) hostSetElementText(target, children as string)
} else if (!optimized) { } else if (!optimized) {
patchChildren(n1, n2, target, null, parentComponent, isSVG) patchChildren(n1, n2, target, null, parentComponent, isSVG)
@ -524,10 +510,10 @@ export function createRenderer(options: RendererOptions) {
: null) : null)
if (nextTarget != null) { if (nextTarget != null) {
// move content // move content
if (shapeFlag & TEXT_CHILDREN) { if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
hostSetElementText(target, '') hostSetElementText(target, '')
hostSetElementText(nextTarget, children as string) 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++) { for (let i = 0; i < (children as VNode[]).length; i++) {
move((children as VNode[])[i], nextTarget, null) move((children as VNode[])[i], nextTarget, null)
} }
@ -591,7 +577,7 @@ export function createRenderer(options: RendererOptions) {
resolveProps(instance, initialVNode.props, Component.props) resolveProps(instance, initialVNode.props, Component.props)
resolveSlots(instance, initialVNode.children) resolveSlots(instance, initialVNode.children)
// setup stateful // setup stateful
if (initialVNode.shapeFlag & STATEFUL_COMPONENT) { if (initialVNode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
setupStatefulComponent(instance) setupStatefulComponent(instance)
} }
const subTree = (instance.subTree = renderComponentRoot(instance)) const subTree = (instance.subTree = renderComponentRoot(instance))
@ -675,7 +661,7 @@ export function createRenderer(options: RendererOptions) {
// fast path // fast path
const { patchFlag, shapeFlag } = n2 const { patchFlag, shapeFlag } = n2
if (patchFlag) { if (patchFlag) {
if (patchFlag & KEYED) { if (patchFlag & PatchFlags.KEYED) {
// this could be either fully-keyed or mixed (some keyed some not) // this could be either fully-keyed or mixed (some keyed some not)
// presence of patchFlag means children are guaranteed to be arrays // presence of patchFlag means children are guaranteed to be arrays
patchKeyedChildren( patchKeyedChildren(
@ -688,7 +674,7 @@ export function createRenderer(options: RendererOptions) {
optimized optimized
) )
return return
} else if (patchFlag & UNKEYED) { } else if (patchFlag & PatchFlags.UNKEYED) {
// unkeyed // unkeyed
patchUnkeyedChildren( patchUnkeyedChildren(
c1 as VNode[], 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 // text children fast path
if (prevShapeFlag & ARRAY_CHILDREN) { if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
unmountChildren(c1 as VNode[], parentComponent) unmountChildren(c1 as VNode[], parentComponent)
} }
hostSetElementText(container, c2 as string) hostSetElementText(container, c2 as string)
} else { } else {
if (prevShapeFlag & TEXT_CHILDREN) { if (prevShapeFlag & ShapeFlags.TEXT_CHILDREN) {
hostSetElementText(container, '') hostSetElementText(container, '')
if (shapeFlag & ARRAY_CHILDREN) { if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
mountChildren( mountChildren(
c2 as VNodeChildren, c2 as VNodeChildren,
container, container,
@ -721,8 +707,8 @@ export function createRenderer(options: RendererOptions) {
isSVG isSVG
) )
} }
} else if (prevShapeFlag & ARRAY_CHILDREN) { } else if (prevShapeFlag & ShapeFlags.ARRAY_CHILDREN) {
if (shapeFlag & ARRAY_CHILDREN) { if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
// two arrays, cannot assume anything, do full diff // two arrays, cannot assume anything, do full diff
patchKeyedChildren( patchKeyedChildren(
c1 as VNode[], c1 as VNode[],
@ -1020,7 +1006,7 @@ export function createRenderer(options: RendererOptions) {
parentComponent, parentComponent,
shouldRemoveChildren shouldRemoveChildren
) )
} else if (vnode.shapeFlag & ARRAY_CHILDREN) { } else if (vnode.shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
unmountChildren( unmountChildren(
vnode.children as VNode[], vnode.children as VNode[],
parentComponent, parentComponent,

View 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 { export {
VNode,
openBlock, openBlock,
createBlock, createBlock,
createVNode, createVNode,
@ -8,20 +15,14 @@ export {
Fragment, Fragment,
Portal Portal
} from './vnode' } from './vnode'
export { createComponent, getCurrentInstance } from './component'
export { createRenderer } from './createRenderer'
export { nextTick } from './scheduler' 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 './apiReactivity'
export * from './apiWatch' export * from './apiWatch'
export * from './apiLifecycle' export * from './apiLifecycle'
export * from './apiInject' export * from './apiInject'
export * from './patchFlags'
export * from './typeFlags' // Flags
export { PublicPatchFlags as PatchFlags } from './patchFlags'
export { PublicShapeFlags as ShapeFlags } from './shapeFlags'

View File

@ -13,48 +13,63 @@
// Check the `patchElement` function in './createRednerer.ts' to see how the // Check the `patchElement` function in './createRednerer.ts' to see how the
// flags are handled during diff. // flags are handled during diff.
// Indicates an element with dynamic textContent (children fast path) export const enum PatchFlags {
export const TEXT = 1 // Indicates an element with dynamic textContent (children fast path)
TEXT = 1,
// Indicates an element with dynamic class. // Indicates an element with dynamic class.
// The compiler also pre-normalizes the :class binding: // The compiler also pre-normalizes the :class binding:
// - b -> normalize(b) // - b -> normalize(b)
// - ['foo', b] -> 'foo' + normalize(b) // - ['foo', b] -> 'foo' + normalize(b)
// - { a, b: c } -> (a ? a : '') + (b ? c : '') // - { a, b: c } -> (a ? a : '') + (b ? c : '')
// - ['a', b, { c }] -> 'a' + normalize(b) + (c ? c : '') // - ['a', b, { c }] -> 'a' + normalize(b) + (c ? c : '')
export const CLASS = 1 << 1 CLASS = 1 << 1,
// Indicates an element with dynamic style // Indicates an element with dynamic style
// The compiler pre-compiles static string styles into static objects // The compiler pre-compiles static string styles into static objects
// + detects and hoists inline static objects // + detects and hoists inline static objects
// e.g. style="color: red" and :style="{ color: 'red' }" both get hoisted as // e.g. style="color: red" and :style="{ color: 'red' }" both get hoisted as
// const style = { color: 'red' } // const style = { color: 'red' }
// render() { return e('div', { style }) } // render() { return e('div', { style }) }
export const STYLE = 1 << 2 STYLE = 1 << 2,
// Indicates an element that has non-class/style dynamic props. // Indicates an element that has non-class/style dynamic props.
// Can also be on a component that has any dynamic props (includes class/style). // Can also be on a component that has any dynamic props (includes
// when this flag is present, the vnode also has a dynamicProps array that // class/style). when this flag is present, the vnode also has a dynamicProps
// contains the keys of the props that may change so the runtime can diff // array that contains the keys of the props that may change so the runtime
// them faster (without having to worry about removed props) // can diff them faster (without having to worry about removed props)
export const PROPS = 1 << 3 PROPS = 1 << 3,
// Indicates an element with props with dynamic keys. When keys change, a full // 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 // diff is always needed to remove the old key. This flag is mutually
// with CLASS, STYLE and PROPS. // exclusive with CLASS, STYLE and PROPS.
export const FULL_PROPS = 1 << 4 FULL_PROPS = 1 << 4,
// Indicates a fragment or element with keyed or partially-keyed v-for children // Indicates a fragment or element with keyed or partially-keyed v-for
export const KEYED = 1 << 5 // children
KEYED = 1 << 5,
// Indicates a fragment or element that contains unkeyed v-for children // Indicates a fragment or element that contains unkeyed v-for children
export const UNKEYED = 1 << 6 UNKEYED = 1 << 6,
// Indicates a component with dynamic slots (e.g. slot that references a v-for // Indicates a component with dynamic slots (e.g. slot that references a v-for
// iterated value, or dynamic slot names). // iterated value, or dynamic slot names).
// Components with this flag are always force updated. // Components with this flag are always force updated.
export const DYNAMIC_SLOTS = 1 << 7 DYNAMIC_SLOTS = 1 << 7,
// Indicates an element with ref. This includes static string refs because the // 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. // refs object is refreshed on each update and all refs need to set again.
export const REF = 1 << 8 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
}

View File

@ -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
}

View File

@ -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

View File

@ -1,16 +1,9 @@
import { isArray, isFunction, isString, isObject, EMPTY_ARR } from '@vue/shared' import { isArray, isFunction, isString, isObject, EMPTY_ARR } from '@vue/shared'
import { ComponentInstance } from './component' import { ComponentInstance, Data } from './component'
import { HostNode } from './createRenderer' import { HostNode } from './createRenderer'
import { RawSlots } from './componentSlots' import { RawSlots } from './componentSlots'
import { CLASS } from './patchFlags' import { PatchFlags } from './patchFlags'
import { import { ShapeFlags } from './shapeFlags'
ELEMENT,
FUNCTIONAL_COMPONENT,
STATEFUL_COMPONENT,
TEXT_CHILDREN,
ARRAY_CHILDREN,
SLOTS_CHILDREN
} from './typeFlags'
export const Fragment = Symbol('Fragment') export const Fragment = Symbol('Fragment')
export const Text = Symbol('Text') export const Text = Symbol('Text')
@ -108,12 +101,12 @@ export function createVNode(
props = props || null props = props || null
// encode the vnode type information into a bitmap // encode the vnode type information into a bitmap
const typeFlag = isString(type) const shapeFlag = isString(type)
? ELEMENT ? ShapeFlags.ELEMENT
: isObject(type) : isObject(type)
? STATEFUL_COMPONENT ? ShapeFlags.STATEFUL_COMPONENT
: isFunction(type) : isFunction(type)
? FUNCTIONAL_COMPONENT ? ShapeFlags.FUNCTIONAL_COMPONENT
: 0 : 0
const vnode: VNode = { const vnode: VNode = {
@ -126,7 +119,7 @@ export function createVNode(
el: null, el: null,
anchor: null, anchor: null,
target: null, target: null,
shapeFlag: typeFlag, shapeFlag,
patchFlag, patchFlag,
dynamicProps, dynamicProps,
dynamicChildren: null dynamicChildren: null
@ -138,7 +131,7 @@ export function createVNode(
if (props !== null) { if (props !== null) {
// class normalization only needed if the vnode isn't generated by // class normalization only needed if the vnode isn't generated by
// compiler-optimized code // compiler-optimized code
if (props.class != null && !(patchFlag & CLASS)) { if (props.class != null && !(patchFlag & PatchFlags.CLASS)) {
props.class = normalizeClass(props.class) props.class = normalizeClass(props.class)
} }
if (props.style != null) { if (props.style != null) {
@ -153,8 +146,8 @@ export function createVNode(
if ( if (
shouldTrack && shouldTrack &&
(patchFlag || (patchFlag ||
typeFlag & STATEFUL_COMPONENT || shapeFlag & ShapeFlags.STATEFUL_COMPONENT ||
typeFlag & FUNCTIONAL_COMPONENT) shapeFlag & ShapeFlags.FUNCTIONAL_COMPONENT)
) { ) {
trackDynamicNode(vnode) 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 // TODO
return vnode return vnode
} }
@ -196,15 +189,15 @@ export function normalizeChildren(vnode: VNode, children: unknown) {
if (children == null) { if (children == null) {
children = null children = null
} else if (isArray(children)) { } else if (isArray(children)) {
type = ARRAY_CHILDREN type = ShapeFlags.ARRAY_CHILDREN
} else if (typeof children === 'object') { } else if (typeof children === 'object') {
type = SLOTS_CHILDREN type = ShapeFlags.SLOTS_CHILDREN
} else if (isFunction(children)) { } else if (isFunction(children)) {
children = { default: children } children = { default: children }
type = SLOTS_CHILDREN type = ShapeFlags.SLOTS_CHILDREN
} else { } else {
children = isString(children) ? children : children + '' children = isString(children) ? children : children + ''
type = TEXT_CHILDREN type = ShapeFlags.TEXT_CHILDREN
} }
vnode.children = children as NormalizedChildren vnode.children = children as NormalizedChildren
vnode.shapeFlag |= type vnode.shapeFlag |= type