@malloydata/malloy-filter 0.0.237-dev250222025222 → 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.
- package/dist/a_simple_parser.js +12 -9
- package/dist/a_simple_parser.js.map +1 -1
- package/dist/base_parser.d.ts +0 -2
- package/dist/base_parser.js.map +1 -1
- package/dist/boolean_parser.d.ts +2 -2
- package/dist/boolean_parser.js.map +1 -1
- package/dist/boolean_serializer.d.ts +4 -4
- package/dist/boolean_serializer.js +3 -3
- package/dist/boolean_serializer.js.map +1 -1
- package/dist/clause_types.d.ts +15 -41
- package/dist/date_parser.d.ts +13 -11
- package/dist/date_parser.js +187 -130
- package/dist/date_parser.js.map +1 -1
- package/dist/date_serializer.d.ts +6 -5
- package/dist/date_serializer.js +53 -71
- package/dist/date_serializer.js.map +1 -1
- package/dist/date_types.d.ts +69 -0
- package/dist/{filter_types.js → date_types.js} +1 -1
- package/dist/date_types.js.map +1 -0
- package/dist/generate_samples.js +154 -85
- package/dist/generate_samples.js.map +1 -1
- package/dist/number_parser.d.ts +2 -2
- package/dist/number_parser.js.map +1 -1
- package/dist/number_serializer.d.ts +4 -4
- package/dist/number_serializer.js +3 -3
- package/dist/number_serializer.js.map +1 -1
- package/dist/string_parser.d.ts +2 -2
- package/dist/string_parser.js.map +1 -1
- package/dist/string_serializer.d.ts +5 -5
- package/dist/string_serializer.js +5 -5
- package/dist/string_serializer.js.map +1 -1
- package/package.json +1 -2
- package/src/a_simple_parser.ts +12 -9
- package/src/base_parser.ts +0 -3
- package/src/boolean_parser.ts +7 -3
- package/src/boolean_serializer.ts +5 -6
- package/src/clause_types.ts +15 -97
- package/src/date_parser.ts +224 -191
- package/src/date_serializer.ts +55 -87
- package/src/date_types.ts +149 -0
- package/src/generate_samples.ts +170 -107
- package/src/number_parser.ts +5 -5
- package/src/number_serializer.ts +5 -6
- package/src/string_parser.ts +14 -9
- package/src/string_serializer.ts +8 -9
- package/tsconfig.json +1 -6
- package/dist/a_simple_serializer.d.ts +0 -1
- package/dist/a_simple_serializer.js +0 -31
- package/dist/a_simple_serializer.js.map +0 -1
- package/dist/base_serializer.d.ts +0 -6
- package/dist/base_serializer.js +0 -11
- package/dist/base_serializer.js.map +0 -1
- package/dist/filter_parser.d.ts +0 -12
- package/dist/filter_parser.js +0 -66
- package/dist/filter_parser.js.map +0 -1
- package/dist/filter_serializer.d.ts +0 -13
- package/dist/filter_serializer.js +0 -43
- package/dist/filter_serializer.js.map +0 -1
- package/dist/filter_types.d.ts +0 -10
- package/dist/filter_types.js.map +0 -1
- package/src/a_simple_serializer.ts +0 -40
- package/src/base_serializer.ts +0 -9
- package/src/filter_parser.ts +0 -68
- package/src/filter_serializer.ts +0 -49
- package/src/filter_types.ts +0 -12
package/src/date_serializer.ts
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
DateRange,
|
|
3
2
|
DateMoment,
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
13
|
-
constructor(clauses:
|
|
14
|
-
|
|
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(
|
|
23
|
-
if (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
|
82
|
-
operator: 'TO' | 'FOR',
|
|
83
|
-
clause: DateRange
|
|
84
|
-
): string {
|
|
35
|
+
private static goDateBetweenClause(clause: DateBetweenClause): string {
|
|
85
36
|
return (
|
|
86
|
-
DateSerializer.dateMomentToString(clause.
|
|
87
|
-
' ' +
|
|
88
|
-
clause.
|
|
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
|
-
|
|
49
|
+
clause.duration.unit
|
|
91
50
|
);
|
|
92
51
|
}
|
|
93
52
|
|
|
94
|
-
private static clauseToString(
|
|
95
|
-
if (operator
|
|
96
|
-
|
|
97
|
-
|
|
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:
|
|
74
|
+
private static clausesToString(clauses: DateClause[]): string {
|
|
103
75
|
let result = '';
|
|
104
76
|
for (const clause of clauses) {
|
|
105
|
-
|
|
106
|
-
|
|
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
|
+
}
|
package/src/generate_samples.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
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
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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
|
|
233
|
+
function testNumberParser() {
|
|
234
|
+
for (const example of numberExamples) {
|
|
235
|
+
testNumberParserSingle(example);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function testStringParserSingle(
|
|
239
240
|
str: string,
|
|
240
|
-
|
|
241
|
-
serializerFunc: (clauses: Clause[]) => BaseSerializer
|
|
241
|
+
outputFormatter?: (clauses: Clause[]) => string
|
|
242
242
|
): void {
|
|
243
|
-
console.log('Input:
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
console.log('Output: '
|
|
250
|
-
}
|
|
251
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
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();
|