@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.
- 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_parser.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
import {SpecialToken, Tokenizer, TokenizerParams} from './tokenizer';
|
|
2
2
|
import {
|
|
3
|
-
DateRange,
|
|
4
|
-
DatePrefix,
|
|
5
|
-
DateMoment,
|
|
6
|
-
DateMomentNow,
|
|
7
|
-
DateMomentInterval,
|
|
8
|
-
DateMomentNumberInterval,
|
|
9
|
-
DateMomentNumberUnit,
|
|
10
|
-
DateMomentNumber,
|
|
11
3
|
DateTimeUnit,
|
|
12
4
|
DateWeekday,
|
|
5
|
+
DateMomentName,
|
|
6
|
+
NamedMoment,
|
|
13
7
|
DateMomentIntervalOperator,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
8
|
+
IntervalMoment,
|
|
9
|
+
DateMomentOffsetFromNowDirection,
|
|
10
|
+
OffsetMoment,
|
|
11
|
+
DateMomentSpanFromNowDirection,
|
|
12
|
+
SpanMoment,
|
|
13
|
+
AbsoluteMoment,
|
|
14
|
+
DateMoment,
|
|
15
|
+
DateBetweenClause,
|
|
16
|
+
Duration,
|
|
17
|
+
DateForClause,
|
|
18
|
+
DateDurationClause,
|
|
18
19
|
DateClause,
|
|
19
|
-
|
|
20
|
-
} from './
|
|
20
|
+
DateParserResponse,
|
|
21
|
+
} from './date_types';
|
|
21
22
|
import {BaseParser} from './base_parser';
|
|
22
23
|
import {Token} from './token_types';
|
|
23
|
-
import {
|
|
24
|
+
import {FilterError} from './clause_types';
|
|
25
|
+
|
|
26
|
+
type DatePrefix = 'BEFORE' | 'AFTER';
|
|
24
27
|
|
|
25
28
|
export class DateParser extends BaseParser {
|
|
26
29
|
private static readonly yearRegex: RegExp = /[%_]/;
|
|
@@ -62,7 +65,7 @@ export class DateParser extends BaseParser {
|
|
|
62
65
|
{type: 'FROM', value: 'from', ignoreCase: true},
|
|
63
66
|
{type: 'FOR', value: 'for', ignoreCase: true},
|
|
64
67
|
{type: 'TO', value: 'to', ignoreCase: true},
|
|
65
|
-
{type: '
|
|
68
|
+
{type: 'YEAR', value: /^\d\d\d\d$/}, // Years are ambiguous, and require special handling.
|
|
66
69
|
{type: 'NUMBER', value: /^[\d.]+/, ignoreCase: true},
|
|
67
70
|
];
|
|
68
71
|
const params: TokenizerParams = {
|
|
@@ -83,44 +86,28 @@ export class DateParser extends BaseParser {
|
|
|
83
86
|
this.index = 0;
|
|
84
87
|
while (this.index < this.tokens.length) {
|
|
85
88
|
if (
|
|
86
|
-
this.matchAndMerge('LAST|UNITOFTIME',
|
|
87
|
-
this.matchAndMerge('LAST|DAYOFWEEK',
|
|
88
|
-
this.matchAndMerge('LAST|NUMBER|UNITOFTIME',
|
|
89
|
-
this.matchAndMerge(
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
) ||
|
|
94
|
-
this.matchAndMerge('
|
|
95
|
-
this.matchAndMerge('
|
|
96
|
-
this.matchAndMerge('
|
|
97
|
-
this.matchAndMerge('
|
|
98
|
-
this.matchAndMerge(
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
) ||
|
|
103
|
-
this.matchAndMerge('
|
|
104
|
-
this.matchAndMerge(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
) ||
|
|
109
|
-
this.matchAndMerge('NUMBER|UNITOFTIME|FROM|NOW', this.tokens, output) ||
|
|
110
|
-
this.matchAndMerge(
|
|
111
|
-
'YEARORNUMBER|UNITOFTIME|FROM|NOW',
|
|
112
|
-
this.tokens,
|
|
113
|
-
output
|
|
114
|
-
) ||
|
|
115
|
-
this.matchAndMerge('NUMBER|UNITOFTIME', this.tokens, output) ||
|
|
116
|
-
this.matchAndMerge('YEARORNUMBER|UNITOFTIME', this.tokens, output) ||
|
|
117
|
-
this.matchAndMerge('DATE|TIME', this.tokens, output) ||
|
|
118
|
-
this.matchAndMerge('TODAY', this.tokens, output) ||
|
|
119
|
-
this.matchAndMerge('YESTERDAY', this.tokens, output) ||
|
|
120
|
-
this.matchAndMerge('TOMORROW', this.tokens, output) ||
|
|
121
|
-
this.matchAndMerge('DATE', this.tokens, output) ||
|
|
122
|
-
this.matchAndMerge('YEARORNUMBER', this.tokens, output) ||
|
|
123
|
-
this.matchAndMerge('NOW', this.tokens, output)
|
|
89
|
+
this.matchAndMerge('LAST|UNITOFTIME', output) ||
|
|
90
|
+
this.matchAndMerge('LAST|DAYOFWEEK', output) ||
|
|
91
|
+
this.matchAndMerge('LAST|NUMBER|UNITOFTIME', output) ||
|
|
92
|
+
this.matchAndMerge('LAST|YEAR|UNITOFTIME', output) ||
|
|
93
|
+
this.matchAndMerge('THIS|UNITOFTIME', output) ||
|
|
94
|
+
this.matchAndMerge('NEXT|UNITOFTIME', output) ||
|
|
95
|
+
this.matchAndMerge('NEXT|DAYOFWEEK', output) ||
|
|
96
|
+
this.matchAndMerge('NEXT|NUMBER|UNITOFTIME', output) ||
|
|
97
|
+
this.matchAndMerge('NEXT|YEAR|UNITOFTIME', output) ||
|
|
98
|
+
this.matchAndMerge('NUMBER|UNITOFTIME|AGO', output) ||
|
|
99
|
+
this.matchAndMerge('YEAR|UNITOFTIME|AGO', output) ||
|
|
100
|
+
this.matchAndMerge('NUMBER|UNITOFTIME|FROM|NOW', output) ||
|
|
101
|
+
this.matchAndMerge('YEAR|UNITOFTIME|FROM|NOW', output) ||
|
|
102
|
+
this.matchAndMerge('NUMBER|UNITOFTIME', output) ||
|
|
103
|
+
this.matchAndMerge('YEAR|UNITOFTIME', output) ||
|
|
104
|
+
this.matchAndMerge('DATE|TIME', output) ||
|
|
105
|
+
this.matchAndMerge('TODAY', output) ||
|
|
106
|
+
this.matchAndMerge('YESTERDAY', output) ||
|
|
107
|
+
this.matchAndMerge('TOMORROW', output) ||
|
|
108
|
+
this.matchAndMerge('DATE', output) ||
|
|
109
|
+
this.matchAndMerge('YEAR', output) ||
|
|
110
|
+
this.matchAndMerge('NOW', output)
|
|
124
111
|
) {
|
|
125
112
|
continue;
|
|
126
113
|
} else {
|
|
@@ -131,16 +118,12 @@ export class DateParser extends BaseParser {
|
|
|
131
118
|
return output;
|
|
132
119
|
}
|
|
133
120
|
|
|
134
|
-
private matchAndMerge(
|
|
135
|
-
types: string,
|
|
136
|
-
tokens: Token[],
|
|
137
|
-
output: Token[]
|
|
138
|
-
): boolean {
|
|
121
|
+
private matchAndMerge(types: string, output: Token[]): boolean {
|
|
139
122
|
const idx = this.index;
|
|
140
|
-
const matchedTokens = Tokenizer.matchTypes(types, tokens, idx);
|
|
123
|
+
const matchedTokens = Tokenizer.matchTypes(types, this.tokens, idx);
|
|
141
124
|
if (matchedTokens) {
|
|
142
125
|
output.push({
|
|
143
|
-
type: '
|
|
126
|
+
type: 'MERGE:' + types,
|
|
144
127
|
value: '',
|
|
145
128
|
values: matchedTokens,
|
|
146
129
|
startIndex: matchedTokens[0].startIndex,
|
|
@@ -152,7 +135,7 @@ export class DateParser extends BaseParser {
|
|
|
152
135
|
return false;
|
|
153
136
|
}
|
|
154
137
|
|
|
155
|
-
public parse():
|
|
138
|
+
public parse(): DateParserResponse {
|
|
156
139
|
this.tokenize();
|
|
157
140
|
let prefix: DatePrefix | undefined = undefined;
|
|
158
141
|
const clauses: DateClause[] = [];
|
|
@@ -181,7 +164,7 @@ export class DateParser extends BaseParser {
|
|
|
181
164
|
});
|
|
182
165
|
this.index++;
|
|
183
166
|
}
|
|
184
|
-
} else if (this.
|
|
167
|
+
} else if (this.handleMerged(prefix, clauses)) {
|
|
185
168
|
prefix = undefined;
|
|
186
169
|
} else {
|
|
187
170
|
errors.push({
|
|
@@ -196,151 +179,187 @@ export class DateParser extends BaseParser {
|
|
|
196
179
|
return {clauses, errors};
|
|
197
180
|
}
|
|
198
181
|
|
|
199
|
-
|
|
200
|
-
private static createMomentInterval(
|
|
182
|
+
private static createMomentClause(
|
|
201
183
|
prefix: DatePrefix | undefined,
|
|
202
|
-
|
|
203
|
-
):
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
if (prefix) {
|
|
211
|
-
moment.prefix = prefix;
|
|
184
|
+
moment: DateMoment
|
|
185
|
+
): DateClause {
|
|
186
|
+
if (!prefix) {
|
|
187
|
+
return {operator: 'ON', moment}; // DateOnClause
|
|
188
|
+
} else if (prefix === 'BEFORE') {
|
|
189
|
+
return {operator: 'BEFORE', moment}; // DateBeforeClause
|
|
190
|
+
} else {
|
|
191
|
+
return {operator: 'AFTER', moment}; // DateAfterClause
|
|
212
192
|
}
|
|
213
|
-
return moment;
|
|
214
193
|
}
|
|
215
194
|
|
|
216
|
-
// LAST|
|
|
217
|
-
private static
|
|
195
|
+
// (BEFORE|AFTER) LAST|DAYOFWEEK
|
|
196
|
+
private static createIntervalMoment(
|
|
218
197
|
prefix: DatePrefix | undefined,
|
|
219
198
|
tokens: Token[]
|
|
220
|
-
):
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const moment:
|
|
227
|
-
|
|
228
|
-
moment.prefix = prefix;
|
|
229
|
-
}
|
|
230
|
-
return moment;
|
|
199
|
+
): DateClause {
|
|
200
|
+
const kind: DateMomentIntervalOperator = tokens[0]
|
|
201
|
+
.type as DateMomentIntervalOperator;
|
|
202
|
+
const unit: DateTimeUnit | DateWeekday = tokens[1].value as
|
|
203
|
+
| DateTimeUnit
|
|
204
|
+
| DateWeekday;
|
|
205
|
+
const moment: IntervalMoment = {type: 'INTERVAL', kind, unit};
|
|
206
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
231
207
|
}
|
|
232
208
|
|
|
233
209
|
// NUMBER|UNITOFTIME|AGO
|
|
234
|
-
|
|
210
|
+
// NUMBER|UNITOFTIME|FROM|NOW
|
|
211
|
+
private static createOffsetMoment(
|
|
235
212
|
prefix: DatePrefix | undefined,
|
|
236
213
|
tokens: Token[]
|
|
237
|
-
):
|
|
238
|
-
const
|
|
239
|
-
const value: string = tokens[0].value;
|
|
214
|
+
): DateClause | undefined {
|
|
215
|
+
const amount = Number(tokens[0].value);
|
|
240
216
|
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
217
|
+
const direction: DateMomentOffsetFromNowDirection =
|
|
218
|
+
tokens[2].type === 'AGO' ? 'AGO' : 'FROMNOW';
|
|
219
|
+
if (!DateParser.isValidNumber(amount)) {
|
|
220
|
+
return undefined;
|
|
244
221
|
}
|
|
245
|
-
|
|
222
|
+
const moment: OffsetMoment = {
|
|
223
|
+
type: 'OFFSET_FROM_NOW',
|
|
224
|
+
direction,
|
|
225
|
+
amount,
|
|
226
|
+
unit,
|
|
227
|
+
};
|
|
228
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
246
229
|
}
|
|
247
230
|
|
|
248
|
-
// NUMBER|UNITOFTIME
|
|
249
|
-
private static
|
|
231
|
+
// (LAST|NEXT)|NUMBER|UNITOFTIME
|
|
232
|
+
private static createSpanMoment(
|
|
250
233
|
prefix: DatePrefix | undefined,
|
|
251
234
|
tokens: Token[]
|
|
252
|
-
):
|
|
253
|
-
const
|
|
254
|
-
const value: string = tokens[0].value;
|
|
235
|
+
): DateClause | undefined {
|
|
236
|
+
const amount = Number(tokens[0].value);
|
|
255
237
|
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
256
|
-
const
|
|
257
|
-
|
|
258
|
-
|
|
238
|
+
const direction: DateMomentSpanFromNowDirection =
|
|
239
|
+
tokens[2].type === 'LAST' ? 'LAST' : 'NEXT';
|
|
240
|
+
if (!DateParser.isValidNumber(amount)) {
|
|
241
|
+
return undefined;
|
|
259
242
|
}
|
|
260
|
-
|
|
243
|
+
const moment: SpanMoment = {type: 'SPAN_FROM_NOW', direction, amount, unit};
|
|
244
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
261
245
|
}
|
|
262
246
|
|
|
263
|
-
// NUMBER|UNITOFTIME
|
|
264
|
-
private static
|
|
247
|
+
// (NUMBER|YEAR)|UNITOFTIME
|
|
248
|
+
private static createDateDuration(
|
|
265
249
|
prefix: DatePrefix | undefined,
|
|
266
250
|
tokens: Token[]
|
|
267
|
-
):
|
|
268
|
-
const operator: DateMomentNumberUnitOperator = 'TIMEBLOCK';
|
|
269
|
-
const value: string = tokens[0].value;
|
|
270
|
-
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
271
|
-
const moment: DateMomentNumberUnit = {operator, value, unit};
|
|
251
|
+
): DateClause | undefined {
|
|
272
252
|
if (prefix) {
|
|
273
|
-
|
|
253
|
+
return undefined; // before 7 hours is ambiguous, not allowed.
|
|
254
|
+
}
|
|
255
|
+
const operator = 'DURATION';
|
|
256
|
+
const amount = Number(tokens[0].value);
|
|
257
|
+
const unit: DateTimeUnit = tokens[1].value as DateTimeUnit;
|
|
258
|
+
if (!DateParser.isValidNumber(amount)) {
|
|
259
|
+
return undefined;
|
|
274
260
|
}
|
|
275
|
-
|
|
261
|
+
const clause: DateDurationClause = {operator, duration: {amount, unit}};
|
|
262
|
+
return clause;
|
|
276
263
|
}
|
|
277
264
|
|
|
278
|
-
// DATE DATE|TIME
|
|
279
|
-
private static
|
|
265
|
+
// (BEFORE|AFTER) DATE DATE|TIME
|
|
266
|
+
private static createAbsoluteMoment(
|
|
280
267
|
prefix: DatePrefix | undefined,
|
|
281
268
|
tokens: Token[]
|
|
282
|
-
):
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const moment: DateMomentNumber = {operator, date: tokens[0].value};
|
|
269
|
+
): DateClause {
|
|
270
|
+
let unit: DateTimeUnit = 'YEAR';
|
|
271
|
+
let date = tokens[0].value;
|
|
286
272
|
if (tokens.length === 2) {
|
|
287
|
-
|
|
273
|
+
const timeStr = tokens[1].value;
|
|
274
|
+
date += ' ' + timeStr;
|
|
275
|
+
if (timeStr.length > 5) unit = 'SECOND';
|
|
276
|
+
else unit = 'MINUTE';
|
|
277
|
+
} else if (date.length > 7) {
|
|
278
|
+
unit = 'DAY';
|
|
279
|
+
} else if (date.length > 4) {
|
|
280
|
+
unit = 'MONTH';
|
|
288
281
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
return moment;
|
|
282
|
+
const moment: AbsoluteMoment = {type: 'ABSOLUTE', date, unit};
|
|
283
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
293
284
|
}
|
|
294
285
|
|
|
295
286
|
// NOW YESTERDAY TODAY TOMORROW
|
|
296
|
-
private static
|
|
287
|
+
private static createNamedMoment(
|
|
297
288
|
prefix: DatePrefix | undefined,
|
|
298
289
|
tokens: Token[]
|
|
299
|
-
):
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
290
|
+
): DateClause {
|
|
291
|
+
let momentName: DateMomentName = 'NOW';
|
|
292
|
+
switch (tokens[0].type) {
|
|
293
|
+
case 'TODAY':
|
|
294
|
+
momentName = 'TODAY';
|
|
295
|
+
break;
|
|
296
|
+
case 'YESTERDAY':
|
|
297
|
+
momentName = 'YESTERDAY';
|
|
298
|
+
break;
|
|
299
|
+
case 'TOMORROW':
|
|
300
|
+
momentName = 'TOMORROW';
|
|
301
|
+
break;
|
|
305
302
|
}
|
|
306
|
-
|
|
303
|
+
const moment: NamedMoment = {type: 'NAMED', name: momentName};
|
|
304
|
+
return DateParser.createMomentClause(prefix, moment);
|
|
307
305
|
}
|
|
308
306
|
|
|
309
|
-
private static
|
|
307
|
+
private static isValidNumber(value: number): boolean {
|
|
308
|
+
return Number.isNaN(value) === false;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
private static createDurationFromMerged(token: Token): Duration | undefined {
|
|
312
|
+
if (!token.values || token.values.length !== 2) {
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
if (
|
|
316
|
+
token.type === 'MERGE:NUMBER|UNITOFTIME' ||
|
|
317
|
+
token.type === 'MERGE:YEAR|UNITOFTIME'
|
|
318
|
+
) {
|
|
319
|
+
const value = Number(token.values[0].value);
|
|
320
|
+
if (!DateParser.isValidNumber(value)) {
|
|
321
|
+
return undefined;
|
|
322
|
+
}
|
|
323
|
+
const unit = token.values[1].value as DateTimeUnit;
|
|
324
|
+
return {amount: value, unit: unit};
|
|
325
|
+
}
|
|
326
|
+
return undefined;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
private static createClauseFromMerged(
|
|
310
330
|
prefix: DatePrefix | undefined,
|
|
311
331
|
token: Token
|
|
312
|
-
):
|
|
332
|
+
): DateClause | undefined {
|
|
313
333
|
const tokens: Token[] = token.values || [];
|
|
314
334
|
switch (token.type) {
|
|
315
|
-
case '
|
|
316
|
-
case '
|
|
317
|
-
case '
|
|
318
|
-
case '
|
|
319
|
-
case '
|
|
320
|
-
return this.
|
|
321
|
-
case '
|
|
322
|
-
case '
|
|
323
|
-
case '
|
|
324
|
-
case '
|
|
325
|
-
return this.
|
|
326
|
-
case '
|
|
327
|
-
case '
|
|
328
|
-
|
|
329
|
-
case '
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
case '
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
case '
|
|
336
|
-
case '
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
case '
|
|
340
|
-
case '
|
|
341
|
-
case '
|
|
342
|
-
|
|
343
|
-
return this.createMomentNow(prefix, tokens);
|
|
335
|
+
case 'MERGE:LAST|UNITOFTIME':
|
|
336
|
+
case 'MERGE:LAST|DAYOFWEEK':
|
|
337
|
+
case 'MERGE:THIS|UNITOFTIME':
|
|
338
|
+
case 'MERGE:NEXT|UNITOFTIME':
|
|
339
|
+
case 'MERGE:NEXT|DAYOFWEEK':
|
|
340
|
+
return this.createIntervalMoment(prefix, tokens);
|
|
341
|
+
case 'MERGE:LAST|NUMBER|UNITOFTIME':
|
|
342
|
+
case 'MERGE:LAST|YEAR|UNITOFTIME':
|
|
343
|
+
case 'MERGE:NEXT|NUMBER|UNITOFTIME':
|
|
344
|
+
case 'MERGE:NEXT|YEAR|UNITOFTIME':
|
|
345
|
+
return this.createSpanMoment(prefix, tokens);
|
|
346
|
+
case 'MERGE:NUMBER|UNITOFTIME|AGO':
|
|
347
|
+
case 'MERGE:YEAR|UNITOFTIME|AGO':
|
|
348
|
+
case 'MERGE:NUMBER|UNITOFTIME|FROM|NOW':
|
|
349
|
+
case 'MERGE:YEAR|UNITOFTIME|FROM|NOW':
|
|
350
|
+
return this.createOffsetMoment(prefix, tokens);
|
|
351
|
+
case 'MERGE:NUMBER|UNITOFTIME':
|
|
352
|
+
case 'MERGE:YEAR|UNITOFTIME':
|
|
353
|
+
return this.createDateDuration(prefix, tokens);
|
|
354
|
+
case 'MERGE:DATE|TIME':
|
|
355
|
+
case 'MERGE:DATE':
|
|
356
|
+
case 'MERGE:YEAR':
|
|
357
|
+
return this.createAbsoluteMoment(prefix, tokens);
|
|
358
|
+
case 'MERGE:NOW':
|
|
359
|
+
case 'MERGE:TODAY':
|
|
360
|
+
case 'MERGE:YESTERDAY':
|
|
361
|
+
case 'MERGE:TOMORROW':
|
|
362
|
+
return this.createNamedMoment(prefix, tokens);
|
|
344
363
|
default:
|
|
345
364
|
return undefined;
|
|
346
365
|
}
|
|
@@ -359,48 +378,62 @@ export class DateParser extends BaseParser {
|
|
|
359
378
|
: this.tokens[position].type.startsWith(value);
|
|
360
379
|
}
|
|
361
380
|
|
|
362
|
-
private handleRange(clauses:
|
|
381
|
+
private handleRange(clauses: DateClause[]): boolean {
|
|
363
382
|
if (
|
|
364
|
-
this.isMatchingToken(this.index, '
|
|
383
|
+
this.isMatchingToken(this.index, 'MERGE', false) &&
|
|
365
384
|
(this.isMatchingToken(this.index + 1, 'TO', true) ||
|
|
366
385
|
this.isMatchingToken(this.index + 1, 'FOR', true)) &&
|
|
367
|
-
this.isMatchingToken(this.index + 2, '
|
|
386
|
+
this.isMatchingToken(this.index + 2, 'MERGE', false)
|
|
368
387
|
) {
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
const operator: 'TO' | 'FOR' = this.tokens[this.index + 1].type as
|
|
377
|
-
| 'TO'
|
|
378
|
-
| 'FOR';
|
|
388
|
+
const startToken = this.tokens[this.index];
|
|
389
|
+
const operator = this.tokens[this.index + 1].type; // TO | FOR
|
|
390
|
+
const endToken = this.tokens[this.index + 2];
|
|
391
|
+
const startClause = DateParser.createClauseFromMerged(
|
|
392
|
+
undefined,
|
|
393
|
+
startToken
|
|
394
|
+
);
|
|
379
395
|
this.index += 3;
|
|
380
|
-
if (
|
|
396
|
+
if (startClause === undefined || !('moment' in startClause)) {
|
|
381
397
|
return false;
|
|
382
398
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
399
|
+
if (operator === 'TO') {
|
|
400
|
+
const endClause = DateParser.createClauseFromMerged(
|
|
401
|
+
undefined,
|
|
402
|
+
endToken
|
|
403
|
+
);
|
|
404
|
+
if (endClause === undefined || !('moment' in endClause)) {
|
|
405
|
+
return false;
|
|
406
|
+
}
|
|
407
|
+
const clause: DateBetweenClause = {
|
|
408
|
+
operator: 'TO_RANGE',
|
|
409
|
+
from: startClause.moment,
|
|
410
|
+
to: endClause.moment,
|
|
411
|
+
};
|
|
412
|
+
clauses.push(clause);
|
|
413
|
+
} else {
|
|
414
|
+
const endDuration = DateParser.createDurationFromMerged(endToken);
|
|
415
|
+
if (endDuration === undefined) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
const clause: DateForClause = {
|
|
419
|
+
operator: 'FOR_RANGE',
|
|
420
|
+
from: startClause.moment,
|
|
421
|
+
duration: endDuration,
|
|
422
|
+
};
|
|
423
|
+
clauses.push(clause);
|
|
424
|
+
}
|
|
389
425
|
return true;
|
|
390
426
|
}
|
|
391
427
|
return false;
|
|
392
428
|
}
|
|
393
429
|
|
|
394
|
-
private
|
|
430
|
+
private handleMerged(
|
|
395
431
|
prefix: DatePrefix | undefined,
|
|
396
432
|
clauses: DateClause[]
|
|
397
433
|
): boolean {
|
|
398
434
|
const token: Token = this.getNext();
|
|
399
|
-
if (token.type.startsWith('
|
|
400
|
-
const clause
|
|
401
|
-
prefix,
|
|
402
|
-
token
|
|
403
|
-
);
|
|
435
|
+
if (token.type.startsWith('MERGE')) {
|
|
436
|
+
const clause = DateParser.createClauseFromMerged(prefix, token);
|
|
404
437
|
this.index++;
|
|
405
438
|
if (clause === undefined) {
|
|
406
439
|
return false;
|