chronolizer 0.2.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 +169 -167
- package/dist/ast/constructors.d.mts +3 -8
- package/dist/ast/fold.d.mts +2 -1
- package/dist/ast/fold.mjs +38 -31
- package/dist/ast/normalize.mjs +4 -2
- package/dist/ast/schemas.d.mts +18 -25
- package/dist/ast/schemas.mjs +8 -17
- package/dist/filter/expression.mjs +3 -20
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +2 -2
- package/dist/language/model.d.mts +33 -33
- package/dist/language/model.mjs +4 -7
- package/dist/language/registry.mjs +3 -21
- package/dist/locales/cs.mjs +70 -17
- package/dist/locales/de.mjs +237 -26
- package/dist/locales/en.mjs +69 -21
- package/dist/locales/es.mjs +325 -77
- package/dist/locales/fr.mjs +215 -51
- package/dist/locales/nl.mjs +189 -50
- package/dist/locales/pl.mjs +295 -121
- package/dist/locales/shared.mjs +129 -23
- package/dist/locales/tr.mjs +86 -21
- package/dist/natural/parse.d.mts +1 -1
- package/dist/natural/policy.mjs +2 -2
- package/dist/resolve/resolve.mjs +1 -9
- package/package.json +1 -1
package/dist/locales/es.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { normalizeNaturalText } from "../natural/text.mjs";
|
|
|
4
4
|
import { defineLanguagePlugin, languagePluginsLayer } from "../language/registry.mjs";
|
|
5
5
|
import { correctWhitespaceSeparatedText } from "../natural/correction.mjs";
|
|
6
6
|
import { completeNaturalPhrases, fixedCalendarPeriodPhrases, naturalCount, prefixNaturalPhrases } from "../natural/suggestion.mjs";
|
|
7
|
-
import { calendarPeriodOffset, candidate, datedPeriods, datedQuarterPeriods, fixedDatePeriod, fixedMonthPeriod, fixedQuarterPeriod, fixedYearPeriod, fromNowRange, futurePeriod, futureRange, isoDate, joinedNowCandidate, joinedPeriodCandidate, monthOfRelativeYear, namedDatePeriod, openBoundaryCandidate, parseTrailingCount, periodEndDay, periodRange, periodStartDay, periodToDateRange, periodsFromPhrases, quarterOfRelativeYear, relativePeriod, relativeWeekend, remainingPeriodRange, renderPeriodRange, textAt, trailingPeriod, trailingRange, untilNowRange, validYear } from "./shared.mjs";
|
|
7
|
+
import { absoluteDatePeriod, calendarPeriodOffset, candidate, 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
8
|
import { Effect, Option, String as String$1 } from "effect";
|
|
9
9
|
//#region src/locales/es.ts
|
|
10
10
|
const months = [
|
|
@@ -45,6 +45,7 @@ const units = [
|
|
|
45
45
|
unit: "day",
|
|
46
46
|
singular: "día",
|
|
47
47
|
plural: "días",
|
|
48
|
+
gender: "masculine",
|
|
48
49
|
current: "hoy",
|
|
49
50
|
previous: "ayer",
|
|
50
51
|
next: "mañana",
|
|
@@ -55,6 +56,7 @@ const units = [
|
|
|
55
56
|
unit: "week",
|
|
56
57
|
singular: "semana",
|
|
57
58
|
plural: "semanas",
|
|
59
|
+
gender: "feminine",
|
|
58
60
|
current: "esta semana",
|
|
59
61
|
previous: "la semana pasada",
|
|
60
62
|
next: "la próxima semana",
|
|
@@ -65,6 +67,7 @@ const units = [
|
|
|
65
67
|
unit: "month",
|
|
66
68
|
singular: "mes",
|
|
67
69
|
plural: "meses",
|
|
70
|
+
gender: "masculine",
|
|
68
71
|
current: "este mes",
|
|
69
72
|
previous: "el mes pasado",
|
|
70
73
|
next: "el próximo mes",
|
|
@@ -75,6 +78,7 @@ const units = [
|
|
|
75
78
|
unit: "quarter",
|
|
76
79
|
singular: "trimestre",
|
|
77
80
|
plural: "trimestres",
|
|
81
|
+
gender: "masculine",
|
|
78
82
|
current: "este trimestre",
|
|
79
83
|
previous: "el trimestre pasado",
|
|
80
84
|
next: "el próximo trimestre",
|
|
@@ -85,6 +89,7 @@ const units = [
|
|
|
85
89
|
unit: "year",
|
|
86
90
|
singular: "año",
|
|
87
91
|
plural: "años",
|
|
92
|
+
gender: "masculine",
|
|
88
93
|
current: "este año",
|
|
89
94
|
previous: "el año pasado",
|
|
90
95
|
next: "el próximo año",
|
|
@@ -92,21 +97,89 @@ const units = [
|
|
|
92
97
|
remaining: "resto del año"
|
|
93
98
|
}
|
|
94
99
|
];
|
|
95
|
-
const
|
|
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
|
+
};
|
|
96
112
|
const unitAliases = [
|
|
97
|
-
[
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
[
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
[
|
|
108
|
-
|
|
109
|
-
|
|
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
|
+
]
|
|
110
183
|
];
|
|
111
184
|
const periodAliases = [
|
|
112
185
|
...units.flatMap((entry) => [
|
|
@@ -129,6 +202,44 @@ const periodAliases = [
|
|
|
129
202
|
entry.next
|
|
130
203
|
]
|
|
131
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
|
+
]),
|
|
132
243
|
[
|
|
133
244
|
"semana pasada",
|
|
134
245
|
"week",
|
|
@@ -237,12 +348,36 @@ const periodAliases = [
|
|
|
237
348
|
-2,
|
|
238
349
|
"anteayer"
|
|
239
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
|
+
],
|
|
240
363
|
[
|
|
241
364
|
"pasado mañana",
|
|
242
365
|
"day",
|
|
243
366
|
2,
|
|
244
367
|
"pasado mañana"
|
|
245
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
|
+
],
|
|
246
381
|
[
|
|
247
382
|
"la semana anterior a la pasada",
|
|
248
383
|
"week",
|
|
@@ -327,17 +462,30 @@ const monthNumber = (value) => {
|
|
|
327
462
|
const short = monthAbbreviations.findIndex((aliases) => aliases.some((alias) => alias === normalized));
|
|
328
463
|
return short === -1 ? void 0 : short + 1;
|
|
329
464
|
};
|
|
465
|
+
const currentDateLabel = (day, month) => `${day} de ${textAt(months, month - 1)}`;
|
|
330
466
|
const parseNamedDate = (input) => {
|
|
331
|
-
const named = String$1.match(/^([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)(?: de)? (\d{4})$/u)(input);
|
|
467
|
+
const named = String$1.match(/^(?:el (?:día )?)?([0-3]?\d)(?: de)? ([a-záéíóúñ]+\.?)(?:(?: de| del)? (\d{4}))$/u)(input);
|
|
332
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}`);
|
|
333
469
|
const numeric = String$1.match(/^([0-3]?\d)[./-]([01]?\d)[./-](\d{4})$/u)(input);
|
|
334
|
-
if (Option.
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
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])}`);
|
|
341
489
|
};
|
|
342
490
|
const quarterNumber = (value) => {
|
|
343
491
|
if ((value.startsWith("q") || value.startsWith("t")) && value.length === 2) return Number(value.slice(1));
|
|
@@ -366,7 +514,8 @@ const parseQuarter = (input) => {
|
|
|
366
514
|
return quarter === void 0 ? Option.none() : Option.some(quarterOfRelativeYear(quarter, 0, `T${quarter}`));
|
|
367
515
|
};
|
|
368
516
|
const parseBasePeriod = (input) => {
|
|
369
|
-
|
|
517
|
+
const absoluteDate = absoluteDatePeriod(input, "es");
|
|
518
|
+
if (Option.isSome(absoluteDate)) return absoluteDate;
|
|
370
519
|
const namedDate = parseNamedDate(input);
|
|
371
520
|
if (Option.isSome(namedDate)) return namedDate;
|
|
372
521
|
const quarter = parseQuarter(input);
|
|
@@ -380,7 +529,7 @@ const parseBasePeriod = (input) => {
|
|
|
380
529
|
if (Option.isSome(monthYear)) {
|
|
381
530
|
const month = monthNumber(textAt(monthYear.value, 1));
|
|
382
531
|
const year = validYear(textAt(monthYear.value, 2));
|
|
383
|
-
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${
|
|
532
|
+
if (month !== void 0 && year !== void 0) return Option.some(fixedMonthPeriod(year, month, `${textAt(months, month - 1)} de ${year}`));
|
|
384
533
|
}
|
|
385
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);
|
|
386
535
|
if (Option.isSome(relativeMonth)) {
|
|
@@ -389,11 +538,11 @@ const parseBasePeriod = (input) => {
|
|
|
389
538
|
const direction = relativeYearDirection(yearText);
|
|
390
539
|
if (month !== void 0) {
|
|
391
540
|
const canonicalYear = relativeYearName(direction);
|
|
392
|
-
return Option.some(monthOfRelativeYear(month, direction, `${
|
|
541
|
+
return Option.some(monthOfRelativeYear(month, direction, `${textAt(months, month - 1)} del ${canonicalYear}`));
|
|
393
542
|
}
|
|
394
543
|
}
|
|
395
544
|
const standaloneMonth = monthNumber(input);
|
|
396
|
-
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0,
|
|
545
|
+
if (standaloneMonth !== void 0) return Option.some(monthOfRelativeYear(standaloneMonth, 0, textAt(months, standaloneMonth - 1)));
|
|
397
546
|
const alias = periodAliases.find((entry) => entry[0] === input);
|
|
398
547
|
if (alias !== void 0) return Option.some(relativePeriod(alias[1], alias[2], alias[3]));
|
|
399
548
|
if ([
|
|
@@ -414,7 +563,7 @@ const parsePeriod = (input) => {
|
|
|
414
563
|
const period = parseBasePeriod(textAt(edge.value, 2));
|
|
415
564
|
if (Option.isSome(period)) {
|
|
416
565
|
const isEnd = edgeName === "fin" || edgeName === "final";
|
|
417
|
-
const canonical = `${isEnd ? "final" : "inicio"}
|
|
566
|
+
const canonical = `${isEnd ? "final" : "inicio"} ${withDe(period.value.canonical)}`;
|
|
418
567
|
return Option.some(isEnd ? periodEndDay(period.value, canonical) : periodStartDay(period.value, canonical));
|
|
419
568
|
}
|
|
420
569
|
}
|
|
@@ -427,43 +576,106 @@ const parsePeriod = (input) => {
|
|
|
427
576
|
].find((prefix) => input.startsWith(prefix));
|
|
428
577
|
return parseBasePeriod(wrapper === void 0 ? input : input.slice(wrapper.length));
|
|
429
578
|
};
|
|
430
|
-
const countedUnit = (value
|
|
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
|
+
};
|
|
431
599
|
const parseCalendarOffset = (input) => {
|
|
432
|
-
const
|
|
433
|
-
const future = String$1.match(/^(?:dentro de|en) ([1-9]\d*) (día|días|dias|semana|semanas|mes|meses|trimestre|trimestres|año|años|ano|anos)$/u)(input);
|
|
434
|
-
const match = Option.firstSomeOf([past, future]);
|
|
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);
|
|
435
601
|
if (Option.isNone(match)) return Option.none();
|
|
436
|
-
const amount =
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
const
|
|
440
|
-
if (entry === void 0) return Option.none();
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
-
|
|
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));
|
|
444
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));
|
|
445
620
|
const parseRollingPeriod = (input) => {
|
|
446
|
-
const
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
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]);
|
|
456
668
|
if (Option.isNone(match)) return Option.none();
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
-
return Option.
|
|
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`)));
|
|
467
679
|
};
|
|
468
680
|
const boundaryCandidate = (input) => openBoundaryCandidate(input, [
|
|
469
681
|
["hasta antes de ", "before"],
|
|
@@ -492,6 +704,8 @@ const parseSpanish = (input) => {
|
|
|
492
704
|
if (Option.isSome(rolling)) return rolling;
|
|
493
705
|
const toDate = toDatePhrases.find((entry) => entry.phrase === input);
|
|
494
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;
|
|
495
709
|
const nowBounded = joinedNowCandidate(input, [
|
|
496
710
|
["desde ", " hasta ahora"],
|
|
497
711
|
["desde ", " hasta hoy"],
|
|
@@ -499,12 +713,16 @@ const parseSpanish = (input) => {
|
|
|
499
713
|
], [
|
|
500
714
|
"desde ahora hasta ",
|
|
501
715
|
"desde hoy hasta ",
|
|
502
|
-
"entre hoy y "
|
|
716
|
+
"entre hoy y ",
|
|
717
|
+
"entre hoy y el "
|
|
503
718
|
], parsePeriod, (period) => `desde ${period} hasta ahora`, (period) => `desde ahora hasta ${period}`);
|
|
504
719
|
if (Option.isSome(nowBounded)) return nowBounded;
|
|
505
720
|
const bounded = joinedPeriodCandidate(input, [
|
|
721
|
+
["desde el ", " hasta el "],
|
|
506
722
|
["desde ", " hasta "],
|
|
723
|
+
["del ", " al "],
|
|
507
724
|
["de ", " a "],
|
|
725
|
+
["entre el ", " y el "],
|
|
508
726
|
["entre ", " y "],
|
|
509
727
|
["", " - "],
|
|
510
728
|
["", " – "],
|
|
@@ -512,18 +730,32 @@ const parseSpanish = (input) => {
|
|
|
512
730
|
["", " hasta "]
|
|
513
731
|
], parsePeriod, (lower, upper) => `desde ${lower} hasta ${upper}`);
|
|
514
732
|
if (Option.isSome(bounded)) return bounded;
|
|
733
|
+
const inclusive = inclusiveBoundaryCandidate(input);
|
|
734
|
+
if (Option.isSome(inclusive)) return inclusive;
|
|
515
735
|
const boundary = boundaryCandidate(input);
|
|
516
736
|
if (Option.isSome(boundary)) return boundary;
|
|
517
|
-
return Option.map(
|
|
737
|
+
return parsePeriod(input).pipe(Option.map((period) => candidate(periodRange(period), period.canonical)));
|
|
518
738
|
};
|
|
519
|
-
const
|
|
520
|
-
...periodAliases.map((entry) => entry[0]),
|
|
739
|
+
const weekendPhrases = [
|
|
521
740
|
"este fin de semana",
|
|
522
741
|
"el fin de semana pasado",
|
|
523
742
|
"el próximo fin de semana",
|
|
524
743
|
"el fin de semana anterior al pasado",
|
|
525
|
-
"el fin de semana después del próximo"
|
|
526
|
-
|
|
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,
|
|
527
759
|
...[
|
|
528
760
|
1,
|
|
529
761
|
2,
|
|
@@ -544,6 +776,7 @@ const staticPeriodPhrases = [
|
|
|
544
776
|
const staticPeriods = periodsFromPhrases(staticPeriodPhrases, parsePeriod);
|
|
545
777
|
const boundaryPrefixes = [
|
|
546
778
|
"desde ",
|
|
779
|
+
"a partir de ",
|
|
547
780
|
"antes de ",
|
|
548
781
|
"hasta ",
|
|
549
782
|
"después de "
|
|
@@ -553,10 +786,21 @@ const countedSuggestions = (input) => {
|
|
|
553
786
|
if (amount === void 0) return [];
|
|
554
787
|
return units.flatMap((entry) => {
|
|
555
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
|
+
}
|
|
556
800
|
return [
|
|
557
|
-
|
|
801
|
+
`${rollingAdjective(entry, false, true)} ${amount} ${noun}`,
|
|
558
802
|
`${amount} ${noun}`,
|
|
559
|
-
|
|
803
|
+
`${rollingAdjective(entry, true, true)} ${amount} ${noun}`,
|
|
560
804
|
`hace ${amount} ${noun}`,
|
|
561
805
|
`dentro de ${amount} ${noun}`
|
|
562
806
|
];
|
|
@@ -565,6 +809,12 @@ const countedSuggestions = (input) => {
|
|
|
565
809
|
const spanishSuggestionPhrases = [
|
|
566
810
|
...units.map((entry) => entry.toDate),
|
|
567
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
|
+
]),
|
|
568
818
|
...staticPeriodPhrases,
|
|
569
819
|
...prefixNaturalPhrases(staticPeriodPhrases, boundaryPrefixes),
|
|
570
820
|
"hasta ahora",
|
|
@@ -592,20 +842,18 @@ const renderSpanish = (range) => {
|
|
|
592
842
|
const future = futurePeriod(range);
|
|
593
843
|
if (Option.isSome(future)) {
|
|
594
844
|
const entry = units.find((unit) => unit.unit === future.value.unit);
|
|
595
|
-
if (entry !== void 0)
|
|
596
|
-
const noun = future.value.amount === 1 ? entry.singular : entry.plural;
|
|
597
|
-
return Option.some(`próximos ${future.value.amount} ${noun}`);
|
|
598
|
-
}
|
|
845
|
+
if (entry !== void 0) return Option.some(rollingCanonical(entry, future.value.amount, true));
|
|
599
846
|
}
|
|
600
847
|
const trailing = trailingPeriod(range);
|
|
601
848
|
if (Option.isSome(trailing)) {
|
|
602
849
|
const entry = units.find((unit) => unit.unit === trailing.value.unit);
|
|
603
|
-
if (entry !== void 0)
|
|
604
|
-
const noun = trailing.value.amount === 1 ? entry.singular : entry.plural;
|
|
605
|
-
return Option.some(`últimos ${trailing.value.amount} ${noun}`);
|
|
606
|
-
}
|
|
850
|
+
if (entry !== void 0) return Option.some(rollingCanonical(entry, trailing.value.amount, false));
|
|
607
851
|
}
|
|
608
|
-
const periods = [
|
|
852
|
+
const periods = [
|
|
853
|
+
...staticPeriods,
|
|
854
|
+
...currentYearDatePeriods(range, currentDateLabel),
|
|
855
|
+
...periodsFromPhrases([...datedPeriods(range, months), ...datedQuarterPeriods(range)], parsePeriod)
|
|
856
|
+
];
|
|
609
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");
|
|
610
858
|
};
|
|
611
859
|
const SpanishContribution = new BaseLanguageContribution({
|