@bimetal/temporal 0.35.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/LICENSE +57 -0
- package/README.md +73 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/constants.d.ts +29 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +29 -0
- package/dist/constants.js.map +1 -0
- package/dist/date-strings.d.ts +23 -0
- package/dist/date-strings.d.ts.map +1 -0
- package/dist/date-strings.js +25 -0
- package/dist/date-strings.js.map +1 -0
- package/dist/datetime.d.ts +100 -0
- package/dist/datetime.d.ts.map +1 -0
- package/dist/datetime.js +289 -0
- package/dist/datetime.js.map +1 -0
- package/dist/duration.d.ts +25 -0
- package/dist/duration.d.ts.map +1 -0
- package/dist/duration.js +43 -0
- package/dist/duration.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +19 -0
- package/dist/errors.js.map +1 -0
- package/dist/format.d.ts +13 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +51 -0
- package/dist/format.js.map +1 -0
- package/dist/granularity.d.ts +13 -0
- package/dist/granularity.d.ts.map +1 -0
- package/dist/granularity.js +70 -0
- package/dist/granularity.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/time-range.d.ts +38 -0
- package/dist/time-range.d.ts.map +1 -0
- package/dist/time-range.js +67 -0
- package/dist/time-range.js.map +1 -0
- package/dist/types.d.ts +50 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/vocabulary.d.ts +40 -0
- package/dist/vocabulary.d.ts.map +1 -0
- package/dist/vocabulary.js +38 -0
- package/dist/vocabulary.js.map +1 -0
- package/package.json +45 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @bimetal/temporal
|
|
3
|
+
*
|
|
4
|
+
* Domain-neutral temporal kernel: time model, durations, grid resolution,
|
|
5
|
+
* formatting. Stateless, deterministic, pure functions. Shared by every
|
|
6
|
+
* BIMETAL component family, not just the calendar.
|
|
7
|
+
* No DOM, no framework dependencies. ZERO external npm dependencies.
|
|
8
|
+
*
|
|
9
|
+
* Surface (Surface-Charge B / D3): this barrel exposes only the temporal base
|
|
10
|
+
* that is actually consumed. The unconsumed half of the duration algebra
|
|
11
|
+
* (`minutes`/`hours`/`days`/`between`/`duration`/`to*`), the unused unit
|
|
12
|
+
* constants, and a handful of unused helpers were retracted before the 1.0
|
|
13
|
+
* freeze — they live in their modules and return additively post-1.0 when a
|
|
14
|
+
* consumer needs them.
|
|
15
|
+
*/
|
|
16
|
+
export type { CalendarDateTime, TimeRange, Granularity, TimeSlot, Clock, FormatOptions, SnapStrategy, } from './types.js';
|
|
17
|
+
export { Month, monthIndex, Weekday, weekdayIndex } from './vocabulary.js';
|
|
18
|
+
/** Forward-API (P1, post-1.0): the typed-error union is advertised but not yet
|
|
19
|
+
* constructed/handled by any consumer. Kept public as the documented error
|
|
20
|
+
* contract; the concrete throwers land post-1.0. */
|
|
21
|
+
export type { CalendarError } from './errors.js';
|
|
22
|
+
export { CalendarValidationError } from './errors.js';
|
|
23
|
+
export { MINUTES_PER_HOUR, HOURS_PER_DAY, DAYS_PER_WEEK, MS_PER_EXACT_DAY, } from './constants.js';
|
|
24
|
+
export { createDateTime, fromEpochMs, now, addDays, addWeeks, addMonths, addYears, addHours, addMinutes, startOfDay, endOfDay, getYear, getMonth, getDayOfMonth, getDayOfWeek, getHours, getMinutes, toMinutesOfDay, isSameDay, isBefore, isAfter, isEqual, daysBetween, } from './datetime.js';
|
|
25
|
+
export { toDateStr, parseDateStr } from './date-strings.js';
|
|
26
|
+
export { createTimeRange, overlaps, clipTo, shiftRange, } from './time-range.js';
|
|
27
|
+
export { durationInMinutes, } from './duration.js';
|
|
28
|
+
export { snap, generateSlots, } from './granularity.js';
|
|
29
|
+
export { formatDateTime, formatDayLabel, } from './format.js';
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,YAAY,EACV,gBAAgB,EAChB,SAAS,EACT,WAAW,EACX,QAAQ,EACR,KAAK,EAGL,aAAa,EACb,YAAY,GACb,MAAM,YAAY,CAAC;AAKpB,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAG3E;;qDAEqD;AACrD,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAGtD,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EACL,cAAc,EAEd,WAAW,EACX,GAAG,EACH,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,UAAU,EACV,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,cAAc,EACd,SAAS,EACT,QAAQ,EACR,OAAO,EACP,OAAO,EACP,WAAW,GACZ,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAG5D,OAAO,EACL,eAAe,EACf,QAAQ,EACR,MAAM,EACN,UAAU,GACX,MAAM,iBAAiB,CAAC;AAGzB,OAAO,EACL,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,IAAI,EACJ,aAAa,GACd,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @bimetal/temporal
|
|
3
|
+
*
|
|
4
|
+
* Domain-neutral temporal kernel: time model, durations, grid resolution,
|
|
5
|
+
* formatting. Stateless, deterministic, pure functions. Shared by every
|
|
6
|
+
* BIMETAL component family, not just the calendar.
|
|
7
|
+
* No DOM, no framework dependencies. ZERO external npm dependencies.
|
|
8
|
+
*
|
|
9
|
+
* Surface (Surface-Charge B / D3): this barrel exposes only the temporal base
|
|
10
|
+
* that is actually consumed. The unconsumed half of the duration algebra
|
|
11
|
+
* (`minutes`/`hours`/`days`/`between`/`duration`/`to*`), the unused unit
|
|
12
|
+
* constants, and a handful of unused helpers were retracted before the 1.0
|
|
13
|
+
* freeze — they live in their modules and return additively post-1.0 when a
|
|
14
|
+
* consumer needs them.
|
|
15
|
+
*/
|
|
16
|
+
// ── Branded vocabulary (Month / Weekday) — see vocabulary.ts for the freeze rule.
|
|
17
|
+
// `Month`/`Weekday` are each a value (the constants) AND a type (the brand) via declaration
|
|
18
|
+
// merging, so this one export line carries both. ──
|
|
19
|
+
export { Month, monthIndex, Weekday, weekdayIndex } from './vocabulary.js';
|
|
20
|
+
export { CalendarValidationError } from './errors.js';
|
|
21
|
+
// ── Time-Unit Constants ─────────────────────────────────────────
|
|
22
|
+
export { MINUTES_PER_HOUR, HOURS_PER_DAY, DAYS_PER_WEEK, MS_PER_EXACT_DAY, } from './constants.js';
|
|
23
|
+
// ── CalendarDateTime ────────────────────────────────────────────
|
|
24
|
+
export { createDateTime,
|
|
25
|
+
// Documented migration bridge from Date/ISO/epochMs (migration guides) — public API.
|
|
26
|
+
fromEpochMs, now, addDays, addWeeks, addMonths, addYears, addHours, addMinutes, startOfDay, endOfDay, getYear, getMonth, getDayOfMonth, getDayOfWeek, getHours, getMinutes, toMinutesOfDay, isSameDay, isBefore, isAfter, isEqual, daysBetween, } from './datetime.js';
|
|
27
|
+
// ── Date strings (timezone-aware CalendarDateTime ↔ "YYYY-MM-DD") ─
|
|
28
|
+
export { toDateStr, parseDateStr } from './date-strings.js';
|
|
29
|
+
// ── TimeRange ───────────────────────────────────────────────────
|
|
30
|
+
export { createTimeRange, overlaps, clipTo, shiftRange, } from './time-range.js';
|
|
31
|
+
// ── Duration ────────────────────────────────────────────────────
|
|
32
|
+
export { durationInMinutes, } from './duration.js';
|
|
33
|
+
// ── Granularity ─────────────────────────────────────────────────
|
|
34
|
+
export { snap, generateSlots, } from './granularity.js';
|
|
35
|
+
// ── Formatting ──────────────────────────────────────────────────
|
|
36
|
+
export { formatDateTime, formatDayLabel, } from './format.js';
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAeH,mFAAmF;AACnF,+FAA+F;AAC/F,uDAAuD;AACvD,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAO3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAEtD,mEAAmE;AACnE,OAAO,EACL,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AAExB,mEAAmE;AACnE,OAAO,EACL,cAAc;AACd,qFAAqF;AACrF,WAAW,EACX,GAAG,EACH,OAAO,EACP,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,UAAU,EACV,UAAU,EACV,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,cAAc,EACd,SAAS,EACT,QAAQ,EACR,OAAO,EACP,OAAO,EACP,WAAW,GACZ,MAAM,eAAe,CAAC;AAEvB,qEAAqE;AACrE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAE5D,mEAAmE;AACnE,OAAO,EACL,eAAe,EACf,QAAQ,EACR,MAAM,EACN,UAAU,GACX,MAAM,iBAAiB,CAAC;AAEzB,mEAAmE;AACnE,OAAO,EACL,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAEvB,mEAAmE;AACnE,OAAO,EACL,IAAI,EACJ,aAAa,GACd,MAAM,kBAAkB,CAAC;AAE1B,mEAAmE;AACnE,OAAO,EACL,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { CalendarDateTime, TimeRange } from './types.js';
|
|
2
|
+
/** Create a TimeRange. Throws if start >= end. */
|
|
3
|
+
export declare function createTimeRange(start: CalendarDateTime, end: CalendarDateTime): TimeRange;
|
|
4
|
+
/**
|
|
5
|
+
* Build a TimeRange for an all-day event with user-facing **inclusive
|
|
6
|
+
* end** semantics.
|
|
7
|
+
*
|
|
8
|
+
* BIMETAL stores all-day events with **exclusive end** internally:
|
|
9
|
+
* `end = midnight of the day AFTER the last visible day`. Custom dialogs
|
|
10
|
+
* and importers that hand-build TimeRanges historically tripped over
|
|
11
|
+
* this — naive `{ start: 2026-04-15T00:00, end: 2026-04-15T23:59 }` looks
|
|
12
|
+
* right in storage but breaks drag math (degenerate ranges, off-by-one
|
|
13
|
+
* sums). This helper takes the *inclusive* form (the user picks "from
|
|
14
|
+
* April 15 to April 17") and normalises both ends:
|
|
15
|
+
*
|
|
16
|
+
* - `start` → `startOfDay(start)` — strips any time-of-day component
|
|
17
|
+
* - `end` → `addDays(startOfDay(end), 1)` — flips inclusive → exclusive
|
|
18
|
+
*
|
|
19
|
+
* @example Single-day event ("just today"):
|
|
20
|
+
* createAllDayTimeRange(today, today)
|
|
21
|
+
* // → { start: today 00:00, end: tomorrow 00:00 }
|
|
22
|
+
*
|
|
23
|
+
* @example Multi-day event ("April 15 through April 17 inclusive"):
|
|
24
|
+
* createAllDayTimeRange(apr15, apr17)
|
|
25
|
+
* // → { start: apr15 00:00, end: apr18 00:00 }
|
|
26
|
+
*/
|
|
27
|
+
export declare function createAllDayTimeRange(startDate: CalendarDateTime, endDate: CalendarDateTime): TimeRange;
|
|
28
|
+
/** Intersection of two ranges. Returns null if they don't overlap. */
|
|
29
|
+
export declare function intersect(a: TimeRange, b: TimeRange): TimeRange | null;
|
|
30
|
+
/** Check if a range contains a point in time. */
|
|
31
|
+
export declare function contains(range: TimeRange, dt: CalendarDateTime): boolean;
|
|
32
|
+
/** Check if two ranges overlap (touching is not overlapping). */
|
|
33
|
+
export declare function overlaps(a: TimeRange, b: TimeRange): boolean;
|
|
34
|
+
/** Clip a range to fit within bounds. Returns null if no overlap. */
|
|
35
|
+
export declare function clipTo(range: TimeRange, bounds: TimeRange): TimeRange | null;
|
|
36
|
+
/** Shift a range to a new start, preserving duration. */
|
|
37
|
+
export declare function shiftRange(range: TimeRange, newStart: CalendarDateTime): TimeRange;
|
|
38
|
+
//# sourceMappingURL=time-range.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-range.d.ts","sourceRoot":"","sources":["../src/time-range.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAI9D,kDAAkD;AAClD,wBAAgB,eAAe,CAAC,KAAK,EAAE,gBAAgB,EAAE,GAAG,EAAE,gBAAgB,GAAG,SAAS,CAQzF;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,gBAAgB,EAC3B,OAAO,EAAE,gBAAgB,GACxB,SAAS,CAKX;AAED,sEAAsE;AACtE,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAQtE;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,gBAAgB,GAAG,OAAO,CAExE;AAED,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAE5D;AAED,qEAAqE;AACrE,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,SAAS,GAAG,IAAI,CAE5E;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,gBAAgB,GAAG,SAAS,CAMlF"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { CalendarValidationError } from './errors.js';
|
|
2
|
+
import { addDays, startOfDay } from './datetime.js';
|
|
3
|
+
/** Create a TimeRange. Throws if start >= end. */
|
|
4
|
+
export function createTimeRange(start, end) {
|
|
5
|
+
if (start.epochMs >= end.epochMs) {
|
|
6
|
+
throw new CalendarValidationError({
|
|
7
|
+
type: 'INVALID_TIME_RANGE',
|
|
8
|
+
message: `start (${start.epochMs}) must be before end (${end.epochMs})`,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
return { start, end };
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build a TimeRange for an all-day event with user-facing **inclusive
|
|
15
|
+
* end** semantics.
|
|
16
|
+
*
|
|
17
|
+
* BIMETAL stores all-day events with **exclusive end** internally:
|
|
18
|
+
* `end = midnight of the day AFTER the last visible day`. Custom dialogs
|
|
19
|
+
* and importers that hand-build TimeRanges historically tripped over
|
|
20
|
+
* this — naive `{ start: 2026-04-15T00:00, end: 2026-04-15T23:59 }` looks
|
|
21
|
+
* right in storage but breaks drag math (degenerate ranges, off-by-one
|
|
22
|
+
* sums). This helper takes the *inclusive* form (the user picks "from
|
|
23
|
+
* April 15 to April 17") and normalises both ends:
|
|
24
|
+
*
|
|
25
|
+
* - `start` → `startOfDay(start)` — strips any time-of-day component
|
|
26
|
+
* - `end` → `addDays(startOfDay(end), 1)` — flips inclusive → exclusive
|
|
27
|
+
*
|
|
28
|
+
* @example Single-day event ("just today"):
|
|
29
|
+
* createAllDayTimeRange(today, today)
|
|
30
|
+
* // → { start: today 00:00, end: tomorrow 00:00 }
|
|
31
|
+
*
|
|
32
|
+
* @example Multi-day event ("April 15 through April 17 inclusive"):
|
|
33
|
+
* createAllDayTimeRange(apr15, apr17)
|
|
34
|
+
* // → { start: apr15 00:00, end: apr18 00:00 }
|
|
35
|
+
*/
|
|
36
|
+
export function createAllDayTimeRange(startDate, endDate) {
|
|
37
|
+
return createTimeRange(startOfDay(startDate), addDays(startOfDay(endDate), 1));
|
|
38
|
+
}
|
|
39
|
+
/** Intersection of two ranges. Returns null if they don't overlap. */
|
|
40
|
+
export function intersect(a, b) {
|
|
41
|
+
const start = Math.max(a.start.epochMs, b.start.epochMs);
|
|
42
|
+
const end = Math.min(a.end.epochMs, b.end.epochMs);
|
|
43
|
+
if (start >= end)
|
|
44
|
+
return null;
|
|
45
|
+
return {
|
|
46
|
+
start: { epochMs: start, timezone: a.start.timezone },
|
|
47
|
+
end: { epochMs: end, timezone: a.start.timezone },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Check if a range contains a point in time. */
|
|
51
|
+
export function contains(range, dt) {
|
|
52
|
+
return dt.epochMs >= range.start.epochMs && dt.epochMs < range.end.epochMs;
|
|
53
|
+
}
|
|
54
|
+
/** Check if two ranges overlap (touching is not overlapping). */
|
|
55
|
+
export function overlaps(a, b) {
|
|
56
|
+
return a.start.epochMs < b.end.epochMs && b.start.epochMs < a.end.epochMs;
|
|
57
|
+
}
|
|
58
|
+
/** Clip a range to fit within bounds. Returns null if no overlap. */
|
|
59
|
+
export function clipTo(range, bounds) {
|
|
60
|
+
return intersect(range, bounds);
|
|
61
|
+
}
|
|
62
|
+
/** Shift a range to a new start, preserving duration. */
|
|
63
|
+
export function shiftRange(range, newStart) {
|
|
64
|
+
const durationMs = range.end.epochMs - range.start.epochMs;
|
|
65
|
+
return createTimeRange(newStart, { epochMs: newStart.epochMs + durationMs, timezone: newStart.timezone });
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=time-range.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"time-range.js","sourceRoot":"","sources":["../src/time-range.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEpD,kDAAkD;AAClD,MAAM,UAAU,eAAe,CAAC,KAAuB,EAAE,GAAqB;IAC5E,IAAI,KAAK,CAAC,OAAO,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;QACjC,MAAM,IAAI,uBAAuB,CAAC;YAChC,IAAI,EAAE,oBAAoB;YAC1B,OAAO,EAAE,UAAU,KAAK,CAAC,OAAO,yBAAyB,GAAG,CAAC,OAAO,GAAG;SACxE,CAAC,CAAC;IACL,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;AACxB,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,qBAAqB,CACnC,SAA2B,EAC3B,OAAyB;IAEzB,OAAO,eAAe,CACpB,UAAU,CAAC,SAAS,CAAC,EACrB,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAChC,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,SAAS,CAAC,CAAY,EAAE,CAAY;IAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnD,IAAI,KAAK,IAAI,GAAG;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO;QACL,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;QACrD,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,EAAE;KAClD,CAAC;AACJ,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,QAAQ,CAAC,KAAgB,EAAE,EAAoB;IAC7D,OAAO,EAAE,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,IAAI,EAAE,CAAC,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC;AAC7E,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,QAAQ,CAAC,CAAY,EAAE,CAAY;IACjD,OAAO,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC;AAC5E,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,MAAM,CAAC,KAAgB,EAAE,MAAiB;IACxD,OAAO,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;AAClC,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,UAAU,CAAC,KAAgB,EAAE,QAA0B;IACrE,MAAM,UAAU,GAAG,KAAK,CAAC,GAAG,CAAC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC;IAC3D,OAAO,eAAe,CACpB,QAAQ,EACR,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,GAAG,UAAU,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,EAAE,CACxE,CAAC;AACJ,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core — Temporal Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Domain-neutral time model: points in time, ranges, durations, grid
|
|
5
|
+
* resolution, formatting. All types are immutable (readonly properties).
|
|
6
|
+
* No framework dependencies. No DOM. No calendar-domain concepts.
|
|
7
|
+
*/
|
|
8
|
+
/** A point in time with timezone context. */
|
|
9
|
+
export interface CalendarDateTime {
|
|
10
|
+
readonly epochMs: number;
|
|
11
|
+
readonly timezone: string;
|
|
12
|
+
}
|
|
13
|
+
/** A span between two points in time. Invariant: start < end. */
|
|
14
|
+
export interface TimeRange {
|
|
15
|
+
readonly start: CalendarDateTime;
|
|
16
|
+
readonly end: CalendarDateTime;
|
|
17
|
+
}
|
|
18
|
+
/** A duration in milliseconds. */
|
|
19
|
+
export interface Duration {
|
|
20
|
+
readonly ms: number;
|
|
21
|
+
}
|
|
22
|
+
/** Time grid resolution. */
|
|
23
|
+
export interface Granularity {
|
|
24
|
+
readonly minutes: number;
|
|
25
|
+
}
|
|
26
|
+
/** A discrete slot in a time grid. */
|
|
27
|
+
export interface TimeSlot {
|
|
28
|
+
readonly range: TimeRange;
|
|
29
|
+
readonly index: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Injectable time source. Used for "now" semantics and by event-sourced
|
|
33
|
+
* stores for event timestamps.
|
|
34
|
+
*
|
|
35
|
+
* Defined locally — structurally identical to `@bimetal/event-sourcing`'s
|
|
36
|
+
* `Clock`. TypeScript's structural typing keeps the two interchangeable
|
|
37
|
+
* without coupling `@bimetal/temporal` to the event-sourcing layer.
|
|
38
|
+
*/
|
|
39
|
+
export interface Clock {
|
|
40
|
+
now(): number;
|
|
41
|
+
}
|
|
42
|
+
/** Options for Intl-based formatting. */
|
|
43
|
+
export interface FormatOptions {
|
|
44
|
+
readonly locale: string;
|
|
45
|
+
readonly dateStyle?: 'full' | 'long' | 'medium' | 'short';
|
|
46
|
+
readonly timeStyle?: 'full' | 'long' | 'medium' | 'short';
|
|
47
|
+
}
|
|
48
|
+
/** Snap rounding strategy. */
|
|
49
|
+
export type SnapStrategy = 'floor' | 'ceil' | 'round';
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,6CAA6C;AAC7C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED,iEAAiE;AACjE,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAC;CAChC;AAED,kCAAkC;AAClC,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAED,4BAA4B;AAC5B,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,sCAAsC;AACtC,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAOD;;;;;;;GAOG;AACH,MAAM,WAAW,KAAK;IACpB,GAAG,IAAI,MAAM,CAAC;CACf;AAID,yCAAyC;AACzC,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAC1D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;CAC3D;AAID,8BAA8B;AAC9B,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core — Temporal Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Domain-neutral time model: points in time, ranges, durations, grid
|
|
5
|
+
* resolution, formatting. All types are immutable (readonly properties).
|
|
6
|
+
* No framework dependencies. No DOM. No calendar-domain concepts.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
declare const MonthBrand: unique symbol;
|
|
2
|
+
/** Calendar month, 0-based (January = 0 … December = 11). House convention. */
|
|
3
|
+
export type Month = number & {
|
|
4
|
+
readonly [MonthBrand]: 'Month';
|
|
5
|
+
};
|
|
6
|
+
export declare const Month: {
|
|
7
|
+
readonly January: Month;
|
|
8
|
+
readonly February: Month;
|
|
9
|
+
readonly March: Month;
|
|
10
|
+
readonly April: Month;
|
|
11
|
+
readonly May: Month;
|
|
12
|
+
readonly June: Month;
|
|
13
|
+
readonly July: Month;
|
|
14
|
+
readonly August: Month;
|
|
15
|
+
readonly September: Month;
|
|
16
|
+
readonly October: Month;
|
|
17
|
+
readonly November: Month;
|
|
18
|
+
readonly December: Month;
|
|
19
|
+
};
|
|
20
|
+
/** Brand a COMPUTED month value. Validates integer 0..11 (January=0 … December=11); throws otherwise. */
|
|
21
|
+
export declare function monthIndex(n: number): Month;
|
|
22
|
+
declare const WeekdayBrand: unique symbol;
|
|
23
|
+
/** Day of week, 0-based Monday (Monday = 0 … Sunday = 6). A HOUSE convention — NOT ISO-8601 (1–7)
|
|
24
|
+
* and NOT JS `Date.getDay()` (0 = Sunday). */
|
|
25
|
+
export type Weekday = number & {
|
|
26
|
+
readonly [WeekdayBrand]: 'Weekday';
|
|
27
|
+
};
|
|
28
|
+
export declare const Weekday: {
|
|
29
|
+
readonly Monday: Weekday;
|
|
30
|
+
readonly Tuesday: Weekday;
|
|
31
|
+
readonly Wednesday: Weekday;
|
|
32
|
+
readonly Thursday: Weekday;
|
|
33
|
+
readonly Friday: Weekday;
|
|
34
|
+
readonly Saturday: Weekday;
|
|
35
|
+
readonly Sunday: Weekday;
|
|
36
|
+
};
|
|
37
|
+
/** Brand a COMPUTED weekday value. Validates integer 0..6 (Monday=0 … Sunday=6); throws otherwise. */
|
|
38
|
+
export declare function weekdayIndex(n: number): Weekday;
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=vocabulary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vocabulary.d.ts","sourceRoot":"","sources":["../src/vocabulary.ts"],"names":[],"mappings":"AAeA,OAAO,CAAC,MAAM,UAAU,EAAE,OAAO,MAAM,CAAC;AACxC,+EAA+E;AAC/E,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAChE,eAAO,MAAM,KAAK;sBACF,KAAK;uBAAiB,KAAK;oBAAc,KAAK;oBAAc,KAAK;kBACrE,KAAK;mBAAa,KAAK;mBAAa,KAAK;qBAAe,KAAK;wBACvD,KAAK;sBAAgB,KAAK;uBAAkB,KAAK;uBAAkB,KAAK;CAChF,CAAC;AAEX,yGAAyG;AACzG,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,KAAK,CAK3C;AAED,OAAO,CAAC,MAAM,YAAY,EAAE,OAAO,MAAM,CAAC;AAC1C;+CAC+C;AAC/C,MAAM,MAAM,OAAO,GAAG,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,YAAY,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AACtE,eAAO,MAAM,OAAO;qBACL,OAAO;sBAAgB,OAAO;wBAAkB,OAAO;uBAAiB,OAAO;qBAC/E,OAAO;uBAAiB,OAAO;qBAAe,OAAO;CAC1D,CAAC;AAEX,sGAAsG;AACtG,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAK/C"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Branded calendar vocabulary — `Month` and `Weekday`.
|
|
3
|
+
*
|
|
4
|
+
* WHY BRANDED (freeze rule, V1_PUBLIC_CONTRACT): a numeric parameter gets a branded vocabulary
|
|
5
|
+
* exactly when several LIVE conventions compete for the same number. `month` (0- vs 1-based) and
|
|
6
|
+
* `weekday` (0=Mon vs 0=Sun vs ISO 1–7) both qualify; `day` (always 1-based) and `hour`/`minute`
|
|
7
|
+
* (clock convention) do NOT. The brand makes a naked number a COMPILE error where a Month/Weekday is
|
|
8
|
+
* expected — a numeric enum/union would silently accept in-range literals and NOT close the trap.
|
|
9
|
+
*
|
|
10
|
+
* The internal representation is UNCHANGED (Month 0-based, Weekday 0=Monday) — this is a vocabulary,
|
|
11
|
+
* not a semantic flip. Use `Month.January`…`Month.December` / `Weekday.Monday`…`Weekday.Sunday` for
|
|
12
|
+
* literals, or `monthIndex(n)` / `weekdayIndex(n)` for COMPUTED values (they validate + brand).
|
|
13
|
+
*/
|
|
14
|
+
import { CalendarValidationError } from './errors.js';
|
|
15
|
+
export const Month = {
|
|
16
|
+
January: 0, February: 1, March: 2, April: 3,
|
|
17
|
+
May: 4, June: 5, July: 6, August: 7,
|
|
18
|
+
September: 8, October: 9, November: 10, December: 11,
|
|
19
|
+
};
|
|
20
|
+
/** Brand a COMPUTED month value. Validates integer 0..11 (January=0 … December=11); throws otherwise. */
|
|
21
|
+
export function monthIndex(n) {
|
|
22
|
+
if (!Number.isInteger(n) || n < 0 || n > 11) {
|
|
23
|
+
throw new CalendarValidationError({ type: 'INVALID_EVENT', field: 'month', message: `month must be an integer 0-11 (January=0 … December=11), got ${n}` });
|
|
24
|
+
}
|
|
25
|
+
return n;
|
|
26
|
+
}
|
|
27
|
+
export const Weekday = {
|
|
28
|
+
Monday: 0, Tuesday: 1, Wednesday: 2, Thursday: 3,
|
|
29
|
+
Friday: 4, Saturday: 5, Sunday: 6,
|
|
30
|
+
};
|
|
31
|
+
/** Brand a COMPUTED weekday value. Validates integer 0..6 (Monday=0 … Sunday=6); throws otherwise. */
|
|
32
|
+
export function weekdayIndex(n) {
|
|
33
|
+
if (!Number.isInteger(n) || n < 0 || n > 6) {
|
|
34
|
+
throw new CalendarValidationError({ type: 'INVALID_EVENT', field: 'weekday', message: `weekday must be an integer 0-6 (Monday=0 … Sunday=6), got ${n}` });
|
|
35
|
+
}
|
|
36
|
+
return n;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=vocabulary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vocabulary.js","sourceRoot":"","sources":["../src/vocabulary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAKtD,MAAM,CAAC,MAAM,KAAK,GAAG;IACnB,OAAO,EAAE,CAAU,EAAE,QAAQ,EAAE,CAAU,EAAE,KAAK,EAAE,CAAU,EAAE,KAAK,EAAE,CAAU;IAC/E,GAAG,EAAE,CAAU,EAAE,IAAI,EAAE,CAAU,EAAE,IAAI,EAAE,CAAU,EAAE,MAAM,EAAE,CAAU;IACvE,SAAS,EAAE,CAAU,EAAE,OAAO,EAAE,CAAU,EAAE,QAAQ,EAAE,EAAW,EAAE,QAAQ,EAAE,EAAW;CAChF,CAAC;AAEX,yGAAyG;AACzG,MAAM,UAAU,UAAU,CAAC,CAAS;IAClC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QAC5C,MAAM,IAAI,uBAAuB,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gEAAgE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7J,CAAC;IACD,OAAO,CAAU,CAAC;AACpB,CAAC;AAMD,MAAM,CAAC,MAAM,OAAO,GAAG;IACrB,MAAM,EAAE,CAAY,EAAE,OAAO,EAAE,CAAY,EAAE,SAAS,EAAE,CAAY,EAAE,QAAQ,EAAE,CAAY;IAC5F,MAAM,EAAE,CAAY,EAAE,QAAQ,EAAE,CAAY,EAAE,MAAM,EAAE,CAAY;CAC1D,CAAC;AAEX,sGAAsG;AACtG,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,IAAI,uBAAuB,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,6DAA6D,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5J,CAAC;IACD,OAAO,CAAY,CAAC;AACtB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bimetal/temporal",
|
|
3
|
+
"version": "0.35.0",
|
|
4
|
+
"description": "Domain-neutral temporal kernel: time model, durations, grid resolution, formatting. Shared across all BIMETAL component families.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"README.md",
|
|
17
|
+
"LICENSE"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc -b",
|
|
21
|
+
"dev": "tsc -b --watch",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"prepublishOnly": "npm run build"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"vitest": "^3.2.1"
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"license": "Apache-2.0",
|
|
32
|
+
"author": "Andreas Biederbeck",
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/bimetal/bimetal.git",
|
|
36
|
+
"directory": "packages/engine/temporal"
|
|
37
|
+
},
|
|
38
|
+
"keywords": [
|
|
39
|
+
"datetime",
|
|
40
|
+
"timezone",
|
|
41
|
+
"duration",
|
|
42
|
+
"temporal",
|
|
43
|
+
"headless"
|
|
44
|
+
]
|
|
45
|
+
}
|