-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
90 lines (70 loc) · 2.09 KB
/
index.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
89
90
type DotElasticType = Record<string, any>;
type Options = Partial<{
clone: boolean,
}>;
let uniqIdCnt = 0;
const uniqId = () => `!!__dot-es__${++uniqIdCnt}__!!`;
const reUniqId = /^!!__dot-es__\d+__!!/;
const reMatchNodes = /(?<!\\)\./;
const reMatchArray = /(?<!\\)\[(\d*)(?<!\\)\]$/;
function matchArray (node: string) {
return node.indexOf('[') && reMatchArray.exec(node);
}
function tidyNode (node: string | undefined): string {
node = (node || '');
if (node.indexOf('[')) {
node = node.replace(reMatchArray, '');
}
if (node.indexOf('\\') >= 0) {
node = node.replace(/\\/g, '');
}
if (reUniqId.test(node)) {
node = node.replace(reUniqId, '');
}
return node;
}
export function u (strings: TemplateStringsArray): string {
return `${uniqId()}${strings.raw[0]}`;
}
function walkPath (path: string, ptr: DotElasticType, skipLast = false): any {
const nodes: string[] = path.split(reMatchNodes);
for (let node of nodes.slice(0, skipLast ? -1 : nodes.length)) {
const idx = matchArray(node);
node = tidyNode(node);
if (!ptr[node]) {
ptr[node] = idx ? [] : {};
}
if (!idx) {
ptr = ptr[node];
} else {
const nIdx = Number(idx[1]) || ptr[node].length;
if (typeof ptr[node][nIdx] === 'undefined') {
ptr[node][nIdx] = {};
}
ptr = ptr[node][nIdx];
}
}
return skipLast ? [ ptr, nodes[nodes.length - 1] ] : ptr;
}
function dot (input: DotElasticType, base: DotElasticType = {}, opts: Options = {}): DotElasticType {
const retval = base && opts.clone ? JSON.parse(JSON.stringify(base)) : base;
Object.keys(input).forEach((key) => {
let [ ptr, leafNode ]: [ any, string ] = walkPath(key, retval, true);
const tidyLeafNode = tidyNode(leafNode);
const idx = matchArray(leafNode);
if (!idx) {
ptr[tidyLeafNode] = input[key];
} else {
if (!ptr[tidyLeafNode]) {
ptr[tidyLeafNode] = [];
}
ptr = ptr[tidyLeafNode];
const nIdx = Number(idx[1]) || ptr.length;
ptr[nIdx] = input[key];
}
});
return retval;
}
dot.u = u;
dot.ln = walkPath;
export default dot;