@craftguild/jscalendar 0.4.0 → 0.5.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/dist/jscal.d.ts CHANGED
@@ -6,9 +6,9 @@ import { TaskObject } from "./jscal/task.js";
6
6
  import { GroupObject } from "./jscal/group.js";
7
7
  import { createId, createUid } from "./jscal/ids.js";
8
8
  import { isEvent, isGroup, isTask } from "./jscal/guards.js";
9
- import { buildAlert, buildAbsoluteTrigger, buildLink, buildLocation, buildNDay, buildOffsetTrigger, buildParticipants, buildRecurrenceRule, buildRelation, buildRelatedTo, buildTimeZone, buildTimeZoneMap, buildTimeZoneRule, buildVirtualLocation, buildVirtualLocations, buildLocations, buildLinks, buildParticipant, buildAlerts } from "./jscal/builders.js";
9
+ import { buildAlert, buildAbsoluteTrigger, buildEventPatch, buildLink, buildLocation, buildNDay, buildOffsetTrigger, buildParticipants, buildRecurrenceRule, buildRelation, buildRelatedTo, buildTimeZone, buildTimeZoneMap, buildTimeZoneRule, buildVirtualLocation, buildVirtualLocations, buildLocations, buildLinks, buildParticipant, buildAlerts, buildTaskPatch, buildGroupPatch } from "./jscal/builders.js";
10
10
  export type { CreateOptions, UpdateOptions } from "./jscal/types.js";
11
- export type { AlertInput, AbsoluteTriggerInput, LinkInput, LocationInput, NDayInput, OffsetTriggerInput, ParticipantInput, RecurrenceRuleInput, RelationInput, TimeZoneInput, TimeZoneRuleInput, VirtualLocationInput, } from "./jscal/builders.js";
11
+ export type { AlertInput, AbsoluteTriggerInput, EventPatchInput, GroupPatchInput, IdValueInput, LinkInput, LocationInput, NDayInput, OffsetTriggerInput, ParticipantInput, RecurrenceRuleInput, RelationInput, TaskPatchInput, TimeZoneInput, TimeZoneRuleInput, VirtualLocationInput, } from "./jscal/builders.js";
12
12
  export { createId, createUid, isEvent, isGroup, isTask };
