chronolizer 0.1.0 → 0.3.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 +184 -119
  2. package/dist/ast/constructors.d.mts +135 -0
  3. package/dist/ast/constructors.mjs +25 -0
  4. package/dist/ast/fold.d.mts +13 -0
  5. package/dist/ast/fold.mjs +58 -0
  6. package/dist/ast/normalize.d.mts +42 -0
  7. package/dist/ast/normalize.mjs +34 -0
  8. package/dist/ast/schemas.d.mts +80 -0
  9. package/dist/ast/schemas.mjs +65 -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 +76 -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 +50 -0
  26. package/dist/language/registry.d.mts +17 -0
  27. package/dist/language/registry.mjs +116 -0
  28. package/dist/locales/cs.d.mts +10 -0
  29. package/dist/locales/cs.mjs +746 -0
  30. package/dist/locales/de.d.mts +10 -0
  31. package/dist/locales/de.mjs +1039 -0
  32. package/dist/locales/en.d.mts +10 -0
  33. package/dist/locales/en.mjs +598 -0
  34. package/dist/locales/es.d.mts +10 -0
  35. package/dist/locales/es.mjs +908 -0
  36. package/dist/locales/fr.d.mts +10 -0
  37. package/dist/locales/fr.mjs +901 -0
  38. package/dist/locales/nl.d.mts +10 -0
  39. package/dist/locales/nl.mjs +791 -0
  40. package/dist/locales/pl.d.mts +10 -0
  41. package/dist/locales/pl.mjs +885 -0
  42. package/dist/locales/shared.mjs +395 -0
  43. package/dist/locales/tr.d.mts +10 -0
  44. package/dist/locales/tr.mjs +725 -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 +58 -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,885 @@
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 } from "../natural/suggestion.mjs";
7
+ import { absoluteDatePeriod, calendarPeriodOffset, candidate, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, parseTrailingCount, periodBoundaryCandidate, 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: "od początku dnia",
90
+ remaining: "do końca tego 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: "od początku tygodnia",
101
+ remaining: "do końca tego 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: "od początku miesiąca",
112
+ remaining: "do końca tego 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: "od początku kwartału",
123
+ remaining: "do końca tego 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: "od początku roku",
134
+ remaining: "do końca tego 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 declinedUnits = [
155
+ [
156
+ "week",
157
+ "tydzień",
158
+ "tygodnia",
159
+ "tygodniem",
160
+ "tygodniu"
161
+ ],
162
+ [
163
+ "month",
164
+ "miesiąc",
165
+ "miesiąca",
166
+ "miesiącem",
167
+ "miesiącu"
168
+ ],
169
+ [
170
+ "quarter",
171
+ "kwartał",
172
+ "kwartału",
173
+ "kwartałem",
174
+ "kwartale"
175
+ ],
176
+ [
177
+ "year",
178
+ "rok",
179
+ "roku",
180
+ "rokiem",
181
+ "roku"
182
+ ]
183
+ ];
184
+ const relativeAdjectives = [
185
+ [
186
+ 0,
187
+ "ten",
188
+ "tego",
189
+ "tym"
190
+ ],
191
+ [
192
+ -1,
193
+ "poprzedni",
194
+ "poprzedniego",
195
+ "poprzednim"
196
+ ],
197
+ [
198
+ 1,
199
+ "następny",
200
+ "następnego",
201
+ "następnym"
202
+ ]
203
+ ];
204
+ const declinedPeriods = declinedUnits.flatMap(([unit, nominativeNoun, genitiveNoun, instrumentalNoun, locativeNoun]) => relativeAdjectives.map(([direction, nominative, genitive, oblique]) => [
205
+ `${nominative} ${nominativeNoun}`,
206
+ unit,
207
+ direction,
208
+ `${genitive} ${genitiveNoun}`,
209
+ `${oblique} ${instrumentalNoun}`,
210
+ `${oblique} ${locativeNoun}`
211
+ ]));
212
+ const periodAliases = [
213
+ ...units.flatMap((entry) => [
214
+ [
215
+ entry.current,
216
+ entry.unit,
217
+ 0,
218
+ entry.current
219
+ ],
220
+ [
221
+ entry.previous,
222
+ entry.unit,
223
+ -1,
224
+ entry.previous
225
+ ],
226
+ [
227
+ entry.next,
228
+ entry.unit,
229
+ 1,
230
+ entry.next
231
+ ]
232
+ ]),
233
+ [
234
+ "zeszły tydzień",
235
+ "week",
236
+ -1,
237
+ "poprzedni tydzień"
238
+ ],
239
+ [
240
+ "przyszły tydzień",
241
+ "week",
242
+ 1,
243
+ "następny tydzień"
244
+ ],
245
+ [
246
+ "zeszły miesiąc",
247
+ "month",
248
+ -1,
249
+ "poprzedni miesiąc"
250
+ ],
251
+ [
252
+ "przyszły miesiąc",
253
+ "month",
254
+ 1,
255
+ "następny miesiąc"
256
+ ],
257
+ [
258
+ "zeszły kwartał",
259
+ "quarter",
260
+ -1,
261
+ "poprzedni kwartał"
262
+ ],
263
+ [
264
+ "przyszły kwartał",
265
+ "quarter",
266
+ 1,
267
+ "następny kwartał"
268
+ ],
269
+ [
270
+ "zeszły rok",
271
+ "year",
272
+ -1,
273
+ "poprzedni rok"
274
+ ],
275
+ [
276
+ "przyszły rok",
277
+ "year",
278
+ 1,
279
+ "następny rok"
280
+ ],
281
+ ...declinedPeriods.flatMap(([canonical, unit, direction, genitive, instrumental, locative]) => [
282
+ [
283
+ genitive,
284
+ unit,
285
+ direction,
286
+ canonical
287
+ ],
288
+ [
289
+ instrumental,
290
+ unit,
291
+ direction,
292
+ canonical
293
+ ],
294
+ [
295
+ locative,
296
+ unit,
297
+ direction,
298
+ canonical
299
+ ]
300
+ ]),
301
+ [
302
+ "zeszłym tygodniu",
303
+ "week",
304
+ -1,
305
+ "poprzedni tydzień"
306
+ ],
307
+ [
308
+ "zeszłym miesiącu",
309
+ "month",
310
+ -1,
311
+ "poprzedni miesiąc"
312
+ ],
313
+ [
314
+ "zeszłym kwartale",
315
+ "quarter",
316
+ -1,
317
+ "poprzedni kwartał"
318
+ ],
319
+ [
320
+ "zeszłym roku",
321
+ "year",
322
+ -1,
323
+ "poprzedni rok"
324
+ ],
325
+ [
326
+ "dziś",
327
+ "day",
328
+ 0,
329
+ "dzisiaj"
330
+ ],
331
+ [
332
+ "przedwczoraj",
333
+ "day",
334
+ -2,
335
+ "przedwczoraj"
336
+ ],
337
+ [
338
+ "pojutrze",
339
+ "day",
340
+ 2,
341
+ "pojutrze"
342
+ ],
343
+ [
344
+ "przedostatni tydzień",
345
+ "week",
346
+ -2,
347
+ "przedostatni tydzień"
348
+ ],
349
+ [
350
+ "tydzień po następnym",
351
+ "week",
352
+ 2,
353
+ "tydzień po następnym"
354
+ ],
355
+ [
356
+ "przedostatni miesiąc",
357
+ "month",
358
+ -2,
359
+ "przedostatni miesiąc"
360
+ ],
361
+ [
362
+ "miesiąc po następnym",
363
+ "month",
364
+ 2,
365
+ "miesiąc po następnym"
366
+ ],
367
+ [
368
+ "przedostatni rok",
369
+ "year",
370
+ -2,
371
+ "przedostatni rok"
372
+ ],
373
+ [
374
+ "rok po następnym",
375
+ "year",
376
+ 2,
377
+ "rok po następnym"
378
+ ]
379
+ ];
380
+ const legacyToDatePhrases = [
381
+ "dzisiaj do tej pory",
382
+ "tydzień do dziś",
383
+ "miesiąc do dziś",
384
+ "kwartał do dziś",
385
+ "rok do dziś"
386
+ ];
387
+ const toDatePhrases = units.flatMap((entry, index) => {
388
+ const aliases = [entry.toDate, textAt(legacyToDatePhrases, index)];
389
+ if (entry.unit === "year") aliases.push("od początku roku do dziś", "w tym roku do dziś");
390
+ return aliases.map((phrase) => ({
391
+ entry,
392
+ phrase
393
+ }));
394
+ });
395
+ const remainingPhrases = units.flatMap((entry) => {
396
+ const implicit = entry.remaining.replace("tego ", "");
397
+ const legacy = entry.remaining.replace("do końca tego", "reszta");
398
+ return [
399
+ entry.remaining,
400
+ implicit,
401
+ legacy
402
+ ].map((phrase) => ({
403
+ entry,
404
+ phrase
405
+ }));
406
+ });
407
+ const relativeYearDirection = (value) => {
408
+ if (value.includes("poprzed")) return -1;
409
+ if (value.includes("następn")) return 1;
410
+ return 0;
411
+ };
412
+ const relativeYearName = (direction) => {
413
+ if (direction < 0) return "poprzedniego roku";
414
+ if (direction > 0) return "następnego roku";
415
+ return "tego roku";
416
+ };
417
+ const monthNumber = (value) => {
418
+ const normalized = value.endsWith(".") ? value.slice(0, -1) : value;
419
+ const full = months.findIndex((month, index) => month === normalized || textAt(monthGenitives, index) === normalized || textAt(monthInstrumentals, index) === normalized || textAt(monthLocatives, index) === normalized);
420
+ if (full !== -1) return full + 1;
421
+ const short = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
422
+ return short === -1 ? void 0 : short + 1;
423
+ };
424
+ const dateLabel = (day, month, year) => `${day}. ${textAt(monthGenitives, month - 1)} ${year}`;
425
+ const currentDateLabel = (day, month) => `${day}. ${textAt(monthGenitives, month - 1)}`;
426
+ const withMonthCase = (value, forms) => {
427
+ const month = months.findIndex((name) => value.startsWith(title(name)) || value.startsWith(name));
428
+ if (month === -1) return value;
429
+ const name = textAt(months, month);
430
+ return `${textAt(forms, month)}${value.slice(name.length)}`;
431
+ };
432
+ const periodCaseIndexes = {
433
+ genitive: 3,
434
+ instrumental: 4,
435
+ locative: 5
436
+ };
437
+ const monthCases = {
438
+ genitive: monthGenitives,
439
+ instrumental: monthInstrumentals,
440
+ locative: monthLocatives
441
+ };
442
+ const withPeriodCase = (value, grammaticalCase) => {
443
+ const period = declinedPeriods.find((entry) => entry[0] === value);
444
+ return period === void 0 ? withMonthCase(value, monthCases[grammaticalCase]) : period[periodCaseIndexes[grammaticalCase]];
445
+ };
446
+ const parseNamedDate = (input) => {
447
+ const named = String$1.match(/^([0-3]?\d)\.?(?: )([a-ząćęłńóśźż]+\.?) (\d{4})$/u)(input);
448
+ if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, dateLabel);
449
+ const numeric = String$1.match(/^([0-3]?\d)(?:\. ?|[/-])([01]?\d)(?:\. ?|[/-])(\d{4})$/u)(input);
450
+ if (Option.isSome(numeric)) {
451
+ const year = validYear(textAt(numeric.value, 3));
452
+ const month = Number(textAt(numeric.value, 2));
453
+ const day = Number(textAt(numeric.value, 1));
454
+ if (year !== void 0 && month >= 1 && month <= 12) {
455
+ const value = isoDate(year, month, day);
456
+ if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, dateLabel(day, month, year)));
457
+ }
458
+ }
459
+ const current = String$1.match(/^([0-3]?\d)\.? ([a-ząćęłńóśźż]+\.?)$/u)(input);
460
+ return Option.isSome(current) ? namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel) : Option.none();
461
+ };
462
+ const quarterNumber = (value) => {
463
+ if (value.startsWith("q") && value.length === 2) return Number(value.slice(1));
464
+ if (value === "1." || value === "pierwszy") return 1;
465
+ if (value === "2." || value === "drugi") return 2;
466
+ if (value === "3." || value === "trzeci") return 3;
467
+ return value === "4." || value === "czwarty" ? 4 : void 0;
468
+ };
469
+ const parseQuarter = (input) => {
470
+ const fixed = String$1.match(/^(q[1-4]|1\.|pierwszy|2\.|drugi|3\.|trzeci|4\.|czwarty)(?: kwartał)? (\d{4})$/u)(input);
471
+ if (Option.isSome(fixed)) {
472
+ const quarter = quarterNumber(textAt(fixed.value, 1));
473
+ const year = validYear(textAt(fixed.value, 2));
474
+ if (quarter !== void 0 && year !== void 0) return Option.some(fixedQuarterPeriod(year, quarter, `Q${quarter} ${year}`));
475
+ }
476
+ const relative = String$1.match(/^(q[1-4]) (poprzedniego roku|następnego roku|tego roku)$/u)(input);
477
+ if (Option.isSome(relative)) {
478
+ const quarter = quarterNumber(textAt(relative.value, 1));
479
+ const direction = relativeYearDirection(textAt(relative.value, 2));
480
+ if (quarter !== void 0) return Option.some(quarterOfRelativeYear(quarter, direction, `Q${quarter} ${relativeYearName(direction)}`));
481
+ }
482
+ const standalone = String$1.match(/^(q[1-4])$/u)(input);
483
+ if (Option.isNone(standalone)) return Option.none();
484
+ const quarter = quarterNumber(textAt(standalone.value, 1));
485
+ return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `Q${quarter}`));
486
+ };
487
+ const parseBasePeriod = (input) => {
488
+ const absoluteDate = absoluteDatePeriod(input, "pl");
489
+ if (Option.isSome(absoluteDate)) return absoluteDate;
490
+ const namedDate = parseNamedDate(input);
491
+ if (Option.isSome(namedDate)) return namedDate;
492
+ const quarter = parseQuarter(input);
493
+ if (Option.isSome(quarter)) return quarter;
494
+ const yearMatch = String$1.match(/^(?:rok |roku )?(\d{4})$/u)(input);
495
+ if (Option.isSome(yearMatch)) {
496
+ const year = validYear(textAt(yearMatch.value, 1));
497
+ if (year !== void 0) return Option.some(fixedYearPeriod(year, String(year)));
498
+ }
499
+ const monthYear = String$1.match(/^([a-ząćęłńóśźż]+\.?) (\d{4})$/u)(input);
500
+ if (Option.isSome(monthYear)) {
501
+ const month = monthNumber(textAt(monthYear.value, 1));
502
+ const year = validYear(textAt(monthYear.value, 2));
503
+ if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${title(textAt(months, month - 1))} ${year}`));
504
+ }
505
+ const relativeMonth = String$1.match(/^([a-ząćęłńóśźż]+\.?) (poprzedniego roku|następnego roku|tego roku)$/u)(input);
506
+ const relativeMonthYearFirst = String$1.match(/^(poprzedniego roku|następnego roku|tego roku) ([a-ząćęłńóśźż]+\.?)$/u)(input);
507
+ const relativeMatch = Option.firstSomeOf([relativeMonth, relativeMonthYearFirst]);
508
+ if (Option.isSome(relativeMatch)) {
509
+ const yearFirst = Option.isSome(relativeMonthYearFirst);
510
+ const monthText = textAt(relativeMatch.value, yearFirst ? 2 : 1);
511
+ const yearText = textAt(relativeMatch.value, yearFirst ? 1 : 2);
512
+ const month = monthNumber(monthText);
513
+ const direction = relativeYearDirection(yearText);
514
+ if (month !== void 0) return Option.some(monthOfRelativeYear(month, direction, `${title(textAt(months, month - 1))} ${relativeYearName(direction)}`));
515
+ }
516
+ const standaloneMonth = monthNumber(input);
517
+ if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, title(textAt(months, standaloneMonth - 1))));
518
+ const alias = periodAliases.find((entry) => entry[0] === input);
519
+ if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
520
+ if (["weekend", "ten weekend"].includes(input)) return Option.some(relativeWeekend(0, "ten weekend"));
521
+ if (["poprzedni weekend", "zeszły weekend"].includes(input)) return Option.some(relativeWeekend(-1, "poprzedni weekend"));
522
+ if (["następny weekend", "przyszły weekend"].includes(input)) return Option.some(relativeWeekend(1, "następny weekend"));
523
+ if (input === "weekend przed poprzednim") return Option.some(relativeWeekend(-2, input));
524
+ if (input === "weekend po następnym") return Option.some(relativeWeekend(2, input));
525
+ return Option.none();
526
+ };
527
+ const parsePeriod = (input) => {
528
+ const edge = String$1.match(/^(początek|koniec) (.+)$/u)(input);
529
+ if (Option.isSome(edge)) {
530
+ const period = parseBasePeriod(textAt(edge.value, 2));
531
+ if (Option.isSome(period)) {
532
+ const isEnd = textAt(edge.value, 1) === "koniec";
533
+ const canonical = `${isEnd ? "koniec" : "początek"} ${withPeriodCase(period.value.canonical, "genitive")}`;
534
+ return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
535
+ }
536
+ }
537
+ const wrapper = [
538
+ "w ",
539
+ "we ",
540
+ "przez ",
541
+ "cały ",
542
+ "całe "
543
+ ].find((prefix) => input.startsWith(prefix));
544
+ return parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
545
+ };
546
+ const countedUnit = (value) => unitAliases.find((entry) => entry[0] === value)?.[1];
547
+ const countedUnitPattern = "dzień|dni|tydzień|tygodnie|tygodni|miesiąc|miesiące|miesięcy|kwartał|kwartały|kwartałów|rok|lata|lat";
548
+ const countedPattern = (source) => new RegExp(source.replace("UNIT", countedUnitPattern), "u");
549
+ const calendarPastPattern = countedPattern("^(?:dokładnie )?(?:([1-9]\\d*) )?(UNIT) temu$");
550
+ const calendarFuturePattern = countedPattern("^za (?:([1-9]\\d*) )?(UNIT)$");
551
+ const rollingPastPatterns = [countedPattern("^(?:ostatni|ostatnie|ostatnich|miniony|minione|minionych) ([1-9]\\d*) (UNIT)$"), countedPattern("^w ciągu (?:ostatniego|ostatnich|minionego|minionych) ([1-9]\\d*) (UNIT)$")];
552
+ const rollingFuturePatterns = [countedPattern("^(?:następny|następne|następnych|kolejny|kolejne|kolejnych) ([1-9]\\d*) (UNIT)$"), countedPattern("^w ciągu (?:najbliższego|najbliższych) ([1-9]\\d*) (UNIT)$")];
553
+ const rollingBarePattern = countedPattern("^([1-9]\\d*) (UNIT)$");
554
+ const firstPatternMatch = (input, patterns) => Option.firstSomeOf(patterns.map((pattern) => String$1.match(pattern)(input)));
555
+ const countNoun = (amount, entry) => {
556
+ if (amount === 1) return entry.singular;
557
+ const lastTwo = amount % 100;
558
+ const last = amount % 10;
559
+ return last >= 2 && last <= 4 && (lastTwo < 12 || lastTwo > 14) ? entry.few : entry.many;
560
+ };
561
+ const parseCalendarOffset = (input) => {
562
+ const past = String$1.match(calendarPastPattern)(input);
563
+ const future = String$1.match(calendarFuturePattern)(input);
564
+ const match = Option.firstSomeOf([past, future]);
565
+ if (Option.isNone(match)) return Option.none();
566
+ const amountText = textAt(match.value, 1);
567
+ const unitText = textAt(match.value, 2);
568
+ const amount = parseTrailingCount(amountText || "1");
569
+ const unit = countedUnit(unitText);
570
+ if (Option.isNone(amount) || unit === void 0) return Option.none();
571
+ const entry = units.find((item) => item.unit === unit);
572
+ if (entry === void 0 || amountText.length === 0 && unitText !== entry.singular) return Option.none();
573
+ const direction = Option.isSome(past) ? -amount.value : amount.value;
574
+ const noun = countNoun(amount.value, entry);
575
+ const canonical = direction < 0 ? `${amount.value} ${noun} temu` : `za ${amount.value} ${noun}`;
576
+ return Option.some(candidate(periodRange(relativePeriod(unit, direction, canonical)), canonical));
577
+ };
578
+ const rollingModifier = (amount, future) => {
579
+ if (amount === 1) return future ? "następny" : "ostatni";
580
+ const lastTwo = amount % 100;
581
+ const last = amount % 10;
582
+ if (last >= 2 && last <= 4 && (lastTwo < 12 || lastTwo > 14)) return future ? "następne" : "ostatnie";
583
+ return future ? "następnych" : "ostatnich";
584
+ };
585
+ const parseRollingPeriod = (input) => {
586
+ const past = firstPatternMatch(input, rollingPastPatterns);
587
+ const bare = String$1.match(rollingBarePattern)(input);
588
+ const future = firstPatternMatch(input, rollingFuturePatterns);
589
+ const match = Option.firstSomeOf([
590
+ past,
591
+ bare,
592
+ future
593
+ ]);
594
+ if (Option.isNone(match)) return Option.none();
595
+ const amount = parseTrailingCount(textAt(match.value, 1));
596
+ const unit = countedUnit(textAt(match.value, 2));
597
+ if (Option.isNone(amount) || unit === void 0) return Option.none();
598
+ const entry = units.find((item) => item.unit === unit);
599
+ if (entry === void 0) return Option.none();
600
+ const isFuture = Option.isSome(future);
601
+ const range = isFuture ? futureRange(amount.value, unit) : trailingRange(amount.value, unit);
602
+ const modifier = rollingModifier(amount.value, isFuture);
603
+ return Option.some(candidate(range, `${modifier} ${amount.value} ${countNoun(amount.value, entry)}`));
604
+ };
605
+ const boundaries = [
606
+ [
607
+ "do początku ",
608
+ "before",
609
+ (period) => `przed ${withPeriodCase(period, "instrumental")}`
610
+ ],
611
+ [
612
+ "począwszy od ",
613
+ "since",
614
+ (period) => `od ${withPeriodCase(period, "genitive")}`
615
+ ],
616
+ [
617
+ "od ",
618
+ "since",
619
+ (period) => `od ${withPeriodCase(period, "genitive")}`
620
+ ],
621
+ [
622
+ "przed ",
623
+ "before",
624
+ (period) => `przed ${withPeriodCase(period, "instrumental")}`
625
+ ],
626
+ [
627
+ "do ",
628
+ "through",
629
+ (period) => `do ${withPeriodCase(period, "genitive")} włącznie`
630
+ ],
631
+ [
632
+ "po ",
633
+ "after",
634
+ (period) => `po ${withPeriodCase(period, "locative")}`
635
+ ]
636
+ ];
637
+ const boundaryCandidate = (input) => {
638
+ const included = String$1.match(/^do (.+) włącznie$/u)(input);
639
+ if (Option.isSome(included)) return parsePeriod(textAt(included.value, 1)).pipe(Option.map((value) => periodBoundaryCandidate(value, "through", `do ${withPeriodCase(value.canonical, "genitive")} włącznie`)));
640
+ for (const [prefix, boundary, canonical] of boundaries) {
641
+ if (!input.startsWith(prefix)) continue;
642
+ const period = parsePeriod(input.slice(prefix.length));
643
+ if (Option.isSome(period)) return Option.some(periodBoundaryCandidate(period.value, boundary, canonical(period.value.canonical)));
644
+ }
645
+ return Option.none();
646
+ };
647
+ const parsePolish = (input) => {
648
+ const remaining = remainingPhrases.find((entry) => entry.phrase === input);
649
+ if (remaining !== void 0) return Option.some(candidate(remainingPeriodRange(remaining.entry.unit), remaining.entry.remaining));
650
+ if ([
651
+ "do dziś",
652
+ "dotychczas",
653
+ "do teraz"
654
+ ].includes(input)) return Option.some(candidate(untilNowRange(), "do dziś"));
655
+ if (["od teraz", "od dziś"].includes(input)) return Option.some(candidate(fromNowRange(), "od teraz"));
656
+ const offset = parseCalendarOffset(input);
657
+ if (Option.isSome(offset)) return offset;
658
+ const rolling = parseRollingPeriod(input);
659
+ if (Option.isSome(rolling)) return rolling;
660
+ const toDate = toDatePhrases.find((entry) => entry.phrase === input);
661
+ if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
662
+ const elidedDayRange = String$1.match(/^(?:(?:między|pomiędzy) ([0-3]?\d)\.? a |([0-3]?\d)\.?[–—])([0-3]?\d)\.? ([a-ząćęłńóśźż]+\.?)(?: (\d{4}))?$/u)(input);
663
+ if (Option.isSome(elidedDayRange)) {
664
+ const lowerDay = textAt(elidedDayRange.value, 1) || textAt(elidedDayRange.value, 2);
665
+ const upperDay = textAt(elidedDayRange.value, 3);
666
+ const month = textAt(elidedDayRange.value, 4);
667
+ const year = textAt(elidedDayRange.value, 5);
668
+ const suffix = year.length === 0 ? "" : ` ${year}`;
669
+ const expanded = `między ${lowerDay} ${month}${suffix} a ${upperDay} ${month}${suffix}`;
670
+ const joined = joinedPeriodCandidate(expanded, [["między ", " a "], ["pomiędzy ", " a "]], parsePeriod, (lower, upper) => `od ${lower} do ${upper} włącznie`);
671
+ if (Option.isSome(joined)) return joined;
672
+ }
673
+ const nowBounded = joinedNowCandidate(input, [
674
+ ["od ", " do dziś"],
675
+ ["między ", " a dziś"],
676
+ ["pomiędzy ", " a dziś"]
677
+ ], [
678
+ "od dziś do ",
679
+ "między dziś a ",
680
+ "pomiędzy dziś a "
681
+ ], parsePeriod, (period) => `od ${period} do dziś`, (period) => `od dziś do ${period}`);
682
+ if (Option.isSome(nowBounded)) return nowBounded;
683
+ const bounded = joinedPeriodCandidate(input, [
684
+ ["od ", " do "],
685
+ ["między ", " a "],
686
+ ["pomiędzy ", " a "],
687
+ ["", " - "],
688
+ ["", " – "],
689
+ ["", " — "]
690
+ ], parsePeriod, (lower, upper) => `od ${lower} do ${upper} włącznie`);
691
+ if (Option.isSome(bounded)) return bounded;
692
+ const boundary = boundaryCandidate(input);
693
+ if (Option.isSome(boundary)) return boundary;
694
+ return parsePeriod(input).pipe(Option.map((period) => candidate(periodRange(period), period.canonical)));
695
+ };
696
+ const edgePhrases = [...declinedPeriods.map((entry) => entry[3]), ...monthGenitives].flatMap((phrase) => [`początek ${phrase}`, `koniec ${phrase}`]);
697
+ const canonicalPeriodPhrases = [
698
+ ...units.flatMap((entry) => [
699
+ entry.current,
700
+ entry.previous,
701
+ entry.next
702
+ ]),
703
+ "przedwczoraj",
704
+ "pojutrze",
705
+ "przedostatni tydzień",
706
+ "tydzień po następnym",
707
+ "przedostatni miesiąc",
708
+ "miesiąc po następnym",
709
+ "przedostatni rok",
710
+ "rok po następnym",
711
+ "ten weekend",
712
+ "poprzedni weekend",
713
+ "następny weekend",
714
+ "weekend przed poprzednim",
715
+ "weekend po następnym"
716
+ ];
717
+ const staticPeriodPhrases = [
718
+ ...periodAliases.map((entry) => entry[0]),
719
+ ...canonicalPeriodPhrases,
720
+ ...edgePhrases,
721
+ ...[
722
+ 1,
723
+ 2,
724
+ 3,
725
+ 4
726
+ ].flatMap((quarter) => [
727
+ `q${quarter}`,
728
+ `q${quarter} tego roku`,
729
+ `q${quarter} poprzedniego roku`,
730
+ `q${quarter} następnego roku`
731
+ ]),
732
+ ...months.flatMap((month) => [
733
+ month,
734
+ `${month} poprzedniego roku`,
735
+ `${month} następnego roku`
736
+ ])
737
+ ];
738
+ const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
739
+ const monthBoundaryPhrases = months.flatMap((_, index) => {
740
+ const genitive = textAt(monthGenitives, index);
741
+ const instrumental = textAt(monthInstrumentals, index);
742
+ const locative = textAt(monthLocatives, index);
743
+ return [
744
+ `od ${genitive}`,
745
+ `począwszy od ${genitive}`,
746
+ `przed ${instrumental}`,
747
+ `do ${genitive} włącznie`,
748
+ `po ${locative}`
749
+ ];
750
+ });
751
+ const fixedBoundaryPhrases = (phrases) => phrases.flatMap((phrase) => [
752
+ `od ${withMonthCase(phrase, monthGenitives)}`,
753
+ `przed ${withMonthCase(phrase, monthInstrumentals)}`,
754
+ `do ${withMonthCase(phrase, monthGenitives)} włącznie`,
755
+ `po ${withMonthCase(phrase, monthLocatives)}`
756
+ ]);
757
+ const countedSuggestions = (input) => {
758
+ const amount = naturalCount(input);
759
+ if (amount === void 0) return [];
760
+ return units.flatMap((entry) => {
761
+ const noun = countNoun(amount, entry);
762
+ return [
763
+ `${rollingModifier(amount, false)} ${amount} ${noun}`,
764
+ `${amount} ${noun}`,
765
+ `${rollingModifier(amount, true)} ${amount} ${noun}`,
766
+ `${amount} ${noun} temu`,
767
+ `za ${amount} ${noun}`
768
+ ];
769
+ });
770
+ };
771
+ const polishSuggestionPhrases = [
772
+ ...toDatePhrases.map((entry) => entry.phrase),
773
+ ...remainingPhrases.map((entry) => entry.phrase),
774
+ ...canonicalPeriodPhrases,
775
+ ...edgePhrases,
776
+ ...[
777
+ 1,
778
+ 2,
779
+ 3,
780
+ 4
781
+ ].flatMap((quarter) => [
782
+ `q${quarter}`,
783
+ `q${quarter} tego roku`,
784
+ `q${quarter} poprzedniego roku`,
785
+ `q${quarter} następnego roku`
786
+ ]),
787
+ ...months,
788
+ ...monthBoundaryPhrases,
789
+ "do dziś",
790
+ "od teraz"
791
+ ];
792
+ const suggestPolish = (input, limit) => {
793
+ const correctedInput = input.startsWith("do koniec") ? `do końca${input.slice(9)}` : input;
794
+ const fixed = fixedCalendarPeriodPhrases(correctedInput, months);
795
+ return completeNaturalPhrases(correctedInput, [
796
+ ...polishSuggestionPhrases,
797
+ ...fixed,
798
+ ...fixedBoundaryPhrases(fixed),
799
+ ...countedSuggestions(correctedInput)
800
+ ], limit);
801
+ };
802
+ const renderPolish = (range) => {
803
+ const offset = calendarPeriodOffset(range);
804
+ if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
805
+ const entry = units.find((unit) => unit.unit === offset.value.unit);
806
+ if (entry !== void 0) {
807
+ const amount = Math.abs(offset.value.amount);
808
+ const noun = countNoun(amount, entry);
809
+ return Option.some(offset.value.amount < 0 ? `${amount} ${noun} temu` : `za ${amount} ${noun}`);
810
+ }
811
+ }
812
+ const future = futurePeriod(range);
813
+ if (Option.isSome(future)) {
814
+ const entry = units.find((unit) => unit.unit === future.value.unit);
815
+ if (entry !== void 0) return Option.some(`${rollingModifier(future.value.amount, true)} ${future.value.amount} ${countNoun(future.value.amount, entry)}`);
816
+ }
817
+ const trailing = trailingPeriod(range);
818
+ if (Option.isSome(trailing)) {
819
+ const entry = units.find((unit) => unit.unit === trailing.value.unit);
820
+ if (entry !== void 0) return Option.some(`${rollingModifier(trailing.value.amount, false)} ${trailing.value.amount} ${countNoun(trailing.value.amount, entry)}`);
821
+ }
822
+ const periods = [
823
+ ...staticPeriods,
824
+ ...currentYearDatePeriods(range, currentDateLabel),
825
+ ...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)
826
+ ];
827
+ return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `od ${withPeriodCase(period, "genitive")}`, (period) => `przed ${withPeriodCase(period, "instrumental")}`, (period) => `do ${withPeriodCase(period, "genitive")} włącznie`, (period) => `po ${withPeriodCase(period, "locative")}`, (lower, upper) => `od ${withPeriodCase(lower, "genitive")} do ${withPeriodCase(upper, "genitive")} włącznie`, (period) => `od ${withPeriodCase(period, "genitive")} do dziś`, (period) => `od dziś do ${withPeriodCase(period, "genitive")}`, () => "do dziś", () => "od teraz");
828
+ };
829
+ const PolishContribution = new BaseLanguageContribution({
830
+ locale: "pl",
831
+ vocabulary: [
832
+ ...months,
833
+ ...monthGenitives,
834
+ ...monthInstrumentals,
835
+ ...monthLocatives,
836
+ ...monthAbbreviations.flatMap((aliases) => aliases),
837
+ ...units.flatMap((entry) => [
838
+ entry.singular,
839
+ entry.few,
840
+ entry.many,
841
+ ...entry.current.split(" "),
842
+ ...entry.previous.split(" "),
843
+ ...entry.next.split(" ")
844
+ ]),
845
+ ...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
846
+ ...remainingPhrases.flatMap((entry) => entry.phrase.split(" ")),
847
+ ...periodAliases.flatMap((entry) => entry[0].split(" ")),
848
+ "ciągu",
849
+ "dokładnie",
850
+ "dziś",
851
+ "dotychczas",
852
+ "koniec",
853
+ "końca",
854
+ "kolejne",
855
+ "między",
856
+ "minione",
857
+ "najbliższych",
858
+ "następne",
859
+ "od",
860
+ "ostatnie",
861
+ "po",
862
+ "początek",
863
+ "począwszy",
864
+ "pomiędzy",
865
+ "poprzedni",
866
+ "przed",
867
+ "teraz",
868
+ "temu",
869
+ "włącznie",
870
+ "we",
871
+ "za"
872
+ ],
873
+ normalize: normalizeNaturalText,
874
+ correct: correctWhitespaceSeparatedText,
875
+ parseExact: parsePolish,
876
+ suggest: suggestPolish,
877
+ render: renderPolish
878
+ });
879
+ const PolishLanguage = defineLanguagePlugin({
880
+ id: "chronolizer/language-pl",
881
+ effect: (context) => Effect.asVoid(context.register("chronolizer/language-pl", PolishContribution))
882
+ });
883
+ const PolishLanguageLayer = languagePluginsLayer([PolishLanguage]);
884
+ //#endregion
885
+ export { PolishContribution, PolishLanguage, PolishLanguageLayer };