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.
- package/README.md +184 -119
- package/dist/ast/constructors.d.mts +135 -0
- package/dist/ast/constructors.mjs +25 -0
- package/dist/ast/fold.d.mts +13 -0
- package/dist/ast/fold.mjs +58 -0
- package/dist/ast/normalize.d.mts +42 -0
- package/dist/ast/normalize.mjs +34 -0
- package/dist/ast/schemas.d.mts +80 -0
- package/dist/ast/schemas.mjs +65 -0
- package/dist/filter/codec.d.mts +92 -0
- package/dist/filter/codec.mjs +48 -0
- package/dist/filter/errors.d.mts +14 -0
- package/dist/filter/errors.mjs +10 -0
- package/dist/filter/expression.d.mts +8 -0
- package/dist/filter/expression.mjs +76 -0
- package/dist/filter/schema.d.mts +13 -0
- package/dist/filter/schema.mjs +11 -0
- package/dist/filter/transformation.d.mts +37 -0
- package/dist/filter/transformation.mjs +20 -0
- package/dist/index.d.mts +22 -969
- package/dist/index.mjs +22 -2305
- package/dist/language/errors.d.mts +38 -0
- package/dist/language/errors.mjs +30 -0
- package/dist/language/model.d.mts +239 -0
- package/dist/language/model.mjs +50 -0
- package/dist/language/registry.d.mts +17 -0
- package/dist/language/registry.mjs +116 -0
- package/dist/locales/cs.d.mts +10 -0
- package/dist/locales/cs.mjs +746 -0
- package/dist/locales/de.d.mts +10 -0
- package/dist/locales/de.mjs +1039 -0
- package/dist/locales/en.d.mts +10 -0
- package/dist/locales/en.mjs +598 -0
- package/dist/locales/es.d.mts +10 -0
- package/dist/locales/es.mjs +908 -0
- package/dist/locales/fr.d.mts +10 -0
- package/dist/locales/fr.mjs +901 -0
- package/dist/locales/nl.d.mts +10 -0
- package/dist/locales/nl.mjs +791 -0
- package/dist/locales/pl.d.mts +10 -0
- package/dist/locales/pl.mjs +885 -0
- package/dist/locales/shared.mjs +395 -0
- package/dist/locales/tr.d.mts +10 -0
- package/dist/locales/tr.mjs +725 -0
- package/dist/natural/correction.d.mts +13 -0
- package/dist/natural/correction.mjs +73 -0
- package/dist/natural/format.d.mts +47 -0
- package/dist/natural/format.mjs +14 -0
- package/dist/natural/parse.d.mts +99 -0
- package/dist/natural/parse.mjs +66 -0
- package/dist/natural/policy.mjs +6 -0
- package/dist/natural/suggest.d.mts +53 -0
- package/dist/natural/suggest.mjs +24 -0
- package/dist/natural/suggestion.d.mts +4 -0
- package/dist/natural/suggestion.mjs +79 -0
- package/dist/natural/text.d.mts +5 -0
- package/dist/natural/text.mjs +5 -0
- package/dist/resolve/resolve.d.mts +79 -0
- package/dist/resolve/resolve.mjs +58 -0
- package/dist/resolve/schema.d.mts +59 -0
- package/dist/resolve/schema.mjs +28 -0
- package/package.json +15 -3
|
@@ -0,0 +1,908 @@
|
|
|
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 { absoluteDatePeriod, calendarPeriodOffset, candidate, currentYearDatePeriods, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedCurrentYearDatePeriod, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodBoundaryCandidate, periodDay, 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/es.ts
|
|
10
|
+
const months = [
|
|
11
|
+
"enero",
|
|
12
|
+
"febrero",
|
|
13
|
+
"marzo",
|
|
14
|
+
"abril",
|
|
15
|
+
"mayo",
|
|
16
|
+
"junio",
|
|
17
|
+
"julio",
|
|
18
|
+
"agosto",
|
|
19
|
+
"septiembre",
|
|
20
|
+
"octubre",
|
|
21
|
+
"noviembre",
|
|
22
|
+
"diciembre"
|
|
23
|
+
];
|
|
24
|
+
const monthAbbreviations = [
|
|
25
|
+
["ene"],
|
|
26
|
+
["feb"],
|
|
27
|
+
["mar"],
|
|
28
|
+
["abr"],
|
|
29
|
+
["may"],
|
|
30
|
+
["jun"],
|
|
31
|
+
["jul"],
|
|
32
|
+
["ago"],
|
|
33
|
+
[
|
|
34
|
+
"sep",
|
|
35
|
+
"sept",
|
|
36
|
+
"set",
|
|
37
|
+
"setiembre"
|
|
38
|
+
],
|
|
39
|
+
["oct"],
|
|
40
|
+
["nov"],
|
|
41
|
+
["dic"]
|
|
42
|
+
];
|
|
43
|
+
const units = [
|
|
44
|
+
{
|
|
45
|
+
unit: "day",
|
|
46
|
+
singular: "día",
|
|
47
|
+
plural: "días",
|
|
48
|
+
gender: "masculine",
|
|
49
|
+
current: "hoy",
|
|
50
|
+
previous: "ayer",
|
|
51
|
+
next: "mañana",
|
|
52
|
+
toDate: "día hasta la fecha",
|
|
53
|
+
remaining: "resto del día"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
unit: "week",
|
|
57
|
+
singular: "semana",
|
|
58
|
+
plural: "semanas",
|
|
59
|
+
gender: "feminine",
|
|
60
|
+
current: "esta semana",
|
|
61
|
+
previous: "la semana pasada",
|
|
62
|
+
next: "la próxima semana",
|
|
63
|
+
toDate: "semana hasta la fecha",
|
|
64
|
+
remaining: "resto de la semana"
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
unit: "month",
|
|
68
|
+
singular: "mes",
|
|
69
|
+
plural: "meses",
|
|
70
|
+
gender: "masculine",
|
|
71
|
+
current: "este mes",
|
|
72
|
+
previous: "el mes pasado",
|
|
73
|
+
next: "el próximo mes",
|
|
74
|
+
toDate: "mes hasta la fecha",
|
|
75
|
+
remaining: "resto del mes"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
unit: "quarter",
|
|
79
|
+
singular: "trimestre",
|
|
80
|
+
plural: "trimestres",
|
|
81
|
+
gender: "masculine",
|
|
82
|
+
current: "este trimestre",
|
|
83
|
+
previous: "el trimestre pasado",
|
|
84
|
+
next: "el próximo trimestre",
|
|
85
|
+
toDate: "trimestre hasta la fecha",
|
|
86
|
+
remaining: "resto del trimestre"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
unit: "year",
|
|
90
|
+
singular: "año",
|
|
91
|
+
plural: "años",
|
|
92
|
+
gender: "masculine",
|
|
93
|
+
current: "este año",
|
|
94
|
+
previous: "el año pasado",
|
|
95
|
+
next: "el próximo año",
|
|
96
|
+
toDate: "año hasta la fecha",
|
|
97
|
+
remaining: "resto del año"
|
|
98
|
+
}
|
|
99
|
+
];
|
|
100
|
+
const gendered = (entry, masculine, feminine) => entry.gender === "feminine" ? feminine : masculine;
|
|
101
|
+
const definiteArticle = (entry, plural = false) => gendered(entry, plural ? "los" : "el", plural ? "las" : "la");
|
|
102
|
+
const indefiniteArticle = (entry) => gendered(entry, "un", "una");
|
|
103
|
+
const withDe = (period) => period.startsWith("el ") ? `del ${period.slice(3)}` : `de ${period}`;
|
|
104
|
+
const afterDe = (period) => {
|
|
105
|
+
if (period.startsWith("del ")) return `el ${period.slice(4)}`;
|
|
106
|
+
return period.startsWith("de ") ? period.slice(3) : period;
|
|
107
|
+
};
|
|
108
|
+
const rollingAdjective = (entry, future, plural) => {
|
|
109
|
+
if (future) return gendered(entry, plural ? "próximos" : "próximo", plural ? "próximas" : "próxima");
|
|
110
|
+
return gendered(entry, plural ? "últimos" : "último", plural ? "últimas" : "última");
|
|
111
|
+
};
|
|
112
|
+
const unitAliases = [
|
|
113
|
+
[
|
|
114
|
+
"día",
|
|
115
|
+
"day",
|
|
116
|
+
false
|
|
117
|
+
],
|
|
118
|
+
[
|
|
119
|
+
"dia",
|
|
120
|
+
"day",
|
|
121
|
+
false
|
|
122
|
+
],
|
|
123
|
+
[
|
|
124
|
+
"días",
|
|
125
|
+
"day",
|
|
126
|
+
true
|
|
127
|
+
],
|
|
128
|
+
[
|
|
129
|
+
"dias",
|
|
130
|
+
"day",
|
|
131
|
+
true
|
|
132
|
+
],
|
|
133
|
+
[
|
|
134
|
+
"semana",
|
|
135
|
+
"week",
|
|
136
|
+
false
|
|
137
|
+
],
|
|
138
|
+
[
|
|
139
|
+
"semanas",
|
|
140
|
+
"week",
|
|
141
|
+
true
|
|
142
|
+
],
|
|
143
|
+
[
|
|
144
|
+
"mes",
|
|
145
|
+
"month",
|
|
146
|
+
false
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
"meses",
|
|
150
|
+
"month",
|
|
151
|
+
true
|
|
152
|
+
],
|
|
153
|
+
[
|
|
154
|
+
"trimestre",
|
|
155
|
+
"quarter",
|
|
156
|
+
false
|
|
157
|
+
],
|
|
158
|
+
[
|
|
159
|
+
"trimestres",
|
|
160
|
+
"quarter",
|
|
161
|
+
true
|
|
162
|
+
],
|
|
163
|
+
[
|
|
164
|
+
"año",
|
|
165
|
+
"year",
|
|
166
|
+
false
|
|
167
|
+
],
|
|
168
|
+
[
|
|
169
|
+
"ano",
|
|
170
|
+
"year",
|
|
171
|
+
false
|
|
172
|
+
],
|
|
173
|
+
[
|
|
174
|
+
"años",
|
|
175
|
+
"year",
|
|
176
|
+
true
|
|
177
|
+
],
|
|
178
|
+
[
|
|
179
|
+
"anos",
|
|
180
|
+
"year",
|
|
181
|
+
true
|
|
182
|
+
]
|
|
183
|
+
];
|
|
184
|
+
const periodAliases = [
|
|
185
|
+
...units.flatMap((entry) => [
|
|
186
|
+
[
|
|
187
|
+
entry.current,
|
|
188
|
+
entry.unit,
|
|
189
|
+
0,
|
|
190
|
+
entry.current
|
|
191
|
+
],
|
|
192
|
+
[
|
|
193
|
+
entry.previous,
|
|
194
|
+
entry.unit,
|
|
195
|
+
-1,
|
|
196
|
+
entry.previous
|
|
197
|
+
],
|
|
198
|
+
[
|
|
199
|
+
entry.next,
|
|
200
|
+
entry.unit,
|
|
201
|
+
1,
|
|
202
|
+
entry.next
|
|
203
|
+
]
|
|
204
|
+
]),
|
|
205
|
+
...units.filter((entry) => entry.unit !== "day").flatMap((entry) => [
|
|
206
|
+
[
|
|
207
|
+
`${entry.singular} actual`,
|
|
208
|
+
entry.unit,
|
|
209
|
+
0,
|
|
210
|
+
entry.current
|
|
211
|
+
],
|
|
212
|
+
[
|
|
213
|
+
`${definiteArticle(entry)} ${entry.singular} anterior`,
|
|
214
|
+
entry.unit,
|
|
215
|
+
-1,
|
|
216
|
+
entry.previous
|
|
217
|
+
],
|
|
218
|
+
[
|
|
219
|
+
`${entry.singular} anterior`,
|
|
220
|
+
entry.unit,
|
|
221
|
+
-1,
|
|
222
|
+
entry.previous
|
|
223
|
+
],
|
|
224
|
+
[
|
|
225
|
+
`${definiteArticle(entry)} ${entry.singular} siguiente`,
|
|
226
|
+
entry.unit,
|
|
227
|
+
1,
|
|
228
|
+
entry.next
|
|
229
|
+
],
|
|
230
|
+
[
|
|
231
|
+
`${entry.singular} siguiente`,
|
|
232
|
+
entry.unit,
|
|
233
|
+
1,
|
|
234
|
+
entry.next
|
|
235
|
+
],
|
|
236
|
+
[
|
|
237
|
+
`${rollingAdjective(entry, true, false)} ${entry.singular}`,
|
|
238
|
+
entry.unit,
|
|
239
|
+
1,
|
|
240
|
+
entry.next
|
|
241
|
+
]
|
|
242
|
+
]),
|
|
243
|
+
[
|
|
244
|
+
"semana pasada",
|
|
245
|
+
"week",
|
|
246
|
+
-1,
|
|
247
|
+
"la semana pasada"
|
|
248
|
+
],
|
|
249
|
+
[
|
|
250
|
+
"semana que viene",
|
|
251
|
+
"week",
|
|
252
|
+
1,
|
|
253
|
+
"la próxima semana"
|
|
254
|
+
],
|
|
255
|
+
[
|
|
256
|
+
"la semana que viene",
|
|
257
|
+
"week",
|
|
258
|
+
1,
|
|
259
|
+
"la próxima semana"
|
|
260
|
+
],
|
|
261
|
+
[
|
|
262
|
+
"proxima semana",
|
|
263
|
+
"week",
|
|
264
|
+
1,
|
|
265
|
+
"la próxima semana"
|
|
266
|
+
],
|
|
267
|
+
[
|
|
268
|
+
"el pasado mes",
|
|
269
|
+
"month",
|
|
270
|
+
-1,
|
|
271
|
+
"el mes pasado"
|
|
272
|
+
],
|
|
273
|
+
[
|
|
274
|
+
"mes pasado",
|
|
275
|
+
"month",
|
|
276
|
+
-1,
|
|
277
|
+
"el mes pasado"
|
|
278
|
+
],
|
|
279
|
+
[
|
|
280
|
+
"mes que viene",
|
|
281
|
+
"month",
|
|
282
|
+
1,
|
|
283
|
+
"el próximo mes"
|
|
284
|
+
],
|
|
285
|
+
[
|
|
286
|
+
"el mes que viene",
|
|
287
|
+
"month",
|
|
288
|
+
1,
|
|
289
|
+
"el próximo mes"
|
|
290
|
+
],
|
|
291
|
+
[
|
|
292
|
+
"el proximo mes",
|
|
293
|
+
"month",
|
|
294
|
+
1,
|
|
295
|
+
"el próximo mes"
|
|
296
|
+
],
|
|
297
|
+
[
|
|
298
|
+
"año pasado",
|
|
299
|
+
"year",
|
|
300
|
+
-1,
|
|
301
|
+
"el año pasado"
|
|
302
|
+
],
|
|
303
|
+
[
|
|
304
|
+
"ano pasado",
|
|
305
|
+
"year",
|
|
306
|
+
-1,
|
|
307
|
+
"el año pasado"
|
|
308
|
+
],
|
|
309
|
+
[
|
|
310
|
+
"año que viene",
|
|
311
|
+
"year",
|
|
312
|
+
1,
|
|
313
|
+
"el próximo año"
|
|
314
|
+
],
|
|
315
|
+
[
|
|
316
|
+
"el año que viene",
|
|
317
|
+
"year",
|
|
318
|
+
1,
|
|
319
|
+
"el próximo año"
|
|
320
|
+
],
|
|
321
|
+
[
|
|
322
|
+
"el proximo año",
|
|
323
|
+
"year",
|
|
324
|
+
1,
|
|
325
|
+
"el próximo año"
|
|
326
|
+
],
|
|
327
|
+
[
|
|
328
|
+
"este ano",
|
|
329
|
+
"year",
|
|
330
|
+
0,
|
|
331
|
+
"este año"
|
|
332
|
+
],
|
|
333
|
+
[
|
|
334
|
+
"trimestre pasado",
|
|
335
|
+
"quarter",
|
|
336
|
+
-1,
|
|
337
|
+
"el trimestre pasado"
|
|
338
|
+
],
|
|
339
|
+
[
|
|
340
|
+
"proximo trimestre",
|
|
341
|
+
"quarter",
|
|
342
|
+
1,
|
|
343
|
+
"el próximo trimestre"
|
|
344
|
+
],
|
|
345
|
+
[
|
|
346
|
+
"anteayer",
|
|
347
|
+
"day",
|
|
348
|
+
-2,
|
|
349
|
+
"anteayer"
|
|
350
|
+
],
|
|
351
|
+
[
|
|
352
|
+
"día antes de ayer",
|
|
353
|
+
"day",
|
|
354
|
+
-2,
|
|
355
|
+
"anteayer"
|
|
356
|
+
],
|
|
357
|
+
[
|
|
358
|
+
"el día antes de ayer",
|
|
359
|
+
"day",
|
|
360
|
+
-2,
|
|
361
|
+
"anteayer"
|
|
362
|
+
],
|
|
363
|
+
[
|
|
364
|
+
"pasado mañana",
|
|
365
|
+
"day",
|
|
366
|
+
2,
|
|
367
|
+
"pasado mañana"
|
|
368
|
+
],
|
|
369
|
+
[
|
|
370
|
+
"día después de mañana",
|
|
371
|
+
"day",
|
|
372
|
+
2,
|
|
373
|
+
"pasado mañana"
|
|
374
|
+
],
|
|
375
|
+
[
|
|
376
|
+
"el día después de mañana",
|
|
377
|
+
"day",
|
|
378
|
+
2,
|
|
379
|
+
"pasado mañana"
|
|
380
|
+
],
|
|
381
|
+
[
|
|
382
|
+
"la semana anterior a la pasada",
|
|
383
|
+
"week",
|
|
384
|
+
-2,
|
|
385
|
+
"la semana anterior a la pasada"
|
|
386
|
+
],
|
|
387
|
+
[
|
|
388
|
+
"la semana después de la próxima",
|
|
389
|
+
"week",
|
|
390
|
+
2,
|
|
391
|
+
"la semana después de la próxima"
|
|
392
|
+
],
|
|
393
|
+
[
|
|
394
|
+
"el mes anterior al pasado",
|
|
395
|
+
"month",
|
|
396
|
+
-2,
|
|
397
|
+
"el mes anterior al pasado"
|
|
398
|
+
],
|
|
399
|
+
[
|
|
400
|
+
"el mes después del próximo",
|
|
401
|
+
"month",
|
|
402
|
+
2,
|
|
403
|
+
"el mes después del próximo"
|
|
404
|
+
],
|
|
405
|
+
[
|
|
406
|
+
"el trimestre anterior al pasado",
|
|
407
|
+
"quarter",
|
|
408
|
+
-2,
|
|
409
|
+
"el trimestre anterior al pasado"
|
|
410
|
+
],
|
|
411
|
+
[
|
|
412
|
+
"el trimestre después del próximo",
|
|
413
|
+
"quarter",
|
|
414
|
+
2,
|
|
415
|
+
"el trimestre después del próximo"
|
|
416
|
+
],
|
|
417
|
+
[
|
|
418
|
+
"el año anterior al pasado",
|
|
419
|
+
"year",
|
|
420
|
+
-2,
|
|
421
|
+
"el año anterior al pasado"
|
|
422
|
+
],
|
|
423
|
+
[
|
|
424
|
+
"el año después del próximo",
|
|
425
|
+
"year",
|
|
426
|
+
2,
|
|
427
|
+
"el año después del próximo"
|
|
428
|
+
]
|
|
429
|
+
];
|
|
430
|
+
const toDatePhrases = units.flatMap((entry) => {
|
|
431
|
+
const noun = entry.singular;
|
|
432
|
+
return [
|
|
433
|
+
entry.toDate,
|
|
434
|
+
`en lo que va del ${noun}`,
|
|
435
|
+
`desde el inicio del ${noun}`,
|
|
436
|
+
`desde el comienzo del ${noun}`,
|
|
437
|
+
`desde principios del ${noun}`,
|
|
438
|
+
`${entry.current} hasta ahora`
|
|
439
|
+
].map((phrase) => ({
|
|
440
|
+
entry,
|
|
441
|
+
phrase
|
|
442
|
+
}));
|
|
443
|
+
});
|
|
444
|
+
const remainingPhrases = units.flatMap((entry) => [entry.remaining, `lo que queda del ${entry.singular}`].map((phrase) => ({
|
|
445
|
+
entry,
|
|
446
|
+
phrase
|
|
447
|
+
})));
|
|
448
|
+
const relativeYearDirection = (value) => {
|
|
449
|
+
if (value.includes("pasado")) return -1;
|
|
450
|
+
if (value.includes("ximo")) return 1;
|
|
451
|
+
return 0;
|
|
452
|
+
};
|
|
453
|
+
const relativeYearName = (direction) => {
|
|
454
|
+
if (direction < 0) return "año pasado";
|
|
455
|
+
if (direction > 0) return "próximo año";
|
|
456
|
+
return "este año";
|
|
457
|
+
};
|
|
458
|
+
const monthNumber = (value) => {
|
|
459
|
+
const normalized = value.endsWith(".") ? value.slice(0, -1) : value;
|
|
460
|
+
const full = months.findIndex((month) => month === normalized);
|
|
461
|
+
if (full !== -1) return full + 1;
|
|
462
|
+
const short = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
|
|
463
|
+
return short === -1 ? void 0 : short + 1;
|
|
464
|
+
};
|
|
465
|
+
const currentDateLabel = (day, month) => `${day} de ${textAt(months, month - 1)}`;
|
|
466
|
+
const parseNamedDate = (input) => {
|
|
467
|
+
const named = String$1.match(/^(?:el (?:día )?)?([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)(?:(?: de| del)? (\d{4}))$/u)(input);
|
|
468
|
+
if (Option.isSome(named)) return namedDatePeriod(textAt(named.value, 3), textAt(named.value, 2), textAt(named.value, 1), monthNumber, (day, month, year) => `${day} de ${textAt(months, month - 1)} de ${year}`);
|
|
469
|
+
const numeric = String$1.match(/^([0-3]?\d)[./-]([01]?\d)[./-](\d{4})$/u)(input);
|
|
470
|
+
if (Option.isSome(numeric)) {
|
|
471
|
+
const year = validYear(textAt(numeric.value, 3));
|
|
472
|
+
const month = Number(textAt(numeric.value, 2));
|
|
473
|
+
const day = Number(textAt(numeric.value, 1));
|
|
474
|
+
if (year !== void 0 && month >= 1 && month <= 12) {
|
|
475
|
+
const value = isoDate(year, month, day);
|
|
476
|
+
if (isIsoDate(value) && value !== "9999-12-31") return Option.some(fixedDatePeriod(value, `${day} de ${textAt(months, month - 1)} de ${year}`));
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const current = String$1.match(/^(?:el (?:día )?)?([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)$/u)(input);
|
|
480
|
+
if (Option.isSome(current)) return namedCurrentYearDatePeriod(textAt(current.value, 2), textAt(current.value, 1), monthNumber, currentDateLabel);
|
|
481
|
+
const relative = String$1.match(/^(?:el (?:día )?)?([0-3]?\d) (de .+|del .+)$/u)(input);
|
|
482
|
+
if (Option.isNone(relative)) return Option.none();
|
|
483
|
+
const periodText = afterDe(textAt(relative.value, 2));
|
|
484
|
+
const alias = periodAliases.find((entry) => entry[0] === periodText && entry[1] === "month");
|
|
485
|
+
if (alias === void 0) return Option.none();
|
|
486
|
+
const day = Number(textAt(relative.value, 1));
|
|
487
|
+
const month = relativePeriod(alias[1], alias[2], alias[3]);
|
|
488
|
+
return periodDay(month, day, `${day} ${withDe(alias[3])}`);
|
|
489
|
+
};
|
|
490
|
+
const quarterNumber = (value) => {
|
|
491
|
+
if ((value.startsWith("q") || value.startsWith("t")) && value.length === 2) return Number(value.slice(1));
|
|
492
|
+
if (value === "primer" || value === "primero") return 1;
|
|
493
|
+
if (value === "segundo") return 2;
|
|
494
|
+
if (value === "tercer" || value === "tercero") return 3;
|
|
495
|
+
return value === "cuarto" ? 4 : void 0;
|
|
496
|
+
};
|
|
497
|
+
const parseQuarter = (input) => {
|
|
498
|
+
const fixed = String$1.match(/^(t[1-4]|q[1-4]|primer|primero|segundo|tercer|tercero|cuarto)(?: trimestre)?(?: de)? (\d{4})$/u)(input);
|
|
499
|
+
if (Option.isSome(fixed)) {
|
|
500
|
+
const quarter = quarterNumber(textAt(fixed.value, 1));
|
|
501
|
+
const year = validYear(textAt(fixed.value, 2));
|
|
502
|
+
if (quarter !== void 0 && year !== void 0) return Option.some(fixedQuarterPeriod(year, quarter, `T${quarter} ${year}`));
|
|
503
|
+
}
|
|
504
|
+
const relative = String$1.match(/^(t[1-4]|q[1-4]) (?:del (año pasado|ano pasado|próximo año|proximo año)|de (este año|este ano))$/u)(input);
|
|
505
|
+
if (Option.isSome(relative)) {
|
|
506
|
+
const quarter = quarterNumber(textAt(relative.value, 1));
|
|
507
|
+
const yearText = textAt(relative.value, 2) || textAt(relative.value, 3);
|
|
508
|
+
const direction = relativeYearDirection(yearText);
|
|
509
|
+
if (quarter !== void 0) return Option.some(quarterOfRelativeYear(quarter, direction, `T${quarter} del ${relativeYearName(direction)}`));
|
|
510
|
+
}
|
|
511
|
+
const standalone = String$1.match(/^(?:el )?(t[1-4]|q[1-4])$/u)(input);
|
|
512
|
+
if (Option.isNone(standalone)) return Option.none();
|
|
513
|
+
const quarter = quarterNumber(textAt(standalone.value, 1));
|
|
514
|
+
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `T${quarter}`));
|
|
515
|
+
};
|
|
516
|
+
const parseBasePeriod = (input) => {
|
|
517
|
+
const absoluteDate = absoluteDatePeriod(input, "es");
|
|
518
|
+
if (Option.isSome(absoluteDate)) return absoluteDate;
|
|
519
|
+
const namedDate = parseNamedDate(input);
|
|
520
|
+
if (Option.isSome(namedDate)) return namedDate;
|
|
521
|
+
const quarter = parseQuarter(input);
|
|
522
|
+
if (Option.isSome(quarter)) return quarter;
|
|
523
|
+
const yearMatch = String$1.match(/^(?:(?:el )?año )?(\d{4})$/u)(input);
|
|
524
|
+
if (Option.isSome(yearMatch)) {
|
|
525
|
+
const year = validYear(textAt(yearMatch.value, 1));
|
|
526
|
+
if (year !== void 0) return Option.some(fixedYearPeriod(year, String(year)));
|
|
527
|
+
}
|
|
528
|
+
const monthYear = String$1.match(/^([a-záéíóúñ]+\.?)(?: de)? (\d{4})$/u)(input);
|
|
529
|
+
if (Option.isSome(monthYear)) {
|
|
530
|
+
const month = monthNumber(textAt(monthYear.value, 1));
|
|
531
|
+
const year = validYear(textAt(monthYear.value, 2));
|
|
532
|
+
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${textAt(months, month - 1)} de ${year}`));
|
|
533
|
+
}
|
|
534
|
+
const relativeMonth = String$1.match(/^([a-záéíóúñ]+\.?) (del año pasado|del ano pasado|del próximo año|del proximo año|de este año|de este ano)$/u)(input);
|
|
535
|
+
if (Option.isSome(relativeMonth)) {
|
|
536
|
+
const month = monthNumber(textAt(relativeMonth.value, 1));
|
|
537
|
+
const yearText = textAt(relativeMonth.value, 2);
|
|
538
|
+
const direction = relativeYearDirection(yearText);
|
|
539
|
+
if (month !== void 0) {
|
|
540
|
+
const canonicalYear = relativeYearName(direction);
|
|
541
|
+
return Option.some(monthOfRelativeYear(month, direction, `${textAt(months, month - 1)} del ${canonicalYear}`));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
const standaloneMonth = monthNumber(input);
|
|
545
|
+
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, textAt(months, standaloneMonth - 1)));
|
|
546
|
+
const alias = periodAliases.find((entry) => entry[0] === input);
|
|
547
|
+
if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
|
|
548
|
+
if ([
|
|
549
|
+
"fin de semana",
|
|
550
|
+
"el fin de semana",
|
|
551
|
+
"este fin de semana"
|
|
552
|
+
].includes(input)) return Option.some(relativeWeekend(0, "este fin de semana"));
|
|
553
|
+
if (["el fin de semana pasado", "fin de semana pasado"].includes(input)) return Option.some(relativeWeekend(-1, "el fin de semana pasado"));
|
|
554
|
+
if (["el próximo fin de semana", "el proximo fin de semana"].includes(input)) return Option.some(relativeWeekend(1, "el próximo fin de semana"));
|
|
555
|
+
if (input === "el fin de semana anterior al pasado") return Option.some(relativeWeekend(-2, input));
|
|
556
|
+
if (input === "el fin de semana después del próximo") return Option.some(relativeWeekend(2, input));
|
|
557
|
+
return Option.none();
|
|
558
|
+
};
|
|
559
|
+
const parsePeriod = (input) => {
|
|
560
|
+
const edge = String$1.match(/^(?:el )?(inicio|comienzo|principio|fin|final)(?: de| del) (.+)$/u)(input);
|
|
561
|
+
if (Option.isSome(edge)) {
|
|
562
|
+
const edgeName = textAt(edge.value, 1);
|
|
563
|
+
const period = parseBasePeriod(textAt(edge.value, 2));
|
|
564
|
+
if (Option.isSome(period)) {
|
|
565
|
+
const isEnd = edgeName === "fin" || edgeName === "final";
|
|
566
|
+
const canonical = `${isEnd ? "final" : "inicio"} ${withDe(period.value.canonical)}`;
|
|
567
|
+
return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
const wrapper = [
|
|
571
|
+
"durante ",
|
|
572
|
+
"en ",
|
|
573
|
+
"todo ",
|
|
574
|
+
"todo el ",
|
|
575
|
+
"toda la "
|
|
576
|
+
].find((prefix) => input.startsWith(prefix));
|
|
577
|
+
return parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
578
|
+
};
|
|
579
|
+
const countedUnit = (value, amount) => {
|
|
580
|
+
const alias = unitAliases.find((entry) => entry[0] === value && entry[2] === (amount !== 1));
|
|
581
|
+
return alias === void 0 ? void 0 : units.find((entry) => entry.unit === alias[1]);
|
|
582
|
+
};
|
|
583
|
+
const writtenAmount = (value) => value === "un" || value === "una" ? Option.some(1) : parseTrailingCount(value);
|
|
584
|
+
const agreesWithArticle = (entry, article, plural = false) => article.length === 0 || article === definiteArticle(entry, plural);
|
|
585
|
+
const agreesWithIndefiniteArticle = (entry, article) => article === indefiniteArticle(entry);
|
|
586
|
+
const withoutAcute = (value) => value.normalize("NFD").replaceAll("́", "");
|
|
587
|
+
const agreesWithRollingModifier = (entry, modifier, future) => {
|
|
588
|
+
if (modifier === "anteriores" || modifier === "siguientes") return true;
|
|
589
|
+
if (!future && modifier === gendered(entry, "pasados", "pasadas")) return true;
|
|
590
|
+
const expected = rollingAdjective(entry, future, true);
|
|
591
|
+
return modifier === expected || modifier === withoutAcute(expected);
|
|
592
|
+
};
|
|
593
|
+
const agreesWithSingularModifier = (entry, modifier, future) => {
|
|
594
|
+
if (entry === void 0) return false;
|
|
595
|
+
if (future && modifier === "siguiente") return true;
|
|
596
|
+
const expected = rollingAdjective(entry, future, false);
|
|
597
|
+
return modifier === expected || modifier === withoutAcute(expected);
|
|
598
|
+
};
|
|
599
|
+
const parseCalendarOffset = (input) => {
|
|
600
|
+
const match = String$1.match(/^(hace|dentro de|en) ([1-9]\d*|un|una) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
601
|
+
if (Option.isNone(match)) return Option.none();
|
|
602
|
+
const amount = writtenAmount(textAt(match.value, 2));
|
|
603
|
+
if (Option.isNone(amount)) return Option.none();
|
|
604
|
+
const entry = countedUnit(textAt(match.value, 3), amount.value);
|
|
605
|
+
const amountText = textAt(match.value, 2);
|
|
606
|
+
if (entry === void 0 || (amountText === "un" || amountText === "una") && !agreesWithIndefiniteArticle(entry, amountText)) return Option.none();
|
|
607
|
+
const isPast = textAt(match.value, 1) === "hace";
|
|
608
|
+
const quantity = amount.value === 1 ? indefiniteArticle(entry) : String(amount.value);
|
|
609
|
+
const noun = amount.value === 1 ? entry.singular : entry.plural;
|
|
610
|
+
const canonical = `${isPast ? "hace" : "dentro de"} ${quantity} ${noun}`;
|
|
611
|
+
const direction = isPast ? -amount.value : amount.value;
|
|
612
|
+
return Option.some(candidate(periodRange(relativePeriod(entry.unit, direction, canonical)), canonical));
|
|
613
|
+
};
|
|
614
|
+
const rollingCanonical = (entry, amount, future) => {
|
|
615
|
+
if (amount > 1) return `${rollingAdjective(entry, future, true)} ${amount} ${entry.plural}`;
|
|
616
|
+
const article = indefiniteArticle(entry);
|
|
617
|
+
return future ? `desde ahora durante ${article} ${entry.singular}` : `desde hace ${article} ${entry.singular}`;
|
|
618
|
+
};
|
|
619
|
+
const rollingCandidate = (entry, amount, future) => candidate(future ? futureRange(amount, entry.unit) : trailingRange(amount, entry.unit), rollingCanonical(entry, amount, future));
|
|
620
|
+
const parseRollingPeriod = (input) => {
|
|
621
|
+
const since = String$1.match(/^desde hace ([1-9]\d*|un|una) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
622
|
+
if (Option.isSome(since)) {
|
|
623
|
+
const amount = writtenAmount(textAt(since.value, 1));
|
|
624
|
+
if (Option.isSome(amount)) {
|
|
625
|
+
const entry = countedUnit(textAt(since.value, 2), amount.value);
|
|
626
|
+
const amountText = textAt(since.value, 1);
|
|
627
|
+
if (entry !== void 0 && (amountText !== "un" && amountText !== "una" || agreesWithIndefiniteArticle(entry, amountText))) return Option.some(rollingCandidate(entry, amount.value, false));
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
const futureSingular = String$1.match(/^desde ahora durante (un|una) (día|dia|semana|mes|trimestre|año|ano)$/u)(input);
|
|
631
|
+
if (Option.isSome(futureSingular)) {
|
|
632
|
+
const entry = countedUnit(textAt(futureSingular.value, 2), 1);
|
|
633
|
+
if (entry !== void 0 && agreesWithIndefiniteArticle(entry, textAt(futureSingular.value, 1))) return Option.some(rollingCandidate(entry, 1, true));
|
|
634
|
+
}
|
|
635
|
+
const lastSingular = String$1.match(/^(?:(?:durante|en) )?(?:este )?(?:(el|la) )?(último|ultimo|última|ultima) (día|dia|semana|mes|trimestre|año|ano)$/u)(input);
|
|
636
|
+
if (Option.isSome(lastSingular)) {
|
|
637
|
+
const entry = countedUnit(textAt(lastSingular.value, 3), 1);
|
|
638
|
+
const modifier = textAt(lastSingular.value, 2);
|
|
639
|
+
if (entry !== void 0 && agreesWithArticle(entry, textAt(lastSingular.value, 1)) && agreesWithSingularModifier(entry, modifier, false)) return Option.some(rollingCandidate(entry, 1, false));
|
|
640
|
+
}
|
|
641
|
+
const nextSingular = String$1.match(/^durante (el|la) (próximo|proximo|próxima|proxima|siguiente) (día|dia|semana|mes|trimestre|año|ano)$/u)(input);
|
|
642
|
+
if (Option.isSome(nextSingular)) {
|
|
643
|
+
const entry = countedUnit(textAt(nextSingular.value, 3), 1);
|
|
644
|
+
const modifier = textAt(nextSingular.value, 2);
|
|
645
|
+
if (entry !== void 0 && agreesWithArticle(entry, textAt(nextSingular.value, 1)) && agreesWithSingularModifier(entry, modifier, true)) return Option.some(rollingCandidate(entry, 1, true));
|
|
646
|
+
}
|
|
647
|
+
const counted = String$1.match(/^(?:(?:durante|en) )?(?:(los|las) )?(últimos|ultimos|últimas|ultimas|pasados|pasadas|anteriores|próximos|proximos|próximas|proximas|siguientes) ([1-9]\d*) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
648
|
+
if (Option.isSome(counted)) {
|
|
649
|
+
const amount = parseTrailingCount(textAt(counted.value, 3));
|
|
650
|
+
if (Option.isSome(amount) && amount.value > 1) {
|
|
651
|
+
const entry = countedUnit(textAt(counted.value, 4), amount.value);
|
|
652
|
+
const modifier = textAt(counted.value, 2);
|
|
653
|
+
const future = modifier.startsWith("próxim") || modifier.startsWith("proxim") || modifier === "siguientes";
|
|
654
|
+
if (entry !== void 0 && agreesWithArticle(entry, textAt(counted.value, 1), true) && agreesWithRollingModifier(entry, modifier, future)) return Option.some(rollingCandidate(entry, amount.value, future));
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
const bare = String$1.match(/^([1-9]\d*) (día|dia|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
658
|
+
if (Option.isNone(bare)) return Option.none();
|
|
659
|
+
const amount = parseTrailingCount(textAt(bare.value, 1));
|
|
660
|
+
if (Option.isNone(amount)) return Option.none();
|
|
661
|
+
const entry = countedUnit(textAt(bare.value, 2), amount.value);
|
|
662
|
+
return entry === void 0 ? Option.none() : Option.some(rollingCandidate(entry, amount.value, false));
|
|
663
|
+
};
|
|
664
|
+
const parseElidedDateRange = (input) => {
|
|
665
|
+
const joined = String$1.match(/^(?:(?:del|desde(?: el)?) ([0-3]?\d) (?:al|hasta(?: el)?)|entre(?: el)? ([0-3]?\d) y(?: el)?) ([0-3]?\d) (.+)$/u)(input);
|
|
666
|
+
const dashed = String$1.match(/^([0-3]?\d)[–—-]([0-3]?\d) (.+)$/u)(input);
|
|
667
|
+
const match = Option.firstSomeOf([joined, dashed]);
|
|
668
|
+
if (Option.isNone(match)) return Option.none();
|
|
669
|
+
const isJoined = Option.isSome(joined);
|
|
670
|
+
const lowerDay = textAt(match.value, 1) || textAt(match.value, 2);
|
|
671
|
+
const upperDay = textAt(match.value, isJoined ? 3 : 2);
|
|
672
|
+
const period = afterDe(textAt(match.value, isJoined ? 4 : 3));
|
|
673
|
+
return joinedPeriodCandidate(`desde ${lowerDay} ${withDe(period)} hasta ${upperDay} ${withDe(period)}`, [["desde ", " hasta "]], parsePeriod, (lower, upper) => `desde ${lower} hasta ${upper}`);
|
|
674
|
+
};
|
|
675
|
+
const inclusiveBoundaryCandidate = (input) => {
|
|
676
|
+
const match = String$1.match(/^hasta (.+) inclusive$/u)(input);
|
|
677
|
+
if (Option.isNone(match)) return Option.none();
|
|
678
|
+
return parsePeriod(textAt(match.value, 1)).pipe(Option.map((value) => periodBoundaryCandidate(value, "through", `hasta ${value.canonical} inclusive`)));
|
|
679
|
+
};
|
|
680
|
+
const boundaryCandidate = (input) => openBoundaryCandidate(input, [
|
|
681
|
+
["hasta antes de ", "before"],
|
|
682
|
+
["hasta el inicio de ", "before"],
|
|
683
|
+
["hasta e incluyendo ", "through"],
|
|
684
|
+
["hasta inclusive ", "through"],
|
|
685
|
+
["a partir de ", "since"],
|
|
686
|
+
["desde ", "since"],
|
|
687
|
+
["antes de ", "before"],
|
|
688
|
+
["hasta ", "through"],
|
|
689
|
+
["después de ", "after"],
|
|
690
|
+
["despues de ", "after"]
|
|
691
|
+
], parsePeriod);
|
|
692
|
+
const parseSpanish = (input) => {
|
|
693
|
+
const remaining = remainingPhrases.find((entry) => entry.phrase === input);
|
|
694
|
+
if (remaining !== void 0) return Option.some(candidate(remainingPeriodRange(remaining.entry.unit), remaining.entry.remaining));
|
|
695
|
+
if (["hasta hoy", "hasta ahora"].includes(input)) return Option.some(candidate(untilNowRange(), "hasta ahora"));
|
|
696
|
+
if ([
|
|
697
|
+
"desde ahora",
|
|
698
|
+
"a partir de ahora",
|
|
699
|
+
"de ahora en adelante"
|
|
700
|
+
].includes(input)) return Option.some(candidate(fromNowRange(), "desde ahora"));
|
|
701
|
+
const offset = parseCalendarOffset(input);
|
|
702
|
+
if (Option.isSome(offset)) return offset;
|
|
703
|
+
const rolling = parseRollingPeriod(input);
|
|
704
|
+
if (Option.isSome(rolling)) return rolling;
|
|
705
|
+
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
706
|
+
if (toDate !== void 0) return Option.some(candidate(periodToDateRange(toDate.entry.unit), toDate.entry.toDate));
|
|
707
|
+
const elided = parseElidedDateRange(input);
|
|
708
|
+
if (Option.isSome(elided)) return elided;
|
|
709
|
+
const nowBounded = joinedNowCandidate(input, [
|
|
710
|
+
["desde ", " hasta ahora"],
|
|
711
|
+
["desde ", " hasta hoy"],
|
|
712
|
+
["entre ", " y hoy"]
|
|
713
|
+
], [
|
|
714
|
+
"desde ahora hasta ",
|
|
715
|
+
"desde hoy hasta ",
|
|
716
|
+
"entre hoy y ",
|
|
717
|
+
"entre hoy y el "
|
|
718
|
+
], parsePeriod, (period) => `desde ${period} hasta ahora`, (period) => `desde ahora hasta ${period}`);
|
|
719
|
+
if (Option.isSome(nowBounded)) return nowBounded;
|
|
720
|
+
const bounded = joinedPeriodCandidate(input, [
|
|
721
|
+
["desde el ", " hasta el "],
|
|
722
|
+
["desde ", " hasta "],
|
|
723
|
+
["del ", " al "],
|
|
724
|
+
["de ", " a "],
|
|
725
|
+
["entre el ", " y el "],
|
|
726
|
+
["entre ", " y "],
|
|
727
|
+
["", " - "],
|
|
728
|
+
["", " – "],
|
|
729
|
+
["", " — "],
|
|
730
|
+
["", " hasta "]
|
|
731
|
+
], parsePeriod, (lower, upper) => `desde ${lower} hasta ${upper}`);
|
|
732
|
+
if (Option.isSome(bounded)) return bounded;
|
|
733
|
+
const inclusive = inclusiveBoundaryCandidate(input);
|
|
734
|
+
if (Option.isSome(inclusive)) return inclusive;
|
|
735
|
+
const boundary = boundaryCandidate(input);
|
|
736
|
+
if (Option.isSome(boundary)) return boundary;
|
|
737
|
+
return parsePeriod(input).pipe(Option.map((period) => candidate(periodRange(period), period.canonical)));
|
|
738
|
+
};
|
|
739
|
+
const weekendPhrases = [
|
|
740
|
+
"este fin de semana",
|
|
741
|
+
"el fin de semana pasado",
|
|
742
|
+
"el próximo fin de semana",
|
|
743
|
+
"el fin de semana anterior al pasado",
|
|
744
|
+
"el fin de semana después del próximo"
|
|
745
|
+
];
|
|
746
|
+
const edgePeriodPhrases = [
|
|
747
|
+
...units.filter((entry) => entry.unit !== "day").flatMap((entry) => [
|
|
748
|
+
entry.current,
|
|
749
|
+
entry.previous,
|
|
750
|
+
entry.next
|
|
751
|
+
]),
|
|
752
|
+
...weekendPhrases,
|
|
753
|
+
...months
|
|
754
|
+
].flatMap((period) => [`inicio ${withDe(period)}`, `final ${withDe(period)}`]);
|
|
755
|
+
const staticPeriodPhrases = [
|
|
756
|
+
...periodAliases.map((entry) => entry[0]),
|
|
757
|
+
...weekendPhrases,
|
|
758
|
+
...edgePeriodPhrases,
|
|
759
|
+
...[
|
|
760
|
+
1,
|
|
761
|
+
2,
|
|
762
|
+
3,
|
|
763
|
+
4
|
|
764
|
+
].flatMap((quarter) => [
|
|
765
|
+
`t${quarter}`,
|
|
766
|
+
`t${quarter} de este año`,
|
|
767
|
+
`t${quarter} del año pasado`,
|
|
768
|
+
`t${quarter} del próximo año`
|
|
769
|
+
]),
|
|
770
|
+
...months.flatMap((month) => [
|
|
771
|
+
month,
|
|
772
|
+
`${month} del año pasado`,
|
|
773
|
+
`${month} del próximo año`
|
|
774
|
+
])
|
|
775
|
+
];
|
|
776
|
+
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
777
|
+
const boundaryPrefixes = [
|
|
778
|
+
"desde ",
|
|
779
|
+
"a partir de ",
|
|
780
|
+
"antes de ",
|
|
781
|
+
"hasta ",
|
|
782
|
+
"después de "
|
|
783
|
+
];
|
|
784
|
+
const countedSuggestions = (input) => {
|
|
785
|
+
const amount = naturalCount(input);
|
|
786
|
+
if (amount === void 0) return [];
|
|
787
|
+
return units.flatMap((entry) => {
|
|
788
|
+
const noun = amount === 1 ? entry.singular : entry.plural;
|
|
789
|
+
if (amount === 1) {
|
|
790
|
+
const article = indefiniteArticle(entry);
|
|
791
|
+
return [
|
|
792
|
+
`${amount} ${noun}`,
|
|
793
|
+
`${rollingAdjective(entry, false, false)} ${noun}`,
|
|
794
|
+
`desde hace ${article} ${noun}`,
|
|
795
|
+
`desde ahora durante ${article} ${noun}`,
|
|
796
|
+
`hace ${article} ${noun}`,
|
|
797
|
+
`dentro de ${article} ${noun}`
|
|
798
|
+
];
|
|
799
|
+
}
|
|
800
|
+
return [
|
|
801
|
+
`${rollingAdjective(entry, false, true)} ${amount} ${noun}`,
|
|
802
|
+
`${amount} ${noun}`,
|
|
803
|
+
`${rollingAdjective(entry, true, true)} ${amount} ${noun}`,
|
|
804
|
+
`hace ${amount} ${noun}`,
|
|
805
|
+
`dentro de ${amount} ${noun}`
|
|
806
|
+
];
|
|
807
|
+
});
|
|
808
|
+
};
|
|
809
|
+
const spanishSuggestionPhrases = [
|
|
810
|
+
...units.map((entry) => entry.toDate),
|
|
811
|
+
...units.map((entry) => entry.remaining),
|
|
812
|
+
...units.flatMap((entry) => [
|
|
813
|
+
`${rollingAdjective(entry, false, false)} ${entry.singular}`,
|
|
814
|
+
`desde hace ${indefiniteArticle(entry)} ${entry.singular}`,
|
|
815
|
+
`desde ahora durante ${indefiniteArticle(entry)} ${entry.singular}`,
|
|
816
|
+
`durante ${definiteArticle(entry)} ${rollingAdjective(entry, true, false)} ${entry.singular}`
|
|
817
|
+
]),
|
|
818
|
+
...staticPeriodPhrases,
|
|
819
|
+
...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
|
|
820
|
+
"hasta ahora",
|
|
821
|
+
"desde ahora"
|
|
822
|
+
];
|
|
823
|
+
const suggestSpanish = (input, limit) => {
|
|
824
|
+
const fixed = fixedCalendarPeriodPhrases(input, months);
|
|
825
|
+
return completeNaturalPhrases(input, [
|
|
826
|
+
...spanishSuggestionPhrases,
|
|
827
|
+
...fixed,
|
|
828
|
+
...prefixNaturalPhrases(fixed, boundaryPrefixes),
|
|
829
|
+
...countedSuggestions(input)
|
|
830
|
+
], limit);
|
|
831
|
+
};
|
|
832
|
+
const renderSpanish = (range) => {
|
|
833
|
+
const offset = calendarPeriodOffset(range);
|
|
834
|
+
if (Option.isSome(offset) && Math.abs(offset.value.amount) > 1) {
|
|
835
|
+
const entry = units.find((unit) => unit.unit === offset.value.unit);
|
|
836
|
+
if (entry !== void 0) {
|
|
837
|
+
const amount = Math.abs(offset.value.amount);
|
|
838
|
+
const noun = amount === 1 ? entry.singular : entry.plural;
|
|
839
|
+
return Option.some(offset.value.amount < 0 ? `hace ${amount} ${noun}` : `dentro de ${amount} ${noun}`);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
const future = futurePeriod(range);
|
|
843
|
+
if (Option.isSome(future)) {
|
|
844
|
+
const entry = units.find((unit) => unit.unit === future.value.unit);
|
|
845
|
+
if (entry !== void 0) return Option.some(rollingCanonical(entry, future.value.amount, true));
|
|
846
|
+
}
|
|
847
|
+
const trailing = trailingPeriod(range);
|
|
848
|
+
if (Option.isSome(trailing)) {
|
|
849
|
+
const entry = units.find((unit) => unit.unit === trailing.value.unit);
|
|
850
|
+
if (entry !== void 0) return Option.some(rollingCanonical(entry, trailing.value.amount, false));
|
|
851
|
+
}
|
|
852
|
+
const periods = [
|
|
853
|
+
...staticPeriods,
|
|
854
|
+
...currentYearDatePeriods(range, currentDateLabel),
|
|
855
|
+
...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)
|
|
856
|
+
];
|
|
857
|
+
return renderPeriodRange(range, [...units.map((entry) => candidate(periodToDateRange(entry.unit), entry.toDate)), ...units.map((entry) => candidate(remainingPeriodRange(entry.unit), entry.remaining))], periods, (period) => `desde ${period}`, (period) => `antes de ${period}`, (period) => `hasta ${period}`, (period) => `después de ${period}`, (lower, upper) => `desde ${lower} hasta ${upper}`, (period) => `desde ${period} hasta ahora`, (period) => `desde ahora hasta ${period}`, () => "hasta ahora", () => "desde ahora");
|
|
858
|
+
};
|
|
859
|
+
const SpanishContribution = new BaseLanguageContribution({
|
|
860
|
+
locale: "es",
|
|
861
|
+
vocabulary: [
|
|
862
|
+
...months,
|
|
863
|
+
...monthAbbreviations.flatMap((aliases) => aliases),
|
|
864
|
+
...units.flatMap((entry) => [
|
|
865
|
+
entry.singular,
|
|
866
|
+
entry.plural,
|
|
867
|
+
...entry.current.split(" "),
|
|
868
|
+
...entry.previous.split(" "),
|
|
869
|
+
...entry.next.split(" ")
|
|
870
|
+
]),
|
|
871
|
+
...toDatePhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
872
|
+
...remainingPhrases.flatMap((entry) => entry.phrase.split(" ")),
|
|
873
|
+
"a",
|
|
874
|
+
"ahora",
|
|
875
|
+
"antes",
|
|
876
|
+
"año",
|
|
877
|
+
"comienzo",
|
|
878
|
+
"de",
|
|
879
|
+
"desde",
|
|
880
|
+
"después",
|
|
881
|
+
"durante",
|
|
882
|
+
"entre",
|
|
883
|
+
"fecha",
|
|
884
|
+
"final",
|
|
885
|
+
"fin",
|
|
886
|
+
"hace",
|
|
887
|
+
"hasta",
|
|
888
|
+
"incluyendo",
|
|
889
|
+
"inicio",
|
|
890
|
+
"pasado",
|
|
891
|
+
"principio",
|
|
892
|
+
"próximo",
|
|
893
|
+
"resto",
|
|
894
|
+
"últimos"
|
|
895
|
+
],
|
|
896
|
+
normalize: normalizeNaturalText,
|
|
897
|
+
correct: correctWhitespaceSeparatedText,
|
|
898
|
+
parseExact: parseSpanish,
|
|
899
|
+
suggest: suggestSpanish,
|
|
900
|
+
render: renderSpanish
|
|
901
|
+
});
|
|
902
|
+
const SpanishLanguage = defineLanguagePlugin({
|
|
903
|
+
id: "chronolizer/language-es",
|
|
904
|
+
effect: (context) => Effect.asVoid(context.register("chronolizer/language-es", SpanishContribution))
|
|
905
|
+
});
|
|
906
|
+
const SpanishLanguageLayer = languagePluginsLayer([SpanishLanguage]);
|
|
907
|
+
//#endregion
|
|
908
|
+
export { SpanishContribution, SpanishLanguage, SpanishLanguageLayer };
|