chronolizer 0.2.0 → 0.4.0
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/README.md +170 -167
- package/dist/ast/constructors.d.mts +3 -8
- package/dist/ast/fold.d.mts +2 -1
- package/dist/ast/fold.mjs +38 -31
- package/dist/ast/normalize.mjs +4 -2
- package/dist/ast/schemas.d.mts +18 -25
- package/dist/ast/schemas.mjs +8 -17
- package/dist/filter/expression.mjs +27 -38
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/language/model.d.mts +33 -33
- package/dist/language/model.mjs +5 -8
- package/dist/language/registry.mjs +35 -33
- package/dist/locales/cs.mjs +253 -31
- package/dist/locales/de.mjs +366 -42
- package/dist/locales/en.mjs +215 -51
- package/dist/locales/es.mjs +498 -91
- package/dist/locales/fr.mjs +360 -65
- package/dist/locales/nl.mjs +302 -64
- package/dist/locales/pl.mjs +447 -135
- package/dist/locales/shared.mjs +192 -23
- package/dist/locales/tr.mjs +220 -41
- package/dist/natural/correction.d.mts +1 -1
- package/dist/natural/correction.mjs +31 -5
- package/dist/natural/format.mjs +1 -1
- package/dist/natural/parse.d.mts +1 -1
- package/dist/natural/parse.mjs +5 -4
- package/dist/natural/policy.mjs +2 -2
- package/dist/natural/suggest.mjs +19 -3
- package/dist/natural/suggestion.mjs +11 -5
- package/dist/resolve/resolve.mjs +2 -10
- package/package.json +1 -1
package/dist/locales/nl.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { normalizeNaturalText } from "../natural/text.mjs";
|
|
|
4
4
|
import { defineLanguagePlugin, languagePluginsLayer } from "../language/registry.mjs";
|
|
5
5
|
import { correctWhitespaceSeparatedText } from "../natural/correction.mjs";
|
|
6
6
|
import { completeNaturalPhrases, fixedCalendarPeriodPhrases, naturalCount, prefixNaturalPhrases } from "../natural/suggestion.mjs";
|
|
7
|
-
import { calendarPeriodOffset, candidate, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodEndDay, periodRange, periodStartDay, periodToDateRange, periodsFromPhrases, quarterOfRelativeYear, relativePeriod, relativeWeekend, remainingPeriodRange, renderPeriodRange, textAt, trailingPeriod, trailingRange, untilNowRange, validYear } from "./shared.mjs";
|
|
7
|
+
import { absoluteDatePeriod, calendarPeriodOffset, candidate, compileCountAliasNormalizer, compoundCountAliases, countAliasVocabulary, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, decimalTens, decomposeShiftedPeriodRange, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodDay, periodEndDay, periodRange, periodStartDay, periodToDateRange, periodsFromPhrases, quarterOfRelativeYear, relativePeriod, relativeWeekday, relativeWeekend, remainingPeriodRange, renderPeriodRange, sequentialCountAliases, shiftPeriod, textAt, trailingPeriod, trailingRange, untilNowRange, validYear } from "./shared.mjs";
|
|
8
8
|
import { Effect, Option, String as String$1 } from "effect";
|
|
9
9
|
//#region src/locales/nl.ts
|
|
10
10
|
const months = [
|
|
@@ -21,6 +21,54 @@ const months = [
|
|
|
21
21
|
"november",
|
|
22
22
|
"december"
|
|
23
23
|
];
|
|
24
|
+
const weekdays = [
|
|
25
|
+
"maandag",
|
|
26
|
+
"dinsdag",
|
|
27
|
+
"woensdag",
|
|
28
|
+
"donderdag",
|
|
29
|
+
"vrijdag",
|
|
30
|
+
"zaterdag",
|
|
31
|
+
"zondag"
|
|
32
|
+
];
|
|
33
|
+
const nextWeekdayPhrases = weekdays.map((weekday) => `volgende ${weekday}`);
|
|
34
|
+
const dutchCountWords = [
|
|
35
|
+
"twee",
|
|
36
|
+
"drie",
|
|
37
|
+
"vier",
|
|
38
|
+
"vijf",
|
|
39
|
+
"zes",
|
|
40
|
+
"zeven",
|
|
41
|
+
"acht",
|
|
42
|
+
"negen",
|
|
43
|
+
"tien",
|
|
44
|
+
"elf",
|
|
45
|
+
"twaalf",
|
|
46
|
+
"dertien",
|
|
47
|
+
"veertien",
|
|
48
|
+
"vijftien",
|
|
49
|
+
"zestien",
|
|
50
|
+
"zeventien",
|
|
51
|
+
"achttien",
|
|
52
|
+
"negentien",
|
|
53
|
+
"twintig"
|
|
54
|
+
];
|
|
55
|
+
const dutchCountOnes = [[1, "een"], ...dutchCountWords.slice(0, 8).map((word, index) => [index + 2, word])];
|
|
56
|
+
const dutchCountAliases = [...sequentialCountAliases(dutchCountWords.map((word) => [word]), 2), ...compoundCountAliases(decimalTens([
|
|
57
|
+
"twintig",
|
|
58
|
+
"dertig",
|
|
59
|
+
"veertig",
|
|
60
|
+
"vijftig",
|
|
61
|
+
"zestig",
|
|
62
|
+
"zeventig",
|
|
63
|
+
"tachtig",
|
|
64
|
+
"negentig"
|
|
65
|
+
]), dutchCountOnes, (ten, one) => {
|
|
66
|
+
return [`${one === "twee" || one === "drie" ? `${one}ën` : `${one}en`}${ten}`];
|
|
67
|
+
})];
|
|
68
|
+
const normalizeDutchCounts = compileCountAliasNormalizer(dutchCountAliases);
|
|
69
|
+
const dutchCountVocabulary = new Set(countAliasVocabulary(dutchCountAliases));
|
|
70
|
+
const correctDutch = (input, vocabulary) => correctWhitespaceSeparatedText(input, vocabulary, dutchCountVocabulary);
|
|
71
|
+
const normalizeDutch = (input, locale) => normalizeDutchCounts(normalizeNaturalText(input, locale));
|
|
24
72
|
const monthAbbreviations = [
|
|
25
73
|
["jan"],
|
|
26
74
|
["feb"],
|
|
@@ -40,6 +88,7 @@ const units = [
|
|
|
40
88
|
unit: "day",
|
|
41
89
|
singular: "dag",
|
|
42
90
|
plural: "dagen",
|
|
91
|
+
article: "de",
|
|
43
92
|
current: "vandaag",
|
|
44
93
|
previous: "gisteren",
|
|
45
94
|
next: "morgen",
|
|
@@ -50,6 +99,7 @@ const units = [
|
|
|
50
99
|
unit: "week",
|
|
51
100
|
singular: "week",
|
|
52
101
|
plural: "weken",
|
|
102
|
+
article: "de",
|
|
53
103
|
current: "deze week",
|
|
54
104
|
previous: "vorige week",
|
|
55
105
|
next: "volgende week",
|
|
@@ -60,6 +110,7 @@ const units = [
|
|
|
60
110
|
unit: "month",
|
|
61
111
|
singular: "maand",
|
|
62
112
|
plural: "maanden",
|
|
113
|
+
article: "de",
|
|
63
114
|
current: "deze maand",
|
|
64
115
|
previous: "vorige maand",
|
|
65
116
|
next: "volgende maand",
|
|
@@ -70,6 +121,7 @@ const units = [
|
|
|
70
121
|
unit: "quarter",
|
|
71
122
|
singular: "kwartaal",
|
|
72
123
|
plural: "kwartalen",
|
|
124
|
+
article: "het",
|
|
73
125
|
current: "dit kwartaal",
|
|
74
126
|
previous: "vorig kwartaal",
|
|
75
127
|
next: "volgend kwartaal",
|
|
@@ -80,6 +132,7 @@ const units = [
|
|
|
80
132
|
unit: "year",
|
|
81
133
|
singular: "jaar",
|
|
82
134
|
plural: "jaar",
|
|
135
|
+
article: "het",
|
|
83
136
|
current: "dit jaar",
|
|
84
137
|
previous: "vorig jaar",
|
|
85
138
|
next: "volgend jaar",
|
|
@@ -87,18 +140,58 @@ const units = [
|
|
|
87
140
|
remaining: "rest van het jaar"
|
|
88
141
|
}
|
|
89
142
|
];
|
|
90
|
-
const
|
|
143
|
+
const afterVan = (period) => period.startsWith("van ") ? period.slice(4) : period;
|
|
91
144
|
const unitAliases = [
|
|
92
|
-
[
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
[
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
145
|
+
[
|
|
146
|
+
"dag",
|
|
147
|
+
"day",
|
|
148
|
+
"singular"
|
|
149
|
+
],
|
|
150
|
+
[
|
|
151
|
+
"dagen",
|
|
152
|
+
"day",
|
|
153
|
+
"plural"
|
|
154
|
+
],
|
|
155
|
+
[
|
|
156
|
+
"week",
|
|
157
|
+
"week",
|
|
158
|
+
"singular"
|
|
159
|
+
],
|
|
160
|
+
[
|
|
161
|
+
"weken",
|
|
162
|
+
"week",
|
|
163
|
+
"plural"
|
|
164
|
+
],
|
|
165
|
+
[
|
|
166
|
+
"maand",
|
|
167
|
+
"month",
|
|
168
|
+
"singular"
|
|
169
|
+
],
|
|
170
|
+
[
|
|
171
|
+
"maanden",
|
|
172
|
+
"month",
|
|
173
|
+
"plural"
|
|
174
|
+
],
|
|
175
|
+
[
|
|
176
|
+
"kwartaal",
|
|
177
|
+
"quarter",
|
|
178
|
+
"singular"
|
|
179
|
+
],
|
|
180
|
+
[
|
|
181
|
+
"kwartalen",
|
|
182
|
+
"quarter",
|
|
183
|
+
"plural"
|
|
184
|
+
],
|
|
185
|
+
[
|
|
186
|
+
"jaar",
|
|
187
|
+
"year",
|
|
188
|
+
"both"
|
|
189
|
+
],
|
|
190
|
+
[
|
|
191
|
+
"jaren",
|
|
192
|
+
"year",
|
|
193
|
+
"plural"
|
|
194
|
+
]
|
|
102
195
|
];
|
|
103
196
|
const periodAliases = [
|
|
104
197
|
...units.flatMap((entry) => [
|
|
@@ -300,17 +393,30 @@ const monthNumber = (value) => {
|
|
|
300
393
|
return short === -1 ? void 0 : short + 1;
|
|
301
394
|
};
|
|
302
395
|
const dateLabel = (day, month, year) => `${day} ${textAt(months, month - 1)} ${year}`;
|
|
396
|
+
const currentDateLabel = (day, month) => `${day} ${textAt(months, month - 1)}`;
|
|
303
397
|
const parseNamedDate = (input) => {
|
|
304
398
|
const named = String$1.match(/^(?:de )?([0-3]?\d)(?:e|ste|de)?(?: van)? ([a-z]+\.?)(?: van)? (\d{4})$/u)(input);
|
|
305
399
|
if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, dateLabel);
|
|
306
400
|
const numeric = String$1.match(/^([0-3]?\d)[./-]([01]?\d)[./-](\d{4})$/u)(input);
|
|
307
|
-
if (Option.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
401
|
+
if (Option.isSome(numeric)) {
|
|
402
|
+
const year = validYear(textAt(numeric.value, 3));
|
|
403
|
+
const month = Number(textAt(numeric.value, 2));
|
|
404
|
+
const day = Number(textAt(numeric.value, 1));
|
|
405
|
+
if (year !== void 0 && month >= 1 && month <= 12) {
|
|
406
|
+
const value = isoDate(year, month, day);
|
|
407
|
+
if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, dateLabel(day, month, year)));
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
const current = String$1.match(/^(?:de )?([0-3]?\d)(?:e|ste|de)?(?: van)? ([a-z]+\.?)$/u)(input);
|
|
411
|
+
if (Option.isSome(current)) return namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel);
|
|
412
|
+
const relative = String$1.match(/^(?:de )?([0-3]?\d)(?:e|ste|de)? van (.+)$/u)(input);
|
|
413
|
+
if (Option.isNone(relative)) return Option.none();
|
|
414
|
+
const periodText = textAt(relative.value, 2);
|
|
415
|
+
const alias = periodAliases.find((entry) => entry[0] === periodText && entry[1] === "month");
|
|
416
|
+
if (alias === void 0) return Option.none();
|
|
417
|
+
const day = Number(textAt(relative.value, 1));
|
|
418
|
+
const month = relativePeriod(alias[1], alias[2], alias[3]);
|
|
419
|
+
return periodDay(month, day, `${day} van ${alias[3]}`);
|
|
314
420
|
};
|
|
315
421
|
const quarterNumber = (value) => {
|
|
316
422
|
if ((value.startsWith("q") || value.startsWith("k")) && value.length === 2) return Number(value.slice(1));
|
|
@@ -337,12 +443,13 @@ const parseQuarter = (input) => {
|
|
|
337
443
|
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
338
444
|
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `K${quarter}`));
|
|
339
445
|
};
|
|
340
|
-
const
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
446
|
+
const parseDatedPeriod = (input) => {
|
|
447
|
+
const knownPeriod = Option.firstSomeOf([
|
|
448
|
+
absoluteDatePeriod(input, "nl"),
|
|
449
|
+
parseNamedDate(input),
|
|
450
|
+
parseQuarter(input)
|
|
451
|
+
]);
|
|
452
|
+
if (Option.isSome(knownPeriod)) return knownPeriod;
|
|
346
453
|
const yearMatch = String$1.match(/^(?:het jaar |jaar )?(\d{4})$/u)(input);
|
|
347
454
|
if (Option.isSome(yearMatch)) {
|
|
348
455
|
const year = validYear(textAt(yearMatch.value, 1));
|
|
@@ -352,7 +459,21 @@ const parseBasePeriod = (input) => {
|
|
|
352
459
|
if (Option.isSome(monthYear)) {
|
|
353
460
|
const month = monthNumber(textAt(monthYear.value, 1));
|
|
354
461
|
const year = validYear(textAt(monthYear.value, 2));
|
|
355
|
-
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${
|
|
462
|
+
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${textAt(months, month - 1)} ${year}`));
|
|
463
|
+
}
|
|
464
|
+
return Option.none();
|
|
465
|
+
};
|
|
466
|
+
const parseBasePeriod = (input) => {
|
|
467
|
+
const datedPeriod = parseDatedPeriod(input);
|
|
468
|
+
if (Option.isSome(datedPeriod)) return datedPeriod;
|
|
469
|
+
const prefixedRelativeMonth = String$1.match(/^(vorige|deze|volgende) ([a-z]+\.?)$/u)(input);
|
|
470
|
+
if (Option.isSome(prefixedRelativeMonth)) {
|
|
471
|
+
const month = monthNumber(textAt(prefixedRelativeMonth.value, 2));
|
|
472
|
+
if (month !== void 0) {
|
|
473
|
+
const modifier = textAt(prefixedRelativeMonth.value, 1);
|
|
474
|
+
const direction = relativeYearDirection(modifier);
|
|
475
|
+
return Option.some(monthOfRelativeYear(month, direction, `${modifier} ${textAt(months, month - 1)}`));
|
|
476
|
+
}
|
|
356
477
|
}
|
|
357
478
|
const relativeMonth = String$1.match(/^([a-z]+\.?)(?: van)? (vorig jaar|volgend jaar|dit jaar)$/u)(input);
|
|
358
479
|
const relativeMonthYearFirst = String$1.match(/^(vorig jaar|volgend jaar|dit jaar) ([a-z]+\.?)$/u)(input);
|
|
@@ -363,10 +484,10 @@ const parseBasePeriod = (input) => {
|
|
|
363
484
|
const yearText = textAt(relativeMatch.value, yearFirst ? 1 : 2);
|
|
364
485
|
const month = monthNumber(monthText);
|
|
365
486
|
const direction = relativeYearDirection(yearText);
|
|
366
|
-
if (month !== void 0) return Option.some(monthOfRelativeYear(month, direction, `${
|
|
487
|
+
if (month !== void 0) return Option.some(monthOfRelativeYear(month, direction, `${textAt(months, month - 1)} ${relativeYearName(direction)}`));
|
|
367
488
|
}
|
|
368
489
|
const standaloneMonth = monthNumber(input);
|
|
369
|
-
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0,
|
|
490
|
+
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, textAt(months, standaloneMonth - 1)));
|
|
370
491
|
const alias = periodAliases.find((entry) => entry[0] === input);
|
|
371
492
|
if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
|
|
372
493
|
if ([
|
|
@@ -386,13 +507,33 @@ const parseBasePeriod = (input) => {
|
|
|
386
507
|
].includes(input)) return Option.some(relativeWeekend(1, "volgend weekend"));
|
|
387
508
|
if (input === "het weekend voor het vorige") return Option.some(relativeWeekend(-2, input));
|
|
388
509
|
if (input === "het weekend na het volgende") return Option.some(relativeWeekend(2, input));
|
|
389
|
-
|
|
510
|
+
const weekday = nextWeekdayPhrases.indexOf(input);
|
|
511
|
+
return weekday === -1 ? Option.none() : Option.some(relativeWeekday(weekday, 1, nextWeekdayPhrases[weekday] ?? input));
|
|
390
512
|
};
|
|
391
513
|
const parsePeriod = (input) => {
|
|
514
|
+
const shifted = String$1.match(/^(.+) (?:(?:over|binnen) ([1-9]\d*) (dag|dagen|week|weken|maand|maanden|kwartaal|kwartalen|jaar|jaren)|([1-9]\d*) (dag|dagen|week|weken|maand|maanden|kwartaal|kwartalen|jaar|jaren) (geleden|later))$/u)(input);
|
|
515
|
+
if (Option.isSome(shifted)) {
|
|
516
|
+
const suffixAmount = textAt(shifted.value, 4);
|
|
517
|
+
const amount = parseTrailingCount(suffixAmount || textAt(shifted.value, 2));
|
|
518
|
+
const unitText = textAt(shifted.value, suffixAmount.length > 0 ? 5 : 3);
|
|
519
|
+
const alias = unitAliases.find((unit) => unit[0] === unitText);
|
|
520
|
+
const entry = alias === void 0 ? void 0 : units.find((unit) => unit.unit === alias[1]);
|
|
521
|
+
const period = parsePeriod(textAt(shifted.value, 1));
|
|
522
|
+
if (Option.isSome(amount) && entry !== void 0 && Option.isSome(period)) {
|
|
523
|
+
const past = textAt(shifted.value, 6) === "geleden";
|
|
524
|
+
const direction = past ? -amount.value : amount.value;
|
|
525
|
+
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
526
|
+
const canonical = past ? `${period.value.canonical} ${amount.value} ${noun} geleden` : `${period.value.canonical} over ${amount.value} ${noun}`;
|
|
527
|
+
return Option.some(shiftPeriod(period.value, direction, entry.unit, canonical));
|
|
528
|
+
}
|
|
529
|
+
}
|
|
392
530
|
const edge = String$1.match(/^(?:het )?(begin|eind|einde)(?: van)? (.+)$/u)(input);
|
|
393
531
|
if (Option.isSome(edge)) {
|
|
394
532
|
const edgeName = textAt(edge.value, 1);
|
|
395
|
-
const
|
|
533
|
+
const periodText = textAt(edge.value, 2);
|
|
534
|
+
const basePeriod = parseBasePeriod(periodText);
|
|
535
|
+
const implicit = units.find((entry) => `${entry.article} ${entry.singular}` === periodText);
|
|
536
|
+
const period = Option.isSome(basePeriod) || implicit === void 0 ? basePeriod : Option.some(relativePeriod(implicit.unit, 0, implicit.current));
|
|
396
537
|
if (Option.isSome(period)) {
|
|
397
538
|
const isEnd = edgeName === "eind" || edgeName === "einde";
|
|
398
539
|
const canonical = `${isEnd ? "eind" : "begin"} van ${period.value.canonical}`;
|
|
@@ -406,34 +547,90 @@ const parsePeriod = (input) => {
|
|
|
406
547
|
"de hele ",
|
|
407
548
|
"het hele "
|
|
408
549
|
].find((prefix) => input.startsWith(prefix));
|
|
409
|
-
|
|
550
|
+
const base = parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
551
|
+
return Option.isSome(base) ? base : parseCalendarOffset(input);
|
|
552
|
+
};
|
|
553
|
+
const countedUnit = (value, amount) => {
|
|
554
|
+
const expected = amount === 1 ? "singular" : "plural";
|
|
555
|
+
const alias = unitAliases.find((entry) => entry[0] === value && (entry[2] === expected || entry[2] === "both"));
|
|
556
|
+
return alias === void 0 ? void 0 : units.find((entry) => entry.unit === alias[1]);
|
|
410
557
|
};
|
|
411
|
-
const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
|
|
412
558
|
const countedUnitPattern = "dag|dagen|week|weken|maand|maanden|kwartaal|kwartalen|jaar|jaren";
|
|
413
559
|
const countedPattern = (source) => new RegExp(source.replace("UNIT", countedUnitPattern), "u");
|
|
414
560
|
const calendarPastPattern = countedPattern("^([1-9]\\d*) (UNIT) geleden$");
|
|
415
561
|
const calendarFuturePatterns = [countedPattern("^(?:over|binnen) ([1-9]\\d*) (UNIT)$"), countedPattern("^([1-9]\\d*) (UNIT) later$")];
|
|
416
|
-
const rollingPastPatterns = [countedPattern("^(?:de )?(?:afgelopen|laatste|vorige) ([1-9]\\d*) (UNIT)$"), countedPattern("^([1-9]\\d*) (?:afgelopen|laatste|vorige) (UNIT)$")];
|
|
417
|
-
const rollingFuturePatterns = [countedPattern("^(?:de )?(?:komende|volgende|aankomende) ([1-9]\\d*) (UNIT)$"), countedPattern("^([1-9]\\d*) (?:komende|volgende|aankomende) (UNIT)$")];
|
|
562
|
+
const rollingPastPatterns = [countedPattern("^(?:(?:de|in de) )?(?:afgelopen|laatste|vorige) ([1-9]\\d*) (UNIT)$"), countedPattern("^([1-9]\\d*) (?:afgelopen|laatste|vorige) (UNIT)$")];
|
|
563
|
+
const rollingFuturePatterns = [countedPattern("^(?:(?:de|in de|binnen de) )?(?:komende|volgende|aankomende) ([1-9]\\d*) (UNIT)$"), countedPattern("^([1-9]\\d*) (?:komende|volgende|aankomende) (UNIT)$")];
|
|
418
564
|
const rollingSincePattern = countedPattern("^(?:sinds|gedurende) ([1-9]\\d*) (UNIT)$");
|
|
419
565
|
const rollingBarePattern = countedPattern("^([1-9]\\d*) (UNIT)$");
|
|
420
566
|
const firstPatternMatch = (input, patterns) => Option.firstSomeOf(patterns.map((pattern) => String$1.match(pattern)(input)));
|
|
567
|
+
const singularRollingCanonical = (entry, future) => future ? `vanaf nu gedurende een ${entry.singular}` : `sinds een ${entry.singular}`;
|
|
568
|
+
const singularRollingPhrases = units.flatMap((entry) => [
|
|
569
|
+
{
|
|
570
|
+
phrase: `${entry.article} afgelopen ${entry.singular}`,
|
|
571
|
+
entry,
|
|
572
|
+
future: false
|
|
573
|
+
},
|
|
574
|
+
{
|
|
575
|
+
phrase: `${entry.article} laatste ${entry.singular}`,
|
|
576
|
+
entry,
|
|
577
|
+
future: false
|
|
578
|
+
},
|
|
579
|
+
{
|
|
580
|
+
phrase: `sinds een ${entry.singular}`,
|
|
581
|
+
entry,
|
|
582
|
+
future: false
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
phrase: `gedurende ${entry.article} komende ${entry.singular}`,
|
|
586
|
+
entry,
|
|
587
|
+
future: true
|
|
588
|
+
},
|
|
589
|
+
{
|
|
590
|
+
phrase: `vanaf nu gedurende een ${entry.singular}`,
|
|
591
|
+
entry,
|
|
592
|
+
future: true
|
|
593
|
+
}
|
|
594
|
+
]);
|
|
595
|
+
const singularCalendarOffsets = units.flatMap((entry) => [
|
|
596
|
+
{
|
|
597
|
+
phrase: `een ${entry.singular} geleden`,
|
|
598
|
+
entry,
|
|
599
|
+
direction: -1
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
phrase: `over een ${entry.singular}`,
|
|
603
|
+
entry,
|
|
604
|
+
direction: 1
|
|
605
|
+
},
|
|
606
|
+
{
|
|
607
|
+
phrase: `binnen een ${entry.singular}`,
|
|
608
|
+
entry,
|
|
609
|
+
direction: 1
|
|
610
|
+
}
|
|
611
|
+
]);
|
|
421
612
|
const parseCalendarOffset = (input) => {
|
|
613
|
+
const singular = singularCalendarOffsets.find((entry) => entry.phrase === input);
|
|
614
|
+
if (singular !== void 0) return Option.some(relativePeriod(singular.entry.unit, singular.direction, singular.phrase));
|
|
422
615
|
const past = String$1.match(calendarPastPattern)(input);
|
|
423
616
|
const future = firstPatternMatch(input, calendarFuturePatterns);
|
|
424
617
|
const match = Option.firstSomeOf([past, future]);
|
|
425
618
|
if (Option.isNone(match)) return Option.none();
|
|
426
619
|
const amount = parseTrailingCount(textAt(match.value, 1));
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
const entry = units.find((item) => item.unit === unit);
|
|
620
|
+
if (Option.isNone(amount)) return Option.none();
|
|
621
|
+
const entry = countedUnit(textAt(match.value, 2), amount.value);
|
|
430
622
|
if (entry === void 0) return Option.none();
|
|
431
623
|
const direction = Option.isSome(past) ? -amount.value : amount.value;
|
|
432
624
|
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
433
625
|
const canonical = direction < 0 ? `${amount.value} ${noun} geleden` : `over ${amount.value} ${noun}`;
|
|
434
|
-
return Option.some(
|
|
626
|
+
return Option.some(relativePeriod(entry.unit, direction, canonical));
|
|
435
627
|
};
|
|
436
628
|
const parseRollingPeriod = (input) => {
|
|
629
|
+
const singular = singularRollingPhrases.find((entry) => entry.phrase === input);
|
|
630
|
+
if (singular !== void 0) {
|
|
631
|
+
const range = singular.future ? futureRange(1, singular.entry.unit) : trailingRange(1, singular.entry.unit);
|
|
632
|
+
return Option.some(candidate(range, singularRollingCanonical(singular.entry, singular.future)));
|
|
633
|
+
}
|
|
437
634
|
const since = String$1.match(rollingSincePattern)(input);
|
|
438
635
|
const past = firstPatternMatch(input, rollingPastPatterns);
|
|
439
636
|
const bare = String$1.match(rollingBarePattern)(input);
|
|
@@ -446,15 +643,26 @@ const parseRollingPeriod = (input) => {
|
|
|
446
643
|
]);
|
|
447
644
|
if (Option.isNone(match)) return Option.none();
|
|
448
645
|
const amount = parseTrailingCount(textAt(match.value, 1));
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
const entry = units.find((item) => item.unit === unit);
|
|
646
|
+
if (Option.isNone(amount)) return Option.none();
|
|
647
|
+
const entry = countedUnit(textAt(match.value, 2), amount.value);
|
|
452
648
|
if (entry === void 0) return Option.none();
|
|
453
649
|
const isFuture = Option.isSome(future);
|
|
454
|
-
const range = isFuture ? futureRange(amount.value, unit) : trailingRange(amount.value, unit);
|
|
650
|
+
const range = isFuture ? futureRange(amount.value, entry.unit) : trailingRange(amount.value, entry.unit);
|
|
651
|
+
if (amount.value === 1) return Option.some(candidate(range, singularRollingCanonical(entry, isFuture)));
|
|
455
652
|
const modifier = isFuture ? "komende" : "afgelopen";
|
|
456
|
-
|
|
457
|
-
|
|
653
|
+
return Option.some(candidate(range, `de ${modifier} ${amount.value} ${entry.plural}`));
|
|
654
|
+
};
|
|
655
|
+
const parseElidedDateRange = (input) => {
|
|
656
|
+
const joined = String$1.match(/^(?:van ([0-3]?\d) tot(?: en met)?|tussen (?:de )?([0-3]?\d)(?:e)? en(?: de)?) ([0-3]?\d)(?:e)? (.+)$/u)(input);
|
|
657
|
+
const dashed = String$1.match(/^([0-3]?\d)[–—-]([0-3]?\d) (.+)$/u)(input);
|
|
658
|
+
const match = Option.firstSomeOf([joined, dashed]);
|
|
659
|
+
if (Option.isNone(match)) return Option.none();
|
|
660
|
+
const isJoined = Option.isSome(joined);
|
|
661
|
+
const lowerDay = textAt(match.value, 1) || textAt(match.value, 2);
|
|
662
|
+
const upperDay = textAt(match.value, isJoined ? 3 : 2);
|
|
663
|
+
const period = afterVan(textAt(match.value, isJoined ? 4 : 3));
|
|
664
|
+
const suffix = periodAliases.some((entry) => entry[0] === period && entry[1] === "month") ? `van ${period}` : period;
|
|
665
|
+
return joinedPeriodCandidate(`van ${lowerDay} ${suffix} tot en met ${upperDay} ${suffix}`, [["van ", " tot en met "]], parsePeriod, (lower, upper) => `van ${lower} tot en met ${upper}`);
|
|
458
666
|
};
|
|
459
667
|
const boundaryCandidate = (input) => openBoundaryCandidate(input, [
|
|
460
668
|
["tot voor ", "before"],
|
|
@@ -479,12 +687,12 @@ const parseDutch = (input) => {
|
|
|
479
687
|
"sinds nu",
|
|
480
688
|
"voortaan"
|
|
481
689
|
].includes(input)) return Option.some(candidate(fromNowRange(), "vanaf nu"));
|
|
482
|
-
const offset = parseCalendarOffset(input);
|
|
483
|
-
if (Option.isSome(offset)) return offset;
|
|
484
690
|
const rolling = parseRollingPeriod(input);
|
|
485
691
|
if (Option.isSome(rolling)) return rolling;
|
|
486
692
|
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
487
693
|
if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
|
|
694
|
+
const elided = parseElidedDateRange(input);
|
|
695
|
+
if (Option.isSome(elided)) return elided;
|
|
488
696
|
const nowBounded = joinedNowCandidate(input, [
|
|
489
697
|
["vanaf ", " tot nu toe"],
|
|
490
698
|
["sinds ", " tot nu toe"],
|
|
@@ -492,7 +700,8 @@ const parseDutch = (input) => {
|
|
|
492
700
|
], [
|
|
493
701
|
"vanaf nu tot en met ",
|
|
494
702
|
"van vandaag tot en met ",
|
|
495
|
-
"tussen vandaag en "
|
|
703
|
+
"tussen vandaag en ",
|
|
704
|
+
"nu tot en met "
|
|
496
705
|
], parsePeriod, (period) => `vanaf ${period} tot nu toe`, (period) => `vanaf nu tot en met ${period}`);
|
|
497
706
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
498
707
|
const bounded = joinedPeriodCandidate(input, [
|
|
@@ -508,16 +717,28 @@ const parseDutch = (input) => {
|
|
|
508
717
|
if (Option.isSome(bounded)) return bounded;
|
|
509
718
|
const boundary = boundaryCandidate(input);
|
|
510
719
|
if (Option.isSome(boundary)) return boundary;
|
|
511
|
-
return Option.map(
|
|
720
|
+
return parsePeriod(input).pipe(Option.map((period) => candidate(periodRange(period), period.canonical)));
|
|
512
721
|
};
|
|
513
|
-
const
|
|
514
|
-
...periodAliases.map((entry) => entry[0]),
|
|
722
|
+
const weekendPhrases = [
|
|
515
723
|
"dit weekend",
|
|
516
724
|
"vorig weekend",
|
|
517
725
|
"volgend weekend",
|
|
518
726
|
"het weekend voor het vorige",
|
|
519
|
-
"het weekend na het volgende"
|
|
520
|
-
|
|
727
|
+
"het weekend na het volgende"
|
|
728
|
+
];
|
|
729
|
+
const edgePeriodPhrases = [
|
|
730
|
+
...units.filter((entry) => entry.unit !== "day").flatMap((entry) => [
|
|
731
|
+
entry.current,
|
|
732
|
+
entry.previous,
|
|
733
|
+
entry.next
|
|
734
|
+
]),
|
|
735
|
+
...weekendPhrases,
|
|
736
|
+
...months
|
|
737
|
+
].flatMap((period) => [`begin van ${period}`, `eind van ${period}`]);
|
|
738
|
+
const staticPeriodPhrases = [
|
|
739
|
+
...periodAliases.map((entry) => entry[0]),
|
|
740
|
+
...weekendPhrases,
|
|
741
|
+
...edgePeriodPhrases,
|
|
521
742
|
...[
|
|
522
743
|
1,
|
|
523
744
|
2,
|
|
@@ -531,9 +752,12 @@ const staticPeriodPhrases = [
|
|
|
531
752
|
]),
|
|
532
753
|
...months.flatMap((month) => [
|
|
533
754
|
month,
|
|
755
|
+
`vorige ${month}`,
|
|
756
|
+
`volgende ${month}`,
|
|
534
757
|
`${month} vorig jaar`,
|
|
535
758
|
`${month} volgend jaar`
|
|
536
|
-
])
|
|
759
|
+
]),
|
|
760
|
+
...nextWeekdayPhrases
|
|
537
761
|
];
|
|
538
762
|
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
539
763
|
const boundaryPrefixes = [
|
|
@@ -563,6 +787,8 @@ const countedSuggestions = (input) => {
|
|
|
563
787
|
const dutchSuggestionPhrases = [
|
|
564
788
|
...units.map((entry) => entry.toDate),
|
|
565
789
|
...units.map((entry) => entry.remaining),
|
|
790
|
+
...singularRollingPhrases.map((entry) => entry.phrase),
|
|
791
|
+
...singularCalendarOffsets.map((entry) => entry.phrase),
|
|
566
792
|
...staticPeriodPhrases,
|
|
567
793
|
...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
|
|
568
794
|
"tot nu toe",
|
|
@@ -578,6 +804,16 @@ const suggestDutch = (input, limit) => {
|
|
|
578
804
|
], limit);
|
|
579
805
|
};
|
|
580
806
|
const renderDutch = (range) => {
|
|
807
|
+
const shifted = decomposeShiftedPeriodRange(range);
|
|
808
|
+
if (Option.isSome(shifted)) {
|
|
809
|
+
const base = renderDutch(shifted.value.baseRange);
|
|
810
|
+
const entry = units.find((unit) => unit.unit === shifted.value.unit);
|
|
811
|
+
if (Option.isSome(base) && entry !== void 0) {
|
|
812
|
+
const amount = Math.abs(shifted.value.amount);
|
|
813
|
+
const noun = amount === 1 ? entry.singular : entry.plural;
|
|
814
|
+
return Option.some(shifted.value.amount < 0 ? `${base.value} ${amount} ${noun} geleden` : `${base.value} over ${amount} ${noun}`);
|
|
815
|
+
}
|
|
816
|
+
}
|
|
581
817
|
const offset = calendarPeriodOffset(range);
|
|
582
818
|
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
583
819
|
const entry = units.find((unit) => unit.unit === offset.value.unit);
|
|
@@ -590,26 +826,25 @@ const renderDutch = (range) => {
|
|
|
590
826
|
const future = futurePeriod(range);
|
|
591
827
|
if (Option.isSome(future)) {
|
|
592
828
|
const entry = units.find((unit) => unit.unit === future.value.unit);
|
|
593
|
-
if (entry !== void 0) {
|
|
594
|
-
const noun = future.value.amount === 1 ? entry.singular : entry.plural;
|
|
595
|
-
return Option.some(`de komende ${future.value.amount} ${noun}`);
|
|
596
|
-
}
|
|
829
|
+
if (entry !== void 0) return Option.some(future.value.amount === 1 ? singularRollingCanonical(entry, true) : `de komende ${future.value.amount} ${entry.plural}`);
|
|
597
830
|
}
|
|
598
831
|
const trailing = trailingPeriod(range);
|
|
599
832
|
if (Option.isSome(trailing)) {
|
|
600
833
|
const entry = units.find((unit) => unit.unit === trailing.value.unit);
|
|
601
|
-
if (entry !== void 0) {
|
|
602
|
-
const noun = trailing.value.amount === 1 ? entry.singular : entry.plural;
|
|
603
|
-
return Option.some(`de afgelopen ${trailing.value.amount} ${noun}`);
|
|
604
|
-
}
|
|
834
|
+
if (entry !== void 0) return Option.some(trailing.value.amount === 1 ? singularRollingCanonical(entry, false) : `de afgelopen ${trailing.value.amount} ${entry.plural}`);
|
|
605
835
|
}
|
|
606
|
-
const periods = [
|
|
836
|
+
const periods = [
|
|
837
|
+
...staticPeriods,
|
|
838
|
+
...currentYearDatePeriods(range, currentDateLabel),
|
|
839
|
+
...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range).map((phrase) => phrase.startsWith("Q") ? `K${phrase.slice(1)}` : phrase)], parsePeriod)
|
|
840
|
+
];
|
|
607
841
|
return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `vanaf ${period}`, (period) => `voor ${period}`, (period) => `tot en met ${period}`, (period) => `na ${period}`, (lower, upper) => `van ${lower} tot en met ${upper}`, (period) => `vanaf ${period} tot nu toe`, (period) => `vanaf nu tot en met ${period}`, () => "tot nu toe", () => "vanaf nu");
|
|
608
842
|
};
|
|
609
843
|
const DutchContribution = new BaseLanguageContribution({
|
|
610
844
|
locale: "nl",
|
|
611
845
|
vocabulary: [
|
|
612
846
|
...months,
|
|
847
|
+
...weekdays,
|
|
613
848
|
...monthAbbreviations.flatMap((aliases) => aliases),
|
|
614
849
|
...units.flatMap((entry) => [
|
|
615
850
|
entry.singular,
|
|
@@ -624,10 +859,13 @@ const DutchContribution = new BaseLanguageContribution({
|
|
|
624
859
|
"begin",
|
|
625
860
|
"binnen",
|
|
626
861
|
"eind",
|
|
862
|
+
"en",
|
|
627
863
|
"geleden",
|
|
628
864
|
"komende",
|
|
629
865
|
"laatste",
|
|
866
|
+
"met",
|
|
630
867
|
"na",
|
|
868
|
+
"nu",
|
|
631
869
|
"over",
|
|
632
870
|
"rest",
|
|
633
871
|
"sinds",
|
|
@@ -637,8 +875,8 @@ const DutchContribution = new BaseLanguageContribution({
|
|
|
637
875
|
"volgend",
|
|
638
876
|
"voor"
|
|
639
877
|
],
|
|
640
|
-
normalize:
|
|
641
|
-
correct:
|
|
878
|
+
normalize: normalizeDutch,
|
|
879
|
+
correct: correctDutch,
|
|
642
880
|
parseExact: parseDutch,
|
|
643
881
|
suggest: suggestDutch,
|
|
644
882
|
render: renderDutch
|