@craftguild/jscalendar 0.5.2 → 0.5.4

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.
Files changed (124) hide show
  1. package/README.md +130 -94
  2. package/dist/index.cjs +3923 -0
  3. package/dist/index.d.cts +802 -0
  4. package/dist/index.d.mts +802 -0
  5. package/dist/index.mjs +3927 -0
  6. package/package.json +46 -31
  7. package/dist/__tests__/builders.test.d.ts +0 -1
  8. package/dist/__tests__/builders.test.js +0 -101
  9. package/dist/__tests__/calendar-extra.test.d.ts +0 -1
  10. package/dist/__tests__/calendar-extra.test.js +0 -221
  11. package/dist/__tests__/calendar.test.d.ts +0 -1
  12. package/dist/__tests__/calendar.test.js +0 -97
  13. package/dist/__tests__/ical-extra.test.d.ts +0 -1
  14. package/dist/__tests__/ical-extra.test.js +0 -87
  15. package/dist/__tests__/ical.test.d.ts +0 -1
  16. package/dist/__tests__/ical.test.js +0 -72
  17. package/dist/__tests__/index.test.d.ts +0 -1
  18. package/dist/__tests__/index.test.js +0 -9
  19. package/dist/__tests__/patch.test.d.ts +0 -1
  20. package/dist/__tests__/patch.test.js +0 -47
  21. package/dist/__tests__/recurrence.test.d.ts +0 -1
  22. package/dist/__tests__/recurrence.test.js +0 -640
  23. package/dist/__tests__/search.test.d.ts +0 -1
  24. package/dist/__tests__/search.test.js +0 -264
  25. package/dist/__tests__/timezones.test.d.ts +0 -1
  26. package/dist/__tests__/timezones.test.js +0 -12
  27. package/dist/__tests__/utils.test.d.ts +0 -1
  28. package/dist/__tests__/utils.test.js +0 -127
  29. package/dist/__tests__/validation.test.d.ts +0 -1
  30. package/dist/__tests__/validation.test.js +0 -224
  31. package/dist/ical.d.ts +0 -13
  32. package/dist/ical.js +0 -270
  33. package/dist/index.d.ts +0 -3
  34. package/dist/index.js +0 -2
  35. package/dist/jscal/base.d.ts +0 -89
  36. package/dist/jscal/base.js +0 -173
  37. package/dist/jscal/builders.d.ts +0 -183
  38. package/dist/jscal/builders.js +0 -287
  39. package/dist/jscal/constants.d.ts +0 -11
  40. package/dist/jscal/constants.js +0 -11
  41. package/dist/jscal/datetime.d.ts +0 -14
  42. package/dist/jscal/datetime.js +0 -42
  43. package/dist/jscal/defaults.d.ts +0 -31
  44. package/dist/jscal/defaults.js +0 -102
  45. package/dist/jscal/duration.d.ts +0 -43
  46. package/dist/jscal/duration.js +0 -75
  47. package/dist/jscal/event.d.ts +0 -23
  48. package/dist/jscal/event.js +0 -78
  49. package/dist/jscal/group.d.ts +0 -31
  50. package/dist/jscal/group.js +0 -69
  51. package/dist/jscal/guards.d.ts +0 -19
  52. package/dist/jscal/guards.js +0 -25
  53. package/dist/jscal/ids.d.ts +0 -11
  54. package/dist/jscal/ids.js +0 -77
  55. package/dist/jscal/normalize.d.ts +0 -32
  56. package/dist/jscal/normalize.js +0 -45
  57. package/dist/jscal/task.d.ts +0 -23
  58. package/dist/jscal/task.js +0 -67
  59. package/dist/jscal/types.d.ts +0 -38
  60. package/dist/jscal/types.js +0 -1
  61. package/dist/jscal.d.ts +0 -145
  62. package/dist/jscal.js +0 -126
  63. package/dist/patch.d.ts +0 -18
  64. package/dist/patch.js +0 -216
  65. package/dist/recurrence/constants.d.ts +0 -13
  66. package/dist/recurrence/constants.js +0 -13
  67. package/dist/recurrence/date-utils.d.ts +0 -125
  68. package/dist/recurrence/date-utils.js +0 -259
  69. package/dist/recurrence/expand.d.ts +0 -23
  70. package/dist/recurrence/expand.js +0 -315
  71. package/dist/recurrence/rule-candidates.d.ts +0 -21
  72. package/dist/recurrence/rule-candidates.js +0 -120
  73. package/dist/recurrence/rule-generate.d.ts +0 -11
  74. package/dist/recurrence/rule-generate.js +0 -36
  75. package/dist/recurrence/rule-matchers.d.ts +0 -34
  76. package/dist/recurrence/rule-matchers.js +0 -120
  77. package/dist/recurrence/rule-normalize.d.ts +0 -9
  78. package/dist/recurrence/rule-normalize.js +0 -57
  79. package/dist/recurrence/rule-selectors.d.ts +0 -7
  80. package/dist/recurrence/rule-selectors.js +0 -21
  81. package/dist/recurrence/rules.d.ts +0 -14
  82. package/dist/recurrence/rules.js +0 -57
  83. package/dist/recurrence/types.d.ts +0 -27
  84. package/dist/recurrence/types.js +0 -1
  85. package/dist/recurrence.d.ts +0 -2
  86. package/dist/recurrence.js +0 -1
  87. package/dist/search.d.ts +0 -44
  88. package/dist/search.js +0 -292
  89. package/dist/timezones/chunk_1.d.ts +0 -2
  90. package/dist/timezones/chunk_1.js +0 -72
  91. package/dist/timezones/chunk_2.d.ts +0 -2
  92. package/dist/timezones/chunk_2.js +0 -72
  93. package/dist/timezones/chunk_3.d.ts +0 -2
  94. package/dist/timezones/chunk_3.js +0 -72
  95. package/dist/timezones/chunk_4.d.ts +0 -2
  96. package/dist/timezones/chunk_4.js +0 -72
  97. package/dist/timezones/chunk_5.d.ts +0 -2
  98. package/dist/timezones/chunk_5.js +0 -72
  99. package/dist/timezones/chunk_6.d.ts +0 -2
  100. package/dist/timezones/chunk_6.js +0 -72
  101. package/dist/timezones/chunk_7.d.ts +0 -2
  102. package/dist/timezones/chunk_7.js +0 -6
  103. package/dist/timezones.d.ts +0 -9
  104. package/dist/timezones.js +0 -452
  105. package/dist/types.d.ts +0 -246
  106. package/dist/types.js +0 -1
  107. package/dist/utils.d.ts +0 -82
  108. package/dist/utils.js +0 -164
  109. package/dist/validate/asserts.d.ts +0 -155
  110. package/dist/validate/asserts.js +0 -381
  111. package/dist/validate/constants.d.ts +0 -25
  112. package/dist/validate/constants.js +0 -33
  113. package/dist/validate/error.d.ts +0 -19
  114. package/dist/validate/error.js +0 -25
  115. package/dist/validate/validators-common.d.ts +0 -64
  116. package/dist/validate/validators-common.js +0 -390
  117. package/dist/validate/validators-objects.d.ts +0 -8
  118. package/dist/validate/validators-objects.js +0 -70
  119. package/dist/validate/validators-recurrence.d.ts +0 -15
  120. package/dist/validate/validators-recurrence.js +0 -115
  121. package/dist/validate/validators.d.ts +0 -1
  122. package/dist/validate/validators.js +0 -1
  123. package/dist/validate.d.ts +0 -2
  124. package/dist/validate.js +0 -2
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
- <p style="text-align: center;">
2
- <img src="assets/d97d4d10-44f9-4b49-9fc2-5aaf33c667ef.png" alt="JSCalendar logo" style="max-height: 320px; height: auto; width: auto;" />
1
+ <p align="center">
2
+ <img src="assets/d97d4d10-44f9-4b49-9fc2-5aaf33c667ef.png" alt="JSCalendar logo" style="height: 320px; width: auto;" />
3
3
  </p>
