@loancrate/json-selector 2.0.0 → 3.0.0
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.
- package/README.md +50 -3
- package/dist/__generated__/parser.d.ts.map +1 -1
- package/dist/access.d.ts +6 -6
- package/dist/access.d.ts.map +1 -1
- package/dist/ast.d.ts +6 -3
- package/dist/ast.d.ts.map +1 -1
- package/dist/evaluate.d.ts +5 -5
- package/dist/evaluate.d.ts.map +1 -1
- package/dist/format.d.ts.map +1 -1
- package/dist/json-selector.esm.js +3510 -0
- package/dist/json-selector.esm.js.map +1 -0
- package/dist/json-selector.umd.js +3575 -0
- package/dist/json-selector.umd.js.map +1 -0
- package/dist/visitor.d.ts +2 -1
- package/dist/visitor.d.ts.map +1 -1
- package/package.json +32 -20
- package/src/__generated__/parser.js +2730 -0
- package/src/access.ts +534 -0
- package/src/ast.ts +114 -0
- package/src/evaluate.ts +269 -0
- package/src/format.ts +144 -0
- package/src/get.ts +9 -0
- package/src/grammar.pegjs +226 -0
- package/src/index.ts +7 -0
- package/src/parse.ts +7 -0
- package/src/set.ts +13 -0
- package/src/util.ts +70 -0
- package/src/visitor.ts +79 -0
- package/dist/__generated__/parser.js +0 -2855
- package/dist/__generated__/parser.js.map +0 -1
- package/dist/access.js +0 -444
- package/dist/access.js.map +0 -1
- package/dist/ast.js +0 -3
- package/dist/ast.js.map +0 -1
- package/dist/evaluate.js +0 -168
- package/dist/evaluate.js.map +0 -1
- package/dist/format.js +0 -119
- package/dist/format.js.map +0 -1
- package/dist/get.js +0 -9
- package/dist/get.js.map +0 -1
- package/dist/index.js +0 -26
- package/dist/index.js.map +0 -1
- package/dist/parse.js +0 -10
- package/dist/parse.js.map +0 -1
- package/dist/set.js +0 -12
- package/dist/set.js.map +0 -1
- package/dist/util.js +0 -70
- package/dist/util.js.map +0 -1
- package/dist/visitor.js +0 -39
- package/dist/visitor.js.map +0 -1
package/src/access.ts
ADDED
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
import { JsonSelector } from "./ast";
|
|
2
|
+
import {
|
|
3
|
+
compare,
|
|
4
|
+
evaluateJsonSelector,
|
|
5
|
+
filter,
|
|
6
|
+
flatten,
|
|
7
|
+
normalizeSlice,
|
|
8
|
+
project,
|
|
9
|
+
slice,
|
|
10
|
+
} from "./evaluate";
|
|
11
|
+
import { formatJsonSelector } from "./format";
|
|
12
|
+
import {
|
|
13
|
+
asArray,
|
|
14
|
+
findId,
|
|
15
|
+
findIdIndex,
|
|
16
|
+
getField,
|
|
17
|
+
getIndex,
|
|
18
|
+
isArray,
|
|
19
|
+
isFalseOrEmpty,
|
|
20
|
+
isObject,
|
|
21
|
+
} from "./util";
|
|
22
|
+
import { visitJsonSelector } from "./visitor";
|
|
23
|
+
|
|
24
|
+
export interface UnboundAccessor {
|
|
25
|
+
readonly selector: JsonSelector;
|
|
26
|
+
isValidContext(context: unknown, rootContext?: unknown): boolean;
|
|
27
|
+
get(context: unknown, rootContext?: unknown): unknown;
|
|
28
|
+
set(value: unknown, context: unknown, rootContext?: unknown): void;
|
|
29
|
+
delete(context: unknown, rootContext?: unknown): void;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
abstract class BaseAccessor implements UnboundAccessor {
|
|
33
|
+
constructor(readonly selector: JsonSelector) {}
|
|
34
|
+
abstract isValidContext(context: unknown, rootContext?: unknown): boolean;
|
|
35
|
+
abstract get(context: unknown, rootContext?: unknown): unknown;
|
|
36
|
+
abstract set(value: unknown, context: unknown, rootContext?: unknown): void;
|
|
37
|
+
abstract delete(context: unknown, rootContext?: unknown): void;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
abstract class ReadOnlyAccessor extends BaseAccessor {
|
|
41
|
+
constructor(selector: JsonSelector) {
|
|
42
|
+
super(selector);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
isValidContext(): boolean {
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
set(): void {
|
|
50
|
+
// ignored
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
delete(): void {
|
|
54
|
+
// ignored
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
class ConstantAccessor<T> extends ReadOnlyAccessor {
|
|
59
|
+
constructor(selector: JsonSelector, readonly value: T) {
|
|
60
|
+
super(selector);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
get(): T {
|
|
64
|
+
return this.value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
class ContextAccessor extends ReadOnlyAccessor {
|
|
69
|
+
constructor() {
|
|
70
|
+
super({ type: "current" });
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
get(context: unknown): unknown {
|
|
74
|
+
return context;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
class RootContextAccessor extends ReadOnlyAccessor {
|
|
78
|
+
constructor() {
|
|
79
|
+
super({ type: "root" });
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
get(context: unknown, rootContext = context): unknown {
|
|
83
|
+
return rootContext;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function makeJsonSelectorAccessor(
|
|
88
|
+
selector: JsonSelector
|
|
89
|
+
): UnboundAccessor {
|
|
90
|
+
return visitJsonSelector<UnboundAccessor, undefined>(
|
|
91
|
+
selector,
|
|
92
|
+
{
|
|
93
|
+
current() {
|
|
94
|
+
return new ContextAccessor();
|
|
95
|
+
},
|
|
96
|
+
root() {
|
|
97
|
+
return new RootContextAccessor();
|
|
98
|
+
},
|
|
99
|
+
literal(selector) {
|
|
100
|
+
return new ConstantAccessor(selector, selector.value);
|
|
101
|
+
},
|
|
102
|
+
identifier(selector) {
|
|
103
|
+
const { id } = selector;
|
|
104
|
+
const Accessor = class extends BaseAccessor {
|
|
105
|
+
constructor() {
|
|
106
|
+
super(selector);
|
|
107
|
+
}
|
|
108
|
+
isValidContext(context: unknown) {
|
|
109
|
+
return isObject(context);
|
|
110
|
+
}
|
|
111
|
+
get(context: unknown) {
|
|
112
|
+
return getField(context, id);
|
|
113
|
+
}
|
|
114
|
+
set(value: unknown, context: unknown) {
|
|
115
|
+
if (isObject(context)) {
|
|
116
|
+
context[id] = value;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
delete(context: unknown) {
|
|
120
|
+
if (isObject(context)) {
|
|
121
|
+
delete context[id];
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
return new Accessor();
|
|
126
|
+
},
|
|
127
|
+
fieldAccess(selector) {
|
|
128
|
+
const { expression, field } = selector;
|
|
129
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
130
|
+
const Accessor = class extends BaseAccessor {
|
|
131
|
+
constructor() {
|
|
132
|
+
super(selector);
|
|
133
|
+
}
|
|
134
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
135
|
+
return isObject(base.get(context, rootContext));
|
|
136
|
+
}
|
|
137
|
+
get(context: unknown, rootContext = context) {
|
|
138
|
+
return getField(base.get(context, rootContext), field);
|
|
139
|
+
}
|
|
140
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
141
|
+
const obj = base.get(context, rootContext);
|
|
142
|
+
if (isObject(obj)) {
|
|
143
|
+
obj[field] = value;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
delete(context: unknown, rootContext = context) {
|
|
147
|
+
const obj = base.get(context, rootContext);
|
|
148
|
+
if (isObject(obj)) {
|
|
149
|
+
delete obj[field];
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
return new Accessor();
|
|
154
|
+
},
|
|
155
|
+
indexAccess(selector) {
|
|
156
|
+
const { expression, index } = selector;
|
|
157
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
158
|
+
const Accessor = class extends BaseAccessor {
|
|
159
|
+
constructor() {
|
|
160
|
+
super(selector);
|
|
161
|
+
}
|
|
162
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
163
|
+
return isArray(base.get(context, rootContext));
|
|
164
|
+
}
|
|
165
|
+
get(context: unknown, rootContext = context) {
|
|
166
|
+
return getIndex(base.get(context, rootContext), index);
|
|
167
|
+
}
|
|
168
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
169
|
+
const arr = base.get(context, rootContext);
|
|
170
|
+
if (isArray(arr)) {
|
|
171
|
+
arr[index] = value;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
delete(context: unknown, rootContext = context) {
|
|
175
|
+
const arr = base.get(context, rootContext);
|
|
176
|
+
if (isArray(arr)) {
|
|
177
|
+
arr.splice(index, 1);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
return new Accessor();
|
|
182
|
+
},
|
|
183
|
+
idAccess(selector) {
|
|
184
|
+
const { expression, id } = selector;
|
|
185
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
186
|
+
const Accessor = class extends BaseAccessor {
|
|
187
|
+
constructor() {
|
|
188
|
+
super(selector);
|
|
189
|
+
}
|
|
190
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
191
|
+
return isArray(base.get(context, rootContext));
|
|
192
|
+
}
|
|
193
|
+
get(context: unknown, rootContext = context) {
|
|
194
|
+
return findId(base.get(context, rootContext), id);
|
|
195
|
+
}
|
|
196
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
197
|
+
const arr = base.get(context, rootContext);
|
|
198
|
+
if (isArray(arr)) {
|
|
199
|
+
const index = findIdIndex(arr, id);
|
|
200
|
+
if (index >= 0) {
|
|
201
|
+
arr[index] = value;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
delete(context: unknown, rootContext = context) {
|
|
206
|
+
const arr = base.get(context, rootContext);
|
|
207
|
+
if (isArray(arr)) {
|
|
208
|
+
const index = findIdIndex(arr, id);
|
|
209
|
+
if (index >= 0) {
|
|
210
|
+
arr.splice(index, 1);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
return new Accessor();
|
|
216
|
+
},
|
|
217
|
+
project(selector) {
|
|
218
|
+
const { expression, projection } = selector;
|
|
219
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
220
|
+
const proj = projection && makeJsonSelectorAccessor(projection);
|
|
221
|
+
const Accessor = class extends BaseAccessor {
|
|
222
|
+
constructor() {
|
|
223
|
+
super(selector);
|
|
224
|
+
}
|
|
225
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
226
|
+
return isArray(base.get(context, rootContext));
|
|
227
|
+
}
|
|
228
|
+
get(context: unknown, rootContext = context) {
|
|
229
|
+
return project(base.get(context, rootContext), projection, context);
|
|
230
|
+
}
|
|
231
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
232
|
+
const arr = base.get(context, rootContext);
|
|
233
|
+
if (isArray(arr)) {
|
|
234
|
+
if (proj) {
|
|
235
|
+
for (const element of arr) {
|
|
236
|
+
proj.set(value, element, rootContext);
|
|
237
|
+
}
|
|
238
|
+
} else {
|
|
239
|
+
replaceArray(arr, asArray(value));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
delete(context: unknown, rootContext = context) {
|
|
244
|
+
const arr = base.get(context, rootContext);
|
|
245
|
+
if (isArray(arr)) {
|
|
246
|
+
if (proj) {
|
|
247
|
+
for (const element of arr) {
|
|
248
|
+
proj.delete(element, rootContext);
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
arr.length = 0;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
return new Accessor();
|
|
257
|
+
},
|
|
258
|
+
filter(selector) {
|
|
259
|
+
const { expression, condition } = selector;
|
|
260
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
261
|
+
const Accessor = class extends BaseAccessor {
|
|
262
|
+
constructor() {
|
|
263
|
+
super(selector);
|
|
264
|
+
}
|
|
265
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
266
|
+
return isArray(base.get(context, rootContext));
|
|
267
|
+
}
|
|
268
|
+
get(context: unknown, rootContext = context) {
|
|
269
|
+
return filter(base.get(context, rootContext), condition, context);
|
|
270
|
+
}
|
|
271
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
272
|
+
const arr = base.get(context, rootContext);
|
|
273
|
+
if (isArray(arr)) {
|
|
274
|
+
replaceArray(
|
|
275
|
+
arr,
|
|
276
|
+
invertedFilter(arr, condition, rootContext).concat(
|
|
277
|
+
asArray(value)
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
delete(context: unknown, rootContext = context) {
|
|
283
|
+
const arr = base.get(context, rootContext);
|
|
284
|
+
if (isArray(arr)) {
|
|
285
|
+
replaceArray(arr, invertedFilter(arr, condition, rootContext));
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
return new Accessor();
|
|
290
|
+
},
|
|
291
|
+
slice(selector) {
|
|
292
|
+
const { expression, start, end, step } = selector;
|
|
293
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
294
|
+
const Accessor = class extends BaseAccessor {
|
|
295
|
+
constructor() {
|
|
296
|
+
super(selector);
|
|
297
|
+
}
|
|
298
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
299
|
+
return isArray(base.get(context, rootContext));
|
|
300
|
+
}
|
|
301
|
+
get(context: unknown, rootContext = context) {
|
|
302
|
+
return slice(base.get(context, rootContext), start, end, step);
|
|
303
|
+
}
|
|
304
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
305
|
+
const arr = base.get(context, rootContext);
|
|
306
|
+
if (isArray(arr)) {
|
|
307
|
+
replaceArray(
|
|
308
|
+
arr,
|
|
309
|
+
invertedSlice(arr, start, end, step).concat(asArray(value))
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
delete(context: unknown, rootContext = context) {
|
|
314
|
+
const arr = base.get(context, rootContext);
|
|
315
|
+
if (isArray(arr)) {
|
|
316
|
+
replaceArray(arr, invertedSlice(arr, start, end, step));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
return new Accessor();
|
|
321
|
+
},
|
|
322
|
+
flatten(selector) {
|
|
323
|
+
const { expression } = selector;
|
|
324
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
325
|
+
const Accessor = class extends BaseAccessor {
|
|
326
|
+
constructor() {
|
|
327
|
+
super(selector);
|
|
328
|
+
}
|
|
329
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
330
|
+
return isArray(base.get(context, rootContext));
|
|
331
|
+
}
|
|
332
|
+
get(context: unknown, rootContext = context) {
|
|
333
|
+
return flatten(base.get(context, rootContext));
|
|
334
|
+
}
|
|
335
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
336
|
+
const arr = base.get(context, rootContext);
|
|
337
|
+
if (isArray(arr)) {
|
|
338
|
+
replaceArray(arr, asArray(value));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
delete(context: unknown, rootContext = context) {
|
|
342
|
+
const arr = base.get(context, rootContext);
|
|
343
|
+
if (isArray(arr)) {
|
|
344
|
+
arr.length = 0;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
return new Accessor();
|
|
349
|
+
},
|
|
350
|
+
not(selector) {
|
|
351
|
+
const { expression } = selector;
|
|
352
|
+
const base = makeJsonSelectorAccessor(expression);
|
|
353
|
+
const Accessor = class extends ReadOnlyAccessor {
|
|
354
|
+
constructor() {
|
|
355
|
+
super(selector);
|
|
356
|
+
}
|
|
357
|
+
get(context: unknown, rootContext = context) {
|
|
358
|
+
return isFalseOrEmpty(base.get(context, rootContext));
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
return new Accessor();
|
|
362
|
+
},
|
|
363
|
+
compare(selector) {
|
|
364
|
+
const { lhs, rhs, operator } = selector;
|
|
365
|
+
const la = makeJsonSelectorAccessor(lhs);
|
|
366
|
+
const ra = makeJsonSelectorAccessor(rhs);
|
|
367
|
+
const Accessor = class extends ReadOnlyAccessor {
|
|
368
|
+
constructor() {
|
|
369
|
+
super(selector);
|
|
370
|
+
}
|
|
371
|
+
get(context: unknown, rootContext = context) {
|
|
372
|
+
const lv = la.get(context, rootContext);
|
|
373
|
+
const rv = ra.get(context, rootContext);
|
|
374
|
+
return compare(lv, rv, operator);
|
|
375
|
+
}
|
|
376
|
+
};
|
|
377
|
+
return new Accessor();
|
|
378
|
+
},
|
|
379
|
+
and(selector) {
|
|
380
|
+
const { lhs, rhs } = selector;
|
|
381
|
+
const la = makeJsonSelectorAccessor(lhs);
|
|
382
|
+
const ra = makeJsonSelectorAccessor(rhs);
|
|
383
|
+
const Accessor = class extends ReadOnlyAccessor {
|
|
384
|
+
constructor() {
|
|
385
|
+
super(selector);
|
|
386
|
+
}
|
|
387
|
+
get(context: unknown, rootContext = context) {
|
|
388
|
+
const lv = la.get(context, rootContext);
|
|
389
|
+
return isFalseOrEmpty(lv) ? lv : ra.get(context, rootContext);
|
|
390
|
+
}
|
|
391
|
+
};
|
|
392
|
+
return new Accessor();
|
|
393
|
+
},
|
|
394
|
+
or(selector) {
|
|
395
|
+
const { lhs, rhs } = selector;
|
|
396
|
+
const la = makeJsonSelectorAccessor(lhs);
|
|
397
|
+
const ra = makeJsonSelectorAccessor(rhs);
|
|
398
|
+
const Accessor = class extends ReadOnlyAccessor {
|
|
399
|
+
constructor() {
|
|
400
|
+
super(selector);
|
|
401
|
+
}
|
|
402
|
+
get(context: unknown, rootContext = context) {
|
|
403
|
+
const lv = la.get(context, rootContext);
|
|
404
|
+
return !isFalseOrEmpty(lv) ? lv : ra.get(context, rootContext);
|
|
405
|
+
}
|
|
406
|
+
};
|
|
407
|
+
return new Accessor();
|
|
408
|
+
},
|
|
409
|
+
pipe(selector) {
|
|
410
|
+
const { lhs, rhs } = selector;
|
|
411
|
+
const la = makeJsonSelectorAccessor(lhs);
|
|
412
|
+
const ra = makeJsonSelectorAccessor(rhs);
|
|
413
|
+
const Accessor = class extends BaseAccessor {
|
|
414
|
+
constructor() {
|
|
415
|
+
super(selector);
|
|
416
|
+
}
|
|
417
|
+
isValidContext(context: unknown, rootContext = context) {
|
|
418
|
+
return ra.isValidContext(la.get(context, rootContext), rootContext);
|
|
419
|
+
}
|
|
420
|
+
get(context: unknown, rootContext = context) {
|
|
421
|
+
return ra.get(la.get(context, rootContext), rootContext);
|
|
422
|
+
}
|
|
423
|
+
set(value: unknown, context: unknown, rootContext = context) {
|
|
424
|
+
ra.set(value, la.get(context, rootContext), rootContext);
|
|
425
|
+
}
|
|
426
|
+
delete(context: unknown, rootContext = context) {
|
|
427
|
+
ra.delete(la.get(context, rootContext), rootContext);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
return new Accessor();
|
|
431
|
+
},
|
|
432
|
+
},
|
|
433
|
+
undefined
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export interface Accessor<T> {
|
|
438
|
+
readonly selector: JsonSelector;
|
|
439
|
+
readonly valid: boolean;
|
|
440
|
+
readonly path: string;
|
|
441
|
+
get(): T;
|
|
442
|
+
set(value: T): void;
|
|
443
|
+
delete(): void;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export function bindJsonSelectorAccessor(
|
|
447
|
+
unbound: UnboundAccessor,
|
|
448
|
+
context: unknown,
|
|
449
|
+
rootContext = context
|
|
450
|
+
): Accessor<unknown> {
|
|
451
|
+
const { selector } = unbound;
|
|
452
|
+
const valid = unbound.isValidContext(context, rootContext);
|
|
453
|
+
return {
|
|
454
|
+
selector,
|
|
455
|
+
valid,
|
|
456
|
+
path: formatJsonSelector(selector),
|
|
457
|
+
get() {
|
|
458
|
+
return unbound.get(context, rootContext);
|
|
459
|
+
},
|
|
460
|
+
set(value: unknown) {
|
|
461
|
+
unbound.set(value, context, rootContext);
|
|
462
|
+
},
|
|
463
|
+
delete() {
|
|
464
|
+
unbound.delete(context, rootContext);
|
|
465
|
+
},
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export function accessWithJsonSelector(
|
|
470
|
+
selector: JsonSelector,
|
|
471
|
+
context: unknown,
|
|
472
|
+
rootContext = context
|
|
473
|
+
): Accessor<unknown> {
|
|
474
|
+
return bindJsonSelectorAccessor(
|
|
475
|
+
makeJsonSelectorAccessor(selector),
|
|
476
|
+
context,
|
|
477
|
+
rootContext
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function replaceArray(
|
|
482
|
+
target: unknown[],
|
|
483
|
+
source: readonly unknown[]
|
|
484
|
+
): unknown[] {
|
|
485
|
+
target.length = 0;
|
|
486
|
+
target.push(...source);
|
|
487
|
+
return target;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function invertedFilter(
|
|
491
|
+
value: unknown[],
|
|
492
|
+
condition: JsonSelector,
|
|
493
|
+
rootContext: unknown
|
|
494
|
+
): unknown[] {
|
|
495
|
+
return value.filter((e) =>
|
|
496
|
+
isFalseOrEmpty(evaluateJsonSelector(condition, e, rootContext))
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
export function invertedSlice(
|
|
501
|
+
value: unknown[],
|
|
502
|
+
start: number | undefined,
|
|
503
|
+
end?: number,
|
|
504
|
+
step?: number
|
|
505
|
+
): unknown[] {
|
|
506
|
+
({ start, end, step } = normalizeSlice(value.length, start, end, step));
|
|
507
|
+
const collected: unknown[] = [];
|
|
508
|
+
if (step > 0) {
|
|
509
|
+
if (start >= end) {
|
|
510
|
+
return value;
|
|
511
|
+
}
|
|
512
|
+
let skip = start;
|
|
513
|
+
for (let i = 0; i < value.length; ++i) {
|
|
514
|
+
if (i < skip || i >= end) {
|
|
515
|
+
collected.push(value[i]);
|
|
516
|
+
} else {
|
|
517
|
+
skip += step;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
} else {
|
|
521
|
+
if (start <= end) {
|
|
522
|
+
return value;
|
|
523
|
+
}
|
|
524
|
+
let skip = start;
|
|
525
|
+
for (let i = value.length - 1; i >= 0; --i) {
|
|
526
|
+
if (i > skip || i <= end) {
|
|
527
|
+
collected.push(value[i]);
|
|
528
|
+
} else {
|
|
529
|
+
skip += step;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
return collected;
|
|
534
|
+
}
|
package/src/ast.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { JsonValue } from "type-fest";
|
|
2
|
+
|
|
3
|
+
export type JsonSelectorNodeType = JsonSelector["type"];
|
|
4
|
+
|
|
5
|
+
export interface JsonSelectorCurrent {
|
|
6
|
+
type: "current";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface JsonSelectorRoot {
|
|
10
|
+
type: "root";
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export interface JsonSelectorLiteral {
|
|
14
|
+
type: "literal";
|
|
15
|
+
value: JsonValue;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface JsonSelectorIdentifier {
|
|
19
|
+
type: "identifier";
|
|
20
|
+
id: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface JsonSelectorFieldAccess {
|
|
24
|
+
type: "fieldAccess";
|
|
25
|
+
expression: JsonSelector;
|
|
26
|
+
field: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface JsonSelectorIndexAccess {
|
|
30
|
+
type: "indexAccess";
|
|
31
|
+
expression: JsonSelector;
|
|
32
|
+
index: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface JsonSelectorIdAccess {
|
|
36
|
+
type: "idAccess";
|
|
37
|
+
expression: JsonSelector;
|
|
38
|
+
id: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface JsonSelectorProject {
|
|
42
|
+
type: "project";
|
|
43
|
+
expression: JsonSelector;
|
|
44
|
+
projection?: JsonSelector;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface JsonSelectorFilter {
|
|
48
|
+
type: "filter";
|
|
49
|
+
expression: JsonSelector;
|
|
50
|
+
condition: JsonSelector;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface JsonSelectorSlice {
|
|
54
|
+
type: "slice";
|
|
55
|
+
expression: JsonSelector;
|
|
56
|
+
start?: number;
|
|
57
|
+
end?: number;
|
|
58
|
+
step?: number;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface JsonSelectorFlatten {
|
|
62
|
+
type: "flatten";
|
|
63
|
+
expression: JsonSelector;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export interface JsonSelectorNot {
|
|
67
|
+
type: "not";
|
|
68
|
+
expression: JsonSelector;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type JsonSelectorCompareOperator = "<" | "<=" | "==" | ">=" | ">" | "!=";
|
|
72
|
+
|
|
73
|
+
export interface JsonSelectorCompare {
|
|
74
|
+
type: "compare";
|
|
75
|
+
operator: JsonSelectorCompareOperator;
|
|
76
|
+
lhs: JsonSelector;
|
|
77
|
+
rhs: JsonSelector;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface JsonSelectorAnd {
|
|
81
|
+
type: "and";
|
|
82
|
+
lhs: JsonSelector;
|
|
83
|
+
rhs: JsonSelector;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface JsonSelectorOr {
|
|
87
|
+
type: "or";
|
|
88
|
+
lhs: JsonSelector;
|
|
89
|
+
rhs: JsonSelector;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface JsonSelectorPipe {
|
|
93
|
+
type: "pipe";
|
|
94
|
+
lhs: JsonSelector;
|
|
95
|
+
rhs: JsonSelector;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export type JsonSelector =
|
|
99
|
+
| JsonSelectorCurrent
|
|
100
|
+
| JsonSelectorRoot
|
|
101
|
+
| JsonSelectorLiteral
|
|
102
|
+
| JsonSelectorIdentifier
|
|
103
|
+
| JsonSelectorFieldAccess
|
|
104
|
+
| JsonSelectorIndexAccess
|
|
105
|
+
| JsonSelectorIdAccess
|
|
106
|
+
| JsonSelectorProject
|
|
107
|
+
| JsonSelectorFilter
|
|
108
|
+
| JsonSelectorSlice
|
|
109
|
+
| JsonSelectorFlatten
|
|
110
|
+
| JsonSelectorNot
|
|
111
|
+
| JsonSelectorCompare
|
|
112
|
+
| JsonSelectorAnd
|
|
113
|
+
| JsonSelectorOr
|
|
114
|
+
| JsonSelectorPipe;
|