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