@intech-software/chronera 0.1.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 +190 -0
- package/README.md +6644 -0
- package/dist/calendar/buddhist/adapter.d.ts +2 -0
- package/dist/calendar/buddhist/adapter.js +33 -0
- package/dist/calendar/buddhist/adapter.js.map +1 -0
- package/dist/calendar/buddhist/constants.d.ts +3 -0
- package/dist/calendar/buddhist/constants.js +14 -0
- package/dist/calendar/buddhist/constants.js.map +1 -0
- package/dist/calendar/buddhist/index.d.ts +3 -0
- package/dist/calendar/buddhist/index.js +4 -0
- package/dist/calendar/buddhist/index.js.map +1 -0
- package/dist/calendar/buddhist/validator.d.ts +4 -0
- package/dist/calendar/buddhist/validator.js +60 -0
- package/dist/calendar/buddhist/validator.js.map +1 -0
- package/dist/calendar/gregory/absolute-day.d.ts +12 -0
- package/dist/calendar/gregory/absolute-day.js +14 -0
- package/dist/calendar/gregory/absolute-day.js.map +1 -0
- package/dist/calendar/gregory/adapter.d.ts +3 -0
- package/dist/calendar/gregory/adapter.js +93 -0
- package/dist/calendar/gregory/adapter.js.map +1 -0
- package/dist/calendar/gregory/constants.d.ts +3 -0
- package/dist/calendar/gregory/constants.js +18 -0
- package/dist/calendar/gregory/constants.js.map +1 -0
- package/dist/calendar/gregory/index.d.ts +4 -0
- package/dist/calendar/gregory/index.js +5 -0
- package/dist/calendar/gregory/index.js.map +1 -0
- package/dist/calendar/gregory/leap-year.d.ts +1 -0
- package/dist/calendar/gregory/leap-year.js +2 -0
- package/dist/calendar/gregory/leap-year.js.map +1 -0
- package/dist/calendar/gregory/validator.d.ts +2 -0
- package/dist/calendar/gregory/validator.js +45 -0
- package/dist/calendar/gregory/validator.js.map +1 -0
- package/dist/calendar/hijri/civil-adapter.d.ts +12 -0
- package/dist/calendar/hijri/civil-adapter.js +132 -0
- package/dist/calendar/hijri/civil-adapter.js.map +1 -0
- package/dist/calendar/hijri/index.d.ts +3 -0
- package/dist/calendar/hijri/index.js +4 -0
- package/dist/calendar/hijri/index.js.map +1 -0
- package/dist/calendar/hijri/tabular-adapter.d.ts +4 -0
- package/dist/calendar/hijri/tabular-adapter.js +79 -0
- package/dist/calendar/hijri/tabular-adapter.js.map +1 -0
- package/dist/calendar/hijri/umm-al-qura-adapter.d.ts +4 -0
- package/dist/calendar/hijri/umm-al-qura-adapter.js +27 -0
- package/dist/calendar/hijri/umm-al-qura-adapter.js.map +1 -0
- package/dist/calendar/index.d.ts +13 -0
- package/dist/calendar/index.js +12 -0
- package/dist/calendar/index.js.map +1 -0
- package/dist/calendar/indian/adapter.d.ts +2 -0
- package/dist/calendar/indian/adapter.js +66 -0
- package/dist/calendar/indian/adapter.js.map +1 -0
- package/dist/calendar/indian/constants.d.ts +5 -0
- package/dist/calendar/indian/constants.js +43 -0
- package/dist/calendar/indian/constants.js.map +1 -0
- package/dist/calendar/indian/index.d.ts +3 -0
- package/dist/calendar/indian/index.js +4 -0
- package/dist/calendar/indian/index.js.map +1 -0
- package/dist/calendar/indian/validator.d.ts +6 -0
- package/dist/calendar/indian/validator.js +65 -0
- package/dist/calendar/indian/validator.js.map +1 -0
- package/dist/calendar/japanese/adapter.d.ts +3 -0
- package/dist/calendar/japanese/adapter.js +63 -0
- package/dist/calendar/japanese/adapter.js.map +1 -0
- package/dist/calendar/japanese/constants.d.ts +17 -0
- package/dist/calendar/japanese/constants.js +85 -0
- package/dist/calendar/japanese/constants.js.map +1 -0
- package/dist/calendar/japanese/index.d.ts +3 -0
- package/dist/calendar/japanese/index.js +4 -0
- package/dist/calendar/japanese/index.js.map +1 -0
- package/dist/calendar/japanese/validator.d.ts +5 -0
- package/dist/calendar/japanese/validator.js +76 -0
- package/dist/calendar/japanese/validator.js.map +1 -0
- package/dist/calendar/persian/adapter.d.ts +2 -0
- package/dist/calendar/persian/adapter.js +42 -0
- package/dist/calendar/persian/adapter.js.map +1 -0
- package/dist/calendar/persian/constants.d.ts +5 -0
- package/dist/calendar/persian/constants.js +43 -0
- package/dist/calendar/persian/constants.js.map +1 -0
- package/dist/calendar/persian/index.d.ts +4 -0
- package/dist/calendar/persian/index.js +5 -0
- package/dist/calendar/persian/index.js.map +1 -0
- package/dist/calendar/persian/math.d.ts +24 -0
- package/dist/calendar/persian/math.js +109 -0
- package/dist/calendar/persian/math.js.map +1 -0
- package/dist/calendar/persian/validator.d.ts +4 -0
- package/dist/calendar/persian/validator.js +52 -0
- package/dist/calendar/persian/validator.js.map +1 -0
- package/dist/calendar/registry.d.ts +9 -0
- package/dist/calendar/registry.js +119 -0
- package/dist/calendar/registry.js.map +1 -0
- package/dist/calendar/roc/adapter.d.ts +2 -0
- package/dist/calendar/roc/adapter.js +47 -0
- package/dist/calendar/roc/adapter.js.map +1 -0
- package/dist/calendar/roc/constants.d.ts +6 -0
- package/dist/calendar/roc/constants.js +34 -0
- package/dist/calendar/roc/constants.js.map +1 -0
- package/dist/calendar/roc/index.d.ts +3 -0
- package/dist/calendar/roc/index.js +4 -0
- package/dist/calendar/roc/index.js.map +1 -0
- package/dist/calendar/roc/validator.d.ts +4 -0
- package/dist/calendar/roc/validator.js +52 -0
- package/dist/calendar/roc/validator.js.map +1 -0
- package/dist/calendar/types.d.ts +34 -0
- package/dist/calendar/types.js +2 -0
- package/dist/calendar/types.js.map +1 -0
- package/dist/core/absolute-day.d.ts +8 -0
- package/dist/core/absolute-day.js +39 -0
- package/dist/core/absolute-day.js.map +1 -0
- package/dist/core/calendar-date.d.ts +11 -0
- package/dist/core/calendar-date.js +37 -0
- package/dist/core/calendar-date.js.map +1 -0
- package/dist/core/day-of-year.d.ts +16 -0
- package/dist/core/day-of-year.js +30 -0
- package/dist/core/day-of-year.js.map +1 -0
- package/dist/core/duration.d.ts +2 -0
- package/dist/core/duration.js +31 -0
- package/dist/core/duration.js.map +1 -0
- package/dist/core/fiscal.d.ts +31 -0
- package/dist/core/fiscal.js +45 -0
- package/dist/core/fiscal.js.map +1 -0
- package/dist/core/gregorian-math.d.ts +4 -0
- package/dist/core/gregorian-math.js +30 -0
- package/dist/core/gregorian-math.js.map +1 -0
- package/dist/core/instant.d.ts +6 -0
- package/dist/core/instant.js +26 -0
- package/dist/core/instant.js.map +1 -0
- package/dist/core/integer.d.ts +1 -0
- package/dist/core/integer.js +7 -0
- package/dist/core/integer.js.map +1 -0
- package/dist/core/iso-week.d.ts +19 -0
- package/dist/core/iso-week.js +41 -0
- package/dist/core/iso-week.js.map +1 -0
- package/dist/core/julian-day.d.ts +26 -0
- package/dist/core/julian-day.js +35 -0
- package/dist/core/julian-day.js.map +1 -0
- package/dist/core/local-date-time.d.ts +2 -0
- package/dist/core/local-date-time.js +15 -0
- package/dist/core/local-date-time.js.map +1 -0
- package/dist/core/local-date.d.ts +2 -0
- package/dist/core/local-date.js +22 -0
- package/dist/core/local-date.js.map +1 -0
- package/dist/core/local-time.d.ts +2 -0
- package/dist/core/local-time.js +28 -0
- package/dist/core/local-time.js.map +1 -0
- package/dist/core/range.d.ts +2 -0
- package/dist/core/range.js +9 -0
- package/dist/core/range.js.map +1 -0
- package/dist/create-chronera.d.ts +2 -0
- package/dist/create-chronera.js +59 -0
- package/dist/create-chronera.js.map +1 -0
- package/dist/errors/error-codes.d.ts +1 -0
- package/dist/errors/error-codes.js +2 -0
- package/dist/errors/error-codes.js.map +1 -0
- package/dist/errors/errors.d.ts +16 -0
- package/dist/errors/errors.js +22 -0
- package/dist/errors/errors.js.map +1 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +2 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/format/format-date-range.d.ts +2 -0
- package/dist/format/format-date-range.js +89 -0
- package/dist/format/format-date-range.js.map +1 -0
- package/dist/format/format-date-time.d.ts +2 -0
- package/dist/format/format-date-time.js +51 -0
- package/dist/format/format-date-time.js.map +1 -0
- package/dist/format/format-date.d.ts +4 -0
- package/dist/format/format-date.js +103 -0
- package/dist/format/format-date.js.map +1 -0
- package/dist/format/format-pattern.d.ts +4 -0
- package/dist/format/format-pattern.js +266 -0
- package/dist/format/format-pattern.js.map +1 -0
- package/dist/format/format-relative.d.ts +2 -0
- package/dist/format/format-relative.js +93 -0
- package/dist/format/format-relative.js.map +1 -0
- package/dist/format/format-time.d.ts +2 -0
- package/dist/format/format-time.js +48 -0
- package/dist/format/format-time.js.map +1 -0
- package/dist/format/index.d.ts +13 -0
- package/dist/format/index.js +12 -0
- package/dist/format/index.js.map +1 -0
- package/dist/format/pattern-scanner.d.ts +8 -0
- package/dist/format/pattern-scanner.js +102 -0
- package/dist/format/pattern-scanner.js.map +1 -0
- package/dist/format/presets/japanese-official.d.ts +8 -0
- package/dist/format/presets/japanese-official.js +39 -0
- package/dist/format/presets/japanese-official.js.map +1 -0
- package/dist/format/presets/taiwan-official.d.ts +6 -0
- package/dist/format/presets/taiwan-official.js +23 -0
- package/dist/format/presets/taiwan-official.js.map +1 -0
- package/dist/format/presets/thai-official.d.ts +2 -0
- package/dist/format/presets/thai-official.js +45 -0
- package/dist/format/presets/thai-official.js.map +1 -0
- package/dist/format/presets/types.d.ts +2 -0
- package/dist/format/presets/types.js +2 -0
- package/dist/format/presets/types.js.map +1 -0
- package/dist/format/presets/world-locales.d.ts +29 -0
- package/dist/format/presets/world-locales.js +330 -0
- package/dist/format/presets/world-locales.js.map +1 -0
- package/dist/format/resolve-date-input.d.ts +9 -0
- package/dist/format/resolve-date-input.js +93 -0
- package/dist/format/resolve-date-input.js.map +1 -0
- package/dist/format/rfc2822.d.ts +17 -0
- package/dist/format/rfc2822.js +59 -0
- package/dist/format/rfc2822.js.map +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/engine.d.ts +8 -0
- package/dist/internal/engine.js +11 -0
- package/dist/internal/engine.js.map +1 -0
- package/dist/locale/numbering-system.d.ts +4 -0
- package/dist/locale/numbering-system.js +133 -0
- package/dist/locale/numbering-system.js.map +1 -0
- package/dist/locale/resolve-locale.d.ts +7 -0
- package/dist/locale/resolve-locale.js +51 -0
- package/dist/locale/resolve-locale.js.map +1 -0
- package/dist/locale/types.d.ts +1 -0
- package/dist/locale/types.js +2 -0
- package/dist/locale/types.js.map +1 -0
- package/dist/operations/arithmetic.d.ts +4 -0
- package/dist/operations/arithmetic.js +13 -0
- package/dist/operations/arithmetic.js.map +1 -0
- package/dist/operations/compare.d.ts +5 -0
- package/dist/operations/compare.js +50 -0
- package/dist/operations/compare.js.map +1 -0
- package/dist/operations/convert-calendar-date.d.ts +4 -0
- package/dist/operations/convert-calendar-date.js +54 -0
- package/dist/operations/convert-calendar-date.js.map +1 -0
- package/dist/operations/day-of-year.d.ts +7 -0
- package/dist/operations/day-of-year.js +29 -0
- package/dist/operations/day-of-year.js.map +1 -0
- package/dist/operations/fiscal.d.ts +5 -0
- package/dist/operations/fiscal.js +25 -0
- package/dist/operations/fiscal.js.map +1 -0
- package/dist/operations/iso-week.d.ts +9 -0
- package/dist/operations/iso-week.js +29 -0
- package/dist/operations/iso-week.js.map +1 -0
- package/dist/operations/julian-day.d.ts +6 -0
- package/dist/operations/julian-day.js +37 -0
- package/dist/operations/julian-day.js.map +1 -0
- package/dist/operations/validate.d.ts +10 -0
- package/dist/operations/validate.js +55 -0
- package/dist/operations/validate.js.map +1 -0
- package/dist/parse/field-normalizer.d.ts +1 -0
- package/dist/parse/field-normalizer.js +5 -0
- package/dist/parse/field-normalizer.js.map +1 -0
- package/dist/parse/index.d.ts +4 -0
- package/dist/parse/index.js +4 -0
- package/dist/parse/index.js.map +1 -0
- package/dist/parse/parse-instant.d.ts +2 -0
- package/dist/parse/parse-instant.js +97 -0
- package/dist/parse/parse-instant.js.map +1 -0
- package/dist/parse/parse-local-date.d.ts +2 -0
- package/dist/parse/parse-local-date.js +31 -0
- package/dist/parse/parse-local-date.js.map +1 -0
- package/dist/parse/pattern-parser.d.ts +2 -0
- package/dist/parse/pattern-parser.js +150 -0
- package/dist/parse/pattern-parser.js.map +1 -0
- package/dist/parse/safe-parse.d.ts +3 -0
- package/dist/parse/safe-parse.js +46 -0
- package/dist/parse/safe-parse.js.map +1 -0
- package/dist/public-types.d.ts +209 -0
- package/dist/public-types.js +2 -0
- package/dist/public-types.js.map +1 -0
- package/dist/runtime/bounded-lru.d.ts +11 -0
- package/dist/runtime/bounded-lru.js +42 -0
- package/dist/runtime/bounded-lru.js.map +1 -0
- package/dist/runtime/capabilities.d.ts +5 -0
- package/dist/runtime/capabilities.js +61 -0
- package/dist/runtime/capabilities.js.map +1 -0
- package/dist/runtime/intl-date-time.d.ts +11 -0
- package/dist/runtime/intl-date-time.js +38 -0
- package/dist/runtime/intl-date-time.js.map +1 -0
- package/dist/runtime/intl-number.d.ts +7 -0
- package/dist/runtime/intl-number.js +35 -0
- package/dist/runtime/intl-number.js.map +1 -0
- package/dist/runtime/intl-relative-time.d.ts +7 -0
- package/dist/runtime/intl-relative-time.js +35 -0
- package/dist/runtime/intl-relative-time.js.map +1 -0
- package/dist/runtime/timezone.d.ts +14 -0
- package/dist/runtime/timezone.js +95 -0
- package/dist/runtime/timezone.js.map +1 -0
- package/package.json +155 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import type { DayOfYearFields } from "./core/day-of-year.js";
|
|
2
|
+
import type { FiscalFields, FiscalOptions, QuarterNumber } from "./core/fiscal.js";
|
|
3
|
+
import type { ChroneraErrorCode } from "./errors/error-codes.js";
|
|
4
|
+
import type { PresetName } from "./format/presets/types.js";
|
|
5
|
+
import type { Rfc2822Options } from "./format/rfc2822.js";
|
|
6
|
+
export type { ChroneraErrorCode, DayOfYearFields, FiscalFields, FiscalOptions, PresetName, QuarterNumber, Rfc2822Options, };
|
|
7
|
+
export type BuiltInCalendarId = "iso8601" | "gregory" | "buddhist" | "islamic" | "islamic-civil" | "islamic-tbla" | "islamic-umalqura" | "persian" | "hebrew" | "japanese" | "roc" | "indian" | "coptic" | "ethiopic" | "chinese" | "dangi";
|
|
8
|
+
type ExtensibleIdentifier = string & Record<never, never>;
|
|
9
|
+
export type CalendarId = BuiltInCalendarId | ExtensibleIdentifier;
|
|
10
|
+
export type LocaleId = string;
|
|
11
|
+
export type TimeZoneId = string;
|
|
12
|
+
export type NumberingSystemId = string;
|
|
13
|
+
export type EraId = string;
|
|
14
|
+
export type MonthCode = `M${string}`;
|
|
15
|
+
export interface Instant {
|
|
16
|
+
readonly kind: "instant";
|
|
17
|
+
readonly epochMilliseconds: number;
|
|
18
|
+
}
|
|
19
|
+
export interface LocalDate {
|
|
20
|
+
readonly kind: "local-date";
|
|
21
|
+
readonly year: number;
|
|
22
|
+
readonly month: number;
|
|
23
|
+
readonly day: number;
|
|
24
|
+
}
|
|
25
|
+
export interface LocalTime {
|
|
26
|
+
readonly kind: "local-time";
|
|
27
|
+
readonly hour: number;
|
|
28
|
+
readonly minute: number;
|
|
29
|
+
readonly second: number;
|
|
30
|
+
readonly millisecond: number;
|
|
31
|
+
}
|
|
32
|
+
export interface LocalDateTime {
|
|
33
|
+
readonly kind: "local-date-time";
|
|
34
|
+
readonly date: LocalDate;
|
|
35
|
+
readonly time: LocalTime;
|
|
36
|
+
}
|
|
37
|
+
export interface CalendarDate {
|
|
38
|
+
readonly kind: "calendar-date";
|
|
39
|
+
readonly calendar: CalendarId;
|
|
40
|
+
readonly era?: EraId;
|
|
41
|
+
readonly eraYear?: number;
|
|
42
|
+
readonly year: number;
|
|
43
|
+
readonly monthCode: MonthCode;
|
|
44
|
+
readonly month?: number;
|
|
45
|
+
readonly day: number;
|
|
46
|
+
}
|
|
47
|
+
export interface ZonedDateTime {
|
|
48
|
+
readonly kind: "zoned-date-time";
|
|
49
|
+
readonly instant: Instant;
|
|
50
|
+
readonly timeZone: TimeZoneId;
|
|
51
|
+
readonly calendar: CalendarId;
|
|
52
|
+
}
|
|
53
|
+
export type FormatDateInput = LocalDate | CalendarDate | Instant | Date;
|
|
54
|
+
export interface Duration {
|
|
55
|
+
readonly years?: number;
|
|
56
|
+
readonly months?: number;
|
|
57
|
+
readonly weeks?: number;
|
|
58
|
+
readonly days?: number;
|
|
59
|
+
readonly hours?: number;
|
|
60
|
+
readonly minutes?: number;
|
|
61
|
+
readonly seconds?: number;
|
|
62
|
+
readonly milliseconds?: number;
|
|
63
|
+
}
|
|
64
|
+
export interface DateRange<TDate> {
|
|
65
|
+
readonly start: TDate;
|
|
66
|
+
readonly end: TDate;
|
|
67
|
+
readonly startInclusive: boolean;
|
|
68
|
+
readonly endInclusive: boolean;
|
|
69
|
+
}
|
|
70
|
+
export interface CalendarConversionMetadata {
|
|
71
|
+
readonly requestedCalendar: CalendarId;
|
|
72
|
+
readonly resolvedCalendar: CalendarId;
|
|
73
|
+
readonly engine: "chronera" | "runtime-intl" | "custom";
|
|
74
|
+
readonly algorithm: string;
|
|
75
|
+
readonly deterministic: boolean;
|
|
76
|
+
readonly dataVersion?: string;
|
|
77
|
+
readonly validFrom?: LocalDate;
|
|
78
|
+
readonly validTo?: LocalDate;
|
|
79
|
+
}
|
|
80
|
+
export interface CalendarConversionResult {
|
|
81
|
+
readonly value: CalendarDate;
|
|
82
|
+
readonly metadata: CalendarConversionMetadata;
|
|
83
|
+
}
|
|
84
|
+
export interface ChroneraIssue {
|
|
85
|
+
readonly code: ChroneraErrorCode;
|
|
86
|
+
readonly message: string;
|
|
87
|
+
readonly path?: readonly (string | number)[];
|
|
88
|
+
}
|
|
89
|
+
export type SafeParseResult<T> = {
|
|
90
|
+
readonly success: true;
|
|
91
|
+
readonly value: T;
|
|
92
|
+
} | {
|
|
93
|
+
readonly success: false;
|
|
94
|
+
readonly error: ChroneraIssue;
|
|
95
|
+
};
|
|
96
|
+
export type Comparison = -1 | 0 | 1;
|
|
97
|
+
export interface CalendarPlugin {
|
|
98
|
+
readonly id: CalendarId;
|
|
99
|
+
readonly algorithm: string;
|
|
100
|
+
readonly deterministic: boolean;
|
|
101
|
+
readonly validFrom: LocalDate;
|
|
102
|
+
readonly validTo: LocalDate;
|
|
103
|
+
toIsoDate(date: CalendarDate): LocalDate;
|
|
104
|
+
fromIsoDate(date: LocalDate): CalendarDate;
|
|
105
|
+
validate(date: CalendarDate): readonly ChroneraIssue[];
|
|
106
|
+
}
|
|
107
|
+
export interface ChroneraConfig {
|
|
108
|
+
readonly locale?: LocaleId;
|
|
109
|
+
readonly calendar?: CalendarId;
|
|
110
|
+
readonly numberingSystem?: NumberingSystemId;
|
|
111
|
+
readonly timeZone?: TimeZoneId;
|
|
112
|
+
readonly calendars?: readonly CalendarPlugin[];
|
|
113
|
+
readonly formatterCacheSize?: number;
|
|
114
|
+
}
|
|
115
|
+
export interface ResolvedChroneraOptions {
|
|
116
|
+
readonly locale: LocaleId;
|
|
117
|
+
readonly calendar: CalendarId;
|
|
118
|
+
readonly numberingSystem?: NumberingSystemId;
|
|
119
|
+
readonly timeZone: TimeZoneId;
|
|
120
|
+
readonly formatterCacheSize: number;
|
|
121
|
+
}
|
|
122
|
+
export interface FormatDateBaseOptions {
|
|
123
|
+
readonly locale?: LocaleId;
|
|
124
|
+
readonly calendar?: CalendarId;
|
|
125
|
+
readonly numberingSystem?: NumberingSystemId;
|
|
126
|
+
readonly timeZone?: TimeZoneId;
|
|
127
|
+
readonly fallback?: "error";
|
|
128
|
+
}
|
|
129
|
+
export type FormatDateOptions = FormatDateBaseOptions & ({
|
|
130
|
+
readonly style?: "numeric" | "short" | "medium" | "long" | "full";
|
|
131
|
+
readonly preset?: never;
|
|
132
|
+
} | {
|
|
133
|
+
readonly style?: never;
|
|
134
|
+
readonly preset: PresetName;
|
|
135
|
+
});
|
|
136
|
+
export interface FormatTimeOptions {
|
|
137
|
+
readonly locale?: LocaleId;
|
|
138
|
+
readonly numberingSystem?: NumberingSystemId;
|
|
139
|
+
readonly timeZone?: TimeZoneId;
|
|
140
|
+
readonly style?: "short" | "medium" | "long" | "full";
|
|
141
|
+
readonly hourCycle?: "h11" | "h12" | "h23" | "h24";
|
|
142
|
+
}
|
|
143
|
+
export interface FormatDateTimeOptions extends FormatDateBaseOptions {
|
|
144
|
+
readonly dateStyle?: "short" | "medium" | "long" | "full";
|
|
145
|
+
readonly timeStyle?: "short" | "medium" | "long" | "full";
|
|
146
|
+
readonly hourCycle?: "h11" | "h12" | "h23" | "h24";
|
|
147
|
+
}
|
|
148
|
+
export type FormatDateRangeOptions = FormatDateOptions & {
|
|
149
|
+
readonly collapse?: "auto" | "none";
|
|
150
|
+
};
|
|
151
|
+
export interface FormatRelativeOptions {
|
|
152
|
+
readonly relativeTo: Instant | LocalDate;
|
|
153
|
+
readonly locale?: LocaleId;
|
|
154
|
+
readonly numeric?: "always" | "auto";
|
|
155
|
+
readonly unit?: "second" | "minute" | "hour" | "day" | "week" | "month" | "year";
|
|
156
|
+
readonly timeZone?: TimeZoneId;
|
|
157
|
+
}
|
|
158
|
+
export interface PatternFormatOptions {
|
|
159
|
+
readonly locale?: LocaleId;
|
|
160
|
+
readonly calendar?: CalendarId;
|
|
161
|
+
readonly numberingSystem?: NumberingSystemId;
|
|
162
|
+
readonly timeZone?: TimeZoneId;
|
|
163
|
+
}
|
|
164
|
+
export interface ParseLocalDateOptions {
|
|
165
|
+
readonly pattern?: string;
|
|
166
|
+
readonly locale?: LocaleId;
|
|
167
|
+
readonly calendar?: "gregory" | "iso8601";
|
|
168
|
+
readonly numberingSystem?: NumberingSystemId;
|
|
169
|
+
}
|
|
170
|
+
export interface ParseInstantOptions {
|
|
171
|
+
readonly excessFractionalSeconds?: "reject" | "truncate" | "round";
|
|
172
|
+
}
|
|
173
|
+
export interface ConvertCalendarOptions {
|
|
174
|
+
readonly fallback?: "error";
|
|
175
|
+
}
|
|
176
|
+
export interface CalendarCapabilities {
|
|
177
|
+
readonly calendar: CalendarId;
|
|
178
|
+
readonly maturity: "stable" | "experimental" | "runtime-dependent" | "planned" | "unsupported";
|
|
179
|
+
readonly canFormat: boolean;
|
|
180
|
+
readonly canParse: boolean;
|
|
181
|
+
readonly canConvertFromAbsoluteDate: boolean;
|
|
182
|
+
readonly canConvertToAbsoluteDate: boolean;
|
|
183
|
+
readonly canValidate: boolean;
|
|
184
|
+
readonly canAddYears: boolean;
|
|
185
|
+
readonly canAddMonths: boolean;
|
|
186
|
+
readonly deterministic: boolean;
|
|
187
|
+
readonly algorithm?: string;
|
|
188
|
+
readonly dataVersion?: string;
|
|
189
|
+
readonly validFrom?: LocalDate;
|
|
190
|
+
readonly validTo?: LocalDate;
|
|
191
|
+
}
|
|
192
|
+
export interface RuntimeCapabilities {
|
|
193
|
+
readonly hasDateTimeFormat: boolean;
|
|
194
|
+
readonly hasFormatToParts: boolean;
|
|
195
|
+
readonly hasFormatRange: boolean;
|
|
196
|
+
readonly hasRelativeTimeFormat: boolean;
|
|
197
|
+
readonly hasLocale: boolean;
|
|
198
|
+
readonly hasSupportedValuesOf: boolean;
|
|
199
|
+
readonly hasTemporal: boolean;
|
|
200
|
+
readonly calendars: Readonly<Record<string, boolean>>;
|
|
201
|
+
readonly timeZones: Readonly<Record<string, boolean>>;
|
|
202
|
+
}
|
|
203
|
+
export interface ChroneraInstance {
|
|
204
|
+
formatDate(input: FormatDateInput, options?: Readonly<FormatDateOptions>): string;
|
|
205
|
+
parseLocalDate(input: string, options?: Readonly<ParseLocalDateOptions>): LocalDate;
|
|
206
|
+
convertCalendarDate(source: CalendarDate, targetCalendar: CalendarId, options?: Readonly<ConvertCalendarOptions>): CalendarConversionResult;
|
|
207
|
+
resolvedOptions(): ResolvedChroneraOptions;
|
|
208
|
+
}
|
|
209
|
+
export type { IsoWeekFields } from "./core/iso-week.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"public-types.js","sourceRoot":"","sources":["../src/public-types.ts"],"names":[],"mappings":"","sourcesContent":["import type { DayOfYearFields } from \"./core/day-of-year.js\";\nimport type {\n FiscalFields,\n FiscalOptions,\n QuarterNumber,\n} from \"./core/fiscal.js\";\nimport type { ChroneraErrorCode } from \"./errors/error-codes.js\";\nimport type { PresetName } from \"./format/presets/types.js\";\nimport type { Rfc2822Options } from \"./format/rfc2822.js\";\n\nexport type {\n ChroneraErrorCode,\n DayOfYearFields,\n FiscalFields,\n FiscalOptions,\n PresetName,\n QuarterNumber,\n Rfc2822Options,\n};\n\nexport type BuiltInCalendarId =\n | \"iso8601\"\n | \"gregory\"\n | \"buddhist\"\n | \"islamic\"\n | \"islamic-civil\"\n | \"islamic-tbla\"\n | \"islamic-umalqura\"\n | \"persian\"\n | \"hebrew\"\n | \"japanese\"\n | \"roc\"\n | \"indian\"\n | \"coptic\"\n | \"ethiopic\"\n | \"chinese\"\n | \"dangi\";\n\ntype ExtensibleIdentifier = string & Record<never, never>;\n\nexport type CalendarId = BuiltInCalendarId | ExtensibleIdentifier;\n\nexport type LocaleId = string;\nexport type TimeZoneId = string;\nexport type NumberingSystemId = string;\nexport type EraId = string;\nexport type MonthCode = `M${string}`;\n\nexport interface Instant {\n readonly kind: \"instant\";\n readonly epochMilliseconds: number;\n}\n\nexport interface LocalDate {\n readonly kind: \"local-date\";\n readonly year: number;\n readonly month: number;\n readonly day: number;\n}\n\nexport interface LocalTime {\n readonly kind: \"local-time\";\n readonly hour: number;\n readonly minute: number;\n readonly second: number;\n readonly millisecond: number;\n}\n\nexport interface LocalDateTime {\n readonly kind: \"local-date-time\";\n readonly date: LocalDate;\n readonly time: LocalTime;\n}\n\nexport interface CalendarDate {\n readonly kind: \"calendar-date\";\n readonly calendar: CalendarId;\n readonly era?: EraId;\n readonly eraYear?: number;\n readonly year: number;\n readonly monthCode: MonthCode;\n readonly month?: number;\n readonly day: number;\n}\n\nexport interface ZonedDateTime {\n readonly kind: \"zoned-date-time\";\n readonly instant: Instant;\n readonly timeZone: TimeZoneId;\n readonly calendar: CalendarId;\n}\n\nexport type FormatDateInput = LocalDate | CalendarDate | Instant | Date;\n\nexport interface Duration {\n readonly years?: number;\n readonly months?: number;\n readonly weeks?: number;\n readonly days?: number;\n readonly hours?: number;\n readonly minutes?: number;\n readonly seconds?: number;\n readonly milliseconds?: number;\n}\n\nexport interface DateRange<TDate> {\n readonly start: TDate;\n readonly end: TDate;\n readonly startInclusive: boolean;\n readonly endInclusive: boolean;\n}\n\nexport interface CalendarConversionMetadata {\n readonly requestedCalendar: CalendarId;\n readonly resolvedCalendar: CalendarId;\n readonly engine: \"chronera\" | \"runtime-intl\" | \"custom\";\n readonly algorithm: string;\n readonly deterministic: boolean;\n readonly dataVersion?: string;\n readonly validFrom?: LocalDate;\n readonly validTo?: LocalDate;\n}\n\nexport interface CalendarConversionResult {\n readonly value: CalendarDate;\n readonly metadata: CalendarConversionMetadata;\n}\n\nexport interface ChroneraIssue {\n readonly code: ChroneraErrorCode;\n readonly message: string;\n readonly path?: readonly (string | number)[];\n}\n\nexport type SafeParseResult<T> =\n | {\n readonly success: true;\n readonly value: T;\n }\n | {\n readonly success: false;\n readonly error: ChroneraIssue;\n };\n\nexport type Comparison = -1 | 0 | 1;\n\nexport interface CalendarPlugin {\n readonly id: CalendarId;\n readonly algorithm: string;\n readonly deterministic: boolean;\n readonly validFrom: LocalDate;\n readonly validTo: LocalDate;\n toIsoDate(date: CalendarDate): LocalDate;\n fromIsoDate(date: LocalDate): CalendarDate;\n validate(date: CalendarDate): readonly ChroneraIssue[];\n}\n\nexport interface ChroneraConfig {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly calendars?: readonly CalendarPlugin[];\n readonly formatterCacheSize?: number;\n}\n\nexport interface ResolvedChroneraOptions {\n readonly locale: LocaleId;\n readonly calendar: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone: TimeZoneId;\n readonly formatterCacheSize: number;\n}\n\nexport interface FormatDateBaseOptions {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly fallback?: \"error\";\n}\n\nexport type FormatDateOptions = FormatDateBaseOptions &\n (\n | {\n readonly style?: \"numeric\" | \"short\" | \"medium\" | \"long\" | \"full\";\n readonly preset?: never;\n }\n | {\n readonly style?: never;\n readonly preset: PresetName;\n }\n );\n\nexport interface FormatTimeOptions {\n readonly locale?: LocaleId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n readonly style?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly hourCycle?: \"h11\" | \"h12\" | \"h23\" | \"h24\";\n}\n\nexport interface FormatDateTimeOptions extends FormatDateBaseOptions {\n readonly dateStyle?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly timeStyle?: \"short\" | \"medium\" | \"long\" | \"full\";\n readonly hourCycle?: \"h11\" | \"h12\" | \"h23\" | \"h24\";\n}\n\nexport type FormatDateRangeOptions = FormatDateOptions & {\n readonly collapse?: \"auto\" | \"none\";\n};\n\nexport interface FormatRelativeOptions {\n readonly relativeTo: Instant | LocalDate;\n readonly locale?: LocaleId;\n readonly numeric?: \"always\" | \"auto\";\n readonly unit?:\n \"second\" | \"minute\" | \"hour\" | \"day\" | \"week\" | \"month\" | \"year\";\n readonly timeZone?: TimeZoneId;\n}\n\nexport interface PatternFormatOptions {\n readonly locale?: LocaleId;\n readonly calendar?: CalendarId;\n readonly numberingSystem?: NumberingSystemId;\n readonly timeZone?: TimeZoneId;\n}\n\nexport interface ParseLocalDateOptions {\n readonly pattern?: string;\n readonly locale?: LocaleId;\n readonly calendar?: \"gregory\" | \"iso8601\";\n readonly numberingSystem?: NumberingSystemId;\n}\n\nexport interface ParseInstantOptions {\n readonly excessFractionalSeconds?: \"reject\" | \"truncate\" | \"round\";\n}\n\nexport interface ConvertCalendarOptions {\n readonly fallback?: \"error\";\n}\n\nexport interface CalendarCapabilities {\n readonly calendar: CalendarId;\n readonly maturity:\n \"stable\" | \"experimental\" | \"runtime-dependent\" | \"planned\" | \"unsupported\";\n readonly canFormat: boolean;\n readonly canParse: boolean;\n readonly canConvertFromAbsoluteDate: boolean;\n readonly canConvertToAbsoluteDate: boolean;\n readonly canValidate: boolean;\n readonly canAddYears: boolean;\n readonly canAddMonths: boolean;\n readonly deterministic: boolean;\n readonly algorithm?: string;\n readonly dataVersion?: string;\n readonly validFrom?: LocalDate;\n readonly validTo?: LocalDate;\n}\n\nexport interface RuntimeCapabilities {\n readonly hasDateTimeFormat: boolean;\n readonly hasFormatToParts: boolean;\n readonly hasFormatRange: boolean;\n readonly hasRelativeTimeFormat: boolean;\n readonly hasLocale: boolean;\n readonly hasSupportedValuesOf: boolean;\n readonly hasTemporal: boolean;\n readonly calendars: Readonly<Record<string, boolean>>;\n readonly timeZones: Readonly<Record<string, boolean>>;\n}\n\nexport interface ChroneraInstance {\n formatDate(\n input: FormatDateInput,\n options?: Readonly<FormatDateOptions>,\n ): string;\n parseLocalDate(\n input: string,\n options?: Readonly<ParseLocalDateOptions>,\n ): LocalDate;\n convertCalendarDate(\n source: CalendarDate,\n targetCalendar: CalendarId,\n options?: Readonly<ConvertCalendarOptions>,\n ): CalendarConversionResult;\n resolvedOptions(): ResolvedChroneraOptions;\n}\n\nexport type { IsoWeekFields } from \"./core/iso-week.js\";\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare class BoundedLRU<T> {
|
|
2
|
+
private readonly cache;
|
|
3
|
+
private readonly maxEntries;
|
|
4
|
+
constructor(maxEntries?: number);
|
|
5
|
+
get(key: string): T | undefined;
|
|
6
|
+
set(key: string, value: T): void;
|
|
7
|
+
has(key: string): boolean;
|
|
8
|
+
clear(): void;
|
|
9
|
+
get size(): number;
|
|
10
|
+
get capacity(): number;
|
|
11
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export class BoundedLRU {
|
|
2
|
+
cache = new Map();
|
|
3
|
+
maxEntries;
|
|
4
|
+
constructor(maxEntries = 64) {
|
|
5
|
+
this.maxEntries = Math.max(1, maxEntries);
|
|
6
|
+
}
|
|
7
|
+
get(key) {
|
|
8
|
+
const value = this.cache.get(key);
|
|
9
|
+
if (value !== undefined) {
|
|
10
|
+
// Refresh key order (MRU at end)
|
|
11
|
+
this.cache.delete(key);
|
|
12
|
+
this.cache.set(key, value);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
set(key, value) {
|
|
17
|
+
if (this.cache.has(key)) {
|
|
18
|
+
this.cache.delete(key);
|
|
19
|
+
}
|
|
20
|
+
else if (this.cache.size >= this.maxEntries) {
|
|
21
|
+
// Evict oldest entry (first key in map)
|
|
22
|
+
const oldestKey = this.cache.keys().next().value;
|
|
23
|
+
if (oldestKey !== undefined) {
|
|
24
|
+
this.cache.delete(oldestKey);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
this.cache.set(key, value);
|
|
28
|
+
}
|
|
29
|
+
has(key) {
|
|
30
|
+
return this.cache.has(key);
|
|
31
|
+
}
|
|
32
|
+
clear() {
|
|
33
|
+
this.cache.clear();
|
|
34
|
+
}
|
|
35
|
+
get size() {
|
|
36
|
+
return this.cache.size;
|
|
37
|
+
}
|
|
38
|
+
get capacity() {
|
|
39
|
+
return this.maxEntries;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=bounded-lru.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bounded-lru.js","sourceRoot":"","sources":["../../src/runtime/bounded-lru.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,UAAU;IACJ,KAAK,GAAG,IAAI,GAAG,EAAa,CAAC;IAC7B,UAAU,CAAS;IAEpC,YAAY,aAAqB,EAAE;QACjC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;IAC5C,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,iCAAiC;YACjC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAQ;QACvB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,CAAC;aAAM,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YAC9C,wCAAwC;YACxC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;YACjD,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,GAAG,CAAC,GAAW;QACb,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF","sourcesContent":["export class BoundedLRU<T> {\n private readonly cache = new Map<string, T>();\n private readonly maxEntries: number;\n\n constructor(maxEntries: number = 64) {\n this.maxEntries = Math.max(1, maxEntries);\n }\n\n get(key: string): T | undefined {\n const value = this.cache.get(key);\n if (value !== undefined) {\n // Refresh key order (MRU at end)\n this.cache.delete(key);\n this.cache.set(key, value);\n }\n return value;\n }\n\n set(key: string, value: T): void {\n if (this.cache.has(key)) {\n this.cache.delete(key);\n } else if (this.cache.size >= this.maxEntries) {\n // Evict oldest entry (first key in map)\n const oldestKey = this.cache.keys().next().value;\n if (oldestKey !== undefined) {\n this.cache.delete(oldestKey);\n }\n }\n this.cache.set(key, value);\n }\n\n has(key: string): boolean {\n return this.cache.has(key);\n }\n\n clear(): void {\n this.cache.clear();\n }\n\n get size(): number {\n return this.cache.size;\n }\n\n get capacity(): number {\n return this.maxEntries;\n }\n}\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export function getRuntimeCapabilities(requests) {
|
|
2
|
+
const hasIntl = typeof Intl !== "undefined";
|
|
3
|
+
const hasDateTimeFormat = hasIntl && typeof Intl.DateTimeFormat === "function";
|
|
4
|
+
const hasFormatToParts = hasDateTimeFormat &&
|
|
5
|
+
typeof Intl.DateTimeFormat.prototype.formatToParts === "function";
|
|
6
|
+
const hasFormatRange = hasDateTimeFormat &&
|
|
7
|
+
typeof Intl.DateTimeFormat.prototype
|
|
8
|
+
.formatRange === "function";
|
|
9
|
+
const hasRelativeTimeFormat = hasIntl && typeof Intl.RelativeTimeFormat === "function";
|
|
10
|
+
const hasLocale = hasIntl && typeof Intl.Locale === "function";
|
|
11
|
+
const hasSupportedValuesOf = hasIntl &&
|
|
12
|
+
typeof Intl
|
|
13
|
+
.supportedValuesOf === "function";
|
|
14
|
+
const hasTemporal = typeof globalThis.Temporal !==
|
|
15
|
+
"undefined";
|
|
16
|
+
const calendars = {};
|
|
17
|
+
if (requests?.calendars) {
|
|
18
|
+
for (const cal of requests.calendars) {
|
|
19
|
+
if (!hasDateTimeFormat) {
|
|
20
|
+
calendars[cal] = false;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
const dtf = new Intl.DateTimeFormat("en-US", { calendar: cal });
|
|
25
|
+
const resolved = dtf.resolvedOptions().calendar;
|
|
26
|
+
calendars[cal] = resolved === cal;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
calendars[cal] = false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const timeZones = {};
|
|
34
|
+
if (requests?.timeZones) {
|
|
35
|
+
for (const tz of requests.timeZones) {
|
|
36
|
+
if (!hasDateTimeFormat) {
|
|
37
|
+
timeZones[tz] = false;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
new Intl.DateTimeFormat("en-US", { timeZone: tz });
|
|
42
|
+
timeZones[tz] = true;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
timeZones[tz] = false;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
hasDateTimeFormat,
|
|
51
|
+
hasFormatToParts,
|
|
52
|
+
hasFormatRange,
|
|
53
|
+
hasRelativeTimeFormat,
|
|
54
|
+
hasLocale,
|
|
55
|
+
hasSupportedValuesOf,
|
|
56
|
+
hasTemporal,
|
|
57
|
+
calendars: Object.freeze(calendars),
|
|
58
|
+
timeZones: Object.freeze(timeZones),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=capabilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/runtime/capabilities.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,sBAAsB,CACpC,QAGE;IAEF,MAAM,OAAO,GAAG,OAAO,IAAI,KAAK,WAAW,CAAC;IAC5C,MAAM,iBAAiB,GACrB,OAAO,IAAI,OAAO,IAAI,CAAC,cAAc,KAAK,UAAU,CAAC;IACvD,MAAM,gBAAgB,GACpB,iBAAiB;QACjB,OAAO,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC,aAAa,KAAK,UAAU,CAAC;IACpE,MAAM,cAAc,GAClB,iBAAiB;QACjB,OAAQ,IAAI,CAAC,cAAc,CAAC,SAAuC;aAChE,WAAW,KAAK,UAAU,CAAC;IAChC,MAAM,qBAAqB,GACzB,OAAO,IAAI,OAAO,IAAI,CAAC,kBAAkB,KAAK,UAAU,CAAC;IAC3D,MAAM,SAAS,GAAG,OAAO,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU,CAAC;IAC/D,MAAM,oBAAoB,GACxB,OAAO;QACP,OAAQ,IAAmD;aACxD,iBAAiB,KAAK,UAAU,CAAC;IACtC,MAAM,WAAW,GACf,OAAQ,UAAgD,CAAC,QAAQ;QACjE,WAAW,CAAC;IAEd,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,IAAI,QAAQ,EAAE,SAAS,EAAE,CAAC;QACxB,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YACrC,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACvB,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;gBACvB,SAAS;YACX,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;gBAChE,MAAM,QAAQ,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC,QAAQ,CAAC;gBAChD,SAAS,CAAC,GAAG,CAAC,GAAG,QAAQ,KAAK,GAAG,CAAC;YACpC,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAA4B,EAAE,CAAC;IAC9C,IAAI,QAAQ,EAAE,SAAS,EAAE,CAAC;QACxB,KAAK,MAAM,EAAE,IAAI,QAAQ,CAAC,SAAS,EAAE,CAAC;YACpC,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACvB,SAAS,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,IAAI,CAAC;gBACH,IAAI,IAAI,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;gBACnD,SAAS,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;YACvB,CAAC;YAAC,MAAM,CAAC;gBACP,SAAS,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC;YACxB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,iBAAiB;QACjB,gBAAgB;QAChB,cAAc;QACd,qBAAqB;QACrB,SAAS;QACT,oBAAoB;QACpB,WAAW;QACX,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;QACnC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;KACpC,CAAC;AACJ,CAAC","sourcesContent":["import type {\n CalendarId,\n RuntimeCapabilities,\n TimeZoneId,\n} from \"../public-types.js\";\n\nexport function getRuntimeCapabilities(\n requests?: Readonly<{\n calendars?: readonly CalendarId[];\n timeZones?: readonly TimeZoneId[];\n }>,\n): RuntimeCapabilities {\n const hasIntl = typeof Intl !== \"undefined\";\n const hasDateTimeFormat =\n hasIntl && typeof Intl.DateTimeFormat === \"function\";\n const hasFormatToParts =\n hasDateTimeFormat &&\n typeof Intl.DateTimeFormat.prototype.formatToParts === \"function\";\n const hasFormatRange =\n hasDateTimeFormat &&\n typeof (Intl.DateTimeFormat.prototype as { formatRange?: unknown })\n .formatRange === \"function\";\n const hasRelativeTimeFormat =\n hasIntl && typeof Intl.RelativeTimeFormat === \"function\";\n const hasLocale = hasIntl && typeof Intl.Locale === \"function\";\n const hasSupportedValuesOf =\n hasIntl &&\n typeof (Intl as unknown as { supportedValuesOf?: unknown })\n .supportedValuesOf === \"function\";\n const hasTemporal =\n typeof (globalThis as unknown as { Temporal?: unknown }).Temporal !==\n \"undefined\";\n\n const calendars: Record<string, boolean> = {};\n if (requests?.calendars) {\n for (const cal of requests.calendars) {\n if (!hasDateTimeFormat) {\n calendars[cal] = false;\n continue;\n }\n try {\n const dtf = new Intl.DateTimeFormat(\"en-US\", { calendar: cal });\n const resolved = dtf.resolvedOptions().calendar;\n calendars[cal] = resolved === cal;\n } catch {\n calendars[cal] = false;\n }\n }\n }\n\n const timeZones: Record<string, boolean> = {};\n if (requests?.timeZones) {\n for (const tz of requests.timeZones) {\n if (!hasDateTimeFormat) {\n timeZones[tz] = false;\n continue;\n }\n try {\n new Intl.DateTimeFormat(\"en-US\", { timeZone: tz });\n timeZones[tz] = true;\n } catch {\n timeZones[tz] = false;\n }\n }\n }\n\n return {\n hasDateTimeFormat,\n hasFormatToParts,\n hasFormatRange,\n hasRelativeTimeFormat,\n hasLocale,\n hasSupportedValuesOf,\n hasTemporal,\n calendars: Object.freeze(calendars),\n timeZones: Object.freeze(timeZones),\n };\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface CachedDateTimeFormatOptions extends Intl.DateTimeFormatOptions {
|
|
2
|
+
locale?: string;
|
|
3
|
+
}
|
|
4
|
+
export declare class IntlDateTimeService {
|
|
5
|
+
private readonly cache;
|
|
6
|
+
constructor(cacheSize?: number);
|
|
7
|
+
getFormatter(locale: string, options?: Intl.DateTimeFormatOptions): Intl.DateTimeFormat;
|
|
8
|
+
private createKey;
|
|
9
|
+
clearCache(): void;
|
|
10
|
+
get cacheSize(): number;
|
|
11
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { BoundedLRU } from "./bounded-lru.js";
|
|
2
|
+
import { ChroneraError } from "../errors/errors.js";
|
|
3
|
+
export class IntlDateTimeService {
|
|
4
|
+
cache;
|
|
5
|
+
constructor(cacheSize = 64) {
|
|
6
|
+
this.cache = new BoundedLRU(cacheSize);
|
|
7
|
+
}
|
|
8
|
+
getFormatter(locale, options = {}) {
|
|
9
|
+
const key = this.createKey(locale, options);
|
|
10
|
+
const cached = this.cache.get(key);
|
|
11
|
+
if (cached) {
|
|
12
|
+
return cached;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const formatter = new Intl.DateTimeFormat(locale, options);
|
|
16
|
+
this.cache.set(key, formatter);
|
|
17
|
+
return formatter;
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", `Failed to create DateTimeFormat for locale "${locale}": ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
createKey(locale, options) {
|
|
24
|
+
const keys = Object.keys(options).sort();
|
|
25
|
+
let optsStr = "";
|
|
26
|
+
for (const k of keys) {
|
|
27
|
+
optsStr += `${k}:${String(options[k])};`;
|
|
28
|
+
}
|
|
29
|
+
return `${locale}|${optsStr}`;
|
|
30
|
+
}
|
|
31
|
+
clearCache() {
|
|
32
|
+
this.cache.clear();
|
|
33
|
+
}
|
|
34
|
+
get cacheSize() {
|
|
35
|
+
return this.cache.size;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=intl-date-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intl-date-time.js","sourceRoot":"","sources":["../../src/runtime/intl-date-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAOpD,MAAM,OAAO,mBAAmB;IACb,KAAK,CAAkC;IAExD,YAAY,YAAoB,EAAE;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAAsB,SAAS,CAAC,CAAC;IAC9D,CAAC;IAED,YAAY,CACV,MAAc,EACd,UAAsC,EAAE;QAExC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC3D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,aAAa,CACrB,8BAA8B,EAC9B,+CAA+C,MAAM,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC7G,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,SAAS,CACf,MAAc,EACd,OAAmC;QAEnC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,IAAI,GAAG,CAAC,IAAI,MAAM,CAAE,OAAmC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACxE,CAAC;QACD,OAAO,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF","sourcesContent":["import { BoundedLRU } from \"./bounded-lru.js\";\nimport { ChroneraError } from \"../errors/errors.js\";\n\nexport interface CachedDateTimeFormatOptions\n extends Intl.DateTimeFormatOptions {\n locale?: string;\n}\n\nexport class IntlDateTimeService {\n private readonly cache: BoundedLRU<Intl.DateTimeFormat>;\n\n constructor(cacheSize: number = 64) {\n this.cache = new BoundedLRU<Intl.DateTimeFormat>(cacheSize);\n }\n\n getFormatter(\n locale: string,\n options: Intl.DateTimeFormatOptions = {},\n ): Intl.DateTimeFormat {\n const key = this.createKey(locale, options);\n const cached = this.cache.get(key);\n if (cached) {\n return cached;\n }\n\n try {\n const formatter = new Intl.DateTimeFormat(locale, options);\n this.cache.set(key, formatter);\n return formatter;\n } catch (err) {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n `Failed to create DateTimeFormat for locale \"${locale}\": ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n }\n }\n\n private createKey(\n locale: string,\n options: Intl.DateTimeFormatOptions,\n ): string {\n const keys = Object.keys(options).sort();\n let optsStr = \"\";\n for (const k of keys) {\n optsStr += `${k}:${String((options as Record<string, unknown>)[k])};`;\n }\n return `${locale}|${optsStr}`;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n\n get cacheSize(): number {\n return this.cache.size;\n }\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BoundedLRU } from "./bounded-lru.js";
|
|
2
|
+
import { ChroneraError } from "../errors/errors.js";
|
|
3
|
+
export class IntlNumberService {
|
|
4
|
+
cache;
|
|
5
|
+
constructor(cacheSize = 64) {
|
|
6
|
+
this.cache = new BoundedLRU(cacheSize);
|
|
7
|
+
}
|
|
8
|
+
getFormatter(locale, options = {}) {
|
|
9
|
+
const key = this.createKey(locale, options);
|
|
10
|
+
const cached = this.cache.get(key);
|
|
11
|
+
if (cached) {
|
|
12
|
+
return cached;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const formatter = new Intl.NumberFormat(locale, options);
|
|
16
|
+
this.cache.set(key, formatter);
|
|
17
|
+
return formatter;
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", `Failed to create NumberFormat for locale "${locale}": ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
createKey(locale, options) {
|
|
24
|
+
const keys = Object.keys(options).sort();
|
|
25
|
+
let optsStr = "";
|
|
26
|
+
for (const k of keys) {
|
|
27
|
+
optsStr += `${k}:${String(options[k])};`;
|
|
28
|
+
}
|
|
29
|
+
return `${locale}|${optsStr}`;
|
|
30
|
+
}
|
|
31
|
+
clearCache() {
|
|
32
|
+
this.cache.clear();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=intl-number.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intl-number.js","sourceRoot":"","sources":["../../src/runtime/intl-number.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,OAAO,iBAAiB;IACX,KAAK,CAAgC;IAEtD,YAAY,YAAoB,EAAE;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAAoB,SAAS,CAAC,CAAC;IAC5D,CAAC;IAED,YAAY,CACV,MAAc,EACd,UAAoC,EAAE;QAEtC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,aAAa,CACrB,8BAA8B,EAC9B,6CAA6C,MAAM,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC3G,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,SAAS,CAAC,MAAc,EAAE,OAAiC;QACjE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,IAAI,GAAG,CAAC,IAAI,MAAM,CAAE,OAAmC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACxE,CAAC;QACD,OAAO,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF","sourcesContent":["import { BoundedLRU } from \"./bounded-lru.js\";\nimport { ChroneraError } from \"../errors/errors.js\";\n\nexport class IntlNumberService {\n private readonly cache: BoundedLRU<Intl.NumberFormat>;\n\n constructor(cacheSize: number = 64) {\n this.cache = new BoundedLRU<Intl.NumberFormat>(cacheSize);\n }\n\n getFormatter(\n locale: string,\n options: Intl.NumberFormatOptions = {},\n ): Intl.NumberFormat {\n const key = this.createKey(locale, options);\n const cached = this.cache.get(key);\n if (cached) {\n return cached;\n }\n\n try {\n const formatter = new Intl.NumberFormat(locale, options);\n this.cache.set(key, formatter);\n return formatter;\n } catch (err) {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n `Failed to create NumberFormat for locale \"${locale}\": ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n }\n }\n\n private createKey(locale: string, options: Intl.NumberFormatOptions): string {\n const keys = Object.keys(options).sort();\n let optsStr = \"\";\n for (const k of keys) {\n optsStr += `${k}:${String((options as Record<string, unknown>)[k])};`;\n }\n return `${locale}|${optsStr}`;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n}\n"]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { BoundedLRU } from "./bounded-lru.js";
|
|
2
|
+
import { ChroneraError } from "../errors/errors.js";
|
|
3
|
+
export class IntlRelativeTimeService {
|
|
4
|
+
cache;
|
|
5
|
+
constructor(cacheSize = 64) {
|
|
6
|
+
this.cache = new BoundedLRU(cacheSize);
|
|
7
|
+
}
|
|
8
|
+
getFormatter(locale, options = {}) {
|
|
9
|
+
const key = this.createKey(locale, options);
|
|
10
|
+
const cached = this.cache.get(key);
|
|
11
|
+
if (cached) {
|
|
12
|
+
return cached;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const formatter = new Intl.RelativeTimeFormat(locale, options);
|
|
16
|
+
this.cache.set(key, formatter);
|
|
17
|
+
return formatter;
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
throw new ChroneraError("CHRONERA_INCOMPATIBLE_OPTION", `Failed to create RelativeTimeFormat for locale "${locale}": ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
createKey(locale, options) {
|
|
24
|
+
const keys = Object.keys(options).sort();
|
|
25
|
+
let optsStr = "";
|
|
26
|
+
for (const k of keys) {
|
|
27
|
+
optsStr += `${k}:${String(options[k])};`;
|
|
28
|
+
}
|
|
29
|
+
return `${locale}|${optsStr}`;
|
|
30
|
+
}
|
|
31
|
+
clearCache() {
|
|
32
|
+
this.cache.clear();
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=intl-relative-time.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intl-relative-time.js","sourceRoot":"","sources":["../../src/runtime/intl-relative-time.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,MAAM,OAAO,uBAAuB;IACjB,KAAK,CAAsC;IAE5D,YAAY,YAAoB,EAAE;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAA0B,SAAS,CAAC,CAAC;IAClE,CAAC;IAED,YAAY,CACV,MAAc,EACd,UAA0C,EAAE;QAE5C,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,MAAM,EAAE,CAAC;YACX,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAC/D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;YAC/B,OAAO,SAAS,CAAC;QACnB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,aAAa,CACrB,8BAA8B,EAC9B,mDAAmD,MAAM,MAAM,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACjH,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,SAAS,CACf,MAAc,EACd,OAAuC;QAEvC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QACzC,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,IAAI,GAAG,CAAC,IAAI,MAAM,CAAE,OAAmC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACxE,CAAC;QACD,OAAO,GAAG,MAAM,IAAI,OAAO,EAAE,CAAC;IAChC,CAAC;IAED,UAAU;QACR,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;CACF","sourcesContent":["import { BoundedLRU } from \"./bounded-lru.js\";\nimport { ChroneraError } from \"../errors/errors.js\";\n\nexport class IntlRelativeTimeService {\n private readonly cache: BoundedLRU<Intl.RelativeTimeFormat>;\n\n constructor(cacheSize: number = 64) {\n this.cache = new BoundedLRU<Intl.RelativeTimeFormat>(cacheSize);\n }\n\n getFormatter(\n locale: string,\n options: Intl.RelativeTimeFormatOptions = {},\n ): Intl.RelativeTimeFormat {\n const key = this.createKey(locale, options);\n const cached = this.cache.get(key);\n if (cached) {\n return cached;\n }\n\n try {\n const formatter = new Intl.RelativeTimeFormat(locale, options);\n this.cache.set(key, formatter);\n return formatter;\n } catch (err) {\n throw new ChroneraError(\n \"CHRONERA_INCOMPATIBLE_OPTION\",\n `Failed to create RelativeTimeFormat for locale \"${locale}\": ${err instanceof Error ? err.message : String(err)}`,\n { cause: err },\n );\n }\n }\n\n private createKey(\n locale: string,\n options: Intl.RelativeTimeFormatOptions,\n ): string {\n const keys = Object.keys(options).sort();\n let optsStr = \"\";\n for (const k of keys) {\n optsStr += `${k}:${String((options as Record<string, unknown>)[k])};`;\n }\n return `${locale}|${optsStr}`;\n }\n\n clearCache(): void {\n this.cache.clear();\n }\n}\n"]}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Instant, TimeZoneId } from "../public-types.js";
|
|
2
|
+
export declare function validateTimeZone(timeZone: unknown): asserts timeZone is TimeZoneId;
|
|
3
|
+
export interface ProjectedZonedFields {
|
|
4
|
+
year: number;
|
|
5
|
+
month: number;
|
|
6
|
+
day: number;
|
|
7
|
+
hour: number;
|
|
8
|
+
minute: number;
|
|
9
|
+
second: number;
|
|
10
|
+
millisecond: number;
|
|
11
|
+
era?: string;
|
|
12
|
+
weekday?: number;
|
|
13
|
+
}
|
|
14
|
+
export declare function projectInstantToZonedFields(instant: Instant, timeZone: TimeZoneId): ProjectedZonedFields;
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { ChroneraError } from "../errors/errors.js";
|
|
2
|
+
const DISALLOWED_TIMEZONE_ABBREVIATIONS = new Set([
|
|
3
|
+
"EST",
|
|
4
|
+
"EDT",
|
|
5
|
+
"CST",
|
|
6
|
+
"CDT",
|
|
7
|
+
"MST",
|
|
8
|
+
"MDT",
|
|
9
|
+
"PST",
|
|
10
|
+
"PDT",
|
|
11
|
+
"IST",
|
|
12
|
+
"WET",
|
|
13
|
+
"CET",
|
|
14
|
+
"EET",
|
|
15
|
+
"BST",
|
|
16
|
+
]);
|
|
17
|
+
export function validateTimeZone(timeZone) {
|
|
18
|
+
if (typeof timeZone !== "string" || timeZone.trim().length === 0) {
|
|
19
|
+
throw new ChroneraError("CHRONERA_INVALID_TIME_ZONE", `Invalid time zone identifier: ${String(timeZone)}.`);
|
|
20
|
+
}
|
|
21
|
+
const trimmed = timeZone.trim();
|
|
22
|
+
if (DISALLOWED_TIMEZONE_ABBREVIATIONS.has(trimmed) ||
|
|
23
|
+
/^GMT[+-]\d+$/i.test(trimmed) ||
|
|
24
|
+
/^[+-]\d{2}(:?\d{2})?$/.test(trimmed)) {
|
|
25
|
+
throw new ChroneraError("CHRONERA_INVALID_TIME_ZONE", `Time zone identifier "${trimmed}" is not a valid canonical IANA time zone. Fixed offsets and abbreviations are not allowed.`);
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
new Intl.DateTimeFormat("en-US", { timeZone: trimmed });
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
throw new ChroneraError("CHRONERA_INVALID_TIME_ZONE", `Unsupported or invalid IANA time zone identifier: "${trimmed}".`, { cause: err });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function projectInstantToZonedFields(instant, timeZone) {
|
|
35
|
+
validateTimeZone(timeZone);
|
|
36
|
+
const date = new Date(instant.epochMilliseconds);
|
|
37
|
+
const formatter = new Intl.DateTimeFormat("en-US", {
|
|
38
|
+
timeZone,
|
|
39
|
+
calendar: "gregory",
|
|
40
|
+
hourCycle: "h23",
|
|
41
|
+
year: "numeric",
|
|
42
|
+
month: "numeric",
|
|
43
|
+
day: "numeric",
|
|
44
|
+
hour: "numeric",
|
|
45
|
+
minute: "numeric",
|
|
46
|
+
second: "numeric",
|
|
47
|
+
era: "short",
|
|
48
|
+
weekday: "narrow",
|
|
49
|
+
});
|
|
50
|
+
const parts = formatter.formatToParts(date);
|
|
51
|
+
let year = 0;
|
|
52
|
+
let month = 0;
|
|
53
|
+
let day = 0;
|
|
54
|
+
let hour = 0;
|
|
55
|
+
let minute = 0;
|
|
56
|
+
let second = 0;
|
|
57
|
+
let era;
|
|
58
|
+
for (const part of parts) {
|
|
59
|
+
switch (part.type) {
|
|
60
|
+
case "year":
|
|
61
|
+
year = Number.parseInt(part.value, 10);
|
|
62
|
+
break;
|
|
63
|
+
case "month":
|
|
64
|
+
month = Number.parseInt(part.value, 10);
|
|
65
|
+
break;
|
|
66
|
+
case "day":
|
|
67
|
+
day = Number.parseInt(part.value, 10);
|
|
68
|
+
break;
|
|
69
|
+
case "hour":
|
|
70
|
+
hour = Number.parseInt(part.value, 10);
|
|
71
|
+
break;
|
|
72
|
+
case "minute":
|
|
73
|
+
minute = Number.parseInt(part.value, 10);
|
|
74
|
+
break;
|
|
75
|
+
case "second":
|
|
76
|
+
second = Number.parseInt(part.value, 10);
|
|
77
|
+
break;
|
|
78
|
+
case "era":
|
|
79
|
+
era = part.value;
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const ms = ((instant.epochMilliseconds % 1000) + 1000) % 1000;
|
|
84
|
+
return {
|
|
85
|
+
year,
|
|
86
|
+
month,
|
|
87
|
+
day,
|
|
88
|
+
hour,
|
|
89
|
+
minute,
|
|
90
|
+
second,
|
|
91
|
+
millisecond: ms,
|
|
92
|
+
...(era !== undefined ? { era } : {}),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=timezone.js.map
|