cronli5 0.1.0 → 0.1.1
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 +43 -32
- package/cronli5.min.js +2 -2
- package/dist/cronli5.cjs +36 -27
- package/dist/cronli5.js +36 -27
- package/dist/lang/de.cjs +6 -1
- package/dist/lang/de.js +6 -1
- package/dist/lang/en.cjs +4 -1
- package/dist/lang/en.js +4 -1
- package/dist/lang/es.cjs +4 -1
- package/dist/lang/es.js +4 -1
- package/dist/lang/fi.cjs +4 -1
- package/dist/lang/fi.js +4 -1
- package/dist/lang/zh.cjs +3 -11
- package/dist/lang/zh.js +3 -11
- package/package.json +1 -1
- package/src/core/analyze.ts +69 -31
- package/src/core/ir.ts +6 -0
- package/src/lang/de/index.ts +5 -1
- package/src/lang/en/index.ts +9 -1
- package/src/lang/es/index.ts +10 -1
- package/src/lang/fi/index.ts +11 -1
- package/src/lang/zh/index.ts +9 -19
- package/types/core/ir.d.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,32 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.1.1]
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- A minute of `0` is no longer dropped when a sub-minute second makes the
|
|
14
|
+
cadence sub-minute. `* 0 * * * *` now reads "every second, zero minutes past
|
|
15
|
+
the hour, every hour" (was "every second, every hour", which described every
|
|
16
|
+
second of *every* minute, losing the minute-0 restriction). The bug affected
|
|
17
|
+
the wildcard-second + minute-0 combination over the every-hour, hour-range,
|
|
18
|
+
and hour-step idioms, in all five languages; fuzz coverage was added for the
|
|
19
|
+
shape so it cannot silently regress.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- A minute **list or range** within an **hour range** now closes on the bare
|
|
24
|
+
hour, with the minutes stated separately: `2,3,4 9-17 * * *` reads "at 2, 3,
|
|
25
|
+
and 4 minutes past the hour from 9 a.m. through 5 p.m." (was "through 5:04
|
|
26
|
+
p.m.", which glued the last fire's minute onto the bound and read as a
|
|
27
|
+
misleading continuous span). Single-minute (`30 9-17 * * *` → "through 5:30
|
|
28
|
+
p.m.") and wildcard (`* 9-17 * * *` → "through 5:59 p.m.") bounds are
|
|
29
|
+
unchanged. All five languages.
|
|
30
|
+
|
|
31
|
+
## [0.1.0]
|
|
32
|
+
|
|
33
|
+
First non-beta release.
|
|
34
|
+
|
|
9
35
|
### Added
|
|
10
36
|
|
|
11
37
|
- **Per-language documentation** under `docs/lang/` (`en.md`, `es.md`,
|
|
@@ -34,7 +60,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
34
60
|
`ampm` option is ignored. Ships with a reviewed corpus, minimal
|
|
35
61
|
pairs, language notes, and a review log under `test/lang/fi/`.
|
|
36
62
|
Like Spanish, Finnish required zero core changes.
|
|
37
|
-
|
|
38
63
|
- Descriptions for **lists containing range or step segments** (e.g.
|
|
39
64
|
`0-30,45` or `9,17-19`) in every field. Minute and second lists read their
|
|
40
65
|
spans discretely (`at five through ten and 20 minutes past the hour`), hour
|
|
@@ -87,6 +112,18 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
87
112
|
- An explicitly supplied year is now always described: object input with a
|
|
88
113
|
`year` property (e.g. `{hour: 9, year: 2030}`) previously validated the
|
|
89
114
|
year and then silently dropped it from the description.
|
|
115
|
+
- Idiomatic descriptions for **lists** (`,`), **ranges** (`-`), and **compound**
|
|
116
|
+
patterns that combine multiple non-trivial fields (e.g.
|
|
117
|
+
`at 30 minutes past the hour from 9 a.m. through 5 p.m.`).
|
|
118
|
+
- Trailing day qualifiers for bare frequencies (e.g. `every minute on Monday`,
|
|
119
|
+
`every hour on January 13`).
|
|
120
|
+
- Dual **ESM** and **CommonJS** builds plus a minified **browser** global, an
|
|
121
|
+
`exports` map, and bundled **TypeScript** type definitions (`cronli5.d.ts`).
|
|
122
|
+
- Continuous integration (GitHub Actions) across Node 18/20/22, with a
|
|
123
|
+
coverage gate.
|
|
124
|
+
- Code coverage via **c8** with enforced thresholds (`npm run coverage`).
|
|
125
|
+
- Property-based tests (**fast-check**), smoke tests against the built
|
|
126
|
+
ESM/CJS artifacts, and type tests (**tsd**, `npm run test:types`).
|
|
90
127
|
|
|
91
128
|
### Changed
|
|
92
129
|
|
|
@@ -94,7 +131,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
94
131
|
`uk` for the Ukrainian language, so the British-English style now uses the
|
|
95
132
|
ISO-3166 country code `'gb'`. `{ dialect: 'uk' }` still works as a
|
|
96
133
|
deprecated alias for `'gb'` and will be removed in a future release.
|
|
97
|
-
|
|
98
134
|
- **Spanish now defaults to the 24-hour clock** (`a las 09:30`,
|
|
99
135
|
`a las 17:00`), matching RAE convention for written Spanish. Pass
|
|
100
136
|
`{ampm: true}` for the previous 12-hour behavior with day periods
|
|
@@ -166,6 +202,11 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
166
202
|
`0-30` in minute lists, and clock-time windows like `9 a.m.-5:45 p.m.`).
|
|
167
203
|
Previously short mode abbreviated names but left "through" in place for
|
|
168
204
|
every field except weekdays.
|
|
205
|
+
- Source is now authored as an ES module in `src/` and bundled with esbuild.
|
|
206
|
+
- Date descriptions always use suffixed numeric ordinals (`1st`, `2nd`, ...).
|
|
207
|
+
- Modernized the toolchain: ESLint 9 (flat config), Mocha 11, Chai 4.
|
|
208
|
+
- Enforced explicit ESLint budgets for cyclomatic `complexity`, `max-depth`,
|
|
209
|
+
and `max-params` as regression guards.
|
|
169
210
|
|
|
170
211
|
### Fixed
|
|
171
212
|
|
|
@@ -236,36 +277,6 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
236
277
|
own clause instead of cross-multiplying into a wall of times
|
|
237
278
|
(`0,30 8-18/2 * * *` reads "at 0 and 30 minutes past the hour, at 8
|
|
238
279
|
a.m., 10 a.m., ..." — six times, not twelve).
|
|
239
|
-
|
|
240
|
-
## [0.1.0]
|
|
241
|
-
|
|
242
|
-
First non-beta release.
|
|
243
|
-
|
|
244
|
-
### Added
|
|
245
|
-
|
|
246
|
-
- Idiomatic descriptions for **lists** (`,`), **ranges** (`-`), and **compound**
|
|
247
|
-
patterns that combine multiple non-trivial fields (e.g.
|
|
248
|
-
`at 30 minutes past the hour from 9 a.m. through 5 p.m.`).
|
|
249
|
-
- Trailing day qualifiers for bare frequencies (e.g. `every minute on Monday`,
|
|
250
|
-
`every hour on January 13`).
|
|
251
|
-
- Dual **ESM** and **CommonJS** builds plus a minified **browser** global, an
|
|
252
|
-
`exports` map, and bundled **TypeScript** type definitions (`cronli5.d.ts`).
|
|
253
|
-
- Continuous integration (GitHub Actions) across Node 18/20/22, with a
|
|
254
|
-
coverage gate.
|
|
255
|
-
- Code coverage via **c8** with enforced thresholds (`npm run coverage`).
|
|
256
|
-
- Property-based tests (**fast-check**), smoke tests against the built
|
|
257
|
-
ESM/CJS artifacts, and type tests (**tsd**, `npm run test:types`).
|
|
258
|
-
|
|
259
|
-
### Changed
|
|
260
|
-
|
|
261
|
-
- Source is now authored as an ES module in `src/` and bundled with esbuild.
|
|
262
|
-
- Date descriptions always use suffixed numeric ordinals (`1st`, `2nd`, ...).
|
|
263
|
-
- Modernized the toolchain: ESLint 9 (flat config), Mocha 11, Chai 4.
|
|
264
|
-
- Enforced explicit ESLint budgets for cyclomatic `complexity`, `max-depth`,
|
|
265
|
-
and `max-params` as regression guards.
|
|
266
|
-
|
|
267
|
-
### Fixed
|
|
268
|
-
|
|
269
280
|
- Weekday/date/month-only patterns no longer drop their qualifier.
|
|
270
281
|
- A specific minute within an hour range is no longer dropped.
|
|
271
282
|
|
package/cronli5.min.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use strict";(()=>{var qn={SUN:0,MON:1,TUE:2,WED:3,THU:4,FRI:5,SAT:6},Jn={JAN:1,FEB:2,MAR:3,APR:4,MAY:5,JUN:6,JUL:7,AUG:8,SEP:9,OCT:10,NOV:11,DEC:12},h={second:{cyclic:!0,max:59,min:0,top:59},minute:{cyclic:!0,max:59,min:0,top:59},hour:{cyclic:!0,max:23,min:0,top:23},date:{aliases:{"?":"*"},cyclic:!0,max:31,min:1,top:31},month:{cyclic:!0,max:12,min:1,numbers:Jn,top:12},weekday:{aliases:{"?":"*",L:"6"},cyclic:!0,max:7,min:0,numbers:qn,top:6},year:{max:9999,min:1970}},k=["second","minute","hour","date","month","weekday","year"],j={"@annually":"0 0 1 1 *","@yearly":"0 0 1 1 *","@monthly":"0 0 1 * *","@weekly":"0 0 * * 0","@daily":"0 0 * * *","@midnight":"0 0 * * *","@hourly":"0 * * * *"},U=6;function s(n,e){return(""+n).indexOf(e)!==-1}function F(n){return Array.from(new Set(n))}function I(n){return/^\d+$/.test(n)}function d(n,e){return I(n)?+n:e[n.toUpperCase()]}function sn(n){return k.forEach(function(r){Vn(n[r],h[r],r)}),n}function Vn(n,e,r){typeof n!="string"&&typeof n!="number"&&un(n,r);let t=""+n;t!=="*"&&(r==="date"&&C(t)||r==="weekday"&&w(t,e)||t.split(",").forEach(function(o){$n(o,e)||un(o,r)}))}function C(n){if(n==="L"||n==="LW"||n==="WL")return!0;let e=/^L-(\d{1,2})$/.exec(n);if(e)return+e[1]>=1&&+e[1]<=30;let r=/^(\d{1,2})W$|^W(\d{1,2})$/.exec(n);if(r){let t=+(r[1]||r[2]);return t>=1&&t<=31}return!1}function w(n,e){if(/L$/.test(n))return v(n.slice(0,-1),e);let r=n.split("#");return r.length===2?v(r[0],e)&&/^[1-5]$/.test(r[1]):!1}function $n(n,e){return s(n,"/")?Yn(n,e):s(n,"-")?an(n,e):v(n,e)}function Yn(n,e){let r=n.split("/");return r.length!==2||!I(r[1])||+r[1]<1?!1:r[0]==="*"||v(r[0],e)||an(r[0],e,!0)}function an(n,e,r){let t=n.split("-");return t.length!==2||!v(t[0],e)||!v(t[1],e)?!1:e.cyclic&&!r?!0:d(t[0],e.numbers)<=d(t[1],e.numbers)}function v(n,e){return n==="*"?!1:I(n)?+n>=e.min&&+n<=e.max:e.numbers?n.toUpperCase()in e.numbers:!1}function un(n,e){throw new Error('`cronli5` was passed an invalid field value "'+n+'" for the '+e+" field.")}function cn(n){k.forEach(function(r){let t=h[r].aliases,i=t&&t[""+n[r]];i&&(n[r]=i)})}function mn(n){return k.forEach(function(r){let t=""+n[r];if(r==="date"&&C(t)||r==="weekday"&&w(t,h[r])){n[r]=t;return}n[r]=Bn(t,h[r])}),n}function Bn(n,e){let r=""+n;if(r==="*")return r;let t=r.split(",").map(function(o){return Xn(Kn(Gn(o,e),e),e)});return t.indexOf("*")!==-1?"*":F(t).sort(function(o,u){return ln(o,e)-ln(u,e)}).join(",")}function Gn(n,e){let r=n.split("/");if(!e.cyclic||r.length!==2||+r[1]!=1)return n;let t=r[0];return s(t,"-")?t:t==="*"||d(t,e.numbers)===e.min?"*":t+"-"+e.top}function Kn(n,e){let r=n.split("/");if(!e.cyclic||typeof e.top!="number"||r.length!==2||s(r[0],"-"))return n;let t=r[0];return(t==="*"?e.min:d(t,e.numbers))+ +r[1]<=e.top?n:t==="*"?""+e.min:t}function Xn(n,e){let r=n.split("/")[0];if(!s(r,"-"))return n;let t=r.split("-");return d(t[0],e.numbers)!==d(t[1],e.numbers)?n:t[0]}function ln(n,e){let r=n.split("/")[0].split("-")[0];return r==="*"?e.min:d(r,e.numbers)}function fn(n,e){let r=n instanceof Array;if(n===null||typeof n>"u"||n===""||r&&n.length===0)throw new Error("`cronli5` expects a non-empty cron pattern as the first argument.");if(r)return dn(n,e);if(typeof n=="object")return Zn(n);if(typeof n=="string")return _n(n,e);throw new Error("`cronli5` was passed an unexpected type.")}function dn(n,e){if(n.length>7)throw new Error("`cronli5` was passed a cron pattern with more than seven fields.");return!e.seconds&&n.length<(e.years?7:6)&&n.unshift("0"),{second:n[0]||"0",minute:n[1]||"*",hour:n[2]||"*",date:n[3]||"*",month:n[4]||"*",weekday:n[5]||"*",year:n[6]||"*"}}function Zn(n){if(!n.second&&!n.minute&&!n.hour)throw new Error("`cronli5` expects that any object being interpreted as a cron pattern have at least one of the following properties: `second`, `minute`, or `hour`");let e=typeof n.second<"u",r=typeof n.minute<"u",t=e?"*":"0",i=e||r?"*":"0";return{second:N(n.second,"0"),minute:N(n.minute,t),hour:N(n.hour,i),date:N(n.date,"*"),month:N(n.month,"*"),weekday:N(n.weekday,"*"),year:N(n.year,"*")}}function N(n,e){return typeof n>"u"?e:n}function _n(n,e){let r=ne(n).split(/\s+/);return dn(r,e)}function ne(n){let e=n.trim();if(e.charAt(0)!=="@")return n;let r=e.toLowerCase();if(Object.hasOwn(j,r))return j[r];throw new Error("`cronli5` does not recognize the macro `"+e+"`.")}function gn(n){return n!=="*"&&!s(n,",")&&!s(n,"-")&&!s(n,"/")}function Q(n){return s(n,"-")&&!s(n,",")&&!s(n,"/")}function ee(n){return s(n,"/")&&!s(n,",")}function q(n){return n!=="*"&&!s(n,"-")&&!s(n,"/")}function J(n){return n!=="*"&&!Q(n)&&!ee(n)}function R(n,e,r){let t=[],i=n;for(;i<=r;)t.push(i),i+=e;return t}function hn(n,e,r,t){let i=n.split("/"),o=+i[1];if(s(i[0],"-")){let f=i[0].split("-");return R(d(f[0],t),o,d(f[1],t))}let u=i[0]==="*"?e:d(i[0],t);return R(u,o,r)}function V(n,e,r){let t=[];return n.split(",").forEach(function(o){if(s(o,"/"))t.push(...hn(o,e,r));else if(s(o,"-")){let u=o.split("-");+u[0]<=+u[1]?t.push(...R(+u[0],1,+u[1])):(t.push(...R(+u[0],1,r)),t.push(...R(e,1,+u[1])))}else t.push(+o)}),F(t)}function re(n){return q(n)?n.split(",").map(Number):[0]}function te(n){if(n==="*")return[0,59];if(Q(n)){let e=n.split("-");if(+e[0]<=+e[1])return[+e[0],+e[1]]}return null}function ie(n){return n==="*"?59:Math.max(...V(n,0,59))}function oe(n){if(gn(n)&&n!=="0")return+n}function ue(n,e){return n==="*"?"wildcard":e==="date"&&C(n)||e==="weekday"&&w(n,h.weekday)?"quartz":s(n,",")?"list":s(n,"/")?"step":s(n,"-")?"range":"single"}function se(n,e,r){return e==="wildcard"||e==="quartz"?null:n.split(",").map(function(i){if(s(i,"/")){let o=i.split("/");return{fires:hn(i,r.min,r.top,r.numbers),interval:+o[1],kind:"step",startToken:o[0]}}return s(i,"-")?{bounds:i.split("-"),kind:"range"}:{kind:"single",value:i}})}function pn(n){let e={},r={};k.forEach(function(u){e[u]=ue(n[u],u),r[u]=se(n[u],e[u],h[u])});let i={analyses:{clockSecond:oe(n.second),lastMinuteFire:ie(n.minute),minuteSpan:te(n.minute),segments:r},pattern:n,shapes:e};return{...i,plan:ae(i)}}function ae(n){let{analyses:e,pattern:r,shapes:t}=n;if(r.second!=="0"){let i=le(r,t,e);if(i)return i}return yn(r,t,e)||Sn(r,t,e)}function le(n,e,r){let t=ce(n,e);return t||(n.hour==="*"&&e.minute==="single"&&n.second!=="*"?{kind:"secondsWithinMinute",singleSecond:e.second==="single"}:e.second==="single"&&q(n.minute)&&J(n.hour)?null:{kind:"composeSeconds",rest:yn(n,e,r)||Sn(n,e,r)})}function ce(n,e){return n.minute!=="*"||n.hour!=="*"?null:n.second==="*"?{kind:"everySecond"}:e.second==="single"?{kind:"secondPastMinute"}:{kind:"standaloneSeconds"}}function yn(n,e,r){if(e.minute==="step")return{hours:fe(n,e,r),kind:"minuteFrequency"};if(e.hour==="single"&&r.minuteSpan)return{hour:+n.hour,kind:"minuteSpanInHour",span:r.minuteSpan};let t=de(n,e);if(t)return t;let i=me(n,e);if(i)return i;if(n.hour==="*")return ge(n,e)}function bn(n){let[e,r]=n.split("/"),t=e==="*"?0:+e;return e.indexOf("-")===-1&&24%+r===0&&t<+r}function me(n,e){return e.hour!=="step"?null:n.minute==="*"?bn(n.hour)?{form:"wildcard",kind:"minuteSpanAcrossHourStep"}:{form:"wildcard",kind:"minutesAcrossHours",times:x(n.hour)}:e.minute==="range"?{form:"range",kind:"minuteSpanAcrossHourStep"}:null}function fe(n,e,r){if(e.hour==="list")return{kind:"during",times:x(n.hour)};if(e.hour==="range"){let t=n.hour.split("-");return{from:+t[0],kind:"window",last:r.lastMinuteFire,to:+t[1]}}return e.hour==="single"?{from:+n.hour,kind:"window",last:r.lastMinuteFire,to:+n.hour}:e.hour==="step"?bn(n.hour)?{kind:"step"}:{kind:"during",times:x(n.hour)}:{kind:"none"}}function de(n,e){return J(n.hour)?n.minute==="*"?{form:"wildcard",kind:"minutesAcrossHours",times:x(n.hour)}:e.minute==="range"||e.minute==="list"&&s(n.minute,"-")&&!s(n.minute,"/")?{form:e.minute==="range"?"range":"list",kind:"minutesAcrossHours",times:x(n.hour)}:null:null}function ge(n,e){if(e.minute==="range")return{kind:"rangeOfMinutes"};if(e.minute==="list")return{kind:"multipleMinutes"};if(n.minute==="*")return{kind:"everyMinute"};if(n.minute!=="0")return{kind:"singleMinute"}}function Sn(n,e,r){if(e.hour==="range"){let t=n.hour.split("-"),i="lead";return n.minute==="*"?i="wildcard":e.minute==="range"&&(i="range"),{from:+t[0],kind:"hourRange",last:r.lastMinuteFire,minuteForm:i,to:+t[1]}}return e.hour==="step"&&n.minute==="0"?{kind:"hourStep"}:n.hour==="*"?{kind:"everyHour"}:he(n,r)}function he(n,e){let r=V(n.hour,0,23),t=re(n.minute);if(r.length*t.length>U)return{fold:t.length===1,kind:"compactClockTimes",minute:t[0]};let i=[];return r.forEach(function(u){t.forEach(function(l){i.push({hour:u,minute:l,second:e.clockSecond})})}),{kind:"clockTimes",times:i}}function x(n){let e=V(n,0,23);return e.length<=U?{fires:e,kind:"fires"}:{kind:"segments"}}function On(n,e){let r=fn(n,e);return cn(r),sn(r),mn(r)}function $(n){return n=""+n,n.length<2?"0"+n:n}function kn(n,e,r){return r.short?n:e[n]||n}function Y(n,{sep:e,pad:r,lean:t}){let i=r?$(n.hour):""+n.hour;return t&&!n.minute&&!n.second?i:i+e+$(n.minute)+(n.second?e+$(n.second):"")}var B={gb:{am:"am",closeUp:!0,dayFirst:!0,midday:"midday",midnight:"midnight",ordinals:!1,pm:"pm",sep:".",serialComma:!1,through:" to "},us:{am:"a.m.",closeUp:!1,dayFirst:!1,midday:"noon",midnight:"midnight",ordinals:!1,pm:"p.m.",sep:":",serialComma:!0,through:" through "},house:{am:"AM",closeUp:!1,dayFirst:!1,midday:"noon",midnight:"midnight",ordinals:!0,pm:"PM",sep:":",serialComma:!0,through:" - "}};function Nn(n){return typeof n=="object"&&n!==null?{...B.us,...n}:B[n==="uk"?"gb":n]||B.us}var pe=["zero","one","two","three","four","five","six","seven","eight","nine","ten"],G=["th","st","nd","rd"],g=[null,["January","Jan"],["February","Feb"],["March","Mar"],["April","Apr"],["May","May"],["June","Jun"],["July","Jul"],["August","Aug"],["September","Sep"],["October","Oct"],["November","Nov"],["December","Dec"]],y=[["Sunday","Sun"],["Monday","Mon"],["Tuesday","Tue"],["Wednesday","Wed"],["Thursday","Thu"],["Friday","Fri"],["Saturday","Sat"]],ye={JAN:g[1],FEB:g[2],MAR:g[3],APR:g[4],MAY:g[5],JUN:g[6],JUL:g[7],AUG:g[8],SEP:g[9],OCT:g[10],NOV:g[11],DEC:g[12]},be={SUN:y[0],MON:y[1],TUE:y[2],WED:y[3],THU:y[4],FRI:y[5],SAT:y[6]},Se=[null,"first","second","third","fourth","fifth"];function Oe(n){return n=n||{},{ampm:typeof n.ampm=="boolean"?n.ampm:!0,lenient:!!n.lenient,seconds:!!n.seconds,short:!!n.short,style:Nn(n.dialect),years:!!n.years}}function ke(n,e){return Xe(zn(n,n.plan,e),n,e)}function zn(n,e,r){let t=Qe[e.kind];return t(n,e,r)}function Ne(n,e,r){return"every second"+a(n,r)}function ze(n,e,r){return H(n,r)+a(n,r)}function Pe(n,e,r){let t=n.pattern.second;return m(t,r)+" "+P(t,"second")+" past the minute, every minute"+a(n,r)}function ve(n,e,r){let t=n.pattern.minute,i=m(t,r),o=P(t,"minute");if(e.singleSecond){let u=n.pattern.second;return i+" "+o+" and "+m(u,r)+" "+P(u,"second")+" past the hour, every hour"+a(n,r)}return H(n,r)+", "+i+" "+o+" past the hour, every hour"+a(n,r)}function Ce(n,e,r){return H(n,r)+", "+zn(n,e.rest,r)}function H(n,e){let r=n.pattern.second,t=n.shapes.second;if(r==="*")return"every second";if(t==="step")return wn(n.analyses.segments.second[0],"second","minute",e);if(t==="range"){let i=r.split("-"),o=E(i,e);return"every second from "+o(i[0])+O(e)+o(i[1])+" past the minute"}return t==="single"?"at "+m(r,e)+" "+P(r,"second")+" past the minute":b(T(n.analyses.segments.second,e),"second","minute",e)}function we(n,e,r){return"every minute"+a(n,r)}function Re(n,e,r){let t=n.pattern.minute;return m(t,r)+" "+P(t,"minute")+" past the hour, every hour"+a(n,r)}function xe(n,e,r){return L(n.pattern.minute,r)+a(n,r)}function Me(n,e,r){return b(T(n.analyses.segments.minute,r),"minute","hour",r)+a(n,r)}function Te(n,e,r){let t=wn(n.analyses.segments.minute[0],"minute","hour",r);return e.hours.kind==="during"?t+=" during the "+Z(n,e.hours.times,!1,r)+" hours":e.hours.kind==="window"?t+=" "+Cn(e.hours,r):e.hours.kind==="step"&&(t+=" "+Pn(n.analyses.segments.hour[0],r)),t+a(n,r)}function Fe(n,e,r){return"every minute from "+c({hour:e.hour,minute:e.span[0]},r)+O(r)+c({hour:e.hour,minute:e.span[1]},r)+a(n,r)}function Ie(n,e,r){if(e.form==="wildcard")return"every minute during the "+Z(n,e.times,!1,r)+" hours"+a(n,r);let t=Z(n,e.times,!0,r);return(e.form==="range"?L(n.pattern.minute,r):b(T(n.analyses.segments.minute,r),"minute","hour",r))+", at "+t+a(n,r)}var He={2:"other",3:"third",4:"fourth",6:"sixth",8:"eighth",12:"twelfth"};function Pn(n,e){let r="during every "+He[n.interval]+" hour",t=n.startToken==="*"?0:+n.startToken;return t===0?r:r+" starting at "+c({hour:t,minute:0},e)}function Le(n,e,r){let t=n.analyses.segments.hour[0];return e.form==="wildcard"?"every minute "+Pn(t,r)+a(n,r):L(n.pattern.minute,r)+", "+Rn(t,r)+a(n,r)}function L(n,e){let r=n.split("-"),t=E(r,e);return"every minute from "+t(r[0])+O(e)+t(r[1])+" past the hour"}function Ee(n,e,r){return"every hour"+a(n,r)}function Ae(n,e,r){let t=Cn(e,r);return e.minuteForm==="wildcard"?"every minute "+t+a(n,r):e.minuteForm==="range"?L(n.pattern.minute,r)+", "+t+a(n,r):vn(n,r)+" "+t+a(n,r)}function vn(n,e){return n.pattern.minute==="0"?"every hour":b(T(n.analyses.segments.minute,e),"minute","hour",e)}function We(n,e,r){return Rn(n.analyses.segments.hour[0],r)+a(n,r)}function Cn(n,e){return"from "+c({hour:n.from,minute:0},e)+O(e)+c({hour:n.to,minute:n.last},e)}function De(n,e,r){let t=rn(e.times),i=e.times.map(function(u){return c({hour:u.hour,minute:u.minute,second:u.second,plain:t},r)});return xn(n,r)+"at "+S(i,r)}function je(n,e,r){if(e.fold){if(n.analyses.segments.hour.some(function(f){return f.kind==="range"})&&!n.analyses.clockSecond)return Ue(n,e,r)+a(n,r);let o={minute:e.minute,second:n.analyses.clockSecond};return xn(n,r)+"at "+_(n,o,!0,r)}let t=b(T(n.analyses.segments.minute,r),"minute","hour",r)+", at "+_(n,{minute:0,second:null},!0,r)+a(n,r);return n.analyses.clockSecond?H(n,r)+", "+t:t}function Ue(n,e,r){let t=e.minute,i=[],o=[];n.analyses.segments.hour.forEach(function(l){l.kind==="range"?i.push("from "+c({hour:l.bounds[0],minute:0},r)+O(r)+c({hour:l.bounds[1],minute:t},r)):l.kind==="step"?o.push(...l.fires):o.push(+l.value)});let u=vn(n,r)+" "+S(i,r);return o.length&&(u+=" and at "+S(o.map(function(l){return c({hour:l,minute:t},r)}),r)),u}var Qe={clockTimes:De,compactClockTimes:je,composeSeconds:Ce,everyHour:Ee,everyMinute:we,everySecond:Ne,hourRange:Ae,hourStep:We,minuteFrequency:Te,minuteSpanAcrossHourStep:Le,minuteSpanInHour:Fe,minutesAcrossHours:Ie,multipleMinutes:Me,rangeOfMinutes:xe,secondPastMinute:Pe,secondsWithinMinute:ve,singleMinute:Re,standaloneSeconds:ze};function wn(n,e,r,t){if(n.startToken.indexOf("-")!==-1)return b(K(n.fires,t),e,r,t);let i=n.startToken==="*"?0:+n.startToken,o=n.interval;return i!==0?n.fires.length<=3?b(K(n.fires,t),e,r,t):"every "+m(o,t)+" "+e+"s from "+m(i,t)+" "+P(i,e)+" past the "+r:60%o===0?"every "+m(o,t)+" "+e+"s":n.fires.length<=2?b(K(n.fires,t),e,r,t):"every "+m(o,t)+" "+e+"s past the "+r}function Rn(n,e){if(n.startToken.indexOf("-")!==-1)return"at "+X(n.fires,e);let r=n.startToken==="*"?0:+n.startToken,t=n.interval;return r===0&&24%t===0?"every "+m(t,e)+" hours":n.fires.length<=3?"at "+X(n.fires,e):r===0?"every "+m(t,e)+" hours from midnight":"every "+m(t,e)+" hours from "+c({hour:r,minute:0},e)}function E(n,e){let r=n.some(function(i){return+i>10});return function(i){return r?""+i:m(i,e)}}function K(n,e){return n.map(E(n,e))}function T(n,e){let r=n.flatMap(function(o){return o.kind==="range"?o.bounds:o.kind==="step"?o.fires:[o.value]}),t=E(r,e);return n.flatMap(function(o){return o.kind==="range"?[t(o.bounds[0])+O(e)+t(o.bounds[1])]:o.kind==="step"?o.fires.map(t):[t(o.value)]})}function b(n,e,r,t){return"at "+S(n,t)+" "+e+"s past the "+r}function qe(n,e,r){return(+n==0||+n==12)&&+e==0&&!(typeof r=="number"&&r>0)}function rn(n){let e=n.filter(function(t){return qe(t.hour,t.minute,t.second)});return e.length>0&&e.length<n.length}function X(n,e){let r=rn(n.map(function(o){return{hour:o,minute:0}})),t=n.map(function(o){return c({hour:o,minute:0,plain:r},e)});return S(t,e)}function Z(n,e,r,t){return e.kind==="fires"?X(e.fires,t):_(n,{minute:0,second:null},r,t)}function Je(n){return n.kind==="range"?n.bounds:n.kind==="step"?n.fires:[n.value]}function _(n,e,r,t){let{minute:i,second:o}=e,u=n.analyses.segments.hour,f=rn(u.flatMap(function(p){return Je(p).map(function(D){return{hour:+D,minute:i,second:o}})})),l=[];return u.forEach(function(p){p.kind==="step"?l.push(...p.fires.map(function(D){return c({hour:D,minute:i,second:o,plain:f},t)})):p.kind==="range"?l.push(c({hour:p.bounds[0],minute:i,second:o,plain:f},t)+O(t)+c({hour:p.bounds[1],minute:i,second:o,plain:f},t)):l.push(c({hour:p.value,minute:i,second:o,plain:f},t))}),S(Ve(l,u,r),t)}function Ve(n,e,r){let t=e.some(function(o){return o.kind==="range"});return!r||!t?n:n.map(function(o,u){return u===0?o:"at "+o})}function S(n,e){if(n.length<=1)return n.join("");if(n.length===2)return n[0]+" and "+n[1];let r=e.style.serialComma?", and ":" and ";return n.slice(0,-1).join(", ")+r+n[n.length-1]}var $e={all:"",month:"in ",stepDate:"on ",weekday:"on "},Ye={all:"every day",month:"every day in ",stepDate:"",weekday:"every "};function a(n,e){let r=Mn(n,$e,e);return r&&" "+r}function xn(n,e){return Mn(n,Ye,e)+" "}function Mn(n,e,r){let t=n.pattern;return t.date!=="*"&&t.weekday!=="*"?Ge(n,r):t.date!=="*"?Be(n,e,r):t.weekday!=="*"?(In(t.weekday,r)||e.weekday+An(n,r))+z(n,r):t.month!=="*"?e.month+A(n,r):e.all}function Be(n,e,r){let t=n.pattern,i=Fn(t.date,r);return i?i+z(n,r):tn(t.date)?e.stepDate+Ln(t.date)+z(n,r):t.month!=="*"&&!Tn(n)?"on the "+nn(n,r)+z(n,r):t.month!=="*"?"on "+Hn(n,r):"on the "+nn(n,r)}function Tn(n){return!En(n.pattern.month)&&n.analyses.segments.month.every(function(r){return r.kind!=="range"})}function Ge(n,e){let r=n.pattern,t=In(r.weekday,e)||"on "+An(n,e),i=Fn(r.date,e);return i?i+z(n,e)+" or "+t:tn(r.date)?Ln(r.date)+z(n,e)+" or "+t:r.month!=="*"&&Tn(n)?"on "+Hn(n,e)+" or "+t+" in "+A(n,e):"on the "+nn(n,e)+" or "+t+z(n,e)}function Fn(n,e){if(n==="L")return"on the last day of the month";if(n==="LW"||n==="WL")return"on the last weekday of the month";let r=/^L-(\d{1,2})$/.exec(n);if(r)return m(+r[1],e)+" "+P(r[1],"day")+" before the last day of the month";let t=/^(\d{1,2})W$|^W(\d{1,2})$/.exec(n);if(t)return"on the weekday nearest the "+M(t[1]||t[2])}function In(n,e){let r=n.split("#");if(r.length===2)return"on the "+Se[+r[1]]+" "+en(r[0],e)+" of the month";if(/L$/.test(n))return"on the last "+en(n.slice(0,-1),e)+" of the month"}function Hn(n,e){let r=A(n,e),t=W(n.analyses.segments.date,e.style.ordinals?M:Ke,e);return e.style.dayFirst?t+" "+r:r+" "+t}function Ke(n){return""+n}function z(n,e){return n.pattern.month==="*"?"":" in "+A(n,e)}function Ln(n){let e=n.split("/"),r=+e[1],t=e[0],o=(r===2?"every other":"every "+M(r))+" day of the month";return t!=="*"&&t!=="1"&&(o+=" from the "+M(t)),o}function nn(n,e){return W(n.analyses.segments.date,M,e)}function A(n,e){let r=En(n.pattern.month);return r||W(n.analyses.segments.month,function(i){return er(i,e)},e)}function En(n){if(!tn(n))return null;let[e,r]=n.split("/");return+r!=2?null:e==="*"||e==="1"?"every odd-numbered month":e==="2"?"every even-numbered month":null}function An(n,e){return W(n.analyses.segments.weekday,function(t){return en(t,e)},e)}function W(n,e,r){let t=[];return n.forEach(function(o){o.kind==="step"?t.push(...o.fires.map(e)):o.kind==="range"?t.push(o.bounds.map(e).join(O(r))):t.push(e(o.value))}),S(t,r)}function tn(n){return n.indexOf("/")!==-1&&n.indexOf("-")===-1&&n.indexOf(",")===-1}function Xe(n,e,r){let t=e.pattern.year;if(t==="*")return n;if(t.indexOf("/")!==-1)return n+" "+_e(t,r);let i=Ze(t,r);if(t.indexOf("-")===-1&&t.indexOf(",")===-1&&e.pattern.date!=="*"&&n.indexOf(" at ")!==-1){let o=r.style.dayFirst?" ":", ";return n.replace(" at ",o+i+" at ")}return n+" in "+i}function Ze(n,e){return n.indexOf(",")!==-1?S(n.split(","),e):n}function _e(n,e){let r=n.split("/"),t=+r[1],i=r[0];if(t<=1)return"every year";let o="every "+m(t,e)+" years";return i!=="*"&&i!=="0"&&(o+=" from "+i),o}function c(n,e){let{hour:r,minute:t,plain:i}=n,o=typeof n.second=="number"&&n.second>0?n.second:0;return e.ampm?nr({hour:r,minute:t,second:o,plain:i},e):Y({hour:r,minute:t,second:o},{pad:!0,sep:e.style.sep})}function nr(n,e){let{hour:r,minute:t,second:i,plain:o}=n,u=e.style;if(!o&&+t==0&&!i){if(+r==0)return u.midnight;if(+r==12)return u.midday}return Y({hour:r%12||12,minute:t,second:i},{lean:!0,sep:u.sep})+(u.closeUp?"":" ")+(r<12?u.am:u.pm)}function m(n,e){return kn(n,pe,e)}function P(n,e){return+n==1?e:e+"s"}function O(n){return n.short?"-":n.style.through}function M(n){let e=Math.abs(n),r=G[e];return r||(e=(e%100-20)%10,r=G[e]||G[0]),n+r}function er(n,e){let r=g[n]||ye[n];return r&&r[e.short?1:0]}function en(n,e){let r=n===7||n==="7"?0:n,t=y[r]||be[r];return t&&t[e.short?1:0]}var rr={describe:ke,fallback:"an unrecognizable cron pattern",options:Oe,reboot:"at system startup",sentence:n=>"Runs "+n+"."},Wn=rr;/**
|
|
1
|
+
"use strict";(()=>{var qn={SUN:0,MON:1,TUE:2,WED:3,THU:4,FRI:5,SAT:6},Vn={JAN:1,FEB:2,MAR:3,APR:4,MAY:5,JUN:6,JUL:7,AUG:8,SEP:9,OCT:10,NOV:11,DEC:12},h={second:{cyclic:!0,max:59,min:0,top:59},minute:{cyclic:!0,max:59,min:0,top:59},hour:{cyclic:!0,max:23,min:0,top:23},date:{aliases:{"?":"*"},cyclic:!0,max:31,min:1,top:31},month:{cyclic:!0,max:12,min:1,numbers:Vn,top:12},weekday:{aliases:{"?":"*",L:"6"},cyclic:!0,max:7,min:0,numbers:qn,top:6},year:{max:9999,min:1970}},k=["second","minute","hour","date","month","weekday","year"],U={"@annually":"0 0 1 1 *","@yearly":"0 0 1 1 *","@monthly":"0 0 1 * *","@weekly":"0 0 * * 0","@daily":"0 0 * * *","@midnight":"0 0 * * *","@hourly":"0 * * * *"},Q=6;function s(n,e){return(""+n).indexOf(e)!==-1}function F(n){return Array.from(new Set(n))}function I(n){return/^\d+$/.test(n)}function d(n,e){return I(n)?+n:e[n.toUpperCase()]}function an(n){return k.forEach(function(r){Jn(n[r],h[r],r)}),n}function Jn(n,e,r){typeof n!="string"&&typeof n!="number"&&sn(n,r);let t=""+n;t!=="*"&&(r==="date"&&C(t)||r==="weekday"&&w(t,e)||t.split(",").forEach(function(o){$n(o,e)||sn(o,r)}))}function C(n){if(n==="L"||n==="LW"||n==="WL")return!0;let e=/^L-(\d{1,2})$/.exec(n);if(e)return+e[1]>=1&&+e[1]<=30;let r=/^(\d{1,2})W$|^W(\d{1,2})$/.exec(n);if(r){let t=+(r[1]||r[2]);return t>=1&&t<=31}return!1}function w(n,e){if(/L$/.test(n))return v(n.slice(0,-1),e);let r=n.split("#");return r.length===2?v(r[0],e)&&/^[1-5]$/.test(r[1]):!1}function $n(n,e){return s(n,"/")?Yn(n,e):s(n,"-")?ln(n,e):v(n,e)}function Yn(n,e){let r=n.split("/");return r.length!==2||!I(r[1])||+r[1]<1?!1:r[0]==="*"||v(r[0],e)||ln(r[0],e,!0)}function ln(n,e,r){let t=n.split("-");return t.length!==2||!v(t[0],e)||!v(t[1],e)?!1:e.cyclic&&!r?!0:d(t[0],e.numbers)<=d(t[1],e.numbers)}function v(n,e){return n==="*"?!1:I(n)?+n>=e.min&&+n<=e.max:e.numbers?n.toUpperCase()in e.numbers:!1}function sn(n,e){throw new Error('`cronli5` was passed an invalid field value "'+n+'" for the '+e+" field.")}function mn(n){k.forEach(function(r){let t=h[r].aliases,i=t&&t[""+n[r]];i&&(n[r]=i)})}function fn(n){return k.forEach(function(r){let t=""+n[r];if(r==="date"&&C(t)||r==="weekday"&&w(t,h[r])){n[r]=t;return}n[r]=Bn(t,h[r])}),n}function Bn(n,e){let r=""+n;if(r==="*")return r;let t=r.split(",").map(function(o){return Zn(Kn(Gn(o,e),e),e)});return t.indexOf("*")!==-1?"*":F(t).sort(function(o,u){return cn(o,e)-cn(u,e)}).join(",")}function Gn(n,e){let r=n.split("/");if(!e.cyclic||r.length!==2||+r[1]!=1)return n;let t=r[0];return s(t,"-")?t:t==="*"||d(t,e.numbers)===e.min?"*":t+"-"+e.top}function Kn(n,e){let r=n.split("/");if(!e.cyclic||typeof e.top!="number"||r.length!==2||s(r[0],"-"))return n;let t=r[0];return(t==="*"?e.min:d(t,e.numbers))+ +r[1]<=e.top?n:t==="*"?""+e.min:t}function Zn(n,e){let r=n.split("/")[0];if(!s(r,"-"))return n;let t=r.split("-");return d(t[0],e.numbers)!==d(t[1],e.numbers)?n:t[0]}function cn(n,e){let r=n.split("/")[0].split("-")[0];return r==="*"?e.min:d(r,e.numbers)}function dn(n,e){let r=n instanceof Array;if(n===null||typeof n>"u"||n===""||r&&n.length===0)throw new Error("`cronli5` expects a non-empty cron pattern as the first argument.");if(r)return gn(n,e);if(typeof n=="object")return Xn(n);if(typeof n=="string")return _n(n,e);throw new Error("`cronli5` was passed an unexpected type.")}function gn(n,e){if(n.length>7)throw new Error("`cronli5` was passed a cron pattern with more than seven fields.");return!e.seconds&&n.length<(e.years?7:6)&&n.unshift("0"),{second:n[0]||"0",minute:n[1]||"*",hour:n[2]||"*",date:n[3]||"*",month:n[4]||"*",weekday:n[5]||"*",year:n[6]||"*"}}function Xn(n){if(!n.second&&!n.minute&&!n.hour)throw new Error("`cronli5` expects that any object being interpreted as a cron pattern have at least one of the following properties: `second`, `minute`, or `hour`");let e=typeof n.second<"u",r=typeof n.minute<"u",t=e?"*":"0",i=e||r?"*":"0";return{second:N(n.second,"0"),minute:N(n.minute,t),hour:N(n.hour,i),date:N(n.date,"*"),month:N(n.month,"*"),weekday:N(n.weekday,"*"),year:N(n.year,"*")}}function N(n,e){return typeof n>"u"?e:n}function _n(n,e){let r=ne(n).split(/\s+/);return gn(r,e)}function ne(n){let e=n.trim();if(e.charAt(0)!=="@")return n;let r=e.toLowerCase();if(Object.hasOwn(U,r))return U[r];throw new Error("`cronli5` does not recognize the macro `"+e+"`.")}function hn(n){return n!=="*"&&!s(n,",")&&!s(n,"-")&&!s(n,"/")}function q(n){return s(n,"-")&&!s(n,",")&&!s(n,"/")}function ee(n){return s(n,"/")&&!s(n,",")}function V(n){return n!=="*"&&!s(n,"-")&&!s(n,"/")}function J(n){return n!=="*"&&!q(n)&&!ee(n)}function R(n,e,r){let t=[],i=n;for(;i<=r;)t.push(i),i+=e;return t}function pn(n,e,r,t){let i=n.split("/"),o=+i[1];if(s(i[0],"-")){let m=i[0].split("-");return R(d(m[0],t),o,d(m[1],t))}let u=i[0]==="*"?e:d(i[0],t);return R(u,o,r)}function $(n,e,r){let t=[];return n.split(",").forEach(function(o){if(s(o,"/"))t.push(...pn(o,e,r));else if(s(o,"-")){let u=o.split("-");+u[0]<=+u[1]?t.push(...R(+u[0],1,+u[1])):(t.push(...R(+u[0],1,r)),t.push(...R(e,1,+u[1])))}else t.push(+o)}),F(t)}function re(n){return V(n)?n.split(",").map(Number):[0]}function te(n){if(n==="*")return[0,59];if(q(n)){let e=n.split("-");if(+e[0]<=+e[1])return[+e[0],+e[1]]}return null}function ie(n){return n==="*"?59:Math.max(...$(n,0,59))}function oe(n){if(hn(n)&&n!=="0")return+n}function ue(n,e){return n==="*"?"wildcard":e==="date"&&C(n)||e==="weekday"&&w(n,h.weekday)?"quartz":s(n,",")?"list":s(n,"/")?"step":s(n,"-")?"range":"single"}function se(n,e,r){return e==="wildcard"||e==="quartz"?null:n.split(",").map(function(i){if(s(i,"/")){let o=i.split("/");return{fires:pn(i,r.min,r.top,r.numbers),interval:+o[1],kind:"step",startToken:o[0]}}return s(i,"-")?{bounds:i.split("-"),kind:"range"}:{kind:"single",value:i}})}function yn(n){let e={},r={};k.forEach(function(u){e[u]=ue(n[u],u),r[u]=se(n[u],e[u],h[u])});let i={analyses:{clockSecond:oe(n.second),lastMinuteFire:ie(n.minute),minuteSpan:te(n.minute),segments:r},pattern:n,shapes:e};return{...i,plan:ae(i)}}function ae(n){let{analyses:e,pattern:r,shapes:t}=n;if(r.second!=="0"){let i=le(r,t,e);if(i)return i}return bn(r,t,e)||On(r,t,e)}function le(n,e,r){let t=ce(n,e);return t||(n.hour==="*"&&e.minute==="single"&&n.second!=="*"?{kind:"secondsWithinMinute",singleSecond:e.second==="single"}:e.second==="single"&&V(n.minute)&&J(n.hour)?null:{kind:"composeSeconds",rest:bn(n,e,r,!0)||On(n,e,r,!0)})}function ce(n,e){return n.minute!=="*"||n.hour!=="*"?null:n.second==="*"?{kind:"everySecond"}:e.second==="single"?{kind:"secondPastMinute"}:{kind:"standaloneSeconds"}}function bn(n,e,r,t=!1){if(e.minute==="step")return{hours:fe(n,e,r),kind:"minuteFrequency"};if(e.hour==="single"&&r.minuteSpan)return{hour:+n.hour,kind:"minuteSpanInHour",span:r.minuteSpan};let i=de(n,e);if(i)return i;let o=me(n,e);if(o)return o;if(n.hour==="*")return ge(n,e,t)}function Sn(n){let[e,r]=n.split("/"),t=e==="*"?0:+e;return e.indexOf("-")===-1&&24%+r===0&&t<+r}function me(n,e){return e.hour!=="step"?null:n.minute==="*"?Sn(n.hour)?{form:"wildcard",kind:"minuteSpanAcrossHourStep"}:{form:"wildcard",kind:"minutesAcrossHours",times:M(n.hour)}:e.minute==="range"?{form:"range",kind:"minuteSpanAcrossHourStep"}:null}function fe(n,e,r){if(e.hour==="list")return{kind:"during",times:M(n.hour)};if(e.hour==="range"){let t=n.hour.split("-");return{from:+t[0],kind:"window",last:r.lastMinuteFire,to:+t[1]}}return e.hour==="single"?{from:+n.hour,kind:"window",last:r.lastMinuteFire,to:+n.hour}:e.hour==="step"?Sn(n.hour)?{kind:"step"}:{kind:"during",times:M(n.hour)}:{kind:"none"}}function de(n,e){return J(n.hour)?n.minute==="*"?{form:"wildcard",kind:"minutesAcrossHours",times:M(n.hour)}:e.minute==="range"||e.minute==="list"&&s(n.minute,"-")&&!s(n.minute,"/")?{form:e.minute==="range"?"range":"list",kind:"minutesAcrossHours",times:M(n.hour)}:null:null}function ge(n,e,r){if(e.minute==="range")return{kind:"rangeOfMinutes"};if(e.minute==="list")return{kind:"multipleMinutes"};if(n.minute==="*")return{kind:"everyMinute"};if(n.minute!=="0"||r)return{kind:"singleMinute"}}function On(n,e,r,t=!1){let i=t&&n.minute==="0";return e.hour==="range"&&!i?he(n,e,r):e.hour==="step"&&n.minute==="0"&&!t?{kind:"hourStep"}:n.hour==="*"&&!i?{kind:"everyHour"}:pe(n,r,i)}function he(n,e,r){let t=n.hour.split("-"),i="lead";return n.minute==="*"?i="wildcard":e.minute==="range"&&(i="range"),{boundMinute:e.minute==="range"||e.minute==="list"?null:r.lastMinuteFire,from:+t[0],kind:"hourRange",last:r.lastMinuteFire,minuteForm:i,to:+t[1]}}function pe(n,e,r=!1){let t=$(n.hour,0,23),i=re(n.minute);if(!r&&t.length*i.length>Q)return{fold:i.length===1,kind:"compactClockTimes",minute:i[0]};let o=[];return t.forEach(function(m){i.forEach(function(D){o.push({hour:m,minute:D,second:e.clockSecond})})}),{kind:"clockTimes",times:o}}function M(n){let e=$(n,0,23);return e.length<=Q?{fires:e,kind:"fires"}:{kind:"segments"}}function kn(n,e){let r=dn(n,e);return mn(r),an(r),fn(r)}function Y(n){return n=""+n,n.length<2?"0"+n:n}function Nn(n,e,r){return r.short?n:e[n]||n}function B(n,{sep:e,pad:r,lean:t}){let i=r?Y(n.hour):""+n.hour;return t&&!n.minute&&!n.second?i:i+e+Y(n.minute)+(n.second?e+Y(n.second):"")}var G={gb:{am:"am",closeUp:!0,dayFirst:!0,midday:"midday",midnight:"midnight",ordinals:!1,pm:"pm",sep:".",serialComma:!1,through:" to "},us:{am:"a.m.",closeUp:!1,dayFirst:!1,midday:"noon",midnight:"midnight",ordinals:!1,pm:"p.m.",sep:":",serialComma:!0,through:" through "},house:{am:"AM",closeUp:!1,dayFirst:!1,midday:"noon",midnight:"midnight",ordinals:!0,pm:"PM",sep:":",serialComma:!0,through:" - "}};function zn(n){return typeof n=="object"&&n!==null?{...G.us,...n}:G[n==="uk"?"gb":n]||G.us}var ye=["zero","one","two","three","four","five","six","seven","eight","nine","ten"],K=["th","st","nd","rd"],g=[null,["January","Jan"],["February","Feb"],["March","Mar"],["April","Apr"],["May","May"],["June","Jun"],["July","Jul"],["August","Aug"],["September","Sep"],["October","Oct"],["November","Nov"],["December","Dec"]],y=[["Sunday","Sun"],["Monday","Mon"],["Tuesday","Tue"],["Wednesday","Wed"],["Thursday","Thu"],["Friday","Fri"],["Saturday","Sat"]],be={JAN:g[1],FEB:g[2],MAR:g[3],APR:g[4],MAY:g[5],JUN:g[6],JUL:g[7],AUG:g[8],SEP:g[9],OCT:g[10],NOV:g[11],DEC:g[12]},Se={SUN:y[0],MON:y[1],TUE:y[2],WED:y[3],THU:y[4],FRI:y[5],SAT:y[6]},Oe=[null,"first","second","third","fourth","fifth"];function ke(n){return n=n||{},{ampm:typeof n.ampm=="boolean"?n.ampm:!0,lenient:!!n.lenient,seconds:!!n.seconds,short:!!n.short,style:zn(n.dialect),years:!!n.years}}function Ne(n,e){return _e(Pn(n,n.plan,e),n,e)}function Pn(n,e,r){let t=Ve[e.kind];return t(n,e,r)}function ze(n,e,r){return"every second"+a(n,r)}function Pe(n,e,r){return H(n,r)+a(n,r)}function ve(n,e,r){let t=n.pattern.second;return c(t,r)+" "+P(t,"second")+" past the minute, every minute"+a(n,r)}function Ce(n,e,r){let t=n.pattern.minute,i=c(t,r),o=P(t,"minute");if(e.singleSecond){let u=n.pattern.second;return i+" "+o+" and "+c(u,r)+" "+P(u,"second")+" past the hour, every hour"+a(n,r)}return H(n,r)+", "+i+" "+o+" past the hour, every hour"+a(n,r)}function we(n,e,r){return H(n,r)+", "+Pn(n,e.rest,r)}function H(n,e){let r=n.pattern.second,t=n.shapes.second;if(r==="*")return"every second";if(t==="step")return Rn(n.analyses.segments.second[0],"second","minute",e);if(t==="range"){let i=r.split("-"),o=A(i,e);return"every second from "+o(i[0])+O(e)+o(i[1])+" past the minute"}return t==="single"?"at "+c(r,e)+" "+P(r,"second")+" past the minute":b(T(n.analyses.segments.second,e),"second","minute",e)}function Re(n,e,r){return"every minute"+a(n,r)}function Me(n,e,r){let t=n.pattern.minute;return c(t,r)+" "+P(t,"minute")+" past the hour, every hour"+a(n,r)}function xe(n,e,r){return L(n.pattern.minute,r)+a(n,r)}function Te(n,e,r){return b(T(n.analyses.segments.minute,r),"minute","hour",r)+a(n,r)}function Fe(n,e,r){let t=Rn(n.analyses.segments.minute[0],"minute","hour",r);return e.hours.kind==="during"?t+=" during the "+_(n,e.hours.times,!1,r)+" hours":e.hours.kind==="window"?t+=" "+wn(e.hours,r):e.hours.kind==="step"&&(t+=" "+vn(n.analyses.segments.hour[0],r)),t+a(n,r)}function Ie(n,e,r){return"every minute from "+l({hour:e.hour,minute:e.span[0]},r)+O(r)+l({hour:e.hour,minute:e.span[1]},r)+a(n,r)}function He(n,e,r){if(e.form==="wildcard")return"every minute during the "+_(n,e.times,!1,r)+" hours"+a(n,r);let t=_(n,e.times,!0,r);return(e.form==="range"?L(n.pattern.minute,r):b(T(n.analyses.segments.minute,r),"minute","hour",r))+", at "+t+a(n,r)}var Le={2:"other",3:"third",4:"fourth",6:"sixth",8:"eighth",12:"twelfth"};function vn(n,e){let r="during every "+Le[n.interval]+" hour",t=n.startToken==="*"?0:+n.startToken;return t===0?r:r+" starting at "+l({hour:t,minute:0},e)}function Ae(n,e,r){let t=n.analyses.segments.hour[0];return e.form==="wildcard"?"every minute "+vn(t,r)+a(n,r):L(n.pattern.minute,r)+", "+Mn(t,r)+a(n,r)}function L(n,e){let r=n.split("-"),t=A(r,e);return"every minute from "+t(r[0])+O(e)+t(r[1])+" past the hour"}function Ee(n,e,r){return"every hour"+a(n,r)}function We(n,e,r){let t=wn(je(e),r);return e.minuteForm==="wildcard"?"every minute "+t+a(n,r):e.minuteForm==="range"?L(n.pattern.minute,r)+", "+t+a(n,r):Cn(n,r)+" "+t+a(n,r)}function Cn(n,e){return n.pattern.minute==="0"?"every hour":b(T(n.analyses.segments.minute,e),"minute","hour",e)}function De(n,e,r){return Mn(n.analyses.segments.hour[0],r)+a(n,r)}function je(n){return{from:n.from,last:n.boundMinute??0,to:n.to}}function wn(n,e){return"from "+l({hour:n.from,minute:0},e)+O(e)+l({hour:n.to,minute:n.last},e)}function Ue(n,e,r){let t=tn(e.times),i=e.times.map(function(u){return l({hour:u.hour,minute:u.minute,second:u.second,plain:t},r)});return xn(n,r)+"at "+S(i,r)}function Qe(n,e,r){if(e.fold){if(n.analyses.segments.hour.some(function(m){return m.kind==="range"})&&!n.analyses.clockSecond)return qe(n,e,r)+a(n,r);let o={minute:e.minute,second:n.analyses.clockSecond};return xn(n,r)+"at "+nn(n,o,!0,r)}let t=b(T(n.analyses.segments.minute,r),"minute","hour",r)+", at "+nn(n,{minute:0,second:null},!0,r)+a(n,r);return n.analyses.clockSecond?H(n,r)+", "+t:t}function qe(n,e,r){let t=e.minute,i=[],o=[];n.analyses.segments.hour.forEach(function(f){f.kind==="range"?i.push("from "+l({hour:f.bounds[0],minute:0},r)+O(r)+l({hour:f.bounds[1],minute:t},r)):f.kind==="step"?o.push(...f.fires):o.push(+f.value)});let u=Cn(n,r)+" "+S(i,r);return o.length&&(u+=" and at "+S(o.map(function(f){return l({hour:f,minute:t},r)}),r)),u}var Ve={clockTimes:Ue,compactClockTimes:Qe,composeSeconds:we,everyHour:Ee,everyMinute:Re,everySecond:ze,hourRange:We,hourStep:De,minuteFrequency:Fe,minuteSpanAcrossHourStep:Ae,minuteSpanInHour:Ie,minutesAcrossHours:He,multipleMinutes:Te,rangeOfMinutes:xe,secondPastMinute:ve,secondsWithinMinute:Ce,singleMinute:Me,standaloneSeconds:Pe};function Rn(n,e,r,t){if(n.startToken.indexOf("-")!==-1)return b(Z(n.fires,t),e,r,t);let i=n.startToken==="*"?0:+n.startToken,o=n.interval;return i!==0?n.fires.length<=3?b(Z(n.fires,t),e,r,t):"every "+c(o,t)+" "+e+"s from "+c(i,t)+" "+P(i,e)+" past the "+r:60%o===0?"every "+c(o,t)+" "+e+"s":n.fires.length<=2?b(Z(n.fires,t),e,r,t):"every "+c(o,t)+" "+e+"s past the "+r}function Mn(n,e){if(n.startToken.indexOf("-")!==-1)return"at "+X(n.fires,e);let r=n.startToken==="*"?0:+n.startToken,t=n.interval;return r===0&&24%t===0?"every "+c(t,e)+" hours":n.fires.length<=3?"at "+X(n.fires,e):r===0?"every "+c(t,e)+" hours from midnight":"every "+c(t,e)+" hours from "+l({hour:r,minute:0},e)}function A(n,e){let r=n.some(function(i){return+i>10});return function(i){return r?""+i:c(i,e)}}function Z(n,e){return n.map(A(n,e))}function T(n,e){let r=n.flatMap(function(o){return o.kind==="range"?o.bounds:o.kind==="step"?o.fires:[o.value]}),t=A(r,e);return n.flatMap(function(o){return o.kind==="range"?[t(o.bounds[0])+O(e)+t(o.bounds[1])]:o.kind==="step"?o.fires.map(t):[t(o.value)]})}function b(n,e,r,t){return"at "+S(n,t)+" "+e+"s past the "+r}function Je(n,e,r){return(+n==0||+n==12)&&+e==0&&!(typeof r=="number"&&r>0)}function tn(n){let e=n.filter(function(t){return Je(t.hour,t.minute,t.second)});return e.length>0&&e.length<n.length}function X(n,e){let r=tn(n.map(function(o){return{hour:o,minute:0}})),t=n.map(function(o){return l({hour:o,minute:0,plain:r},e)});return S(t,e)}function _(n,e,r,t){return e.kind==="fires"?X(e.fires,t):nn(n,{minute:0,second:null},r,t)}function $e(n){return n.kind==="range"?n.bounds:n.kind==="step"?n.fires:[n.value]}function nn(n,e,r,t){let{minute:i,second:o}=e,u=n.analyses.segments.hour,m=tn(u.flatMap(function(p){return $e(p).map(function(j){return{hour:+j,minute:i,second:o}})})),f=[];return u.forEach(function(p){p.kind==="step"?f.push(...p.fires.map(function(j){return l({hour:j,minute:i,second:o,plain:m},t)})):p.kind==="range"?f.push(l({hour:p.bounds[0],minute:i,second:o,plain:m},t)+O(t)+l({hour:p.bounds[1],minute:i,second:o,plain:m},t)):f.push(l({hour:p.value,minute:i,second:o,plain:m},t))}),S(Ye(f,u,r),t)}function Ye(n,e,r){let t=e.some(function(o){return o.kind==="range"});return!r||!t?n:n.map(function(o,u){return u===0?o:"at "+o})}function S(n,e){if(n.length<=1)return n.join("");if(n.length===2)return n[0]+" and "+n[1];let r=e.style.serialComma?", and ":" and ";return n.slice(0,-1).join(", ")+r+n[n.length-1]}var Be={all:"",month:"in ",stepDate:"on ",weekday:"on "},Ge={all:"every day",month:"every day in ",stepDate:"",weekday:"every "};function a(n,e){let r=Tn(n,Be,e);return r&&" "+r}function xn(n,e){return Tn(n,Ge,e)+" "}function Tn(n,e,r){let t=n.pattern;return t.date!=="*"&&t.weekday!=="*"?Ze(n,r):t.date!=="*"?Ke(n,e,r):t.weekday!=="*"?(Hn(t.weekday,r)||e.weekday+Wn(n,r))+z(n,r):t.month!=="*"?e.month+E(n,r):e.all}function Ke(n,e,r){let t=n.pattern,i=In(t.date,r);return i?i+z(n,r):on(t.date)?e.stepDate+An(t.date)+z(n,r):t.month!=="*"&&!Fn(n)?"on the "+en(n,r)+z(n,r):t.month!=="*"?"on "+Ln(n,r):"on the "+en(n,r)}function Fn(n){return!En(n.pattern.month)&&n.analyses.segments.month.every(function(r){return r.kind!=="range"})}function Ze(n,e){let r=n.pattern,t=Hn(r.weekday,e)||"on "+Wn(n,e),i=In(r.date,e);return i?i+z(n,e)+" or "+t:on(r.date)?An(r.date)+z(n,e)+" or "+t:r.month!=="*"&&Fn(n)?"on "+Ln(n,e)+" or "+t+" in "+E(n,e):"on the "+en(n,e)+" or "+t+z(n,e)}function In(n,e){if(n==="L")return"on the last day of the month";if(n==="LW"||n==="WL")return"on the last weekday of the month";let r=/^L-(\d{1,2})$/.exec(n);if(r)return c(+r[1],e)+" "+P(r[1],"day")+" before the last day of the month";let t=/^(\d{1,2})W$|^W(\d{1,2})$/.exec(n);if(t)return"on the weekday nearest the "+x(t[1]||t[2])}function Hn(n,e){let r=n.split("#");if(r.length===2)return"on the "+Oe[+r[1]]+" "+rn(r[0],e)+" of the month";if(/L$/.test(n))return"on the last "+rn(n.slice(0,-1),e)+" of the month"}function Ln(n,e){let r=E(n,e),t=W(n.analyses.segments.date,e.style.ordinals?x:Xe,e);return e.style.dayFirst?t+" "+r:r+" "+t}function Xe(n){return""+n}function z(n,e){return n.pattern.month==="*"?"":" in "+E(n,e)}function An(n){let e=n.split("/"),r=+e[1],t=e[0],o=(r===2?"every other":"every "+x(r))+" day of the month";return t!=="*"&&t!=="1"&&(o+=" from the "+x(t)),o}function en(n,e){return W(n.analyses.segments.date,x,e)}function E(n,e){let r=En(n.pattern.month);return r||W(n.analyses.segments.month,function(i){return tr(i,e)},e)}function En(n){if(!on(n))return null;let[e,r]=n.split("/");return+r!=2?null:e==="*"||e==="1"?"every odd-numbered month":e==="2"?"every even-numbered month":null}function Wn(n,e){return W(n.analyses.segments.weekday,function(t){return rn(t,e)},e)}function W(n,e,r){let t=[];return n.forEach(function(o){o.kind==="step"?t.push(...o.fires.map(e)):o.kind==="range"?t.push(o.bounds.map(e).join(O(r))):t.push(e(o.value))}),S(t,r)}function on(n){return n.indexOf("/")!==-1&&n.indexOf("-")===-1&&n.indexOf(",")===-1}function _e(n,e,r){let t=e.pattern.year;if(t==="*")return n;if(t.indexOf("/")!==-1)return n+" "+er(t,r);let i=nr(t,r);if(t.indexOf("-")===-1&&t.indexOf(",")===-1&&e.pattern.date!=="*"&&n.indexOf(" at ")!==-1){let o=r.style.dayFirst?" ":", ";return n.replace(" at ",o+i+" at ")}return n+" in "+i}function nr(n,e){return n.indexOf(",")!==-1?S(n.split(","),e):n}function er(n,e){let r=n.split("/"),t=+r[1],i=r[0];if(t<=1)return"every year";let o="every "+c(t,e)+" years";return i!=="*"&&i!=="0"&&(o+=" from "+i),o}function l(n,e){let{hour:r,minute:t,plain:i}=n,o=typeof n.second=="number"&&n.second>0?n.second:0;return e.ampm?rr({hour:r,minute:t,second:o,plain:i},e):B({hour:r,minute:t,second:o},{pad:!0,sep:e.style.sep})}function rr(n,e){let{hour:r,minute:t,second:i,plain:o}=n,u=e.style;if(!o&&+t==0&&!i){if(+r==0)return u.midnight;if(+r==12)return u.midday}return B({hour:r%12||12,minute:t,second:i},{lean:!0,sep:u.sep})+(u.closeUp?"":" ")+(r<12?u.am:u.pm)}function c(n,e){return Nn(n,ye,e)}function P(n,e){return+n==1?e:e+"s"}function O(n){return n.short?"-":n.style.through}function x(n){let e=Math.abs(n),r=K[e];return r||(e=(e%100-20)%10,r=K[e]||K[0]),n+r}function tr(n,e){let r=g[n]||be[n];return r&&r[e.short?1:0]}function rn(n,e){let r=n===7||n==="7"?0:n,t=y[r]||Se[r];return t&&t[e.short?1:0]}var ir={describe:Ne,fallback:"an unrecognizable cron pattern",options:ke,reboot:"at system startup",sentence:n=>"Runs "+n+"."},Dn=ir;/**
|
|
2
2
|
* @license MIT, Copyright (c) 2026 Andrew Brož
|
|
3
|
-
*/function
|
|
3
|
+
*/function or(n,e){let r=e&&e.lang||Dn,t=r.options(e);if(!t.lenient)return jn(Un(n,r,t),r,e);try{return jn(Un(n,r,t),r,e)}catch{return r.fallback}}function jn(n,e,r){return r&&r.sentence?e.sentence(n):n}function Un(n,e,r){if(typeof n=="string"&&n.trim().toLowerCase()==="@reboot")return e.reboot;let t=yn(kn(n,r)),i=e.strategy?e.strategy(t,t.plan):t.plan;return e.describe({...t,plan:i},r)}var un=or;typeof globalThis<"u"&&Object.assign(globalThis,{cronli5:un});var Ur=un;})();
|
package/dist/cronli5.cjs
CHANGED
|
@@ -532,7 +532,7 @@ function planSeconds(pattern, shapes, analyses) {
|
|
|
532
532
|
}
|
|
533
533
|
return {
|
|
534
534
|
kind: "composeSeconds",
|
|
535
|
-
rest: planMinutes(pattern, shapes, analyses) || planHours(pattern, shapes, analyses)
|
|
535
|
+
rest: planMinutes(pattern, shapes, analyses, true) || planHours(pattern, shapes, analyses, true)
|
|
536
536
|
};
|
|
537
537
|
}
|
|
538
538
|
function planStandaloneSeconds(pattern, shapes) {
|
|
@@ -547,7 +547,7 @@ function planStandaloneSeconds(pattern, shapes) {
|
|
|
547
547
|
}
|
|
548
548
|
return { kind: "standaloneSeconds" };
|
|
549
549
|
}
|
|
550
|
-
function planMinutes(pattern, shapes, analyses) {
|
|
550
|
+
function planMinutes(pattern, shapes, analyses, subMinuteSecond = false) {
|
|
551
551
|
if (shapes.minute === "step") {
|
|
552
552
|
return {
|
|
553
553
|
hours: planFrequencyHours(pattern, shapes, analyses),
|
|
@@ -570,7 +570,7 @@ function planMinutes(pattern, shapes, analyses) {
|
|
|
570
570
|
return underStep;
|
|
571
571
|
}
|
|
572
572
|
if (pattern.hour === "*") {
|
|
573
|
-
return planMinutesUnderOpenHour(pattern, shapes);
|
|
573
|
+
return planMinutesUnderOpenHour(pattern, shapes, subMinuteSecond);
|
|
574
574
|
}
|
|
575
575
|
}
|
|
576
576
|
function cleanHourStride(hourField) {
|
|
@@ -640,7 +640,7 @@ function planMinutesAcrossHours(pattern, shapes) {
|
|
|
640
640
|
}
|
|
641
641
|
return null;
|
|
642
642
|
}
|
|
643
|
-
function planMinutesUnderOpenHour(pattern, shapes) {
|
|
643
|
+
function planMinutesUnderOpenHour(pattern, shapes, subMinuteSecond) {
|
|
644
644
|
if (shapes.minute === "range") {
|
|
645
645
|
return { kind: "rangeOfMinutes" };
|
|
646
646
|
}
|
|
@@ -650,39 +650,45 @@ function planMinutesUnderOpenHour(pattern, shapes) {
|
|
|
650
650
|
if (pattern.minute === "*") {
|
|
651
651
|
return { kind: "everyMinute" };
|
|
652
652
|
}
|
|
653
|
-
if (pattern.minute !== "0") {
|
|
653
|
+
if (pattern.minute !== "0" || subMinuteSecond) {
|
|
654
654
|
return { kind: "singleMinute" };
|
|
655
655
|
}
|
|
656
656
|
}
|
|
657
|
-
function planHours(pattern, shapes, analyses) {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
if (pattern.minute === "*") {
|
|
662
|
-
minuteForm = "wildcard";
|
|
663
|
-
} else if (shapes.minute === "range") {
|
|
664
|
-
minuteForm = "range";
|
|
665
|
-
}
|
|
666
|
-
return {
|
|
667
|
-
from: +bounds[0],
|
|
668
|
-
kind: "hourRange",
|
|
669
|
-
last: analyses.lastMinuteFire,
|
|
670
|
-
minuteForm,
|
|
671
|
-
to: +bounds[1]
|
|
672
|
-
};
|
|
657
|
+
function planHours(pattern, shapes, analyses, subMinuteSecond = false) {
|
|
658
|
+
const absorbsMinuteZero = subMinuteSecond && pattern.minute === "0";
|
|
659
|
+
if (shapes.hour === "range" && !absorbsMinuteZero) {
|
|
660
|
+
return planHourRange(pattern, shapes, analyses);
|
|
673
661
|
}
|
|
674
|
-
if (shapes.hour === "step" && pattern.minute === "0") {
|
|
662
|
+
if (shapes.hour === "step" && pattern.minute === "0" && !subMinuteSecond) {
|
|
675
663
|
return { kind: "hourStep" };
|
|
676
664
|
}
|
|
677
|
-
if (pattern.hour === "*") {
|
|
665
|
+
if (pattern.hour === "*" && !absorbsMinuteZero) {
|
|
678
666
|
return { kind: "everyHour" };
|
|
679
667
|
}
|
|
680
|
-
return planClockTimes(pattern, analyses);
|
|
668
|
+
return planClockTimes(pattern, analyses, absorbsMinuteZero);
|
|
681
669
|
}
|
|
682
|
-
function
|
|
670
|
+
function planHourRange(pattern, shapes, analyses) {
|
|
671
|
+
const bounds = pattern.hour.split("-");
|
|
672
|
+
let minuteForm = "lead";
|
|
673
|
+
if (pattern.minute === "*") {
|
|
674
|
+
minuteForm = "wildcard";
|
|
675
|
+
} else if (shapes.minute === "range") {
|
|
676
|
+
minuteForm = "range";
|
|
677
|
+
}
|
|
678
|
+
const multiValued = shapes.minute === "range" || shapes.minute === "list";
|
|
679
|
+
return {
|
|
680
|
+
boundMinute: multiValued ? null : analyses.lastMinuteFire,
|
|
681
|
+
from: +bounds[0],
|
|
682
|
+
kind: "hourRange",
|
|
683
|
+
last: analyses.lastMinuteFire,
|
|
684
|
+
minuteForm,
|
|
685
|
+
to: +bounds[1]
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
function planClockTimes(pattern, analyses, enumerate = false) {
|
|
683
689
|
const hours = enumerateFires(pattern.hour, 0, 23);
|
|
684
690
|
const minutes = enumerateValues(pattern.minute);
|
|
685
|
-
if (hours.length * minutes.length > maxClockTimes) {
|
|
691
|
+
if (!enumerate && hours.length * minutes.length > maxClockTimes) {
|
|
686
692
|
return {
|
|
687
693
|
fold: minutes.length === 1,
|
|
688
694
|
kind: "compactClockTimes",
|
|
@@ -996,7 +1002,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
996
1002
|
return "every hour" + trailingQualifier(ir, opts);
|
|
997
1003
|
}
|
|
998
1004
|
function renderHourRange(ir, plan, opts) {
|
|
999
|
-
const window = hourWindow(plan, opts);
|
|
1005
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
1000
1006
|
if (plan.minuteForm === "wildcard") {
|
|
1001
1007
|
return "every minute " + window + trailingQualifier(ir, opts);
|
|
1002
1008
|
}
|
|
@@ -1019,6 +1025,9 @@ function rangeMinuteLead(ir, opts) {
|
|
|
1019
1025
|
function renderHourStep(ir, plan, opts) {
|
|
1020
1026
|
return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
|
|
1021
1027
|
}
|
|
1028
|
+
function boundedWindow(plan) {
|
|
1029
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
1030
|
+
}
|
|
1022
1031
|
function hourWindow(window, opts) {
|
|
1023
1032
|
return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
|
|
1024
1033
|
}
|
package/dist/cronli5.js
CHANGED
|
@@ -506,7 +506,7 @@ function planSeconds(pattern, shapes, analyses) {
|
|
|
506
506
|
}
|
|
507
507
|
return {
|
|
508
508
|
kind: "composeSeconds",
|
|
509
|
-
rest: planMinutes(pattern, shapes, analyses) || planHours(pattern, shapes, analyses)
|
|
509
|
+
rest: planMinutes(pattern, shapes, analyses, true) || planHours(pattern, shapes, analyses, true)
|
|
510
510
|
};
|
|
511
511
|
}
|
|
512
512
|
function planStandaloneSeconds(pattern, shapes) {
|
|
@@ -521,7 +521,7 @@ function planStandaloneSeconds(pattern, shapes) {
|
|
|
521
521
|
}
|
|
522
522
|
return { kind: "standaloneSeconds" };
|
|
523
523
|
}
|
|
524
|
-
function planMinutes(pattern, shapes, analyses) {
|
|
524
|
+
function planMinutes(pattern, shapes, analyses, subMinuteSecond = false) {
|
|
525
525
|
if (shapes.minute === "step") {
|
|
526
526
|
return {
|
|
527
527
|
hours: planFrequencyHours(pattern, shapes, analyses),
|
|
@@ -544,7 +544,7 @@ function planMinutes(pattern, shapes, analyses) {
|
|
|
544
544
|
return underStep;
|
|
545
545
|
}
|
|
546
546
|
if (pattern.hour === "*") {
|
|
547
|
-
return planMinutesUnderOpenHour(pattern, shapes);
|
|
547
|
+
return planMinutesUnderOpenHour(pattern, shapes, subMinuteSecond);
|
|
548
548
|
}
|
|
549
549
|
}
|
|
550
550
|
function cleanHourStride(hourField) {
|
|
@@ -614,7 +614,7 @@ function planMinutesAcrossHours(pattern, shapes) {
|
|
|
614
614
|
}
|
|
615
615
|
return null;
|
|
616
616
|
}
|
|
617
|
-
function planMinutesUnderOpenHour(pattern, shapes) {
|
|
617
|
+
function planMinutesUnderOpenHour(pattern, shapes, subMinuteSecond) {
|
|
618
618
|
if (shapes.minute === "range") {
|
|
619
619
|
return { kind: "rangeOfMinutes" };
|
|
620
620
|
}
|
|
@@ -624,39 +624,45 @@ function planMinutesUnderOpenHour(pattern, shapes) {
|
|
|
624
624
|
if (pattern.minute === "*") {
|
|
625
625
|
return { kind: "everyMinute" };
|
|
626
626
|
}
|
|
627
|
-
if (pattern.minute !== "0") {
|
|
627
|
+
if (pattern.minute !== "0" || subMinuteSecond) {
|
|
628
628
|
return { kind: "singleMinute" };
|
|
629
629
|
}
|
|
630
630
|
}
|
|
631
|
-
function planHours(pattern, shapes, analyses) {
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if (pattern.minute === "*") {
|
|
636
|
-
minuteForm = "wildcard";
|
|
637
|
-
} else if (shapes.minute === "range") {
|
|
638
|
-
minuteForm = "range";
|
|
639
|
-
}
|
|
640
|
-
return {
|
|
641
|
-
from: +bounds[0],
|
|
642
|
-
kind: "hourRange",
|
|
643
|
-
last: analyses.lastMinuteFire,
|
|
644
|
-
minuteForm,
|
|
645
|
-
to: +bounds[1]
|
|
646
|
-
};
|
|
631
|
+
function planHours(pattern, shapes, analyses, subMinuteSecond = false) {
|
|
632
|
+
const absorbsMinuteZero = subMinuteSecond && pattern.minute === "0";
|
|
633
|
+
if (shapes.hour === "range" && !absorbsMinuteZero) {
|
|
634
|
+
return planHourRange(pattern, shapes, analyses);
|
|
647
635
|
}
|
|
648
|
-
if (shapes.hour === "step" && pattern.minute === "0") {
|
|
636
|
+
if (shapes.hour === "step" && pattern.minute === "0" && !subMinuteSecond) {
|
|
649
637
|
return { kind: "hourStep" };
|
|
650
638
|
}
|
|
651
|
-
if (pattern.hour === "*") {
|
|
639
|
+
if (pattern.hour === "*" && !absorbsMinuteZero) {
|
|
652
640
|
return { kind: "everyHour" };
|
|
653
641
|
}
|
|
654
|
-
return planClockTimes(pattern, analyses);
|
|
642
|
+
return planClockTimes(pattern, analyses, absorbsMinuteZero);
|
|
655
643
|
}
|
|
656
|
-
function
|
|
644
|
+
function planHourRange(pattern, shapes, analyses) {
|
|
645
|
+
const bounds = pattern.hour.split("-");
|
|
646
|
+
let minuteForm = "lead";
|
|
647
|
+
if (pattern.minute === "*") {
|
|
648
|
+
minuteForm = "wildcard";
|
|
649
|
+
} else if (shapes.minute === "range") {
|
|
650
|
+
minuteForm = "range";
|
|
651
|
+
}
|
|
652
|
+
const multiValued = shapes.minute === "range" || shapes.minute === "list";
|
|
653
|
+
return {
|
|
654
|
+
boundMinute: multiValued ? null : analyses.lastMinuteFire,
|
|
655
|
+
from: +bounds[0],
|
|
656
|
+
kind: "hourRange",
|
|
657
|
+
last: analyses.lastMinuteFire,
|
|
658
|
+
minuteForm,
|
|
659
|
+
to: +bounds[1]
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
function planClockTimes(pattern, analyses, enumerate = false) {
|
|
657
663
|
const hours = enumerateFires(pattern.hour, 0, 23);
|
|
658
664
|
const minutes = enumerateValues(pattern.minute);
|
|
659
|
-
if (hours.length * minutes.length > maxClockTimes) {
|
|
665
|
+
if (!enumerate && hours.length * minutes.length > maxClockTimes) {
|
|
660
666
|
return {
|
|
661
667
|
fold: minutes.length === 1,
|
|
662
668
|
kind: "compactClockTimes",
|
|
@@ -970,7 +976,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
970
976
|
return "every hour" + trailingQualifier(ir, opts);
|
|
971
977
|
}
|
|
972
978
|
function renderHourRange(ir, plan, opts) {
|
|
973
|
-
const window = hourWindow(plan, opts);
|
|
979
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
974
980
|
if (plan.minuteForm === "wildcard") {
|
|
975
981
|
return "every minute " + window + trailingQualifier(ir, opts);
|
|
976
982
|
}
|
|
@@ -993,6 +999,9 @@ function rangeMinuteLead(ir, opts) {
|
|
|
993
999
|
function renderHourStep(ir, plan, opts) {
|
|
994
1000
|
return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
|
|
995
1001
|
}
|
|
1002
|
+
function boundedWindow(plan) {
|
|
1003
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
1004
|
+
}
|
|
996
1005
|
function hourWindow(window, opts) {
|
|
997
1006
|
return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
|
|
998
1007
|
}
|
package/dist/lang/de.cjs
CHANGED
|
@@ -433,7 +433,12 @@ function hourStepPhrase(ir) {
|
|
|
433
433
|
return cleanStep(segment, 24) ? everyN(segment.interval, UNITS.hour) : atHours(segment.fires);
|
|
434
434
|
}
|
|
435
435
|
function renderHourRange(ir, plan, opts) {
|
|
436
|
-
const window = hourWindow(
|
|
436
|
+
const window = hourWindow(
|
|
437
|
+
plan.from,
|
|
438
|
+
plan.to,
|
|
439
|
+
plan.boundMinute ?? 0,
|
|
440
|
+
opts.style.sep
|
|
441
|
+
);
|
|
437
442
|
if (plan.minuteForm === "wildcard") {
|
|
438
443
|
return "jede Minute " + window;
|
|
439
444
|
}
|
package/dist/lang/de.js
CHANGED
|
@@ -407,7 +407,12 @@ function hourStepPhrase(ir) {
|
|
|
407
407
|
return cleanStep(segment, 24) ? everyN(segment.interval, UNITS.hour) : atHours(segment.fires);
|
|
408
408
|
}
|
|
409
409
|
function renderHourRange(ir, plan, opts) {
|
|
410
|
-
const window = hourWindow(
|
|
410
|
+
const window = hourWindow(
|
|
411
|
+
plan.from,
|
|
412
|
+
plan.to,
|
|
413
|
+
plan.boundMinute ?? 0,
|
|
414
|
+
opts.style.sep
|
|
415
|
+
);
|
|
411
416
|
if (plan.minuteForm === "wildcard") {
|
|
412
417
|
return "jede Minute " + window;
|
|
413
418
|
}
|
package/dist/lang/en.cjs
CHANGED
|
@@ -307,7 +307,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
307
307
|
return "every hour" + trailingQualifier(ir, opts);
|
|
308
308
|
}
|
|
309
309
|
function renderHourRange(ir, plan, opts) {
|
|
310
|
-
const window = hourWindow(plan, opts);
|
|
310
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
311
311
|
if (plan.minuteForm === "wildcard") {
|
|
312
312
|
return "every minute " + window + trailingQualifier(ir, opts);
|
|
313
313
|
}
|
|
@@ -330,6 +330,9 @@ function rangeMinuteLead(ir, opts) {
|
|
|
330
330
|
function renderHourStep(ir, plan, opts) {
|
|
331
331
|
return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
|
|
332
332
|
}
|
|
333
|
+
function boundedWindow(plan) {
|
|
334
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
335
|
+
}
|
|
333
336
|
function hourWindow(window, opts) {
|
|
334
337
|
return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
|
|
335
338
|
}
|
package/dist/lang/en.js
CHANGED
|
@@ -281,7 +281,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
281
281
|
return "every hour" + trailingQualifier(ir, opts);
|
|
282
282
|
}
|
|
283
283
|
function renderHourRange(ir, plan, opts) {
|
|
284
|
-
const window = hourWindow(plan, opts);
|
|
284
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
285
285
|
if (plan.minuteForm === "wildcard") {
|
|
286
286
|
return "every minute " + window + trailingQualifier(ir, opts);
|
|
287
287
|
}
|
|
@@ -304,6 +304,9 @@ function rangeMinuteLead(ir, opts) {
|
|
|
304
304
|
function renderHourStep(ir, plan, opts) {
|
|
305
305
|
return stepHours(ir.analyses.segments.hour[0], opts) + trailingQualifier(ir, opts);
|
|
306
306
|
}
|
|
307
|
+
function boundedWindow(plan) {
|
|
308
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
309
|
+
}
|
|
307
310
|
function hourWindow(window, opts) {
|
|
308
311
|
return "from " + getTime({ hour: window.from, minute: 0 }, opts) + through(opts) + getTime({ hour: window.to, minute: window.last }, opts);
|
|
309
312
|
}
|
package/dist/lang/es.cjs
CHANGED
|
@@ -331,7 +331,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
331
331
|
return "cada hora" + trailingQualifier(ir, opts);
|
|
332
332
|
}
|
|
333
333
|
function renderHourRange(ir, plan, opts) {
|
|
334
|
-
const window = hourWindow(plan, opts);
|
|
334
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
335
335
|
if (plan.minuteForm === "wildcard") {
|
|
336
336
|
return "cada minuto " + window + trailingQualifier(ir, opts);
|
|
337
337
|
}
|
|
@@ -347,6 +347,9 @@ function renderHourRange(ir, plan, opts) {
|
|
|
347
347
|
function renderHourStep(ir, plan, opts) {
|
|
348
348
|
return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
|
|
349
349
|
}
|
|
350
|
+
function boundedWindow(plan) {
|
|
351
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
352
|
+
}
|
|
350
353
|
function hourWindow(window, opts) {
|
|
351
354
|
return timeRange(
|
|
352
355
|
{ hour: window.from, minute: 0 },
|
package/dist/lang/es.js
CHANGED
|
@@ -305,7 +305,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
305
305
|
return "cada hora" + trailingQualifier(ir, opts);
|
|
306
306
|
}
|
|
307
307
|
function renderHourRange(ir, plan, opts) {
|
|
308
|
-
const window = hourWindow(plan, opts);
|
|
308
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
309
309
|
if (plan.minuteForm === "wildcard") {
|
|
310
310
|
return "cada minuto " + window + trailingQualifier(ir, opts);
|
|
311
311
|
}
|
|
@@ -321,6 +321,9 @@ function renderHourRange(ir, plan, opts) {
|
|
|
321
321
|
function renderHourStep(ir, plan, opts) {
|
|
322
322
|
return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
|
|
323
323
|
}
|
|
324
|
+
function boundedWindow(plan) {
|
|
325
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
326
|
+
}
|
|
324
327
|
function hourWindow(window, opts) {
|
|
325
328
|
return timeRange(
|
|
326
329
|
{ hour: window.from, minute: 0 },
|
package/dist/lang/fi.cjs
CHANGED
|
@@ -465,7 +465,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
465
465
|
return "joka tunti" + trailingQualifier(ir, opts);
|
|
466
466
|
}
|
|
467
467
|
function renderHourRange(ir, plan, opts) {
|
|
468
|
-
const window = hourWindow(plan, opts);
|
|
468
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
469
469
|
if (plan.minuteForm === "wildcard") {
|
|
470
470
|
return "joka minuutti " + window + trailingQualifier(ir, opts);
|
|
471
471
|
}
|
|
@@ -487,6 +487,9 @@ function renderHourRange(ir, plan, opts) {
|
|
|
487
487
|
function renderHourStep(ir, plan, opts) {
|
|
488
488
|
return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
|
|
489
489
|
}
|
|
490
|
+
function boundedWindow(plan) {
|
|
491
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
492
|
+
}
|
|
490
493
|
function hourWindow(window, opts) {
|
|
491
494
|
return kloRange(
|
|
492
495
|
{ hour: window.from, minute: 0 },
|
package/dist/lang/fi.js
CHANGED
|
@@ -439,7 +439,7 @@ function renderEveryHour(ir, plan, opts) {
|
|
|
439
439
|
return "joka tunti" + trailingQualifier(ir, opts);
|
|
440
440
|
}
|
|
441
441
|
function renderHourRange(ir, plan, opts) {
|
|
442
|
-
const window = hourWindow(plan, opts);
|
|
442
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
443
443
|
if (plan.minuteForm === "wildcard") {
|
|
444
444
|
return "joka minuutti " + window + trailingQualifier(ir, opts);
|
|
445
445
|
}
|
|
@@ -461,6 +461,9 @@ function renderHourRange(ir, plan, opts) {
|
|
|
461
461
|
function renderHourStep(ir, plan, opts) {
|
|
462
462
|
return stepHours(stepSegment(ir.analyses.segments.hour), opts) + trailingQualifier(ir, opts);
|
|
463
463
|
}
|
|
464
|
+
function boundedWindow(plan) {
|
|
465
|
+
return { from: plan.from, last: plan.boundMinute ?? 0, to: plan.to };
|
|
466
|
+
}
|
|
464
467
|
function hourWindow(window, opts) {
|
|
465
468
|
return kloRange(
|
|
466
469
|
{ hour: window.from, minute: 0 },
|
package/dist/lang/zh.cjs
CHANGED
|
@@ -320,15 +320,12 @@ function composeSecondsOnHour(ir, plan, opts) {
|
|
|
320
320
|
const sec = secondClause(ir);
|
|
321
321
|
const { rest } = plan;
|
|
322
322
|
const restText = render(ir, rest, opts);
|
|
323
|
-
if (rest.kind === "everyHour") {
|
|
324
|
-
return sec + "\uFF0C\u6BCF\u5C0F\u65F6";
|
|
325
|
-
}
|
|
326
|
-
if (rest.kind === "hourStep") {
|
|
327
|
-
return sec + "\uFF0C" + restText;
|
|
328
|
-
}
|
|
329
323
|
if ((rest.kind === "clockTimes" || rest.kind === "compactClockTimes") && isDaily(ir)) {
|
|
330
324
|
return "\u6BCF\u5929" + restText + sec;
|
|
331
325
|
}
|
|
326
|
+
if (rest.kind === "singleMinute") {
|
|
327
|
+
return restText + "\uFF0C" + sec;
|
|
328
|
+
}
|
|
332
329
|
return restText + sec;
|
|
333
330
|
}
|
|
334
331
|
function composeSecondsCadence(ir) {
|
|
@@ -348,17 +345,12 @@ function composeSecondsCadence(ir) {
|
|
|
348
345
|
function composeSecondsListed(ir) {
|
|
349
346
|
const sec = secondClause(ir);
|
|
350
347
|
const minutes = "\u6BCF\u5C0F\u65F6" + valueList(fieldSegments(ir, "minute"), "\u5206");
|
|
351
|
-
const minuteSegs = fieldSegments(ir, "minute");
|
|
352
348
|
if (ir.shapes.hour === "wildcard") {
|
|
353
349
|
return minutes + "\uFF0C" + sec;
|
|
354
350
|
}
|
|
355
351
|
if (isHourCadence(ir)) {
|
|
356
352
|
return cadence(stepSegment(ir, "hour").interval, UNITS.hour) + "\uFF0C" + minutes + "\uFF0C" + sec;
|
|
357
353
|
}
|
|
358
|
-
if (ir.shapes.hour === "range" && minuteSegs.length === 1 && minuteSegs[0].kind === "range") {
|
|
359
|
-
const [from, to] = fieldSegments(ir, "hour")[0].bounds;
|
|
360
|
-
return "\u5728" + hourWord(+from) + "\u81F3" + to + "\u70B9" + minuteSegs[0].bounds[1] + "\u5206\u4E4B\u95F4\uFF0C" + sec;
|
|
361
|
-
}
|
|
362
354
|
return hourFrame(ir) + minutes + "\uFF0C" + sec;
|
|
363
355
|
}
|
|
364
356
|
function renderComposeSeconds(ir, plan, opts) {
|
package/dist/lang/zh.js
CHANGED
|
@@ -294,15 +294,12 @@ function composeSecondsOnHour(ir, plan, opts) {
|
|
|
294
294
|
const sec = secondClause(ir);
|
|
295
295
|
const { rest } = plan;
|
|
296
296
|
const restText = render(ir, rest, opts);
|
|
297
|
-
if (rest.kind === "everyHour") {
|
|
298
|
-
return sec + "\uFF0C\u6BCF\u5C0F\u65F6";
|
|
299
|
-
}
|
|
300
|
-
if (rest.kind === "hourStep") {
|
|
301
|
-
return sec + "\uFF0C" + restText;
|
|
302
|
-
}
|
|
303
297
|
if ((rest.kind === "clockTimes" || rest.kind === "compactClockTimes") && isDaily(ir)) {
|
|
304
298
|
return "\u6BCF\u5929" + restText + sec;
|
|
305
299
|
}
|
|
300
|
+
if (rest.kind === "singleMinute") {
|
|
301
|
+
return restText + "\uFF0C" + sec;
|
|
302
|
+
}
|
|
306
303
|
return restText + sec;
|
|
307
304
|
}
|
|
308
305
|
function composeSecondsCadence(ir) {
|
|
@@ -322,17 +319,12 @@ function composeSecondsCadence(ir) {
|
|
|
322
319
|
function composeSecondsListed(ir) {
|
|
323
320
|
const sec = secondClause(ir);
|
|
324
321
|
const minutes = "\u6BCF\u5C0F\u65F6" + valueList(fieldSegments(ir, "minute"), "\u5206");
|
|
325
|
-
const minuteSegs = fieldSegments(ir, "minute");
|
|
326
322
|
if (ir.shapes.hour === "wildcard") {
|
|
327
323
|
return minutes + "\uFF0C" + sec;
|
|
328
324
|
}
|
|
329
325
|
if (isHourCadence(ir)) {
|
|
330
326
|
return cadence(stepSegment(ir, "hour").interval, UNITS.hour) + "\uFF0C" + minutes + "\uFF0C" + sec;
|
|
331
327
|
}
|
|
332
|
-
if (ir.shapes.hour === "range" && minuteSegs.length === 1 && minuteSegs[0].kind === "range") {
|
|
333
|
-
const [from, to] = fieldSegments(ir, "hour")[0].bounds;
|
|
334
|
-
return "\u5728" + hourWord(+from) + "\u81F3" + to + "\u70B9" + minuteSegs[0].bounds[1] + "\u5206\u4E4B\u95F4\uFF0C" + sec;
|
|
335
|
-
}
|
|
336
328
|
return hourFrame(ir) + minutes + "\uFF0C" + sec;
|
|
337
329
|
}
|
|
338
330
|
function renderComposeSeconds(ir, plan, opts) {
|
package/package.json
CHANGED
package/src/core/analyze.ts
CHANGED
|
@@ -269,10 +269,13 @@ function planSeconds(
|
|
|
269
269
|
return null;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
+
// The second makes the cadence sub-minute, so a minute of 0 is a real
|
|
273
|
+
// restriction that must be stated, not absorbed into an hourly idiom (which
|
|
274
|
+
// would silently drop it). Route minute 0 to the minute-explicit forms.
|
|
272
275
|
return {
|
|
273
276
|
kind: 'composeSeconds',
|
|
274
|
-
rest: planMinutes(pattern, shapes, analyses) ||
|
|
275
|
-
planHours(pattern, shapes, analyses)
|
|
277
|
+
rest: planMinutes(pattern, shapes, analyses, true) ||
|
|
278
|
+
planHours(pattern, shapes, analyses, true)
|
|
276
279
|
};
|
|
277
280
|
}
|
|
278
281
|
|
|
@@ -303,7 +306,8 @@ function planStandaloneSeconds(
|
|
|
303
306
|
function planMinutes(
|
|
304
307
|
pattern: Pattern,
|
|
305
308
|
shapes: Shapes,
|
|
306
|
-
analyses: Analyses
|
|
309
|
+
analyses: Analyses,
|
|
310
|
+
subMinuteSecond = false
|
|
307
311
|
): PlanNode | undefined {
|
|
308
312
|
if (shapes.minute === 'step') {
|
|
309
313
|
return {
|
|
@@ -333,7 +337,7 @@ function planMinutes(
|
|
|
333
337
|
}
|
|
334
338
|
|
|
335
339
|
if (pattern.hour === '*') {
|
|
336
|
-
return planMinutesUnderOpenHour(pattern, shapes);
|
|
340
|
+
return planMinutesUnderOpenHour(pattern, shapes, subMinuteSecond);
|
|
337
341
|
}
|
|
338
342
|
}
|
|
339
343
|
|
|
@@ -451,7 +455,8 @@ function planMinutesAcrossHours(
|
|
|
451
455
|
// Minute strategies that only stand on their own under a wildcard hour.
|
|
452
456
|
function planMinutesUnderOpenHour(
|
|
453
457
|
pattern: Pattern,
|
|
454
|
-
shapes: Shapes
|
|
458
|
+
shapes: Shapes,
|
|
459
|
+
subMinuteSecond: boolean
|
|
455
460
|
): PlanNode | undefined {
|
|
456
461
|
if (shapes.minute === 'range') {
|
|
457
462
|
return {kind: 'rangeOfMinutes'};
|
|
@@ -465,56 +470,89 @@ function planMinutesUnderOpenHour(
|
|
|
465
470
|
return {kind: 'everyMinute'};
|
|
466
471
|
}
|
|
467
472
|
|
|
468
|
-
|
|
473
|
+
// Minute 0 normally defers to "every hour" so a standalone `0 * * * *`
|
|
474
|
+
// stays terse; under a sub-minute second it must be stated, so name it.
|
|
475
|
+
if (pattern.minute !== '0' || subMinuteSecond) {
|
|
469
476
|
return {kind: 'singleMinute'};
|
|
470
477
|
}
|
|
471
478
|
}
|
|
472
479
|
|
|
473
|
-
// Hour strategies: the chain's last resort always produces a plan.
|
|
480
|
+
// Hour strategies: the chain's last resort always produces a plan. Under a
|
|
481
|
+
// sub-minute second a minute of 0 is a real restriction, so the absorbing
|
|
482
|
+
// idioms (hour range, hour step, every hour) are skipped for it and the hour
|
|
483
|
+
// is enumerated as clock times instead, stating the :00.
|
|
474
484
|
function planHours(
|
|
475
485
|
pattern: Pattern,
|
|
476
486
|
shapes: Shapes,
|
|
477
|
-
analyses: Analyses
|
|
487
|
+
analyses: Analyses,
|
|
488
|
+
subMinuteSecond = false
|
|
478
489
|
): PlanNode {
|
|
479
|
-
|
|
480
|
-
const bounds = pattern.hour.split('-');
|
|
481
|
-
let minuteForm: 'lead' | 'wildcard' | 'range' = 'lead';
|
|
482
|
-
|
|
483
|
-
if (pattern.minute === '*') {
|
|
484
|
-
minuteForm = 'wildcard';
|
|
485
|
-
}
|
|
486
|
-
else if (shapes.minute === 'range') {
|
|
487
|
-
minuteForm = 'range';
|
|
488
|
-
}
|
|
490
|
+
const absorbsMinuteZero = subMinuteSecond && pattern.minute === '0';
|
|
489
491
|
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
kind: 'hourRange',
|
|
493
|
-
last: analyses.lastMinuteFire,
|
|
494
|
-
minuteForm,
|
|
495
|
-
to: +bounds[1]
|
|
496
|
-
};
|
|
492
|
+
if (shapes.hour === 'range' && !absorbsMinuteZero) {
|
|
493
|
+
return planHourRange(pattern, shapes, analyses);
|
|
497
494
|
}
|
|
498
495
|
|
|
499
|
-
if (shapes.hour === 'step' && pattern.minute === '0') {
|
|
496
|
+
if (shapes.hour === 'step' && pattern.minute === '0' && !subMinuteSecond) {
|
|
500
497
|
return {kind: 'hourStep'};
|
|
501
498
|
}
|
|
502
499
|
|
|
503
|
-
if (pattern.hour === '*') {
|
|
500
|
+
if (pattern.hour === '*' && !absorbsMinuteZero) {
|
|
504
501
|
return {kind: 'everyHour'};
|
|
505
502
|
}
|
|
506
503
|
|
|
507
|
-
|
|
504
|
+
// When minute 0 must be stated, enumerate the on-the-hour times explicitly:
|
|
505
|
+
// the compact fold of a contiguous hour range would otherwise restate the
|
|
506
|
+
// hour-range idiom ("every hour from X through Y") and re-drop the :00.
|
|
507
|
+
return planClockTimes(pattern, analyses, absorbsMinuteZero);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
// The hour-range plan: a window from the first hour through the last. The
|
|
511
|
+
// minute clause leads (a single fire or a list), fires every minute (a range),
|
|
512
|
+
// or fills the window (a wildcard). A multi-valued minute (list or range)
|
|
513
|
+
// closes the window on the bare hour, stating its minutes separately; a single
|
|
514
|
+
// fire or a wildcard names an exact closing minute (its fire, or the wildcard's
|
|
515
|
+
// last :59) — otherwise the glued last fire reads as a continuous span.
|
|
516
|
+
function planHourRange(
|
|
517
|
+
pattern: Pattern,
|
|
518
|
+
shapes: Shapes,
|
|
519
|
+
analyses: Analyses
|
|
520
|
+
): PlanNode {
|
|
521
|
+
const bounds = pattern.hour.split('-');
|
|
522
|
+
let minuteForm: 'lead' | 'wildcard' | 'range' = 'lead';
|
|
523
|
+
|
|
524
|
+
if (pattern.minute === '*') {
|
|
525
|
+
minuteForm = 'wildcard';
|
|
526
|
+
}
|
|
527
|
+
else if (shapes.minute === 'range') {
|
|
528
|
+
minuteForm = 'range';
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const multiValued = shapes.minute === 'range' || shapes.minute === 'list';
|
|
532
|
+
|
|
533
|
+
return {
|
|
534
|
+
boundMinute: multiValued ? null : analyses.lastMinuteFire,
|
|
535
|
+
from: +bounds[0],
|
|
536
|
+
kind: 'hourRange',
|
|
537
|
+
last: analyses.lastMinuteFire,
|
|
538
|
+
minuteForm,
|
|
539
|
+
to: +bounds[1]
|
|
540
|
+
};
|
|
508
541
|
}
|
|
509
542
|
|
|
510
543
|
// Enumerated clock times up to the cap; past it, a compact form (a single
|
|
511
544
|
// minute folds into hour-segment windows; a minute list leads with its own
|
|
512
|
-
// clause).
|
|
513
|
-
|
|
545
|
+
// clause). `enumerate` forces the explicit list past the cap, used when a
|
|
546
|
+
// minute restriction must be named rather than folded into an hour idiom.
|
|
547
|
+
function planClockTimes(
|
|
548
|
+
pattern: Pattern,
|
|
549
|
+
analyses: Analyses,
|
|
550
|
+
enumerate = false
|
|
551
|
+
): PlanNode {
|
|
514
552
|
const hours = enumerateFires(pattern.hour, 0, 23);
|
|
515
553
|
const minutes = enumerateValues(pattern.minute);
|
|
516
554
|
|
|
517
|
-
if (hours.length * minutes.length > maxClockTimes) {
|
|
555
|
+
if (!enumerate && hours.length * minutes.length > maxClockTimes) {
|
|
518
556
|
return {
|
|
519
557
|
fold: minutes.length === 1,
|
|
520
558
|
kind: 'compactClockTimes',
|
package/src/core/ir.ts
CHANGED
|
@@ -78,6 +78,12 @@ export type PlanNode =
|
|
|
78
78
|
from: number;
|
|
79
79
|
to: number;
|
|
80
80
|
last: number;
|
|
81
|
+
// The minute to show on the closing bound, or `null` to close on the
|
|
82
|
+
// bare hour with the minutes stated separately. A single fire or a
|
|
83
|
+
// wildcard names an exact closing minute (the fire, or `:59`); a minute
|
|
84
|
+
// list or range would otherwise glue its last fire onto the bound and
|
|
85
|
+
// read as a continuous span, so it closes bare instead.
|
|
86
|
+
boundMinute: number | null;
|
|
81
87
|
minuteForm: 'lead' | 'wildcard' | 'range';
|
|
82
88
|
}
|
|
83
89
|
| {kind: 'hourStep'}
|
package/src/lang/de/index.ts
CHANGED
|
@@ -657,7 +657,11 @@ function renderHourRange(
|
|
|
657
657
|
plan: Extract<PlanNode, {kind: 'hourRange'}>,
|
|
658
658
|
opts: Opts
|
|
659
659
|
): string {
|
|
660
|
-
|
|
660
|
+
// A bare close (`boundMinute` null) lands on the top of the final hour
|
|
661
|
+
// (minute 0), matching the minute-0 baseline, with the minutes stated
|
|
662
|
+
// separately; a single fire or wildcard names an exact closing minute.
|
|
663
|
+
const window = hourWindow(plan.from, plan.to, plan.boundMinute ?? 0,
|
|
664
|
+
opts.style.sep);
|
|
661
665
|
|
|
662
666
|
if (plan.minuteForm === 'wildcard') {
|
|
663
667
|
return 'jede Minute ' + window;
|
package/src/lang/en/index.ts
CHANGED
|
@@ -376,7 +376,7 @@ function renderEveryHour(ir: IR, plan: PlanOf<'everyHour'>,
|
|
|
376
376
|
// minute; a discrete minute anchors as a lead clause.
|
|
377
377
|
function renderHourRange(ir: IR, plan: PlanOf<'hourRange'>,
|
|
378
378
|
opts: NormalizedOptions): string {
|
|
379
|
-
const window = hourWindow(plan, opts);
|
|
379
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
380
380
|
|
|
381
381
|
if (plan.minuteForm === 'wildcard') {
|
|
382
382
|
return 'every minute ' + window + trailingQualifier(ir, opts);
|
|
@@ -411,6 +411,14 @@ function renderHourStep(ir: IR, plan: PlanOf<'hourStep'>,
|
|
|
411
411
|
trailingQualifier(ir, opts);
|
|
412
412
|
}
|
|
413
413
|
|
|
414
|
+
// The hour-range plan as a window whose closing minute honors `boundMinute`:
|
|
415
|
+
// a bare close (`null`) lands on the top of the final hour (`:00`), matching
|
|
416
|
+
// the minute-0 baseline, with the minutes stated separately elsewhere.
|
|
417
|
+
function boundedWindow(plan: PlanOf<'hourRange'>):
|
|
418
|
+
{from: number; to: number; last: number} {
|
|
419
|
+
return {from: plan.from, last: plan.boundMinute ?? 0, to: plan.to};
|
|
420
|
+
}
|
|
421
|
+
|
|
414
422
|
// An hour window phrase, e.g. "from 9 a.m. through 5:45 p.m.". Windows
|
|
415
423
|
// open at the top of the first hour and close at the minute field's last
|
|
416
424
|
// fire within the final hour.
|
package/src/lang/es/index.ts
CHANGED
|
@@ -525,7 +525,7 @@ function renderHourRange(
|
|
|
525
525
|
plan: Extract<PlanNode, {kind: 'hourRange'}>,
|
|
526
526
|
opts: Opts
|
|
527
527
|
): string {
|
|
528
|
-
const window = hourWindow(plan, opts);
|
|
528
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
529
529
|
|
|
530
530
|
if (plan.minuteForm === 'wildcard') {
|
|
531
531
|
return 'cada minuto ' + window + trailingQualifier(ir, opts);
|
|
@@ -558,6 +558,15 @@ function renderHourStep(
|
|
|
558
558
|
trailingQualifier(ir, opts);
|
|
559
559
|
}
|
|
560
560
|
|
|
561
|
+
// The hour-range plan as a window whose closing minute honors `boundMinute`:
|
|
562
|
+
// a bare close (`null`) lands on the top of the final hour (minute 0),
|
|
563
|
+
// matching the minute-0 baseline, with the minutes stated separately.
|
|
564
|
+
function boundedWindow(
|
|
565
|
+
plan: Extract<PlanNode, {kind: 'hourRange'}>
|
|
566
|
+
): {from: number; to: number; last: number} {
|
|
567
|
+
return {from: plan.from, last: plan.boundMinute ?? 0, to: plan.to};
|
|
568
|
+
}
|
|
569
|
+
|
|
561
570
|
// "de las 9:00 a las 17:45": a window from the top of the first hour to
|
|
562
571
|
// the minute field's last fire within the final hour.
|
|
563
572
|
function hourWindow(
|
package/src/lang/fi/index.ts
CHANGED
|
@@ -686,7 +686,7 @@ function renderHourRange(
|
|
|
686
686
|
plan: Extract<PlanNode, {kind: 'hourRange'}>,
|
|
687
687
|
opts: NormalizedOptions
|
|
688
688
|
): string {
|
|
689
|
-
const window = hourWindow(plan, opts);
|
|
689
|
+
const window = hourWindow(boundedWindow(plan), opts);
|
|
690
690
|
|
|
691
691
|
if (plan.minuteForm === 'wildcard') {
|
|
692
692
|
return 'joka minuutti ' + window + trailingQualifier(ir, opts);
|
|
@@ -726,6 +726,16 @@ function renderHourStep(
|
|
|
726
726
|
trailingQualifier(ir, opts);
|
|
727
727
|
}
|
|
728
728
|
|
|
729
|
+
// The hour-range plan as a window whose closing minute honors `boundMinute`:
|
|
730
|
+
// a bare close (`null`) lands on the top of the final hour (minute 0), so
|
|
731
|
+
// `kloRange` renders the bare "klo 9–17" form, with the minutes stated
|
|
732
|
+
// separately; a single fire or wildcard names an exact closing minute.
|
|
733
|
+
function boundedWindow(
|
|
734
|
+
plan: Extract<PlanNode, {kind: 'hourRange'}>
|
|
735
|
+
): HourWindow {
|
|
736
|
+
return {from: plan.from, last: plan.boundMinute ?? 0, to: plan.to};
|
|
737
|
+
}
|
|
738
|
+
|
|
729
739
|
// "klo 9.00–17.45": a window from the top of the first hour to the
|
|
730
740
|
// minute field's last fire within the final hour.
|
|
731
741
|
function hourWindow(window: HourWindow, opts: NormalizedOptions): string {
|
package/src/lang/zh/index.ts
CHANGED
|
@@ -423,19 +423,17 @@ function composeSecondsOnHour(ir: IR, plan: PlanNode, opts: Opts): string {
|
|
|
423
423
|
const {rest} = plan as Extract<PlanNode, {kind: 'composeSeconds'}>;
|
|
424
424
|
const restText = render(ir, rest, opts);
|
|
425
425
|
|
|
426
|
-
if (rest.kind === 'everyHour') {
|
|
427
|
-
return sec + ',每小时';
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
if (rest.kind === 'hourStep') {
|
|
431
|
-
return sec + ',' + restText;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
426
|
if ((rest.kind === 'clockTimes' || rest.kind === 'compactClockTimes') &&
|
|
435
427
|
isDaily(ir)) {
|
|
436
428
|
return '每天' + restText + sec;
|
|
437
429
|
}
|
|
438
430
|
|
|
431
|
+
// A stated minute (e.g. minute 0 under a sub-minute second) takes the same
|
|
432
|
+
// "," connector the listed-minute path uses.
|
|
433
|
+
if (rest.kind === 'singleMinute') {
|
|
434
|
+
return restText + ',' + sec;
|
|
435
|
+
}
|
|
436
|
+
|
|
439
437
|
return restText + sec;
|
|
440
438
|
}
|
|
441
439
|
|
|
@@ -460,10 +458,12 @@ function composeSecondsCadence(ir: IR): string {
|
|
|
460
458
|
}
|
|
461
459
|
|
|
462
460
|
// Listed/ranged minute: "每小时<minutes>,每秒", confined by any hour frame.
|
|
461
|
+
// A minute list or range under an hour range closes on the bare hour frame
|
|
462
|
+
// ("在9点至17点之间"), stating its minutes separately, rather than gluing its
|
|
463
|
+
// last fire onto the window end ("…17点30分") and reading as a continuous span.
|
|
463
464
|
function composeSecondsListed(ir: IR): string {
|
|
464
465
|
const sec = secondClause(ir);
|
|
465
466
|
const minutes = '每小时' + valueList(fieldSegments(ir, 'minute'), '分');
|
|
466
|
-
const minuteSegs = fieldSegments(ir, 'minute');
|
|
467
467
|
|
|
468
468
|
if (ir.shapes.hour === 'wildcard') {
|
|
469
469
|
return minutes + ',' + sec;
|
|
@@ -474,16 +474,6 @@ function composeSecondsListed(ir: IR): string {
|
|
|
474
474
|
minutes + ',' + sec;
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
// A minute range under an hour range folds into the window end ("…17点30分").
|
|
478
|
-
if (ir.shapes.hour === 'range' && minuteSegs.length === 1 &&
|
|
479
|
-
minuteSegs[0].kind === 'range') {
|
|
480
|
-
const [from, to] = (fieldSegments(ir, 'hour')[0] as
|
|
481
|
-
Extract<Segment, {kind: 'range'}>).bounds;
|
|
482
|
-
|
|
483
|
-
return '在' + hourWord(+from) + '至' + to + '点' +
|
|
484
|
-
minuteSegs[0].bounds[1] + '分之间,' + sec;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
477
|
return hourFrame(ir) + minutes + ',' + sec;
|
|
488
478
|
}
|
|
489
479
|
|