calendaryjs 0.2.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +147 -21
- package/README.md +30 -11
- package/dist/builder/index.cjs +16 -2
- package/dist/builder/index.d.cts +12 -4
- package/dist/builder/index.d.ts +12 -4
- package/dist/builder/index.js +16 -3
- package/dist/{events-Bm7R9XFB.d.cts → events-DSiv9j6V.d.cts} +52 -8
- package/dist/{events-Bm7R9XFB.d.ts → events-DSiv9j6V.d.ts} +52 -8
- package/dist/index.cjs +147 -16
- package/dist/index.d.cts +37 -2
- package/dist/index.d.ts +37 -2
- package/dist/index.js +147 -16
- package/package.json +2 -2
package/LICENSE
CHANGED
|
@@ -1,21 +1,147 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
Required Notice: Copyright © 2026 calendaryjs (https://github.com/vbilltran68/calendaryjs)
|
|
2
|
+
|
|
3
|
+
calendaryjs (the core engine) is licensed under the PolyForm Noncommercial
|
|
4
|
+
License 1.0.0, reproduced below. It is FREE for any noncommercial purpose.
|
|
5
|
+
|
|
6
|
+
COMMERCIAL USE REQUIRES A SEPARATE COMMERCIAL LICENSE. Running calendaryjs in
|
|
7
|
+
or for a commercial product, service, or revenue-generating site (including
|
|
8
|
+
ad-supported sites) is commercial use. To obtain a commercial license, see
|
|
9
|
+
COMMERCIAL.md or contact the author via the repository above.
|
|
10
|
+
|
|
11
|
+
The official plugins (packages/lunar, hijri, liturgical, ics) are MIT-licensed,
|
|
12
|
+
but they require this core, so commercial use of the combined work still
|
|
13
|
+
requires a commercial license for the core.
|
|
14
|
+
|
|
15
|
+
----------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
# PolyForm Noncommercial License 1.0.0
|
|
18
|
+
|
|
19
|
+
<https://polyformproject.org/licenses/noncommercial/1.0.0>
|
|
20
|
+
|
|
21
|
+
## Acceptance
|
|
22
|
+
|
|
23
|
+
In order to get any license under these terms, you must agree
|
|
24
|
+
to them as both strict obligations and conditions to all
|
|
25
|
+
your licenses.
|
|
26
|
+
|
|
27
|
+
## Copyright License
|
|
28
|
+
|
|
29
|
+
The licensor grants you a copyright license for the
|
|
30
|
+
software to do everything you might do with the software
|
|
31
|
+
that would otherwise infringe the licensor's copyright
|
|
32
|
+
in it for any permitted purpose. However, you may
|
|
33
|
+
only distribute the software according to [Distribution
|
|
34
|
+
License](#distribution-license) and make changes or new works
|
|
35
|
+
based on the software according to [Changes and New Works
|
|
36
|
+
License](#changes-and-new-works-license).
|
|
37
|
+
|
|
38
|
+
## Distribution License
|
|
39
|
+
|
|
40
|
+
The licensor grants you an additional copyright license
|
|
41
|
+
to distribute copies of the software. Your license
|
|
42
|
+
to distribute covers distributing the software with
|
|
43
|
+
changes and new works permitted by [Changes and New Works
|
|
44
|
+
License](#changes-and-new-works-license).
|
|
45
|
+
|
|
46
|
+
## Notices
|
|
47
|
+
|
|
48
|
+
You must ensure that anyone who gets a copy of any part of
|
|
49
|
+
the software from you also gets a copy of these terms or the
|
|
50
|
+
URL for them above, as well as copies of any plain-text lines
|
|
51
|
+
beginning with `Required Notice:` that the licensor provided
|
|
52
|
+
with the software. For example:
|
|
53
|
+
|
|
54
|
+
> Required Notice: Copyright Yoyodyne, Inc. (http://example.com)
|
|
55
|
+
|
|
56
|
+
## Changes and New Works License
|
|
57
|
+
|
|
58
|
+
The licensor grants you an additional copyright license to
|
|
59
|
+
make changes and new works based on the software for any
|
|
60
|
+
permitted purpose.
|
|
61
|
+
|
|
62
|
+
## Patent License
|
|
63
|
+
|
|
64
|
+
The licensor grants you a patent license for the software that
|
|
65
|
+
covers patent claims the licensor can license, or becomes able
|
|
66
|
+
to license, that you would infringe by using the software.
|
|
67
|
+
|
|
68
|
+
## Noncommercial Purposes
|
|
69
|
+
|
|
70
|
+
Any noncommercial purpose is a permitted purpose.
|
|
71
|
+
|
|
72
|
+
## Personal Uses
|
|
73
|
+
|
|
74
|
+
Personal use for research, experiment, and testing for
|
|
75
|
+
the benefit of public knowledge, personal study, private
|
|
76
|
+
entertainment, hobby projects, amateur pursuits, or religious
|
|
77
|
+
observance, without any anticipated commercial application,
|
|
78
|
+
is use for a permitted purpose.
|
|
79
|
+
|
|
80
|
+
## Noncommercial Organizations
|
|
81
|
+
|
|
82
|
+
Use by any charitable organization, educational institution,
|
|
83
|
+
public research organization, public safety or health
|
|
84
|
+
organization, environmental protection organization,
|
|
85
|
+
or government institution is use for a permitted purpose
|
|
86
|
+
regardless of the source of funding or obligations resulting
|
|
87
|
+
from the funding.
|
|
88
|
+
|
|
89
|
+
## Fair Use
|
|
90
|
+
|
|
91
|
+
You may have "fair use" rights for the software under the
|
|
92
|
+
law. These terms do not limit them.
|
|
93
|
+
|
|
94
|
+
## No Other Rights
|
|
95
|
+
|
|
96
|
+
These terms do not allow you to sublicense or transfer any of
|
|
97
|
+
your licenses to anyone else, or prevent the licensor from
|
|
98
|
+
granting licenses to anyone else. These terms do not imply
|
|
99
|
+
any other licenses.
|
|
100
|
+
|
|
101
|
+
## Patent Defense
|
|
102
|
+
|
|
103
|
+
If you make any written claim that the software infringes or
|
|
104
|
+
contributes to infringement of any patent, your patent license
|
|
105
|
+
for the software granted under these terms ends immediately. If
|
|
106
|
+
your company makes such a claim, your patent license ends
|
|
107
|
+
immediately for work on behalf of your company.
|
|
108
|
+
|
|
109
|
+
## Violations
|
|
110
|
+
|
|
111
|
+
The first time you are notified in writing that you have
|
|
112
|
+
violated any of these terms, or done anything with the software
|
|
113
|
+
not covered by your licenses, your licenses can nonetheless
|
|
114
|
+
continue if you come into full compliance with these terms,
|
|
115
|
+
and take practical steps to correct past violations, within
|
|
116
|
+
32 days of receiving notice. Otherwise, all your licenses
|
|
117
|
+
end immediately.
|
|
118
|
+
|
|
119
|
+
## No Liability
|
|
120
|
+
|
|
121
|
+
***As far as the law allows, the software comes as is, without
|
|
122
|
+
any warranty or condition, and the licensor will not be liable
|
|
123
|
+
to you for any damages arising out of these terms or the use
|
|
124
|
+
or nature of the software, under any kind of legal claim.***
|
|
125
|
+
|
|
126
|
+
## Definitions
|
|
127
|
+
|
|
128
|
+
The **licensor** is the individual or entity offering these
|
|
129
|
+
terms, and the **software** is the software the licensor makes
|
|
130
|
+
available under these terms.
|
|
131
|
+
|
|
132
|
+
**You** refers to the individual or entity agreeing to these
|
|
133
|
+
terms.
|
|
134
|
+
|
|
135
|
+
**Your company** is any legal entity, sole proprietorship,
|
|
136
|
+
or other kind of organization that you work for, plus all
|
|
137
|
+
organizations that have control over, are under the control of,
|
|
138
|
+
or are under common control with that organization. **Control**
|
|
139
|
+
means ownership of substantially all the assets of an entity,
|
|
140
|
+
or the power to direct its management and policies by vote,
|
|
141
|
+
contract, or otherwise. Control can be direct or indirect.
|
|
142
|
+
|
|
143
|
+
**Your licenses** are all the licenses granted to you for the
|
|
144
|
+
software under these terms.
|
|
145
|
+
|
|
146
|
+
**Use** means anything you do with the software requiring one
|
|
147
|
+
of your licenses.
|
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<img alt="Zero dependencies" src="https://img.shields.io/badge/deps-zero-22c55e?style=for-the-badge&labelColor=16120F" />
|
|
14
14
|
</p>
|
|
15
15
|
|
|
16
|
-
- 🔁 **Recurrence engine** — weekly, monthly, nth-weekday, formula, relative
|
|
16
|
+
- 🔁 **Recurrence engine** — daily, weekly, monthly, nth-weekday, formula, relative
|
|
17
17
|
- 🔌 **Pluggable calendar systems** — one engine, every calendar
|
|
18
18
|
- ✍️ **Fluent builder** — `every("week").on("mon", "wed", "fri")`
|
|
19
19
|
- 🔍 **Query API** — filter events across groups & date ranges
|
|
@@ -70,6 +70,9 @@ every("year")
|
|
|
70
70
|
.title("Thanksgiving");
|
|
71
71
|
every(2, "weeks").on("tuesday").title("Standup"); // every other Tuesday
|
|
72
72
|
every("week").on("monday", "wednesday", "friday").title("Gym"); // pick weekdays
|
|
73
|
+
every("month").on(nth(1, "monday")).title("Retro"); // 1st Monday of every month
|
|
74
|
+
every("month").on(-1).title("Rent"); // last day of every month
|
|
75
|
+
every(3, "days").title("Water plants"); // every 3 days
|
|
73
76
|
once("2026-06-15").title("Wedding"); // a single date
|
|
74
77
|
```
|
|
75
78
|
|
|
@@ -83,6 +86,9 @@ once("2026-06-15").title("Wedding"); // a single date
|
|
|
83
86
|
cal.getEvents("2026-12-25"); // a single day
|
|
84
87
|
cal.getEventsInRange("2026-01-01", "2026-12-31"); // a range
|
|
85
88
|
cal.search().group("holidays").range("2026-01-01", "2026-12-31").getEvents();
|
|
89
|
+
|
|
90
|
+
// Filter by kind, status, or source (each matches any of the listed values)
|
|
91
|
+
cal.search().type("weekly").status("confirmed").source("work-feed").getEvents();
|
|
86
92
|
```
|
|
87
93
|
|
|
88
94
|
## 4 · Add a calendar system
|
|
@@ -127,19 +133,30 @@ cal.load({
|
|
|
127
133
|
cal.load(jsonString); // …or from a .cdy (JSON) string, read from disk or fetched
|
|
128
134
|
```
|
|
129
135
|
|
|
136
|
+
The reverse — **`cal.toCollection()`** — serializes events back out, declaring the plugins
|
|
137
|
+
their types need so the result re-loads cleanly. `JSON.stringify` it for a `.cdy` file:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
const doc = cal.toCollection({ name: "holidays" });
|
|
141
|
+
// → { collection: "holidays", plugins: ["calendaryjs-plugin-lunar"], events: [ … ] }
|
|
142
|
+
|
|
143
|
+
JSON.stringify(doc); // the .cdy form — write to disk, or POST it somewhere
|
|
144
|
+
```
|
|
145
|
+
|
|
130
146
|
## Reference
|
|
131
147
|
|
|
132
148
|
### Event types
|
|
133
149
|
|
|
134
|
-
| Type | Description
|
|
135
|
-
| ------------- |
|
|
136
|
-
| `const` | Fixed annual date
|
|
137
|
-
| `fixed` | One-time date
|
|
138
|
-
| `monthly` | Same day every month (interval
|
|
139
|
-
| `weekly` | One or more weekdays (interval/range)
|
|
140
|
-
| `
|
|
141
|
-
| `
|
|
142
|
-
| `
|
|
150
|
+
| Type | Description | Example |
|
|
151
|
+
| ------------- | -------------------------------------------------- | --------------------------- |
|
|
152
|
+
| `const` | Fixed annual date (negative day = from month end) | Christmas (Dec 25) |
|
|
153
|
+
| `fixed` | One-time date | Wedding (Jun 15, 2025) |
|
|
154
|
+
| `monthly` | Same day every month (interval; `-1` = last day) | Payday (15th) · Rent (-1) |
|
|
155
|
+
| `weekly` | One or more weekdays (interval/range) | Standup (Mon, Wed, Fri) |
|
|
156
|
+
| `daily` | Every day, or every N days | Water plants (every 3 days) |
|
|
157
|
+
| `nth-weekday` | Nth weekday of a month — or every month — anchored | 1st Monday of every month |
|
|
158
|
+
| `formula` | Custom formula | Last business day of May |
|
|
159
|
+
| `relative` | Offset from a registered anchor | 49 days after an anchor |
|
|
143
160
|
|
|
144
161
|
Plugins add more types (e.g. `lunar`, `hijri`, `liturgical`).
|
|
145
162
|
|
|
@@ -168,4 +185,6 @@ Every event shares `BaseEventProperties` plus its type-specific date fields.
|
|
|
168
185
|
|
|
169
186
|
## License
|
|
170
187
|
|
|
171
|
-
|
|
188
|
+
[PolyForm Noncommercial 1.0.0](./LICENSE) — free for any noncommercial purpose.
|
|
189
|
+
**Commercial use (incl. ad-supported sites) requires a commercial license** — see
|
|
190
|
+
[COMMERCIAL.md](https://github.com/vbilltran68/calendaryjs/blob/main/COMMERCIAL.md).
|
package/dist/builder/index.cjs
CHANGED
|
@@ -28,6 +28,9 @@ var MONTHS = {
|
|
|
28
28
|
dec: 12
|
|
29
29
|
};
|
|
30
30
|
function nth(n, weekday, month) {
|
|
31
|
+
if (month === void 0) {
|
|
32
|
+
return { type: "nth-weekday", fields: { nth: n, dayOfWeek: WEEKDAYS[weekday] } };
|
|
33
|
+
}
|
|
31
34
|
const m = typeof month === "number" ? month : MONTHS[month];
|
|
32
35
|
if (!m) throw new Error(`unknown month "${month}"`);
|
|
33
36
|
return { type: "nth-weekday", fields: { nth: n, dayOfWeek: WEEKDAYS[weekday], month: m } };
|
|
@@ -154,6 +157,7 @@ var BaseBuilder = class {
|
|
|
154
157
|
return id;
|
|
155
158
|
}
|
|
156
159
|
};
|
|
160
|
+
var INTERVAL_TYPES = /* @__PURE__ */ new Set(["weekly", "monthly", "daily"]);
|
|
157
161
|
var EventBuilder = class extends BaseBuilder {
|
|
158
162
|
constructor(unit, interval) {
|
|
159
163
|
super();
|
|
@@ -191,7 +195,10 @@ var EventBuilder = class extends BaseBuilder {
|
|
|
191
195
|
return this;
|
|
192
196
|
}
|
|
193
197
|
const sel = selector;
|
|
194
|
-
|
|
198
|
+
const monthlyNth = sel.type === "nth-weekday" && this.unit === "month";
|
|
199
|
+
if (!monthlyNth && this.unit !== "year") {
|
|
200
|
+
throw new Error(`.on(<selector>) needs every("year")`);
|
|
201
|
+
}
|
|
195
202
|
this.selectorType = sel.type;
|
|
196
203
|
Object.assign(this.fields, sel.fields);
|
|
197
204
|
return this;
|
|
@@ -226,6 +233,9 @@ var EventBuilder = class extends BaseBuilder {
|
|
|
226
233
|
return this;
|
|
227
234
|
}
|
|
228
235
|
build() {
|
|
236
|
+
if (!this.selectorType && this.unit === "day") {
|
|
237
|
+
this.selectorType = "daily";
|
|
238
|
+
}
|
|
229
239
|
if (!this.selectorType) {
|
|
230
240
|
throw new Error(`every("${this.unit}") needs a position \u2014 call .on(...)`);
|
|
231
241
|
}
|
|
@@ -236,7 +246,7 @@ var EventBuilder = class extends BaseBuilder {
|
|
|
236
246
|
...this.payload
|
|
237
247
|
};
|
|
238
248
|
if (this.interval > 1) {
|
|
239
|
-
if (
|
|
249
|
+
if (!INTERVAL_TYPES.has(this.selectorType)) {
|
|
240
250
|
throw new Error(
|
|
241
251
|
`every(${this.interval}, \u2026) is not supported for "${this.selectorType}" yet`
|
|
242
252
|
);
|
|
@@ -318,6 +328,9 @@ function weekly(weekday, ...moreWeekdays) {
|
|
|
318
328
|
function monthly(day) {
|
|
319
329
|
return every("month").on(day);
|
|
320
330
|
}
|
|
331
|
+
function daily() {
|
|
332
|
+
return every("day");
|
|
333
|
+
}
|
|
321
334
|
function yearly(month, day) {
|
|
322
335
|
return every("year").on(date(month, day));
|
|
323
336
|
}
|
|
@@ -328,6 +341,7 @@ function slug(value) {
|
|
|
328
341
|
exports.EventBuilder = EventBuilder;
|
|
329
342
|
exports.FixedBuilder = FixedBuilder;
|
|
330
343
|
exports.RelativeBuilder = RelativeBuilder;
|
|
344
|
+
exports.daily = daily;
|
|
331
345
|
exports.date = date;
|
|
332
346
|
exports.every = every;
|
|
333
347
|
exports.from = from;
|
package/dist/builder/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EventConfig } from '../events-
|
|
1
|
+
import { E as EventConfig } from '../events-DSiv9j6V.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A position selector — passed to {@link EventBuilder.on}. It contributes the
|
|
@@ -38,7 +38,13 @@ declare const MONTHS: {
|
|
|
38
38
|
readonly dec: 12;
|
|
39
39
|
};
|
|
40
40
|
type MonthName = keyof typeof MONTHS;
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* An `nth-weekday` position. With a month it's an annual date —
|
|
43
|
+
* `every("year").on(nth(2, "sunday", "may"))` (2nd Sunday of May). Without a
|
|
44
|
+
* month it repeats monthly — `every("month").on(nth(1, "monday"))` (1st Monday
|
|
45
|
+
* of every month).
|
|
46
|
+
*/
|
|
47
|
+
declare function nth(n: 1 | 2 | 3 | 4 | -1, weekday: Weekday): Selector;
|
|
42
48
|
declare function nth(n: 1 | 2 | 3 | 4 | -1, weekday: Weekday, month: MonthName | number): Selector;
|
|
43
49
|
type Unit = "day" | "week" | "month" | "year";
|
|
44
50
|
declare const PLURAL: Record<string, Unit>;
|
|
@@ -145,9 +151,11 @@ declare function once(dateStr: string): FixedBuilder;
|
|
|
145
151
|
* a multi-day weekly: `weekly("monday","wednesday","friday")`.
|
|
146
152
|
*/
|
|
147
153
|
declare function weekly(weekday: Weekday, ...moreWeekdays: Weekday[]): EventBuilder;
|
|
148
|
-
/** `monthly(15)` = `every("month").on(15)
|
|
154
|
+
/** `monthly(15)` = `every("month").on(15)`; `monthly(-1)` = the last day of every month. */
|
|
149
155
|
declare function monthly(day: number): EventBuilder;
|
|
156
|
+
/** `daily()` = `every("day")` — every day. Use `every(N, "days")` for a wider cadence. */
|
|
157
|
+
declare function daily(): EventBuilder;
|
|
150
158
|
/** `yearly(12, 25)` = `every("year").on(date(12, 25))`. */
|
|
151
159
|
declare function yearly(month: number, day: number): EventBuilder;
|
|
152
160
|
|
|
153
|
-
export { EventBuilder, FixedBuilder, type MonthName, RelativeBuilder, type Selector, type Weekday, date, every, from, monthly, nth, once, weekly, yearly };
|
|
161
|
+
export { EventBuilder, FixedBuilder, type MonthName, RelativeBuilder, type Selector, type Weekday, daily, date, every, from, monthly, nth, once, weekly, yearly };
|
package/dist/builder/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as EventConfig } from '../events-
|
|
1
|
+
import { E as EventConfig } from '../events-DSiv9j6V.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* A position selector — passed to {@link EventBuilder.on}. It contributes the
|
|
@@ -38,7 +38,13 @@ declare const MONTHS: {
|
|
|
38
38
|
readonly dec: 12;
|
|
39
39
|
};
|
|
40
40
|
type MonthName = keyof typeof MONTHS;
|
|
41
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* An `nth-weekday` position. With a month it's an annual date —
|
|
43
|
+
* `every("year").on(nth(2, "sunday", "may"))` (2nd Sunday of May). Without a
|
|
44
|
+
* month it repeats monthly — `every("month").on(nth(1, "monday"))` (1st Monday
|
|
45
|
+
* of every month).
|
|
46
|
+
*/
|
|
47
|
+
declare function nth(n: 1 | 2 | 3 | 4 | -1, weekday: Weekday): Selector;
|
|
42
48
|
declare function nth(n: 1 | 2 | 3 | 4 | -1, weekday: Weekday, month: MonthName | number): Selector;
|
|
43
49
|
type Unit = "day" | "week" | "month" | "year";
|
|
44
50
|
declare const PLURAL: Record<string, Unit>;
|
|
@@ -145,9 +151,11 @@ declare function once(dateStr: string): FixedBuilder;
|
|
|
145
151
|
* a multi-day weekly: `weekly("monday","wednesday","friday")`.
|
|
146
152
|
*/
|
|
147
153
|
declare function weekly(weekday: Weekday, ...moreWeekdays: Weekday[]): EventBuilder;
|
|
148
|
-
/** `monthly(15)` = `every("month").on(15)
|
|
154
|
+
/** `monthly(15)` = `every("month").on(15)`; `monthly(-1)` = the last day of every month. */
|
|
149
155
|
declare function monthly(day: number): EventBuilder;
|
|
156
|
+
/** `daily()` = `every("day")` — every day. Use `every(N, "days")` for a wider cadence. */
|
|
157
|
+
declare function daily(): EventBuilder;
|
|
150
158
|
/** `yearly(12, 25)` = `every("year").on(date(12, 25))`. */
|
|
151
159
|
declare function yearly(month: number, day: number): EventBuilder;
|
|
152
160
|
|
|
153
|
-
export { EventBuilder, FixedBuilder, type MonthName, RelativeBuilder, type Selector, type Weekday, date, every, from, monthly, nth, once, weekly, yearly };
|
|
161
|
+
export { EventBuilder, FixedBuilder, type MonthName, RelativeBuilder, type Selector, type Weekday, daily, date, every, from, monthly, nth, once, weekly, yearly };
|
package/dist/builder/index.js
CHANGED
|
@@ -26,6 +26,9 @@ var MONTHS = {
|
|
|
26
26
|
dec: 12
|
|
27
27
|
};
|
|
28
28
|
function nth(n, weekday, month) {
|
|
29
|
+
if (month === void 0) {
|
|
30
|
+
return { type: "nth-weekday", fields: { nth: n, dayOfWeek: WEEKDAYS[weekday] } };
|
|
31
|
+
}
|
|
29
32
|
const m = typeof month === "number" ? month : MONTHS[month];
|
|
30
33
|
if (!m) throw new Error(`unknown month "${month}"`);
|
|
31
34
|
return { type: "nth-weekday", fields: { nth: n, dayOfWeek: WEEKDAYS[weekday], month: m } };
|
|
@@ -152,6 +155,7 @@ var BaseBuilder = class {
|
|
|
152
155
|
return id;
|
|
153
156
|
}
|
|
154
157
|
};
|
|
158
|
+
var INTERVAL_TYPES = /* @__PURE__ */ new Set(["weekly", "monthly", "daily"]);
|
|
155
159
|
var EventBuilder = class extends BaseBuilder {
|
|
156
160
|
constructor(unit, interval) {
|
|
157
161
|
super();
|
|
@@ -189,7 +193,10 @@ var EventBuilder = class extends BaseBuilder {
|
|
|
189
193
|
return this;
|
|
190
194
|
}
|
|
191
195
|
const sel = selector;
|
|
192
|
-
|
|
196
|
+
const monthlyNth = sel.type === "nth-weekday" && this.unit === "month";
|
|
197
|
+
if (!monthlyNth && this.unit !== "year") {
|
|
198
|
+
throw new Error(`.on(<selector>) needs every("year")`);
|
|
199
|
+
}
|
|
193
200
|
this.selectorType = sel.type;
|
|
194
201
|
Object.assign(this.fields, sel.fields);
|
|
195
202
|
return this;
|
|
@@ -224,6 +231,9 @@ var EventBuilder = class extends BaseBuilder {
|
|
|
224
231
|
return this;
|
|
225
232
|
}
|
|
226
233
|
build() {
|
|
234
|
+
if (!this.selectorType && this.unit === "day") {
|
|
235
|
+
this.selectorType = "daily";
|
|
236
|
+
}
|
|
227
237
|
if (!this.selectorType) {
|
|
228
238
|
throw new Error(`every("${this.unit}") needs a position \u2014 call .on(...)`);
|
|
229
239
|
}
|
|
@@ -234,7 +244,7 @@ var EventBuilder = class extends BaseBuilder {
|
|
|
234
244
|
...this.payload
|
|
235
245
|
};
|
|
236
246
|
if (this.interval > 1) {
|
|
237
|
-
if (
|
|
247
|
+
if (!INTERVAL_TYPES.has(this.selectorType)) {
|
|
238
248
|
throw new Error(
|
|
239
249
|
`every(${this.interval}, \u2026) is not supported for "${this.selectorType}" yet`
|
|
240
250
|
);
|
|
@@ -316,6 +326,9 @@ function weekly(weekday, ...moreWeekdays) {
|
|
|
316
326
|
function monthly(day) {
|
|
317
327
|
return every("month").on(day);
|
|
318
328
|
}
|
|
329
|
+
function daily() {
|
|
330
|
+
return every("day");
|
|
331
|
+
}
|
|
319
332
|
function yearly(month, day) {
|
|
320
333
|
return every("year").on(date(month, day));
|
|
321
334
|
}
|
|
@@ -323,4 +336,4 @@ function slug(value) {
|
|
|
323
336
|
return value.toLowerCase().replace(/đ/g, "d").normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "event";
|
|
324
337
|
}
|
|
325
338
|
|
|
326
|
-
export { EventBuilder, FixedBuilder, RelativeBuilder, date, every, from, monthly, nth, once, weekly, yearly };
|
|
339
|
+
export { EventBuilder, FixedBuilder, RelativeBuilder, daily, date, every, from, monthly, nth, once, weekly, yearly };
|
|
@@ -228,8 +228,10 @@ interface ConstEvent<TMetadata extends Record<string, unknown> = Record<string,
|
|
|
228
228
|
*/
|
|
229
229
|
month: number;
|
|
230
230
|
/**
|
|
231
|
-
* Day of the month
|
|
231
|
+
* Day of the month. `1`–`31`, or **negative to count from the end**
|
|
232
|
+
* (`-1` = last day, `-2` = second-to-last).
|
|
232
233
|
* @example 25 // 25th day
|
|
234
|
+
* @example -1 // last day of the month
|
|
233
235
|
*/
|
|
234
236
|
day: number;
|
|
235
237
|
/**
|
|
@@ -292,9 +294,12 @@ interface FixedEvent<TMetadata extends Record<string, unknown> = Record<string,
|
|
|
292
294
|
interface MonthlyEvent<TMetadata extends Record<string, unknown> = Record<string, unknown>, TCategory extends string = string> extends BaseEventProperties<TMetadata, TCategory> {
|
|
293
295
|
type: "monthly";
|
|
294
296
|
/**
|
|
295
|
-
* Day of the month
|
|
296
|
-
*
|
|
297
|
+
* Day of the month. `1`–`31`, or **negative to count from the end**
|
|
298
|
+
* (`-1` = last day of every month, `-2` = second-to-last).
|
|
299
|
+
* Note: a positive day past the month's length (e.g. 31 in February) is
|
|
300
|
+
* skipped for that month.
|
|
297
301
|
* @example 15 // 15th of each month
|
|
302
|
+
* @example -1 // last day of every month
|
|
298
303
|
*/
|
|
299
304
|
day: number;
|
|
300
305
|
/**
|
|
@@ -372,6 +377,43 @@ interface WeeklyEvent<TMetadata extends Record<string, unknown> = Record<string,
|
|
|
372
377
|
*/
|
|
373
378
|
excludeDates?: string[];
|
|
374
379
|
}
|
|
380
|
+
/**
|
|
381
|
+
* DAILY - Recurring events every day, or every N days.
|
|
382
|
+
* Supports an interval, a date range, and date exclusions. With `interval > 1`
|
|
383
|
+
* the cadence is phased off `startDate` (or a fixed epoch when omitted) so
|
|
384
|
+
* "every N days" stays in step across the year boundary instead of resetting.
|
|
385
|
+
* @template TMetadata - Custom metadata type extending Record<string, unknown>
|
|
386
|
+
* @example
|
|
387
|
+
* // Every day
|
|
388
|
+
* { type: "daily", id: "standup" }
|
|
389
|
+
*
|
|
390
|
+
* // Every 3 days, anchored to a start date
|
|
391
|
+
* { type: "daily", id: "meds", interval: 3, startDate: "2025-01-01" }
|
|
392
|
+
*/
|
|
393
|
+
interface DailyEvent<TMetadata extends Record<string, unknown> = Record<string, unknown>, TCategory extends string = string> extends BaseEventProperties<TMetadata, TCategory> {
|
|
394
|
+
type: "daily";
|
|
395
|
+
/**
|
|
396
|
+
* Recurrence interval in days (default: 1).
|
|
397
|
+
* @example 3 // every third day
|
|
398
|
+
*/
|
|
399
|
+
interval?: number;
|
|
400
|
+
/**
|
|
401
|
+
* Anchor date for interval phasing and the lower bound (YYYY-MM-DD).
|
|
402
|
+
* With `interval > 1`, occurrences land on `startDate`, `startDate + interval`, …
|
|
403
|
+
* @example "2025-01-06"
|
|
404
|
+
*/
|
|
405
|
+
startDate?: string;
|
|
406
|
+
/**
|
|
407
|
+
* End date for the recurrence (YYYY-MM-DD, inclusive).
|
|
408
|
+
* @example "2025-12-31"
|
|
409
|
+
*/
|
|
410
|
+
endDate?: string;
|
|
411
|
+
/**
|
|
412
|
+
* Specific dates to exclude (YYYY-MM-DD).
|
|
413
|
+
* @example ["2025-12-25"]
|
|
414
|
+
*/
|
|
415
|
+
excludeDates?: string[];
|
|
416
|
+
}
|
|
375
417
|
/**
|
|
376
418
|
* FORMULA - Custom formula-based events
|
|
377
419
|
* @template TMetadata - Custom metadata type extending Record<string, unknown>
|
|
@@ -434,11 +476,13 @@ interface NthWeekdayEvent<TMetadata extends Record<string, unknown> = Record<str
|
|
|
434
476
|
* - `1`–`4`: 1st through 4th occurrence
|
|
435
477
|
* - `-1`: last occurrence
|
|
436
478
|
*
|
|
437
|
-
* Required in simple mode
|
|
479
|
+
* Required in simple mode. Omit for anchored mode.
|
|
438
480
|
*/
|
|
439
481
|
nth?: 1 | 2 | 3 | 4 | -1;
|
|
440
482
|
/**
|
|
441
|
-
* Month (1-12).
|
|
483
|
+
* Month (1-12). In simple mode, **omit to repeat every month** (e.g. the first
|
|
484
|
+
* Monday of every month); set it to pin one month (e.g. the 4th Thursday of
|
|
485
|
+
* November). Ignored in anchored mode.
|
|
442
486
|
*/
|
|
443
487
|
month?: number;
|
|
444
488
|
/**
|
|
@@ -488,7 +532,7 @@ interface RelativeEvent<TMetadata extends Record<string, unknown> = Record<strin
|
|
|
488
532
|
weeks?: number;
|
|
489
533
|
};
|
|
490
534
|
}
|
|
491
|
-
type CoreEventConfig<TMetadata extends Record<string, unknown> = Record<string, unknown>, TCategory extends string = string> = ConstEvent<TMetadata, TCategory> | FixedEvent<TMetadata, TCategory> | MonthlyEvent<TMetadata, TCategory> | WeeklyEvent<TMetadata, TCategory> | NthWeekdayEvent<TMetadata, TCategory> | FormulaEvent<TMetadata, TCategory> | RelativeEvent<TMetadata, TCategory>;
|
|
535
|
+
type CoreEventConfig<TMetadata extends Record<string, unknown> = Record<string, unknown>, TCategory extends string = string> = ConstEvent<TMetadata, TCategory> | FixedEvent<TMetadata, TCategory> | MonthlyEvent<TMetadata, TCategory> | WeeklyEvent<TMetadata, TCategory> | DailyEvent<TMetadata, TCategory> | NthWeekdayEvent<TMetadata, TCategory> | FormulaEvent<TMetadata, TCategory> | RelativeEvent<TMetadata, TCategory>;
|
|
492
536
|
/**
|
|
493
537
|
* Generic event config - extended by plugins.
|
|
494
538
|
* Use the generic parameter to enforce metadata types.
|
|
@@ -513,7 +557,7 @@ type EventConfig<TMetadata extends Record<string, unknown> = Record<string, unkn
|
|
|
513
557
|
/**
|
|
514
558
|
* Event type identifiers
|
|
515
559
|
*/
|
|
516
|
-
type CoreEventType = "const" | "fixed" | "monthly" | "weekly" | "nth-weekday" | "formula" | "relative";
|
|
560
|
+
type CoreEventType = "const" | "fixed" | "monthly" | "weekly" | "daily" | "nth-weekday" | "formula" | "relative";
|
|
517
561
|
/**
|
|
518
562
|
* Custom event configuration for overriding event properties.
|
|
519
563
|
* Used by generator packages to allow customization of generated events.
|
|
@@ -587,4 +631,4 @@ type CustomEventConfig<TMetadata extends Record<string, unknown> = Record<string
|
|
|
587
631
|
*/
|
|
588
632
|
type CustomEventResolver<TKey extends string, TMetadata extends Record<string, unknown> = Record<string, unknown>, TCategory extends string = string, TExclude extends keyof BaseEventProperties = never> = (key: TKey) => CustomEventConfig<TMetadata, TCategory, TExclude> | undefined;
|
|
589
633
|
|
|
590
|
-
export type { BaseEventProperties as B, ConflictResolver as C, DateString as D, EventConfig as E, FixedEvent as F, MonthlyEvent as M, NthWeekdayEvent as N, OverrideDatesMap as O, RelativeEvent as R, WeekdayIndex as W, ConflictAction as a, ConflictMap as b, ConflictResolverFn as c, ConstEvent as d, CoreEventConfig as e, CoreEventType as f, CustomEventConfig as g, CustomEventResolver as h,
|
|
634
|
+
export type { BaseEventProperties as B, ConflictResolver as C, DateString as D, EventConfig as E, FixedEvent as F, MonthlyEvent as M, NthWeekdayEvent as N, OverrideDatesMap as O, RelativeEvent as R, WeekdayIndex as W, ConflictAction as a, ConflictMap as b, ConflictResolverFn as c, ConstEvent as d, CoreEventConfig as e, CoreEventType as f, CustomEventConfig as g, CustomEventResolver as h, DailyEvent as i, DateAnchor as j, EventException as k, EventExceptions as l, FormulaEvent as m, Reminder as n, WeeklyEvent as o };
|