diff --git a/main.test.ts b/main.test.ts index febdc96..85d3738 100644 --- a/main.test.ts +++ b/main.test.ts @@ -3,26 +3,23 @@ import { assertEquals } from 'https://deno.land/std@0.154.0/testing/asserts.ts'; import { Event, EventConfig, Calendar } from './mod.ts'; import { short_utc } from './date.ts'; -Deno.test('UTC event', - () => { - const cfg: EventConfig = { - title: 'test', - beginDate: [2022, 8, 1, 10, 10], - endDate: [2022, 8, 1, 11, 10], - desc: 'Hello', - zone: 'utc' // Universal time required - }; - const evt = new Event(cfg); - const lines = evt.toLines() - assertEquals(lines[0][0], "BEGIN") - assertEquals(lines[0][1], "VEVENT") +Deno.test('UTC event', () => { + const cfg: EventConfig = { + title: 'test', + beginDate: [2022, 8, 1, 10, 10], + endDate: [2022, 8, 1, 11, 10], + desc: 'Hello', + zone: 'utc', // Universal time required + }; + const evt = new Event(cfg); + const lines = evt.toLines(); + assertEquals(lines[0][0], 'BEGIN'); + assertEquals(lines[0][1], 'VEVENT'); - // Note 'Z' suffix for UTC (precaution against daylight saving time surprises) - assertEquals(lines[3], ["DTSTART", "20220801T101000Z"]) - assertEquals(lines[4], ["DTEND", "20220801T111000Z"]) - - }, -); + // Note 'Z' suffix for UTC (precaution against daylight saving time surprises) + assertEquals(lines[3], ['DTSTART', '20220801T101000Z']); + assertEquals(lines[4], ['DTEND', '20220801T111000Z']); +}); Deno.test({ name: 'calendar', @@ -49,11 +46,11 @@ Deno.test({ desc: 'Implement a module to generate .ics files', organizer: { name: 'Sam Worthington', - email: 'sam@dev.com' + email: 'sam@dev.com', }, url: 'https://www.google.com/', location: 'ABC Tank Warehouse', - geo: { lat: 10.4, lon: 44.5 } + geo: { lat: 10.4, lon: 44.5 }, }; const cfg2: EventConfig = { @@ -78,3 +75,26 @@ Deno.test({ console.log(calendar.toString()); }, }); + +Deno.test('UTC event custom ID', () => { + const customId = '03bdde99-ede2-410e-b1b1-4c2a09d65b1f'; + const cfg: EventConfig = { + customId, + title: 'test custom ID event', + beginDate: [2022, 8, 1, 10, 10], + endDate: [2022, 8, 1, 11, 10], + desc: 'Hello', + zone: 'utc', // Universal time required + }; + const evt = new Event(cfg); + const lines = evt.toLines(); + + assertEquals(lines[0], ['BEGIN', 'VEVENT']); + + assertEquals(lines[1][0], 'UID'); + assertEquals(lines[1][1], customId); + + assertEquals(lines[lines.length - 1], ['END', 'VEVENT']); + + console.log(evt.toString()); +}); diff --git a/main.ts b/main.ts index ccc4acb..e578bf8 100644 --- a/main.ts +++ b/main.ts @@ -17,18 +17,20 @@ const eventBegin: ContentLine = ['BEGIN', 'VEVENT']; const eventEnd: ContentLine = ['END', 'VEVENT']; -const parseGeo = (geo?: {lat: number, lon: number}) => { +const parseGeo = (geo?: { lat: number; lon: number }) => { return geo ? `${geo.lat};${geo.lon}` : undefined; -} +}; -const parseOrganizer = (organizer?: {name: string, email: string}) => { - return organizer? `CN=${organizer.name}:mailto:${organizer.email}` : undefined -} +const parseOrganizer = (organizer?: { name: string; email: string }) => { + return organizer + ? `CN=${organizer.name}:mailto:${organizer.email}` + : undefined; +}; export class Event { - zone: Zone = 'local' - constructor (protected config: EventConfig) { - if (config.zone) this.zone = config.zone + zone: Zone = 'local'; + constructor(protected config: EventConfig) { + if (config.zone) this.zone = config.zone; if (config.duration !== undefined) { // Duration is provided if (!(config.beginDate instanceof Date)) { @@ -48,13 +50,24 @@ export class Event { } toLines(): ContentLine[] { - const uid = crypto.randomUUID(); - const { title, desc, rrule, alarm, location, url, organizer, geo, htmlContent } = this.config; + const { + customId, + title, + desc, + rrule, + alarm, + location, + url, + organizer, + geo, + htmlContent, + } = this.config; + const uid = customId ?? crypto.randomUUID(); const result = [ eventBegin, ['UID', uid], - ['DTSTAMP', parseDate(new Date(), "utc")], + ['DTSTAMP', parseDate(new Date(), 'utc')], ['DTSTART', parseDate(this.config.beginDate, this.zone)], ['DTEND', parseDate(this.config.endDate!, this.zone)], ['SUMMARY', title], @@ -66,17 +79,21 @@ export class Event { ['ORGANIZER', parseOrganizer(organizer)], ...parseAlarm(alarm), eventEnd, - ].filter(line => line[1] !== undefined) as ContentLine[]; + ].filter((line) => line[1] !== undefined) as ContentLine[]; return result; } + + toString() { + return stringifyLines(this.toLines()); + } } export class Calendar { constructor(protected events: Event[]) {} toLines(): ContentLine[] { - const eventLines = this.events.map(evt => evt.toLines()).flat(); + const eventLines = this.events.map((evt) => evt.toLines()).flat(); return [calendarBegin, ...calendarProps, ...eventLines, calendarEnd]; } @@ -87,6 +104,7 @@ export class Calendar { } export interface EventConfig { + customId?: string; title: string; beginDate: DateData; endDate?: DateData; @@ -96,10 +114,10 @@ export interface EventConfig { alarm?: AlarmConfig; location?: string; url?: string; - organizer?: { name: string; email: string; dir?: string; }; - geo?: { lat: number; lon: number; }; + organizer?: { name: string; email: string; dir?: string }; + geo?: { lat: number; lon: number }; htmlContent?: string; - zone?: Zone // default to local + zone?: Zone; // default to local } export interface AlarmConfig {