import type { Component } from 'types/component' import type { ComponentOptions } from 'types/options' import type { KNodeComponentOptions, KNodeData } from 'types/knode' /** * @internal */ export default class KNode { tag?: string data: KNodeData | undefined children?: Array | null text?: string elm: Node | undefined ns?: string context?: Component // rendered in this component's scope key: string | number | undefined componentOptions?: KNodeComponentOptions componentInstance?: Component // component instance parent: KNode | undefined | null // component placeholder node // strictly internal raw: boolean // contains raw HTML? (server only) isStatic: boolean // hoisted static node isRootInsert: boolean // necessary for enter transition check isComment: boolean // empty comment placeholder? isCloned: boolean // is a cloned node? isOnce: boolean // is a k-once node? asyncFactory?: Function // async component factory function asyncMeta: Object | void isAsyncPlaceholder: boolean ssrContext?: Object | void fnContext: Component | void // real context vm for functional nodes fnOptions?: ComponentOptions | null // for SSR caching devtoolsMeta?: Object | null // used to store functional render context for devtools fnScopeId?: string | null // functional scope id support isComponentRootElement?: boolean | null // for SSR directives constructor( tag?: string, data?: KNodeData, children?: Array | null, text?: string, elm?: Node, context?: Component, componentOptions?: KNodeComponentOptions, asyncFactory?: Function ) { this.tag = tag this.data = data this.children = children this.text = text this.elm = elm this.ns = undefined this.context = context this.fnContext = undefined this.fnOptions = undefined this.fnScopeId = undefined this.key = data && data.key this.componentOptions = componentOptions this.componentInstance = undefined this.parent = undefined this.raw = false this.isStatic = false this.isRootInsert = true this.isComment = false this.isCloned = false this.isOnce = false this.asyncFactory = asyncFactory this.asyncMeta = undefined this.isAsyncPlaceholder = false } // DEPRECATED: alias for componentInstance for backwards compat. /* istanbul ignore next */ get child(): Component | void { return this.componentInstance } } export const createEmptyKNode = (text: string = '') => { const node = new KNode() node.text = text node.isComment = true return node } export function createTextKNode(val: string | number) { return new KNode(undefined, undefined, undefined, String(val)) } // optimized shallow clone // used for static nodes and slot nodes because they may be reused across // multiple renders, cloning them avoids errors when DOM manipulations rely // on their elm reference. export function cloneKNode(knode: KNode): KNode { const cloned = new KNode( knode.tag, knode.data, // #7975 // clone children array to avoid mutating original in case of cloning // a child. knode.children && knode.children.slice(), knode.text, knode.elm, knode.context, knode.componentOptions, knode.asyncFactory ) cloned.ns = knode.ns cloned.isStatic = knode.isStatic cloned.key = knode.key cloned.isComment = knode.isComment cloned.fnContext = knode.fnContext cloned.fnOptions = knode.fnOptions cloned.fnScopeId = knode.fnScopeId cloned.asyncMeta = knode.asyncMeta cloned.isCloned = true return cloned }