4
4
 
5
5
  # RFC 8984 (JSCalendar) TypeScript Library
@@ -34,19 +34,19 @@ import { JsCal } from "@craftguild/jscalendar";
34
34
 
35
35
  // Create a recurring event and a simple task, then expand occurrences.
36
36
  const event = new JsCal.Event({
37
- title: "Weekly Sync",
38
- start: new Date(2026, 0, 1, 0, 0, 0, 0),
39
- recurrenceRules: [
40
- JsCal.RecurrenceRule({
41
- frequency: "weekly",
42
- byDay: [JsCal.ByDay({ day: "th" })],
43
- }),
44
- ],
37
+ title: "Weekly Sync",
38
+ start: new Date(2026, 0, 1, 0, 0, 0, 0),
39
+ recurrenceRules: [
40
+ JsCal.RecurrenceRule({
41
+ frequency: "weekly",
42
+ byDay: [JsCal.ByDay({ day: "th" })],
43
+ }),
44
+ ],
45
45
  });
46
46
 
47
47
  const task = new JsCal.Task({
48
- title: "Prepare Notes",
49
- start: new Date(2026, 0, 1, 0, 0, 0, 0),
48
+ title: "Prepare Notes",
49
+ start: new Date(2026, 0, 1, 0, 0, 0, 0),
50
50
  });
