@dxos/echo-query 0.8.4-main.c4373fc → 0.8.4-main.c85a9c8dae

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.
Files changed (43) hide show
  1. package/dist/lib/{browser → neutral}/index.mjs +257 -68
  2. package/dist/lib/neutral/index.mjs.map +7 -0
  3. package/dist/lib/neutral/meta.json +1 -0
  4. package/dist/query-lite/index.d.ts +9890 -0
  5. package/dist/query-lite/index.d.ts.map +1 -0
  6. package/dist/query-lite/index.js +415 -0
  7. package/dist/query-lite/index.js.map +1 -0
  8. package/dist/types/src/index.d.ts +1 -0
  9. package/dist/types/src/index.d.ts.map +1 -1
  10. package/dist/types/src/parser/gen/query.terms.d.ts +1 -1
  11. package/dist/types/src/parser/gen/query.terms.d.ts.map +1 -1
  12. package/dist/types/src/parser/query-builder.d.ts +12 -4
  13. package/dist/types/src/parser/query-builder.d.ts.map +1 -1
  14. package/dist/types/src/query-lite/index.d.ts +2 -0
  15. package/dist/types/src/query-lite/index.d.ts.map +1 -0
  16. package/dist/types/src/query-lite/query-lite.d.ts +8 -0
  17. package/dist/types/src/query-lite/query-lite.d.ts.map +1 -0
  18. package/dist/types/src/sandbox/index.d.ts +2 -0
  19. package/dist/types/src/sandbox/index.d.ts.map +1 -0
  20. package/dist/types/src/sandbox/quickjs.d.ts.map +1 -1
  21. package/dist/types/tsconfig.tsbuildinfo +1 -1
  22. package/package.json +22 -17
  23. package/src/env.d.ts +1 -1
  24. package/src/index.ts +1 -0
  25. package/src/parser/gen/query.terms.ts +24 -23
  26. package/src/parser/gen/query.ts +8 -8
  27. package/src/parser/query-builder.ts +65 -12
  28. package/src/parser/query.grammar +8 -2
  29. package/src/parser/query.test.ts +75 -22
  30. package/src/query-lite/index.ts +5 -0
  31. package/src/{query-env/index.ts → query-lite/query-lite.ts} +145 -59
  32. package/src/sandbox/index.ts +5 -0
  33. package/src/sandbox/query-sandbox.test.ts +9 -8
  34. package/src/sandbox/query-sandbox.ts +3 -3
  35. package/src/sandbox/quickjs.ts +1 -2
  36. package/dist/lib/browser/index.mjs.map +0 -7
  37. package/dist/lib/browser/meta.json +0 -1
  38. package/dist/lib/node-esm/index.mjs +0 -530
  39. package/dist/lib/node-esm/index.mjs.map +0 -7
  40. package/dist/lib/node-esm/meta.json +0 -1
  41. package/dist/query-env/index.js +0 -387
  42. package/dist/types/src/query-env/index.d.ts +0 -8
  43. package/dist/types/src/query-env/index.d.ts.map +0 -1
@@ -4,16 +4,21 @@
4
4
 
5
5
  import type * as Schema from 'effect/Schema';
6
6
 
7
- import type { Filter, Order, Query, Ref } from '@dxos/echo';
8
- import type * as Echo from '@dxos/echo';
7
+ import type { Filter as Filter$, Order as Order$, Query as Query$, Ref } from '@dxos/echo';
9
8
  import type { ForeignKey, QueryAST } from '@dxos/echo-protocol';
10
9
  import { assertArgument } from '@dxos/invariant';
11
10
  import type { DXN, ObjectId } from '@dxos/keys';
12
11
 
