@malloydata/malloy-filter 0.0.240-dev250311213218 → 0.0.240

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 (114) hide show
  1. package/README.md +53 -86
  2. package/dist/boolean_filter_expression.d.ts +5 -0
  3. package/dist/boolean_filter_expression.js +68 -0
  4. package/dist/boolean_filter_expression.js.map +1 -0
  5. package/dist/clause_utils.d.ts +111 -0
  6. package/dist/clause_utils.js +280 -0
  7. package/dist/clause_utils.js.map +1 -0
  8. package/dist/filter_clause.d.ts +127 -0
  9. package/dist/filter_clause.js +81 -0
  10. package/dist/filter_clause.js.map +1 -0
  11. package/dist/index.d.ts +5 -10
  12. package/dist/index.js +10 -19
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib/fexpr_number_parser.d.ts +28 -0
  15. package/dist/lib/fexpr_number_parser.js +77 -0
  16. package/dist/lib/fexpr_number_parser.js.map +1 -0
  17. package/dist/lib/fexpr_string_parser.d.ts +28 -0
  18. package/dist/lib/fexpr_string_parser.js +54 -0
  19. package/dist/lib/fexpr_string_parser.js.map +1 -0
  20. package/dist/lib/ftemporal_parser.d.ts +28 -0
  21. package/dist/lib/ftemporal_parser.js +161 -0
  22. package/dist/lib/ftemporal_parser.js.map +1 -0
  23. package/dist/nearley_parse.d.ts +6 -0
  24. package/dist/nearley_parse.js +45 -0
  25. package/dist/nearley_parse.js.map +1 -0
  26. package/dist/number_filter_expression.d.ts +5 -0
  27. package/dist/number_filter_expression.js +95 -0
  28. package/dist/number_filter_expression.js.map +1 -0
  29. package/dist/string_filter_expression.d.ts +5 -0
  30. package/dist/string_filter_expression.js +108 -0
  31. package/dist/string_filter_expression.js.map +1 -0
  32. package/dist/temporal_filter_expression.d.ts +5 -0
  33. package/dist/temporal_filter_expression.js +125 -0
  34. package/dist/temporal_filter_expression.js.map +1 -0
  35. package/package.json +16 -8
  36. package/src/boolean_filter_expression.ts +62 -0
  37. package/src/clause_utils.ts +315 -0
  38. package/src/filter_clause.ts +286 -0
  39. package/src/index.ts +5 -10
  40. package/src/lib/fexpr_number_parser.ts +113 -0
  41. package/src/lib/fexpr_string_parser.ts +84 -0
  42. package/src/lib/ftemporal_parser.ts +235 -0
  43. package/src/nearley_parse.ts +45 -0
  44. package/src/number_filter_expression.ts +75 -0
  45. package/src/string_filter_expression.ts +86 -0
  46. package/src/temporal_filter_expression.ts +111 -0
  47. package/SAMPLES.md +0 -724
  48. package/SERIALIZE_SAMPLES.md +0 -567
  49. package/dist/a_simple_parser.d.ts +0 -1
  50. package/dist/a_simple_parser.js +0 -29
  51. package/dist/a_simple_parser.js.map +0 -1
  52. package/dist/base_parser.d.ts +0 -11
  53. package/dist/base_parser.js +0 -39
  54. package/dist/base_parser.js.map +0 -1
  55. package/dist/boolean_parser.d.ts +0 -7
  56. package/dist/boolean_parser.js +0 -76
  57. package/dist/boolean_parser.js.map +0 -1
  58. package/dist/boolean_serializer.d.ts +0 -8
  59. package/dist/boolean_serializer.js +0 -45
  60. package/dist/boolean_serializer.js.map +0 -1
  61. package/dist/clause_types.d.ts +0 -68
  62. package/dist/clause_types.js +0 -9
  63. package/dist/clause_types.js.map +0 -1
  64. package/dist/date_parser.d.ts +0 -25
  65. package/dist/date_parser.js +0 -434
  66. package/dist/date_parser.js.map +0 -1
  67. package/dist/date_serializer.d.ts +0 -11
  68. package/dist/date_serializer.js +0 -94
  69. package/dist/date_serializer.js.map +0 -1
  70. package/dist/date_types.d.ts +0 -75
  71. package/dist/date_types.js +0 -9
  72. package/dist/date_types.js.map +0 -1
  73. package/dist/generate_samples.d.ts +0 -1
  74. package/dist/generate_samples.js +0 -339
  75. package/dist/generate_samples.js.map +0 -1
  76. package/dist/number_parser.d.ts +0 -17
  77. package/dist/number_parser.js +0 -252
  78. package/dist/number_parser.js.map +0 -1
  79. package/dist/number_serializer.d.ts +0 -11
  80. package/dist/number_serializer.js +0 -85
  81. package/dist/number_serializer.js.map +0 -1
  82. package/dist/string_parser.d.ts +0 -18
  83. package/dist/string_parser.js +0 -195
  84. package/dist/string_parser.js.map +0 -1
  85. package/dist/string_serializer.d.ts +0 -13
  86. package/dist/string_serializer.js +0 -108
  87. package/dist/string_serializer.js.map +0 -1
  88. package/dist/token_types.d.ts +0 -7
  89. package/dist/token_types.js +0 -9
  90. package/dist/token_types.js.map +0 -1
  91. package/dist/tokenizer.d.ts +0 -52
  92. package/dist/tokenizer.js +0 -269
  93. package/dist/tokenizer.js.map +0 -1
  94. package/dist/tokenizer.spec.d.ts +0 -1
  95. package/dist/tokenizer.spec.js +0 -261
  96. package/dist/tokenizer.spec.js.map +0 -1
  97. package/jest.config.js +0 -3
  98. package/src/DEVELOPING.md +0 -19
  99. package/src/a_simple_parser.ts +0 -32
  100. package/src/base_parser.ts +0 -49
  101. package/src/boolean_parser.ts +0 -77
  102. package/src/boolean_serializer.ts +0 -46
  103. package/src/clause_types.ts +0 -122
  104. package/src/date_parser.ts +0 -512
  105. package/src/date_serializer.ts +0 -93
  106. package/src/date_types.ts +0 -167
  107. package/src/generate_samples.ts +0 -374
  108. package/src/number_parser.ts +0 -278
  109. package/src/number_serializer.ts +0 -102
  110. package/src/string_parser.ts +0 -207
  111. package/src/string_serializer.ts +0 -140
  112. package/src/token_types.ts +0 -14
  113. package/src/tokenizer.spec.ts +0 -280
  114. package/src/tokenizer.ts +0 -327
