From 91e5a13e6b7f26ea8a84305286c29b67ba9e4c48 Mon Sep 17 00:00:00 2001
From: skirtle <65301168+skirtles-code@users.noreply.github.com>
Date: Tue, 8 Oct 2024 15:33:23 +0100
Subject: [PATCH] Refactor into multiple files
---
.../src/__tests__/base.spec.ts | 245 ++++++++
...-vnode-utils.spec.ts => iterators.spec.ts} | 243 +-------
packages/vue-vnode-utils/src/base.ts | 95 ++++
packages/vue-vnode-utils/src/index.ts | 524 +-----------------
packages/vue-vnode-utils/src/iterators.ts | 414 ++++++++++++++
5 files changed, 791 insertions(+), 730 deletions(-)
create mode 100644 packages/vue-vnode-utils/src/__tests__/base.spec.ts
rename packages/vue-vnode-utils/src/__tests__/{vue-vnode-utils.spec.ts => iterators.spec.ts} (80%)
create mode 100644 packages/vue-vnode-utils/src/base.ts
create mode 100644 packages/vue-vnode-utils/src/iterators.ts
diff --git a/packages/vue-vnode-utils/src/__tests__/base.spec.ts b/packages/vue-vnode-utils/src/__tests__/base.spec.ts
new file mode 100644
index 0000000..cb4f850
--- /dev/null
+++ b/packages/vue-vnode-utils/src/__tests__/base.spec.ts
@@ -0,0 +1,245 @@
+import { describe, expect, it } from 'vitest'
+import {
+ createCommentVNode,
+ createStaticVNode,
+ createVNode,
+ createTextVNode,
+ defineAsyncComponent,
+ Fragment,
+ h,
+ Text
+} from 'vue'
+import {
+ getText,
+ getType,
+ isComment,
+ isComponent,
+ isElement,
+ isFragment,
+ isFunctionalComponent,
+ isStatefulComponent,
+ isStatic,
+ isText
+} from '../base'
+
+describe('isComment', () => {
+ it('isComment - 194a', () => {
+ expect(isComment(undefined)).toBe(true)
+ expect(isComment(null)).toBe(true)
+ expect(isComment(false)).toBe(true)
+ expect(isComment(true)).toBe(true)
+ expect(isComment(createCommentVNode('Text'))).toBe(true)
+
+ expect(isComment('')).toBe(false)
+ expect(isComment(0)).toBe(false)
+ expect(isComment(NaN)).toBe(false)
+ expect(isComment(0n)).toBe(false)
+ expect(isComment(createTextVNode('Text'))).toBe(false)
+ expect(isComment({})).toBe(false)
+ expect(isComment([])).toBe(false)
+ })
+})
+
+describe('isComponent', () => {
+ it('isComponent - b049', () => {
+ expect(isComponent(h({}))).toBe(true)
+ expect(isComponent(h(() => null))).toBe(true)
+ expect(isComponent(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(true)
+
+ expect(isComponent(h('div'))).toBe(false)
+ expect(isComponent(createTextVNode('Text'))).toBe(false)
+ expect(isComponent(createCommentVNode('Text'))).toBe(false)
+ expect(isComponent('')).toBe(false)
+ expect(isComponent({})).toBe(false)
+ expect(isComponent([])).toBe(false)
+ expect(isComponent(null)).toBe(false)
+ expect(isComponent(undefined)).toBe(false)
+ expect(isComponent(false)).toBe(false)
+ expect(isComponent(true)).toBe(false)
+ expect(isComponent(0)).toBe(false)
+ expect(isComponent(7)).toBe(false)
+ })
+})
+
+describe('isFunctionalComponent', () => {
+ it('isFunctionalComponent - 1af7', () => {
+ expect(isFunctionalComponent(h(() => null))).toBe(true)
+
+ expect(isFunctionalComponent(h({}))).toBe(false)
+ expect(isFunctionalComponent(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
+ expect(isFunctionalComponent(h('div'))).toBe(false)
+ expect(isFunctionalComponent(createTextVNode('Text'))).toBe(false)
+ expect(isFunctionalComponent(createCommentVNode('Text'))).toBe(false)
+ expect(isFunctionalComponent('')).toBe(false)
+ expect(isFunctionalComponent({})).toBe(false)
+ expect(isFunctionalComponent([])).toBe(false)
+ expect(isFunctionalComponent(null)).toBe(false)
+ expect(isFunctionalComponent(undefined)).toBe(false)
+ expect(isFunctionalComponent(false)).toBe(false)
+ expect(isFunctionalComponent(true)).toBe(false)
+ expect(isFunctionalComponent(0)).toBe(false)
+ expect(isFunctionalComponent(7)).toBe(false)
+ })
+})
+
+describe('isStatefulComponent', () => {
+ it('isStatefulComponent - ecee', () => {
+ expect(isStatefulComponent(h({}))).toBe(true)
+ expect(isStatefulComponent(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(true)
+
+ expect(isStatefulComponent(h(() => null))).toBe(false)
+ expect(isStatefulComponent(h('div'))).toBe(false)
+ expect(isStatefulComponent(createTextVNode('Text'))).toBe(false)
+ expect(isStatefulComponent(createCommentVNode('Text'))).toBe(false)
+ expect(isStatefulComponent('')).toBe(false)
+ expect(isStatefulComponent({})).toBe(false)
+ expect(isStatefulComponent([])).toBe(false)
+ expect(isStatefulComponent(null)).toBe(false)
+ expect(isStatefulComponent(undefined)).toBe(false)
+ expect(isStatefulComponent(false)).toBe(false)
+ expect(isStatefulComponent(true)).toBe(false)
+ expect(isStatefulComponent(0)).toBe(false)
+ expect(isStatefulComponent(7)).toBe(false)
+ })
+})
+
+describe('isElement', () => {
+ it('isElement - aa0d', () => {
+ expect(isElement(h('div'))).toBe(true)
+
+ expect(isElement(h({}))).toBe(false)
+ expect(isElement(h(() => null))).toBe(false)
+ expect(isElement(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
+ expect(isElement(createTextVNode('Text'))).toBe(false)
+ expect(isElement(createCommentVNode('Text'))).toBe(false)
+ expect(isElement(createVNode(Fragment, null, [h('div')]))).toBe(false)
+ expect(isElement('')).toBe(false)
+ expect(isElement('string')).toBe(false)
+ expect(isElement({})).toBe(false)
+ expect(isElement([])).toBe(false)
+ expect(isElement(null)).toBe(false)
+ expect(isElement(undefined)).toBe(false)
+ expect(isElement(false)).toBe(false)
+ expect(isElement(true)).toBe(false)
+ expect(isElement(0)).toBe(false)
+ expect(isElement(7)).toBe(false)
+ })
+})
+
+describe('isFragment', () => {
+ it('isFragment - d88b', () => {
+ expect(isFragment([])).toBe(true)
+ expect(isFragment(createVNode(Fragment, null, []))).toBe(true)
+
+ expect(isFragment(h({}))).toBe(false)
+ expect(isFragment(h(() => null))).toBe(false)
+ expect(isFragment(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
+ expect(isFragment(h('div'))).toBe(false)
+ expect(isFragment(h('div', null, []))).toBe(false)
+ expect(isFragment(createTextVNode('Text'))).toBe(false)
+ expect(isFragment(createCommentVNode('Text'))).toBe(false)
+ expect(isFragment('')).toBe(false)
+ expect(isFragment('string')).toBe(false)
+ expect(isFragment({})).toBe(false)
+ expect(isFragment(null)).toBe(false)
+ expect(isFragment(undefined)).toBe(false)
+ expect(isFragment(false)).toBe(false)
+ expect(isFragment(true)).toBe(false)
+ expect(isFragment(0)).toBe(false)
+ expect(isFragment(7)).toBe(false)
+ })
+})
+
+describe('isText', () => {
+ it('isText - 7952', () => {
+ expect(isText('')).toBe(true)
+ expect(isText('string')).toBe(true)
+ expect(isText(0)).toBe(true)
+ expect(isText(7)).toBe(true)
+ expect(isText(createTextVNode('Text'))).toBe(true)
+
+ expect(isText(h({}))).toBe(false)
+ expect(isText(h(() => null))).toBe(false)
+ expect(isText(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
+ expect(isText(h('div'))).toBe(false)
+ expect(isText(h('div', null, []))).toBe(false)
+ expect(isText(createCommentVNode('Text'))).toBe(false)
+ expect(isText(createVNode(Fragment, null, []))).toBe(false)
+ expect(isText({})).toBe(false)
+ expect(isText([])).toBe(false)
+ expect(isText(null)).toBe(false)
+ expect(isText(undefined)).toBe(false)
+ expect(isText(false)).toBe(false)
+ expect(isText(true)).toBe(false)
+ })
+})
+
+describe('isStatic', () => {
+ it('isStatic - aabf', () => {
+ expect(isStatic(createStaticVNode('
', 1))).toBe(true)
+
+ expect(isStatic(h({}))).toBe(false)
+ expect(isStatic(h(() => null))).toBe(false)
+ expect(isStatic(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
+ expect(isStatic(h('div'))).toBe(false)
+ expect(isStatic(h('div', null, []))).toBe(false)
+ expect(isStatic(createTextVNode('Text'))).toBe(false)
+ expect(isStatic(createCommentVNode('Text'))).toBe(false)
+ expect(isStatic(createVNode(Fragment, null, []))).toBe(false)
+ expect(isStatic('')).toBe(false)
+ expect(isStatic('string')).toBe(false)
+ expect(isStatic({})).toBe(false)
+ expect(isStatic([])).toBe(false)
+ expect(isStatic(null)).toBe(false)
+ expect(isStatic(undefined)).toBe(false)
+ expect(isStatic(false)).toBe(false)
+ expect(isStatic(true)).toBe(false)
+ expect(isStatic(0)).toBe(false)
+ expect(isStatic(7)).toBe(false)
+ })
+})
+
+describe('getText', () => {
+ it('getText - 50eb', () => {
+ expect(getText('')).toBe('')
+ expect(getText('Text')).toBe('Text')
+ expect(getText(0)).toBe('0')
+ expect(getText(7)).toBe('7')
+ expect(getText(createTextVNode('Text'))).toBe('Text')
+
+ expect(getText(null as any)).toBe(undefined)
+ expect(getText(undefined as any)).toBe(undefined)
+ expect(getText({} as any)).toBe(undefined)
+ expect(getText([] as any)).toBe(undefined)
+ expect(getText(true as any)).toBe(undefined)
+ expect(getText(false as any)).toBe(undefined)
+ expect(getText(h('div'))).toBe(undefined)
+ expect(getText(h({}))).toBe(undefined)
+ })
+})
+
+describe('getType', () => {
+ it('getType - ba43', () => {
+ expect(getType(h({}))).toBe('component')
+ expect(getType(h(() => null))).toBe('component')
+ expect(getType(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe('component')
+ expect(getType(h('div'))).toBe('element')
+ expect(getType(h('div', null, []))).toBe('element')
+ expect(getType(createTextVNode('Text'))).toBe('text')
+ expect(getType(createCommentVNode('Text'))).toBe('comment')
+ expect(getType(createVNode(Fragment, null, []))).toBe('fragment')
+ expect(getType(createStaticVNode('', 1))).toBe('static')
+ expect(getType('')).toBe('text')
+ expect(getType('string')).toBe('text')
+ expect(getType({})).toBe(undefined)
+ expect(getType([])).toBe('fragment')
+ expect(getType(null)).toBe('comment')
+ expect(getType(undefined)).toBe('comment')
+ expect(getType(false)).toBe('comment')
+ expect(getType(true)).toBe('comment')
+ expect(getType(0)).toBe('text')
+ expect(getType(7)).toBe('text')
+ expect(getType(Fragment)).toBe(undefined)
+ expect(getType(Text)).toBe(undefined)
+ })
+})
diff --git a/packages/vue-vnode-utils/src/__tests__/vue-vnode-utils.spec.ts b/packages/vue-vnode-utils/src/__tests__/iterators.spec.ts
similarity index 80%
rename from packages/vue-vnode-utils/src/__tests__/vue-vnode-utils.spec.ts
rename to packages/vue-vnode-utils/src/__tests__/iterators.spec.ts
index 37fa37d..57ca3fa 100644
--- a/packages/vue-vnode-utils/src/__tests__/vue-vnode-utils.spec.ts
+++ b/packages/vue-vnode-utils/src/__tests__/iterators.spec.ts
@@ -6,7 +6,6 @@ import {
createStaticVNode,
createVNode,
createTextVNode,
- defineAsyncComponent,
Fragment,
h,
isVNode,
@@ -16,6 +15,14 @@ import {
type VNodeArrayChildren,
type VNodeChild
} from 'vue'
+import {
+ getText,
+ isComment,
+ isComponent,
+ isElement,
+ isFragment,
+ isText
+} from '../base'
import {
addProps,
ALL_VNODES,
@@ -25,21 +32,11 @@ import {
everyChild,
extractSingleChild,
findChild,
- getText,
- getType,
- isComment,
- isComponent,
- isElement,
isEmpty,
- isFragment,
- isFunctionalComponent,
- isStatefulComponent,
- isStatic,
- isText,
replaceChildren,
SKIP_COMMENTS,
someChild
-} from '../index'
+} from '../iterators'
type TreeNode = string | number | null | undefined | boolean | [string | typeof Fragment | Component, (Record | null)?, TreeNode[]?]
@@ -1583,225 +1580,3 @@ describe('extractSingleChild', () => {
expect(out).toBe(node)
})
})
-
-describe('isComment', () => {
- it('isComment - 194a', () => {
- expect(isComment(undefined)).toBe(true)
- expect(isComment(null)).toBe(true)
- expect(isComment(false)).toBe(true)
- expect(isComment(true)).toBe(true)
- expect(isComment(createCommentVNode('Text'))).toBe(true)
-
- expect(isComment('')).toBe(false)
- expect(isComment(0)).toBe(false)
- expect(isComment(NaN)).toBe(false)
- expect(isComment(0n)).toBe(false)
- expect(isComment(createTextVNode('Text'))).toBe(false)
- expect(isComment({})).toBe(false)
- expect(isComment([])).toBe(false)
- })
-})
-
-describe('isComponent', () => {
- it('isComponent - b049', () => {
- expect(isComponent(h({}))).toBe(true)
- expect(isComponent(h(() => null))).toBe(true)
- expect(isComponent(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(true)
-
- expect(isComponent(h('div'))).toBe(false)
- expect(isComponent(createTextVNode('Text'))).toBe(false)
- expect(isComponent(createCommentVNode('Text'))).toBe(false)
- expect(isComponent('')).toBe(false)
- expect(isComponent({})).toBe(false)
- expect(isComponent([])).toBe(false)
- expect(isComponent(null)).toBe(false)
- expect(isComponent(undefined)).toBe(false)
- expect(isComponent(false)).toBe(false)
- expect(isComponent(true)).toBe(false)
- expect(isComponent(0)).toBe(false)
- expect(isComponent(7)).toBe(false)
- })
-})
-
-describe('isFunctionalComponent', () => {
- it('isFunctionalComponent - 1af7', () => {
- expect(isFunctionalComponent(h(() => null))).toBe(true)
-
- expect(isFunctionalComponent(h({}))).toBe(false)
- expect(isFunctionalComponent(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
- expect(isFunctionalComponent(h('div'))).toBe(false)
- expect(isFunctionalComponent(createTextVNode('Text'))).toBe(false)
- expect(isFunctionalComponent(createCommentVNode('Text'))).toBe(false)
- expect(isFunctionalComponent('')).toBe(false)
- expect(isFunctionalComponent({})).toBe(false)
- expect(isFunctionalComponent([])).toBe(false)
- expect(isFunctionalComponent(null)).toBe(false)
- expect(isFunctionalComponent(undefined)).toBe(false)
- expect(isFunctionalComponent(false)).toBe(false)
- expect(isFunctionalComponent(true)).toBe(false)
- expect(isFunctionalComponent(0)).toBe(false)
- expect(isFunctionalComponent(7)).toBe(false)
- })
-})
-
-describe('isStatefulComponent', () => {
- it('isStatefulComponent - ecee', () => {
- expect(isStatefulComponent(h({}))).toBe(true)
- expect(isStatefulComponent(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(true)
-
- expect(isStatefulComponent(h(() => null))).toBe(false)
- expect(isStatefulComponent(h('div'))).toBe(false)
- expect(isStatefulComponent(createTextVNode('Text'))).toBe(false)
- expect(isStatefulComponent(createCommentVNode('Text'))).toBe(false)
- expect(isStatefulComponent('')).toBe(false)
- expect(isStatefulComponent({})).toBe(false)
- expect(isStatefulComponent([])).toBe(false)
- expect(isStatefulComponent(null)).toBe(false)
- expect(isStatefulComponent(undefined)).toBe(false)
- expect(isStatefulComponent(false)).toBe(false)
- expect(isStatefulComponent(true)).toBe(false)
- expect(isStatefulComponent(0)).toBe(false)
- expect(isStatefulComponent(7)).toBe(false)
- })
-})
-
-describe('isElement', () => {
- it('isElement - aa0d', () => {
- expect(isElement(h('div'))).toBe(true)
-
- expect(isElement(h({}))).toBe(false)
- expect(isElement(h(() => null))).toBe(false)
- expect(isElement(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
- expect(isElement(createTextVNode('Text'))).toBe(false)
- expect(isElement(createCommentVNode('Text'))).toBe(false)
- expect(isElement(createVNode(Fragment, null, [h('div')]))).toBe(false)
- expect(isElement('')).toBe(false)
- expect(isElement('string')).toBe(false)
- expect(isElement({})).toBe(false)
- expect(isElement([])).toBe(false)
- expect(isElement(null)).toBe(false)
- expect(isElement(undefined)).toBe(false)
- expect(isElement(false)).toBe(false)
- expect(isElement(true)).toBe(false)
- expect(isElement(0)).toBe(false)
- expect(isElement(7)).toBe(false)
- })
-})
-
-describe('isFragment', () => {
- it('isFragment - d88b', () => {
- expect(isFragment([])).toBe(true)
- expect(isFragment(createVNode(Fragment, null, []))).toBe(true)
-
- expect(isFragment(h({}))).toBe(false)
- expect(isFragment(h(() => null))).toBe(false)
- expect(isFragment(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
- expect(isFragment(h('div'))).toBe(false)
- expect(isFragment(h('div', null, []))).toBe(false)
- expect(isFragment(createTextVNode('Text'))).toBe(false)
- expect(isFragment(createCommentVNode('Text'))).toBe(false)
- expect(isFragment('')).toBe(false)
- expect(isFragment('string')).toBe(false)
- expect(isFragment({})).toBe(false)
- expect(isFragment(null)).toBe(false)
- expect(isFragment(undefined)).toBe(false)
- expect(isFragment(false)).toBe(false)
- expect(isFragment(true)).toBe(false)
- expect(isFragment(0)).toBe(false)
- expect(isFragment(7)).toBe(false)
- })
-})
-
-describe('isText', () => {
- it('isText - 7952', () => {
- expect(isText('')).toBe(true)
- expect(isText('string')).toBe(true)
- expect(isText(0)).toBe(true)
- expect(isText(7)).toBe(true)
- expect(isText(createTextVNode('Text'))).toBe(true)
-
- expect(isText(h({}))).toBe(false)
- expect(isText(h(() => null))).toBe(false)
- expect(isText(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
- expect(isText(h('div'))).toBe(false)
- expect(isText(h('div', null, []))).toBe(false)
- expect(isText(createCommentVNode('Text'))).toBe(false)
- expect(isText(createVNode(Fragment, null, []))).toBe(false)
- expect(isText({})).toBe(false)
- expect(isText([])).toBe(false)
- expect(isText(null)).toBe(false)
- expect(isText(undefined)).toBe(false)
- expect(isText(false)).toBe(false)
- expect(isText(true)).toBe(false)
- })
-})
-
-describe('isStatic', () => {
- it('isStatic - aabf', () => {
- expect(isStatic(createStaticVNode('', 1))).toBe(true)
-
- expect(isStatic(h({}))).toBe(false)
- expect(isStatic(h(() => null))).toBe(false)
- expect(isStatic(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe(false)
- expect(isStatic(h('div'))).toBe(false)
- expect(isStatic(h('div', null, []))).toBe(false)
- expect(isStatic(createTextVNode('Text'))).toBe(false)
- expect(isStatic(createCommentVNode('Text'))).toBe(false)
- expect(isStatic(createVNode(Fragment, null, []))).toBe(false)
- expect(isStatic('')).toBe(false)
- expect(isStatic('string')).toBe(false)
- expect(isStatic({})).toBe(false)
- expect(isStatic([])).toBe(false)
- expect(isStatic(null)).toBe(false)
- expect(isStatic(undefined)).toBe(false)
- expect(isStatic(false)).toBe(false)
- expect(isStatic(true)).toBe(false)
- expect(isStatic(0)).toBe(false)
- expect(isStatic(7)).toBe(false)
- })
-})
-
-describe('getText', () => {
- it('getText - 50eb', () => {
- expect(getText('')).toBe('')
- expect(getText('Text')).toBe('Text')
- expect(getText(0)).toBe('0')
- expect(getText(7)).toBe('7')
- expect(getText(createTextVNode('Text'))).toBe('Text')
-
- expect(getText(null as any)).toBe(undefined)
- expect(getText(undefined as any)).toBe(undefined)
- expect(getText({} as any)).toBe(undefined)
- expect(getText([] as any)).toBe(undefined)
- expect(getText(true as any)).toBe(undefined)
- expect(getText(false as any)).toBe(undefined)
- expect(getText(h('div'))).toBe(undefined)
- expect(getText(h({}))).toBe(undefined)
- })
-})
-
-describe('getType', () => {
- it('getType - ba43', () => {
- expect(getType(h({}))).toBe('component')
- expect(getType(h(() => null))).toBe('component')
- expect(getType(h(defineAsyncComponent(() => Promise.resolve({}))))).toBe('component')
- expect(getType(h('div'))).toBe('element')
- expect(getType(h('div', null, []))).toBe('element')
- expect(getType(createTextVNode('Text'))).toBe('text')
- expect(getType(createCommentVNode('Text'))).toBe('comment')
- expect(getType(createVNode(Fragment, null, []))).toBe('fragment')
- expect(getType(createStaticVNode('', 1))).toBe('static')
- expect(getType('')).toBe('text')
- expect(getType('string')).toBe('text')
- expect(getType({})).toBe(undefined)
- expect(getType([])).toBe('fragment')
- expect(getType(null)).toBe('comment')
- expect(getType(undefined)).toBe('comment')
- expect(getType(false)).toBe('comment')
- expect(getType(true)).toBe('comment')
- expect(getType(0)).toBe('text')
- expect(getType(7)).toBe('text')
- expect(getType(Fragment)).toBe(undefined)
- expect(getType(Text)).toBe(undefined)
- })
-})
diff --git a/packages/vue-vnode-utils/src/base.ts b/packages/vue-vnode-utils/src/base.ts
new file mode 100644
index 0000000..90690e9
--- /dev/null
+++ b/packages/vue-vnode-utils/src/base.ts
@@ -0,0 +1,95 @@
+import {
+ Comment as CommentVNode,
+ type Component,
+ type ComponentOptions,
+ Fragment as FragmentVNode,
+ type FunctionalComponent,
+ isVNode,
+ Static as StaticVNode,
+ Text as TextVNode,
+ type VNode,
+ type VNodeArrayChildren
+} from 'vue'
+
+export const isComment = (vnode: unknown): vnode is (null | undefined | boolean | (VNode & { type: typeof CommentVNode })) => {
+ return getType(vnode) === 'comment'
+}
+
+export const isComponent = (vnode: unknown): vnode is (VNode & { type: Component }) => {
+ return getType(vnode) === 'component'
+}
+
+export const isElement = (vnode: unknown): vnode is (VNode & { type: string }) => {
+ return getType(vnode) === 'element'
+}
+
+export const isFragment = (vnode: unknown): vnode is ((VNode & { type: typeof FragmentVNode }) | VNodeArrayChildren) => {
+ return getType(vnode) === 'fragment'
+}
+
+export const isFunctionalComponent = (vnode: unknown): vnode is (VNode & { type: FunctionalComponent }) => {
+ return isComponent(vnode) && typeof vnode.type === 'function'
+}
+
+export const isStatefulComponent = (vnode: unknown): vnode is (VNode & { type: ComponentOptions }) => {
+ return isComponent(vnode) && typeof vnode.type === 'object'
+}
+
+export const isStatic = (vnode: unknown): vnode is (VNode & { type: typeof StaticVNode }) => {
+ return getType(vnode) === 'static'
+}
+
+export const isText = (vnode: unknown): vnode is (string | number | (VNode & { type: typeof TextVNode })) => {
+ return getType(vnode) === 'text'
+}
+
+export const getText = (vnode: VNode | string | number): string | undefined => {
+ if (typeof vnode === 'string') {
+ return vnode
+ }
+
+ if (typeof vnode === 'number') {
+ return String(vnode)
+ }
+
+ if (isVNode(vnode) && vnode.type === TextVNode) {
+ return String(vnode.children)
+ }
+
+ return undefined
+}
+
+export const getType = (vnode: unknown) => {
+ const typeofVNode = typeof vnode
+
+ if (vnode == null || typeofVNode === 'boolean') {
+ return 'comment'
+ } else if (typeofVNode === 'string' || typeofVNode === 'number') {
+ return 'text'
+ } else if (Array.isArray(vnode)) {
+ return 'fragment'
+ }
+
+ if (isVNode(vnode)) {
+ const { type } = vnode
+ const typeofType = typeof type
+
+ if (typeofType === 'symbol') {
+ if (type === FragmentVNode) {
+ return 'fragment'
+ } else if (type === TextVNode) {
+ return 'text'
+ } else if (type === CommentVNode) {
+ return 'comment'
+ } else if (type === StaticVNode) {
+ return 'static'
+ }
+ } else if (typeofType === 'string') {
+ return 'element'
+ } else if (typeofType === 'object' || typeofType === 'function') {
+ return 'component'
+ }
+ }
+
+ return undefined
+}
diff --git a/packages/vue-vnode-utils/src/index.ts b/packages/vue-vnode-utils/src/index.ts
index d55fb8b..e243a73 100644
--- a/packages/vue-vnode-utils/src/index.ts
+++ b/packages/vue-vnode-utils/src/index.ts
@@ -1,496 +1,28 @@
-import {
- cloneVNode,
- Comment as CommentVNode,
- type Component,
- type ComponentOptions,
- createCommentVNode,
- createTextVNode,
- Fragment as FragmentVNode,
- type FunctionalComponent,
- isVNode,
- Static as StaticVNode,
- Text as TextVNode,
- type VNode,
- type VNodeArrayChildren,
- type VNodeChild
-} from 'vue'
-
-export const isComment = (vnode: unknown): vnode is (null | undefined | boolean | (VNode & { type: typeof CommentVNode })) => {
- return getType(vnode) === 'comment'
-}
-
-export const isComponent = (vnode: unknown): vnode is (VNode & { type: Component }) => {
- return getType(vnode) === 'component'
-}
-
-export const isElement = (vnode: unknown): vnode is (VNode & { type: string }) => {
- return getType(vnode) === 'element'
-}
-
-export const isFragment = (vnode: unknown): vnode is ((VNode & { type: typeof FragmentVNode }) | VNodeArrayChildren) => {
- return getType(vnode) === 'fragment'
-}
-
-export const isFunctionalComponent = (vnode: unknown): vnode is (VNode & { type: FunctionalComponent }) => {
- return isComponent(vnode) && typeof vnode.type === 'function'
-}
-
-export const isStatefulComponent = (vnode: unknown): vnode is (VNode & { type: ComponentOptions }) => {
- return isComponent(vnode) && typeof vnode.type === 'object'
-}
-
-export const isStatic = (vnode: unknown): vnode is (VNode & { type: typeof StaticVNode }) => {
- return getType(vnode) === 'static'
-}
-
-export const isText = (vnode: unknown): vnode is (string | number | (VNode & { type: typeof TextVNode })) => {
- return getType(vnode) === 'text'
-}
-
-export const getText = (vnode: VNode | string | number): string | undefined => {
- if (typeof vnode === 'string') {
- return vnode
- }
-
- if (typeof vnode === 'number') {
- return String(vnode)
- }
-
- if (isVNode(vnode) && vnode.type === TextVNode) {
- return String(vnode.children)
- }
-
- return undefined
-}
-
-type ValueTypes = 'string' | 'number' | 'boolean' | 'undefined' | 'symbol' | 'bigint' | 'object' | 'function' | 'array' | 'date' | 'regexp' | 'vnode' | 'null'
-
-const typeOf = (value: unknown) => {
- let t: ValueTypes = typeof value
-
- if (t === 'object') {
- if (value === null) {
- t = 'null'
- } else if (Array.isArray(value)) {
- t = 'array'
- } else if (isVNode(value)) {
- t = 'vnode'
- } else if (value instanceof Date) {
- t = 'date'
- } else if (value instanceof RegExp) {
- t = 'regexp'
- }
- }
-
- return t
-}
-
-const warn = (method: string, msg: string) => {
- console.warn(`[${method}] ${msg}`)
-}
-
-const checkArguments = (method: string, passed: unknown[], expected: string[]) => {
- for (let index = 0; index < passed.length; ++index) {
- const t = typeOf(passed[index])
- const expect = expected[index]
-
- if (expect !== t) {
- warn(method, `Argument ${index + 1} was ${t}, should be ${expect}`)
- }
- }
-}
-
-export const getType = (vnode: unknown) => {
- const typeofVNode = typeof vnode
-
- if (vnode == null || typeofVNode === 'boolean') {
- return 'comment'
- } else if (typeofVNode === 'string' || typeofVNode === 'number') {
- return 'text'
- } else if (Array.isArray(vnode)) {
- return 'fragment'
- }
-
- if (isVNode(vnode)) {
- const { type } = vnode
- const typeofType = typeof type
-
- if (typeofType === 'symbol') {
- if (type === FragmentVNode) {
- return 'fragment'
- } else if (type === TextVNode) {
- return 'text'
- } else if (type === CommentVNode) {
- return 'comment'
- } else if (type === StaticVNode) {
- return 'static'
- }
- } else if (typeofType === 'string') {
- return 'element'
- } else if (typeofType === 'object' || typeofType === 'function') {
- return 'component'
- }
- }
-
- return undefined
-}
-
-const isEmptyObject = (obj: Record) => {
- for (const prop in obj) {
- return false
- }
-
- return true
-}
-
-const getFragmentChildren = (fragmentVNode: VNode | VNodeArrayChildren): VNodeArrayChildren => {
- if (Array.isArray(fragmentVNode)) {
- return fragmentVNode
- }
-
- const { children } = fragmentVNode
-
- if (Array.isArray(children)) {
- return children
- }
-
- if (__DEV__) {
- warn('getFragmentChildren', `Unknown children for fragment: ${typeOf(children)}`)
- }
-
- return []
-}
-
-export type IterationOptions = {
- element?: boolean
- component?: boolean
- comment?: boolean
- text?: boolean
- static?: boolean
-}
-
-// esbuild can remove an identity function, so long as it uses a function declaration
-function freeze(obj: T): T {
- if (__DEV__) {
- return Object.freeze(obj)
- }
-
- return obj
-}
-
-export const COMPONENTS_AND_ELEMENTS: IterationOptions = /*#__PURE__*/ freeze({
- element: true,
- component: true
-})
-
-export const SKIP_COMMENTS: IterationOptions = /*#__PURE__*/ freeze({
- element: true,
- component: true,
- text: true,
- static: true
-})
-
-export const ALL_VNODES: IterationOptions = /*#__PURE__*/ freeze({
- element: true,
- component: true,
- text: true,
- static: true,
- comment: true
-})
-
-const promoteToVNode = (node: VNode | string | number | boolean | null | undefined | void, options: IterationOptions): VNode | null => {
- const type = getType(node)
-
- // In practice, we don't call this function for fragments, but TS gets unhappy if we don't handle it
- if (!type || type === 'fragment' || !options[type]) {
- return null
- }
-
- if (isVNode(node)) {
- return node
- }
-
- if (type === 'text') {
- return createTextVNode(getText(node as (string | number)))
- }
-
- return createCommentVNode()
-}
-
-export const addProps = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => (Record | null | void),
- options: IterationOptions = COMPONENTS_AND_ELEMENTS
-): VNodeArrayChildren => {
- if (__DEV__) {
- checkArguments('addProps', [children, callback, options], ['array', 'function', 'object'])
- }
-
- return replaceChildrenInternal(children, (vnode) => {
- const props = callback(vnode)
-
- if (__DEV__) {
- const typeofProps = typeOf(props)
-
- if (!['object', 'null', 'undefined'].includes(typeofProps)) {
- warn('addProps', `Callback returned unexpected ${typeofProps}: ${String(props)}`)
- }
- }
-
- if (props && !isEmptyObject(props)) {
- return cloneVNode(vnode, props, true)
- }
- }, options)
-}
-
-export const replaceChildren = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => (VNode | VNodeArrayChildren | string | number | void),
- options: IterationOptions = SKIP_COMMENTS
-): VNodeArrayChildren => {
- if (__DEV__) {
- checkArguments('replaceChildren', [children, callback, options], ['array', 'function', 'object'])
- }
-
- return replaceChildrenInternal(children, callback, options)
-}
-
-const replaceChildrenInternal = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => (VNode | VNodeArrayChildren | string | number | void),
- options: IterationOptions
-): VNodeArrayChildren => {
- let nc: VNodeArrayChildren | null = null
-
- for (let index = 0; index < children.length; ++index) {
- const child = children[index]
-
- if (isFragment(child)) {
- const oldFragmentChildren = getFragmentChildren(child)
- const newFragmentChildren = replaceChildrenInternal(oldFragmentChildren, callback, options)
-
- let newChild: VNodeChild = child
-
- if (oldFragmentChildren !== newFragmentChildren) {
- nc ??= children.slice(0, index)
-
- if (Array.isArray(child)) {
- newChild = newFragmentChildren
- } else {
- newChild = cloneVNode(child)
-
- newChild.children = newFragmentChildren
- }
- }
-
- nc && nc.push(newChild)
- } else {
- const vnode = promoteToVNode(child, options)
-
- if (vnode) {
- const newNodes = callback(vnode) ?? vnode
-
- if (__DEV__) {
- const typeOfNewNodes = typeOf(newNodes)
-
- if (!['array', 'vnode', 'string', 'number', 'undefined'].includes(typeOfNewNodes)) {
- warn('replaceChildren', `Callback returned unexpected ${typeOfNewNodes} ${String(newNodes)}`)
- }
- }
-
- if (newNodes !== child) {
- nc ??= children.slice(0, index)
- }
-
- if (Array.isArray(newNodes)) {
- nc && nc.push(...newNodes)
- } else {
- nc && nc.push(newNodes)
- }
- } else {
- nc && nc.push(child)
- }
- }
- }
-
- return nc ?? children
-}
-
-export const betweenChildren = (
- children: VNodeArrayChildren,
- callback: (previousVNode: VNode, nextVNode: VNode) => (VNode | VNodeArrayChildren | string | number | void),
- options: IterationOptions = SKIP_COMMENTS
-): VNodeArrayChildren => {
- if (__DEV__) {
- checkArguments('betweenChildren', [children, callback, options], ['array', 'function', 'object'])
- }
-
- let previousVNode: VNode | null = null
-
- return replaceChildrenInternal(children, vnode => {
- let insertedNodes: VNode | VNodeArrayChildren | string | number | void = undefined
-
- if (previousVNode) {
- insertedNodes = callback(previousVNode, vnode)
-
- if (__DEV__) {
- const typeOfInsertedNodes = typeOf(insertedNodes)
-
- if (!['array', 'vnode', 'string', 'number', 'undefined'].includes(typeOfInsertedNodes)) {
- warn('betweenChildren', `Callback returned unexpected ${typeOfInsertedNodes} ${String(insertedNodes)}`)
- }
- }
- }
-
- previousVNode = vnode
-
- if (insertedNodes == null || (Array.isArray(insertedNodes) && insertedNodes.length === 0)) {
- return
- }
-
- if (Array.isArray(insertedNodes)) {
- return [...insertedNodes, vnode]
- }
-
- return [insertedNodes, vnode]
- }, options)
-}
-
-export const someChild = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => unknown,
- options: IterationOptions = ALL_VNODES
-): boolean => {
- if (__DEV__) {
- checkArguments('someChild', [children, callback, options], ['array', 'function', 'object'])
- }
-
- return someChildInternal(children, callback, options)
-}
-
-const someChildInternal = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => unknown,
- options: IterationOptions
-): boolean => {
- for (const child of children) {
- if (isFragment(child)) {
- if (someChild(getFragmentChildren(child), callback, options)) {
- return true
- }
- } else {
- const vnode = promoteToVNode(child, options)
-
- if (vnode && callback(vnode)) {
- return true
- }
- }
- }
-
- return false
-}
-
-export const everyChild = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => unknown,
- options: IterationOptions = ALL_VNODES
-): boolean => {
- if (__DEV__) {
- checkArguments('everyChild', [children, callback, options], ['array', 'function', 'object'])
- }
-
- return !someChildInternal(children, (vnode) => !callback(vnode), options)
-}
-
-export const eachChild = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => void,
- options: IterationOptions = ALL_VNODES
-): void => {
- if (__DEV__) {
- checkArguments('eachChild', [children, callback, options], ['array', 'function', 'object'])
- }
-
- someChildInternal(children, (vnode) => {
- callback(vnode)
- }, options)
-}
-
-export const findChild = (
- children: VNodeArrayChildren,
- callback: (vnode: VNode) => unknown,
- options: IterationOptions = ALL_VNODES
-): (VNode | undefined) => {
- if (__DEV__) {
- checkArguments('findChild', [children, callback, options], ['array', 'function', 'object'])
- }
-
- let node: VNode | undefined = undefined
-
- someChildInternal(children, (vnode) => {
- if (callback(vnode)) {
- node = vnode
- return true
- }
- }, options)
-
- return node
-}
-
-const COLLAPSIBLE_WHITESPACE_RE = /\S|\u00a0/
-
-export const isEmpty = (children: VNodeArrayChildren): boolean => {
- if (__DEV__) {
- checkArguments('isEmpty', [children], ['array'])
- }
-
- return !someChildInternal(children, (vnode) => {
- if (isText(vnode)) {
- const text = getText(vnode) || ''
-
- return COLLAPSIBLE_WHITESPACE_RE.test(text)
- }
-
- return true
- }, SKIP_COMMENTS)
-}
-
-export const extractSingleChild = (children: VNodeArrayChildren): VNode | undefined => {
- if (__DEV__) {
- checkArguments('extractSingleChild', [children], ['array'])
- }
-
- const node = findChild(children, () => {
- return true
- }, COMPONENTS_AND_ELEMENTS)
-
- if (__DEV__) {
- someChildInternal(children, (vnode) => {
- let warning = ''
-
- // The equality check is valid here as matching nodes can't come from promotions
- if (vnode === node) {
- return false
- }
-
- if (isElement(vnode) || isComponent(vnode)) {
- warning = 'Multiple root nodes found, only one expected'
- } else if (isText(vnode)) {
- const text = getText(vnode) || ''
-
- if (COLLAPSIBLE_WHITESPACE_RE.test(text)) {
- warning = `Non-empty text node:\n'${text}'`
- }
- } else {
- warning = `Encountered unexpected ${getType(vnode)} VNode`
- }
-
- if (warning) {
- warn('extractSingleChild', warning)
- return true
- }
- }, SKIP_COMMENTS)
- }
-
- return node
-}
+export {
+ getText,
+ getType,
+ isComment,
+ isComponent,
+ isElement,
+ isFragment,
+ isFunctionalComponent,
+ isStatefulComponent,
+ isStatic,
+ isText
+} from './base'
+
+export {
+ addProps,
+ ALL_VNODES,
+ betweenChildren,
+ COMPONENTS_AND_ELEMENTS,
+ eachChild,
+ everyChild,
+ extractSingleChild,
+ findChild,
+ isEmpty,
+ type IterationOptions,
+ replaceChildren,
+ SKIP_COMMENTS,
+ someChild
+} from './iterators'
diff --git a/packages/vue-vnode-utils/src/iterators.ts b/packages/vue-vnode-utils/src/iterators.ts
new file mode 100644
index 0000000..7ebecc0
--- /dev/null
+++ b/packages/vue-vnode-utils/src/iterators.ts
@@ -0,0 +1,414 @@
+import {
+ cloneVNode,
+ createCommentVNode,
+ createTextVNode,
+ isVNode,
+ type VNode,
+ type VNodeArrayChildren,
+ type VNodeChild
+} from 'vue'
+import {
+ getText,
+ getType,
+ isComponent,
+ isElement,
+ isFragment,
+ isText
+} from './base'
+
+const warn = (method: string, msg: string) => {
+ console.warn(`[${method}] ${msg}`)
+}
+
+const checkArguments = (method: string, passed: unknown[], expected: string[]) => {
+ for (let index = 0; index < passed.length; ++index) {
+ const t = typeOf(passed[index])
+ const expect = expected[index]
+
+ if (expect !== t) {
+ warn(method, `Argument ${index + 1} was ${t}, should be ${expect}`)
+ }
+ }
+}
+
+const isEmptyObject = (obj: Record) => {
+ for (const prop in obj) {
+ return false
+ }
+
+ return true
+}
+
+type ValueTypes = 'string' | 'number' | 'boolean' | 'undefined' | 'symbol' | 'bigint' | 'object' | 'function' | 'array' | 'date' | 'regexp' | 'vnode' | 'null'
+
+const typeOf = (value: unknown) => {
+ let t: ValueTypes = typeof value
+
+ if (t === 'object') {
+ if (value === null) {
+ t = 'null'
+ } else if (Array.isArray(value)) {
+ t = 'array'
+ } else if (isVNode(value)) {
+ t = 'vnode'
+ } else if (value instanceof Date) {
+ t = 'date'
+ } else if (value instanceof RegExp) {
+ t = 'regexp'
+ }
+ }
+
+ return t
+}
+
+const getFragmentChildren = (fragmentVNode: VNode | VNodeArrayChildren): VNodeArrayChildren => {
+ if (Array.isArray(fragmentVNode)) {
+ return fragmentVNode
+ }
+
+ const { children } = fragmentVNode
+
+ if (Array.isArray(children)) {
+ return children
+ }
+
+ if (__DEV__) {
+ warn('getFragmentChildren', `Unknown children for fragment: ${typeOf(children)}`)
+ }
+
+ return []
+}
+
+export type IterationOptions = {
+ element?: boolean
+ component?: boolean
+ comment?: boolean
+ text?: boolean
+ static?: boolean
+}
+
+// esbuild can remove an identity function, so long as it uses a function declaration
+function freeze(obj: T): T {
+ if (__DEV__) {
+ return Object.freeze(obj)
+ }
+
+ return obj
+}
+
+export const COMPONENTS_AND_ELEMENTS: IterationOptions = /*#__PURE__*/ freeze({
+ element: true,
+ component: true
+})
+
+export const SKIP_COMMENTS: IterationOptions = /*#__PURE__*/ freeze({
+ element: true,
+ component: true,
+ text: true,
+ static: true
+})
+
+export const ALL_VNODES: IterationOptions = /*#__PURE__*/ freeze({
+ element: true,
+ component: true,
+ text: true,
+ static: true,
+ comment: true
+})
+
+const promoteToVNode = (node: VNode | string | number | boolean | null | undefined | void, options: IterationOptions): VNode | null => {
+ const type = getType(node)
+
+ // In practice, we don't call this function for fragments, but TS gets unhappy if we don't handle it
+ if (!type || type === 'fragment' || !options[type]) {
+ return null
+ }
+
+ if (isVNode(node)) {
+ return node
+ }
+
+ if (type === 'text') {
+ return createTextVNode(getText(node as (string | number)))
+ }
+
+ return createCommentVNode()
+}
+
+export const addProps = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => (Record | null | void),
+ options: IterationOptions = COMPONENTS_AND_ELEMENTS
+): VNodeArrayChildren => {
+ if (__DEV__) {
+ checkArguments('addProps', [children, callback, options], ['array', 'function', 'object'])
+ }
+
+ return replaceChildrenInternal(children, (vnode) => {
+ const props = callback(vnode)
+
+ if (__DEV__) {
+ const typeofProps = typeOf(props)
+
+ if (!['object', 'null', 'undefined'].includes(typeofProps)) {
+ warn('addProps', `Callback returned unexpected ${typeofProps}: ${String(props)}`)
+ }
+ }
+
+ if (props && !isEmptyObject(props)) {
+ return cloneVNode(vnode, props, true)
+ }
+ }, options)
+}
+
+export const replaceChildren = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => (VNode | VNodeArrayChildren | string | number | void),
+ options: IterationOptions = SKIP_COMMENTS
+): VNodeArrayChildren => {
+ if (__DEV__) {
+ checkArguments('replaceChildren', [children, callback, options], ['array', 'function', 'object'])
+ }
+
+ return replaceChildrenInternal(children, callback, options)
+}
+
+const replaceChildrenInternal = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => (VNode | VNodeArrayChildren | string | number | void),
+ options: IterationOptions
+): VNodeArrayChildren => {
+ let nc: VNodeArrayChildren | null = null
+
+ for (let index = 0; index < children.length; ++index) {
+ const child = children[index]
+
+ if (isFragment(child)) {
+ const oldFragmentChildren = getFragmentChildren(child)
+ const newFragmentChildren = replaceChildrenInternal(oldFragmentChildren, callback, options)
+
+ let newChild: VNodeChild = child
+
+ if (oldFragmentChildren !== newFragmentChildren) {
+ nc ??= children.slice(0, index)
+
+ if (Array.isArray(child)) {
+ newChild = newFragmentChildren
+ } else {
+ newChild = cloneVNode(child)
+
+ newChild.children = newFragmentChildren
+ }
+ }
+
+ nc && nc.push(newChild)
+ } else {
+ const vnode = promoteToVNode(child, options)
+
+ if (vnode) {
+ const newNodes = callback(vnode) ?? vnode
+
+ if (__DEV__) {
+ const typeOfNewNodes = typeOf(newNodes)
+
+ if (!['array', 'vnode', 'string', 'number', 'undefined'].includes(typeOfNewNodes)) {
+ warn('replaceChildren', `Callback returned unexpected ${typeOfNewNodes} ${String(newNodes)}`)
+ }
+ }
+
+ if (newNodes !== child) {
+ nc ??= children.slice(0, index)
+ }
+
+ if (Array.isArray(newNodes)) {
+ nc && nc.push(...newNodes)
+ } else {
+ nc && nc.push(newNodes)
+ }
+ } else {
+ nc && nc.push(child)
+ }
+ }
+ }
+
+ return nc ?? children
+}
+
+export const betweenChildren = (
+ children: VNodeArrayChildren,
+ callback: (previousVNode: VNode, nextVNode: VNode) => (VNode | VNodeArrayChildren | string | number | void),
+ options: IterationOptions = SKIP_COMMENTS
+): VNodeArrayChildren => {
+ if (__DEV__) {
+ checkArguments('betweenChildren', [children, callback, options], ['array', 'function', 'object'])
+ }
+
+ let previousVNode: VNode | null = null
+
+ return replaceChildrenInternal(children, vnode => {
+ let insertedNodes: VNode | VNodeArrayChildren | string | number | void = undefined
+
+ if (previousVNode) {
+ insertedNodes = callback(previousVNode, vnode)
+
+ if (__DEV__) {
+ const typeOfInsertedNodes = typeOf(insertedNodes)
+
+ if (!['array', 'vnode', 'string', 'number', 'undefined'].includes(typeOfInsertedNodes)) {
+ warn('betweenChildren', `Callback returned unexpected ${typeOfInsertedNodes} ${String(insertedNodes)}`)
+ }
+ }
+ }
+
+ previousVNode = vnode
+
+ if (insertedNodes == null || (Array.isArray(insertedNodes) && insertedNodes.length === 0)) {
+ return
+ }
+
+ if (Array.isArray(insertedNodes)) {
+ return [...insertedNodes, vnode]
+ }
+
+ return [insertedNodes, vnode]
+ }, options)
+}
+
+export const someChild = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => unknown,
+ options: IterationOptions = ALL_VNODES
+): boolean => {
+ if (__DEV__) {
+ checkArguments('someChild', [children, callback, options], ['array', 'function', 'object'])
+ }
+
+ return someChildInternal(children, callback, options)
+}
+
+const someChildInternal = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => unknown,
+ options: IterationOptions
+): boolean => {
+ for (const child of children) {
+ if (isFragment(child)) {
+ if (someChild(getFragmentChildren(child), callback, options)) {
+ return true
+ }
+ } else {
+ const vnode = promoteToVNode(child, options)
+
+ if (vnode && callback(vnode)) {
+ return true
+ }
+ }
+ }
+
+ return false
+}
+
+export const everyChild = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => unknown,
+ options: IterationOptions = ALL_VNODES
+): boolean => {
+ if (__DEV__) {
+ checkArguments('everyChild', [children, callback, options], ['array', 'function', 'object'])
+ }
+
+ return !someChildInternal(children, (vnode) => !callback(vnode), options)
+}
+
+export const eachChild = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => void,
+ options: IterationOptions = ALL_VNODES
+): void => {
+ if (__DEV__) {
+ checkArguments('eachChild', [children, callback, options], ['array', 'function', 'object'])
+ }
+
+ someChildInternal(children, (vnode) => {
+ callback(vnode)
+ }, options)
+}
+
+export const findChild = (
+ children: VNodeArrayChildren,
+ callback: (vnode: VNode) => unknown,
+ options: IterationOptions = ALL_VNODES
+): (VNode | undefined) => {
+ if (__DEV__) {
+ checkArguments('findChild', [children, callback, options], ['array', 'function', 'object'])
+ }
+
+ let node: VNode | undefined = undefined
+
+ someChildInternal(children, (vnode) => {
+ if (callback(vnode)) {
+ node = vnode
+ return true
+ }
+ }, options)
+
+ return node
+}
+
+const COLLAPSIBLE_WHITESPACE_RE = /\S|\u00a0/
+
+export const isEmpty = (children: VNodeArrayChildren): boolean => {
+ if (__DEV__) {
+ checkArguments('isEmpty', [children], ['array'])
+ }
+
+ return !someChildInternal(children, (vnode) => {
+ if (isText(vnode)) {
+ const text = getText(vnode) || ''
+
+ return COLLAPSIBLE_WHITESPACE_RE.test(text)
+ }
+
+ return true
+ }, SKIP_COMMENTS)
+}
+
+export const extractSingleChild = (children: VNodeArrayChildren): VNode | undefined => {
+ if (__DEV__) {
+ checkArguments('extractSingleChild', [children], ['array'])
+ }
+
+ const node = findChild(children, () => {
+ return true
+ }, COMPONENTS_AND_ELEMENTS)
+
+ if (__DEV__) {
+ someChildInternal(children, (vnode) => {
+ let warning = ''
+
+ // The equality check is valid here as matching nodes can't come from promotions
+ if (vnode === node) {
+ return false
+ }
+
+ if (isElement(vnode) || isComponent(vnode)) {
+ warning = 'Multiple root nodes found, only one expected'
+ } else if (isText(vnode)) {
+ const text = getText(vnode) || ''
+
+ if (COLLAPSIBLE_WHITESPACE_RE.test(text)) {
+ warning = `Non-empty text node:\n'${text}'`
+ }
+ } else {
+ warning = `Encountered unexpected ${getType(vnode)} VNode`
+ }
+
+ if (warning) {
+ warn('extractSingleChild', warning)
+ return true
+ }
+ }, SKIP_COMMENTS)
+ }
+
+ return node
+}