51
51
 
52
52
  const from = new Date(2026, 0, 1, 0, 0, 0, 0);
@@ -54,12 +54,13 @@ const to = new Date(2026, 0, 31, 0, 0, 0, 0);
54
54
  const generator = JsCal.expandRecurrence([event, task], { from, to });
55
55
 
56
56
  for (const item of generator) {
57
- // Expanded JSCalendar objects for events and tasks in the range.
58
- console.log(JSON.stringify(item));
57
+ // Expanded JSCalendar objects for events and tasks in the range.
58
+ console.log(JSON.stringify(item));
59
59
  }
60
60
  ```
61
61
 
62
62
  Sample output (truncated):
63
+
63
64
  ```txt
64
65
  {"title":"Weekly Sync","@type":"Event","start":"2026-01-01T00:00:00",...}
65
66
  {"title":"Prepare Notes","@type":"Task","start":"2026-01-01T00:00:00",...}
@@ -76,10 +77,10 @@ object and normalizes required fields (e.g., `uid`, `updated`).
76
77
 
77
78
  ```ts
78
79
  const event = new JsCal.Event({
79
- title: "Team Sync",
80
- start: "2026-02-10T10:00:00",
81
- timeZone: "America/New_York",
82
- duration: "PT30M",
80
+ title: "Team Sync",
81
+ start: "2026-02-10T10:00:00",
82
+ timeZone: "America/New_York",
83
+ duration: "PT30M",
83
84
  });
84
85
  ```
85
86
 
