@malloydata/malloy-filter 0.0.237-dev250222012247 → 0.0.237-dev250222034547

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 (65) hide show
  1. package/dist/a_simple_parser.js +12 -9
  2. package/dist/a_simple_parser.js.map +1 -1
  3. package/dist/base_parser.d.ts +0 -2
  4. package/dist/base_parser.js.map +1 -1
  5. package/dist/boolean_parser.d.ts +2 -2
  6. package/dist/boolean_parser.js.map +1 -1
  7. package/dist/boolean_serializer.d.ts +4 -4
  8. package/dist/boolean_serializer.js +3 -3
  9. package/dist/boolean_serializer.js.map +1 -1
  10. package/dist/clause_types.d.ts +15 -41
  11. package/dist/date_parser.d.ts +13 -11
  12. package/dist/date_parser.js +187 -130
  13. package/dist/date_parser.js.map +1 -1
  14. package/dist/date_serializer.d.ts +6 -5
  15. package/dist/date_serializer.js +53 -71
  16. package/dist/date_serializer.js.map +1 -1
  17. package/dist/date_types.d.ts +69 -0
  18. package/dist/{filter_types.js → date_types.js} +1 -1
  19. package/dist/date_types.js.map +1 -0
  20. package/dist/generate_samples.js +154 -85
  21. package/dist/generate_samples.js.map +1 -1
  22. package/dist/number_parser.d.ts +2 -2
  23. package/dist/number_parser.js.map +1 -1
  24. package/dist/number_serializer.d.ts +4 -4
  25. package/dist/number_serializer.js +3 -3
  26. package/dist/number_serializer.js.map +1 -1
  27. package/dist/string_parser.d.ts +2 -2
  28. package/dist/string_parser.js.map +1 -1
  29. package/dist/string_serializer.d.ts +5 -5
  30. package/dist/string_serializer.js +5 -5
  31. package/dist/string_serializer.js.map +1 -1
  32. package/package.json +1 -2
  33. package/src/a_simple_parser.ts +12 -9
  34. package/src/base_parser.ts +0 -3
  35. package/src/boolean_parser.ts +7 -3
  36. package/src/boolean_serializer.ts +5 -6
  37. package/src/clause_types.ts +15 -97
  38. package/src/date_parser.ts +224 -191
  39. package/src/date_serializer.ts +55 -87
  40. package/src/date_types.ts +149 -0
  41. package/src/generate_samples.ts +170 -107
  42. package/src/number_parser.ts +5 -5
  43. package/src/number_serializer.ts +5 -6
  44. package/src/string_parser.ts +14 -9
  45. package/src/string_serializer.ts +8 -9
  46. package/tsconfig.json +1 -6
  47. package/dist/a_simple_serializer.d.ts +0 -1
  48. package/dist/a_simple_serializer.js +0 -31
  49. package/dist/a_simple_serializer.js.map +0 -1
  50. package/dist/base_serializer.d.ts +0 -6
  51. package/dist/base_serializer.js +0 -11
  52. package/dist/base_serializer.js.map +0 -1
  53. package/dist/filter_parser.d.ts +0 -12
  54. package/dist/filter_parser.js +0 -66
  55. package/dist/filter_parser.js.map +0 -1
  56. package/dist/filter_serializer.d.ts +0 -13
  57. package/dist/filter_serializer.js +0 -43
  58. package/dist/filter_serializer.js.map +0 -1
  59. package/dist/filter_types.d.ts +0 -10
  60. package/dist/filter_types.js.map +0 -1
  61. package/src/a_simple_serializer.ts +0 -40
  62. package/src/base_serializer.ts +0 -9
  63. package/src/filter_parser.ts +0 -68
  64. package/src/filter_serializer.ts +0 -49
  65. package/src/filter_types.ts +0 -12