13
- class OrderClass implements Echo.Order<any> {
14
- private static variance: Echo.Order<any>['~Order'] = {} as Echo.Order<any>['~Order'];
12
+ //
13
+ // Light-weight implementation of query execution.
14
+ //
15
+
16
+ // TODO(wittjosiah): The `export * as ...` syntax causes tsdown to genereate multiple files which breaks the sandbox.
15
17
 
16
- static is(value: unknown): value is Echo.Order<any> {
18
+ class OrderClass implements Order$.Any {
19
+ private static 'variance': Order$.Any['~Order'] = {} as Order$.Any['~Order'];
20
+
21
+ static is(value: unknown): value is Order$.Any {
17
22
  return typeof value === 'object' && value !== null && '~Order' in value;
18
23
  }
19
24
 
@@ -21,27 +26,33 @@ class OrderClass implements Echo.Order<any> {
21
26
 
22
27
  '~Order' = OrderClass.variance;
23
28
  }
29
+
24
30
  namespace Order1 {
25
- export const natural: Echo.Order<any> = new OrderClass({ kind: 'natural' });
26
- export const property = <T>(property: keyof T & string, direction: QueryAST.OrderDirection): Echo.Order<T> =>
31
+ export const natural: Order$.Any = new OrderClass({ kind: 'natural' });
32
+ export const property = <T>(property: keyof T & string, direction: QueryAST.OrderDirection): Order$.Order<T> =>
27
33
  new OrderClass({
28
34
  kind: 'property',
29
35
  property,
30
36
  direction,
31
37
  });
38
+ export const rank = <T>(direction: QueryAST.OrderDirection = 'desc'): Order$.Order<T> =>
39
+ new OrderClass({
40
+ kind: 'rank',
41
+ direction,
42
+ });
32
43
  }
33
44
 
34
- const Order2: typeof Echo.Order = Order1;
45
+ const Order2: typeof Order$ = Order1;
35
46
  export { Order2 as Order };
36
47
 
37
- class FilterClass implements Echo.Filter<any> {
38
- private static variance: Echo.Filter<any>['~Filter'] = {} as Echo.Filter<any>['~Filter'];
48
+ class FilterClass implements Filter$.Any {
49
+ private static 'variance': Filter$.Any['~Filter'] = {} as Filter$.Any['~Filter'];
39
50
 
40
- static is(value: unknown): value is Echo.Filter<any> {
51
+ static is(value: unknown): value is Filter$.Any {
41
52
  return typeof value === 'object' && value !== null && '~Filter' in value;
42
53
  }
43
54
 
44
- static fromAst(ast: QueryAST.Filter): Filter<any> {
55
+ static fromAst(ast: QueryAST.Filter): Filter$.Any {
45
56
  return new FilterClass(ast);
46
57
  }
47
58
 
@@ -72,7 +83,7 @@ class FilterClass implements Echo.Filter<any> {
72
83
  });
73
84
  }
74
85
 
75
- static ids(...ids: ObjectId[]): Echo.Filter<any> {
86
+ static id(...ids: ObjectId[]): Filter$.Any {
76
87
  // assertArgument(
77
88
  // ids.every((id) => ObjectId.isValid(id)),
78
89
  // 'ids',
@@ -93,8 +104,8 @@ class FilterClass implements Echo.Filter<any> {
93
104
 
94
105
  static type<S extends Schema.Schema.All>(
95
106
  schema: S | string,
96
- props?: Echo.Filter.Props<Schema.Schema.Type<S>>,
97
- ): Echo.Filter<Schema.Schema.Type<S>> {
107
+ props?: Filter$.Props<Schema.Schema.Type<S>>,
108
+ ): Filter$.Filter<Schema.Schema.Type<S>> {
98
109
  if (typeof schema !== 'string') {
99
110
  throw new TypeError('expected typename as the first paramter');
100
111
  }
@@ -105,7 +116,7 @@ class FilterClass implements Echo.Filter<any> {
105
116
  });
106
117
  }
107
118
 
108
- static typename(typename: string): Echo.Filter<any> {
119
+ static typename(typename: string): Filter$.Any {
109
120
  return new FilterClass({
110
121
  type: 'object',
111
122
  typename: makeTypeDxn(typename),
@@ -113,7 +124,7 @@ class FilterClass implements Echo.Filter<any> {
113
124
  });
114
125
  }
115
126
 
116
- static typeDXN(dxn: DXN): Echo.Filter<any> {
127
+ static typeDXN(dxn: DXN): Filter$.Any {
117
128
  return new FilterClass({
118
129
  type: 'object',
119
130
  typename: dxn.toString(),
@@ -121,14 +132,14 @@ class FilterClass implements Echo.Filter<any> {
121
132
  });
122
133
  }
123
134
 
124
- static tag(tag: string): Echo.Filter<any> {
135
+ static tag(tag: string): Filter$.Any {
125
136
  return new FilterClass({
126
137
  type: 'tag',
127
138
  tag,
128
139
  });
129
140
  }
130
141
 
131
- static props<T>(props: Echo.Filter.Props<T>): Echo.Filter<T> {
142
+ static props<T>(props: Filter$.Props<T>): Filter$.Filter<T> {
132
143
  return new FilterClass({
133
144
  type: 'object',
134
145
  typename: null,
@@ -136,7 +147,7 @@ class FilterClass implements Echo.Filter<any> {
136
147
  });
137
148
  }
138
149
 
139
- static text(text: string, options?: Echo.Query.TextSearchOptions): Echo.Filter<any> {
150
+ static text(text: string, options?: Filter$.TextSearchOptions): Filter$.Any {
140
151
  return new FilterClass({
141
152
  type: 'text-search',
142
153
  text,
@@ -147,7 +158,7 @@ class FilterClass implements Echo.Filter<any> {
147
158
  static foreignKeys<S extends Schema.Schema.All>(
148
159
  schema: S | string,
149
160
  keys: ForeignKey[],
150
- ): Echo.Filter<Schema.Schema.Type<S>> {
161
+ ): Filter$.Filter<Schema.Schema.Type<S>> {
151
162
  assertArgument(typeof schema === 'string', 'schema');
152
163
  assertArgument(!schema.startsWith('dxn:'), 'schema');
153
164
  return new FilterClass({
@@ -158,7 +169,7 @@ class FilterClass implements Echo.Filter<any> {
158
169
  });
159
170
  }
160
171
 
161
- static eq<T>(value: T): Echo.Filter<T> {
172
+ static eq<T>(value: T): Filter$.Filter<T | undefined> {
162
173
  if (!isRef(value) && typeof value === 'object' && value !== null) {
163
174
  throw new TypeError('Cannot use object as a value for eq filter');
164
175
  }
@@ -170,7 +181,7 @@ class FilterClass implements Echo.Filter<any> {
170
181
  });
171
182
  }
172
183
 
173
- static neq<T>(value: T): Echo.Filter<T> {
184
+ static neq<T>(value: T): Filter$.Filter<T | undefined> {
174
185
  return new FilterClass({
175
186
  type: 'compare',
176
187
  operator: 'neq',
@@ -178,7 +189,7 @@ class FilterClass implements Echo.Filter<any> {
178
189
  });
179
190
  }
180
191
 
181
- static gt<T>(value: T): Echo.Filter<T> {
192
+ static gt<T>(value: T): Filter$.Filter<T | undefined> {
182
193
  return new FilterClass({
183
194
  type: 'compare',
184
195
  operator: 'gt',
@@ -186,7 +197,7 @@ class FilterClass implements Echo.Filter<any> {
186
197
  });
187
198
  }
188
199
 
189
- static gte<T>(value: T): Echo.Filter<T> {
200
+ static gte<T>(value: T): Filter$.Filter<T | undefined> {
190
201
  return new FilterClass({
191
202
  type: 'compare',
192
203
  operator: 'gte',
@@ -194,7 +205,7 @@ class FilterClass implements Echo.Filter<any> {
194
205
  });
195
206
  }
196
207
 
197
- static lt<T>(value: T): Echo.Filter<T> {
208
+ static lt<T>(value: T): Filter$.Filter<T | undefined> {
198
209
  return new FilterClass({
199
210
  type: 'compare',
200
211
  operator: 'lt',
@@ -202,7 +213,7 @@ class FilterClass implements Echo.Filter<any> {
202
213
  });
203
214
  }
204
215
 
205
- static lte<T>(value: T): Echo.Filter<T> {
216
+ static lte<T>(value: T): Filter$.Filter<T | undefined> {
206
217
  return new FilterClass({
207
218
  type: 'compare',
208
219
  operator: 'lte',
@@ -210,21 +221,21 @@ class FilterClass implements Echo.Filter<any> {
210
221
  });
211
222
  }
212
223
 
213
- static in<T>(...values: T[]): Echo.Filter<T> {
224
+ static in<T>(...values: T[]): Filter$.Filter<T | undefined> {
214
225
  return new FilterClass({
215
226
  type: 'in',
216
227
  values,
217
228
  });
218
229
  }
219
230
 
220
- static contains<T>(value: T): Echo.Filter<T[]> {
231
+ static contains<T>(value: T): Filter$.Filter<readonly T[] | undefined> {
221
232
  return new FilterClass({
222
233
  type: 'contains',
223
234
  value,
224
235
  });
225
236
  }
226
237
 
227
- static between<T>(from: T, to: T): Echo.Filter<T> {
238
+ static between<T>(from: T, to: T): Filter$.Filter<unknown> {
228
239
  return new FilterClass({
229
240
  type: 'range',
230
241
  from,
@@ -232,21 +243,25 @@ class FilterClass implements Echo.Filter<any> {
232
243
  });
233
244
  }
234
245
 
235
- static not<F extends Echo.Filter.Any>(filter: F): Echo.Filter<Echo.Filter.Type<F>> {
246
+ static not<F extends Filter$.Any>(filter: F): Filter$.Filter<Filter$.Type<F>> {
236
247
  return new FilterClass({
237
248
  type: 'not',
238
249
  filter: filter.ast,
239
250
  });
240
251
  }
241
252
 
242
- static and<T>(...filters: Echo.Filter<T>[]): Echo.Filter<T> {
253
+ static and<Filters extends readonly Filter$.Any[]>(
254
+ ...filters: Filters
255
+ ): Filter$.Filter<Filter$.Type<Filters[number]>> {
243
256
  return new FilterClass({
244
257
  type: 'and',
245
258
  filters: filters.map((f) => f.ast),
246
259
  });
247
260
  }
248
261
 
249
- static or<T>(...filters: Echo.Filter<T>[]): Echo.Filter<T> {
262
+ static or<Filters extends readonly Filter$.Any[]>(
263
+ ...filters: Filters
264
+ ): Filter$.Filter<Filter$.Type<Filters[number]>> {
250
265
  return new FilterClass({
251
266
  type: 'or',
252
267
  filters: filters.map((f) => f.ast),
@@ -258,7 +273,7 @@ class FilterClass implements Echo.Filter<any> {
258
273
  '~Filter' = FilterClass.variance;
259
274
  }
260
275
 
261
- export const Filter1: typeof Echo.Filter = FilterClass;
276
+ export const Filter1: typeof Filter$ = FilterClass;
262
277
  export { Filter1 as Filter };
263
278
 
264
279
  /**
@@ -267,7 +282,7 @@ export { Filter1 as Filter };
267
282
  // TODO(dmaretskyi): Filter only properties that are references (or optional references, or unions that include references).
268
283
  type RefPropKey<T> = keyof T & string;
269
284
 
270
- const propsFilterToAst = (predicates: Echo.Filter.Props<any>): Pick<QueryAST.FilterObject, 'id' | 'props'> => {
285
+ const propsFilterToAst = (predicates: Filter$.Props<any>): Pick<QueryAST.FilterObject, 'id' | 'props'> => {
271
286
  let idFilter: readonly ObjectId[] | undefined;
272
287
  if ('id' in predicates) {
273
288
  assertArgument(
@@ -312,32 +327,32 @@ const processPredicate = (predicate: any): QueryAST.Filter => {
312
327
  return FilterClass.eq(predicate).ast;
313
328
  };
314
329
 
315
- class QueryClass implements Echo.Query<any> {
316
- private static variance: Echo.Query<any>['~Query'] = {} as Echo.Query<any>['~Query'];
330
+ class QueryClass implements Query$.Any {
331
+ private static 'variance': Query$.Any['~Query'] = {} as Query$.Any['~Query'];
317
332
 
318
- static is(value: unknown): value is Echo.Query<any> {
333
+ static is(value: unknown): value is Query$.Any {
319
334
  return typeof value === 'object' && value !== null && '~Query' in value;
320
335
  }
321
336
 
322
- static fromAst(ast: QueryAST.Query): Echo.Query<any> {
337
+ static fromAst(ast: QueryAST.Query): Query$.Any {
323
338
  return new QueryClass(ast);
324
339
  }
325
340
 
326
- static select<F extends Echo.Filter.Any>(filter: F): Echo.Query<Echo.Filter.Type<F>> {
341
+ static select<F extends Filter$.Any>(filter: F): Query$.Query<Filter$.Type<F>> {
327
342
  return new QueryClass({
328
343
  type: 'select',
329
344
  filter: filter.ast,
330
345
  });
331
346
  }
332
347
 
333
- static type(schema: Schema.Schema.All | string, predicates?: Echo.Filter.Props<unknown>): Query<any> {
348
+ static type(schema: Schema.Schema.All | string, predicates?: Filter$.Props<unknown>): Query$.Any {
334
349
  return new QueryClass({
335
350
  type: 'select',
336
351
  filter: FilterClass.type(schema, predicates).ast,
337
352
  });
338
353
  }
339
354
 
340
- static all(...queries: Query<any>[]): Query<any> {
355
+ static all(...queries: Query$.Any[]): Query$.Any {
341
356
  if (queries.length === 0) {
342
357
  throw new TypeError(
343
358
  'Query.all combines results of multiple queries, to query all objects use Query.select(Filter.everything())',
@@ -349,7 +364,7 @@ class QueryClass implements Echo.Query<any> {
349
364
  });
350
365
  }
351
366
 
352
- static without<T>(source: Query<T>, exclude: Query<T>): Query<T> {
367
+ static without<T>(source: Query$.Query<T>, exclude: Query$.Query<T>): Query$.Query<T> {
353
368
  return new QueryClass({
354
369
  type: 'set-difference',
355
370
  source: source.ast,
@@ -357,11 +372,20 @@ class QueryClass implements Echo.Query<any> {
357
372
  });
358
373
  }
359
374
 
375
+ static from(source: any, options?: { includeFeeds?: boolean }): Query$.Any {
376
+ const baseQuery: QueryAST.Query = {
377
+ type: 'select',
378
+ filter: FilterClass.everything().ast,
379
+ };
380
+ const wrapper = new QueryClass(baseQuery);
381
+ return wrapper.from(source, options);
382
+ }
383
+
360
384
  constructor(public readonly ast: QueryAST.Query) {}
361
385
 
362
386
  '~Query' = QueryClass.variance;
363
387
 
364
- select(filter: Filter<any> | Filter.Props<any>): Query<any> {
388
+ select(filter: Filter$.Any | Filter$.Props<any>): Query$.Any {
365
389
  if (FilterClass.is(filter)) {
366
390
  return new QueryClass({
367
391
  type: 'filter',
@@ -377,7 +401,7 @@ class QueryClass implements Echo.Query<any> {
377
401
  }
378
402
  }
379
403
 
380
- reference(key: string): Query<any> {
404
+ reference(key: string): Query$.Any {
381
405
  return new QueryClass({
382
406
  type: 'reference-traversal',
383
407
  anchor: this.ast,
@@ -385,36 +409,40 @@ class QueryClass implements Echo.Query<any> {
385
409
  });
386
410
  }
387
411
 
388
- referencedBy(target: Schema.Schema.All | string, key: string): Query<any> {
389
- assertArgument(typeof target === 'string', 'target');
390
- assertArgument(!target.startsWith('dxn:'), 'target');
412
+ referencedBy(target?: Schema.Schema.All | string, key?: string): Query$.Any {
413
+ const typename =
414
+ target !== undefined
415
+ ? (assertArgument(typeof target === 'string', 'target'),
416
+ assertArgument(!target.startsWith('dxn:'), 'target'),
417
+ target)
418
+ : null;
391
419
  return new QueryClass({
392
420
  type: 'incoming-references',
393
421
  anchor: this.ast,
394
- property: key,
395
- typename: target,
422
+ property: key ?? null,
423
+ typename,
396
424
  });
397
425
  }
398
426
 
399
- sourceOf(relation: Schema.Schema.All | string, predicates?: Filter.Props<unknown> | undefined): Query<any> {
427
+ sourceOf(relation?: Schema.Schema.All | string, predicates?: Filter$.Props<unknown> | undefined): Query$.Any {
400
428
  return new QueryClass({
401
429
  type: 'relation',
402
430
  anchor: this.ast,
403
431
  direction: 'outgoing',
404
- filter: FilterClass.type(relation, predicates).ast,
432
+ filter: relation !== undefined ? FilterClass.type(relation, predicates).ast : undefined,
405
433
  });
406
434
  }
407
435
 
408
- targetOf(relation: Schema.Schema.All | string, predicates?: Filter.Props<unknown> | undefined): Query<any> {
436
+ targetOf(relation?: Schema.Schema.All | string, predicates?: Filter$.Props<unknown> | undefined): Query$.Any {
409
437
  return new QueryClass({
410
438
  type: 'relation',
411
439
  anchor: this.ast,
412
440
  direction: 'incoming',
413
- filter: FilterClass.type(relation, predicates).ast,
441
+ filter: relation !== undefined ? FilterClass.type(relation, predicates).ast : undefined,
414
442
  });
415
443
  }
416
444
 
417
- source(): Query<any> {
445
+ source(): Query$.Any {
418
446
  return new QueryClass({
419
447
  type: 'relation-traversal',
420
448
  anchor: this.ast,
@@ -422,7 +450,7 @@ class QueryClass implements Echo.Query<any> {
422
450
  });
423
451
  }
424
452
 
425
- target(): Query<any> {
453
+ target(): Query$.Any {
426
454
  return new QueryClass({
427
455
  type: 'relation-traversal',
428
456
  anchor: this.ast,
@@ -430,7 +458,23 @@ class QueryClass implements Echo.Query<any> {
430
458
  });
431
459
  }
432
460
 
433
- orderBy(...order: Order<any>[]): Query<any> {
461
+ parent(): Query$.Any {
462
+ return new QueryClass({
463
+ type: 'hierarchy-traversal',
464
+ anchor: this.ast,
465
+ direction: 'to-parent',
466
+ });
467
+ }
468
+
469
+ children(): Query$.Any {
470
+ return new QueryClass({
471
+ type: 'hierarchy-traversal',
472
+ anchor: this.ast,
473
+ direction: 'to-children',
474
+ });
475
+ }
476
+
477
+ orderBy(...order: Order$.Any[]): Query$.Any {
434
478
  return new QueryClass({
435
479
  type: 'order',
436
480
  query: this.ast,
@@ -438,7 +482,40 @@ class QueryClass implements Echo.Query<any> {
438
482
  });
439
483
  }
440
484
 
441
- options(options: QueryAST.QueryOptions): Query<any> {
485
+ limit(limit: number): Query$.Any {
486
+ return new QueryClass({
487
+ type: 'limit',
488
+ query: this.ast,
489
+ limit,
490
+ });
491
+ }
492
+
493
+ from(arg: any, options?: { includeFeeds?: boolean }): Query$.Any {
494
+ if (arg === 'all-accessible-spaces') {
495
+ return new QueryClass({
496
+ type: 'from',
497
+ query: this.ast,
498
+ from: {
499
+ _tag: 'scope',
500
+ scope: {
501
+ ...(options?.includeFeeds ? { allQueuesFromSpaces: true } : {}),
502
+ },
503
+ },
504
+ });
505
+ }
506
+
507
+ if (_isScopeLike(arg)) {
508
+ return new QueryClass({
509
+ type: 'from',
510
+ query: this.ast,
511
+ from: { _tag: 'scope', scope: arg },
512
+ });
513
+ }
514
+
515
+ throw new TypeError('Database and Feed objects are not supported in query-lite sandbox');
516
+ }
517
+
518
+ options(options: QueryAST.QueryOptions): Query$.Any {
442
519
  return new QueryClass({
443
520
  type: 'options',
444
521
  query: this.ast,
@@ -447,7 +524,7 @@ class QueryClass implements Echo.Query<any> {
447
524
  }
448
525
  }
449
526
 
450
- export const Query1: typeof Echo.Query = QueryClass;
527
+ export const Query1: typeof Query$ = QueryClass;
451
528
  export { Query1 as Query };
452
529
 
453
530
  const RefTypeId: unique symbol = Symbol('@dxos/echo-query/Ref');
@@ -460,3 +537,12 @@ const makeTypeDxn = (typename: string) => {
460
537
  assertArgument(!typename.startsWith('dxn:'), 'typename');
461
538
  return `dxn:type:${typename}`;
462
539
  };
540
+
541
+ const SCOPE_KEYS = new Set(['spaceIds', 'queues', 'allQueuesFromSpaces']);
542
+
543
+ const _isScopeLike = (value: unknown): value is QueryAST.Scope => {
544
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
545
+ return false;
546
+ }
547
+ return Object.keys(value).every((key) => SCOPE_KEYS.has(key));
548
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './query-sandbox';
@@ -5,6 +5,7 @@
5
5
  import { afterAll, beforeAll, describe, expect, test } from 'vitest';
6
6
 
7
7
  import { Filter, Order, Query } from '@dxos/echo';
8
+ import { trim } from '@dxos/util';
8
9
 
9
10
  import { QuerySandbox } from './query-sandbox';
10
11
 
@@ -14,38 +15,38 @@ describe('QuerySandbox', () => {
14
15
  afterAll(() => sandbox.close());
15
16
 
16
17
  test('works', { timeout: 10_000 }, async () => {
17
- const ast = sandbox.eval(`
18
+ const ast = sandbox.eval(trim`
18
19
  Query.select(Filter.typename('dxos.org/type/Person'))
19
20
  `);
20
21
  expect(ast).toEqual(Query.select(Filter.typename('dxos.org/type/Person')).ast);
21
22
  });
22
23
 
23
24
  test('works with just Filter passed in', () => {
24
- const ast = sandbox.eval(`
25
+ const ast = sandbox.eval(trim`
25
26
  Filter.typename('dxos.org/type/Person')
26
27
  `);
27
28
  expect(ast).toEqual(Query.select(Filter.typename('dxos.org/type/Person')).ast);
28
29
  });
29
30
 
30
31
  test('Order', () => {
31
- const ast = sandbox.eval(`
32
+ const ast = sandbox.eval(trim`
32
33
  Query.type('dxos.org/type/Person').orderBy(Order.property('name', 'desc'))
33
34
  `);
34
35
  expect(ast).toEqual(Query.type('dxos.org/type/Person').orderBy(Order.property('name', 'desc')).ast);
35
36
  });
36
37
 
37
38
  test('traversal', () => {
38
- const ast = sandbox.eval(`
39
- Query.select(Filter.type('example.com/type/Person', { jobTitle: 'investor' }))
39
+ const ast = sandbox.eval(trim`
40
+ Query.select(Filter.type('dxos.org/type/Person', { jobTitle: 'investor' }))
40
41
  .reference('organization')
41
- .targetOf('example.com/relation/ResearchOn')
42
+ .targetOf('dxos.org/relation/HasSubject')
42
43
  .source()
43
44
  `);
44
45
 
45
46
  expect(ast).toEqual(
46
- Query.select(Filter.type('example.com/type/Person', { jobTitle: 'investor' }))
47
+ Query.select(Filter.type('dxos.org/type/Person', { jobTitle: 'investor' }))
47
48
  .reference('organization')
48
- .targetOf('example.com/relation/ResearchOn')
49
+ .targetOf('dxos.org/relation/HasSubject')
49
50
  .source().ast,
50
51
  );
51
52
  });
@@ -7,7 +7,7 @@ import { Query, type QueryAST } from '@dxos/echo';
7
7
  import { trim } from '@dxos/util';
8
8
  import { type QuickJSRuntime, type QuickJSWASMModule, createQuickJS } from '@dxos/vendor-quickjs';
9
9
 
10
- import envCode from '#query-env?raw';
10
+ import envCode from '#query-lite?raw';
11
11
 
12
12
  import { unwrapResult } from './quickjs';
13
13
 
@@ -34,7 +34,7 @@ export class QuerySandbox extends Resource {
34
34
  this.#runtime = quickJS.newRuntime({
35
35
  moduleLoader: (moduleName, _context) => {
36
36
  switch (moduleName) {
37
- case 'dxos:query-env':
37
+ case 'dxos:query-lite':
38
38
  return envCode;
39
39
  default:
40
40
  throw new Error(`Module not found: ${moduleName}`);
@@ -54,7 +54,7 @@ export class QuerySandbox extends Resource {
54
54
  eval(queryCode: string): QueryAST.Query {
55
55
  using context = this.#runtime.newContext();
56
56
  const globals = trim`
57
- import { Filter, Order, Query } from 'dxos:query-env';
57
+ import { Filter, Order, Query } from 'dxos:query-lite';
58
58
  globalThis.Filter = Filter;
59
59
  globalThis.Order = Order;
60
60
  globalThis.Query = Query;
@@ -17,8 +17,7 @@ export const unwrapResult = <T>(context: QuickJSContext, result: SuccessOrFail<T
17
17
  if (
18
18
  typeof contextError === 'object' &&
19
19
  typeof contextError.name === 'string' &&
20
- typeof contextError.message === 'string' &&
21
- typeof contextError.stack === 'string'
20
+ typeof contextError.message === 'string'
22
21
  ) {
23
22
  const error = new Error(contextError.message);
24
23
  Object.defineProperty(error, 'name', { value: contextError.name });
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../src/parser/gen/query.ts", "../../../src/parser/gen/query.terms.ts", "../../../src/parser/gen/index.ts", "../../../src/parser/query-builder.ts"],
4
- "sourcesContent": ["// This file was generated by lezer-generator. You probably shouldn't edit it.\nimport {LRParser} from \"@lezer/lr\"\nconst spec_Identifier = {__proto__:null,type:18, NOT:82, not:82, \"!\":82, AND:84, and:84, OR:86, or:86}\nexport const parser = LRParser.deserialize({\n version: 14,\n states: \"(QOVQPOOOOQO'#C_'#C_OOQO'#Ca'#CaOnQPO'#CcOsQPO'#ChO{QPO'#CnO!TQPO'#CgOOQO'#C^'#C^OOQO'#Cv'#CvOOQO'#DU'#DUOVQPO'#DUQ!YQPOOOVQPO'#DUO!jQPO,58}O!oQPO'#DOO!tQPO,59SO!|QPO'#CpOOQO,59Y,59YO#RQPO,59YO#ZQQO,59RO#oQPO,59pOOQO'#Cw'#CwOOQO'#Cx'#CxOOQO'#Cy'#CyOVQPO,59pOVQPO,59pOVQPO,59pO$jQPO,59pOOQO1G.i1G.iOOQO,59j,59jOOQO-E6|-E6|O#ZQQO,59[O$}QPO'#DPO%SQPO1G.tOOQO1G.t1G.tO%[QQO'#CsOOQO'#Cj'#CjOOQO1G.m1G.mO%cQPO1G/[O%yQPO1G/[O&aQPO1G/[OOQO1G/[1G/[OOQO1G.v1G.vOOQO,59k,59kOOQO-E6}-E6}OOQO7+$`7+$`OOQO,59_,59_O&wQPO,59_O#ZQQO'#DQO'PQPO1G.yOOQO1G.y1G.yOOQO,59l,59lOOQO-E7O-E7OOOQO7+$e7+$e\",\n stateData: \"'X~OwOS~OSPOUQOWSOXROcTOp[OyWO~OY]O~O]^OY[X~OW`OfaO~OYcO~OngOogOzeO{fO~PVOWlO~OWmO~O]^OY[a~OYoO~OepOfrO~OUtO_tO`tOatOcTOhsO~OyWOSxaUxaWxaXxacxanxaoxapxauxazxa{xaqxa~OngOogOqyOzeO{fO~PVOW`O~OepOf}O~Oi!OO~P#ZOnxioxiuxizxi{xiqxi~PVOzeOnxioxiuxi{xiqxi~PVOzeO{fOnxioxiuxiqxi~PVOe!QOi!SO~Oe!QOi!VO~O\",\n goto: \"%TyPPz!XP!XP!XPPP!X!fP!sPPP#PP#dPP#^PP#j#x$O$TPPPP$X$_$ePPP$kgXOYZ[hijkvwxgVOYZ[hijkvwxgUOYZ[hijkvwxQucQzoQ!PsR!T!QfVOYZ[hijkvwxXtcos!QQbTR{piYOYZ[dhijkvwxXhZkwxViZkxTjZkQ_SRn_QqbR|qQ!R!PR!U!RQZO^dYZdkvwxQk[QvhQwiRxj\",\n nodeNames: \"⚠ Query Filter TagFilter Tag TextFilter String TypeFilter Identifier TypeKeyword : PropertyFilter PropertyPath . Value Number Boolean Null ObjectLiteral { ObjectProperty , } ArrayLiteral [ ] Not And Or Relation ArrowRight ArrowLeft ( )\",\n maxTerm: 43,\n skippedNodes: [0],\n repeatNodeCount: 3,\n tokenData: \"2w~RrX^#]pq#]rs$Qst%nwx&fxy'}yz(S|}(X}!O(^!O!P)}!Q![(g![!]*S!^!_*X!c!}*d!}#O+O#P#Q+T#R#S*d#T#Y*d#Y#Z+Y#Z#b*d#b#c.i#c#h*d#h#i1Z#i#o*d#o#p2m#q#r2r#y#z#]$f$g#]#BY#BZ#]$IS$I_#]$I|$JO#]$JT$JU#]$KV$KW#]&FU&FV#]~#bYw~X^#]pq#]#y#z#]$f$g#]#BY#BZ#]$IS$I_#]$I|$JO#]$JT$JU#]$KV$KW#]&FU&FV#]~$TVOr$Qrs$js#O$Q#O#P$o#P;'S$Q;'S;=`%h<%lO$Q~$oOU~~$rRO;'S$Q;'S;=`${;=`O$Q~%OWOr$Qrs$js#O$Q#O#P$o#P;'S$Q;'S;=`%h;=`<%l$Q<%lO$Q~%kP;=`<%l$Q~%qT}!O&Q!Q![&Q!c!}&Q#R#S&Q#T#o&Q~&VTS~}!O&Q!Q![&Q!c!}&Q#R#S&Q#T#o&Q~&iVOw&fwx$jx#O&f#O#P'O#P;'S&f;'S;=`'w<%lO&f~'RRO;'S&f;'S;=`'[;=`O&f~'_WOw&fwx$jx#O&f#O#P'O#P;'S&f;'S;=`'w;=`<%l&f<%lO&f~'zP;=`<%l&f~(SOp~~(XOq~~(^Oe~~(aQ!Q![(g!`!a)x~(lS_~!O!P(x!Q![(g!g!h)^#X#Y)^~({P!Q![)O~)TR_~!Q![)O!g!h)^#X#Y)^~)aR{|)j}!O)j!Q![)p~)mP!Q![)p~)uP_~!Q![)p~)}On~~*SO]~~*XOY~~*[P}!O*_~*dOo~P*iVWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#o*d~+TOh~~+YOi~R+_WWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#U+w#U#o*dR+|XWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#`*d#`#a,i#a#o*dR,nXWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#g*d#g#h-Z#h#o*dR-`XWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#X*d#X#Y-{#Y#o*dR.SV`QWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#o*dR.nXWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#i*d#i#j/Z#j#o*dR/`XWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#`*d#`#a/{#a#o*dR0QXWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#`*d#`#a0m#a#o*dR0tVWPaQ}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#o*dR1`XWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#f*d#f#g1{#g#o*dR2QXWP}!O*d!O!P*d!P!Q*d!Q![*d!c!}*d#R#S*d#T#i*d#i#j-Z#j#o*d~2rOc~~2wOf~\",\n tokenizers: [0, 1],\n topRules: {\"Query\":[0,1]},\n specialized: [{term: 8, get: (value: keyof typeof spec_Identifier) => spec_Identifier[value] || -1}],\n tokenPrec: 0\n})\n", "// This file was generated by lezer-generator. You probably shouldn't edit it.\nexport const\n Query = 1,\n Filter = 2,\n TagFilter = 3,\n Tag = 4,\n TextFilter = 5,\n String = 6,\n TypeFilter = 7,\n Identifier = 8,\n TypeKeyword = 9,\n PropertyFilter = 11,\n PropertyPath = 12,\n Value = 14,\n Number = 15,\n Boolean = 16,\n Null = 17,\n ObjectLiteral = 18,\n ObjectProperty = 20,\n ArrayLiteral = 23,\n Not = 26,\n And = 27,\n Or = 28,\n Relation = 29,\n ArrowRight = 30,\n ArrowLeft = 31\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { LRParser } from '@lezer/lr';\nimport { parser } from './query';\nimport * as terms from './query.terms';\n\nexport namespace QueryDSL {\n export const Parser: LRParser = parser;\n export const Node = terms;\n export const Tokens = ['type:', 'AND', 'OR', 'NOT'];\n}\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Parser, type Tree, type TreeCursor } from '@lezer/common';\n\nimport { Filter, type TagMap } from '@dxos/echo';\nimport { invariant } from '@dxos/invariant';\n\nimport { QueryDSL } from './gen';\n\n/**\n * Stateless query builder that parses DSL trees into filters.\n *\n * NOTE: QueryBuilder was largely developed using Claude Sonnet 4.5 (in Windsurf)..\n * To modify the functionality, create a minimal breaking test and direct the LLM to fix either the grammar or builder.\n */\nexport class QueryBuilder {\n private readonly _parser: Parser = QueryDSL.Parser.configure({ strict: true });\n\n constructor(private readonly _tags?: TagMap) {}\n\n /**\n * Check valid input.\n */\n validate(input: string): boolean {\n try {\n const tree = this._parser.parse(input);\n return tree.cursor().node.name === 'Query';\n } catch {\n return false;\n }\n }\n\n /**\n * Build a query from the input string.\n */\n build(input: string): Filter.Any | undefined {\n try {\n const tree = this._parser.parse(input);\n return this.buildQuery(tree, input);\n } catch {\n return undefined;\n }\n }\n\n /**\n * Build a query from a parsed DSL tree.\n */\n buildQuery(tree: Tree, input: string): Filter.Any | undefined {\n const cursor = tree.cursor();\n\n // Start at root (Query node).\n if (cursor.node.name !== 'Query') {\n return undefined;\n }\n\n // Check if Query has multiple children (binary expression).\n const children: Array<{ name: string; from: number; to: number }> = [];\n if (cursor.firstChild()) {\n do {\n children.push({ name: cursor.node.name, from: cursor.from, to: cursor.to });\n } while (cursor.nextSibling());\n cursor.parent();\n }\n\n // If we have an operator in the children, or multiple expressions (implicit AND), parse as binary expression.\n const hasOperator = children.some((child) => child.name === 'And' || child.name === 'Or');\n const hasMultipleExpressions =\n children.filter((child) => child.name === 'Filter' || child.name === 'Not' || child.name === '(').length > 1;\n if (hasOperator || hasMultipleExpressions) {\n return this._parseBinaryExpression(cursor, input);\n }\n\n // Otherwise, parse the single expression.\n if (!cursor.firstChild()) {\n return Filter.nothing();\n }\n\n return this._parseExpression(cursor, input);\n }\n\n /**\n * Parse an expression node.\n */\n private _parseExpression(cursor: TreeCursor, input: string): Filter.Any | undefined {\n const nodeName = cursor.node.name;\n\n switch (nodeName) {\n case 'Filter':\n return this._parseFilter(cursor, input);\n\n case 'Not': {\n // Move past NOT token to the expression.\n cursor.nextSibling();\n const notFilter = this._parseExpression(cursor, input);\n return notFilter ? Filter.not(notFilter) : undefined;\n }\n\n case 'And':\n case 'Or':\n // This is the operator node, we need to handle the binary expression.\n // The cursor is positioned at the operator, we need to go back to parent.\n cursor.parent();\n return this._parseBinaryExpression(cursor, input);\n\n case '(': {\n // Skip opening paren.\n cursor.nextSibling();\n const parenFilter = this._parseExpression(cursor, input);\n // Skip closing paren.\n cursor.nextSibling();\n return parenFilter;\n }\n\n default: {\n // Check if this is a binary expression (has And/Or as a child).\n const savedPos = cursor.from;\n if (cursor.firstChild()) {\n // Look for And/Or operators or multiple expressions (implicit AND).\n let hasOperator = false;\n let expressionCount = 0;\n do {\n if (cursor.node.name === 'And' || cursor.node.name === 'Or') {\n hasOperator = true;\n break;\n }\n if (cursor.node.name === 'Filter' || cursor.node.name === 'Not' || cursor.node.name === '(') {\n expressionCount++;\n }\n } while (cursor.nextSibling());\n hasOperator = hasOperator || expressionCount > 1;\n\n // Reset cursor to the saved position.\n cursor.parent();\n cursor.firstChild();\n while (cursor.from !== savedPos && cursor.nextSibling()) {}\n\n if (hasOperator) {\n cursor.parent();\n return this._parseBinaryExpression(cursor, input);\n } else {\n const result = this._parseExpression(cursor, input);\n cursor.parent();\n return result;\n }\n }\n return Filter.nothing();\n }\n }\n }\n\n /**\n * Parse a binary expression (AND/OR).\n */\n private _parseBinaryExpression(cursor: TreeCursor, input: string): Filter.Any {\n const filters: Filter.Any[] = [];\n let operator: 'and' | 'or' | null = null;\n\n // Collect all filters and operators.\n if (cursor.firstChild()) {\n do {\n const nodeName = cursor.node.name;\n\n if (nodeName === 'And' || nodeName === 'Or') {\n operator = nodeName.toLowerCase() as 'and' | 'or';\n } else if (nodeName === '(') {\n // Handle parenthesized expression.\n // Look ahead to see if this is a binary expression.\n const savedPos = cursor.from;\n cursor.nextSibling(); // Move past '('\n\n // Check if the parentheses contain a binary expression.\n let hasBinaryOp = false;\n do {\n if (cursor.node.name === 'And' || cursor.node.name === 'Or') {\n hasBinaryOp = true;\n break;\n }\n } while (cursor.nextSibling() && cursor.node.name !== ')');\n\n // Reset cursor to start of parenthesized content.\n cursor.parent();\n cursor.firstChild();\n while (cursor.from !== savedPos && cursor.nextSibling()) {}\n cursor.nextSibling(); // Move past '(' again.\n\n if (hasBinaryOp) {\n // Find the matching closing parenthesis.\n let depth = 1;\n const exprStart = cursor.from;\n let exprEnd = cursor.to;\n\n while (cursor.nextSibling() && depth > 0) {\n if (cursor.node.name === '(') depth++;\n else if (cursor.node.name === ')') {\n depth--;\n if (depth === 0) {\n exprEnd = cursor.from;\n }\n }\n }\n\n // Parse the expression inside parentheses as a subtree.\n const subInput = input.slice(exprStart, exprEnd);\n const subTree = this._parser.parse(subInput);\n const subFilter = this.buildQuery(subTree, subInput);\n if (subFilter) {\n filters.push(subFilter);\n }\n } else {\n // Simple parenthesized expression.\n const subFilter = this._parseExpression(cursor, input);\n if (subFilter) {\n filters.push(subFilter);\n }\n\n // Skip until we find the closing parenthesis.\n while (cursor.nextSibling() && cursor.node.name !== ')') {}\n }\n } else if (nodeName !== ')') {\n const subFilter = this._parseExpression(cursor, input);\n if (subFilter) {\n filters.push(subFilter);\n }\n }\n } while (cursor.nextSibling());\n\n cursor.parent();\n }\n\n if (filters.length === 0) {\n return Filter.nothing();\n }\n\n if (filters.length === 1) {\n return filters[0];\n }\n\n return operator === 'or' ? Filter.or(...filters) : Filter.and(...filters);\n }\n\n /**\n * Parse a Filter node.\n */\n private _parseFilter(cursor: TreeCursor, input: string): Filter.Any | undefined {\n if (!cursor.firstChild()) {\n return Filter.nothing();\n }\n\n let result: Filter.Any | undefined = undefined;\n const filterType = cursor.node.name;\n switch (filterType) {\n case 'TagFilter':\n if (this._tags) {\n result = this._parseTagFilter(cursor, input);\n }\n break;\n\n case 'TextFilter':\n result = this._parseTextFilter(cursor, input);\n break;\n\n case 'TypeFilter':\n result = this._parseTypeFilter(cursor, input);\n break;\n\n case 'ObjectLiteral':\n result = this._parseObjectLiteral(cursor, input);\n break;\n\n case 'PropertyFilter':\n result = this._parsePropertyFilter(cursor, input);\n break;\n\n default:\n result = Filter.nothing();\n }\n\n cursor.parent();\n return result;\n }\n\n /**\n * Parse a TypeFilter node (type:typename).\n */\n private _parseTypeFilter(cursor: TreeCursor, input: string): Filter.Any {\n // Skip TypeKeyword.\n cursor.firstChild();\n cursor.nextSibling(); // Skip ':'\n cursor.nextSibling(); // Move to Identifier\n\n const typename = this._getNodeText(cursor, input);\n cursor.parent(); // Go back to TypeFilter.\n return Filter.typename(typename);\n }\n\n /**\n * Parse a TextFilter node (quoted string).\n */\n private _parseTextFilter(cursor: TreeCursor, input: string): Filter.Any {\n cursor.firstChild(); // Move to String node.\n const text = this._getNodeText(cursor, input);\n cursor.parent(); // Go back to TextFilter.\n // Remove quotes.\n return Filter.text(text.slice(1, -1));\n }\n\n /**\n * Parse an ObjectLiteral node.\n */\n private _parseObjectLiteral(cursor: TreeCursor, input: string): Filter.Any {\n const props: Record<string, any> = {};\n\n if (cursor.firstChild()) {\n do {\n if (cursor.node.name === 'ObjectProperty') {\n const { key, value } = this._parseObjectProperty(cursor, input);\n if (key) {\n // Convert simple values to Filter.eq for compatibility with Filter.props.\n props[key] = Filter.eq(value);\n }\n }\n } while (cursor.nextSibling());\n\n cursor.parent();\n }\n\n return Filter.props(props);\n }\n\n /**\n * Parse an ObjectProperty node.\n */\n private _parseObjectProperty(cursor: TreeCursor, input: string): { key: string | null; value: any } {\n let key: string | null = null;\n let value: any = null;\n\n if (cursor.firstChild()) {\n // First child should be the property name (Identifier).\n if (cursor.node.name === 'Identifier') {\n key = this._getNodeText(cursor, input);\n }\n\n // Skip ':' and move to Value.\n cursor.nextSibling();\n cursor.nextSibling();\n\n if (cursor.node.name === 'Value' && cursor.firstChild()) {\n value = this._parseValue(cursor, input);\n cursor.parent();\n }\n\n cursor.parent();\n }\n\n return { key, value };\n }\n\n /**\n * Parse a PropertyFilter node (property:value).\n */\n private _parsePropertyFilter(cursor: TreeCursor, input: string): Filter.Any {\n let path: string | null = null;\n let value: any = null;\n\n if (cursor.firstChild()) {\n // First child is PropertyPath.\n if (cursor.node.name === 'PropertyPath') {\n path = this._parsePropertyPath(cursor, input);\n }\n\n // Skip ':' and move to Value.\n cursor.nextSibling();\n cursor.nextSibling();\n\n if (cursor.node.name === 'Value' && cursor.firstChild()) {\n value = this._parseValue(cursor, input);\n cursor.parent();\n }\n\n cursor.parent();\n }\n\n if (!path) {\n return Filter.nothing();\n }\n\n return Filter.props({ [path]: value });\n }\n\n /**\n * Parse a PropertyPath node (supports dot notation).\n */\n private _parsePropertyPath(cursor: TreeCursor, input: string): string {\n const parts: string[] = [];\n\n if (cursor.firstChild()) {\n do {\n if (cursor.node.name === 'Identifier') {\n parts.push(this._getNodeText(cursor, input));\n }\n } while (cursor.nextSibling());\n\n cursor.parent();\n }\n\n return parts.join('.');\n }\n\n /**\n * Parse a TagFilter node (#tag).\n */\n private _parseTagFilter(cursor: TreeCursor, input: string): Filter.Any | undefined {\n invariant(this._tags);\n const str = this._getNodeText(cursor, input).slice(1).toLowerCase();\n const [key] = Object.entries(this._tags!).find(([, value]) => value.label.toLowerCase() === str) ?? [];\n return key ? Filter.tag(key) : undefined;\n }\n\n /**\n * Parse a Value node.\n */\n private _parseValue(cursor: TreeCursor, input: string): any {\n const valueType = cursor.node.name;\n\n switch (valueType) {\n case 'String': {\n // Remove quotes.\n const str = this._getNodeText(cursor, input);\n return str.slice(1, -1);\n }\n\n case 'Number':\n return Number(this._getNodeText(cursor, input));\n\n case 'Boolean':\n return this._getNodeText(cursor, input) === 'true';\n\n case 'Null':\n return null;\n\n case 'ObjectLiteral': {\n // For nested objects, parse recursively.\n const props: Record<string, any> = {};\n if (cursor.firstChild()) {\n do {\n if (cursor.node.name === 'ObjectProperty') {\n const { key, value } = this._parseObjectProperty(cursor, input);\n if (key) {\n props[key] = value;\n }\n }\n } while (cursor.nextSibling());\n cursor.parent();\n }\n return props;\n }\n\n case 'ArrayLiteral': {\n // Parse array values\n const array: any[] = [];\n if (cursor.firstChild()) {\n do {\n if (cursor.node.name === 'Value' && cursor.firstChild()) {\n array.push(this._parseValue(cursor, input));\n cursor.parent();\n }\n } while (cursor.nextSibling());\n cursor.parent();\n }\n return array;\n }\n\n default:\n return null;\n }\n }\n\n /**\n * Get the text content of the current node.\n */\n private _getNodeText(cursor: TreeCursor, input: string): string {\n return input.slice(cursor.from, cursor.to);\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["LRParser", "spec_Identifier", "__proto__", "type", "NOT", "not", "AND", "and", "OR", "or", "parser", "LRParser", "deserialize", "version", "states", "stateData", "goto", "nodeNames", "maxTerm", "skippedNodes", "repeatNodeCount", "tokenData", "tokenizers", "topRules", "specialized", "term", "get", "value", "tokenPrec", "Number", "Query", "Filter", "TagFilter", "Tag", "TextFilter", "String", "TypeFilter", "Identifier", "TypeKeyword", "PropertyFilter", "PropertyPath", "Value", "Number", "Boolean", "Null", "ObjectLiteral", "ObjectProperty", "ArrayLiteral", "Not", "And", "Or", "Relation", "ArrowRight", "ArrowLeft", "QueryDSL", "Parser", "parser", "Node", "terms", "Tokens", "Filter", "invariant", "QueryBuilder", "validate", "input", "tree", "_parser", "parse", "cursor", "node", "name", "build", "buildQuery", "undefined", "children", "firstChild", "push", "from", "to", "nextSibling", "parent", "hasOperator", "some", "child", "hasMultipleExpressions", "filter", "length", "_parseBinaryExpression", "Filter", "nothing", "_parseExpression", "nodeName", "_parseFilter", "notFilter", "not", "parenFilter", "savedPos", "expressionCount", "result", "filters", "operator", "toLowerCase", "hasBinaryOp", "depth", "exprStart", "exprEnd", "subInput", "slice", "subTree", "subFilter", "or", "and", "filterType", "_tags", "_parseTagFilter", "_parseTextFilter", "_parseTypeFilter", "_parseObjectLiteral", "_parsePropertyFilter", "typename", "_getNodeText", "text", "props", "key", "value", "_parseObjectProperty", "eq", "_parseValue", "path", "_parsePropertyPath", "parts", "join", "invariant", "str", "Object", "entries", "find", "label", "tag", "valueType", "Number", "array", "QueryDSL", "Parser", "configure", "strict"]
7
- }