package/README.md CHANGED
@@ -1,91 +1,58 @@
1
- # Malloy Filter Expressions
2
-
3
- This repository contains the parser and serializer for Malloy filter expressions. Filter expressions give Malloy users a powerful, yet simple and intuitive, way to specify complex filtering conditions.
4
-
5
- The library contains no external dependencies, and is designed to produce a lightweight data structure that can be embedded with minimal overhead into products interfacing with Malloy. Instructions for building and using the library are below.
6
-
7
- The WN for filter expressions is [TBD].
8
-
9
- ## Building
10
-
11
- ```bash
12
- npm run build
13
- ```
14
-
15
- ## Using
16
-
17
- To use the parser, simply import `FilterParser` and go.
18
-
19
- Example:
20
-
21
- ```code
22
- import {BooleanParser} from './boolean_parser';
23
- import {StringParser} from './string_parser';
24
- import {NumberParser} from './number_parser';
25
- import {DateParser} from './date_parser';
26
-
27
- function aSimpleParser() {
28
- let str = 'CAT,DOG';
29
- const stringResponse = new StringParser(str).parse();
30
- console.log(str, '\n', ...stringResponse.clauses, '\n');
31
-
32
- str = '-5.5, 10, 2.3e7';
33
- const numberResponse = new NumberParser(str).parse();
34
- console.log(str, '\n', ...numberResponse.clauses, '\n');
35
-
36
- str = 'null, false';
37
- const booleanResponse = new BooleanParser(str).parse();
38
- console.log(str, '\n', ...booleanResponse.clauses, '\n');
39
-
40
- str = 'after 2025-10-05';
41
- const dateResponse = new DateParser(str).parse();
42
- console.log(str, '\n', ...dateResponse.clauses, '\n');
1
+ # Filter Languages
2
+
3
+ There is a unique filter language for each filterable data type. The documentation-bRoKeN-lInK describes the various languages.
4
+
5
+ # Grammars
6
+
7
+ `malloy-filter` use [moo](https://github.com/no-context/moo?tab=readme-ov-file) and [nearley](https://nearley.js.org/) to generate parsers for each sub language. The grammars are in `grammars`.
8
+
9
+ After changing a `.ne` file use `npm run build` to update the generated parser.
10
+
11
+ # API
12
+
13
+ Refer to the [clause interfaces](src/filter_clause.ts) for details on the
14
+ output of the parser, or look at the parser tests in [`src/test/`](src/test/) for more examples
15
+ of parser output.
16
+
17
+ ```TypeScript
18
+ import {StringFilterExpression, StringClause} from '@malloydata/malloy-filter'
19
+
20
+ // or ...
21
+ // NumberFilterExpression, NumberClause
22
+ // BooleanFilterExpression, BooleanClause
23
+ // TemporalFilterExpression, TemporalClause
24
+
25
+ // Each has two entry points, "parse" and "unparse"
26
+
27
+ const stringParse = StringFilterExpression.parse('FOO%,-FOOD')
28
+ if (stringParse.parsed) {
29
+ console.log(JSON.stringify(stringParse.parsed, null, 2));
30
+ /*
31
+ * Output will look something like this ...
32
+ * { operator: ',',
33
+ * members: [
34
+ * {operator: 'starts', values: ['FOO']}
35
+ * {operator: '=', not: true, values: ['FOOD']}
36
+ * ],
37
+ * }
38
+ */
39
+ console.log(StringFilterExpression.unparse(stringParse.parse));
40
+ /*
41
+ * There will be minor variations on unparse, for example in this
42
+ * case there will be space after the comma:
43
+ *
44
+ * FOO%, -FOOD
45
+ */
46
+ } else {
47
+ console.log(stringParse.log);
43
48
  }
44
-
45
- aSimpleParser();
46
49
  ```
47
50
 
48
- Output:
49
-
50
- ```code
51
- CAT,DOG
52
- { operator: '=', values: [ 'CAT', 'DOG' ] }
51
+ # Testing
53
52
 