@@ -1,17 +1,13 @@
1
1
  import {
2
- DateRange,
3
2
  DateMoment,
4
- DateMomentInterval,
5
- DateMomentNumberInterval,
6
- DateMomentNumberUnit,
7
- DateMomentNumber,
8
- Clause,
9
- } from './clause_types';
10
- import {BaseSerializer} from './base_serializer';
3
+ DateBetweenClause,
4
+ DateForClause,
5
+ DateClause,
6
+ } from './date_types';
11
7
 
12
- export class DateSerializer extends BaseSerializer {
13
- constructor(clauses: Clause[]) {
14
- super(clauses);
8
+ export class DateSerializer {
9
+ constructor(private clauses: DateClause[]) {
10
+ this.clauses = clauses;
15
11
  }
16
12
 
17
13
  public serialize(): string {
@@ -19,95 +15,67 @@ export class DateSerializer extends BaseSerializer {
19
15
  return result.trim().replace(/,$/, '');
20
16
  }
21
17
 
22
- private static dateMomentToString(operator: string, clause: Clause): string {
23
- if (
24
- operator === 'NOW' ||
25
- operator === 'TODAY' ||
26
- operator === 'YESTERDAY' ||
27
- operator === 'TOMORROW'
28
- ) {
29
- const custom: DateMoment = clause as DateMoment;
30
- return custom.prefix ? custom.prefix + ' ' + operator : operator;
31
- } else if (
32
- operator === 'LAST' ||
33
- operator === 'THIS' ||
34
- operator === 'NEXT'
35
- ) {
36
- const custom: DateMomentInterval = clause as DateMomentInterval;
37
- let value = custom.operator + ' ' + custom.unit;
38
- if (custom.prefix) {
39
- value = custom.prefix + ' ' + value;
40
- }
41
- return value;
42
- } else if (operator === 'LASTN' || operator === 'NEXTN') {
43
- const custom: DateMomentNumberInterval =
44
- clause as DateMomentNumberInterval;
45
- operator = operator.substring(0, 4); // Strip "N"
46
- let value = operator + ' ' + custom.value + ' ' + custom.unit;
47
- if (custom.prefix) {
48
- value = custom.prefix + ' ' + value;
49
- }
50
- return value;
51
- } else if (operator === 'AGO' || operator === 'FROMNOW') {
52
- const custom: DateMomentNumberInterval =
53
- clause as DateMomentNumberInterval;
54
- if (operator === 'FROMNOW') operator = 'FROM NOW';
55
- let value = custom.value + ' ' + custom.unit + ' ' + operator;
56
- if (custom.prefix) {
57
- value = custom.prefix + ' ' + value;
58
- }
59
- return value;
60
- } else if (operator === 'TIMEBLOCK') {
61
- const custom: DateMomentNumberUnit = clause as DateMomentNumberUnit;
62
- let value = custom.value + ' ' + custom.unit;
63
- if (custom.prefix) {
64
- value = custom.prefix + ' ' + value;
65
- }
66
- return value;
67
- } else if (operator === 'DATE' || operator === 'DATETIME') {
68
- const custom: DateMomentNumber = clause as DateMomentNumber;
69
- let value = custom.date;
70
- if (custom.time) {
71
- value = value + ' ' + custom.time;
72
- }
73
- if (custom.prefix) {
74
- value = custom.prefix + ' ' + value;
75
- }
76
- return value;
18
+ private static dateMomentToString(moment: DateMoment): string {
19
+ if (moment.type === 'ABSOLUTE') {
20
+ return moment.date;
21
+ } else if (moment.type === 'INTERVAL') {
22
+ return moment.kind + ' ' + moment.unit;
23
+ } else if (moment.type === 'NAMED') {
24
+ return moment.name;
25
+ } else if (moment.type === 'OFFSET_FROM_NOW') {
26
+ const direction = moment.direction === 'FROMNOW' ? 'FROM NOW' : 'AGO';
27
+ return moment.amount + ' ' + moment.unit + ' ' + direction;
28
+ } else if (moment.type === 'SPAN_FROM_NOW') {
29
+ return moment.direction + ' ' + moment.amount + ' ' + moment.unit;
30
+ } else {
31
+ throw new Error('moment type not recognized ' + JSON.stringify(moment));
77
32
  }
78
- return '';
79
33
  }
80
34
 
81
- private static dateRangeToString(
82
- operator: 'TO' | 'FOR',
83
- clause: DateRange
84
- ): string {
35
+ private static goDateBetweenClause(clause: DateBetweenClause): string {
85
36
  return (
86
- DateSerializer.dateMomentToString(clause.start.operator, clause.start) +
87
- ' ' +
88
- clause.operator +
37
+ DateSerializer.dateMomentToString(clause.from) +
38
+ ' TO ' +
39
+ DateSerializer.dateMomentToString(clause.to)
40
+ );
41
+ }
42
+
43
+ private static goDateForClause(clause: DateForClause): string {
44
+ return (
45
+ DateSerializer.dateMomentToString(clause.from) +
46
+ ' FOR ' +
47
+ clause.duration.amount +
89
48
  ' ' +
90
- DateSerializer.dateMomentToString(clause.end.operator, clause.end)
49
+ clause.duration.unit
91
50
  );
92
51
  }
93
52
 
94
- private static clauseToString(operator: string, clause: Clause): string {
95
- if (operator === 'TO' || operator === 'FOR') {
96
- const custom = clause as DateRange;
97
- return DateSerializer.dateRangeToString(operator, custom);
53
+ private static clauseToString(clause: DateClause): string {
54
+ if (!('operator' in clause)) {
55
+ throw new Error('Invalid date clause ' + JSON.stringify(clause));
56
+ }
57
+ if (clause.operator === 'TO_RANGE') {
58
+ return DateSerializer.goDateBetweenClause(clause);
59
+ } else if (clause.operator === 'FOR_RANGE') {
60
+ return DateSerializer.goDateForClause(clause);
61
+ } else if (clause.operator === 'BEFORE') {
62
+ return 'BEFORE ' + DateSerializer.dateMomentToString(clause.moment);
63
+ } else if (clause.operator === 'AFTER') {
64
+ return 'AFTER ' + DateSerializer.dateMomentToString(clause.moment);
65
+ } else if (clause.operator === 'ON') {
66
+ return DateSerializer.dateMomentToString(clause.moment);
67
+ } else if (clause.operator === 'DURATION') {
68
+ return clause.duration.amount + ' ' + clause.duration.unit;
69
+ } else {
70
+ throw new Error('Clause type not recognized ' + JSON.stringify(clause));
98
71
  }
99
- return DateSerializer.dateMomentToString(operator, clause);
100
72
  }
101
73
 
102
- private static clausesToString(clauses: Clause[]): string {
74
+ private static clausesToString(clauses: DateClause[]): string {
103
75
  let result = '';
104
76
  for (const clause of clauses) {
105
- if ('operator' in clause) {
106
- result += DateSerializer.clauseToString(clause.operator, clause);
107
- result += ', ';
108
- } else {
109
- throw new Error('Invalid date clause ' + JSON.stringify(clause));
110
- }
77
+ result += DateSerializer.clauseToString(clause);
78
+ result += ', ';
111
79
  }
112
80
  return result;
113
81
  }
@@ -0,0 +1,149 @@
1
+ import {FilterError} from './clause_types';
2
+
3
+ export type DateTimeUnit =
4
+ | 'YEAR'
5
+ | 'QUARTER'
6
+ | 'MONTH'
7
+ | 'WEEK'
8
+ | 'DAY'
9
+ | 'HOUR'
10
+ | 'MINUTE'
11
+ | 'SECOND';
12
+
13
+ export type DateWeekday =
14
+ | 'MONDAY'
15
+ | 'TUESDAY'
16
+ | 'WEDNESDAY'
17
+ | 'THURSDAY'
18
+ | 'FRIDAY'
19
+ | 'SATURDAY'
20
+ | 'SUNDAY';
21
+
22
+ // 7 weeks, 32 hours
23
+ export interface Duration {
24
+ amount: number;
25
+ unit: DateTimeUnit;
26
+ }
27
+
28
+ export type DateMomentName = 'NOW' | 'TODAY' | 'YESTERDAY' | 'TOMORROW';
29
+
30
+ // now, today, yesterday, tomorrow
31
+ export interface NamedMoment {
32
+ type: 'NAMED';
33
+ name: DateMomentName;
34
+ }
35
+
36
+ export type DateMomentIntervalOperator = 'LAST' | 'THIS' | 'NEXT';
37
+
38
+ // LAST|UNITOFTIME, LAST|DAYOFWEEK
39
+ // THIS|UNITOFTIME
40
+ // NEXT|UNITOFTIME, NEXT|DAYOFWEEK
41
+ // last month, next tuesday, this month
42
+ export interface IntervalMoment {
43
+ type: 'INTERVAL';
44
+ kind: DateMomentIntervalOperator;
45
+ unit: DateTimeUnit | DateWeekday;
46
+ }
47
+
48
+ export type DateMomentOffsetFromNowDirection = 'AGO' | 'FROMNOW';
49
+
50
+ // NUMBER|UNITOFTIME|AGO
51
+ // NUMBER|UNITOFTIME|FROM|NOW
52
+ // 3 hours ago, 6 weeks from now
53
+ export interface OffsetMoment {
54
+ type: 'OFFSET_FROM_NOW';
55
+ direction: DateMomentOffsetFromNowDirection;
56
+ unit: DateTimeUnit;
57
+ amount: number;
58
+ }
59
+
60
+ export type DateMomentSpanFromNowDirection = 'LAST' | 'NEXT';
61
+
62
+ // LAST|NUMBER|UNITOFTIME
63
+ // NEXT|NUMBER|UNITOFTIME
64
+ // last 3 hours, next 2025 seconds, last 6 weeks
65
+ export interface SpanMoment {
66
+ type: 'SPAN_FROM_NOW';
67
+ direction: DateMomentSpanFromNowDirection;
68
+ unit: DateTimeUnit;
69
+ amount: number;
70
+ }
71
+
72
+ // 2005, 2005-01, 2005-01-01, 2005-01-01 00:00, 2005-01-01 00:00:01
73
+ export interface AbsoluteMoment {
74
+ type: 'ABSOLUTE';
75
+ date: string;
76
+ unit: DateTimeUnit;
77
+ }
78
+
79
+ // 2025-01
80
+ // {
81
+ // operator: 'ON';
82
+ // moment: { date: '2025-01';
83
+ // unit: 'MONTH' }
84
+ // }
85
+
86
+ // after 2025-01
87
+ // {
88
+ // operator: 'AFTER';
89
+ // moment: { date: '2025-01';
90
+ // unit: 'MONTH' }
91
+ // }
92
+
93
+ export type DateMoment =
94
+ | AbsoluteMoment // 2005-01
95
+ | NamedMoment // "today"
96
+ | IntervalMoment // "this month"
97
+ | SpanMoment // "last 3 weeks, next 3 weeks
98
+ | OffsetMoment; // "3 days ago"
99
+
100
+ // after 2005-01, after 3 hours ago
101
+ export interface DateAfterClause {
102
+ operator: 'AFTER';
103
+ moment: DateMoment;
104
+ }
105
+
106
+ // before 2005-01, before 3 hours ago
107
+ export interface DateBeforeClause {
108
+ operator: 'BEFORE';
109
+ moment: DateMoment;
110
+ }
111
+
112
+ // next week, last 3 weeks, 3 days ago
113
+ export interface DateOnClause {
114
+ operator: 'ON';
115
+ moment: DateMoment;
116
+ }
117
+
118
+ // 2015 to next month
119
+ export interface DateBetweenClause {
120
+ operator: 'TO_RANGE';
121
+ from: DateMoment;
122
+ to: DateMoment;
123
+ }
124
+
125
+ // 2025-01-01 12:00:00 for 3 days
126
+ export interface DateForClause {
127
+ operator: 'FOR_RANGE';
128
+ from: DateMoment;
129
+ duration: Duration;
130
+ }
131
+
132
+ // 3 days
133
+ export interface DateDurationClause {
134
+ operator: 'DURATION';
135
+ duration: Duration;
136
+ }
137
+
138
+ export type DateClause =
139
+ | DateAfterClause
140
+ | DateBeforeClause
141
+ | DateOnClause
142
+ | DateBetweenClause
143
+ | DateForClause
144
+ | DateDurationClause;
145
+
146
+ export interface DateParserResponse {
147
+ clauses: DateClause[];
148
+ errors: FilterError[];
149
+ }
@@ -1,15 +1,16 @@
1
- import {Clause} from './clause_types';
2
1
  import {SpecialToken, Tokenizer, TokenizerParams} from './tokenizer';
3
2
  import {BooleanParser} from './boolean_parser';
4
3
  import {StringParser} from './string_parser';
5
4
  import {NumberParser} from './number_parser';
6
5
  import {DateParser} from './date_parser';
7
- import {BaseParser} from './base_parser';
8
6
  import {BooleanSerializer} from './boolean_serializer';
9
7
  import {StringSerializer} from './string_serializer';
10
8
  import {NumberSerializer} from './number_serializer';
11
9
  import {DateSerializer} from './date_serializer';
12
- import {BaseSerializer} from './base_serializer';
10
+ import {BooleanClause, NumberClause, StringClause} from './clause_types';
11
+ import {DateClause} from './date_types';
12
+
13
+ type Clause = BooleanClause | DateClause | NumberClause | StringClause;
13
14
 
14
15
  const numberExamples = [
15
16
  '5',
@@ -88,7 +89,7 @@ const dateExamples = [
88
89
  'before 3 days ago',
89
90
  'before 2025-08-30 08:30:20',
90
91
  'after 2025-10-05',
91
- '2025-08-30 12:00:00 to 2025-09-18 14:00:00',
92
+ '2025-08-30 12:00 to 2025-09-18 14:30',
92
93
  'this year',
93
94
  'next tuesday',
94
95
  '7 years from now',
@@ -108,6 +109,7 @@ const dateExamples = [
108
109
  'for', // Bad syntax
109
110
  '7', // Bad syntax
110
111
  'from now', // Bad syntax
112
+ '2025-12-25 12:32:', // Bad syntax
111
113
  '',
112
114
  ];
113
115
 
@@ -207,77 +209,86 @@ function testTokenizerNumber() {
207
209
  }
208
210
  }
209
211
 
210
- function testParserSingle(
212
+ function testNumberParserSingle(
211
213
  str: string,
212
- parser: BaseParser,
213
214
  outputFormatter?: (clauses: Clause[]) => string
214
215
  ): void {
215
216
  console.log('Input: ', str);
216
- try {
217
- const response = parser.parse();
218
- // console.log('Tokens: ', parser.getTokens());
219
- if (response.clauses && response.clauses.length > 0) {
220
- if (outputFormatter) {
221
- console.log('Output: ', outputFormatter(response.clauses));
222
- } else {
223
- console.log('Output: ', ...response.clauses);
224
- }
225
- }
226
- if (response.errors && response.errors.length > 0) {
227
- console.log('Errors: ', ...response.errors);
228
- }
229
- } catch (ex: Error | unknown) {
230
- if (ex instanceof Error) console.error('Thrown Error: ', ex.message);
231
- else {
232
- console.error('Thrown Unknown error: ', ex);
217
+ const parser = new NumberParser(str);
218
+ const response = parser.parse();
219
+ // console.log('Tokens: ', parser.getTokens());
220
+ if (response.clauses && response.clauses.length > 0) {
221
+ if (outputFormatter) {
222
+ console.log('Output: ', outputFormatter(response.clauses));
223
+ } else {
224
+ console.log('Output: ', ...response.clauses);
233
225
  }
234
226
  }
227
+ if (response.errors && response.errors.length > 0) {
228
+ console.log('Errors: ', ...response.errors);
229
+ }
235
230
  console.log('');
236
231
  }
237
232
 
238
- function testSerializerRoundtrip(
233
+ function testNumberParser() {
234
+ for (const example of numberExamples) {
235
+ testNumberParserSingle(example);
236
+ }
237
+ }
238
+
239
+ function testStringParserSingle(
239
240
  str: string,
240
- parser: BaseParser,
241
- serializerFunc: (clauses: Clause[]) => BaseSerializer
241
+ outputFormatter?: (clauses: Clause[]) => string
242
242
  ): void {
243
- console.log('Input: ' + str);
244
- try {
245
- const response = parser.parse();
246
- // console.log('Clause: ', ...response.clauses, '\n');
247
- if (response.clauses && response.clauses.length > 0) {
248
- const result = serializerFunc(response.clauses || []).serialize();
249
- console.log('Output: ' + result);
250
- }
251
- if (response.errors && response.errors.length > 0) {
252
- console.log('Errors: ', ...response.errors);
253
- }
254
- } catch (ex: Error | unknown) {
255
- if (ex instanceof Error) console.error('Thrown Error: ', ex.message);
256
- else {
257
- console.error('Thrown Unknown error: ', ex);
243
+ console.log('Input: ', str);
244
+ const parser = new StringParser(str);
245
+ const response = parser.parse();
246
+ // console.log('Tokens: ', parser.getTokens());
247
+ if (response.clauses && response.clauses.length > 0) {
248
+ if (outputFormatter) {
249
+ console.log('Output: ', outputFormatter(response.clauses));
250
+ } else {
251
+ console.log('Output: ', ...response.clauses);
258
252
  }
259
253
  }
260
- console.log('');
261
- }
262
-
263
- function testNumberParser() {
264
- for (const example of numberExamples) {
265
- const parser = new NumberParser(example);
266
- testParserSingle(example, parser);
254
+ if (response.errors && response.errors.length > 0) {
255
+ console.log('Errors: ', ...response.errors);
267
256
  }
257
+ console.log('');
268
258
  }
269
259
 
270
260
  function testStringParser() {
271
261
  for (const example of stringExamples) {
272
262
  const parser = new StringParser(example);
273
- testParserSingle(example, parser);
263
+ testStringParserSingle(example);
274
264
  }
275
265
  }
276
266
 
267
+ function testBooleanParserSingle(
268
+ str: string,
269
+ outputFormatter?: (clauses: Clause[]) => string
270
+ ): void {
271
+ console.log('Input: ', str);
272
+ const parser = new BooleanParser(str);
273
+ const response = parser.parse();
274
+ // console.log('Tokens: ', parser.getTokens());
275
+ if (response.clauses && response.clauses.length > 0) {
276
+ if (outputFormatter) {
277
+ console.log('Output: ', outputFormatter(response.clauses));
278
+ } else {
279
+ console.log('Output: ', ...response.clauses);
280
+ }
281
+ }
282
+ if (response.errors && response.errors.length > 0) {
283
+ console.log('Errors: ', ...response.errors);
284
+ }
285
+ console.log('');
286
+ }
287
+
277
288
  function testBooleanParser() {
278
289
  for (const example of booleanExamples) {
279
290
  const parser = new BooleanParser(example);
280
- testParserSingle(example, parser);
291
+ testBooleanParserSingle(example);
281
292
  }
282
293
  }
283
294
 
@@ -289,67 +300,112 @@ function jsonFormatter(clauses: Clause[]): string {
289
300
  return str;
290
301
  }
291
302
 
303
+ function testDateParserSingle(
304
+ str: string,
305
+ outputFormatter?: (clauses: Clause[]) => string
306
+ ): void {
307
+ console.log('Input: ', str);
308
+ const parser = new DateParser(str);
309
+ const response = parser.parse();
310
+ // console.log('Tokens: ', parser.getTokens());
311
+ if (response.clauses && response.clauses.length > 0) {
312
+ if (outputFormatter) {
313
+ console.log('Output: ', outputFormatter(response.clauses));
314
+ } else {
315
+ console.log('Output: ', ...response.clauses);
316
+ }
317
+ }
318
+ if (response.errors && response.errors.length > 0) {
319
+ console.log('Errors: ', ...response.errors);
320
+ }
321
+ console.log('');
322
+ }
323
+
292
324
  function testDateParser() {
293
325
  for (const example of dateExamples) {
294
326
  const parser = new DateParser(example);
295
- testParserSingle(example, parser);
296
- //testParserSingle(example, parser, jsonFormatter);
327
+ testDateParserSingle(example);
297
328
  }
298
329
  }
299
330
 
331
+ function testNumberRoundtrip(str: string): void {
332
+ console.log('Input: ' + str);
333
+ const response = new NumberParser(str).parse();
334
+ // console.log('Clause: ', ...response.clauses, '\n');
335
+ if (response.clauses && response.clauses.length > 0) {
336
+ const result = new NumberSerializer(response.clauses || []).serialize();
337
+ console.log('Output: ' + result);
338
+ }
339
+ if (response.errors && response.errors.length > 0) {
340
+ console.log('Errors: ', ...response.errors);
341
+ }
342
+ console.log('');
343
+ }
344
+
300
345
  function testNumberSerializer(): void {
301
- const examples = [
302
- [{operator: '>', value: 10}],
303
- [{startOperator: '>=', startValue: 20, endOperator: '<=', endValue: 30}],
304
- ];
305
346
  for (const example of numberExamples) {
306
- testSerializerRoundtrip(
307
- example,
308
- new NumberParser(example),
309
- clauses => new NumberSerializer(clauses)
310
- );
347
+ testNumberRoundtrip(example);
348
+ }
349
+ }
350
+
351
+ function testStringRoundtrip(str: string): void {
352
+ console.log('Input: ' + str);
353
+ const response = new StringParser(str).parse();
354
+ // console.log('Clause: ', ...response.clauses, '\n');
355
+ if (response.clauses && response.clauses.length > 0) {
356
+ const result = new StringSerializer(response.clauses || []).serialize();
357
+ console.log('Output: ' + result);
311
358
  }
359
+ if (response.errors && response.errors.length > 0) {
360
+ console.log('Errors: ', ...response.errors);
361
+ }
362
+ console.log('');
312
363
  }
313
364
 
314
365
  function testStringSerializer(): void {
315
366
  for (const example of stringExamples) {
316
- testSerializerRoundtrip(
317
- example,
318
- new StringParser(example),
319
- clauses => new StringSerializer(clauses)
320
- );
367
+ testStringRoundtrip(example);
321
368
  }
322
369
  }
323
370
 
371
+ function testBooleanRoundtrip(str: string): void {
372
+ console.log('Input: ' + str);
373
+ const response = new BooleanParser(str).parse();
374
+ // console.log('Clause: ', ...response.clauses, '\n');
375
+ if (response.clauses && response.clauses.length > 0) {
376
+ const result = new BooleanSerializer(response.clauses || []).serialize();
377
+ console.log('Output: ' + result);
378
+ }
379
+ if (response.errors && response.errors.length > 0) {
380
+ console.log('Errors: ', ...response.errors);
381
+ }
382
+ console.log('');
383
+ }
384
+
324
385
  function testBooleanSerializer(): void {
325
386
  const examples = [[{operator: 'TRUE'}]];
326
387
  for (const example of booleanExamples) {
327
- testSerializerRoundtrip(
328
- example,
329
- new BooleanParser(example),
330
- clauses => new BooleanSerializer(clauses)
331
- );
388
+ testBooleanRoundtrip(example);
332
389
  }
333
390
  }
334
391
 
392
+ function testDateRoundtrip(str: string): void {
393
+ console.log('Input: ' + str);
394
+ const response = new DateParser(str).parse();
395
+ // console.log('Clause: ', ...response.clauses, '\n');
396
+ if (response.clauses && response.clauses.length > 0) {
397
+ const result = new DateSerializer(response.clauses || []).serialize();
398
+ console.log('Output: ' + result);
399
+ }
400
+ if (response.errors && response.errors.length > 0) {
401
+ console.log('Errors: ', ...response.errors);
402
+ }
403
+ console.log('');
404
+ }
405
+
335
406
  function testDateSerializer(): void {
336
- const examples = [
337
- [{prefix: 'BEFORE', values: [{type: 'day', value: 'yesterday'}]}],
338
- [
339
- {
340
- start: [{type: 'day', value: 'today'}],
341
- operator: 'TO',
342
- end: [{type: 'day', value: 'tomorrow'}],
343
- },
344
- ],
345
- [{type: 'day', value: 'today'}],
346
- ];
347
407
  for (const example of dateExamples) {
348
- testSerializerRoundtrip(
349
- example,
350
- new DateParser(example),
351
- clauses => new DateSerializer(clauses)
352
- );
408
+ testDateRoundtrip(example);
353
409
  }
354
410
  }
355
411
 
@@ -362,26 +418,33 @@ function printHeader(title: string): void {
362
418
 
363
419
  // Comment or uncomment the following function calls to disable/enable examples.
364
420
  function generateSamples() {
365
- //printHeader('Tokenizer');
366
- //testTokenizerString();
367
- //testTokenizerNumber();
368
- //testTokenizerMatchTypes();
369
- //printHeader('Numbers');
370
- //testNumberParser();
371
- //printHeader('Strings');
372
- //testStringParser();
373
- //printHeader('Booleans');
374
- //testBooleanParser();
375
- //printHeader('Dates and Times');
376
- //testDateParser();
377
- printHeader('Number Serializer');
378
- testNumberSerializer();
379
- printHeader('String Serializer');
380
- testStringSerializer();
381
- printHeader('Boolean Serializer');
382
- testBooleanSerializer();
383
- printHeader('Date and Time Serializer');
384
- testDateSerializer();
421
+ try {
422
+ //printHeader('Tokenizer');
423
+ //testTokenizerString();
424
+ //testTokenizerNumber();
425
+ //testTokenizerMatchTypes();
426
+ printHeader('Numbers');
427
+ testNumberParser();
428
+ printHeader('Strings');
429
+ testStringParser();
430
+ printHeader('Booleans');
431
+ testBooleanParser();
432
+ printHeader('Dates and Times');
433
+ testDateParser();
434
+ printHeader('Number Serializer');
435
+ testNumberSerializer();
436
+ printHeader('String Serializer');
437
+ testStringSerializer();
438
+ printHeader('Boolean Serializer');
439
+ testBooleanSerializer();
440
+ printHeader('Date and Time Serializer');
441
+ testDateSerializer();
442
+ } catch (ex: Error | unknown) {
443
+ if (ex instanceof Error) console.error('Thrown Error: ', ex.message);
444
+ else {
445
+ console.error('Thrown Unknown error: ', ex);
446
+ }
447
+ }
385
448
  }
386
449
 
387
450
  generateSamples();