style(13-03): apply Prettier formatting across repo
Mechanical reformat — no logic changes. 398 files changed, 19125 insertions(+), 16457 deletions(-). Prettier 3.8.4 with .prettierrc (singleQuote:true, semi:true, tabWidth:2, trailingComma:all, printWidth:100). Isolated per D-13-08 for reviewability.
This commit is contained in:
@@ -14,26 +14,26 @@
|
||||
* This assertion locks the Plan 03 routing fix.
|
||||
*/
|
||||
|
||||
import 'temporal-polyfill/global'
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import 'temporal-polyfill/global';
|
||||
import { describe, it, expect } from 'vitest';
|
||||
|
||||
import { hydrateEvents } from './hydrateEvents.js'
|
||||
import { hydrateEvents } from './hydrateEvents.js';
|
||||
|
||||
// Minimal CalendarOccurrence shape for test purposes
|
||||
interface TestOccurrence {
|
||||
id: string
|
||||
uid: string
|
||||
calendarId: number
|
||||
calendarName: string
|
||||
ownerUserId: number
|
||||
color: string
|
||||
isShared: boolean
|
||||
title: string
|
||||
start: string
|
||||
end: string
|
||||
allDay: boolean
|
||||
location: string | null
|
||||
description: string | null
|
||||
id: string;
|
||||
uid: string;
|
||||
calendarId: number;
|
||||
calendarName: string;
|
||||
ownerUserId: number;
|
||||
color: string;
|
||||
isShared: boolean;
|
||||
title: string;
|
||||
start: string;
|
||||
end: string;
|
||||
allDay: boolean;
|
||||
location: string | null;
|
||||
description: string | null;
|
||||
}
|
||||
|
||||
function makeOccurrence(overrides: Partial<TestOccurrence>): TestOccurrence {
|
||||
@@ -52,11 +52,10 @@ function makeOccurrence(overrides: Partial<TestOccurrence>): TestOccurrence {
|
||||
location: null,
|
||||
description: null,
|
||||
...overrides,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
describe('hydrateEvents — RED stubs (Wave 0)', () => {
|
||||
|
||||
describe('Temporal type conversion', () => {
|
||||
it('converts all-day occurrence (allDay:true) to Temporal.PlainDate for start and end', () => {
|
||||
const occurrences = [
|
||||
@@ -65,33 +64,33 @@ describe('hydrateEvents — RED stubs (Wave 0)', () => {
|
||||
start: '2026-06-15',
|
||||
end: '2026-06-15',
|
||||
}),
|
||||
]
|
||||
];
|
||||
|
||||
const result = hydrateEvents(occurrences)
|
||||
expect(result).toHaveLength(1)
|
||||
const result = hydrateEvents(occurrences);
|
||||
expect(result).toHaveLength(1);
|
||||
|
||||
const evt = result[0]
|
||||
const evt = result[0];
|
||||
// Schedule-X requires Temporal.PlainDate for all-day events
|
||||
expect(evt.start).toBeInstanceOf(Temporal.PlainDate)
|
||||
expect(evt.end).toBeInstanceOf(Temporal.PlainDate)
|
||||
})
|
||||
expect(evt.start).toBeInstanceOf(Temporal.PlainDate);
|
||||
expect(evt.end).toBeInstanceOf(Temporal.PlainDate);
|
||||
});
|
||||
|
||||
it('converts an all-day exclusive DTEND to an inclusive last day for Schedule-X', () => {
|
||||
// Single-day event: iCal DTSTART:24 / DTEND:25 (exclusive). Schedule-X end is
|
||||
// inclusive, so a 1-day event must have start === end (renders on one day only).
|
||||
const single = hydrateEvents([
|
||||
makeOccurrence({ allDay: true, start: '2026-06-24', end: '2026-06-25' }),
|
||||
])[0]
|
||||
expect((single.start as Temporal.PlainDate).toString()).toBe('2026-06-24')
|
||||
expect((single.end as Temporal.PlainDate).toString()).toBe('2026-06-24')
|
||||
])[0];
|
||||
expect((single.start as Temporal.PlainDate).toString()).toBe('2026-06-24');
|
||||
expect((single.end as Temporal.PlainDate).toString()).toBe('2026-06-24');
|
||||
|
||||
// Two-day event: DTSTART:26 / DTEND:28 (exclusive) → inclusive last day = 27.
|
||||
const multi = hydrateEvents([
|
||||
makeOccurrence({ allDay: true, start: '2026-06-26', end: '2026-06-28' }),
|
||||
])[0]
|
||||
expect((multi.start as Temporal.PlainDate).toString()).toBe('2026-06-26')
|
||||
expect((multi.end as Temporal.PlainDate).toString()).toBe('2026-06-27')
|
||||
})
|
||||
])[0];
|
||||
expect((multi.start as Temporal.PlainDate).toString()).toBe('2026-06-26');
|
||||
expect((multi.end as Temporal.PlainDate).toString()).toBe('2026-06-27');
|
||||
});
|
||||
|
||||
it('converts timed occurrence (allDay:false) to Temporal.ZonedDateTime for start and end', () => {
|
||||
const occurrences = [
|
||||
@@ -100,16 +99,16 @@ describe('hydrateEvents — RED stubs (Wave 0)', () => {
|
||||
start: '2026-06-15T10:00:00-04:00[America/New_York]',
|
||||
end: '2026-06-15T11:00:00-04:00[America/New_York]',
|
||||
}),
|
||||
]
|
||||
];
|
||||
|
||||
const result = hydrateEvents(occurrences)
|
||||
expect(result).toHaveLength(1)
|
||||
const result = hydrateEvents(occurrences);
|
||||
expect(result).toHaveLength(1);
|
||||
|
||||
const evt = result[0]
|
||||
expect(evt.start).toBeInstanceOf(Temporal.ZonedDateTime)
|
||||
expect(evt.end).toBeInstanceOf(Temporal.ZonedDateTime)
|
||||
})
|
||||
})
|
||||
const evt = result[0];
|
||||
expect(evt.start).toBeInstanceOf(Temporal.ZonedDateTime);
|
||||
expect(evt.end).toBeInstanceOf(Temporal.ZonedDateTime);
|
||||
});
|
||||
});
|
||||
|
||||
describe('calendarId routing — Plan 03 contract', () => {
|
||||
it('shared occurrence (isShared:true) gets Schedule-X calendarId "shared"', () => {
|
||||
@@ -119,14 +118,14 @@ describe('hydrateEvents — RED stubs (Wave 0)', () => {
|
||||
calendarId: 5,
|
||||
ownerUserId: 2,
|
||||
}),
|
||||
]
|
||||
];
|
||||
|
||||
const result = hydrateEvents(occurrences)
|
||||
expect(result).toHaveLength(1)
|
||||
const result = hydrateEvents(occurrences);
|
||||
expect(result).toHaveLength(1);
|
||||
|
||||
// Shared-family events must route to the 'shared' calendar slot in Schedule-X config
|
||||
expect(result[0].calendarId).toBe('shared')
|
||||
})
|
||||
expect(result[0].calendarId).toBe('shared');
|
||||
});
|
||||
|
||||
it('personal occurrence (isShared:false) gets Schedule-X calendarId === String(ownerUserId), NOT String(calendarId)', () => {
|
||||
// This assertion locks the routing decision: personal events are grouped by MEMBER (ownerUserId),
|
||||
@@ -134,17 +133,17 @@ describe('hydrateEvents — RED stubs (Wave 0)', () => {
|
||||
const occurrences = [
|
||||
makeOccurrence({
|
||||
isShared: false,
|
||||
calendarId: 99, // DB calendar row id
|
||||
ownerUserId: 7, // DB user id — this is the correct Schedule-X key
|
||||
calendarId: 99, // DB calendar row id
|
||||
ownerUserId: 7, // DB user id — this is the correct Schedule-X key
|
||||
}),
|
||||
]
|
||||
];
|
||||
|
||||
const result = hydrateEvents(occurrences)
|
||||
expect(result).toHaveLength(1)
|
||||
const result = hydrateEvents(occurrences);
|
||||
expect(result).toHaveLength(1);
|
||||
|
||||
// Must be '7' (String(ownerUserId)), NOT '99' (String(calendarId))
|
||||
expect(result[0].calendarId).toBe('7')
|
||||
expect(result[0].calendarId).not.toBe('99')
|
||||
})
|
||||
})
|
||||
})
|
||||
expect(result[0].calendarId).toBe('7');
|
||||
expect(result[0].calendarId).not.toBe('99');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user