chronolizer 0.1.0 → 0.2.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.
Files changed (62) hide show
  1. package/README.md +70 -7
  2. package/dist/ast/constructors.d.mts +140 -0
  3. package/dist/ast/constructors.mjs +25 -0
  4. package/dist/ast/fold.d.mts +12 -0
  5. package/dist/ast/fold.mjs +51 -0
  6. package/dist/ast/normalize.d.mts +42 -0
  7. package/dist/ast/normalize.mjs +32 -0
  8. package/dist/ast/schemas.d.mts +87 -0
  9. package/dist/ast/schemas.mjs +74 -0
  10. package/dist/filter/codec.d.mts +92 -0
  11. package/dist/filter/codec.mjs +48 -0
  12. package/dist/filter/errors.d.mts +14 -0
  13. package/dist/filter/errors.mjs +10 -0
  14. package/dist/filter/expression.d.mts +8 -0
  15. package/dist/filter/expression.mjs +93 -0
  16. package/dist/filter/schema.d.mts +13 -0
  17. package/dist/filter/schema.mjs +11 -0
  18. package/dist/filter/transformation.d.mts +37 -0
  19. package/dist/filter/transformation.mjs +20 -0
  20. package/dist/index.d.mts +22 -969
  21. package/dist/index.mjs +22 -2305
  22. package/dist/language/errors.d.mts +38 -0
  23. package/dist/language/errors.mjs +30 -0
  24. package/dist/language/model.d.mts +239 -0
  25. package/dist/language/model.mjs +53 -0
  26. package/dist/language/registry.d.mts +17 -0
  27. package/dist/language/registry.mjs +134 -0
  28. package/dist/locales/cs.d.mts +10 -0
  29. package/dist/locales/cs.mjs +693 -0
  30. package/dist/locales/de.d.mts +10 -0
  31. package/dist/locales/de.mjs +828 -0
  32. package/dist/locales/en.d.mts +10 -0
  33. package/dist/locales/en.mjs +550 -0
  34. package/dist/locales/es.d.mts +10 -0
  35. package/dist/locales/es.mjs +660 -0
  36. package/dist/locales/fr.d.mts +10 -0
  37. package/dist/locales/fr.mjs +737 -0
  38. package/dist/locales/nl.d.mts +10 -0
  39. package/dist/locales/nl.mjs +652 -0
  40. package/dist/locales/pl.d.mts +10 -0
  41. package/dist/locales/pl.mjs +711 -0
  42. package/dist/locales/shared.mjs +289 -0
  43. package/dist/locales/tr.d.mts +10 -0
  44. package/dist/locales/tr.mjs +660 -0
  45. package/dist/natural/correction.d.mts +13 -0
  46. package/dist/natural/correction.mjs +73 -0
  47. package/dist/natural/format.d.mts +47 -0
  48. package/dist/natural/format.mjs +14 -0
  49. package/dist/natural/parse.d.mts +99 -0
  50. package/dist/natural/parse.mjs +66 -0
  51. package/dist/natural/policy.mjs +6 -0
  52. package/dist/natural/suggest.d.mts +53 -0
  53. package/dist/natural/suggest.mjs +24 -0
  54. package/dist/natural/suggestion.d.mts +4 -0
  55. package/dist/natural/suggestion.mjs +79 -0
  56. package/dist/natural/text.d.mts +5 -0
  57. package/dist/natural/text.mjs +5 -0
  58. package/dist/resolve/resolve.d.mts +79 -0
  59. package/dist/resolve/resolve.mjs +66 -0
  60. package/dist/resolve/schema.d.mts +59 -0
  61. package/dist/resolve/schema.mjs +28 -0
  62. package/package.json +15 -3
