calendaryjs 0.2.3 → 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 +36 -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
|
@@ -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 };
|
package/dist/index.cjs
CHANGED
|
@@ -86,6 +86,14 @@ function getYearsInRange(from, to) {
|
|
|
86
86
|
function createDate(year, month, day) {
|
|
87
87
|
return new Date(year, month - 1, day);
|
|
88
88
|
}
|
|
89
|
+
function getDaysInMonth(year, month) {
|
|
90
|
+
return new Date(year, month, 0).getDate();
|
|
91
|
+
}
|
|
92
|
+
function resolveDayOfMonth(day, year, month) {
|
|
93
|
+
if (day >= 0) return day;
|
|
94
|
+
const resolved = getDaysInMonth(year, month) + day + 1;
|
|
95
|
+
return resolved >= 1 ? resolved : null;
|
|
96
|
+
}
|
|
89
97
|
function addDays(date, days) {
|
|
90
98
|
const result = new Date(date);
|
|
91
99
|
result.setDate(result.getDate() + days);
|
|
@@ -127,7 +135,7 @@ var constEventHandler = {
|
|
|
127
135
|
validate(event) {
|
|
128
136
|
if (typeof event !== "object" || event === null) return false;
|
|
129
137
|
const e = event;
|
|
130
|
-
return e.type === "const" && typeof e.month === "number" && e.month >= 1 && e.month <= 12 && typeof e.day === "number" && e.day >=
|
|
138
|
+
return e.type === "const" && typeof e.month === "number" && e.month >= 1 && e.month <= 12 && typeof e.day === "number" && e.day >= -31 && e.day <= 31 && e.day !== 0 && typeof e.title === "string" && typeof e.id === "string";
|
|
131
139
|
},
|
|
132
140
|
generate(event, year) {
|
|
133
141
|
if (event.startYear !== void 0 && year < event.startYear) {
|
|
@@ -139,7 +147,9 @@ var constEventHandler = {
|
|
|
139
147
|
if (event.excludeYears?.includes(year)) {
|
|
140
148
|
return [];
|
|
141
149
|
}
|
|
142
|
-
|
|
150
|
+
const day = resolveDayOfMonth(event.day, year, event.month);
|
|
151
|
+
if (day === null) return [];
|
|
152
|
+
return [createDate(year, event.month, day)];
|
|
143
153
|
}
|
|
144
154
|
};
|
|
145
155
|
|
|
@@ -159,14 +169,11 @@ var fixedEventHandler = {
|
|
|
159
169
|
};
|
|
160
170
|
|
|
161
171
|
// src/generators/monthly.ts
|
|
162
|
-
function getDaysInMonth(year, month) {
|
|
163
|
-
return new Date(year, month, 0).getDate();
|
|
164
|
-
}
|
|
165
172
|
var monthlyEventHandler = {
|
|
166
173
|
validate(event) {
|
|
167
174
|
if (typeof event !== "object" || event === null) return false;
|
|
168
175
|
const e = event;
|
|
169
|
-
return e.type === "monthly" && typeof e.day === "number" && e.day >=
|
|
176
|
+
return e.type === "monthly" && typeof e.day === "number" && e.day >= -31 && e.day <= 31 && e.day !== 0 && typeof e.title === "string" && typeof e.id === "string";
|
|
170
177
|
},
|
|
171
178
|
generate(event, year) {
|
|
172
179
|
const dates = [];
|
|
@@ -184,10 +191,11 @@ var monthlyEventHandler = {
|
|
|
184
191
|
continue;
|
|
185
192
|
}
|
|
186
193
|
const daysInMonth = getDaysInMonth(year, month);
|
|
187
|
-
|
|
194
|
+
const day = resolveDayOfMonth(event.day, year, month);
|
|
195
|
+
if (day === null || day > daysInMonth) {
|
|
188
196
|
continue;
|
|
189
197
|
}
|
|
190
|
-
const date = createDate(year, month,
|
|
198
|
+
const date = createDate(year, month, day);
|
|
191
199
|
const dateStr = formatDate(date);
|
|
192
200
|
if (event.excludeDates?.includes(dateStr)) {
|
|
193
201
|
continue;
|
|
@@ -265,6 +273,49 @@ var weeklyEventHandler = {
|
|
|
265
273
|
}
|
|
266
274
|
};
|
|
267
275
|
|
|
276
|
+
// src/generators/daily.ts
|
|
277
|
+
var PHASE_EPOCH = createDate(1970, 1, 1);
|
|
278
|
+
var dailyEventHandler = {
|
|
279
|
+
validate(event) {
|
|
280
|
+
if (typeof event !== "object" || event === null) return false;
|
|
281
|
+
const e = event;
|
|
282
|
+
if (e.type !== "daily") return false;
|
|
283
|
+
if (typeof e.title !== "string" || typeof e.id !== "string") return false;
|
|
284
|
+
if (e.interval !== void 0 && (typeof e.interval !== "number" || e.interval < 1))
|
|
285
|
+
return false;
|
|
286
|
+
return true;
|
|
287
|
+
},
|
|
288
|
+
generate(event, year) {
|
|
289
|
+
const interval = event.interval ?? 1;
|
|
290
|
+
const yearEnd = createDate(year, 12, 31);
|
|
291
|
+
const startLimit = event.startDate ? parseDate(event.startDate) : null;
|
|
292
|
+
const endLimit = event.endDate ? parseDate(event.endDate) : null;
|
|
293
|
+
const anchor = startLimit ?? PHASE_EPOCH;
|
|
294
|
+
const dates = [];
|
|
295
|
+
let current = createDate(year, 1, 1);
|
|
296
|
+
while (current <= yearEnd) {
|
|
297
|
+
if (startLimit && current < startLimit) {
|
|
298
|
+
current = addDays(current, 1);
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (endLimit && current > endLimit) break;
|
|
302
|
+
if (interval > 1) {
|
|
303
|
+
const offset = daysBetween(anchor, current);
|
|
304
|
+
if (offset % interval !== 0) {
|
|
305
|
+
current = addDays(current, 1);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const dateStr = formatDate(current);
|
|
310
|
+
if (!event.excludeDates?.includes(dateStr)) {
|
|
311
|
+
dates.push(new Date(current));
|
|
312
|
+
}
|
|
313
|
+
current = addDays(current, 1);
|
|
314
|
+
}
|
|
315
|
+
return dates;
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
|
|
268
319
|
// src/generators/nth-weekday.ts
|
|
269
320
|
function nthWeekdayInMonth(year, month, dayOfWeek, nth) {
|
|
270
321
|
if (nth === -1) {
|
|
@@ -307,7 +358,7 @@ var nthWeekdayEventHandler = {
|
|
|
307
358
|
const hasAnchored = e.after !== void 0;
|
|
308
359
|
if (hasSimple && !hasAnchored) {
|
|
309
360
|
if (typeof e.nth !== "number" || ![1, 2, 3, 4, -1].includes(e.nth)) return false;
|
|
310
|
-
if (typeof e.month !== "number" || e.month < 1 || e.month > 12)
|
|
361
|
+
if (e.month !== void 0 && (typeof e.month !== "number" || e.month < 1 || e.month > 12))
|
|
311
362
|
return false;
|
|
312
363
|
} else if (!hasAnchored) {
|
|
313
364
|
return false;
|
|
@@ -331,9 +382,17 @@ var nthWeekdayEventHandler = {
|
|
|
331
382
|
}
|
|
332
383
|
return candidate ? [candidate] : [];
|
|
333
384
|
}
|
|
334
|
-
if (event.nth !== void 0
|
|
335
|
-
|
|
336
|
-
|
|
385
|
+
if (event.nth !== void 0) {
|
|
386
|
+
if (event.month !== void 0) {
|
|
387
|
+
const date = nthWeekdayInMonth(year, event.month, event.dayOfWeek, event.nth);
|
|
388
|
+
return date ? [date] : [];
|
|
389
|
+
}
|
|
390
|
+
const dates = [];
|
|
391
|
+
for (let month = 1; month <= 12; month++) {
|
|
392
|
+
const date = nthWeekdayInMonth(year, month, event.dayOfWeek, event.nth);
|
|
393
|
+
if (date) dates.push(date);
|
|
394
|
+
}
|
|
395
|
+
return dates;
|
|
337
396
|
}
|
|
338
397
|
return [];
|
|
339
398
|
}
|
|
@@ -650,6 +709,27 @@ var SearchBuilder = class {
|
|
|
650
709
|
this.options.hasAllCategories = categories;
|
|
651
710
|
return this;
|
|
652
711
|
}
|
|
712
|
+
/**
|
|
713
|
+
* Filter by event type(s) — match any (e.g. `"weekly"`, `"daily"`, a plugin type).
|
|
714
|
+
*/
|
|
715
|
+
type(...types) {
|
|
716
|
+
this.options.types = types;
|
|
717
|
+
return this;
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Filter by status — match any (e.g. hide cancelled by listing the ones you want).
|
|
721
|
+
*/
|
|
722
|
+
status(...status) {
|
|
723
|
+
this.options.status = status;
|
|
724
|
+
return this;
|
|
725
|
+
}
|
|
726
|
+
/**
|
|
727
|
+
* Filter by source — match any (the plugin / feed / subscription that produced it).
|
|
728
|
+
*/
|
|
729
|
+
source(...source) {
|
|
730
|
+
this.options.source = source;
|
|
731
|
+
return this;
|
|
732
|
+
}
|
|
653
733
|
/**
|
|
654
734
|
* Search by metadata key-value pairs.
|
|
655
735
|
* Supports nested objects and case-insensitive string matching.
|
|
@@ -897,6 +977,15 @@ function executeSearch(events, options) {
|
|
|
897
977
|
return options.hasAllCategories.every((cat) => e.categories.includes(cat));
|
|
898
978
|
});
|
|
899
979
|
}
|
|
980
|
+
if (options.types && options.types.length > 0) {
|
|
981
|
+
results = results.filter((e) => options.types.includes(e.type));
|
|
982
|
+
}
|
|
983
|
+
if (options.status && options.status.length > 0) {
|
|
984
|
+
results = results.filter((e) => e.status !== void 0 && options.status.includes(e.status));
|
|
985
|
+
}
|
|
986
|
+
if (options.source && options.source.length > 0) {
|
|
987
|
+
results = results.filter((e) => e.source !== void 0 && options.source.includes(e.source));
|
|
988
|
+
}
|
|
900
989
|
if (options.metadata) {
|
|
901
990
|
results = results.filter((e) => matchesMetadata(e.metadata, options.metadata));
|
|
902
991
|
}
|
|
@@ -990,6 +1079,7 @@ var CalendaryInstance = class _CalendaryInstance {
|
|
|
990
1079
|
this.eventTypeHandlers.set("fixed", fixedEventHandler);
|
|
991
1080
|
this.eventTypeHandlers.set("monthly", monthlyEventHandler);
|
|
992
1081
|
this.eventTypeHandlers.set("weekly", weeklyEventHandler);
|
|
1082
|
+
this.eventTypeHandlers.set("daily", dailyEventHandler);
|
|
993
1083
|
this.eventTypeHandlers.set("nth-weekday", nthWeekdayEventHandler);
|
|
994
1084
|
this.eventTypeHandlers.set(
|
|
995
1085
|
"formula",
|
|
@@ -1086,6 +1176,27 @@ var CalendaryInstance = class _CalendaryInstance {
|
|
|
1086
1176
|
events: c.events
|
|
1087
1177
|
});
|
|
1088
1178
|
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Export events as a portable {@link Collection} — the inverse of {@link load}.
|
|
1181
|
+
* Serializes the plain event configs plus a manifest of the plugins their event
|
|
1182
|
+
* types need, so the result round-trips back through `load()`. Pass it to
|
|
1183
|
+
* `JSON.stringify` for a `.cdy` document.
|
|
1184
|
+
*
|
|
1185
|
+
* @param options.group - export a single group; omit to export every group's events.
|
|
1186
|
+
* @param options.name - the collection name (also the default group id on re-load).
|
|
1187
|
+
* @param options.version - an informational version stamp.
|
|
1188
|
+
*/
|
|
1189
|
+
toCollection(options = {}) {
|
|
1190
|
+
const groups = options.group !== void 0 ? [this.groups.get(options.group)].filter((g) => g != null) : [...this.groups.values()];
|
|
1191
|
+
const events = groups.flatMap((g) => g.events);
|
|
1192
|
+
const usedTypes = new Set(events.map((e) => e.type));
|
|
1193
|
+
const plugins = [...this.plugins.values()].filter((p) => Object.keys(p.eventTypes ?? {}).some((t) => usedTypes.has(t))).map((p) => p.name);
|
|
1194
|
+
const out = { events };
|
|
1195
|
+
if (options.name) out.collection = options.name;
|
|
1196
|
+
if (options.version) out.version = options.version;
|
|
1197
|
+
if (plugins.length) out.plugins = plugins;
|
|
1198
|
+
return out;
|
|
1199
|
+
}
|
|
1089
1200
|
removeGroup(groupId) {
|
|
1090
1201
|
this.groups.delete(groupId);
|
|
1091
1202
|
this.dirty = true;
|
|
@@ -1106,12 +1217,18 @@ var CalendaryInstance = class _CalendaryInstance {
|
|
|
1106
1217
|
return this;
|
|
1107
1218
|
}
|
|
1108
1219
|
generateEvents(from, to) {
|
|
1220
|
+
if (this.dirty) {
|
|
1221
|
+
this.cache.invalidate();
|
|
1222
|
+
this.dirty = false;
|
|
1223
|
+
}
|
|
1109
1224
|
const cacheKey = `${from}:${to}`;
|
|
1110
|
-
if (
|
|
1225
|
+
if (this.cache.has(cacheKey)) {
|
|
1111
1226
|
return this.cache.get(cacheKey);
|
|
1112
1227
|
}
|
|
1113
1228
|
const events = [];
|
|
1114
|
-
const
|
|
1229
|
+
const inRange = getYearsInRange(from, to);
|
|
1230
|
+
const years = inRange.length ? [inRange[0] - 1, ...inRange, inRange[inRange.length - 1] + 1] : inRange;
|
|
1231
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1115
1232
|
for (const group of this.groups.values()) {
|
|
1116
1233
|
if (!group.enabled) continue;
|
|
1117
1234
|
for (const eventConfig of group.events) {
|
|
@@ -1124,6 +1241,10 @@ var CalendaryInstance = class _CalendaryInstance {
|
|
|
1124
1241
|
let dateStr = formatDate(date);
|
|
1125
1242
|
if (directives.startDate && dateStr < directives.startDate) continue;
|
|
1126
1243
|
if (directives.endDate && dateStr > directives.endDate) continue;
|
|
1244
|
+
const occYear = +dateStr.slice(0, 4);
|
|
1245
|
+
if (directives.startYear !== void 0 && occYear < directives.startYear) continue;
|
|
1246
|
+
if (directives.endYear !== void 0 && occYear > directives.endYear) continue;
|
|
1247
|
+
if (directives.excludeYears?.includes(occYear)) continue;
|
|
1127
1248
|
const exception = directives.exceptions?.[dateStr];
|
|
1128
1249
|
if (exception && "skip" in exception) {
|
|
1129
1250
|
continue;
|
|
@@ -1143,6 +1264,13 @@ var CalendaryInstance = class _CalendaryInstance {
|
|
|
1143
1264
|
}
|
|
1144
1265
|
}
|
|
1145
1266
|
if (!isDateInRange(dateStr, from, to)) continue;
|
|
1267
|
+
const dedupeKey = JSON.stringify([
|
|
1268
|
+
group.id,
|
|
1269
|
+
eventConfig.id,
|
|
1270
|
+
dateStr
|
|
1271
|
+
]);
|
|
1272
|
+
if (seen.has(dedupeKey)) continue;
|
|
1273
|
+
seen.add(dedupeKey);
|
|
1146
1274
|
const calendarEvent = this.createCalendarEvent(
|
|
1147
1275
|
eventConfig,
|
|
1148
1276
|
group,
|
|
@@ -1161,13 +1289,13 @@ var CalendaryInstance = class _CalendaryInstance {
|
|
|
1161
1289
|
});
|
|
1162
1290
|
this.cache.set(cacheKey, events);
|
|
1163
1291
|
this.index.index(events);
|
|
1164
|
-
this.dirty = false;
|
|
1165
1292
|
return events;
|
|
1166
1293
|
}
|
|
1167
1294
|
createCalendarEvent(config, group, dateStr, override) {
|
|
1168
1295
|
const base = config;
|
|
1169
1296
|
const event = {
|
|
1170
1297
|
id: generateEventId(base.id, dateStr),
|
|
1298
|
+
type: base.type,
|
|
1171
1299
|
sourceEventId: base.id,
|
|
1172
1300
|
title: base.title,
|
|
1173
1301
|
date: dateStr,
|
|
@@ -1223,13 +1351,16 @@ var CalendaryInstance = class _CalendaryInstance {
|
|
|
1223
1351
|
* Get calendar days for a date range
|
|
1224
1352
|
*/
|
|
1225
1353
|
getDays(options) {
|
|
1226
|
-
const { groups } = options;
|
|
1354
|
+
const { groups, types } = options;
|
|
1227
1355
|
const fromStr = normalizeDateInput(options.from);
|
|
1228
1356
|
const toStr = normalizeDateInput(options.to);
|
|
1229
1357
|
let events = this.generateEvents(fromStr, toStr);
|
|
1230
1358
|
if (groups && groups.length > 0) {
|
|
1231
1359
|
events = events.filter((e) => groups.includes(e.groupId));
|
|
1232
1360
|
}
|
|
1361
|
+
if (types && types.length > 0) {
|
|
1362
|
+
events = events.filter((e) => types.includes(e.type));
|
|
1363
|
+
}
|
|
1233
1364
|
const eventsByDate = /* @__PURE__ */ new Map();
|
|
1234
1365
|
for (const event of events) {
|
|
1235
1366
|
const existing = eventsByDate.get(event.date) || [];
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as EventConfig, B as BaseEventProperties, D as DateString, C as ConflictResolver, a as ConflictAction } from './events-
|
|
2
|
-
export { b as ConflictMap, c as ConflictResolverFn, d as ConstEvent, e as CoreEventConfig, f as CoreEventType, g as CustomEventConfig, h as CustomEventResolver, i as DateAnchor, F as FixedEvent,
|
|
1
|
+
import { E as EventConfig, B as BaseEventProperties, D as DateString, C as ConflictResolver, a as ConflictAction } from './events-DSiv9j6V.cjs';
|
|
2
|
+
export { b as ConflictMap, c as ConflictResolverFn, d as ConstEvent, e as CoreEventConfig, f as CoreEventType, g as CustomEventConfig, h as CustomEventResolver, i as DailyEvent, j as DateAnchor, k as EventException, l as EventExceptions, F as FixedEvent, m as FormulaEvent, M as MonthlyEvent, N as NthWeekdayEvent, O as OverrideDatesMap, R as RelativeEvent, n as Reminder, W as WeekdayIndex, o as WeeklyEvent } from './events-DSiv9j6V.cjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Group configuration
|
|
@@ -71,6 +71,11 @@ interface Group extends GroupConfig {
|
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
73
|
interface CalendarEvent<TMetadata extends Record<string, unknown> = Record<string, unknown>, TCategory extends string = string> extends BaseEventProperties<TMetadata, TCategory> {
|
|
74
|
+
/**
|
|
75
|
+
* The originating event-config `type` (e.g. `"const"`, `"weekly"`, `"daily"`,
|
|
76
|
+
* or a plugin type). Lets a consumer group or filter occurrences by kind.
|
|
77
|
+
*/
|
|
78
|
+
type: string;
|
|
74
79
|
/** Original event ID from the event config */
|
|
75
80
|
sourceEventId: string;
|
|
76
81
|
/** Date in YYYY-MM-DD format */
|
|
@@ -269,6 +274,9 @@ interface SearchOptions {
|
|
|
269
274
|
keywordsContain?: string[];
|
|
270
275
|
categories?: string[];
|
|
271
276
|
hasAllCategories?: string[];
|
|
277
|
+
types?: string[];
|
|
278
|
+
status?: ("confirmed" | "tentative" | "cancelled")[];
|
|
279
|
+
source?: string[];
|
|
272
280
|
metadata?: MetadataQuery;
|
|
273
281
|
minPriority?: number;
|
|
274
282
|
maxPriority?: number;
|
|
@@ -368,6 +376,18 @@ declare class SearchBuilder<TMetadata extends Record<string, unknown> = Record<s
|
|
|
368
376
|
* Filter by categories (must have all)
|
|
369
377
|
*/
|
|
370
378
|
hasAllCategories(categories: string[]): this;
|
|
379
|
+
/**
|
|
380
|
+
* Filter by event type(s) — match any (e.g. `"weekly"`, `"daily"`, a plugin type).
|
|
381
|
+
*/
|
|
382
|
+
type(...types: string[]): this;
|
|
383
|
+
/**
|
|
384
|
+
* Filter by status — match any (e.g. hide cancelled by listing the ones you want).
|
|
385
|
+
*/
|
|
386
|
+
status(...status: ("confirmed" | "tentative" | "cancelled")[]): this;
|
|
387
|
+
/**
|
|
388
|
+
* Filter by source — match any (the plugin / feed / subscription that produced it).
|
|
389
|
+
*/
|
|
390
|
+
source(...source: string[]): this;
|
|
371
391
|
/**
|
|
372
392
|
* Search by metadata key-value pairs.
|
|
373
393
|
* Supports nested objects and case-insensitive string matching.
|
|
@@ -512,6 +532,21 @@ declare class CalendaryInstance<TMetadata extends Record<string, unknown> = Reco
|
|
|
512
532
|
* Nothing is fetched or executed behind your back.
|
|
513
533
|
*/
|
|
514
534
|
load(collection: Collection | string): this;
|
|
535
|
+
/**
|
|
536
|
+
* Export events as a portable {@link Collection} — the inverse of {@link load}.
|
|
537
|
+
* Serializes the plain event configs plus a manifest of the plugins their event
|
|
538
|
+
* types need, so the result round-trips back through `load()`. Pass it to
|
|
539
|
+
* `JSON.stringify` for a `.cdy` document.
|
|
540
|
+
*
|
|
541
|
+
* @param options.group - export a single group; omit to export every group's events.
|
|
542
|
+
* @param options.name - the collection name (also the default group id on re-load).
|
|
543
|
+
* @param options.version - an informational version stamp.
|
|
544
|
+
*/
|
|
545
|
+
toCollection(options?: {
|
|
546
|
+
name?: string;
|
|
547
|
+
version?: string;
|
|
548
|
+
group?: string;
|
|
549
|
+
}): Collection;
|
|
515
550
|
removeGroup(groupId: string): this;
|
|
516
551
|
getGroup(groupId: string): Group | undefined;
|
|
517
552
|
getGroups(): Group[];
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as EventConfig, B as BaseEventProperties, D as DateString, C as ConflictResolver, a as ConflictAction } from './events-
|
|
2
|
-
export { b as ConflictMap, c as ConflictResolverFn, d as ConstEvent, e as CoreEventConfig, f as CoreEventType, g as CustomEventConfig, h as CustomEventResolver, i as DateAnchor, F as FixedEvent,
|
|
1
|
+
import { E as EventConfig, B as BaseEventProperties, D as DateString, C as ConflictResolver, a as ConflictAction } from './events-DSiv9j6V.js';
|
|
2
|
+
export { b as ConflictMap, c as ConflictResolverFn, d as ConstEvent, e as CoreEventConfig, f as CoreEventType, g as CustomEventConfig, h as CustomEventResolver, i as DailyEvent, j as DateAnchor, k as EventException, l as EventExceptions, F as FixedEvent, m as FormulaEvent, M as MonthlyEvent, N as NthWeekdayEvent, O as OverrideDatesMap, R as RelativeEvent, n as Reminder, W as WeekdayIndex, o as WeeklyEvent } from './events-DSiv9j6V.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Group configuration
|
|
@@ -71,6 +71,11 @@ interface Group extends GroupConfig {
|
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
73
|
interface CalendarEvent<TMetadata extends Record<string, unknown> = Record<string, unknown>, TCategory extends string = string> extends BaseEventProperties<TMetadata, TCategory> {
|
|
74
|
+
/**
|
|
75
|
+
* The originating event-config `type` (e.g. `"const"`, `"weekly"`, `"daily"`,
|
|
76
|
+
* or a plugin type). Lets a consumer group or filter occurrences by kind.
|
|
77
|
+
*/
|
|
78
|
+
type: string;
|
|
74
79
|
/** Original event ID from the event config */
|
|
75
80
|
sourceEventId: string;
|
|
76
81
|
/** Date in YYYY-MM-DD format */
|
|
@@ -269,6 +274,9 @@ interface SearchOptions {
|
|
|
269
274
|
keywordsContain?: string[];
|
|
270
275
|
categories?: string[];
|
|
271
276
|
hasAllCategories?: string[];
|
|
277
|
+
types?: string[];
|
|
278
|
+
status?: ("confirmed" | "tentative" | "cancelled")[];
|
|
279
|
+
source?: string[];
|
|
272
280
|
metadata?: MetadataQuery;
|
|
273
281
|
minPriority?: number;
|
|
274
282
|
maxPriority?: number;
|
|
@@ -368,6 +376,18 @@ declare class SearchBuilder<TMetadata extends Record<string, unknown> = Record<s
|
|
|
368
376
|
* Filter by categories (must have all)
|
|
369
377
|
*/
|
|
370
378
|
hasAllCategories(categories: string[]): this;
|
|
379
|
+
/**
|
|
380
|
+
* Filter by event type(s) — match any (e.g. `"weekly"`, `"daily"`, a plugin type).
|
|
381
|
+
*/
|
|
382
|
+
type(...types: string[]): this;
|
|
383
|
+
/**
|
|
384
|
+
* Filter by status — match any (e.g. hide cancelled by listing the ones you want).
|
|
385
|
+
*/
|
|
386
|
+
status(...status: ("confirmed" | "tentative" | "cancelled")[]): this;
|
|
387
|
+
/**
|
|
388
|
+
* Filter by source — match any (the plugin / feed / subscription that produced it).
|
|
389
|
+
*/
|
|
390
|
+
source(...source: string[]): this;
|
|
371
391
|
/**
|
|
372
392
|
* Search by metadata key-value pairs.
|
|
373
393
|
* Supports nested objects and case-insensitive string matching.
|
|
@@ -512,6 +532,21 @@ declare class CalendaryInstance<TMetadata extends Record<string, unknown> = Reco
|
|
|
512
532
|
* Nothing is fetched or executed behind your back.
|
|
513
533
|
*/
|
|
514
534
|
load(collection: Collection | string): this;
|
|
535
|
+
/**
|
|
536
|
+
* Export events as a portable {@link Collection} — the inverse of {@link load}.
|
|
537
|
+
* Serializes the plain event configs plus a manifest of the plugins their event
|
|
538
|
+
* types need, so the result round-trips back through `load()`. Pass it to
|
|
539
|
+
* `JSON.stringify` for a `.cdy` document.
|
|
540
|
+
*
|
|
541
|
+
* @param options.group - export a single group; omit to export every group's events.
|
|
542
|
+
* @param options.name - the collection name (also the default group id on re-load).
|
|
543
|
+
* @param options.version - an informational version stamp.
|
|
544
|
+
*/
|
|
545
|
+
toCollection(options?: {
|
|
546
|
+
name?: string;
|
|
547
|
+
version?: string;
|
|
548
|
+
group?: string;
|
|
549
|
+
}): Collection;
|
|
515
550
|
removeGroup(groupId: string): this;
|
|
516
551
|
getGroup(groupId: string): Group | undefined;
|
|
517
552
|
getGroups(): Group[];
|