ranuts 0.1.0-alpha → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/assets/img/sort/bubble.gif +0 -0
  2. package/assets/img/sort/complexity.png +0 -0
  3. package/assets/img/sort/select.gif +0 -0
  4. package/assets/img/sort/sort.png +0 -0
  5. package/assets/img/tree/balanceTree.png +0 -0
  6. package/dist/index.d.ts +15 -8
  7. package/dist/index.js +1078 -44
  8. package/dist/index.js.map +1 -1
  9. package/dist/index.umd.cjs +1 -1
  10. package/dist/index.umd.cjs.map +1 -1
  11. package/dist/src/file/fileInfo.d.ts +7 -0
  12. package/dist/src/file/fs.d.ts +2 -0
  13. package/dist/src/file/readDir.d.ts +6 -0
  14. package/dist/src/file/readFile.d.ts +8 -0
  15. package/dist/src/file/watchFile.d.ts +8 -0
  16. package/dist/src/file/writeFile.d.ts +8 -0
  17. package/dist/src/mode/subscribe.d.ts +16 -0
  18. package/dist/src/ranlog/behavior.d.ts +1 -0
  19. package/dist/src/ranlog/env.d.ts +5 -0
  20. package/dist/src/ranlog/error.d.ts +2 -0
  21. package/dist/src/ranlog/index.d.ts +26 -0
  22. package/dist/src/ranlog/performance.d.ts +21 -0
  23. package/dist/src/ranlog/report.d.ts +7 -0
  24. package/dist/src/ranlog/request.d.ts +18 -0
  25. package/dist/src/ranlog/utils.d.ts +19 -0
  26. package/dist/src/utils/filterObj.d.ts +8 -0
  27. package/dist/src/utils/str2Xml.d.ts +8 -0
  28. package/dist/src/vnode/h.d.ts +6 -0
  29. package/dist/src/vnode/hooks.d.ts +23 -0
  30. package/dist/src/vnode/htmlDomApi.d.ts +33 -0
  31. package/dist/src/vnode/init.d.ts +2 -0
  32. package/dist/src/vnode/is.d.ts +5 -0
  33. package/dist/src/vnode/modules/attributes.d.ts +8 -0
  34. package/dist/src/vnode/modules/class.d.ts +8 -0
  35. package/dist/src/vnode/modules/index.d.ts +7 -0
  36. package/dist/src/vnode/modules/listeners.d.ts +14 -0
  37. package/dist/src/vnode/modules/props.d.ts +8 -0
  38. package/dist/src/vnode/modules/style.d.ts +14 -0
  39. package/dist/src/vnode/vnode.d.ts +31 -0
  40. package/package.json +32 -9
  41. package/readme.md +1 -0
  42. package/src/astParser/Parser.ts +654 -0
  43. package/src/astParser/Tokenizer.ts +447 -0
  44. package/src/astParser/nodeTypes.ts +194 -0
  45. package/src/astParser/utils.ts +27 -0
  46. package/src/babel/parser.ts +10 -0
  47. package/src/colors/fmt.ts +29 -0
  48. package/src/colors/isColorSupported.ts +13 -0
  49. package/src/file/appendFile.ts +29 -0
  50. package/src/file/fileInfo.ts +22 -0
  51. package/src/file/fs.ts +9 -0
  52. package/src/file/readDir.ts +18 -0
  53. package/src/file/readFile.ts +26 -0
  54. package/src/file/watchFile.ts +31 -0
  55. package/src/file/writeFile.ts +38 -0
  56. package/src/mode/subscribe.ts +89 -0
  57. package/src/ran/commit.ts +0 -0
  58. package/src/ran/dom.ts +0 -0
  59. package/src/ran/hooks.ts +0 -0
  60. package/src/ran/reconcile.ts +0 -0
  61. package/src/ran/schedule.ts +0 -0
  62. package/src/ranlog/behavior.ts +5 -0
  63. package/src/ranlog/console.ts +16 -0
  64. package/src/ranlog/env.ts +29 -0
  65. package/src/ranlog/error.ts +11 -0
  66. package/src/ranlog/performance.ts +65 -0
  67. package/src/ranlog/report.ts +33 -0
  68. package/src/ranlog/request.ts +60 -0
  69. package/src/ranlog/utils.ts +92 -0
  70. package/src/ranpack/ast/Declaration.ts +120 -0
  71. package/src/ranpack/ast/Node.ts +7 -0
  72. package/src/ranpack/ast/Reference.ts +32 -0
  73. package/src/ranpack/ast/Scope.ts +80 -0
  74. package/src/ranpack/bundle.ts +50 -0
  75. package/src/ranpack/graph.ts +143 -0
  76. package/src/ranpack/module.ts +431 -0
  77. package/src/ranpack/moduleLoader.ts +73 -0
  78. package/src/ranpack/plugins.ts +70 -0
  79. package/src/ranpack/statement.ts +66 -0
  80. package/src/ranpack/utils/buildScope.ts +77 -0
  81. package/src/ranpack/utils/findReference.ts +36 -0
  82. package/src/ranpack/utils/isFunctionDeclaration.ts +41 -0
  83. package/src/ranpack/utils/makeLegalIdentifier.ts +18 -0
  84. package/src/ranpack/utils/object.ts +8 -0
  85. package/src/ranpack/utils/resolve.ts +32 -0
  86. package/src/ranpack/utils/walk.ts +66 -0
  87. package/src/ranpack/ws.ts +269 -0
  88. package/src/server/connectType.ts +9 -0
  89. package/src/server/encodeUrl.ts +46 -0
  90. package/src/server/escapeHtml.ts +46 -0
  91. package/src/server/get.ts +36 -0
  92. package/src/server/jitter.ts +77 -0
  93. package/src/server/mimeType.ts +858 -0
  94. package/src/server/paresUrl.ts +40 -0
  95. package/src/server/send.ts +89 -0
  96. package/src/server/server.ts +67 -0
  97. package/src/server/status.ts +191 -0
  98. package/src/server/traverse.ts +54 -0
  99. package/src/server/websocket.ts +200 -0
  100. package/src/sort/bubble.ts +21 -0
  101. package/src/sort/bucket.ts +11 -0
  102. package/src/sort/count.ts +10 -0
  103. package/src/sort/heap.ts +10 -0
  104. package/src/sort/insert.ts +20 -0
  105. package/src/sort/merge.ts +35 -0
  106. package/src/sort/quick.ts +50 -0
  107. package/src/sort/radix.ts +11 -0
  108. package/src/sort/randomArray.ts +21 -0
  109. package/src/sort/select.ts +23 -0
  110. package/src/sort/shell.ts +22 -0
  111. package/src/utils/compose.ts +37 -0
  112. package/src/utils/filterObj.ts +21 -0
  113. package/src/utils/mergeObj.ts +12 -0
  114. package/src/utils/startTask.ts +15 -0
  115. package/src/utils/str2Xml.ts +26 -0
  116. package/src/utils/taskEnd.ts +14 -0
  117. package/src/vnode/h.ts +108 -0
  118. package/src/vnode/hooks.ts +25 -0
  119. package/src/vnode/htmlDomApi.ts +199 -0
  120. package/src/vnode/init.ts +429 -0
  121. package/src/vnode/is.ts +17 -0
  122. package/src/vnode/modules/attributes.ts +70 -0
  123. package/src/vnode/modules/class.ts +46 -0
  124. package/src/vnode/modules/listeners.ts +123 -0
  125. package/src/vnode/modules/props.ts +41 -0
  126. package/src/vnode/modules/style.ts +118 -0
  127. package/src/vnode/vnode.ts +65 -0
