generated from 47ng/typescript-library-starter
-
-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathtraverseTree.ts
88 lines (79 loc) · 1.8 KB
/
traverseTree.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
export type Literal = string | number | boolean | null
export type Dict = { [key: string]: Json }
export type Json = Literal | Array<Json> | Dict
export type JsonType =
| 'string'
| 'number'
| 'boolean'
| 'null'
| 'array'
| 'object'
export interface Item {
key?: string
path: string[]
node: Json
type: JsonType
}
/**
* Traverse a JSON object depth-first, in a `reduce` manner.
*
* @param input The root node to traverse
* @param callback A function to call on each visited node
* @param initialState Think of this as the last argument of `reduce`
*/
export function traverseTree<State>(
input: Json,
callback: (state: State, item: Item) => State,
initialState: State
) {
type StackItem = Item & {
state: State
}
const stack: StackItem[] = [
{
path: [],
type: typeOf(input),
node: input,
state: initialState
}
]
while (stack.length > 0) {
const { state, ...item } = stack.shift()!
const newState = callback(state, item)
if (!isCollection(item.node)) {
continue
}
const children: StackItem[] = Object.entries(item.node).map(
([key, child]) => ({
key,
node: child,
type: typeOf(child),
path: [...item.path, key],
state: newState
})
)
stack.unshift(...children)
}
}
// Helpers --
function isObject(item: Json): item is Dict {
return (
typeof item === 'object' &&
Object.prototype.toString.call(item) === '[object Object]'
)
}
function isCollection(item: Json): item is Array<Json> | Dict {
return Array.isArray(item) || isObject(item)
}
function typeOf(item: Json): JsonType {
if (Array.isArray(item)) {
return 'array'
}
if (isObject(item)) {
return 'object'
}
if (item === null) {
return 'null'
}
return typeof item as JsonType
}