@neo-reckoning/core 0.1.0-alpha.1

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/events.js ADDED
@@ -0,0 +1,28 @@
1
+ import { buildDate } from './time.js';
2
+ /**
3
+ * Convert a native DateRange + one of its expanded Occurrences into a CalendarEvent.
4
+ */
5
+ export function fromDateRange(range, occurrence) {
6
+ const start = buildDate(occurrence.date, occurrence.startTime, range.timezone);
7
+ let end = null;
8
+ if (occurrence.endTime) {
9
+ end = buildDate(occurrence.date, occurrence.endTime, range.timezone);
10
+ }
11
+ return {
12
+ id: `${range.id}:${occurrence.date}${occurrence.startTime ? `:${occurrence.startTime}` : ''}`,
13
+ title: range.title ?? range.label,
14
+ start,
15
+ end,
16
+ allDay: occurrence.allDay,
17
+ source: 'native',
18
+ sourceId: range.id,
19
+ editable: true,
20
+ };
21
+ }
22
+ /**
23
+ * Batch-convert: expand a DateRange within a window and return CalendarEvents.
24
+ */
25
+ export function expandToEvents(range, occurrences) {
26
+ return occurrences.map(o => fromDateRange(range, o));
27
+ }
28
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAEtC;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,KAAgB,EAAE,UAAsB;IACpE,MAAM,KAAK,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IAE/E,IAAI,GAAG,GAAgB,IAAI,CAAC;IAC5B,IAAI,UAAU,CAAC,OAAO,EAAE,CAAC;QACvB,GAAG,GAAG,SAAS,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC;IACvE,CAAC;IAED,OAAO;QACL,EAAE,EAAE,GAAG,KAAK,CAAC,EAAE,IAAI,UAAU,CAAC,IAAI,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE;QAC7F,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK;QACjC,KAAK;QACL,GAAG;QACH,MAAM,EAAE,UAAU,CAAC,MAAM;QACzB,MAAM,EAAE,QAAQ;QAChB,QAAQ,EAAE,KAAK,CAAC,EAAE;QAClB,QAAQ,EAAE,IAAI;KACf,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAC5B,KAAgB,EAChB,WAAyB;IAEzB,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;AACvD,CAAC"}
package/dist/grid.d.ts ADDED
@@ -0,0 +1,36 @@
1
+ import type { CalendarGridConfig, Month, DateRange } from './types.js';
2
+ /**
3
+ * CalendarGrid — generates the data structure for rendering month-based
4
+ * calendar views. Produces Month/Week/Day objects with range membership
5
+ * pre-computed for each day.
6
+ */
7
+ export declare class CalendarGrid {
8
+ months: Month[];
9
+ private focusDate;
10
+ private numberOfMonths;
11
+ private ranges;
12
+ private weekStartsOn;
13
+ private locale;
14
+ private evaluator;
15
+ private fidelity;
16
+ constructor(config: CalendarGridConfig);
17
+ /** Advance focus by one month and regenerate. */
18
+ next(): void;
19
+ /** Go back one month and regenerate. */
20
+ prev(): void;
21
+ /** Jump to a specific date and regenerate. */
22
+ goTo(date: string): void;
23
+ /** Get the current focus date. */
24
+ getFocusDate(): string;
25
+ /** Update the ranges and regenerate. */
26
+ setRanges(ranges: DateRange[]): void;
27
+ private generate;
28
+ private generateMonth;
29
+ private generateWeeks;
30
+ private createDay;
31
+ private evaluateRangesForDay;
32
+ private formatMonthLabel;
33
+ private shiftMonth;
34
+ private shiftDay;
35
+ }
36
+ //# sourceMappingURL=grid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.d.ts","sourceRoot":"","sources":["../src/grid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,KAAK,EAIL,SAAS,EAEV,MAAM,YAAY,CAAC;AASpB;;;;GAIG;AACH,qBAAa,YAAY;IACvB,MAAM,EAAE,KAAK,EAAE,CAAC;IAEhB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,QAAQ,CAAe;gBAEnB,MAAM,EAAE,kBAAkB;IAWtC,iDAAiD;IACjD,IAAI,IAAI,IAAI;IAKZ,wCAAwC;IACxC,IAAI,IAAI,IAAI;IAKZ,8CAA8C;IAC9C,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAKxB,kCAAkC;IAClC,YAAY,IAAI,MAAM;IAItB,wCAAwC;IACxC,SAAS,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI;IAOpC,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,aAAa;IA8CrB,OAAO,CAAC,SAAS;IAmCjB,OAAO,CAAC,oBAAoB;IAyB5B,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,UAAU;IASlB,OAAO,CAAC,QAAQ;CAKjB"}
package/dist/grid.js ADDED
@@ -0,0 +1,177 @@
1
+ import { RangeEvaluator } from './evaluator.js';
2
+ import { parseDate, formatDate, daysInMonth, getToday, } from './time.js';
3
+ /**
4
+ * CalendarGrid — generates the data structure for rendering month-based
5
+ * calendar views. Produces Month/Week/Day objects with range membership
6
+ * pre-computed for each day.
7
+ */
8
+ export class CalendarGrid {
9
+ months;
10
+ focusDate;
11
+ numberOfMonths;
12
+ ranges;
13
+ weekStartsOn;
14
+ locale;
15
+ evaluator;
16
+ fidelity;
17
+ constructor(config) {
18
+ this.focusDate = config.focusDate;
19
+ this.numberOfMonths = config.numberOfMonths;
20
+ this.ranges = config.ranges;
21
+ this.weekStartsOn = config.weekStartsOn ?? 0;
22
+ this.locale = config.locale;
23
+ this.fidelity = config.fidelity ?? 'month';
24
+ this.evaluator = new RangeEvaluator(config.userTimezone);
25
+ this.months = this.generate();
26
+ }
27
+ /** Advance focus by one month and regenerate. */
28
+ next() {
29
+ this.focusDate = this.shiftMonth(this.focusDate, 1);
30
+ this.months = this.generate();
31
+ }
32
+ /** Go back one month and regenerate. */
33
+ prev() {
34
+ this.focusDate = this.shiftMonth(this.focusDate, -1);
35
+ this.months = this.generate();
36
+ }
37
+ /** Jump to a specific date and regenerate. */
38
+ goTo(date) {
39
+ this.focusDate = date;
40
+ this.months = this.generate();
41
+ }
42
+ /** Get the current focus date. */
43
+ getFocusDate() {
44
+ return this.focusDate;
45
+ }
46
+ /** Update the ranges and regenerate. */
47
+ setRanges(ranges) {
48
+ this.ranges = ranges;
49
+ this.months = this.generate();
50
+ }
51
+ // === Private ===
52
+ generate() {
53
+ const months = [];
54
+ const { year, month } = parseDate(this.focusDate);
55
+ const today = getToday();
56
+ for (let i = 0; i < this.numberOfMonths; i++) {
57
+ const d = new Date(year, month + i, 1);
58
+ const m = d.getMonth();
59
+ const y = d.getFullYear();
60
+ months.push(this.generateMonth(y, m, today));
61
+ }
62
+ return months;
63
+ }
64
+ generateMonth(year, month, today) {
65
+ const label = this.formatMonthLabel(year, month);
66
+ const weeks = this.generateWeeks(year, month, today);
67
+ return { year, month, label, weeks };
68
+ }
69
+ generateWeeks(year, month, today) {
70
+ const weeks = [];
71
+ const totalDays = daysInMonth(year, month);
72
+ // Find the weekday of the 1st (0=Sun, 6=Sat)
73
+ const firstDayOfMonth = new Date(year, month, 1).getDay();
74
+ // How many leading days from the previous month
75
+ const leadingDays = (firstDayOfMonth - this.weekStartsOn + 7) % 7;
76
+ // Build all day cells needed
77
+ const dayCells = [];
78
+ // Previous month padding
79
+ const prevMonth = month === 0 ? 11 : month - 1;
80
+ const prevYear = month === 0 ? year - 1 : year;
81
+ const prevMonthDays = daysInMonth(prevYear, prevMonth);
82
+ for (let i = leadingDays - 1; i >= 0; i--) {
83
+ const day = prevMonthDays - i;
84
+ const dateStr = formatDate(new Date(prevYear, prevMonth, day));
85
+ dayCells.push(this.createDay(dateStr, day, false, today));
86
+ }
87
+ // Current month
88
+ for (let day = 1; day <= totalDays; day++) {
89
+ const dateStr = formatDate(new Date(year, month, day));
90
+ dayCells.push(this.createDay(dateStr, day, true, today));
91
+ }
92
+ // Next month padding — fill to complete weeks
93
+ const nextMonth = month === 11 ? 0 : month + 1;
94
+ const nextYear = month === 11 ? year + 1 : year;
95
+ let nextDay = 1;
96
+ while (dayCells.length % 7 !== 0) {
97
+ const dateStr = formatDate(new Date(nextYear, nextMonth, nextDay));
98
+ dayCells.push(this.createDay(dateStr, nextDay, false, today));
99
+ nextDay++;
100
+ }
101
+ // Chunk into weeks
102
+ for (let i = 0; i < dayCells.length; i += 7) {
103
+ weeks.push({ days: dayCells.slice(i, i + 7) });
104
+ }
105
+ return weeks;
106
+ }
107
+ createDay(dateStr, dayOfMonth, isCurrentMonth, today) {
108
+ const fidelity = this.fidelity;
109
+ if (fidelity === 'year') {
110
+ // Year fidelity: only compute hasActivity, skip ranges[] and timeSlots[]
111
+ const hasActivity = this.ranges.some(r => this.evaluator.isDateInRange(dateStr, r));
112
+ return {
113
+ date: dateStr,
114
+ dayOfMonth,
115
+ isCurrentMonth,
116
+ isToday: dateStr === today,
117
+ ranges: [],
118
+ timeSlots: [],
119
+ hasActivity,
120
+ };
121
+ }
122
+ // Month, week, and day fidelity: compute ranges[]
123
+ const ranges = this.evaluateRangesForDay(dateStr);
124
+ // Week and day fidelity: also compute timeSlots[]
125
+ const timeSlots = (fidelity === 'week' || fidelity === 'day')
126
+ ? this.ranges.flatMap(r => this.evaluator.expandDay(r, dateStr))
127
+ : [];
128
+ return {
129
+ date: dateStr,
130
+ dayOfMonth,
131
+ isCurrentMonth,
132
+ isToday: dateStr === today,
133
+ ranges,
134
+ timeSlots,
135
+ };
136
+ }
137
+ evaluateRangesForDay(dateStr) {
138
+ const infos = [];
139
+ for (const range of this.ranges) {
140
+ if (!this.evaluator.isDateInRange(dateStr, range))
141
+ continue;
142
+ // Check contiguous span boundaries
143
+ const prevDate = this.shiftDay(dateStr, -1);
144
+ const nextDate = this.shiftDay(dateStr, 1);
145
+ const prevInRange = this.evaluator.isDateInRange(prevDate, range);
146
+ const nextInRange = this.evaluator.isDateInRange(nextDate, range);
147
+ infos.push({
148
+ rangeId: range.id,
149
+ label: range.label,
150
+ isStart: !prevInRange,
151
+ isEnd: !nextInRange,
152
+ isContinuation: prevInRange && nextInRange,
153
+ ...(range.displayType !== undefined ? { displayType: range.displayType } : {}),
154
+ });
155
+ }
156
+ return infos;
157
+ }
158
+ formatMonthLabel(year, month) {
159
+ const date = new Date(year, month, 1);
160
+ const options = { year: 'numeric', month: 'long' };
161
+ return new Intl.DateTimeFormat(this.locale, options).format(date);
162
+ }
163
+ shiftMonth(dateStr, delta) {
164
+ const { year, month, day } = parseDate(dateStr);
165
+ const d = new Date(year, month + delta, 1);
166
+ // Clamp day to the new month's max
167
+ const maxDay = daysInMonth(d.getFullYear(), d.getMonth());
168
+ d.setDate(Math.min(day, maxDay));
169
+ return formatDate(d);
170
+ }
171
+ shiftDay(dateStr, delta) {
172
+ const { year, month, day } = parseDate(dateStr);
173
+ const d = new Date(year, month, day + delta);
174
+ return formatDate(d);
175
+ }
176
+ }
177
+ //# sourceMappingURL=grid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid.js","sourceRoot":"","sources":["../src/grid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export type { DateRange, Occurrence, TimeSlot, DayRangeInfo, SpanInfo, Day, Week, Month, CalendarEvent, PositionedEvent, TimelineSlot, CalendarGridConfig, TimelineGridConfig, CacheAdapter, ViewFidelity, DisplayType, YearGridConfig, YearMonth, YearDay, Conflict, FreeSlot, ScheduleScore, } from './types.js';
2
+ export { RangeEvaluator } from './evaluator.js';
3
+ export { CalendarGrid } from './grid.js';
4
+ export { TimelineGrid, computeEventPositions } from './timeline.js';
5
+ export { YearGrid } from './yearGrid.js';
6
+ export { scoreSchedule } from './scoring.js';
7
+ export { resolveDisplayType } from './displayType.js';
8
+ export { fromDateRange, expandToEvents } from './events.js';
9
+ export { parseTime, formatTime, timeToMinutes, minutesToTime, parseDate, formatDate, getDayOfWeek, daysInMonth, dateRange, getToday, convertTime, buildDate, } from './time.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,SAAS,EACT,UAAU,EACV,QAAQ,EACR,YAAY,EACZ,QAAQ,EACR,GAAG,EACH,IAAI,EACJ,KAAK,EACL,aAAa,EACb,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,kBAAkB,EAClB,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,cAAc,EACd,SAAS,EACT,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAGzC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG5D,OAAO,EACL,SAAS,EACT,UAAU,EACV,aAAa,EACb,aAAa,EACb,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,QAAQ,EACR,WAAW,EACX,SAAS,GACV,MAAM,WAAW,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ // Core classes
2
+ export { RangeEvaluator } from './evaluator.js';
3
+ export { CalendarGrid } from './grid.js';
4
+ export { TimelineGrid, computeEventPositions } from './timeline.js';
5
+ export { YearGrid } from './yearGrid.js';
6
+ // Schedule scoring
7
+ export { scoreSchedule } from './scoring.js';
8
+ // Display type resolution
9
+ export { resolveDisplayType } from './displayType.js';
10
+ // Event normalization
11
+ export { fromDateRange, expandToEvents } from './events.js';
12
+ // Time utilities (exposed for consumers that need them)
13
+ export { parseTime, formatTime, timeToMinutes, minutesToTime, parseDate, formatDate, getDayOfWeek, daysInMonth, dateRange, getToday, convertTime, buildDate, } from './time.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA0BA,eAAe;AACf,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,mBAAmB;AACnB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,0BAA0B;AAC1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAEtD,sBAAsB;AACtB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE5D,wDAAwD;AACxD,OAAO,EACL,SAAS,EACT,UAAU,EACV,aAAa,EACb,aAAa,EACb,SAAS,EACT,UAAU,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,QAAQ,EACR,WAAW,EACX,SAAS,GACV,MAAM,WAAW,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { DateRange, ScheduleScore } from './types.js';
2
+ import { RangeEvaluator } from './evaluator.js';
3
+ /**
4
+ * Score a schedule across a date window.
5
+ *
6
+ * Analyses conflicts, free time, focus blocks, and context switches
7
+ * for a set of DateRanges evaluated within [from, to].
8
+ */
9
+ export declare function scoreSchedule(evaluator: RangeEvaluator, ranges: DateRange[], from: Date, to: Date, options?: {
10
+ focusBlockMinutes?: number;
11
+ dayStart?: string;
12
+ dayEnd?: string;
13
+ }): ScheduleScore;
14
+ //# sourceMappingURL=scoring.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.d.ts","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAY,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,SAAS,EAAE,cAAc,EACzB,MAAM,EAAE,SAAS,EAAE,EACnB,IAAI,EAAE,IAAI,EACV,EAAE,EAAE,IAAI,EACR,OAAO,CAAC,EAAE;IACR,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GACA,aAAa,CAiGf"}
@@ -0,0 +1,152 @@
1
+ import { RangeEvaluator } from './evaluator.js';
2
+ import { formatDate, dateRange, timeToMinutes } from './time.js';
3
+ /**
4
+ * Score a schedule across a date window.
5
+ *
6
+ * Analyses conflicts, free time, focus blocks, and context switches
7
+ * for a set of DateRanges evaluated within [from, to].
8
+ */
9
+ export function scoreSchedule(evaluator, ranges, from, to, options) {
10
+ const focusBlockMinutes = options?.focusBlockMinutes ?? 60;
11
+ const dayStartMin = timeToMinutes(options?.dayStart ?? '09:00');
12
+ const dayEndMin = timeToMinutes(options?.dayEnd ?? '17:00');
13
+ const fromStr = formatDate(from);
14
+ const toStr = formatDate(to);
15
+ const days = dateRange(fromStr, toStr);
16
+ let totalConflicts = 0;
17
+ let totalFreeMinutes = 0;
18
+ let totalFocusBlocks = 0;
19
+ let totalContextSwitches = 0;
20
+ let conflictDays = 0;
21
+ for (const day of days) {
22
+ // Gather all time slots for this day across all ranges
23
+ const allSlots = [];
24
+ for (const range of ranges) {
25
+ if (!evaluator.isDateInRange(day, range))
26
+ continue;
27
+ const slots = evaluator.getTimeSlots(day, range);
28
+ if (slots.length > 0) {
29
+ allSlots.push(...slots);
30
+ }
31
+ }
32
+ // Sort slots by start time
33
+ allSlots.sort((a, b) => timeToMinutes(a.startTime) - timeToMinutes(b.startTime));
34
+ // --- Conflicts ---
35
+ // Count pairs of slots that overlap in time
36
+ let dayHasConflict = false;
37
+ for (let i = 0; i < allSlots.length; i++) {
38
+ const slotAStart = timeToMinutes(allSlots[i].startTime);
39
+ const slotAEnd = allSlots[i].endTime
40
+ ? timeToMinutes(allSlots[i].endTime)
41
+ : slotAStart + (allSlots[i].duration ?? 0);
42
+ if (slotAEnd <= slotAStart)
43
+ continue; // skip point-in-time
44
+ for (let j = i + 1; j < allSlots.length; j++) {
45
+ const slotBStart = timeToMinutes(allSlots[j].startTime);
46
+ const slotBEnd = allSlots[j].endTime
47
+ ? timeToMinutes(allSlots[j].endTime)
48
+ : slotBStart + (allSlots[j].duration ?? 0);
49
+ if (slotBEnd <= slotBStart)
50
+ continue;
51
+ // Since sorted by start, slotBStart >= slotAStart
52
+ if (slotBStart < slotAEnd) {
53
+ totalConflicts++;
54
+ dayHasConflict = true;
55
+ }
56
+ }
57
+ }
58
+ if (dayHasConflict)
59
+ conflictDays++;
60
+ // --- Build merged occupied intervals within working hours ---
61
+ const occupied = mergeIntervals(allSlots, dayStartMin, dayEndMin);
62
+ // --- Free time = working hours minus occupied ---
63
+ const workingMinutes = dayEndMin - dayStartMin;
64
+ let occupiedMinutes = 0;
65
+ for (const [s, e] of occupied) {
66
+ occupiedMinutes += e - s;
67
+ }
68
+ const freeMinutes = workingMinutes - occupiedMinutes;
69
+ totalFreeMinutes += freeMinutes;
70
+ // --- Focus blocks: gaps within working hours >= focusBlockMinutes ---
71
+ const gaps = computeGaps(occupied, dayStartMin, dayEndMin);
72
+ for (const [s, e] of gaps) {
73
+ if (e - s >= focusBlockMinutes) {
74
+ totalFocusBlocks++;
75
+ }
76
+ }
77
+ // --- Context switches ---
78
+ // Transitions between different rangeIds in chronological order
79
+ let switches = 0;
80
+ let lastRangeId = null;
81
+ for (const slot of allSlots) {
82
+ if (lastRangeId !== null && slot.rangeId !== lastRangeId) {
83
+ switches++;
84
+ }
85
+ lastRangeId = slot.rangeId;
86
+ }
87
+ totalContextSwitches += switches;
88
+ }
89
+ const avgContextSwitches = days.length > 0 ? totalContextSwitches / days.length : 0;
90
+ return {
91
+ conflicts: totalConflicts,
92
+ freeMinutes: totalFreeMinutes,
93
+ focusBlocks: totalFocusBlocks,
94
+ avgContextSwitches,
95
+ conflictDays,
96
+ };
97
+ }
98
+ /**
99
+ * Merge time slots into non-overlapping intervals, clipped to [dayStart, dayEnd].
100
+ * Returns sorted array of [start, end] minute pairs.
101
+ */
102
+ function mergeIntervals(slots, dayStartMin, dayEndMin) {
103
+ // Convert to minute intervals, clipped to working hours
104
+ const intervals = [];
105
+ for (const slot of slots) {
106
+ const start = timeToMinutes(slot.startTime);
107
+ const end = slot.endTime
108
+ ? timeToMinutes(slot.endTime)
109
+ : start + (slot.duration ?? 0);
110
+ if (end <= start)
111
+ continue; // skip zero-length
112
+ const clippedStart = Math.max(start, dayStartMin);
113
+ const clippedEnd = Math.min(end, dayEndMin);
114
+ if (clippedStart < clippedEnd) {
115
+ intervals.push([clippedStart, clippedEnd]);
116
+ }
117
+ }
118
+ if (intervals.length === 0)
119
+ return [];
120
+ // Sort by start
121
+ intervals.sort((a, b) => a[0] - b[0]);
122
+ // Merge overlapping
123
+ const merged = [intervals[0]];
124
+ for (let i = 1; i < intervals.length; i++) {
125
+ const last = merged[merged.length - 1];
126
+ if (intervals[i][0] <= last[1]) {
127
+ last[1] = Math.max(last[1], intervals[i][1]);
128
+ }
129
+ else {
130
+ merged.push(intervals[i]);
131
+ }
132
+ }
133
+ return merged;
134
+ }
135
+ /**
136
+ * Compute gaps between merged intervals within [dayStart, dayEnd].
137
+ */
138
+ function computeGaps(merged, dayStartMin, dayEndMin) {
139
+ const gaps = [];
140
+ let cursor = dayStartMin;
141
+ for (const [s, e] of merged) {
142
+ if (s > cursor) {
143
+ gaps.push([cursor, s]);
144
+ }
145
+ cursor = Math.max(cursor, e);
146
+ }
147
+ if (cursor < dayEndMin) {
148
+ gaps.push([cursor, dayEndMin]);
149
+ }
150
+ return gaps;
151
+ }
152
+ //# sourceMappingURL=scoring.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scoring.js","sourceRoot":"","sources":["../src/scoring.ts"],"names":[],"mappings":"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"}
package/dist/time.d.ts ADDED
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Internal time/date utilities for neo-reckoning.
3
+ * Uses Intl.DateTimeFormat for timezone conversion — no external dependencies.
4
+ */
5
+ /** Parse "HH:mm" into { hour, minute } */
6
+ export declare function parseTime(time: string): {
7
+ hour: number;
8
+ minute: number;
9
+ };
10
+ /** Format { hour, minute } into "HH:mm" */
11
+ export declare function formatTime(hour: number, minute: number): string;
12
+ /** Convert minutes since midnight to "HH:mm" */
13
+ export declare function minutesToTime(minutes: number): string;
14
+ /** Convert "HH:mm" to minutes since midnight */
15
+ export declare function timeToMinutes(time: string): number;
16
+ /** Add minutes to a time string, clamping at 24:00. Returns null if result >= 24:00. */
17
+ export declare function addMinutes(time: string, minutes: number): string | null;
18
+ /** Parse "YYYY-MM-DD" into { year, month, day } */
19
+ export declare function parseDate(date: string): {
20
+ year: number;
21
+ month: number;
22
+ day: number;
23
+ };
24
+ /** Format a Date to "YYYY-MM-DD" */
25
+ export declare function formatDate(date: Date): string;
26
+ /** Get the day of week (0=Sunday) for a "YYYY-MM-DD" string */
27
+ export declare function getDayOfWeek(dateStr: string): number;
28
+ /** Get the number of days in a given month (0-indexed month) */
29
+ export declare function daysInMonth(year: number, month: number): number;
30
+ /** Compare two "YYYY-MM-DD" strings. Returns -1, 0, or 1. */
31
+ export declare function compareDates(a: string, b: string): number;
32
+ /** Generate all dates (as "YYYY-MM-DD") between from and to, inclusive. */
33
+ export declare function dateRange(from: string, to: string): string[];
34
+ /** Get today's date as "YYYY-MM-DD" in a given timezone (or local if not specified). */
35
+ export declare function getToday(timezone?: string): string;
36
+ /**
37
+ * Format a Date as "YYYY-MM-DD" in a specific timezone using Intl.DateTimeFormat.
38
+ */
39
+ export declare function formatDateInTimezone(date: Date, timezone: string): string;
40
+ /**
41
+ * Get the hour and minute of a Date in a specific timezone.
42
+ */
43
+ export declare function getTimeInTimezone(date: Date, timezone: string): {
44
+ hour: number;
45
+ minute: number;
46
+ };
47
+ /**
48
+ * Convert a time from one timezone to another on a given date.
49
+ * Returns the converted time as "HH:mm", or null if the time doesn't exist
50
+ * (e.g., spring-forward DST gap).
51
+ */
52
+ export declare function convertTime(dateStr: string, time: string, fromTimezone: string, toTimezone: string): string | null;
53
+ /**
54
+ * Build a Date object from a date string and time string in a given timezone.
55
+ * If timezone is null/undefined (floating), uses local time.
56
+ */
57
+ export declare function buildDate(dateStr: string, time: string | null, timezone?: string | null): Date;
58
+ //# sourceMappingURL=time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.d.ts","sourceRoot":"","sources":["../src/time.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0CAA0C;AAC1C,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAGxE;AAED,2CAA2C;AAC3C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAIrD;AAED,gDAAgD;AAChD,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGlD;AAED,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIvE;AAED,mDAAmD;AACnD,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAGpF;AAED,oCAAoC;AACpC,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAK7C;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGpD;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,6DAA6D;AAC7D,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAIzD;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,CAc5D;AAED,wFAAwF;AACxF,wBAAgB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CASzE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAWhG;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAyBf;AAcD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAsB9F"}