@@ -0,0 +1,20 @@
1
+ /**
2
+ * @description: 插入排序,维护一个有序的数组,将后面的数字插入到前面的有序数组中国
3
+ * @param {Array} list
4
+ * @return {Array}
5
+ */
6
+ const insert = (list: Array<string>): Array<string> => {
7
+ const { length } = list
8
+ for (let i = 1; i < length; i++) {
9
+ let preIndex = i - 1
10
+ const current = list[i]
11
+ while (preIndex >= 0 && list[preIndex] > current) {
12
+ list[preIndex + 1] = list[preIndex]
13
+ preIndex--
14
+ }
15
+ list[preIndex + 1] = current
16
+ }
17
+ return list
18
+ }
19
+
20
+ export default insert
@@ -0,0 +1,35 @@
1
+ const combine = (left: Array<number>, right: Array<number>) => {
2
+ const list: Array<number> = []
3
+ while (left.length > 0 && right.length > 0) {
4
+ if (left[0] <= right[0]) {
5
+ list.push(left.shift() as number)
6
+ } else {
7
+ list.push(right.shift() as number)
8
+ }
9
+ }
10
+
11
+ while (left.length) {
12
+ list.push(left.shift() as number)
13
+ }
14
+ while (right.length) {
15
+ list.push(right.shift() as number)
16
+ }
17
+ return list
18
+ }
19
+ /**
20
+ * @description: 归并排序
21
+ * @param {Array} list
22
+ * @return {Array}
23
+ */
24
+ const merge = (list: Array<number>): Array<number> => {
25
+ const { length } = list
26
+ if (length < 2) {
27
+ return list
28
+ }
29
+ const middle = Math.floor(length / 2)
30
+ const left = list.slice(0, middle)
31
+ const right = list.slice(middle)
32
+ return combine(merge(left), merge(right))
33
+ }
34
+
35
+ export default merge
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @description: 设置基准值pivot
3
+ * @param {Array} list
4
+ * @param {number} left
5
+ * @param {number} right
6
+ * @return {number} index
7
+ */
8
+ const partition = (list: Array<number>, left: number, right: number) => {
9
+ const pivot = left
10
+ let index = pivot + 1
11
+ for (let i = index; i <= right; i++) {
12
+ if (list[i] < list[pivot]) {
13
+ const temp = list[i]
14
+ list[i] = list[index]
15
+ list[index] = temp
16
+ index++
17
+ }
18
+ }
19
+ const temp = list[pivot]
20
+ list[pivot] = list[index - 1]
21
+ list[index - 1] = temp
22
+ return index - 1
23
+ }
24
+ /**
25
+ * @description: 不断分区,设置基准值
26
+ * @param {Array} list
27
+ * @param {number} left
28
+ * @param {number} right
29
+ * @return {Array}
30
+ */
31
+ const combine = (list: Array<number>, left: number, right: number) => {
32
+ let partitionIndex
33
+ if (left < right) {
34
+ partitionIndex = partition(list, left, right)
35
+ combine(list, left, partitionIndex - 1)
36
+ combine(list, partitionIndex + 1, right)
37
+ }
38
+ return list
39
+ }
40
+ /**
41
+ * @description: 快速排序
42
+ * @param {Array} list
43
+ * @return {Array}
44
+ */
45
+ const quick = (list: Array<number>): Array<number> => {
46
+ const { length } = list
47
+ return combine(list, 0, length - 1)
48
+ }
49
+
50
+ export default quick
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @description: 基数排序
3
+ * @param {Array<number>} list
4
+ * @return {Array<number>}
5
+ */
6
+ const radix = (list: Array<number>): Array<number> => {
7
+ return list
8
+ }
9
+
10
+ export default radix
11
+
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @description: 通过数组长度,数组最大值,数组的最小值随机生成数组
3
+ * @param {number} length
4
+ * @param {number} min
5
+ * @param {number} max
6
+ * @return {Array<number>}
7
+ */
8
+ const randomArray = (
9
+ length: number = 10,
10
+ min: number = 0,
11
+ max: number = min + 100,
12
+ ): Array<number> => {
13
+ if (min > max) {
14
+ throw new Error('max must be max min')
15
+ }
16
+ return Array.from({ length }, (_) =>
17
+ Math.floor(Math.random() * (max - min) + min),
18
+ )
19
+ }
20
+
21
+ export default randomArray
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @description: 选择排序,遍历一遍,找到最小值,放到最前面,重复n次上述操作。
3
+ * @param {Array} list
4
+ * @return {Array}
5
+ */
6
+ const select = (list: Array<number>): Array<number> => {
7
+ const { length } = list
8
+ for (let i = 0; i < length; i++) {
9
+ let minIndex = i
10
+ for (let j = i + 1; j < length; j++) {
11
+ if (list[j] <= list[minIndex]) {
12
+ minIndex = j
13
+ }
14
+ }
15
+
16
+ const temp = list[i]
17
+ list[i] = list[minIndex]
18
+ list[minIndex] = temp
19
+ }
20
+ return list
21
+ }
22
+
23
+ export default select
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @description: 希尔排序,是简单插入排序的改进版。它与插入排序的不同之处在于,它会优先比较距离较远的元素。希尔排序又叫缩小增量排序。
3
+ * @param {Array} list
4
+ * @return {Array}
5
+ */
6
+ const shell = (list: Array<number>): Array<number> => {
7
+ const { length } = list
8
+ for (let gap = Math.floor(length / 2); gap > 0; gap = Math.floor(gap / 2)) {
9
+ for (let i = gap; i < length; i++) {
10
+ let j = i
11
+ const current = list[i]
12
+ while (j - gap >= 0 && current < list[j - gap]) {
13
+ list[j] = list[j - gap]
14
+ j = j - gap
15
+ }
16
+ list[j] = current
17
+ }
18
+ }
19
+ return list
20
+ }
21
+
22
+ export default shell
@@ -0,0 +1,37 @@
1
+ export type Next = () => Promise<never> | Promise<void>
2
+
3
+ type Middleware<T> = (context: T, next: Next) => any
4
+
5
+ type ComposedMiddleware<T> = (context: T, next?: Next) => Promise<void>
6
+ /**
7
+ * @description: 将异步函数转化为同步的方式进行执行
8
+ * @param {Array} middleware
9
+ * @return {*}
10
+ */
11
+ export function compose<T>(
12
+ middleware: Array<Middleware<T>>,
13
+ ): ComposedMiddleware<T> {
14
+ if (!Array.isArray(middleware))
15
+ throw new TypeError('Middleware stack must be an array!')
16
+ for (const fn of middleware) {
17
+ if (typeof fn !== 'function')
18
+ throw new TypeError('Middleware must be composed of functions!')
19
+ }
20
+ return function (context, next) {
21
+ let index = -1
22
+ return dispatch(0)
23
+ function dispatch(i: number): Promise<never> | Promise<void> {
24
+ if (i <= index)
25
+ return Promise.reject(new Error('next() called multiple times'))
26
+ index = i
27
+ let fn = middleware[i]
28
+ if (i === middleware.length && next) fn = next
29
+ if (!fn) return Promise.resolve()
30
+ try {
31
+ return Promise.resolve(fn(context, dispatch.bind(null, i + 1)))
32
+ } catch (err) {
33
+ return Promise.reject(err)
34
+ }
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @description: 过滤对象的属性,去除对象中在list数组里面有的属性,返回一个新对象,一般是用于去除空字符和null
3
+ * @param {Object} obj 传入对象
4
+ * @param {Array} list 传入数组
5
+ * @return {Object}
6
+ */
7
+
8
+ const filterObj = (
9
+ obj: Record<string | symbol, any>,
10
+ list: Array<string | symbol>,
11
+ ): Record<string | symbol, any> => {
12
+ const result: Record<string | symbol, any> = {}
13
+ Object.keys(obj).forEach((item) => {
14
+ if (!list.includes(obj[item])) {
15
+ result[item] = obj[item]
16
+ }
17
+ })
18
+ return result
19
+ }
20
+
21
+ export default filterObj
@@ -0,0 +1,12 @@
1
+ type Obj = Record<string, any>
2
+
3
+ const merge = (a: Obj, b?: Obj): Obj => {
4
+ if (a && b) {
5
+ for (const key in b) {
6
+ a[key] = b[key]
7
+ }
8
+ }
9
+ return a
10
+ }
11
+
12
+ export default merge
@@ -0,0 +1,15 @@
1
+ import { hrtime } from 'node:process'
2
+
3
+ const startTask = (): symbol => {
4
+ if(typeof window !== 'undefined'){
5
+ const startTime = window.performance.now()
6
+ return Symbol.for(`${startTime}`)
7
+ }
8
+ if(typeof process !== 'undefined'){
9
+ const startTime = hrtime.bigint()
10
+ return Symbol.for(`${startTime}`)
11
+ }
12
+ return Symbol.for(`${Date.now()}`)
13
+ }
14
+
15
+ export default startTask
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @description: 传入字符串和指定的格式,将字符串转成xml
3
+ * @param {string} xmlStr
4
+ * @param {DOMParserSupportedType} format
5
+ * @return {Document}
6
+ */
7
+ const str2Xml = (
8
+ xmlStr: string,
9
+ format: DOMParserSupportedType = 'text/xml',
10
+ ): HTMLElement | undefined => {
11
+ if (window.DOMParser)
12
+ return new window.DOMParser().parseFromString(xmlStr, format)
13
+ .documentElement
14
+ if (
15
+ typeof window.ActiveXObject !== 'undefined' &&
16
+ new window.ActiveXObject('Microsoft.XMLDOM')
17
+ ) {
18
+ const xmlDoc = new window.ActiveXObject('Microsoft.XMLDOM')
19
+ xmlDoc.async = 'false'
20
+ xmlDoc.loadXML(xmlStr)
21
+ return xmlDoc
22
+ }
23
+ return undefined
24
+ }
25
+
26
+ export default str2Xml
@@ -0,0 +1,14 @@
1
+ import { hrtime } from 'node:process'
2
+
3
+ const taskEnd = (symbol: symbol): number | bigint => {
4
+ const startTime = Symbol.keyFor(symbol)
5
+ if (typeof window !== 'undefined' && startTime) {
6
+ return window.performance.now() - Number(startTime)
7
+ }
8
+ if (typeof process !== 'undefined' && startTime) {
9
+ return hrtime.bigint() - BigInt(startTime)
10
+ }
11
+ return Date.now() - Number(startTime)
12
+ }
13
+
14
+ export default taskEnd
package/src/vnode/h.ts ADDED
@@ -0,0 +1,108 @@
1
+ import type {
2
+ VNode,
3
+ VNodeChildElement,
4
+ VNodeChildren,
5
+ VNodeData,
6
+ VNodes,
7
+ } from './vnode'
8
+ import { vnode } from './vnode'
9
+ // 类型判断
10
+ import * as is from './is'
11
+
12
+ export function addNS(
13
+ data: VNodeData,
14
+ children: Array<VNode | string | number> |undefined,
15
+ sel: string | undefined,
16
+ ): void {
17
+ data.ns = 'http://www.w3.org/2000/svg'
18
+ if (sel !== 'foreignObject' && children !== undefined) {
19
+ for (let i = 0; i < children.length; ++i) {
20
+ const child = children[i]
21
+ if (typeof child === 'string' || typeof child === 'number') continue
22
+ const childData = child.data
23
+ if (childData !== undefined) {
24
+ addNS(childData, child.children as VNodes, child.sel)
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ // h 函数的重载
31
+ export function h(sel: string): VNode
32
+ export function h(sel: string, data: VNodeData | null): VNode
33
+ export function h(sel: string, children: VNodeChildren): VNode
34
+ export function h(
35
+ sel: string,
36
+ data: VNodeData | null,
37
+ children: VNodeChildren,
38
+ ): VNode
39
+ export function h(
40
+ sel: string,
41
+ b?: VNodeData | null | VNodeChildren,
42
+ c?: VNodeChildren,
43
+ ): VNode {
44
+ // 缓存 VNode 数据
45
+ let data: VNodeData = {}
46
+ // 缓存 children 数据
47
+ let children: VNodeChildElement[] | undefined = undefined
48
+ // 缓存文本数据
49
+ let text: string | number | undefined
50
+ // 用于缓存遍历children的index
51
+ let i: number
52
+
53
+ // 处理参数,实现重载的机制
54
+ if (c !== undefined) {
55
+ // 处理三个参数的情况
56
+ // sel、data、children/text
57
+ if (b != null) {
58
+ data = b as VNodeData
59
+ }
60
+ if (is.array(c)) {
61
+ children = c
62
+ // 如果c是字符串或者数字
63
+ } else if (is.primitive(c)) {
64
+ text = c
65
+ // 如果c是VNode
66
+ } else if (c && c.sel) {
67
+ children = [c]
68
+ }
69
+ } else if (b !== undefined && b != null) {
70
+ // 处理两个参数的情况
71
+ // 如果b是数组
72
+ if (is.array(b)) {
73
+ children = b
74
+ // 如果b是字符串或数字
75
+ } else if (is.primitive(b)) {
76
+ text = b
77
+ } else {
78
+ // 这里由于b没有使用any类型,所以需要进一步判断b是否为VNode
79
+ if (is.isVnode(b)) {
80
+ children = [b]
81
+ } else {
82
+ data = b
83
+ }
84
+ }
85
+ }
86
+ // 处理 children 中的原始值(string/number)
87
+ if (typeof children !== 'undefined') {
88
+ for (i = 0; i < children.length; ++i) {
89
+ // 如果 child 是string/number,创建文本节点
90
+ // 这里由于children没有使用any类型,所以需要进一步判断children[i]是否为string | number
91
+ // 不能直接使用children[i],所以使用msg缓存
92
+ const msg = children[i]
93
+ if (is.primitive(msg)) {
94
+ children[i] = vnode(undefined, undefined, undefined, msg, undefined)
95
+ }
96
+ }
97
+ }
98
+ if (
99
+ sel[0] === 's' &&
100
+ sel[1] === 'v' &&
101
+ sel[2] === 'g' &&
102
+ (sel.length === 3 || sel[3] === '.' || sel[3] === '#')
103
+ ) {
104
+ addNS(data, children, sel)
105
+ }
106
+ // 符合VNode
107
+ return vnode(sel, data, children, text, undefined)
108
+ }
@@ -0,0 +1,25 @@
1
+ import type { VNode } from "./vnode";
2
+
3
+ export type PreHook = () => any;
4
+ export type InitHook = (vNode: VNode) => any;
5
+ export type CreateHook = (emptyVNode: VNode, vNode: VNode) => any;
6
+ export type InsertHook = (vNode: VNode) => any;
7
+ export type PrePatchHook = (oldVNode: VNode, vNode: VNode) => any;
8
+ export type UpdateHook = (oldVNode: VNode, vNode: VNode) => any;
9
+ export type PostPatchHook = (oldVNode: VNode, vNode: VNode) => any;
10
+ export type DestroyHook = (vNode: VNode) => any;
11
+ export type RemoveHook = (vNode: VNode, removeCallback: () => void) => any;
12
+ export type PostHook = () => any;
13
+
14
+ export interface Hooks {
15
+ pre?: PreHook;
16
+ init?: InitHook;
17
+ create?: CreateHook;
18
+ insert?: InsertHook;
19
+ prepatch?: PrePatchHook;
20
+ update?: UpdateHook;
21
+ postpatch?: PostPatchHook;
22
+ destroy?: DestroyHook;
23
+ remove?: RemoveHook;
24
+ post?: PostHook;
25
+ }
@@ -0,0 +1,199 @@
1
+ export interface Fragment extends DocumentFragment {
2
+ parent: Node | null
3
+ firstChildNode: ChildNode | null
4
+ lastChildNode: ChildNode | null
5
+ }
6
+
7
+ export interface DOMAPI {
8
+ // 创建元素节点
9
+ createElement: (tagName: any, options?: ElementCreationOptions) => HTMLElement
10
+ createElementNS: (
11
+ namespaceURI: string,
12
+ qualifiedName: string,
13
+ options?: ElementCreationOptions,
14
+ ) => Element
15
+ /**
16
+ * @experimental
17
+ * @todo Make it required when the fragment is considered stable.
18
+ */
19
+ createDocumentFragment?: () => Fragment
20
+ // 创建文本节点
21
+ createTextNode: (text: string) => Text
22
+ // 创建注释节点
23
+ createComment: (text: string) => Comment
24
+ // 在指定的已有子节点之前插入新的子节点。
25
+ insertBefore: (
26
+ parentNode: Node,
27
+ newNode: Node,
28
+ referenceNode: Node | null,
29
+ ) => void
30
+ // 删除子节点
31
+ removeChild: (node: Node, child: Node) => void
32
+ // 添加子节点
33
+ appendChild: (node: Node, child: Node) => void
34
+ // 获取元素父节点
35
+ parentNode: (node: Node) => Node | null
36
+ // 获取元素紧跟的节点
37
+ nextSibling: (node: Node) => Node | null
38
+ // 获取元素标签名
39
+ tagName: (elm: Element) => string
40
+ // 设置元素文本内容
41
+ setTextContent: (node: Node, text: string | null) => void
42
+ // 获取元素文本内容
43
+ getTextContent: (node: Node) => string | null
44
+ // 判定是否为元素节点
45
+ isElement: (node: Node) => node is Element
46
+ // 判定是否为文本节点
47
+ isText: (node: Node) => node is Text
48
+ // 判定是否为注释节点
49
+ isComment: (node: Node) => node is Comment
50
+ /**
51
+ * @experimental
52
+ * @todo Make it required when the fragment is considered stable.
53
+ */
54
+ isDocumentFragment?: (node: Node) => node is DocumentFragment
55
+ }
56
+
57
+ function createElement(
58
+ tagName: any,
59
+ options?: ElementCreationOptions,
60
+ ): HTMLElement {
61
+ return document.createElement(tagName, options)
62
+ }
63
+
64
+ function createElementNS(
65
+ namespaceURI: string,
66
+ qualifiedName: string,
67
+ options?: ElementCreationOptions,
68
+ ): Element {
69
+ return document.createElementNS(namespaceURI, qualifiedName, options)
70
+ }
71
+
72
+ function createDocumentFragment(): Fragment {
73
+ return parseFragment(document.createDocumentFragment())
74
+ }
75
+
76
+ function createTextNode(text: string): Text {
77
+ return document.createTextNode(text)
78
+ }
79
+
80
+ function createComment(text: string): Comment {
81
+ return document.createComment(text)
82
+ }
83
+
84
+ function insertBefore(
85
+ parentNode: Node,
86
+ newNode: Node,
87
+ referenceNode: Node | null,
88
+ ): void {
89
+ if (isDocumentFragment(parentNode)) {
90
+ let node: Node | null = parentNode
91
+ while (node && isDocumentFragment(node)) {
92
+ const fragment = parseFragment(node)
93
+ node = fragment.parent
94
+ }
95
+ parentNode = node ?? parentNode
96
+ }
97
+ if (isDocumentFragment(newNode)) {
98
+ newNode = parseFragment(newNode, parentNode)
99
+ }
100
+ if (referenceNode && isDocumentFragment(referenceNode)) {
101
+ referenceNode = parseFragment(referenceNode).firstChildNode
102
+ }
103
+ parentNode.insertBefore(newNode, referenceNode)
104
+ }
105
+
106
+ function removeChild(node: Node, child: Node): void {
107
+ node.removeChild(child)
108
+ }
109
+
110
+ function appendChild(node: Node, child: Node): void {
111
+ if (isDocumentFragment(child)) {
112
+ child = parseFragment(child, node)
113
+ }
114
+ node.appendChild(child)
115
+ }
116
+
117
+ function parentNode(node: Node): Node | null {
118
+ if (isDocumentFragment(node)) {
119
+ while (node && isDocumentFragment(node)) {
120
+ const fragment = parseFragment(node)
121
+ node = fragment.parent as Node
122
+ }
123
+ return node ?? null
124
+ }
125
+ return node.parentNode
126
+ }
127
+
128
+ function nextSibling(node: Node): Node | null {
129
+ if (isDocumentFragment(node)) {
130
+ const fragment = parseFragment(node)
131
+ const parent = parentNode(fragment)
132
+ if (parent && fragment.lastChildNode) {
133
+ const children = Array.from(parent.childNodes)
134
+ const index = children.indexOf(fragment.lastChildNode)
135
+ return children[index + 1] ?? null
136
+ }
137
+ return null
138
+ }
139
+ return node.nextSibling
140
+ }
141
+
142
+ function tagName(elm: Element): string {
143
+ return elm.tagName
144
+ }
145
+
146
+ function setTextContent(node: Node, text: string | null): void {
147
+ node.textContent = text
148
+ }
149
+
150
+ function getTextContent(node: Node): string | null {
151
+ return node.textContent
152
+ }
153
+
154
+ function isElement(node: Node): node is Element {
155
+ return node.nodeType === 1
156
+ }
157
+
158
+ function isText(node: Node): node is Text {
159
+ return node.nodeType === 3
160
+ }
161
+
162
+ function isComment(node: Node): node is Comment {
163
+ return node.nodeType === 8
164
+ }
165
+
166
+ function isDocumentFragment(node: Node): node is DocumentFragment {
167
+ return node.nodeType === 11
168
+ }
169
+
170
+ function parseFragment(
171
+ fragmentNode: DocumentFragment,
172
+ parentNode?: Node | null,
173
+ ): Fragment {
174
+ const fragment = fragmentNode as Fragment
175
+ fragment.parent ??= parentNode ?? null
176
+ fragment.firstChildNode ??= fragmentNode.firstChild
177
+ fragment.lastChildNode ??= fragmentNode.lastChild
178
+ return fragment
179
+ }
180
+
181
+ export const htmlDomApi: DOMAPI = {
182
+ createElement,
183
+ createElementNS,
184
+ createTextNode,
185
+ createDocumentFragment,
186
+ createComment,
187
+ insertBefore,
188
+ removeChild,
189
+ appendChild,
190
+ parentNode,
191
+ nextSibling,
192
+ tagName,
193
+ setTextContent,
194
+ getTextContent,
195
+ isElement,
196
+ isText,
197
+ isComment,
198
+ isDocumentFragment,
199
+ }