cronli5 0.1.4 → 0.1.5
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/CHANGELOG.md +25 -0
- package/cronli5.min.js +2 -2
- package/dist/cronli5.cjs +180 -36
- package/dist/cronli5.js +180 -36
- package/dist/lang/de.cjs +172 -8
- package/dist/lang/de.js +172 -8
- package/dist/lang/en.cjs +175 -29
- package/dist/lang/en.js +175 -29
- package/dist/lang/es.cjs +180 -25
- package/dist/lang/es.js +180 -25
- package/dist/lang/fi.cjs +188 -40
- package/dist/lang/fi.js +188 -40
- package/dist/lang/zh.cjs +165 -19
- package/dist/lang/zh.js +165 -19
- package/package.json +2 -1
- package/src/core/analyze.ts +7 -0
- package/src/core/ir.ts +1 -1
- package/src/core/util.ts +31 -1
- package/src/lang/de/index.ts +360 -16
- package/src/lang/en/index.ts +333 -33
- package/src/lang/es/index.ts +373 -40
- package/src/lang/fi/index.ts +404 -72
- package/src/lang/zh/index.ts +327 -35
- package/types/core/ir.d.ts +1 -1
- package/types/core/util.d.ts +6 -1
package/dist/lang/en.js
CHANGED
|
@@ -1,3 +1,23 @@
|
|
|
1
|
+
// src/core/util.ts
|
|
2
|
+
function arithmeticStep(values) {
|
|
3
|
+
if (values.length < 5) {
|
|
4
|
+
return null;
|
|
5
|
+
}
|
|
6
|
+
const interval = values[1] - values[0];
|
|
7
|
+
if (interval < 2) {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
11
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return { start: values[0], interval, last: values[values.length - 1] };
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// src/core/specs.ts
|
|
19
|
+
var maxClockTimes = 6;
|
|
20
|
+
|
|
1
21
|
// src/core/format.ts
|
|
2
22
|
function pad(n) {
|
|
3
23
|
n = "" + n;
|
|
@@ -153,7 +173,15 @@ function renderSecondsWithinMinute(ir, plan, opts) {
|
|
|
153
173
|
}
|
|
154
174
|
return secondsLeadClause(ir, opts) + ", " + minuteWord + " " + minuteUnit + " past the hour, every hour" + trailingQualifier(ir, opts);
|
|
155
175
|
}
|
|
176
|
+
function composeHourCadence(ir, plan, opts) {
|
|
177
|
+
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
178
|
+
return clockRest && ir.shapes.minute === "single" ? hourCadence(ir, +ir.pattern.minute, opts) : null;
|
|
179
|
+
}
|
|
156
180
|
function renderComposeSeconds(ir, plan, opts) {
|
|
181
|
+
const cadence = composeHourCadence(ir, plan, opts);
|
|
182
|
+
if (cadence !== null) {
|
|
183
|
+
return cadence;
|
|
184
|
+
}
|
|
157
185
|
if (plan.rest.kind === "clockTimes" && (ir.shapes.second === "wildcard" || ir.shapes.second === "step")) {
|
|
158
186
|
const minute = plan.rest.times[0].minute;
|
|
159
187
|
if (+minute === 0) {
|
|
@@ -186,6 +214,9 @@ function clockTimesOf(ir, plan, opts) {
|
|
|
186
214
|
return joinList(times, opts) + (trail && ", " + trail);
|
|
187
215
|
}
|
|
188
216
|
function secondsLeadClause(ir, opts) {
|
|
217
|
+
return secondsClause(ir, "minute", opts);
|
|
218
|
+
}
|
|
219
|
+
function secondsClause(ir, anchor, opts) {
|
|
189
220
|
const secondField = ir.pattern.second;
|
|
190
221
|
const shape = ir.shapes.second;
|
|
191
222
|
if (secondField === "*") {
|
|
@@ -195,22 +226,27 @@ function secondsLeadClause(ir, opts) {
|
|
|
195
226
|
return stepCycle60(
|
|
196
227
|
ir.analyses.segments.second[0],
|
|
197
228
|
"second",
|
|
198
|
-
|
|
229
|
+
anchor,
|
|
199
230
|
opts
|
|
200
231
|
);
|
|
201
232
|
}
|
|
202
233
|
if (shape === "range") {
|
|
203
234
|
const bounds = secondField.split("-");
|
|
204
235
|
const num = seriesNumber(bounds, opts);
|
|
205
|
-
return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the
|
|
236
|
+
return "every second from " + num(bounds[0]) + through(opts) + num(bounds[1]) + " past the " + anchor;
|
|
206
237
|
}
|
|
207
238
|
if (shape === "single") {
|
|
208
|
-
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the
|
|
239
|
+
return "at " + getNumber(secondField, opts) + " " + pluralize(secondField, "second") + " past the " + anchor;
|
|
209
240
|
}
|
|
210
|
-
return
|
|
241
|
+
return strideFromSegments(
|
|
242
|
+
ir.analyses.segments.second,
|
|
243
|
+
"second",
|
|
244
|
+
anchor,
|
|
245
|
+
opts
|
|
246
|
+
) ?? listPastThe(
|
|
211
247
|
segmentWords(ir.analyses.segments.second, opts),
|
|
212
248
|
"second",
|
|
213
|
-
|
|
249
|
+
anchor,
|
|
214
250
|
opts
|
|
215
251
|
);
|
|
216
252
|
}
|
|
@@ -225,12 +261,11 @@ function renderRangeOfMinutes(ir, plan, opts) {
|
|
|
225
261
|
return minuteRangeLead(ir.pattern.minute, opts) + trailingQualifier(ir, opts);
|
|
226
262
|
}
|
|
227
263
|
function renderMultipleMinutes(ir, plan, opts) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
"hour",
|
|
264
|
+
const stride = strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts);
|
|
265
|
+
return (stride ?? listPastThe(segmentWords(
|
|
266
|
+
ir.analyses.segments.minute,
|
|
232
267
|
opts
|
|
233
|
-
) + trailingQualifier(ir, opts);
|
|
268
|
+
), "minute", "hour", opts)) + trailingQualifier(ir, opts);
|
|
234
269
|
}
|
|
235
270
|
function renderMinuteFrequency(ir, plan, opts) {
|
|
236
271
|
let phrase = stepCycle60(
|
|
@@ -260,8 +295,9 @@ function renderMinutesAcrossHours(ir, plan, opts) {
|
|
|
260
295
|
}
|
|
261
296
|
const times = hourTimesFromPlan(ir, plan.times, true, opts);
|
|
262
297
|
const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute, opts) : (
|
|
263
|
-
// The 'list' form is a minute list, which has segments
|
|
264
|
-
|
|
298
|
+
// The 'list' form is a minute list, which has segments; an offset/uneven
|
|
299
|
+
// step enumerated to that list reads as a stride.
|
|
300
|
+
strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
265
301
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
266
302
|
"minute",
|
|
267
303
|
"hour",
|
|
@@ -288,7 +324,13 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
|
288
324
|
if (plan.form === "wildcard") {
|
|
289
325
|
return "every minute " + everyNthHour(segment, opts) + trailingQualifier(ir, opts);
|
|
290
326
|
}
|
|
291
|
-
|
|
327
|
+
const lead = plan.form === "list" ? strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
328
|
+
segmentWords(ir.analyses.segments.minute, opts),
|
|
329
|
+
"minute",
|
|
330
|
+
"hour",
|
|
331
|
+
opts
|
|
332
|
+
) : minuteRangeLead(ir.pattern.minute, opts);
|
|
333
|
+
return lead + ", " + stepHours(segment, opts) + trailingQualifier(ir, opts);
|
|
292
334
|
}
|
|
293
335
|
function minuteRangeLead(minuteField, opts) {
|
|
294
336
|
const bounds = minuteField.split("-");
|
|
@@ -312,7 +354,12 @@ function rangeMinuteLead(ir, opts) {
|
|
|
312
354
|
if (ir.pattern.minute === "0") {
|
|
313
355
|
return "every hour";
|
|
314
356
|
}
|
|
315
|
-
return
|
|
357
|
+
return strideFromSegments(
|
|
358
|
+
ir.analyses.segments.minute,
|
|
359
|
+
"minute",
|
|
360
|
+
"hour",
|
|
361
|
+
opts
|
|
362
|
+
) ?? listPastThe(
|
|
316
363
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
317
364
|
"minute",
|
|
318
365
|
"hour",
|
|
@@ -329,6 +376,12 @@ function hourWindow(window, opts) {
|
|
|
329
376
|
return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
|
|
330
377
|
}
|
|
331
378
|
function renderClockTimes(ir, plan, opts) {
|
|
379
|
+
if (ir.shapes.minute === "single") {
|
|
380
|
+
const cadence = hourCadence(ir, +ir.pattern.minute, opts);
|
|
381
|
+
if (cadence !== null) {
|
|
382
|
+
return cadence;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
332
385
|
const plain = mixedTwelve(plan.times);
|
|
333
386
|
const times = plan.times.map(function clock(time) {
|
|
334
387
|
return getTime({
|
|
@@ -342,6 +395,10 @@ function renderClockTimes(ir, plan, opts) {
|
|
|
342
395
|
}
|
|
343
396
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
344
397
|
if (plan.fold) {
|
|
398
|
+
const cadence = hourCadence(ir, +plan.minute, opts);
|
|
399
|
+
if (cadence !== null) {
|
|
400
|
+
return cadence;
|
|
401
|
+
}
|
|
345
402
|
const hasRange = ir.analyses.segments.hour.some(function range(segment) {
|
|
346
403
|
return segment.kind === "range";
|
|
347
404
|
});
|
|
@@ -352,13 +409,14 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
352
409
|
return interpretDayQualifier(ir, opts) + "at " + hourSegmentTimes(ir, fold, true, opts);
|
|
353
410
|
}
|
|
354
411
|
const phrase = (
|
|
355
|
-
// The non-fold branch is a minute list, which has segments.
|
|
356
|
-
|
|
412
|
+
// The non-fold branch is a minute list, which has segments. An
|
|
413
|
+
// offset/uneven step enumerated to that list reads as a stride.
|
|
414
|
+
(strideFromSegments(ir.analyses.segments.minute, "minute", "hour", opts) ?? listPastThe(
|
|
357
415
|
segmentWords(ir.analyses.segments.minute, opts),
|
|
358
416
|
"minute",
|
|
359
417
|
"hour",
|
|
360
418
|
opts
|
|
361
|
-
) + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts)
|
|
419
|
+
)) + ", at " + hourSegmentTimes(ir, { minute: 0, second: null }, true, opts) + trailingQualifier(ir, opts)
|
|
362
420
|
);
|
|
363
421
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
|
|
364
422
|
}
|
|
@@ -406,24 +464,50 @@ var renderers = {
|
|
|
406
464
|
singleMinute: renderSingleMinute,
|
|
407
465
|
standaloneSeconds: renderStandaloneSeconds
|
|
408
466
|
};
|
|
467
|
+
function renderStride(stride, opts) {
|
|
468
|
+
const { interval, start, last, cycle, unit, anchor } = stride;
|
|
469
|
+
const cadence = "every " + getNumber(interval, opts) + " " + unit + "s";
|
|
470
|
+
const tiles = cycle % interval === 0;
|
|
471
|
+
if (start === 0 && tiles) {
|
|
472
|
+
return cadence;
|
|
473
|
+
}
|
|
474
|
+
if (start < interval && tiles) {
|
|
475
|
+
return cadence + " from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
|
|
476
|
+
}
|
|
477
|
+
const num = seriesNumber([start, last], opts);
|
|
478
|
+
return cadence + " from " + num(start) + through(opts) + num(last) + " " + pluralize(last, unit) + " past the " + anchor;
|
|
479
|
+
}
|
|
480
|
+
function singleValues(segments) {
|
|
481
|
+
const values = [];
|
|
482
|
+
for (const segment of segments) {
|
|
483
|
+
if (segment.kind !== "single") {
|
|
484
|
+
return null;
|
|
485
|
+
}
|
|
486
|
+
values.push(+segment.value);
|
|
487
|
+
}
|
|
488
|
+
return values;
|
|
489
|
+
}
|
|
490
|
+
function strideFromSegments(segments, unit, anchor, opts) {
|
|
491
|
+
const values = singleValues(segments);
|
|
492
|
+
const step = values && arithmeticStep(values);
|
|
493
|
+
return step ? renderStride({ ...step, cycle: 60, unit, anchor }, opts) : null;
|
|
494
|
+
}
|
|
409
495
|
function stepCycle60(segment, unit, anchor, opts) {
|
|
410
496
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
411
497
|
return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
|
|
412
498
|
}
|
|
413
499
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (segment.fires.length <= 3) {
|
|
417
|
-
return listPastThe(
|
|
418
|
-
numberWords(segment.fires, opts),
|
|
419
|
-
unit,
|
|
420
|
-
anchor,
|
|
421
|
-
opts
|
|
422
|
-
);
|
|
423
|
-
}
|
|
424
|
-
return "every " + getNumber(interval, opts) + " " + unit + "s from " + getNumber(start, opts) + " " + pluralize(start, unit) + " past the " + anchor;
|
|
500
|
+
if (start !== 0 && segment.fires.length <= 3) {
|
|
501
|
+
return listPastThe(numberWords(segment.fires, opts), unit, anchor, opts);
|
|
425
502
|
}
|
|
426
|
-
return
|
|
503
|
+
return renderStride({
|
|
504
|
+
interval: segment.interval,
|
|
505
|
+
start,
|
|
506
|
+
last: segment.fires[segment.fires.length - 1],
|
|
507
|
+
cycle: 60,
|
|
508
|
+
unit,
|
|
509
|
+
anchor
|
|
510
|
+
}, opts);
|
|
427
511
|
}
|
|
428
512
|
function stepHours(segment, opts) {
|
|
429
513
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -439,6 +523,68 @@ function stepHours(segment, opts) {
|
|
|
439
523
|
}
|
|
440
524
|
return "every " + getNumber(interval, opts) + " hours from " + getTime({ hour: start, minute: 0 }, opts);
|
|
441
525
|
}
|
|
526
|
+
function hourStrideCadence(stride, opts) {
|
|
527
|
+
const { start, interval, last } = stride;
|
|
528
|
+
const cadence = "every " + getNumber(interval, opts) + " hours";
|
|
529
|
+
const tiles = 24 % interval === 0;
|
|
530
|
+
if (start === 0 && tiles) {
|
|
531
|
+
return cadence;
|
|
532
|
+
}
|
|
533
|
+
if (start < interval && tiles) {
|
|
534
|
+
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts);
|
|
535
|
+
}
|
|
536
|
+
return cadence + " from " + getTime({ hour: start, minute: 0 }, opts) + through(opts) + getTime({ hour: last, minute: 0 }, opts);
|
|
537
|
+
}
|
|
538
|
+
function hourStride(ir) {
|
|
539
|
+
const segments = ir.analyses.segments.hour;
|
|
540
|
+
if (segments.length === 1 && segments[0].kind === "step") {
|
|
541
|
+
const segment = segments[0];
|
|
542
|
+
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
543
|
+
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
544
|
+
}
|
|
545
|
+
const values = singleValues(segments);
|
|
546
|
+
const step = values && arithmeticStep(values);
|
|
547
|
+
return step || null;
|
|
548
|
+
}
|
|
549
|
+
function subMinuteSecond(ir) {
|
|
550
|
+
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
551
|
+
}
|
|
552
|
+
function hourCadenceLead(ir, minute, opts) {
|
|
553
|
+
if (minute === 0) {
|
|
554
|
+
if (subMinuteSecond(ir)) {
|
|
555
|
+
return secondsClause(ir, "minute", opts) + " for one minute";
|
|
556
|
+
}
|
|
557
|
+
return secondsClause(ir, "hour", opts);
|
|
558
|
+
}
|
|
559
|
+
const minutePhrase = getNumber(minute, opts) + " " + pluralize(minute, "minute") + " past the hour";
|
|
560
|
+
if (ir.pattern.second === "0") {
|
|
561
|
+
return minutePhrase;
|
|
562
|
+
}
|
|
563
|
+
return secondsClause(ir, "minute", opts) + ", " + minutePhrase;
|
|
564
|
+
}
|
|
565
|
+
function hourCadence(ir, minute, opts) {
|
|
566
|
+
const stride = hourStride(ir);
|
|
567
|
+
if (!stride) {
|
|
568
|
+
return null;
|
|
569
|
+
}
|
|
570
|
+
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
571
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes) {
|
|
572
|
+
return null;
|
|
573
|
+
}
|
|
574
|
+
const confinement = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
|
|
575
|
+
if (confinement) {
|
|
576
|
+
return secondsClause(ir, "minute", opts) + " for one minute " + everyNthHour(confinement, opts) + trailingQualifier(ir, opts);
|
|
577
|
+
}
|
|
578
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
579
|
+
}
|
|
580
|
+
function cleanStrideSegment(ir) {
|
|
581
|
+
const segments = ir.analyses.segments.hour;
|
|
582
|
+
const segment = segments.length === 1 && segments[0];
|
|
583
|
+
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1 || !(segment.interval in stepOrdinals)) {
|
|
584
|
+
return null;
|
|
585
|
+
}
|
|
586
|
+
return segment;
|
|
587
|
+
}
|
|
442
588
|
function seriesNumber(values, opts) {
|
|
443
589
|
const anyBig = values.some(function big(v) {
|
|
444
590
|
return +v > 10;
|
package/dist/lang/es.cjs
CHANGED
|
@@ -50,12 +50,28 @@ var weekdayNumbers = {
|
|
|
50
50
|
FRI: 5,
|
|
51
51
|
SAT: 6
|
|
52
52
|
};
|
|
53
|
+
var maxClockTimes = 6;
|
|
53
54
|
|
|
54
55
|
// src/core/util.ts
|
|
55
56
|
function isNonNegativeInteger(value) {
|
|
56
57
|
const digits = /^\d+$/;
|
|
57
58
|
return digits.test(value);
|
|
58
59
|
}
|
|
60
|
+
function arithmeticStep(values) {
|
|
61
|
+
if (values.length < 5) {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
const interval = values[1] - values[0];
|
|
65
|
+
if (interval < 2) {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
for (let i = 2; i < values.length; i += 1) {
|
|
69
|
+
if (values[i] - values[i - 1] !== interval) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return { start: values[0], interval, last: values[values.length - 1] };
|
|
74
|
+
}
|
|
59
75
|
function toFieldNumber(token, numberMap) {
|
|
60
76
|
return isNonNegativeInteger(token) ? +token : numberMap[token.toUpperCase()];
|
|
61
77
|
}
|
|
@@ -173,19 +189,31 @@ function renderSecondsWithinMinute(ir, plan, opts) {
|
|
|
173
189
|
}
|
|
174
190
|
return secondsLeadClause(ir, opts) + ", en el minuto " + minuteField + " de cada hora" + trailingQualifier(ir, opts);
|
|
175
191
|
}
|
|
192
|
+
function secondsListAtClock(ir, rest, opts) {
|
|
193
|
+
const clockPhrases = rest.times.map(function clock(time) {
|
|
194
|
+
return atTime(timePhrase(time.hour, time.minute, null, opts));
|
|
195
|
+
});
|
|
196
|
+
const grouped = groupClockTimesByArticle(clockPhrases);
|
|
197
|
+
const clockList = grouped.startsWith("a ") ? grouped.slice(2) : grouped;
|
|
198
|
+
const stride = strideFromSegments(fieldSegments(ir, "second"), "segundo", "", opts);
|
|
199
|
+
const secondsPhrase = stride ?? "en los segundos " + joinList(segmentWords(fieldSegments(ir, "second")));
|
|
200
|
+
const dayFrame = trailingQualifier(ir, opts);
|
|
201
|
+
return (dayFrame ? dayFrame.trimStart() + ", " : "") + secondsPhrase + " de " + clockList;
|
|
202
|
+
}
|
|
203
|
+
function composeHourCadence(ir, plan, opts) {
|
|
204
|
+
const clockRest = plan.rest.kind === "clockTimes" || plan.rest.kind === "compactClockTimes";
|
|
205
|
+
return clockRest && ir.shapes.minute === "single" ? hourCadence(ir, +ir.pattern.minute, opts) : null;
|
|
206
|
+
}
|
|
176
207
|
function renderComposeSeconds(ir, plan, opts) {
|
|
208
|
+
const hourCad = composeHourCadence(ir, plan, opts);
|
|
209
|
+
if (hourCad !== null) {
|
|
210
|
+
return hourCad;
|
|
211
|
+
}
|
|
177
212
|
if (plan.rest.kind === "clockTimes" && (ir.shapes.second === "wildcard" || ir.shapes.second === "step")) {
|
|
178
213
|
return pinnedMinuteSeconds(ir, plan.rest, opts);
|
|
179
214
|
}
|
|
180
215
|
if (plan.rest.kind === "clockTimes" && ir.shapes.second === "list") {
|
|
181
|
-
|
|
182
|
-
return atTime(timePhrase(time.hour, time.minute, null, opts));
|
|
183
|
-
});
|
|
184
|
-
const grouped = groupClockTimesByArticle(clockPhrases);
|
|
185
|
-
const clockList = grouped.startsWith("a ") ? grouped.slice(2) : grouped;
|
|
186
|
-
const secondsPhrase = "en los segundos " + joinList(segmentWords(fieldSegments(ir, "second")));
|
|
187
|
-
const dayFrame = trailingQualifier(ir, opts);
|
|
188
|
-
return (dayFrame ? dayFrame.trimStart() + ", " : "") + secondsPhrase + " de " + clockList;
|
|
216
|
+
return secondsListAtClock(ir, plan.rest, opts);
|
|
189
217
|
}
|
|
190
218
|
if (plan.rest.kind === "hourRange" && ir.shapes.second === "step" && ir.pattern.weekday !== "*") {
|
|
191
219
|
const restNode = plan.rest;
|
|
@@ -194,8 +222,18 @@ function renderComposeSeconds(ir, plan, opts) {
|
|
|
194
222
|
const cadence = "cada " + numero(stepSegment(ir.analyses.segments.second).interval, opts) + " segundos del minuto " + ir.pattern.minute;
|
|
195
223
|
return dayFrame + ", " + window + ", " + cadence;
|
|
196
224
|
}
|
|
225
|
+
if (isEveryOtherMinuteSeconds(ir, plan)) {
|
|
226
|
+
return secondsLeadClause(ir, opts) + " de " + render(ir, plan.rest, opts);
|
|
227
|
+
}
|
|
197
228
|
return secondsLeadClause(ir, opts) + ", " + render(ir, plan.rest, opts);
|
|
198
229
|
}
|
|
230
|
+
function isEveryOtherMinuteSeconds(ir, plan) {
|
|
231
|
+
if (plan.rest.kind !== "minuteFrequency" || ir.shapes.second !== "wildcard" || ir.shapes.hour !== "wildcard") {
|
|
232
|
+
return false;
|
|
233
|
+
}
|
|
234
|
+
const minuteStep = stepSegment(ir.analyses.segments.minute);
|
|
235
|
+
return minuteStep.startToken === "*" && minuteStep.interval === 2;
|
|
236
|
+
}
|
|
199
237
|
function pinnedMinuteSeconds(ir, rest, opts) {
|
|
200
238
|
const dayTrail = leadingQualifier(ir, opts).trimEnd();
|
|
201
239
|
const trail = dayTrail ? ", " + dayTrail : "";
|
|
@@ -205,6 +243,9 @@ function pinnedMinuteSeconds(ir, rest, opts) {
|
|
|
205
243
|
return secondsLeadClause(ir, opts) + " de " + explicitClockList(rest.times, opts) + trail;
|
|
206
244
|
}
|
|
207
245
|
function secondsLeadClause(ir, opts) {
|
|
246
|
+
return secondsClause(ir, "minuto", opts);
|
|
247
|
+
}
|
|
248
|
+
function secondsClause(ir, anchor, opts) {
|
|
208
249
|
const secondField = ir.pattern.second;
|
|
209
250
|
const shape = ir.shapes.second;
|
|
210
251
|
if (secondField === "*") {
|
|
@@ -214,18 +255,23 @@ function secondsLeadClause(ir, opts) {
|
|
|
214
255
|
return stepCycle60(
|
|
215
256
|
stepSegment(ir.analyses.segments.second),
|
|
216
257
|
"segundo",
|
|
217
|
-
|
|
258
|
+
anchor,
|
|
218
259
|
opts
|
|
219
260
|
);
|
|
220
261
|
}
|
|
221
262
|
if (shape === "range") {
|
|
222
263
|
const bounds = secondField.split("-");
|
|
223
|
-
return "cada segundo del " + bounds[0] + " al " + bounds[1] + " de cada
|
|
264
|
+
return "cada segundo del " + bounds[0] + " al " + bounds[1] + " de cada " + anchor;
|
|
224
265
|
}
|
|
225
266
|
if (shape === "single") {
|
|
226
|
-
return "en el segundo " + secondField + " de cada
|
|
267
|
+
return "en el segundo " + secondField + " de cada " + anchor;
|
|
227
268
|
}
|
|
228
|
-
return
|
|
269
|
+
return strideFromSegments(
|
|
270
|
+
fieldSegments(ir, "second"),
|
|
271
|
+
"segundo",
|
|
272
|
+
anchor,
|
|
273
|
+
opts
|
|
274
|
+
) ?? "en los segundos " + joinList(segmentWords(fieldSegments(ir, "second"))) + " de cada " + anchor;
|
|
229
275
|
}
|
|
230
276
|
function renderEveryMinute(ir, plan, opts) {
|
|
231
277
|
return "cada minuto" + trailingQualifier(ir, opts);
|
|
@@ -237,10 +283,15 @@ function renderRangeOfMinutes(ir, plan, opts) {
|
|
|
237
283
|
return minuteRangeLead(ir.pattern.minute) + " de cada hora" + trailingQualifier(ir, opts);
|
|
238
284
|
}
|
|
239
285
|
function renderMultipleMinutes(ir, plan, opts) {
|
|
240
|
-
return minutesList(ir) + trailingQualifier(ir, opts);
|
|
286
|
+
return minutesList(ir, opts) + trailingQualifier(ir, opts);
|
|
241
287
|
}
|
|
242
|
-
function minutesList(ir) {
|
|
243
|
-
return
|
|
288
|
+
function minutesList(ir, opts) {
|
|
289
|
+
return strideFromSegments(
|
|
290
|
+
fieldSegments(ir, "minute"),
|
|
291
|
+
"minuto",
|
|
292
|
+
"hora",
|
|
293
|
+
opts
|
|
294
|
+
) ?? "en los minutos " + joinList(segmentWords(fieldSegments(ir, "minute"))) + " de cada hora";
|
|
244
295
|
}
|
|
245
296
|
function minuteRangeLead(minuteField) {
|
|
246
297
|
const bounds = minuteField.split("-");
|
|
@@ -328,7 +379,7 @@ function renderMinutesAcrossHours(ir, plan, opts) {
|
|
|
328
379
|
}
|
|
329
380
|
return "cada minuto " + hourSpanFromTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
|
|
330
381
|
}
|
|
331
|
-
const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute) : minutesList(ir);
|
|
382
|
+
const lead = plan.form === "range" ? minuteRangeLead(ir.pattern.minute) : minutesList(ir, opts);
|
|
332
383
|
return lead + ", " + atHourTimes(ir, plan.times, opts) + trailingQualifier(ir, opts);
|
|
333
384
|
}
|
|
334
385
|
function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
@@ -336,7 +387,8 @@ function renderMinuteSpanAcrossHourStep(ir, plan, opts) {
|
|
|
336
387
|
if (plan.form === "wildcard") {
|
|
337
388
|
return "cada minuto, " + stepHourSpan(segment, opts) + trailingQualifier(ir, opts);
|
|
338
389
|
}
|
|
339
|
-
|
|
390
|
+
const lead = plan.form === "list" ? minutesList(ir, opts) : minuteRangeLead(ir.pattern.minute);
|
|
391
|
+
return lead + ", " + stepHours(segment, opts) + trailingQualifier(ir, opts);
|
|
340
392
|
}
|
|
341
393
|
function renderEveryHour(ir, plan, opts) {
|
|
342
394
|
return "cada hora" + trailingQualifier(ir, opts);
|
|
@@ -352,7 +404,7 @@ function renderHourRange(ir, plan, opts) {
|
|
|
352
404
|
if (ir.pattern.minute === "0") {
|
|
353
405
|
return "cada hora " + window + trailingQualifier(ir, opts);
|
|
354
406
|
}
|
|
355
|
-
const lead = ir.shapes.minute === "single" ? "en el minuto " + ir.pattern.minute + " de cada hora" : minutesList(ir);
|
|
407
|
+
const lead = ir.shapes.minute === "single" ? "en el minuto " + ir.pattern.minute + " de cada hora" : minutesList(ir, opts);
|
|
356
408
|
return lead + ", " + window + trailingQualifier(ir, opts);
|
|
357
409
|
}
|
|
358
410
|
function renderHourStep(ir, plan, opts) {
|
|
@@ -426,6 +478,12 @@ function unionYaseaSuffix(ir, opts) {
|
|
|
426
478
|
return ", ya sea " + domArm(ir, opts) + " o " + dowArm(ir);
|
|
427
479
|
}
|
|
428
480
|
function renderClockTimes(ir, plan, opts) {
|
|
481
|
+
if (ir.shapes.minute === "single") {
|
|
482
|
+
const cadence = hourCadence(ir, +ir.pattern.minute, opts);
|
|
483
|
+
if (cadence !== null) {
|
|
484
|
+
return cadence;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
429
487
|
const phrases = plan.times.map(function clock(time) {
|
|
430
488
|
return atTime(timePhrase(time.hour, time.minute, time.second, opts));
|
|
431
489
|
});
|
|
@@ -607,6 +665,10 @@ function groupClockTimesByArticle(phrases) {
|
|
|
607
665
|
}
|
|
608
666
|
function renderCompactClockTimes(ir, plan, opts) {
|
|
609
667
|
if (plan.fold) {
|
|
668
|
+
const cadence = hourCadence(ir, plan.minute, opts);
|
|
669
|
+
if (cadence !== null) {
|
|
670
|
+
return cadence;
|
|
671
|
+
}
|
|
610
672
|
const ranged = hourSegments(ir).some(function range(segment) {
|
|
611
673
|
return segment.kind === "range";
|
|
612
674
|
});
|
|
@@ -615,7 +677,7 @@ function renderCompactClockTimes(ir, plan, opts) {
|
|
|
615
677
|
}
|
|
616
678
|
return leadingQualifier(ir, opts) + hourSegmentTimes(ir, plan.minute, ir.analyses.clockSecond, opts);
|
|
617
679
|
}
|
|
618
|
-
const phrase = minutesList(ir) + ", " + hourSegmentTimes(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
680
|
+
const phrase = minutesList(ir, opts) + ", " + hourSegmentTimes(ir, 0, null, opts) + trailingQualifier(ir, opts);
|
|
619
681
|
return ir.analyses.clockSecond ? secondsLeadClause(ir, opts) + ", " + phrase : phrase;
|
|
620
682
|
}
|
|
621
683
|
var renderers = {
|
|
@@ -638,19 +700,50 @@ var renderers = {
|
|
|
638
700
|
singleMinute: renderSingleMinute,
|
|
639
701
|
standaloneSeconds: renderStandaloneSeconds
|
|
640
702
|
};
|
|
703
|
+
function renderStride(stride, opts) {
|
|
704
|
+
const { interval, start, last, cycle, unit, anchor } = stride;
|
|
705
|
+
const cadence = "cada " + numero(interval, opts) + " " + unit + "s";
|
|
706
|
+
const tiles = cycle % interval === 0;
|
|
707
|
+
if (start === 0 && tiles) {
|
|
708
|
+
return cadence;
|
|
709
|
+
}
|
|
710
|
+
const tail = anchor ? " de cada " + anchor : "";
|
|
711
|
+
if (start < interval && tiles) {
|
|
712
|
+
return cadence + " a partir del " + unit + " " + start + tail;
|
|
713
|
+
}
|
|
714
|
+
return cadence + " del " + unit + " " + start + " al " + last + tail;
|
|
715
|
+
}
|
|
641
716
|
function stepCycle60(segment, unit, anchor, opts) {
|
|
642
717
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
643
718
|
return "en los " + unit + "s " + joinList(wordList(segment.fires)) + " de cada " + anchor;
|
|
644
719
|
}
|
|
645
720
|
const start = segment.startToken === "*" ? 0 : +segment.startToken;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
721
|
+
if (start !== 0 && segment.fires.length <= 3) {
|
|
722
|
+
return "en los " + unit + "s " + joinList(wordList(segment.fires)) + " de cada " + anchor;
|
|
723
|
+
}
|
|
724
|
+
return renderStride({
|
|
725
|
+
interval: segment.interval,
|
|
726
|
+
start,
|
|
727
|
+
last: segment.fires[segment.fires.length - 1],
|
|
728
|
+
cycle: 60,
|
|
729
|
+
unit,
|
|
730
|
+
anchor
|
|
731
|
+
}, opts);
|
|
732
|
+
}
|
|
733
|
+
function strideFromSegments(segments, unit, anchor, opts) {
|
|
734
|
+
const values = singleValues(segments);
|
|
735
|
+
const step = values && arithmeticStep(values);
|
|
736
|
+
return step ? renderStride({ ...step, cycle: 60, unit, anchor }, opts) : null;
|
|
737
|
+
}
|
|
738
|
+
function singleValues(segments) {
|
|
739
|
+
const values = [];
|
|
740
|
+
for (const segment of segments) {
|
|
741
|
+
if (segment.kind !== "single") {
|
|
742
|
+
return null;
|
|
650
743
|
}
|
|
651
|
-
|
|
744
|
+
values.push(+segment.value);
|
|
652
745
|
}
|
|
653
|
-
return
|
|
746
|
+
return values;
|
|
654
747
|
}
|
|
655
748
|
function stepHours(segment, opts) {
|
|
656
749
|
if (segment.startToken.indexOf("-") !== -1) {
|
|
@@ -666,6 +759,68 @@ function stepHours(segment, opts) {
|
|
|
666
759
|
}
|
|
667
760
|
return "cada " + numero(interval, opts) + " horas a partir de " + timePhrase(start, 0, null, opts);
|
|
668
761
|
}
|
|
762
|
+
function hourStrideCadence(stride, opts) {
|
|
763
|
+
const { start, interval, last } = stride;
|
|
764
|
+
const cadence = "cada " + numero(interval, opts) + " horas";
|
|
765
|
+
const tiles = 24 % interval === 0;
|
|
766
|
+
if (start === 0 && tiles) {
|
|
767
|
+
return cadence;
|
|
768
|
+
}
|
|
769
|
+
if (start < interval && tiles) {
|
|
770
|
+
return cadence + " a partir de " + timePhrase(start, 0, null, opts);
|
|
771
|
+
}
|
|
772
|
+
return cadence + " de " + timePhrase(start, 0, null, opts) + " a " + timePhrase(last, 0, null, opts);
|
|
773
|
+
}
|
|
774
|
+
function hourStride(ir) {
|
|
775
|
+
const segments = fieldSegments(ir, "hour");
|
|
776
|
+
if (segments.length === 1 && segments[0].kind === "step") {
|
|
777
|
+
const segment = segments[0];
|
|
778
|
+
const start = segment.startToken === "*" ? 0 : +segment.startToken.split("-")[0];
|
|
779
|
+
return { interval: segment.interval, last: segment.fires[segment.fires.length - 1], start };
|
|
780
|
+
}
|
|
781
|
+
const values = singleValues(segments);
|
|
782
|
+
const step = values && arithmeticStep(values);
|
|
783
|
+
return step || null;
|
|
784
|
+
}
|
|
785
|
+
function subMinuteSecond(ir) {
|
|
786
|
+
return ir.pattern.second === "*" || ir.shapes.second === "step";
|
|
787
|
+
}
|
|
788
|
+
function hourCadenceLead(ir, minute, opts) {
|
|
789
|
+
if (minute === 0) {
|
|
790
|
+
if (subMinuteSecond(ir)) {
|
|
791
|
+
return secondsClause(ir, "minuto", opts) + " durante un minuto";
|
|
792
|
+
}
|
|
793
|
+
return secondsClause(ir, "hora", opts);
|
|
794
|
+
}
|
|
795
|
+
const minutePhrase = "en el minuto " + minute;
|
|
796
|
+
if (ir.pattern.second === "0") {
|
|
797
|
+
return minutePhrase;
|
|
798
|
+
}
|
|
799
|
+
return secondsClause(ir, "minuto", opts) + ", " + minutePhrase;
|
|
800
|
+
}
|
|
801
|
+
function hourCadence(ir, minute, opts) {
|
|
802
|
+
const stride = hourStride(ir);
|
|
803
|
+
if (!stride) {
|
|
804
|
+
return null;
|
|
805
|
+
}
|
|
806
|
+
const fires = (stride.last - stride.start) / stride.interval + 1;
|
|
807
|
+
if (ir.pattern.second === "0" && fires <= maxClockTimes) {
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
810
|
+
const confinement = minute === 0 && subMinuteSecond(ir) && cleanStrideSegment(ir);
|
|
811
|
+
if (confinement) {
|
|
812
|
+
return secondsClause(ir, "minuto", opts) + " durante un minuto, " + stepHourSpan(confinement, opts) + trailingQualifier(ir, opts);
|
|
813
|
+
}
|
|
814
|
+
return hourCadenceLead(ir, minute, opts) + ", " + hourStrideCadence(stride, opts) + trailingQualifier(ir, opts);
|
|
815
|
+
}
|
|
816
|
+
function cleanStrideSegment(ir) {
|
|
817
|
+
const segments = fieldSegments(ir, "hour");
|
|
818
|
+
const segment = segments.length === 1 && segments[0];
|
|
819
|
+
if (!segment || segment.kind !== "step" || segment.startToken.indexOf("-") !== -1) {
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
822
|
+
return segment;
|
|
823
|
+
}
|
|
669
824
|
function atTimes(hours, opts) {
|
|
670
825
|
return hours.map(function each(hour) {
|
|
671
826
|
return atTime(timePhrase(hour, 0, null, opts));
|