13
13
  export declare const JsCal: {
14
14
  Event: typeof EventObject;
@@ -16,6 +16,9 @@ export declare const JsCal: {
16
16
  Group: typeof GroupObject;
17
17
  createUid: typeof createUid;
18
18
  createId: typeof createId;
19
+ isEvent: typeof isEvent;
20
+ isGroup: typeof isGroup;
21
+ isTask: typeof isTask;
19
22
  duration: {
20
23
  seconds(value: number): string;
21
24
  minutes(value: number): string;
@@ -43,6 +46,10 @@ export declare const JsCal: {
43
46
  TimeZoneRule: typeof buildTimeZoneRule;
44
47
  RecurrenceRule: typeof buildRecurrenceRule;
45
48
  NDay: typeof buildNDay;
49
+ ByDay: typeof buildNDay;
50
+ EventPatch: typeof buildEventPatch;
51
+ TaskPatch: typeof buildTaskPatch;
52
+ GroupPatch: typeof buildGroupPatch;
46
53
  participants: typeof buildParticipants;
47
54
  locations: typeof buildLocations;
48
55
  virtualLocations: typeof buildVirtualLocations;
package/dist/jscal.js CHANGED
@@ -10,7 +10,7 @@ import { Duration } from "./jscal/duration.js";
10
10
  import { createId, createUid } from "./jscal/ids.js";
11
11
  import { normalizeItems, normalizeToObjects } from "./jscal/normalize.js";
12
12
  import { isEvent, isGroup, isTask } from "./jscal/guards.js";
13
- import { buildAlert, buildAbsoluteTrigger, buildLink, buildLocation, buildNDay, buildOffsetTrigger, buildParticipants, buildRecurrenceRule, buildRelation, buildRelatedTo, buildTimeZone, buildTimeZoneMap, buildTimeZoneRule, buildVirtualLocation, buildVirtualLocations, buildLocations, buildLinks, buildParticipant, buildAlerts, } from "./jscal/builders.js";
13
+ import { buildAlert, buildAbsoluteTrigger, buildEventPatch, buildLink, buildLocation, buildNDay, buildOffsetTrigger, buildParticipants, buildRecurrenceRule, buildRelation, buildRelatedTo, buildTimeZone, buildTimeZoneMap, buildTimeZoneRule, buildVirtualLocation, buildVirtualLocations, buildLocations, buildLinks, buildParticipant, buildAlerts, buildTaskPatch, buildGroupPatch, } from "./jscal/builders.js";
14
14
  export { createId, createUid, isEvent, isGroup, isTask };
15
15
  export const JsCal = {
16
16
  Event: EventObject,
@@ -18,6 +18,9 @@ export const JsCal = {
18
18
  Group: GroupObject,
19
19
  createUid,
20
20
  createId,
21
+ isEvent,
22
+ isGroup,
23
+ isTask,
21
24
  duration: Duration,
22
25
  timeZone: resolveTimeZone,
23
26
  timeZones: TimeZones,
@@ -34,6 +37,11 @@ export const JsCal = {
34
37
  TimeZoneRule: buildTimeZoneRule,
35
38
  RecurrenceRule: buildRecurrenceRule,
36
39
  NDay: buildNDay,
40
+ // Alias for NDay to better mirror the byDay naming in recurrence rules.
41
+ ByDay: buildNDay,
42
+ EventPatch: buildEventPatch,
43
+ TaskPatch: buildTaskPatch,
44
+ GroupPatch: buildGroupPatch,
37
45
  participants: buildParticipants,
38
46
  locations: buildLocations,
39
47
  virtualLocations: buildVirtualLocations,
package/dist/patch.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { PatchObject } from "./types.js";
1
+ import type { PatchLike } from "./types.js";
2
2
  /**
3
3
  * Error thrown when a patch operation is invalid.
4
4
  */
@@ -15,4 +15,4 @@ export declare class PatchError extends Error {
15
15
  * @param patch Patch object to apply.
16
16
  * @return Patched clone of the input object.
17
17
  */
18
- export declare function applyPatch<T extends object>(input: T, patch: PatchObject): T;
18
+ export declare function applyPatch<T extends object>(input: T, patch: PatchLike): T;
@@ -1,7 +1,7 @@
1
1
  import type { JSCalendarObject } from "../types.js";
2
2
  import type { RecurrenceRange } from "./types.js";
3
3
  /**
4
- * Expand recurrence into occurrences.
4
+ * Expand recurrence into occurrences sorted by recurrenceId/start.
5
5
  * @param items JSCalendar objects to expand.
6
6
  * @param range Date range bounds.
7
7
  * @return Generator of expanded occurrences.
@@ -3,22 +3,43 @@ import { dateTimeInTimeZone, localDateTimeFromDate, localDateTimeToUtcDate } fro
3
3
  import { TYPE_EVENT, TYPE_TASK } from "./constants.js";
4
4
  import { expandRule } from "./rules.js";
5
5
  /**
6
- * Expand recurrence into occurrences.
6
+ * Expand recurrence into occurrences sorted by recurrenceId/start.
7
7
  * @param items JSCalendar objects to expand.
8
8
  * @param range Date range bounds.
9
9
  * @return Generator of expanded occurrences.
10
10
  */
11
11
  export function* expandRecurrence(items, range) {
12
+ const occurrences = [];
13
+ let index = 0;
12
14
  for (const item of items) {
13
15
  if (item["@type"] === TYPE_EVENT) {
14
- yield* expandEvent(item, range);
15
- }
16
- else if (item["@type"] === TYPE_TASK) {
17
- yield* expandTask(item, range);
16
+ for (const occurrence of expandEvent(item, range)) {
17
+ occurrences.push({ value: occurrence, key: occurrenceKey(occurrence), index });
18
+ index += 1;
19
+ }
20
+ continue;
18
21
  }
19
- else {
20
- yield item;
22
+ if (item["@type"] === TYPE_TASK) {
23
+ for (const occurrence of expandTask(item, range)) {
24
+ occurrences.push({ value: occurrence, key: occurrenceKey(occurrence), index });
25
+ index += 1;
26
+ }
27
+ continue;
21
28
  }
29
+ occurrences.push({ value: item, key: occurrenceKey(item), index });
30
+ index += 1;
31
+ }
32
+ occurrences.sort((a, b) => {
33
+ if (a.key && b.key)
34
+ return a.key.localeCompare(b.key);
35
+ if (a.key)
36
+ return -1;
37
+ if (b.key)
38
+ return 1;
39
+ return a.index - b.index;
40
+ });
41
+ for (const occurrence of occurrences) {
42
+ yield occurrence.value;
22
43
  }
23
44
  }
24
45
  /**
package/dist/types.d.ts CHANGED
@@ -12,7 +12,30 @@ export type JsonPrimitive = string | number | boolean | null;
12
12
  export type JsonValue = JsonPrimitive | JsonValue[] | {
13
13
  [key: string]: JsonValue;
14
14
  };
15
- export type PatchObject = Record<string, JsonValue | null>;
15
+ export type PatchValue = JsonValue | null;
16
+ export interface PatchObject {
17
+ [key: string]: PatchValue;
18
+ }
19
+ type PatchFields<T> = {
20
+ [K in keyof Omit<T, "@type">]?: T[K] | null;
21
+ };
22
+ type PatchTag<TTag extends string> = {
23
+ __patchType?: TTag;
24
+ };
25
+ export type EventPatch = PatchFields<Event> & PatchTag<"Event">;
26
+ export type TaskPatch = PatchFields<Task> & PatchTag<"Task">;
27
+ export type GroupPatch = PatchFields<Group> & PatchTag<"Group">;
28
+ export type ParticipantPatch = PatchFields<Participant>;
29
+ export type LocationPatch = PatchFields<Location>;
30
+ export type VirtualLocationPatch = PatchFields<VirtualLocation>;
31
+ export type AlertPatch = PatchFields<Alert>;
32
+ export type RelationPatch = PatchFields<Relation>;
33
+ export type LinkPatch = PatchFields<Link>;
34
+ export type TimeZonePatch = PatchFields<TimeZone>;
35
+ export type TimeZoneRulePatch = PatchFields<TimeZoneRule>;
36
+ export type RecurrenceRulePatch = PatchFields<RecurrenceRule>;
37
+ export type NDayPatch = PatchFields<NDay>;
38
+ export type PatchLike = PatchObject | EventPatch | TaskPatch | GroupPatch | TimeZoneRulePatch;
16
39
  export interface Relation {
17
40
  "@type": "Relation";
18
41
  relation?: BooleanMap;
@@ -124,7 +147,7 @@ export interface TimeZoneRule {
124
147
  offsetFrom: string;
125
148
  offsetTo: string;
126
149
  recurrenceRules?: RecurrenceRule[];
127
- recurrenceOverrides?: Record<LocalDateTime, PatchObject>;
150
+ recurrenceOverrides?: Record<LocalDateTime, TimeZoneRulePatch>;
128
151
  names?: BooleanMap;
129
152
  comments?: string[];
130
153
  }
@@ -162,7 +185,6 @@ export interface JSCalendarCommon {
162
185
  recurrenceIdTimeZone?: TimeZoneId | null;
163
186
  recurrenceRules?: RecurrenceRule[];
164
187
  excludedRecurrenceRules?: RecurrenceRule[];
165
- recurrenceOverrides?: Record<LocalDateTime, PatchObject>;
166
188
  excluded?: boolean;
167
189
  priority?: Int;
168
190
  freeBusyStatus?: string;
@@ -173,7 +195,6 @@ export interface JSCalendarCommon {
173
195
  requestStatus?: string;
174
196
  useDefaultAlerts?: boolean;
175
197
  alerts?: Record<Id, Alert>;
176
- localizations?: Record<string, PatchObject>;
177
198
  timeZone?: TimeZoneId | null;
178
199
  timeZones?: Partial<Record<TimeZoneId, TimeZone>>;
179
200
  }
@@ -182,6 +203,8 @@ export interface Event extends JSCalendarCommon {
182
203
  start: LocalDateTime;
183
204
  duration?: Duration;
184
205
  status?: string;
206
+ localizations?: Record<string, EventPatch>;
207
+ recurrenceOverrides?: Record<LocalDateTime, EventPatch>;
185
208
  }
186
209
  export interface Task extends JSCalendarCommon {
187
210
  "@type": "Task";
@@ -191,11 +214,15 @@ export interface Task extends JSCalendarCommon {
191
214
  percentComplete?: UnsignedInt;
192
215
  progress?: string;
193
216
  progressUpdated?: UTCDateTime;
217
+ localizations?: Record<string, TaskPatch>;
218
+ recurrenceOverrides?: Record<LocalDateTime, TaskPatch>;
194
219
  }
195
220
  export interface Group extends JSCalendarCommon {
196
221
  "@type": "Group";
197
222
  entries: Array<Event | Task>;
198
223
  source?: string;
224
+ localizations?: Record<string, GroupPatch>;
225
+ recurrenceOverrides?: Record<LocalDateTime, GroupPatch>;
199
226
  }
200
227
  export type JSCalendarObject = Event | Task | Group;
201
228
  export type CalendarType = JSCalendarObject["@type"];
@@ -1,4 +1,4 @@
1
- import type { JsonValue, PatchObject } from "../types.js";
1
+ import type { JsonValue, PatchLike } from "../types.js";
2
2
  /**
3
3
  * Get the UTF-8 byte length of a string.
4
4
  * @param value Input string.
@@ -152,4 +152,4 @@ export declare function assertJsonValue(value: JsonValue | object | null | undef
152
152
  * @param path Validation path.
153
153
  * @return Nothing.
154
154
  */
155
- export declare function assertPatchObject(value: PatchObject | undefined, path: string): void;
155
+ export declare function assertPatchObject(value: PatchLike | undefined, path: string): void;
@@ -191,8 +191,13 @@ export function validateParticipant(value, path) {
191
191
  }
192
192
  }
193
193
  assertString(value.kind, `${path}.kind`);
194
- if (value.roles)
195
- assertBooleanMap(value.roles, `${path}.roles`);
194
+ if (!value.roles) {
195
+ fail(`${path}.roles`, "is required");
196
+ }
197
+ assertBooleanMap(value.roles, `${path}.roles`);
198
+ if (Object.keys(value.roles).length === 0) {
199
+ fail(`${path}.roles`, "must include at least one role");
200
+ }
196
201
  assertId(value.locationId, `${path}.locationId`);
197
202
  assertString(value.language, `${path}.language`);
198
203
  assertString(value.participationStatus, `${path}.participationStatus`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@craftguild/jscalendar",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "RFC 8984 (JSCalendar) data model helpers for TypeScript",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",