@@ -0,0 +1,10 @@
1
+ import { LanguageConflictError, LanguageRegistrationError } from "../language/errors.mjs";
2
+ import { BaseLanguageContribution, LanguagePlugin } from "../language/model.mjs";
3
+ import { LanguageRegistry } from "../language/registry.mjs";
4
+ import "../index.mjs";
5
+ //#region src/locales/nl.d.ts
6
+ declare const DutchContribution: BaseLanguageContribution;
7
+ declare const DutchLanguage: LanguagePlugin;
8
+ declare const DutchLanguageLayer: import("effect/Layer").Layer<LanguageRegistry, LanguageConflictError | LanguageRegistrationError, never>;
9
+ //#endregion
10
+ export { DutchContribution, DutchLanguage, DutchLanguageLayer };
@@ -0,0 +1,652 @@
1
+ import { isIsoDate } from "../ast/schemas.mjs";
2
+ import { BaseLanguageContribution } from "../language/model.mjs";
3
+ import { normalizeNaturalText } from "../natural/text.mjs";
4
+ import { defineLanguagePlugin, languagePluginsLayer } from "../language/registry.mjs";
5
+ import { correctWhitespaceSeparatedText } from "../natural/correction.mjs";
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";
8
+ import { Effect, Option, String as String$1 } from "effect";
9
+ //#region src/locales/nl.ts
10
+ const months = [
11
+ "januari",
12
+ "februari",
13
+ "maart",
14
+ "april",
15
+ "mei",
16
+ "juni",
17
+ "juli",
18
+ "augustus",
19
+ "september",
20
+ "oktober",
21
+ "november",
22
+ "december"
23
+ ];
24
+ const monthAbbreviations = [
25
+ ["jan"],
26
+ ["feb"],
27
+ ["mar", "mrt"],
28
+ ["apr"],
29
+ [],
30
+ ["jun"],
31
+ ["jul"],
32
+ ["aug"],
33
+ ["sep", "sept"],
34
+ ["okt"],
35
+ ["nov"],
36
+ ["dec"]
37
+ ];
38
+ const units = [
39
+ {
40
+ unit: "day",
41
+ singular: "dag",
42
+ plural: "dagen",
43
+ current: "vandaag",
44
+ previous: "gisteren",
45
+ next: "morgen",
46
+ toDate: "dag tot nu toe",
47
+ remaining: "rest van de dag"
48
+ },
49
+ {
50
+ unit: "week",
51
+ singular: "week",
52
+ plural: "weken",
53
+ current: "deze week",
54
+ previous: "vorige week",
55
+ next: "volgende week",
56
+ toDate: "week tot nu toe",
57
+ remaining: "rest van de week"
58
+ },
59
+ {
60
+ unit: "month",
61
+ singular: "maand",
62
+ plural: "maanden",
63
+ current: "deze maand",
64
+ previous: "vorige maand",
65
+ next: "volgende maand",
66
+ toDate: "maand tot nu toe",
67
+ remaining: "rest van de maand"
68
+ },
69
+ {
70
+ unit: "quarter",
71
+ singular: "kwartaal",
72
+ plural: "kwartalen",
73
+ current: "dit kwartaal",
74
+ previous: "vorig kwartaal",
75
+ next: "volgend kwartaal",
76
+ toDate: "kwartaal tot nu toe",
77
+ remaining: "rest van het kwartaal"
78
+ },
79
+ {
80
+ unit: "year",
81
+ singular: "jaar",
82
+ plural: "jaar",
83
+ current: "dit jaar",
84
+ previous: "vorig jaar",
85
+ next: "volgend jaar",
86
+ toDate: "jaar tot nu toe",
87
+ remaining: "rest van het jaar"
88
+ }
89
+ ];
90
+ const title = (value) => `${value.slice(0, 1).toLocaleUpperCase("nl")}${value.slice(1)}`;
91
+ const unitAliases = [
92
+ ["dag", "day"],
93
+ ["dagen", "day"],
94
+ ["week", "week"],
95
+ ["weken", "week"],
96
+ ["maand", "month"],
97
+ ["maanden", "month"],
98
+ ["kwartaal", "quarter"],
99
+ ["kwartalen", "quarter"],
100
+ ["jaar", "year"],
101
+ ["jaren", "year"]
102
+ ];
103
+ const periodAliases = [
104
+ ...units.flatMap((entry) => [
105
+ [
106
+ entry.current,
107
+ entry.unit,
108
+ 0,
109
+ entry.current
110
+ ],
111
+ [
112
+ entry.previous,
113
+ entry.unit,
114
+ -1,
115
+ entry.previous
116
+ ],
117
+ [
118
+ entry.next,
119
+ entry.unit,
120
+ 1,
121
+ entry.next
122
+ ]
123
+ ]),
124
+ [
125
+ "huidige week",
126
+ "week",
127
+ 0,
128
+ "deze week"
129
+ ],
130
+ [
131
+ "afgelopen week",
132
+ "week",
133
+ -1,
134
+ "vorige week"
135
+ ],
136
+ [
137
+ "komende week",
138
+ "week",
139
+ 1,
140
+ "volgende week"
141
+ ],
142
+ [
143
+ "huidige maand",
144
+ "month",
145
+ 0,
146
+ "deze maand"
147
+ ],
148
+ [
149
+ "afgelopen maand",
150
+ "month",
151
+ -1,
152
+ "vorige maand"
153
+ ],
154
+ [
155
+ "aankomende maand",
156
+ "month",
157
+ 1,
158
+ "volgende maand"
159
+ ],
160
+ [
161
+ "huidig kwartaal",
162
+ "quarter",
163
+ 0,
164
+ "dit kwartaal"
165
+ ],
166
+ [
167
+ "afgelopen kwartaal",
168
+ "quarter",
169
+ -1,
170
+ "vorig kwartaal"
171
+ ],
172
+ [
173
+ "komend kwartaal",
174
+ "quarter",
175
+ 1,
176
+ "volgend kwartaal"
177
+ ],
178
+ [
179
+ "huidig jaar",
180
+ "year",
181
+ 0,
182
+ "dit jaar"
183
+ ],
184
+ [
185
+ "afgelopen jaar",
186
+ "year",
187
+ -1,
188
+ "vorig jaar"
189
+ ],
190
+ [
191
+ "komend jaar",
192
+ "year",
193
+ 1,
194
+ "volgend jaar"
195
+ ],
196
+ [
197
+ "eergisteren",
198
+ "day",
199
+ -2,
200
+ "eergisteren"
201
+ ],
202
+ [
203
+ "overmorgen",
204
+ "day",
205
+ 2,
206
+ "overmorgen"
207
+ ],
208
+ [
209
+ "de week voor de vorige",
210
+ "week",
211
+ -2,
212
+ "de week voor de vorige"
213
+ ],
214
+ [
215
+ "de week na de volgende",
216
+ "week",
217
+ 2,
218
+ "de week na de volgende"
219
+ ],
220
+ [
221
+ "de maand voor de vorige",
222
+ "month",
223
+ -2,
224
+ "de maand voor de vorige"
225
+ ],
226
+ [
227
+ "de maand na de volgende",
228
+ "month",
229
+ 2,
230
+ "de maand na de volgende"
231
+ ],
232
+ [
233
+ "het kwartaal voor het vorige",
234
+ "quarter",
235
+ -2,
236
+ "het kwartaal voor het vorige"
237
+ ],
238
+ [
239
+ "het kwartaal na het volgende",
240
+ "quarter",
241
+ 2,
242
+ "het kwartaal na het volgende"
243
+ ],
244
+ [
245
+ "het jaar voor het vorige",
246
+ "year",
247
+ -2,
248
+ "het jaar voor het vorige"
249
+ ],
250
+ [
251
+ "het jaar na het volgende",
252
+ "year",
253
+ 2,
254
+ "het jaar na het volgende"
255
+ ]
256
+ ];
257
+ const periodArticle = {
258
+ day: "van de dag",
259
+ week: "van de week",
260
+ month: "van de maand",
261
+ quarter: "van het kwartaal",
262
+ year: "van het jaar"
263
+ };
264
+ const toDatePhrases = units.flatMap((entry) => {
265
+ const yearAliases = entry.unit === "year" ? [
266
+ "sinds jaarbegin",
267
+ "vanaf jaarbegin",
268
+ "sinds het begin van dit jaar"
269
+ ] : [];
270
+ return [
271
+ entry.toDate,
272
+ `sinds het begin ${periodArticle[entry.unit]}`,
273
+ `vanaf het begin ${periodArticle[entry.unit]}`,
274
+ `${entry.current} tot nu toe`,
275
+ ...yearAliases
276
+ ].map((phrase) => ({
277
+ entry,
278
+ phrase
279
+ }));
280
+ });
281
+ const remainingPhrases = units.flatMap((entry) => [entry.remaining, `wat over is ${periodArticle[entry.unit]}`].map((phrase) => ({
282
+ entry,
283
+ phrase
284
+ })));
285
+ const relativeYearDirection = (value) => {
286
+ if (value.includes("vorig")) return -1;
287
+ if (value.includes("volgend")) return 1;
288
+ return 0;
289
+ };
290
+ const relativeYearName = (direction) => {
291
+ if (direction < 0) return "vorig jaar";
292
+ if (direction > 0) return "volgend jaar";
293
+ return "dit jaar";
294
+ };
295
+ const monthNumber = (value) => {
296
+ const normalized = value.endsWith(".") ? value.slice(0, -1) : value;
297
+ const full = months.findIndex((month) => month === normalized);
298
+ if (full !== -1) return full + 1;
299
+ const short = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
300
+ return short === -1 ? void 0 : short + 1;
301
+ };
302
+ const dateLabel = (day, month, year) => `${day} ${textAt(months, month - 1)} ${year}`;
303
+ const parseNamedDate = (input) => {
304
+ const named = String$1.match(/^(?:de )?([0-3]?\d)(?:e|ste|de)?(?: van)? ([a-z]+\.?)(?: van)? (\d{4})$/u)(input);
305
+ if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, dateLabel);
306
+ const numeric = String$1.match(/^([0-3]?\d)[./-]([01]?\d)[./-](\d{4})$/u)(input);
307
+ if (Option.isNone(numeric)) return Option.none();
308
+ const year = validYear(textAt(numeric.value, 3));
309
+ const month = Number(textAt(numeric.value, 2));
310
+ const day = Number(textAt(numeric.value, 1));
311
+ if (year === void 0 || month < 1 || month > 12) return Option.none();
312
+ const value = isoDate(year, month, day);
313
+ return isIsoDate(value) && value !== "9999-12-31" ? Option.some(fixedDatePeriod(value, dateLabel(day, month, year))) : Option.none();
314
+ };
315
+ const quarterNumber = (value) => {
316
+ if ((value.startsWith("q") || value.startsWith("k")) && value.length === 2) return Number(value.slice(1));
317
+ if (value === "1e" || value === "eerste") return 1;
318
+ if (value === "2e" || value === "tweede") return 2;
319
+ if (value === "3e" || value === "derde") return 3;
320
+ return value === "4e" || value === "vierde" ? 4 : void 0;
321
+ };
322
+ const parseQuarter = (input) => {
323
+ const fixed = String$1.match(/^(k[1-4]|q[1-4]|1e|eerste|2e|tweede|3e|derde|4e|vierde)(?: kwartaal)?(?: van)? (\d{4})$/u)(input);
324
+ if (Option.isSome(fixed)) {
325
+ const quarter = quarterNumber(textAt(fixed.value, 1));
326
+ const year = validYear(textAt(fixed.value, 2));
327
+ if (quarter !== void 0 && year !== void 0) return Option.some(fixedQuarterPeriod(year, quarter, `K${quarter} ${year}`));
328
+ }
329
+ const relative = String$1.match(/^(?:het )?(k[1-4]|q[1-4]) (?:van )?(vorig jaar|volgend jaar|dit jaar)$/u)(input);
330
+ if (Option.isSome(relative)) {
331
+ const quarter = quarterNumber(textAt(relative.value, 1));
332
+ const direction = relativeYearDirection(textAt(relative.value, 2));
333
+ if (quarter !== void 0) return Option.some(quarterOfRelativeYear(quarter, direction, `K${quarter} ${relativeYearName(direction)}`));
334
+ }
335
+ const standalone = String$1.match(/^(?:het )?(k[1-4]|q[1-4])$/u)(input);
336
+ if (Option.isNone(standalone)) return Option.none();
337
+ const quarter = quarterNumber(textAt(standalone.value, 1));
338
+ return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `K${quarter}`));
339
+ };
340
+ const parseBasePeriod = (input) => {
341
+ if (isIsoDate(input) && input !== "9999-12-31") return Option.some(fixedDatePeriod(input, input));
342
+ const namedDate = parseNamedDate(input);
343
+ if (Option.isSome(namedDate)) return namedDate;
344
+ const quarter = parseQuarter(input);
345
+ if (Option.isSome(quarter)) return quarter;
346
+ const yearMatch = String$1.match(/^(?:het jaar |jaar )?(\d{4})$/u)(input);
347
+ if (Option.isSome(yearMatch)) {
348
+ const year = validYear(textAt(yearMatch.value, 1));
349
+ if (year !== void 0) return Option.some(fixedYearPeriod(year, String(year)));
350
+ }
351
+ const monthYear = String$1.match(/^([a-z]+\.?)(?: van)? (\d{4})$/u)(input);
352
+ if (Option.isSome(monthYear)) {
353
+ const month = monthNumber(textAt(monthYear.value, 1));
354
+ const year = validYear(textAt(monthYear.value, 2));
355
+ if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${title(textAt(months, month - 1))} ${year}`));
356
+ }
357
+ const relativeMonth = String$1.match(/^([a-z]+\.?)(?: van)? (vorig jaar|volgend jaar|dit jaar)$/u)(input);
358
+ const relativeMonthYearFirst = String$1.match(/^(vorig jaar|volgend jaar|dit jaar) ([a-z]+\.?)$/u)(input);
359
+ const relativeMatch = Option.firstSomeOf([relativeMonth, relativeMonthYearFirst]);
360
+ if (Option.isSome(relativeMatch)) {
361
+ const yearFirst = Option.isSome(relativeMonthYearFirst);
362
+ const monthText = textAt(relativeMatch.value, yearFirst ? 2 : 1);
363
+ const yearText = textAt(relativeMatch.value, yearFirst ? 1 : 2);
364
+ const month = monthNumber(monthText);
365
+ const direction = relativeYearDirection(yearText);
366
+ if (month !== void 0) return Option.some(monthOfRelativeYear(month, direction, `${title(textAt(months, month - 1))} ${relativeYearName(direction)}`));
367
+ }
368
+ const standaloneMonth = monthNumber(input);
369
+ if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, title(textAt(months, standaloneMonth - 1))));
370
+ const alias = periodAliases.find((entry) => entry[0] === input);
371
+ if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
372
+ if ([
373
+ "weekend",
374
+ "het weekend",
375
+ "dit weekend"
376
+ ].includes(input)) return Option.some(relativeWeekend(0, "dit weekend"));
377
+ if ([
378
+ "vorig weekend",
379
+ "het vorige weekend",
380
+ "afgelopen weekend"
381
+ ].includes(input)) return Option.some(relativeWeekend(-1, "vorig weekend"));
382
+ if ([
383
+ "volgend weekend",
384
+ "het volgende weekend",
385
+ "komend weekend"
386
+ ].includes(input)) return Option.some(relativeWeekend(1, "volgend weekend"));
387
+ if (input === "het weekend voor het vorige") return Option.some(relativeWeekend(-2, input));
388
+ if (input === "het weekend na het volgende") return Option.some(relativeWeekend(2, input));
389
+ return Option.none();
390
+ };
391
+ const parsePeriod = (input) => {
392
+ const edge = String$1.match(/^(?:het )?(begin|eind|einde)(?: van)? (.+)$/u)(input);
393
+ if (Option.isSome(edge)) {
394
+ const edgeName = textAt(edge.value, 1);
395
+ const period = parseBasePeriod(textAt(edge.value, 2));
396
+ if (Option.isSome(period)) {
397
+ const isEnd = edgeName === "eind" || edgeName === "einde";
398
+ const canonical = `${isEnd ? "eind" : "begin"} van ${period.value.canonical}`;
399
+ return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
400
+ }
401
+ }
402
+ const wrapper = [
403
+ "gedurende ",
404
+ "in ",
405
+ "heel ",
406
+ "de hele ",
407
+ "het hele "
408
+ ].find((prefix) => input.startsWith(prefix));
409
+ return parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
410
+ };
411
+ const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
412
+ const countedUnitPattern = "dag|dagen|week|weken|maand|maanden|kwartaal|kwartalen|jaar|jaren";
413
+ const countedPattern = (source) => new RegExp(source.replace("UNIT", countedUnitPattern), "u");
414
+ const calendarPastPattern = countedPattern("^([1-9]\\d*) (UNIT) geleden$");
415
+ 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)$")];
418
+ const rollingSincePattern = countedPattern("^(?:sinds|gedurende) ([1-9]\\d*) (UNIT)$");
419
+ const rollingBarePattern = countedPattern("^([1-9]\\d*) (UNIT)$");
420
+ const firstPatternMatch = (input, patterns) => Option.firstSomeOf(patterns.map((pattern) => String$1.match(pattern)(input)));
421
+ const parseCalendarOffset = (input) => {
422
+ const past = String$1.match(calendarPastPattern)(input);
423
+ const future = firstPatternMatch(input, calendarFuturePatterns);
424
+ const match = Option.firstSomeOf([past, future]);
425
+ if (Option.isNone(match)) return Option.none();
426
+ const amount = parseTrailingCount(textAt(match.value, 1));
427
+ const unit = countedUnit(textAt(match.value, 2));
428
+ if (Option.isNone(amount) || unit === void 0) return Option.none();
429
+ const entry = units.find((item) => item.unit === unit);
430
+ if (entry === void 0) return Option.none();
431
+ const direction = Option.isSome(past) ? -amount.value : amount.value;
432
+ const noun = amount.value === 1 ? entry.singular : entry.plural;
433
+ const canonical = direction < 0 ? `${amount.value} ${noun} geleden` : `over ${amount.value} ${noun}`;
434
+ return Option.some(candidate(periodRange(relativePeriod(unit, direction, canonical)), canonical));
435
+ };
436
+ const parseRollingPeriod = (input) => {
437
+ const since = String$1.match(rollingSincePattern)(input);
438
+ const past = firstPatternMatch(input, rollingPastPatterns);
439
+ const bare = String$1.match(rollingBarePattern)(input);
440
+ const future = firstPatternMatch(input, rollingFuturePatterns);
441
+ const match = Option.firstSomeOf([
442
+ since,
443
+ past,
444
+ bare,
445
+ future
446
+ ]);
447
+ if (Option.isNone(match)) return Option.none();
448
+ const amount = parseTrailingCount(textAt(match.value, 1));
449
+ const unit = countedUnit(textAt(match.value, 2));
450
+ if (Option.isNone(amount) || unit === void 0) return Option.none();
451
+ const entry = units.find((item) => item.unit === unit);
452
+ if (entry === void 0) return Option.none();
453
+ const isFuture = Option.isSome(future);
454
+ const range = isFuture ? futureRange(amount.value, unit) : trailingRange(amount.value, unit);
455
+ const modifier = isFuture ? "komende" : "afgelopen";
456
+ const noun = amount.value === 1 ? entry.singular : entry.plural;
457
+ return Option.some(candidate(range, `de ${modifier} ${amount.value} ${noun}`));
458
+ };
459
+ const boundaryCandidate = (input) => openBoundaryCandidate(input, [
460
+ ["tot voor ", "before"],
461
+ ["tot het begin van ", "before"],
462
+ ["tot en met ", "through"],
463
+ ["vanaf ", "since"],
464
+ ["sinds ", "since"],
465
+ ["voor ", "before"],
466
+ ["tot ", "through"],
467
+ ["na ", "after"]
468
+ ], parsePeriod);
469
+ const parseDutch = (input) => {
470
+ const remaining = remainingPhrases.find((entry) => entry.phrase === input);
471
+ if (remaining !== void 0) return Option.some(candidate(remainingPeriodRange(remaining.entry.unit), remaining.entry.remaining));
472
+ if ([
473
+ "tot vandaag",
474
+ "tot nu",
475
+ "tot nu toe"
476
+ ].includes(input)) return Option.some(candidate(untilNowRange(), "tot nu toe"));
477
+ if ([
478
+ "vanaf nu",
479
+ "sinds nu",
480
+ "voortaan"
481
+ ].includes(input)) return Option.some(candidate(fromNowRange(), "vanaf nu"));
482
+ const offset = parseCalendarOffset(input);
483
+ if (Option.isSome(offset)) return offset;
484
+ const rolling = parseRollingPeriod(input);
485
+ if (Option.isSome(rolling)) return rolling;
486
+ const toDate = toDatePhrases.find((entry) => entry.phrase === input);
487
+ if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
488
+ const nowBounded = joinedNowCandidate(input, [
489
+ ["vanaf ", " tot nu toe"],
490
+ ["sinds ", " tot nu toe"],
491
+ ["tussen ", " en vandaag"]
492
+ ], [
493
+ "vanaf nu tot en met ",
494
+ "van vandaag tot en met ",
495
+ "tussen vandaag en "
496
+ ], parsePeriod, (period) => `vanaf ${period} tot nu toe`, (period) => `vanaf nu tot en met ${period}`);
497
+ if (Option.isSome(nowBounded)) return nowBounded;
498
+ const bounded = joinedPeriodCandidate(input, [
499
+ ["van ", " tot en met "],
500
+ ["van ", " tot "],
501
+ ["tussen ", " en "],
502
+ ["", " - "],
503
+ ["", " – "],
504
+ ["", " — "],
505
+ ["", " tot en met "],
506
+ ["", " tot "]
507
+ ], parsePeriod, (lower, upper) => `van ${lower} tot en met ${upper}`);
508
+ if (Option.isSome(bounded)) return bounded;
509
+ const boundary = boundaryCandidate(input);
510
+ if (Option.isSome(boundary)) return boundary;
511
+ return Option.map(parsePeriod(input), (period) => candidate(periodRange(period), period.canonical));
512
+ };
513
+ const staticPeriodPhrases = [
514
+ ...periodAliases.map((entry) => entry[0]),
515
+ "dit weekend",
516
+ "vorig weekend",
517
+ "volgend weekend",
518
+ "het weekend voor het vorige",
519
+ "het weekend na het volgende",
520
+ ...periodAliases.flatMap((entry) => [`begin van ${entry[0]}`, `eind van ${entry[0]}`]),
521
+ ...[
522
+ 1,
523
+ 2,
524
+ 3,
525
+ 4
526
+ ].flatMap((quarter) => [
527
+ `k${quarter}`,
528
+ `k${quarter} dit jaar`,
529
+ `k${quarter} vorig jaar`,
530
+ `k${quarter} volgend jaar`
531
+ ]),
532
+ ...months.flatMap((month) => [
533
+ month,
534
+ `${month} vorig jaar`,
535
+ `${month} volgend jaar`
536
+ ])
537
+ ];
538
+ const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
539
+ const boundaryPrefixes = [
540
+ "vanaf ",
541
+ "sinds ",
542
+ "voor ",
543
+ "tot en met ",
544
+ "na "
545
+ ];
546
+ const countedSuggestions = (input) => {
547
+ const amount = naturalCount(input);
548
+ if (amount === void 0) return [];
549
+ return units.flatMap((entry) => {
550
+ const noun = amount === 1 ? entry.singular : entry.plural;
551
+ return [
552
+ `de afgelopen ${amount} ${noun}`,
553
+ `afgelopen ${amount} ${noun}`,
554
+ `de laatste ${amount} ${noun}`,
555
+ `${amount} ${noun}`,
556
+ `de komende ${amount} ${noun}`,
557
+ `komende ${amount} ${noun}`,
558
+ `${amount} ${noun} geleden`,
559
+ `over ${amount} ${noun}`
560
+ ];
561
+ });
562
+ };
563
+ const dutchSuggestionPhrases = [
564
+ ...units.map((entry) => entry.toDate),
565
+ ...units.map((entry) => entry.remaining),
566
+ ...staticPeriodPhrases,
567
+ ...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
568
+ "tot nu toe",
569
+ "vanaf nu"
570
+ ];
571
+ const suggestDutch = (input, limit) => {
572
+ const fixed = fixedCalendarPeriodPhrases(input, months).map((phrase) => phrase.startsWith("q") ? `k${phrase.slice(1)}` : phrase);
573
+ return completeNaturalPhrases(input, [
574
+ ...dutchSuggestionPhrases,
575
+ ...fixed,
576
+ ...prefixNaturalPhrases(fixed, boundaryPrefixes),
577
+ ...countedSuggestions(input)
578
+ ], limit);
579
+ };
580
+ const renderDutch = (range) => {
581
+ const offset = calendarPeriodOffset(range);
582
+ if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
583
+ const entry = units.find((unit) => unit.unit === offset.value.unit);
584
+ if (entry !== void 0) {
585
+ const amount = Math.abs(offset.value.amount);
586
+ const noun = amount === 1 ? entry.singular : entry.plural;
587
+ return Option.some(offset.value.amount < 0 ? `${amount} ${noun} geleden` : `over ${amount} ${noun}`);
588
+ }
589
+ }
590
+ const future = futurePeriod(range);
591
+ if (Option.isSome(future)) {
592
+ 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
+ }
597
+ }
598
+ const trailing = trailingPeriod(range);
599
+ if (Option.isSome(trailing)) {
600
+ 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
+ }
605
+ }
606
+ const periods = [...staticPeriods, ...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range).map((phrase) => phrase.startsWith("Q") ? `K${phrase.slice(1)}` : phrase)], parsePeriod)];
607
+ 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
+ };
609
+ const DutchContribution = new BaseLanguageContribution({
610
+ locale: "nl",
611
+ vocabulary: [
612
+ ...months,
613
+ ...monthAbbreviations.flatMap((aliases) => aliases),
614
+ ...units.flatMap((entry) => [
615
+ entry.singular,
616
+ entry.plural,
617
+ ...entry.current.split(" "),
618
+ ...entry.previous.split(" "),
619
+ ...entry.next.split(" ")
620
+ ]),
621
+ ...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
622
+ ...remainingPhrases.flatMap((entry) => entry.phrase.split(" ")),
623
+ "afgelopen",
624
+ "begin",
625
+ "binnen",
626
+ "eind",
627
+ "geleden",
628
+ "komende",
629
+ "laatste",
630
+ "na",
631
+ "over",
632
+ "rest",
633
+ "sinds",
634
+ "tussen",
635
+ "tot",
636
+ "vanaf",
637
+ "volgend",
638
+ "voor"
639
+ ],
640
+ normalize: normalizeNaturalText,
641
+ correct: correctWhitespaceSeparatedText,
642
+ parseExact: parseDutch,
643
+ suggest: suggestDutch,
644
+ render: renderDutch
645
+ });
646
+ const DutchLanguage = defineLanguagePlugin({
647
+ id: "chronolizer/language-nl",
648
+ effect: (context) => Effect.asVoid(context.register("chronolizer/language-nl", DutchContribution))
649
+ });
650
+ const DutchLanguageLayer = languagePluginsLayer([DutchLanguage]);
651
+ //#endregion
652
+ export { DutchContribution, DutchLanguage, DutchLanguageLayer };
@@ -0,0 +1,10 @@
1
+ import { LanguageConflictError, LanguageRegistrationError } from "../language/errors.mjs";
2
+ import { BaseLanguageContribution, LanguagePlugin } from "../language/model.mjs";
3
+ import { LanguageRegistry } from "../language/registry.mjs";
4
+ import "../index.mjs";
5
+ //#region src/locales/pl.d.ts
6
+ declare const PolishContribution: BaseLanguageContribution;
7
+ declare const PolishLanguage: LanguagePlugin;
8
+ declare const PolishLanguageLayer: import("effect/Layer").Layer<LanguageRegistry, LanguageConflictError | LanguageRegistrationError, never>;
9
+ //#endregion
10
+ export { PolishContribution, PolishLanguage, PolishLanguageLayer };