1import { isRegExp, isArray, remove } from 'shared/util'2import { getFirstComponentChild } from 'core/vdom/helpers/index'3import type VNode from 'core/vdom/vnode'4import type { VNodeComponentOptions } from 'types/vnode'5import type { Component } from 'types/component'6import { getComponentName } from '../vdom/create-component'78type CacheEntry = {9 name?: string10 tag?: string11 componentInstance?: Component12}1314type CacheEntryMap = Record<string, CacheEntry | null>1516function _getComponentName(opts?: VNodeComponentOptions): string | null {17 return opts && (getComponentName(opts.Ctor.options as any) || opts.tag)18}1920function matches(21 pattern: string | RegExp | Array<string>,22 name: string23): boolean {24 if (isArray(pattern)) {25 return pattern.indexOf(name) > -126 } else if (typeof pattern === 'string') {27 return pattern.split(',').indexOf(name) > -128 } else if (isRegExp(pattern)) {29 return pattern.test(name)30 }31 /* istanbul ignore next */32 return false33}3435function pruneCache(36 keepAliveInstance: {37 cache: CacheEntryMap38 keys: string[]39 _vnode: VNode40 $vnode: VNode41 },42 filter: Function43) {44 const { cache, keys, _vnode, $vnode } = keepAliveInstance45 for (const key in cache) {46 const entry = cache[key]47 if (entry) {48 const name = entry.name49 if (name && !filter(name)) {50 pruneCacheEntry(cache, key, keys, _vnode)51 }52 }53 }54 $vnode.componentOptions!.children = undefined55}5657function pruneCacheEntry(58 cache: CacheEntryMap,59 key: string,60 keys: Array<string>,61 current?: VNode62) {63 const entry = cache[key]64 if (entry && (!current || entry.tag !== current.tag)) {65 // @ts-expect-error can be undefined66 entry.componentInstance.$destroy()67 }68 cache[key] = null69 remove(keys, key)70}7172const patternTypes: Array<Function> = [String, RegExp, Array]7374// TODO defineComponent75export default {76 name: 'keep-alive',77 abstract: true,7879 props: {80 include: patternTypes,81 exclude: patternTypes,82 max: [String, Number]83 },8485 methods: {86 cacheVNode() {87 const { cache, keys, vnodeToCache, keyToCache } = this88 if (vnodeToCache) {89 const { tag, componentInstance, componentOptions } = vnodeToCache90 cache[keyToCache] = {91 name: _getComponentName(componentOptions),92 tag,93 componentInstance94 }95 keys.push(keyToCache)96 // prune oldest entry97 if (this.max && keys.length > parseInt(this.max)) {98 pruneCacheEntry(cache, keys[0], keys, this._vnode)99 }100 this.vnodeToCache = null101 }102 }103 },104105 created() {106 this.cache = Object.create(null)107 this.keys = []108 },109110 destroyed() {111 for (const key in this.cache) {112 pruneCacheEntry(this.cache, key, this.keys)113 }114 },115116 mounted() {117 this.cacheVNode()118 this.$watch('include', val => {119 pruneCache(this, name => matches(val, name))120 })121 this.$watch('exclude', val => {122 pruneCache(this, name => !matches(val, name))123 })124 },125126 updated() {127 this.cacheVNode()128 },129130 render() {131 const slot = this.$slots.default132 const vnode = getFirstComponentChild(slot)133 const componentOptions = vnode && vnode.componentOptions134 if (componentOptions) {135 // check pattern136 const name = _getComponentName(componentOptions)137 const { include, exclude } = this138 if (139 // not included140 (include && (!name || !matches(include, name))) ||141 // excluded142 (exclude && name && matches(exclude, name))143 ) {144 return vnode145 }146147 const { cache, keys } = this148 const key =149 vnode.key == null150 ? // same constructor may get registered as different local components151 // so cid alone is not enough (#3269)152 componentOptions.Ctor.cid +153 (componentOptions.tag ? `::${componentOptions.tag}` : '')154 : vnode.key155 if (cache[key]) {156 vnode.componentInstance = cache[key].componentInstance157 // make current key freshest158 remove(keys, key)159 keys.push(key)160 } else {161 // delay setting the cache until update162 this.vnodeToCache = vnode163 this.keyToCache = key164 }165166 // @ts-expect-error can vnode.data can be undefined167 vnode.data.keepAlive = true168 }169 return vnode || (slot && slot[0])170 }171}
Findings
✓ No findings reported for this file.