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,711 @@
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/pl.ts
10
+ const months = [
11
+ "styczeń",
12
+ "luty",
13
+ "marzec",
14
+ "kwiecień",
15
+ "maj",
16
+ "czerwiec",
17
+ "lipiec",
18
+ "sierpień",
19
+ "wrzesień",
20
+ "październik",
21
+ "listopad",
22
+ "grudzień"
23
+ ];
24
+ const monthGenitives = [
25
+ "stycznia",
26
+ "lutego",
27
+ "marca",
28
+ "kwietnia",
29
+ "maja",
30
+ "czerwca",
31
+ "lipca",
32
+ "sierpnia",
33
+ "września",
34
+ "października",
35
+ "listopada",
36
+ "grudnia"
37
+ ];
38
+ const monthInstrumentals = [
39
+ "styczniem",
40
+ "lutym",
41
+ "marcem",
42
+ "kwietniem",
43
+ "majem",
44
+ "czerwcem",
45
+ "lipcem",
46
+ "sierpniem",
47
+ "wrześniem",
48
+ "październikiem",
49
+ "listopadem",
50
+ "grudniem"
51
+ ];
52
+ const monthLocatives = [
53
+ "styczniu",
54
+ "lutym",
55
+ "marcu",
56
+ "kwietniu",
57
+ "maju",
58
+ "czerwcu",
59
+ "lipcu",
60
+ "sierpniu",
61
+ "wrześniu",
62
+ "październiku",
63
+ "listopadzie",
64
+ "grudniu"
65
+ ];
66
+ const monthAbbreviations = [
67
+ ["sty"],
68
+ ["lut"],
69
+ ["mar"],
70
+ ["kwi"],
71
+ ["maj"],
72
+ ["cze"],
73
+ ["lip"],
74
+ ["sie"],
75
+ ["wrz"],
76
+ ["paź", "paz"],
77
+ ["lis"],
78
+ ["gru"]
79
+ ];
80
+ const units = [
81
+ {
82
+ unit: "day",
83
+ singular: "dzień",
84
+ few: "dni",
85
+ many: "dni",
86
+ current: "dzisiaj",
87
+ previous: "wczoraj",
88
+ next: "jutro",
89
+ toDate: "dzisiaj do tej pory",
90
+ remaining: "reszta dnia"
91
+ },
92
+ {
93
+ unit: "week",
94
+ singular: "tydzień",
95
+ few: "tygodnie",
96
+ many: "tygodni",
97
+ current: "ten tydzień",
98
+ previous: "poprzedni tydzień",
99
+ next: "następny tydzień",
100
+ toDate: "tydzień do dziś",
101
+ remaining: "reszta tygodnia"
102
+ },
103
+ {
104
+ unit: "month",
105
+ singular: "miesiąc",
106
+ few: "miesiące",
107
+ many: "miesięcy",
108
+ current: "ten miesiąc",
109
+ previous: "poprzedni miesiąc",
110
+ next: "następny miesiąc",
111
+ toDate: "miesiąc do dziś",
112
+ remaining: "reszta miesiąca"
113
+ },
114
+ {
115
+ unit: "quarter",
116
+ singular: "kwartał",
117
+ few: "kwartały",
118
+ many: "kwartałów",
119
+ current: "ten kwartał",
120
+ previous: "poprzedni kwartał",
121
+ next: "następny kwartał",
122
+ toDate: "kwartał do dziś",
123
+ remaining: "reszta kwartału"
124
+ },
125
+ {
126
+ unit: "year",
127
+ singular: "rok",
128
+ few: "lata",
129
+ many: "lat",
130
+ current: "ten rok",
131
+ previous: "poprzedni rok",
132
+ next: "następny rok",
133
+ toDate: "rok do dziś",
134
+ remaining: "reszta roku"
135
+ }
136
+ ];
137
+ const title = (value) => `${value.slice(0, 1).toLocaleUpperCase("pl")}${value.slice(1)}`;
138
+ const unitAliases = [
139
+ ["dzień", "day"],
140
+ ["dni", "day"],
141
+ ["tydzień", "week"],
142
+ ["tygodnie", "week"],
143
+ ["tygodni", "week"],
144
+ ["miesiąc", "month"],
145
+ ["miesiące", "month"],
146
+ ["miesięcy", "month"],
147
+ ["kwartał", "quarter"],
148
+ ["kwartały", "quarter"],
149
+ ["kwartałów", "quarter"],
150
+ ["rok", "year"],
151
+ ["lata", "year"],
152
+ ["lat", "year"]
153
+ ];
154
+ const periodAliases = [
155
+ ...units.flatMap((entry) => [
156
+ [
157
+ entry.current,
158
+ entry.unit,
159
+ 0,
160
+ entry.current
161
+ ],
162
+ [
163
+ entry.previous,
164
+ entry.unit,
165
+ -1,
166
+ entry.previous
167
+ ],
168
+ [
169
+ entry.next,
170
+ entry.unit,
171
+ 1,
172
+ entry.next
173
+ ]
174
+ ]),
175
+ [
176
+ "zeszły tydzień",
177
+ "week",
178
+ -1,
179
+ "poprzedni tydzień"
180
+ ],
181
+ [
182
+ "przyszły tydzień",
183
+ "week",
184
+ 1,
185
+ "następny tydzień"
186
+ ],
187
+ [
188
+ "zeszły miesiąc",
189
+ "month",
190
+ -1,
191
+ "poprzedni miesiąc"
192
+ ],
193
+ [
194
+ "przyszły miesiąc",
195
+ "month",
196
+ 1,
197
+ "następny miesiąc"
198
+ ],
199
+ [
200
+ "zeszły kwartał",
201
+ "quarter",
202
+ -1,
203
+ "poprzedni kwartał"
204
+ ],
205
+ [
206
+ "przyszły kwartał",
207
+ "quarter",
208
+ 1,
209
+ "następny kwartał"
210
+ ],
211
+ [
212
+ "zeszły rok",
213
+ "year",
214
+ -1,
215
+ "poprzedni rok"
216
+ ],
217
+ [
218
+ "przyszły rok",
219
+ "year",
220
+ 1,
221
+ "następny rok"
222
+ ],
223
+ [
224
+ "tego tygodnia",
225
+ "week",
226
+ 0,
227
+ "ten tydzień"
228
+ ],
229
+ [
230
+ "poprzedniego tygodnia",
231
+ "week",
232
+ -1,
233
+ "poprzedni tydzień"
234
+ ],
235
+ [
236
+ "następnego tygodnia",
237
+ "week",
238
+ 1,
239
+ "następny tydzień"
240
+ ],
241
+ [
242
+ "tego miesiąca",
243
+ "month",
244
+ 0,
245
+ "ten miesiąc"
246
+ ],
247
+ [
248
+ "poprzedniego miesiąca",
249
+ "month",
250
+ -1,
251
+ "poprzedni miesiąc"
252
+ ],
253
+ [
254
+ "następnego miesiąca",
255
+ "month",
256
+ 1,
257
+ "następny miesiąc"
258
+ ],
259
+ [
260
+ "tego kwartału",
261
+ "quarter",
262
+ 0,
263
+ "ten kwartał"
264
+ ],
265
+ [
266
+ "poprzedniego kwartału",
267
+ "quarter",
268
+ -1,
269
+ "poprzedni kwartał"
270
+ ],
271
+ [
272
+ "następnego kwartału",
273
+ "quarter",
274
+ 1,
275
+ "następny kwartał"
276
+ ],
277
+ [
278
+ "tego roku",
279
+ "year",
280
+ 0,
281
+ "ten rok"
282
+ ],
283
+ [
284
+ "poprzedniego roku",
285
+ "year",
286
+ -1,
287
+ "poprzedni rok"
288
+ ],
289
+ [
290
+ "następnego roku",
291
+ "year",
292
+ 1,
293
+ "następny rok"
294
+ ],
295
+ [
296
+ "przedwczoraj",
297
+ "day",
298
+ -2,
299
+ "przedwczoraj"
300
+ ],
301
+ [
302
+ "pojutrze",
303
+ "day",
304
+ 2,
305
+ "pojutrze"
306
+ ],
307
+ [
308
+ "przedostatni tydzień",
309
+ "week",
310
+ -2,
311
+ "przedostatni tydzień"
312
+ ],
313
+ [
314
+ "tydzień po następnym",
315
+ "week",
316
+ 2,
317
+ "tydzień po następnym"
318
+ ],
319
+ [
320
+ "przedostatni miesiąc",
321
+ "month",
322
+ -2,
323
+ "przedostatni miesiąc"
324
+ ],
325
+ [
326
+ "miesiąc po następnym",
327
+ "month",
328
+ 2,
329
+ "miesiąc po następnym"
330
+ ],
331
+ [
332
+ "przedostatni rok",
333
+ "year",
334
+ -2,
335
+ "przedostatni rok"
336
+ ],
337
+ [
338
+ "rok po następnym",
339
+ "year",
340
+ 2,
341
+ "rok po następnym"
342
+ ]
343
+ ];
344
+ const toDatePhrases = units.flatMap((entry) => {
345
+ const yearAliases = entry.unit === "year" ? [
346
+ "od początku roku",
347
+ "od początku roku do dziś",
348
+ "w tym roku do dziś"
349
+ ] : [];
350
+ return [entry.toDate, ...yearAliases].map((phrase) => ({
351
+ entry,
352
+ phrase
353
+ }));
354
+ });
355
+ const remainingPhrases = units.map((entry) => ({
356
+ entry,
357
+ phrase: entry.remaining
358
+ }));
359
+ const relativeYearDirection = (value) => {
360
+ if (value.includes("poprzed")) return -1;
361
+ if (value.includes("następn")) return 1;
362
+ return 0;
363
+ };
364
+ const relativeYearName = (direction) => {
365
+ if (direction < 0) return "poprzedniego roku";
366
+ if (direction > 0) return "następnego roku";
367
+ return "tego roku";
368
+ };
369
+ const monthNumber = (value) => {
370
+ const normalized = value.endsWith(".") ? value.slice(0, -1) : value;
371
+ const full = months.findIndex((month, index) => month === normalized || textAt(monthGenitives, index) === normalized || textAt(monthInstrumentals, index) === normalized || textAt(monthLocatives, index) === normalized);
372
+ if (full !== -1) return full + 1;
373
+ const short = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
374
+ return short === -1 ? void 0 : short + 1;
375
+ };
376
+ const dateLabel = (day, month, year) => `${day}. ${textAt(monthGenitives, month - 1)} ${year}`;
377
+ const withMonthCase = (value, forms) => {
378
+ const month = months.findIndex((name) => value.startsWith(title(name)) || value.startsWith(name));
379
+ if (month === -1) return value;
380
+ const name = textAt(months, month);
381
+ return `${textAt(forms, month)}${value.slice(name.length)}`;
382
+ };
383
+ const parseNamedDate = (input) => {
384
+ const named = String$1.match(/^([0-3]?\d)\.?(?: )([a-ząćęłńóśźż]+\.?) (\d{4})$/u)(input);
385
+ if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, dateLabel);
386
+ const numeric = String$1.match(/^([0-3]?\d)(?:\. ?|[/-])([01]?\d)(?:\. ?|[/-])(\d{4})$/u)(input);
387
+ if (Option.isNone(numeric)) return Option.none();
388
+ const year = validYear(textAt(numeric.value, 3));
389
+ const month = Number(textAt(numeric.value, 2));
390
+ const day = Number(textAt(numeric.value, 1));
391
+ if (year === void 0 || month < 1 || month > 12) return Option.none();
392
+ const value = isoDate(year, month, day);
393
+ return isIsoDate(value) && value !== "9999-12-31" ? Option.some(fixedDatePeriod(value, dateLabel(day, month, year))) : Option.none();
394
+ };
395
+ const quarterNumber = (value) => {
396
+ if (value.startsWith("q") && value.length === 2) return Number(value.slice(1));
397
+ if (value === "1." || value === "pierwszy") return 1;
398
+ if (value === "2." || value === "drugi") return 2;
399
+ if (value === "3." || value === "trzeci") return 3;
400
+ return value === "4." || value === "czwarty" ? 4 : void 0;
401
+ };
402
+ const parseQuarter = (input) => {
403
+ const fixed = String$1.match(/^(q[1-4]|1\.|pierwszy|2\.|drugi|3\.|trzeci|4\.|czwarty)(?: kwartał)? (\d{4})$/u)(input);
404
+ if (Option.isSome(fixed)) {
405
+ const quarter = quarterNumber(textAt(fixed.value, 1));
406
+ const year = validYear(textAt(fixed.value, 2));
407
+ if (quarter !== void 0 && year !== void 0) return Option.some(fixedQuarterPeriod(year, quarter, `Q${quarter} ${year}`));
408
+ }
409
+ const relative = String$1.match(/^(q[1-4]) (poprzedniego roku|następnego roku|tego roku)$/u)(input);
410
+ if (Option.isSome(relative)) {
411
+ const quarter = quarterNumber(textAt(relative.value, 1));
412
+ const direction = relativeYearDirection(textAt(relative.value, 2));
413
+ if (quarter !== void 0) return Option.some(quarterOfRelativeYear(quarter, direction, `Q${quarter} ${relativeYearName(direction)}`));
414
+ }
415
+ const standalone = String$1.match(/^(q[1-4])$/u)(input);
416
+ if (Option.isNone(standalone)) return Option.none();
417
+ const quarter = quarterNumber(textAt(standalone.value, 1));
418
+ return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `Q${quarter}`));
419
+ };
420
+ const parseBasePeriod = (input) => {
421
+ if (isIsoDate(input) && input !== "9999-12-31") return Option.some(fixedDatePeriod(input, input));
422
+ const namedDate = parseNamedDate(input);
423
+ if (Option.isSome(namedDate)) return namedDate;
424
+ const quarter = parseQuarter(input);
425
+ if (Option.isSome(quarter)) return quarter;
426
+ const yearMatch = String$1.match(/^(?:rok |roku )?(\d{4})$/u)(input);
427
+ if (Option.isSome(yearMatch)) {
428
+ const year = validYear(textAt(yearMatch.value, 1));
429
+ if (year !== void 0) return Option.some(fixedYearPeriod(year, String(year)));
430
+ }
431
+ const monthYear = String$1.match(/^([a-ząćęłńóśźż]+\.?) (\d{4})$/u)(input);
432
+ if (Option.isSome(monthYear)) {
433
+ const month = monthNumber(textAt(monthYear.value, 1));
434
+ const year = validYear(textAt(monthYear.value, 2));
435
+ if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${title(textAt(months, month - 1))} ${year}`));
436
+ }
437
+ const relativeMonth = String$1.match(/^([a-ząćęłńóśźż]+\.?) (poprzedniego roku|następnego roku|tego roku)$/u)(input);
438
+ const relativeMonthYearFirst = String$1.match(/^(poprzedniego roku|następnego roku|tego roku) ([a-ząćęłńóśźż]+\.?)$/u)(input);
439
+ const relativeMatch = Option.firstSomeOf([relativeMonth, relativeMonthYearFirst]);
440
+ if (Option.isSome(relativeMatch)) {
441
+ const yearFirst = Option.isSome(relativeMonthYearFirst);
442
+ const monthText = textAt(relativeMatch.value, yearFirst ? 2 : 1);
443
+ const yearText = textAt(relativeMatch.value, yearFirst ? 1 : 2);
444
+ const month = monthNumber(monthText);
445
+ const direction = relativeYearDirection(yearText);
446
+ if (month !== void 0) return Option.some(monthOfRelativeYear(month, direction, `${title(textAt(months, month - 1))} ${relativeYearName(direction)}`));
447
+ }
448
+ const standaloneMonth = monthNumber(input);
449
+ if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, title(textAt(months, standaloneMonth - 1))));
450
+ const alias = periodAliases.find((entry) => entry[0] === input);
451
+ if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
452
+ if (["weekend", "ten weekend"].includes(input)) return Option.some(relativeWeekend(0, "ten weekend"));
453
+ if (["poprzedni weekend", "zeszły weekend"].includes(input)) return Option.some(relativeWeekend(-1, "poprzedni weekend"));
454
+ if (["następny weekend", "przyszły weekend"].includes(input)) return Option.some(relativeWeekend(1, "następny weekend"));
455
+ if (input === "weekend przed poprzednim") return Option.some(relativeWeekend(-2, input));
456
+ if (input === "weekend po następnym") return Option.some(relativeWeekend(2, input));
457
+ return Option.none();
458
+ };
459
+ const parsePeriod = (input) => {
460
+ const edge = String$1.match(/^(początek|koniec) (.+)$/u)(input);
461
+ if (Option.isSome(edge)) {
462
+ const period = parseBasePeriod(textAt(edge.value, 2));
463
+ if (Option.isSome(period)) {
464
+ const isEnd = textAt(edge.value, 1) === "koniec";
465
+ const canonical = `${isEnd ? "koniec" : "początek"} ${period.value.canonical}`;
466
+ return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
467
+ }
468
+ }
469
+ const wrapper = [
470
+ "w ",
471
+ "przez ",
472
+ "cały ",
473
+ "całe "
474
+ ].find((prefix) => input.startsWith(prefix));
475
+ return parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
476
+ };
477
+ const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
478
+ const countedUnitPattern = "dzień|dni|tydzień|tygodnie|tygodni|miesiąc|miesiące|miesięcy|kwartał|kwartały|kwartałów|rok|lata|lat";
479
+ const countedPattern = (source) => new RegExp(source.replace("UNIT", countedUnitPattern), "u");
480
+ const calendarPastPattern = countedPattern("^([1-9]\\d*) (UNIT) temu$");
481
+ const calendarFuturePattern = countedPattern("^za ([1-9]\\d*) (UNIT)$");
482
+ const rollingPastPatterns = [countedPattern("^(?:ostatni|ostatnie|ostatnich|miniony|minione|minionych) ([1-9]\\d*) (UNIT)$")];
483
+ const rollingFuturePatterns = [countedPattern("^(?:następny|następne|następnych|kolejny|kolejne|kolejnych) ([1-9]\\d*) (UNIT)$")];
484
+ const rollingBarePattern = countedPattern("^([1-9]\\d*) (UNIT)$");
485
+ const firstPatternMatch = (input, patterns) => Option.firstSomeOf(patterns.map((pattern) => String$1.match(pattern)(input)));
486
+ const countNoun = (amount, entry) => {
487
+ if (amount === 1) return entry.singular;
488
+ const lastTwo = amount % 100;
489
+ const last = amount % 10;
490
+ return last >= 2 && last <= 4 && (lastTwo < 12 || lastTwo > 14) ? entry.few : entry.many;
491
+ };
492
+ const parseCalendarOffset = (input) => {
493
+ const past = String$1.match(calendarPastPattern)(input);
494
+ const future = String$1.match(calendarFuturePattern)(input);
495
+ const match = Option.firstSomeOf([past, future]);
496
+ if (Option.isNone(match)) return Option.none();
497
+ const amount = parseTrailingCount(textAt(match.value, 1));
498
+ const unit = countedUnit(textAt(match.value, 2));
499
+ if (Option.isNone(amount) || unit === void 0) return Option.none();
500
+ const entry = units.find((item) => item.unit === unit);
501
+ if (entry === void 0) return Option.none();
502
+ const direction = Option.isSome(past) ? -amount.value : amount.value;
503
+ const noun = countNoun(amount.value, entry);
504
+ const canonical = direction < 0 ? `${amount.value} ${noun} temu` : `za ${amount.value} ${noun}`;
505
+ return Option.some(candidate(periodRange(relativePeriod(unit, direction, canonical)), canonical));
506
+ };
507
+ const rollingModifier = (amount, future) => {
508
+ if (amount === 1) return future ? "następny" : "ostatni";
509
+ const lastTwo = amount % 100;
510
+ const last = amount % 10;
511
+ if (last >= 2 && last <= 4 && (lastTwo < 12 || lastTwo > 14)) return future ? "następne" : "ostatnie";
512
+ return future ? "następnych" : "ostatnich";
513
+ };
514
+ const parseRollingPeriod = (input) => {
515
+ const past = firstPatternMatch(input, rollingPastPatterns);
516
+ const bare = String$1.match(rollingBarePattern)(input);
517
+ const future = firstPatternMatch(input, rollingFuturePatterns);
518
+ const match = Option.firstSomeOf([
519
+ past,
520
+ bare,
521
+ future
522
+ ]);
523
+ if (Option.isNone(match)) return Option.none();
524
+ const amount = parseTrailingCount(textAt(match.value, 1));
525
+ const unit = countedUnit(textAt(match.value, 2));
526
+ if (Option.isNone(amount) || unit === void 0) return Option.none();
527
+ const entry = units.find((item) => item.unit === unit);
528
+ if (entry === void 0) return Option.none();
529
+ const isFuture = Option.isSome(future);
530
+ const range = isFuture ? futureRange(amount.value, unit) : trailingRange(amount.value, unit);
531
+ const modifier = rollingModifier(amount.value, isFuture);
532
+ return Option.some(candidate(range, `${modifier} ${amount.value} ${countNoun(amount.value, entry)}`));
533
+ };
534
+ const boundaryCandidate = (input) => {
535
+ const included = String$1.match(/^do (.+) włącznie$/u)(input);
536
+ if (Option.isSome(included)) return openBoundaryCandidate(`do ${textAt(included.value, 1)}`, [["do ", "through"]], parsePeriod);
537
+ return openBoundaryCandidate(input, [
538
+ ["do początku ", "before"],
539
+ ["począwszy od ", "since"],
540
+ ["od ", "since"],
541
+ ["przed ", "before"],
542
+ ["do ", "through"],
543
+ ["po ", "after"]
544
+ ], parsePeriod);
545
+ };
546
+ const parsePolish = (input) => {
547
+ const remaining = remainingPhrases.find((entry) => entry.phrase === input);
548
+ if (remaining !== void 0) return Option.some(candidate(remainingPeriodRange(remaining.entry.unit), remaining.entry.remaining));
549
+ if ([
550
+ "do dziś",
551
+ "dotychczas",
552
+ "do teraz"
553
+ ].includes(input)) return Option.some(candidate(untilNowRange(), "do dziś"));
554
+ if (["od teraz", "od dziś"].includes(input)) return Option.some(candidate(fromNowRange(), "od teraz"));
555
+ const offset = parseCalendarOffset(input);
556
+ if (Option.isSome(offset)) return offset;
557
+ const rolling = parseRollingPeriod(input);
558
+ if (Option.isSome(rolling)) return rolling;
559
+ const toDate = toDatePhrases.find((entry) => entry.phrase === input);
560
+ if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
561
+ const nowBounded = joinedNowCandidate(input, [["od ", " do dziś"], ["między ", " a dziś"]], ["od dziś do ", "między dziś a "], parsePeriod, (period) => `od ${period} do dziś`, (period) => `od dziś do ${period}`);
562
+ if (Option.isSome(nowBounded)) return nowBounded;
563
+ const bounded = joinedPeriodCandidate(input, [
564
+ ["od ", " do "],
565
+ ["między ", " a "],
566
+ ["", " - "],
567
+ ["", " – "],
568
+ ["", " — "]
569
+ ], parsePeriod, (lower, upper) => `od ${lower} do ${upper} włącznie`);
570
+ if (Option.isSome(bounded)) return bounded;
571
+ const boundary = boundaryCandidate(input);
572
+ if (Option.isSome(boundary)) return boundary;
573
+ return Option.map(parsePeriod(input), (period) => candidate(periodRange(period), period.canonical));
574
+ };
575
+ const staticPeriodPhrases = [
576
+ ...periodAliases.map((entry) => entry[0]),
577
+ "ten weekend",
578
+ "poprzedni weekend",
579
+ "następny weekend",
580
+ "weekend przed poprzednim",
581
+ "weekend po następnym",
582
+ ...periodAliases.flatMap((entry) => [`początek ${entry[0]}`, `koniec ${entry[0]}`]),
583
+ ...[
584
+ 1,
585
+ 2,
586
+ 3,
587
+ 4
588
+ ].flatMap((quarter) => [
589
+ `q${quarter}`,
590
+ `q${quarter} tego roku`,
591
+ `q${quarter} poprzedniego roku`,
592
+ `q${quarter} następnego roku`
593
+ ]),
594
+ ...months.flatMap((month) => [
595
+ month,
596
+ `${month} poprzedniego roku`,
597
+ `${month} następnego roku`
598
+ ])
599
+ ];
600
+ const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
601
+ const boundaryPrefixes = [
602
+ "od ",
603
+ "począwszy od ",
604
+ "przed ",
605
+ "do ",
606
+ "po "
607
+ ];
608
+ const countedSuggestions = (input) => {
609
+ const amount = naturalCount(input);
610
+ if (amount === void 0) return [];
611
+ return units.flatMap((entry) => {
612
+ const noun = countNoun(amount, entry);
613
+ return [
614
+ `${rollingModifier(amount, false)} ${amount} ${noun}`,
615
+ `${amount} ${noun}`,
616
+ `${rollingModifier(amount, true)} ${amount} ${noun}`,
617
+ `${amount} ${noun} temu`,
618
+ `za ${amount} ${noun}`
619
+ ];
620
+ });
621
+ };
622
+ const polishSuggestionPhrases = [
623
+ ...units.map((entry) => entry.toDate),
624
+ ...units.map((entry) => entry.remaining),
625
+ ...staticPeriodPhrases,
626
+ ...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
627
+ "do dziś",
628
+ "od teraz"
629
+ ];
630
+ const suggestPolish = (input, limit) => {
631
+ const fixed = fixedCalendarPeriodPhrases(input, months);
632
+ return completeNaturalPhrases(input, [
633
+ ...polishSuggestionPhrases,
634
+ ...fixed,
635
+ ...prefixNaturalPhrases(fixed, boundaryPrefixes),
636
+ ...countedSuggestions(input)
637
+ ], limit);
638
+ };
639
+ const renderPolish = (range) => {
640
+ const offset = calendarPeriodOffset(range);
641
+ if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
642
+ const entry = units.find((unit) => unit.unit === offset.value.unit);
643
+ if (entry !== void 0) {
644
+ const amount = Math.abs(offset.value.amount);
645
+ const noun = countNoun(amount, entry);
646
+ return Option.some(offset.value.amount < 0 ? `${amount} ${noun} temu` : `za ${amount} ${noun}`);
647
+ }
648
+ }
649
+ const future = futurePeriod(range);
650
+ if (Option.isSome(future)) {
651
+ const entry = units.find((unit) => unit.unit === future.value.unit);
652
+ if (entry !== void 0) return Option.some(`${rollingModifier(future.value.amount, true)} ${future.value.amount} ${countNoun(future.value.amount, entry)}`);
653
+ }
654
+ const trailing = trailingPeriod(range);
655
+ if (Option.isSome(trailing)) {
656
+ const entry = units.find((unit) => unit.unit === trailing.value.unit);
657
+ if (entry !== void 0) return Option.some(`${rollingModifier(trailing.value.amount, false)} ${trailing.value.amount} ${countNoun(trailing.value.amount, entry)}`);
658
+ }
659
+ const periods = [...staticPeriods, ...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)];
660
+ return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `od ${withMonthCase(period, monthGenitives)}`, (period) => `przed ${withMonthCase(period, monthInstrumentals)}`, (period) => `do ${withMonthCase(period, monthGenitives)} włącznie`, (period) => `po ${withMonthCase(period, monthLocatives)}`, (lower, upper) => `od ${withMonthCase(lower, monthGenitives)} do ${withMonthCase(upper, monthGenitives)} włącznie`, (period) => `od ${withMonthCase(period, monthGenitives)} do dziś`, (period) => `od dziś do ${withMonthCase(period, monthGenitives)}`, () => "do dziś", () => "od teraz");
661
+ };
662
+ const PolishContribution = new BaseLanguageContribution({
663
+ locale: "pl",
664
+ vocabulary: [
665
+ ...months,
666
+ ...monthGenitives,
667
+ ...monthInstrumentals,
668
+ ...monthLocatives,
669
+ ...monthAbbreviations.flatMap((aliases) => aliases),
670
+ ...units.flatMap((entry) => [
671
+ entry.singular,
672
+ entry.few,
673
+ entry.many,
674
+ ...entry.current.split(" "),
675
+ ...entry.previous.split(" "),
676
+ ...entry.next.split(" ")
677
+ ]),
678
+ ...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
679
+ ...remainingPhrases.flatMap((entry) => entry.phrase.split(" ")),
680
+ "dziś",
681
+ "dotychczas",
682
+ "koniec",
683
+ "kolejne",
684
+ "między",
685
+ "minione",
686
+ "następne",
687
+ "od",
688
+ "ostatnie",
689
+ "po",
690
+ "początek",
691
+ "począwszy",
692
+ "poprzedni",
693
+ "przed",
694
+ "teraz",
695
+ "temu",
696
+ "włącznie",
697
+ "za"
698
+ ],
699
+ normalize: normalizeNaturalText,
700
+ correct: correctWhitespaceSeparatedText,
701
+ parseExact: parsePolish,
702
+ suggest: suggestPolish,
703
+ render: renderPolish
704
+ });
705
+ const PolishLanguage = defineLanguagePlugin({
706
+ id: "chronolizer/language-pl",
707
+ effect: (context) => Effect.asVoid(context.register("chronolizer/language-pl", PolishContribution))
708
+ });
709
+ const PolishLanguageLayer = languagePluginsLayer([PolishLanguage]);
710
+ //#endregion
711
+ export { PolishContribution, PolishLanguage, PolishLanguageLayer };