1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | export function* trace(expr, val, path) {
|
7 | if (expr) {
|
8 | const [loc, ...rest] = expr.split(";");
|
9 | const x = rest.join(";");
|
10 | if (val !== null && typeof val === 'object' && loc in val) {
|
11 | yield* trace(x, val[loc], path + ";" + loc);
|
12 | }
|
13 | else if (loc === "*") {
|
14 | for (const [m, _l, v, p] of walk(loc, val, path)) {
|
15 | yield* trace(m + ";" + x, v, p);
|
16 | }
|
17 | }
|
18 | else if (loc === "..") {
|
19 | yield* trace(x, val, path);
|
20 | for (const [m, _l, v, p] of walk(loc, val, path)) {
|
21 | if (typeof v[m] === "object")
|
22 | yield* trace("..;" + x, v[m], p + ";" + m);
|
23 | }
|
24 | }
|
25 | else if (/,/.test(loc)) {
|
26 | for (let s = loc.split(/'?,'?/), i = 0, n = s.length; i < n; i++)
|
27 | yield* trace(s[i] + ";" + x, val, path);
|
28 | }
|
29 | else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) {
|
30 | yield* slice(loc, x, val, path);
|
31 | }
|
32 | }
|
33 | else
|
34 | yield [path, val];
|
35 | }
|
36 | function* slice(loc, expr, val, path) {
|
37 | if (val instanceof Array) {
|
38 | const len = val.length;
|
39 | let start = 0, end = len, step = 1;
|
40 | loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, (_$0, $1, $2, $3) => {
|
41 | start = parseInt($1 || start);
|
42 | end = parseInt($2 || end);
|
43 | step = parseInt($3 || step);
|
44 | return '';
|
45 | });
|
46 | start = (start < 0) ? Math.max(0, start + len) : Math.min(len, start);
|
47 | end = (end < 0) ? Math.max(0, end + len) : Math.min(len, end);
|
48 | for (let i = start; i < end; i += step)
|
49 | yield* trace(i + ";" + expr, val, path);
|
50 | }
|
51 | }
|
52 | function* walk(loc, val, path) {
|
53 | if (val instanceof Array) {
|
54 | for (let i = 0, n = val.length; i < n; i++)
|
55 | if (i in val)
|
56 | yield [i, loc, val, path];
|
57 | }
|
58 | else if (typeof val === "object") {
|
59 | for (const m in val)
|
60 | if (val.hasOwnProperty(m))
|
61 | yield [m, loc, val, path];
|
62 | }
|
63 | }
|
64 | export function normalize(expr) {
|
65 | const subX = [];
|
66 | if (!expr.startsWith('$'))
|
67 | expr = '$' + expr;
|
68 | return expr
|
69 | .replace(/[\['](\??\(.*?\))[\]']/g, (_$0, $1) => { return "[#" + (subX.push($1) - 1) + "]"; })
|
70 | .replace(/'?\.'?|\['?/g, ";")
|
71 | .replace(/;;;|;;/g, ";..;")
|
72 | .replace(/;$|'?\]|'$/g, "")
|
73 | .replace(/#([0-9]+)/g, (_$0, $1) => { return subX[$1]; });
|
74 | }
|
75 |
|
76 | export function match(expr, path) {
|
77 | if (expr && path) {
|
78 | const [loc, ...restLoc] = expr.split(";");
|
79 | const [val, ...restVal] = path.split(";");
|
80 | const exprRest = restLoc.join(";");
|
81 | const pathRest = restVal.join(';');
|
82 | if (loc === val) {
|
83 | return match(exprRest, pathRest);
|
84 | }
|
85 | else if (loc === "*") {
|
86 | return match(exprRest, pathRest);
|
87 | }
|
88 | else if (loc === "..") {
|
89 | return match(exprRest, path) || match("..;" + exprRest, pathRest);
|
90 | }
|
91 | else if (/,/.test(loc)) {
|
92 | if (loc.split(/'?,'?/).some(v => v === val))
|
93 | return match(exprRest, pathRest);
|
94 | else
|
95 | return false;
|
96 | }
|
97 | else if (/^(-?[0-9]*):(-?[0-9]*):?([0-9]*)$/.test(loc)) {
|
98 | let start = 0, end = Number.MAX_SAFE_INTEGER, step = 1;
|
99 | loc.replace(/^(-?[0-9]*):(-?[0-9]*):?(-?[0-9]*)$/g, (_$0, $1, $2, $3) => {
|
100 | start = parseInt($1 || start);
|
101 | end = parseInt($2 || end);
|
102 | step = parseInt($3 || step);
|
103 | return '';
|
104 | });
|
105 | const idx = Number(val);
|
106 | if (start < 0 || end < 0 || step < 0)
|
107 | throw TypeError('Negative numbers not supported. Can\'t know length ahead of time when stream parsing');
|
108 | if (idx >= start && idx < end && start + idx % step === 0)
|
109 | return match(exprRest, pathRest);
|
110 | else
|
111 | return false;
|
112 | }
|
113 | }
|
114 | else if (!expr && !path)
|
115 | return true;
|
116 | return false;
|
117 | }
|
118 |
|
\ | No newline at end of file |