54
- -5.5, 10, 2.3e7
55
- { operator: '=', values: [ -5.5, 10, 23000000 ] }
53
+ The `malloy-filter` tests use Jest.
56
54
 
57
- null, false
58
- { operator: 'NULL' } { operator: 'FALSEORNULL' }
59
-
60
- after 2025-10-05
61
- {
62
- operator: 'AFTER',
63
- moment: { type: 'ABSOLUTE', date: '2025-10-05', unit: 'DAY' }
64
- }
65
- ```
66
-
67
- Likewise, to use the serializers, simply import the `*Serializer` classes.
68
-
69
- ## Parsers
70
-
71
- Each filter type is handled by a different parser (strings, numbers, dates and times, etc).
72
-
73
- ### Number Parser
74
-
75
- The number parser `number_parser.ts` supports the operations highlighted on the [Samples](SAMPLES.md#numbers) page.
76
-
77
- ### String Parser
78
-
79
- The string parser `string_parser.ts` supports the operations highlighted on the [Samples](SAMPLES.md#strings) page.
80
-
81
- ### Boolean Parser
82
-
83
- The boolean parser `boolean_parser.ts` supports the operations highlighted on the [Samples](SAMPLES.md#booleans) page.
84
-
85
- ### Date and Time Parser
86
-
87
- The date and time parser `date_parser.ts` supports the operations highlighted on the [Samples](SAMPLES.md#dates-and-times) page.
88
-
89
- ## Serializers
90
-
91
- Each parser has a complementary serializer that converts the parser output (`xxxClause[]`) back to a string. See examples of the round trip from string to Clause to string on the [Serialization Samples](SERIALIZE_SAMPLES.md) page.
55
+ ```bash
56
+ npm run build
57
+ npm run test
58
+ ```
@@ -0,0 +1,5 @@
1
+ import { BooleanClause, FilterParserReponse } from './filter_clause';
2
+ export declare const BooleanFilterExpression: {
3
+ parse(srcText: string): FilterParserReponse<BooleanClause>;
4
+ unparse(bc: BooleanClause | null): string;
5
+ };
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.BooleanFilterExpression = void 0;
10
+ exports.BooleanFilterExpression = {
11
+ parse(srcText) {
12
+ var _a;
13
+ const ret = { parsed: null, log: [] };
14
+ let src = srcText.toLowerCase().trim().replace(/\s\s+/, ' ');
15
+ let negate = false;
16
+ if (src.startsWith('not ')) {
17
+ negate = true;
18
+ src = src.slice(4);
19
+ }
20
+ if (src === 'true') {
21
+ ret.parsed = { operator: 'true' };
22
+ }
23
+ else if (src === 'false') {
24
+ ret.parsed = { operator: 'false_or_null' };
25
+ }
26
+ else if (src === '=false') {
27
+ ret.parsed = { operator: 'false' };
28
+ }
29
+ else if (src === 'null') {
30
+ ret.parsed = { operator: 'null' };
31
+ }
32
+ else if (src === 'not null') {
33
+ ret.parsed = { operator: 'null', not: true };
34
+ }
35
+ else {
36
+ const nonSpace = srcText.match(/[^\s]/);
37
+ const startIndex = nonSpace ? (_a = nonSpace.index) !== null && _a !== void 0 ? _a : 0 : 0;
38
+ ret.log = [
39
+ {
40
+ message: 'Illegal boolean filter. Must be one of true,false,=false,null,not null',
41
+ severity: 'error',
42
+ startIndex,
43
+ endIndex: startIndex + srcText.length - 1,
44
+ },
45
+ ];
46
+ }
47
+ if (negate && ret.parsed) {
48
+ ret.parsed.not = true;
49
+ }
50
+ return ret;
51
+ },
52
+ unparse(bc) {
53
+ if (bc === null) {
54
+ return '';
55
+ }
56
+ const n = bc.not ? 'not ' : '';
57
+ switch (bc.operator) {
58
+ case 'true':
59
+ case 'null':
60
+ return n + bc.operator;
61
+ case 'false_or_null':
62
+ return n + 'false';
63
+ case 'false':
64
+ return n + '=false';
65
+ }
66
+ },
67
+ };
68
+ //# sourceMappingURL=boolean_filter_expression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boolean_filter_expression.js","sourceRoot":"","sources":["../src/boolean_filter_expression.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAIU,QAAA,uBAAuB,GAAG;IACrC,KAAK,CAAC,OAAe;;QACnB,MAAM,GAAG,GAAuC,EAAC,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAC,CAAC;QACxE,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC7D,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE;YAC1B,MAAM,GAAG,IAAI,CAAC;YACd,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACpB;QACD,IAAI,GAAG,KAAK,MAAM,EAAE;YAClB,GAAG,CAAC,MAAM,GAAG,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC;SACjC;aAAM,IAAI,GAAG,KAAK,OAAO,EAAE;YAC1B,GAAG,CAAC,MAAM,GAAG,EAAC,QAAQ,EAAE,eAAe,EAAC,CAAC;SAC1C;aAAM,IAAI,GAAG,KAAK,QAAQ,EAAE;YAC3B,GAAG,CAAC,MAAM,GAAG,EAAC,QAAQ,EAAE,OAAO,EAAC,CAAC;SAClC;aAAM,IAAI,GAAG,KAAK,MAAM,EAAE;YACzB,GAAG,CAAC,MAAM,GAAG,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC;SACjC;aAAM,IAAI,GAAG,KAAK,UAAU,EAAE;YAC7B,GAAG,CAAC,MAAM,GAAG,EAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAC,CAAC;SAC5C;aAAM;YACL,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAA,QAAQ,CAAC,KAAK,mCAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YACtD,GAAG,CAAC,GAAG,GAAG;gBACR;oBACE,OAAO,EACL,wEAAwE;oBAC1E,QAAQ,EAAE,OAAO;oBACjB,UAAU;oBACV,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC;iBAC1C;aACF,CAAC;SACH;QACD,IAAI,MAAM,IAAI,GAAG,CAAC,MAAM,EAAE;YACxB,GAAG,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,CAAC;SACvB;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IACD,OAAO,CAAC,EAAwB;QAC9B,IAAI,EAAE,KAAK,IAAI,EAAE;YACf,OAAO,EAAE,CAAC;SACX;QACD,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,QAAQ,EAAE,CAAC,QAAQ,EAAE;YACnB,KAAK,MAAM,CAAC;YACZ,KAAK,MAAM;gBACT,OAAO,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;YACzB,KAAK,eAAe;gBAClB,OAAO,CAAC,GAAG,OAAO,CAAC;YACrB,KAAK,OAAO;gBACV,OAAO,CAAC,GAAG,QAAQ,CAAC;SACvB;IACH,CAAC;CACF,CAAC"}
@@ -0,0 +1,111 @@
1
+ import { ChainOp, NumberRange, StringClause, NumberClause, TemporalUnit, TemporalLiteral, TemporalClause } from './filter_clause';
2
+ /**
3
+ * If there is a minus token, add "not:true" to the clause
4
+ */
5
+ export declare function maybeNot(data: (Object | undefined)[]): Object | {
6
+ not: boolean;
7
+ operator: "null";
8
+ } | {
9
+ not: boolean;
10
+ operator: import("./filter_clause").StringConditionOperator;
11
+ values: string[];
12
+ } | {
13
+ not: boolean;
14
+ operator: "~";
15
+ escaped_values: string[];
16
+ } | {
17
+ not: boolean;
18
+ operator: "empty";
19
+ } | {
20
+ not: boolean;
21
+ operator: ChainOp;
22
+ members: StringClause[];
23
+ } | {
24
+ not: boolean;
25
+ operator: "()";
26
+ expr: StringClause;
27
+ } | undefined;
28
+ export declare function unescape(str: string): string;
29
+ /**
30
+ * Escape all of these: ,;| ()\%_
31
+ */
32
+ export declare function escape(str: string): string;
33
+ /**
34
+ * Generate the correct match clause operator based on the contents
35
+ * of the match string.
36
+ */
37
+ export declare function matchOp(matchSrc: string): StringClause;
38
+ export declare function conjoin(left: Object, op: string, right: Object): StringClause | null;
39
+ export declare function joinNumbers(left: Object, op: string, right: Object): NumberClause | null;
40
+ export declare function mkRange(left: string, rFrom: string, rTo: string, right: string): NumberRange | null;
41
+ export declare function numNot(op: Object, notToken: unknown): Object | {
42
+ not: boolean;
43
+ operator: "null";
44
+ } | {
45
+ not: boolean;
46
+ operator: import("./filter_clause").NumberOperator;
47
+ values: string[];
48
+ } | {
49
+ not: boolean;
50
+ operator: "range";
51
+ startOperator: import("./filter_clause").NumberRangeOperator;
52
+ startValue: string;
53
+ endOperator: import("./filter_clause").NumberRangeOperator;
54
+ endValue: string;
55
+ } | {
56
+ not: boolean;
57
+ operator: "()";
58
+ expr: NumberClause;
59
+ } | {
60
+ not: boolean;
61
+ operator: ChainOp;
62
+ members: NumberClause[];
63
+ };
64
+ export declare function temporalNot(op: Object, notToken: unknown): Object | {
65
+ not: boolean;
66
+ operator: "null";
67
+ } | {
68
+ not: boolean;
69
+ operator: "before";
70
+ before: import("./filter_clause").Moment;
71
+ } | {
72
+ not: boolean;
73
+ operator: "after";
74
+ after: import("./filter_clause").Moment;
75
+ } | {
76
+ not: boolean;
77
+ operator: "to";
78
+ fromMoment: import("./filter_clause").Moment;
79
+ toMoment: import("./filter_clause").Moment;
80
+ } | {
81
+ not: boolean;
82
+ operator: "for";
83
+ begin: import("./filter_clause").Moment;
84
+ units: TemporalUnit;
85
+ n: string;
86
+ } | {
87
+ not: boolean;
88
+ operator: "in_last";
89
+ units: TemporalUnit;
90
+ n: string;
91
+ } | {
92
+ not: boolean;
93
+ operator: "last" | "next";
94
+ units: TemporalUnit;
95
+ n: string;
96
+ } | {
97
+ not: boolean;
98
+ operator: "in";
99
+ in: import("./filter_clause").Moment;
100
+ } | {
101
+ not: boolean;
102
+ operator: ChainOp;
103
+ members: TemporalClause[];
104
+ } | {
105
+ not: boolean;
106
+ operator: "()";
107
+ expr: TemporalClause;
108
+ };
109
+ export declare function joinTemporal(left: Object, op: string, right: Object): TemporalClause | null;
110
+ export declare function timeLiteral(literal: string, units?: TemporalUnit): TemporalLiteral;
111
+ export declare function mkUnits(unit_s: string): TemporalUnit | undefined;
@@ -0,0 +1,280 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.mkUnits = exports.timeLiteral = exports.joinTemporal = exports.temporalNot = exports.numNot = exports.mkRange = exports.joinNumbers = exports.conjoin = exports.matchOp = exports.escape = exports.unescape = exports.maybeNot = void 0;
10
+ const filter_clause_1 = require("./filter_clause");
11
+ /**
12
+ * If there is a minus token, add "not:true" to the clause
13
+ */
14
+ function maybeNot(data) {
15
+ const [isMinus, op] = data;
16
+ if (isMinus && op && (0, filter_clause_1.isStringClause)(op)) {
17
+ return { ...op, not: true };
18
+ }
19
+ return op;
20
+ }
21
+ exports.maybeNot = maybeNot;
22
+ function unescape(str) {
23
+ return str.replace(/\\(.)/g, '$1');
24
+ }
25
+ exports.unescape = unescape;
26
+ /**
27
+ * Escape all of these: ,;| ()\%_
28
+ */
29
+ function escape(str) {
30
+ const lstr = str.toLowerCase();
31
+ if (lstr === 'null' || lstr === 'empty') {
32
+ return '\\' + str;
33
+ }
34
+ return str.replace(/([,; |()\\%_-])/g, '\\$1');
35
+ }
36
+ exports.escape = escape;
37
+ /**
38
+ * I tried to write the regex for these and I just kept finding strings where the regex failed.
39
+ * Look at a string and find if it uses any unescaped like characters, if it starts or ends with
40
+ * a percent match, and counts trailing spaces
41
+ */
42
+ function describeString(s) {
43
+ let state = 0;
44
+ let percentStart = false;
45
+ let percentEnd = false;
46
+ let endSpace = 0;
47
+ let hasLike = false;
48
+ const iLen = s.length;
49
+ for (const c of s) {
50
+ if (state === 0) {
51
+ // Beginning of line
52
+ state = 1;
53
+ if (c === '%') {
54
+ hasLike = true;
55
+ percentStart = true;
56
+ continue;
57
+ }
58
+ }
59
+ if (state === 1) {
60
+ // Looking for backslash
61
+ if (c === '\\') {
62
+ endSpace = 0;
63
+ percentEnd = false;
64
+ state = 2;
65
+ continue;
66
+ }
67
+ if (c === ' ' || c === '\t') {
68
+ percentEnd = false;
69
+ endSpace += 1;
70
+ }
71
+ else {
72
+ endSpace = 0;
73
+ if (c === '%') {
74
+ hasLike = true;
75
+ percentEnd = true;
76
+ }
77
+ else if (c === '_') {
78
+ hasLike = true;
79
+ percentEnd = false;
80
+ }
81
+ }
82
+ continue;
83
+ }
84
+ if (state === 2) {
85
+ state = 1;
86
+ }
87
+ }
88
+ /*
89
+ * For the purposes of "startsWith" and "endsWith"
90
+ * the string "%" neither starts nor ends a match string
91
+ */
92
+ return {
93
+ hasLike,
94
+ percentEnd: percentEnd && iLen > 1,
95
+ percentStart: percentStart && iLen > 1,
96
+ endSpace,
97
+ };
98
+ }
99
+ /**
100
+ * Generate the correct match clause operator based on the contents
101
+ * of the match string.
102
+ */
103
+ function matchOp(matchSrc) {
104
+ let matchTxt = matchSrc.trimStart();
105
+ const { hasLike, percentEnd, percentStart, endSpace } = describeString(matchTxt);
106
+ if (endSpace > 0) {
107
+ matchTxt = matchTxt.slice(0, -endSpace);
108
+ }
109
+ if (hasLike) {
110
+ if (percentStart && percentEnd) {
111
+ const mid = matchTxt.slice(1, -1);
112
+ if (!describeString(mid).hasLike && mid.length > 0) {
113
+ return { operator: 'contains', values: [unescape(mid)] };
114
+ }
115
+ }
116
+ else if (percentEnd) {
117
+ const tail = matchTxt.slice(0, -1);
118
+ if (!describeString(tail).hasLike) {
119
+ return { operator: 'starts', values: [unescape(tail)] };
120
+ }
121
+ }
122
+ else if (percentStart) {
123
+ const head = matchTxt.slice(1);
124
+ if (!describeString(head).hasLike) {
125
+ return { operator: 'ends', values: [unescape(head)] };
126
+ }
127
+ }
128
+ return { operator: '~', escaped_values: [matchTxt] };
129
+ }
130
+ if (matchTxt === 'null' || matchTxt === 'NULL') {
131
+ return { operator: 'null' };
132
+ }
133
+ if (matchTxt === 'empty' || matchTxt === 'EMPTY') {
134
+ return { operator: 'empty' };
135
+ }
136
+ // Unescape everything else
137
+ return { operator: '=', values: [unescape(matchTxt)] };
138
+ }
139
+ exports.matchOp = matchOp;
140
+ function sameAs(a, b) {
141
+ var _a, _b;
142
+ return (a.operator === b.operator && ((_a = a['not']) !== null && _a !== void 0 ? _a : false) === ((_b = b['not']) !== null && _b !== void 0 ? _b : false));
143
+ }
144
+ function conjoin(left, op, right) {
145
+ if ((0, filter_clause_1.isStringClause)(left) && (0, filter_clause_1.isStringClause)(right)) {
146
+ if (op === ',') {
147
+ if (left.operator === '~' && sameAs(left, right)) {
148
+ return {
149
+ ...left,
150
+ escaped_values: [...left.escaped_values, ...right.escaped_values],
151
+ };
152
+ }
153
+ if ((0, filter_clause_1.isStringCondition)(left) && sameAs(left, right)) {
154
+ return { ...left, values: [...left.values, ...right.values] };
155
+ }
156
+ }
157
+ const operator = op === ',' ? ',' : op === '|' ? 'or' : op === ';' ? 'and' : undefined;
158
+ if (operator) {
159
+ if (left.operator === operator) {
160
+ return { ...left, members: [...left.members, right] };
161
+ }
162
+ return { operator, members: [left, right] };
163
+ }
164
+ }
165
+ return null;
166
+ }
167
+ exports.conjoin = conjoin;
168
+ function joinNumbers(left, op, right) {
169
+ if ((0, filter_clause_1.isNumberClause)(left) && (0, filter_clause_1.isNumberClause)(right)) {
170
+ if ((op === ',' || op === 'or') &&
171
+ left.operator === '=' &&
172
+ sameAs(left, right)) {
173
+ const ret = {
174
+ operator: '=',
175
+ values: [...left.values, ...right.values],
176
+ };
177
+ if (left.not) {
178
+ ret.not = true;
179
+ }
180
+ return ret;
181
+ }
182
+ if (op === ',' || op === 'and' || op === 'or') {
183
+ if (left.operator === op) {
184
+ return { ...left, members: [...left.members, right] };
185
+ }
186
+ return { operator: op, members: [left, right] };
187
+ }
188
+ }
189
+ return null;
190
+ }
191
+ exports.joinNumbers = joinNumbers;
192
+ function mkRange(left, rFrom, rTo, right) {
193
+ return {
194
+ operator: 'range',
195
+ startValue: rFrom,
196
+ startOperator: left === '(' ? '>' : '>=',
197
+ endValue: rTo,
198
+ endOperator: right === ')' ? '<' : '<=',
199
+ };
200
+ }
201
+ exports.mkRange = mkRange;
202
+ function numNot(op, notToken) {
203
+ if ((0, filter_clause_1.isNumberClause)(op) && notToken) {
204
+ return { ...op, not: true };
205
+ }
206
+ return op;
207
+ }
208
+ exports.numNot = numNot;
209
+ function temporalNot(op, notToken) {
210
+ if ((0, filter_clause_1.isTemporalClause)(op) && notToken) {
211
+ return { ...op, not: true };
212
+ }
213
+ return op;
214
+ }
215
+ exports.temporalNot = temporalNot;
216
+ function joinTemporal(left, op, right) {
217
+ if ((0, filter_clause_1.isTemporalClause)(left) && (0, filter_clause_1.isTemporalClause)(right)) {
218
+ // if (
219
+ // (op === ',' || op === 'or') &&
220
+ // left.operator === '=' &&
221
+ // sameAs(left, right)
222
+ // ) {
223
+ // const ret: NumberClause = {
224
+ // operator: '=',
225
+ // values: [...left.values, ...right.values],
226
+ // };
227
+ // if (left.not) {
228
+ // ret.not = true;
229
+ // }
230
+ // return ret;
231
+ // }
232
+ if (op === ',' || op === 'and' || op === 'or') {
233
+ if (left.operator === op) {
234
+ return { ...left, members: [...left.members, right] };
235
+ }
236
+ return { operator: op, members: [left, right] };
237
+ }
238
+ }
239
+ return null;
240
+ }
241
+ exports.joinTemporal = joinTemporal;
242
+ function timeLiteral(literal, units) {
243
+ const ret = { moment: 'literal', literal };
244
+ if (units) {
245
+ ret.units = units;
246
+ }
247
+ return ret;
248
+ }
249
+ exports.timeLiteral = timeLiteral;
250
+ function mkUnits(unit_s) {
251
+ switch (unit_s.toLowerCase()) {
252
+ case 'second':
253
+ case 'seconds':
254
+ return 'second';
255
+ case 'minute':
256
+ case 'minutes':
257
+ return 'minute';
258
+ case 'hour':
259
+ case 'hours':
260
+ return 'hour';
261
+ case 'day':
262
+ case 'days':
263
+ return 'day';
264
+ case 'week':
265
+ case 'weeks':
266
+ return 'week';
267
+ case 'month':
268
+ case 'months':
269
+ return 'month';
270
+ case 'quarter':
271
+ case 'quarters':
272
+ return 'quarter';
273
+ case 'year':
274
+ case 'years':
275
+ return 'year';
276
+ }
277
+ return undefined;
278
+ }
279
+ exports.mkUnits = mkUnits;
280
+ //# sourceMappingURL=clause_utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clause_utils.js","sourceRoot":"","sources":["../src/clause_utils.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEH,mDAayB;AAEzB;;GAEG;AACH,SAAgB,QAAQ,CAAC,IAA4B;IACnD,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC;IAC3B,IAAI,OAAO,IAAI,EAAE,IAAI,IAAA,8BAAc,EAAC,EAAE,CAAC,EAAE;QACvC,OAAO,EAAC,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAC,CAAC;KAC3B;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAND,4BAMC;AAED,SAAgB,QAAQ,CAAC,GAAW;IAClC,OAAO,GAAG,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC;AAFD,4BAEC;AAED;;GAEG;AACH,SAAgB,MAAM,CAAC,GAAW;IAChC,MAAM,IAAI,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;IAC/B,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,OAAO,EAAE;QACvC,OAAO,IAAI,GAAG,GAAG,CAAC;KACnB;IACD,OAAO,GAAG,CAAC,OAAO,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;AACjD,CAAC;AAND,wBAMC;AAED;;;;GAIG;AACH,SAAS,cAAc,CAAC,CAAS;IAC/B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,YAAY,GAAG,KAAK,CAAC;IACzB,IAAI,UAAU,GAAG,KAAK,CAAC;IACvB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC;IACtB,KAAK,MAAM,CAAC,IAAI,CAAC,EAAE;QACjB,IAAI,KAAK,KAAK,CAAC,EAAE;YACf,oBAAoB;YACpB,KAAK,GAAG,CAAC,CAAC;YACV,IAAI,CAAC,KAAK,GAAG,EAAE;gBACb,OAAO,GAAG,IAAI,CAAC;gBACf,YAAY,GAAG,IAAI,CAAC;gBACpB,SAAS;aACV;SACF;QAED,IAAI,KAAK,KAAK,CAAC,EAAE;YACf,wBAAwB;YACxB,IAAI,CAAC,KAAK,IAAI,EAAE;gBACd,QAAQ,GAAG,CAAC,CAAC;gBACb,UAAU,GAAG,KAAK,CAAC;gBACnB,KAAK,GAAG,CAAC,CAAC;gBACV,SAAS;aACV;YACD,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,EAAE;gBAC3B,UAAU,GAAG,KAAK,CAAC;gBACnB,QAAQ,IAAI,CAAC,CAAC;aACf;iBAAM;gBACL,QAAQ,GAAG,CAAC,CAAC;gBACb,IAAI,CAAC,KAAK,GAAG,EAAE;oBACb,OAAO,GAAG,IAAI,CAAC;oBACf,UAAU,GAAG,IAAI,CAAC;iBACnB;qBAAM,IAAI,CAAC,KAAK,GAAG,EAAE;oBACpB,OAAO,GAAG,IAAI,CAAC;oBACf,UAAU,GAAG,KAAK,CAAC;iBACpB;aACF;YACD,SAAS;SACV;QAED,IAAI,KAAK,KAAK,CAAC,EAAE;YACf,KAAK,GAAG,CAAC,CAAC;SACX;KACF;IACD;;;OAGG;IACH,OAAO;QACL,OAAO;QACP,UAAU,EAAE,UAAU,IAAI,IAAI,GAAG,CAAC;QAClC,YAAY,EAAE,YAAY,IAAI,IAAI,GAAG,CAAC;QACtC,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,SAAgB,OAAO,CAAC,QAAgB;IACtC,IAAI,QAAQ,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;IACpC,MAAM,EAAC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAC,GACjD,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC3B,IAAI,QAAQ,GAAG,CAAC,EAAE;QAChB,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;KACzC;IACD,IAAI,OAAO,EAAE;QACX,IAAI,YAAY,IAAI,UAAU,EAAE;YAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YAClC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE;gBAClD,OAAO,EAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAC,CAAC;aACxD;SACF;aAAM,IAAI,UAAU,EAAE;YACrB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACnC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;gBACjC,OAAO,EAAC,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAC,CAAC;aACvD;SACF;aAAM,IAAI,YAAY,EAAE;YACvB,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAC/B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE;gBACjC,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAC,CAAC;aACrD;SACF;QACD,OAAO,EAAC,QAAQ,EAAE,GAAG,EAAE,cAAc,EAAE,CAAC,QAAQ,CAAC,EAAC,CAAC;KACpD;IACD,IAAI,QAAQ,KAAK,MAAM,IAAI,QAAQ,KAAK,MAAM,EAAE;QAC9C,OAAO,EAAC,QAAQ,EAAE,MAAM,EAAC,CAAC;KAC3B;IACD,IAAI,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,OAAO,EAAE;QAChD,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAC,CAAC;KAC5B;IACD,2BAA2B;IAC3B,OAAO,EAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EAAC,CAAC;AACvD,CAAC;AAlCD,0BAkCC;AAED,SAAS,MAAM,CAAuB,CAAI,EAAE,CAAa;;IACvD,OAAO,CACL,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,QAAQ,IAAI,CAAC,MAAA,CAAC,CAAC,KAAK,CAAC,mCAAI,KAAK,CAAC,KAAK,CAAC,MAAA,CAAC,CAAC,KAAK,CAAC,mCAAI,KAAK,CAAC,CACzE,CAAC;AACJ,CAAC;AAED,SAAgB,OAAO,CACrB,IAAY,EACZ,EAAU,EACV,KAAa;IAEb,IAAI,IAAA,8BAAc,EAAC,IAAI,CAAC,IAAI,IAAA,8BAAc,EAAC,KAAK,CAAC,EAAE;QACjD,IAAI,EAAE,KAAK,GAAG,EAAE;YACd,IAAI,IAAI,CAAC,QAAQ,KAAK,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE;gBAChD,OAAO;oBACL,GAAG,IAAI;oBACP,cAAc,EAAE,CAAC,GAAG,IAAI,CAAC,cAAc,EAAE,GAAG,KAAK,CAAC,cAAc,CAAC;iBAClE,CAAC;aACH;YACD,IAAI,IAAA,iCAAiB,EAAC,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE;gBAClD,OAAO,EAAC,GAAG,IAAI,EAAE,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC,EAAC,CAAC;aAC7D;SACF;QACD,MAAM,QAAQ,GACZ,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,IAAI,QAAQ,EAAE;YACZ,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE;gBAC9B,OAAO,EAAC,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAC,CAAC;aACrD;YACD,OAAO,EAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAAC,CAAC;SAC3C;KACF;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AA3BD,0BA2BC;AAED,SAAgB,WAAW,CACzB,IAAY,EACZ,EAAU,EACV,KAAa;IAEb,IAAI,IAAA,8BAAc,EAAC,IAAI,CAAC,IAAI,IAAA,8BAAc,EAAC,KAAK,CAAC,EAAE;QACjD,IACE,CAAC,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,CAAC;YAC3B,IAAI,CAAC,QAAQ,KAAK,GAAG;YACrB,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,EACnB;YACA,MAAM,GAAG,GAAiB;gBACxB,QAAQ,EAAE,GAAG;gBACb,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,CAAC;aAC1C,CAAC;YACF,IAAI,IAAI,CAAC,GAAG,EAAE;gBACZ,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC;aAChB;YACD,OAAO,GAAG,CAAC;SACZ;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE;YAC7C,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,EAAE;gBACxB,OAAO,EAAC,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAC,CAAC;aACrD;YACD,OAAO,EAAC,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAAC,CAAC;SAC/C;KACF;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AA5BD,kCA4BC;AAED,SAAgB,OAAO,CACrB,IAAY,EACZ,KAAa,EACb,GAAW,EACX,KAAa;IAEb,OAAO;QACL,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,KAAK;QACjB,aAAa,EAAE,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;QACxC,QAAQ,EAAE,GAAG;QACb,WAAW,EAAE,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;KACxC,CAAC;AACJ,CAAC;AAbD,0BAaC;AAED,SAAgB,MAAM,CAAC,EAAU,EAAE,QAAiB;IAClD,IAAI,IAAA,8BAAc,EAAC,EAAE,CAAC,IAAI,QAAQ,EAAE;QAClC,OAAO,EAAC,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAC,CAAC;KAC3B;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AALD,wBAKC;AAED,SAAgB,WAAW,CAAC,EAAU,EAAE,QAAiB;IACvD,IAAI,IAAA,gCAAgB,EAAC,EAAE,CAAC,IAAI,QAAQ,EAAE;QACpC,OAAO,EAAC,GAAG,EAAE,EAAE,GAAG,EAAE,IAAI,EAAC,CAAC;KAC3B;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AALD,kCAKC;AAED,SAAgB,YAAY,CAC1B,IAAY,EACZ,EAAU,EACV,KAAa;IAEb,IAAI,IAAA,gCAAgB,EAAC,IAAI,CAAC,IAAI,IAAA,gCAAgB,EAAC,KAAK,CAAC,EAAE;QACrD,OAAO;QACP,mCAAmC;QACnC,6BAA6B;QAC7B,wBAAwB;QACxB,MAAM;QACN,gCAAgC;QAChC,qBAAqB;QACrB,iDAAiD;QACjD,OAAO;QACP,oBAAoB;QACpB,sBAAsB;QACtB,MAAM;QACN,gBAAgB;QAChB,IAAI;QACJ,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,KAAK,IAAI,EAAE,KAAK,IAAI,EAAE;YAC7C,IAAI,IAAI,CAAC,QAAQ,KAAK,EAAE,EAAE;gBACxB,OAAO,EAAC,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,EAAC,CAAC;aACrD;YACD,OAAO,EAAC,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAAC,CAAC;SAC/C;KACF;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AA5BD,oCA4BC;AAED,SAAgB,WAAW,CACzB,OAAe,EACf,KAAoB;IAEpB,MAAM,GAAG,GAAoB,EAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAC,CAAC;IAC1D,IAAI,KAAK,EAAE;QACT,GAAG,CAAC,KAAK,GAAG,KAAK,CAAC;KACnB;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AATD,kCASC;AAED,SAAgB,OAAO,CAAC,MAAc;IACpC,QAAQ,MAAM,CAAC,WAAW,EAAE,EAAE;QAC5B,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,QAAQ,CAAC;QAClB,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,QAAQ,CAAC;QAClB,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;QAChB,KAAK,KAAK,CAAC;QACX,KAAK,MAAM;YACT,OAAO,KAAK,CAAC;QACf,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;QAChB,KAAK,OAAO,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,OAAO,CAAC;QACjB,KAAK,SAAS,CAAC;QACf,KAAK,UAAU;YACb,OAAO,SAAS,CAAC;QACnB,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,MAAM,CAAC;KACjB;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AA5BD,0BA4BC"}