@@ -87,10 +88,10 @@ const event = new JsCal.Event({
87
88
 
88
89
  ```ts
89
90
  const task = new JsCal.Task({
90
- title: "Write report",
91
- start: "2026-02-11T09:00:00",
92
- due: "2026-02-11T17:00:00",
93
- percentComplete: 10,
91
+ title: "Write report",
92
+ start: "2026-02-11T09:00:00",
93
+ due: "2026-02-11T17:00:00",
94
+ percentComplete: 10,
94
95
  });
95
96
  ```
96
97
 
@@ -101,8 +102,8 @@ or `JsCal.Event`/`JsCal.Task` instances.
101
102
 
102
103
  ```ts
103
104
  const group = new JsCal.Group({
104
- title: "Project A",
105
- entries: [event, task.eject()],
105
+ title: "Project A",
106
+ entries: [event, task.eject()],
106
107
  });
107
108
  ```
108
109
 
@@ -124,18 +125,33 @@ your database), but builders offer a safer, clearer option for app code.
124
125
 
125
126
  ```ts
126
127
  const task = new JsCal.Task({
127
- title: "Write report",
128
- start: "2026-02-11T09:00:00",
129
- participants: JsCal.participants([
130
- { value: JsCal.Participant({ name: "Alice", email: "a@example.com", roles: { attendee: true } }) },
131
- { value: JsCal.Participant({ name: "Bob", roles: { attendee: true } }) },
132
- ]),
133
- locations: JsCal.locations([
134
- { value: JsCal.Location({ name: "Room A" }) },
135
- ]),
136
- alerts: JsCal.alerts([
137
- { value: JsCal.Alert({ trigger: JsCal.OffsetTrigger({ offset: JsCal.duration.minutes(-15) }) }) },
138
- ]),
128
+ title: "Write report",
129
+ start: "2026-02-11T09:00:00",
130
+ participants: JsCal.participants([
131
+ {
132
+ value: JsCal.Participant({
133
+ name: "Alice",
134
+ email: "a@example.com",
135
+ roles: { attendee: true },
136
+ }),
137
+ },
138
+ {
139
+ value: JsCal.Participant({
140
+ name: "Bob",
141
+ roles: { attendee: true },
142
+ }),
143
+ },
144
+ ]),
145
+ locations: JsCal.locations([{ value: JsCal.Location({ name: "Room A" }) }]),
146
+ alerts: JsCal.alerts([
147
+ {
148
+ value: JsCal.Alert({
149
+ trigger: JsCal.OffsetTrigger({
150
+ offset: JsCal.duration.minutes(-15),
151
+ }),
152
+ }),
153
+ },
154
+ ]),
139
155
  });
140
156
  ```
141
157
 
@@ -143,17 +159,25 @@ const task = new JsCal.Task({
143
159
 
144
160
  ```ts
145
161
  const task = new JsCal.Task({
146
- title: "Imported task",
147
- start: "2026-02-11T09:00:00",
148
- participants: {
149
- p1: { "@type": "Participant", name: "Alice", email: "a@example.com", roles: { attendee: true } },
150
- },
151
- locations: {
152
- l1: { "@type": "Location", name: "Room A" },
153
- },
154
- alerts: {
155
- a1: { "@type": "Alert", trigger: { "@type": "OffsetTrigger", offset: "-PT15M" } },
156
- },
162
+ title: "Imported task",
163
+ start: "2026-02-11T09:00:00",
164
+ participants: {
165
+ p1: {
166
+ "@type": "Participant",
167
+ name: "Alice",
168
+ email: "a@example.com",
169
+ roles: { attendee: true },
170
+ },
171
+ },
172
+ locations: {
173
+ l1: { "@type": "Location", name: "Room A" },
174
+ },
175
+ alerts: {
176
+ a1: {
177
+ "@type": "Alert",
178
+ trigger: { "@type": "OffsetTrigger", offset: "-PT15M" },
179
+ },
180
+ },
157
181
  });
158
182
  ```
159
183
 
@@ -177,6 +201,7 @@ clone of that underlying JSCalendar object for serialization, storage,
177
201
  or passing across app boundaries.
178
202
 
179
203
  Why `eject()` exists:
204
+
180
205
  - Class instances are convenient for building and updating objects with
181
206
  helpers like `patch`.
182
207
  - External APIs, storage layers, and JSON stringify expect plain objects.
@@ -184,12 +209,16 @@ Why `eject()` exists:
184
209
  from the original instance (and vice versa).
185
210
 
186
211
  What changes after `eject()`:
212
+
187
213
  - You lose helper methods; the result is just a plain JSCalendar object.
188
214
  - Mutating the plain object does not affect the original instance.
189
215
  - The instance can still be used and updated independently.
190
216
 
191
217
  ```ts
192
- const event = new JsCal.Event({ title: "Kickoff", start: "2026-02-02T10:00:00" });
218
+ const event = new JsCal.Event({
219
+ title: "Kickoff",
220
+ start: "2026-02-02T10:00:00",
221
+ });
193
222
  const plain = event.eject();
194
223
 
195
224
  // Plain object is ready for JSON / storage / network.
@@ -216,40 +245,47 @@ You can also patch nested maps by replacing the full map in one call:
216
245
 
217
246
  ```ts
218
247
  const withParticipants = event.patch({
219
- participants: {
220
- p1: { "@type": "Participant", roles: { attendee: true }, email: "a@example.com" },
221
- },
248
+ participants: {
249
+ p1: {
250
+ "@type": "Participant",
251
+ roles: { attendee: true },
252
+ email: "a@example.com",
253
+ },
254
+ },
222
255
  });
223
256
  ```
224
257
 
225
258
  Two common patterns for nested patches:
226
259
 
227
- 1) Set raw values directly
260
+ 1. Set raw values directly
261
+
228
262
  ```ts
229
263
  const withLocations = event.patch({
230
- locations: {
231
- l1: { "@type": "Location", name: "Room A" },
232
- },
264
+ locations: {
265
+ l1: { "@type": "Location", name: "Room A" },
266
+ },
233
267
  });
234
268
  ```
235
269
 
236
- 2) Use helpers to build or merge map values
270
+ 2. Use helpers to build or merge map values
271
+
237
272
  ```ts
238
273
  const withLocations = event.patch({
239
- locations: JsCal.locations([
240
- { id: "l1", value: JsCal.Location({ name: "Room A" }) },
241
- { value: JsCal.Location({ name: "Room B" }) },
242
- ]),
274
+ locations: JsCal.locations([
275
+ { id: "l1", value: JsCal.Location({ name: "Room A" }) },
276
+ { value: JsCal.Location({ name: "Room B" }) },
277
+ ]),
243
278
  });
244
279
  ```
245
280
 
246
281
  To merge into an existing map, pass the current map as the second argument:
282
+
247
283
  ```ts
248
284
  const withLocations = event.patch({
249
- locations: JsCal.locations(
250
- [{ value: JsCal.Location({ name: "Room C" }) }],
251
- event.data.locations,
252
- ),
285
+ locations: JsCal.locations(
286
+ [{ value: JsCal.Location({ name: "Room C" }) }],
287
+ event.data.locations,
288
+ ),
253
289
  });
254
290
  ```
255
291
 
@@ -264,20 +300,20 @@ Date fields accept either RFC 8984 strings or JavaScript `Date`. When a
264
300
 
265
301
  ```ts
266
302
  const eventFromDate = new JsCal.Event({
267
- title: "Kickoff",
268
- start: new Date(),
303
+ title: "Kickoff",
304
+ start: new Date(),
269
305
  });
270
306
 
271
307
  const eventWithSeconds = new JsCal.Event({
272
- title: "Kickoff",
273
- start: new Date(),
274
- duration: 90 * 60, // seconds
308
+ title: "Kickoff",
309
+ start: new Date(),
310
+ duration: 90 * 60, // seconds
275
311
  });
276
312
 
277
313
  const eventWithZone = new JsCal.Event({
278
- title: "Kickoff",
279
- start: new Date(),
280
- timeZone: JsCal.timeZone("asia/tokyo"), // => Asia/Tokyo
314
+ title: "Kickoff",
315
+ start: new Date(),
316
+ timeZone: JsCal.timeZone("asia/tokyo"), // => Asia/Tokyo
281
317
  });
282
318
  ```
283
319
 
@@ -292,8 +328,8 @@ query engine or build a custom index.
292
328
 
293
329
  ```ts
294
330
  const results = JsCal.filterByDateRange(items, {
295
- start: "2026-02-01T00:00:00Z",
296
- end: "2026-02-28T23:59:59Z",
331
+ start: "2026-02-01T00:00:00Z",
332
+ end: "2026-02-28T23:59:59Z",
297
333
  });
298
334
 
299
335
  const found = JsCal.findByUid(items, "uid-123");
@@ -320,11 +356,11 @@ overrides and exclusions. The output instances contain `recurrenceId`
320
356
  and preserve the base object’s data unless a patch modifies fields.
321
357
 
322
358
  ```ts
323
- for (const occ of JsCal.expandRecurrence(
324
- [event],
325
- { from: new Date("2026-02-01"), to: new Date("2026-03-01") }
326
- )) {
327
- console.log(occ);
359
+ for (const occ of JsCal.expandRecurrence([event], {
360
+ from: new Date("2026-02-01"),
361
+ to: new Date("2026-03-01"),
362
+ })) {
363
+ console.log(occ);
328
364
  }
329
365
  ```
330
366
 
@@ -336,15 +372,15 @@ scrolling or an infinite feed.
336
372
 
337
373
  ```ts
338
374
  const page1 = JsCal.expandRecurrencePaged(
339
- [event],
340
- { from: new Date("2026-02-01"), to: new Date("2026-03-01") },
341
- { limit: 50 }
375
+ [event],
376
+ { from: new Date("2026-02-01"), to: new Date("2026-03-01") },
377
+ { limit: 50 },
342
378
  );
343
379
 
344
380
  const page2 = JsCal.expandRecurrencePaged(
345
- [event],
346
- { from: new Date("2026-02-01"), to: new Date("2026-03-01") },
347
- { limit: 50, cursor: page1.nextCursor }
381
+ [event],
382
+ { from: new Date("2026-02-01"), to: new Date("2026-03-01") },
383
+ { limit: 50, cursor: page1.nextCursor },
348
384
  );
349
385
  ```
350
386
 
@@ -360,15 +396,15 @@ compared as simple strings.
360
396
 
361
397
  ```ts
362
398
  const event = new JsCal.Event({
363
- start: "2026-02-01T10:00:00",
364
- timeZone: "Asia/Tokyo",
399
+ start: "2026-02-01T10:00:00",
400
+ timeZone: "Asia/Tokyo",
365
401
  });
366
402
 
367
403
  // 2026-02-01T01:00:00Z is 10:00 in Asia/Tokyo
368
- const results = JsCal.filterByDateRange(
369
- [event],
370
- { start: new Date("2026-02-01T01:00:00Z"), end: new Date("2026-02-01T01:00:00Z") }
371
- );
404
+ const results = JsCal.filterByDateRange([event], {
405
+ start: new Date("2026-02-01T01:00:00Z"),
406
+ end: new Date("2026-02-01T01:00:00Z"),
407
+ });
372
408
  console.log(results.length); // 1
373
409
  ```
374
410
 
@@ -413,9 +449,9 @@ and this library’s behavior.
413
449
  - **Validation**: strict type/format validation is enforced by default (RFC-style date/time and duration rules),
414
450
  but can be disabled with `{ validate: false }` in create/update/patch.
415
451
  - **Time zone and DST**:
416
- - Range filtering and recurrence comparisons use `date-fns-tz`.
417
- - Recurrence generation still operates on LocalDateTime arithmetic and does not fully normalize
418
- DST gaps/overlaps into canonical UTC instants for all cases.
452
+ - Range filtering and recurrence comparisons use `date-fns-tz`.
453
+ - Recurrence generation still operates on LocalDateTime arithmetic and does not fully normalize
454
+ DST gaps/overlaps into canonical UTC instants for all cases.
419
455
  - **iCalendar export**: minimal mapping + `X-JSCALENDAR`; no VTIMEZONE generation.
420
456
 
421
457
  If you require strict, formal compliance, please treat this as a foundation