@j13b/scheduler 0.0.0-stage → 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.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -2
  3. package/dist/alterations.d.ts +6 -0
  4. package/dist/alterations.d.ts.map +1 -0
  5. package/dist/alterations.js +61 -0
  6. package/dist/alterations.js.map +1 -0
  7. package/dist/cjs/alterations.d.ts +5 -0
  8. package/dist/cjs/alterations.js +96 -0
  9. package/dist/cjs/dispatcher.d.ts +38 -0
  10. package/dist/cjs/dispatcher.js +165 -0
  11. package/dist/cjs/dispatcher_store.d.ts +9 -0
  12. package/dist/cjs/dispatcher_store.js +15 -0
  13. package/dist/cjs/generators/anchored.d.ts +3 -0
  14. package/dist/cjs/generators/anchored.js +57 -0
  15. package/dist/cjs/generators/days_of_month.d.ts +3 -0
  16. package/dist/cjs/generators/days_of_month.js +76 -0
  17. package/dist/cjs/generators/days_of_week.d.ts +5 -0
  18. package/dist/cjs/generators/days_of_week.js +65 -0
  19. package/dist/cjs/generators/days_of_year.d.ts +3 -0
  20. package/dist/cjs/generators/days_of_year.js +70 -0
  21. package/dist/cjs/generators/instant.d.ts +3 -0
  22. package/dist/cjs/generators/instant.js +15 -0
  23. package/dist/cjs/generators/local_date_time.d.ts +3 -0
  24. package/dist/cjs/generators/local_date_time.js +31 -0
  25. package/dist/cjs/generators/months_of_year.d.ts +3 -0
  26. package/dist/cjs/generators/months_of_year.js +109 -0
  27. package/dist/cjs/generators/types.d.ts +9 -0
  28. package/dist/cjs/generators/types.js +19 -0
  29. package/dist/cjs/generators/weeks_of_month.d.ts +3 -0
  30. package/dist/cjs/generators/weeks_of_month.js +99 -0
  31. package/dist/cjs/generators/yearly.d.ts +3 -0
  32. package/dist/cjs/generators/yearly.js +52 -0
  33. package/dist/cjs/in_memory_port.d.ts +18 -0
  34. package/dist/cjs/in_memory_port.js +59 -0
  35. package/dist/cjs/index.d.ts +6 -0
  36. package/dist/cjs/index.js +14 -0
  37. package/dist/cjs/occurrence_key.d.ts +5 -0
  38. package/dist/cjs/occurrence_key.js +21 -0
  39. package/dist/cjs/package.json +3 -0
  40. package/dist/cjs/port.d.ts +15 -0
  41. package/dist/cjs/port.js +2 -0
  42. package/dist/cjs/scheduler.d.ts +24 -0
  43. package/dist/cjs/scheduler.js +460 -0
  44. package/dist/cjs/types.d.ts +149 -0
  45. package/dist/cjs/types.js +58 -0
  46. package/dist/cjs/tz.d.ts +22 -0
  47. package/dist/cjs/tz.js +197 -0
  48. package/dist/dispatcher.d.ts +39 -0
  49. package/dist/dispatcher.d.ts.map +1 -0
  50. package/dist/dispatcher.js +111 -0
  51. package/dist/dispatcher.js.map +1 -0
  52. package/dist/dispatcher_store.d.ts +10 -0
  53. package/dist/dispatcher_store.d.ts.map +1 -0
  54. package/dist/dispatcher_store.js +13 -0
  55. package/dist/dispatcher_store.js.map +1 -0
  56. package/dist/generators/anchored.d.ts +4 -0
  57. package/dist/generators/anchored.d.ts.map +1 -0
  58. package/dist/generators/anchored.js +42 -0
  59. package/dist/generators/anchored.js.map +1 -0
  60. package/dist/generators/days_of_month.d.ts +4 -0
  61. package/dist/generators/days_of_month.d.ts.map +1 -0
  62. package/dist/generators/days_of_month.js +53 -0
  63. package/dist/generators/days_of_month.js.map +1 -0
  64. package/dist/generators/days_of_week.d.ts +6 -0
  65. package/dist/generators/days_of_week.d.ts.map +1 -0
  66. package/dist/generators/days_of_week.js +43 -0
  67. package/dist/generators/days_of_week.js.map +1 -0
  68. package/dist/generators/days_of_year.d.ts +4 -0
  69. package/dist/generators/days_of_year.d.ts.map +1 -0
  70. package/dist/generators/days_of_year.js +50 -0
  71. package/dist/generators/days_of_year.js.map +1 -0
  72. package/dist/generators/instant.d.ts +4 -0
  73. package/dist/generators/instant.d.ts.map +1 -0
  74. package/dist/generators/instant.js +15 -0
  75. package/dist/generators/instant.js.map +1 -0
  76. package/dist/generators/local_date_time.d.ts +4 -0
  77. package/dist/generators/local_date_time.d.ts.map +1 -0
  78. package/dist/generators/local_date_time.js +20 -0
  79. package/dist/generators/local_date_time.js.map +1 -0
  80. package/dist/generators/months_of_year.d.ts +4 -0
  81. package/dist/generators/months_of_year.d.ts.map +1 -0
  82. package/dist/generators/months_of_year.js +64 -0
  83. package/dist/generators/months_of_year.js.map +1 -0
  84. package/dist/generators/types.d.ts +10 -0
  85. package/dist/generators/types.d.ts.map +1 -0
  86. package/dist/generators/types.js +14 -0
  87. package/dist/generators/types.js.map +1 -0
  88. package/dist/generators/weeks_of_month.d.ts +4 -0
  89. package/dist/generators/weeks_of_month.d.ts.map +1 -0
  90. package/dist/generators/weeks_of_month.js +61 -0
  91. package/dist/generators/weeks_of_month.js.map +1 -0
  92. package/dist/generators/yearly.d.ts +4 -0
  93. package/dist/generators/yearly.d.ts.map +1 -0
  94. package/dist/generators/yearly.js +37 -0
  95. package/dist/generators/yearly.js.map +1 -0
  96. package/dist/in_memory_port.d.ts +19 -0
  97. package/dist/in_memory_port.d.ts.map +1 -0
  98. package/dist/in_memory_port.js +45 -0
  99. package/dist/in_memory_port.js.map +1 -0
  100. package/dist/index.d.ts +7 -0
  101. package/dist/index.d.ts.map +1 -0
  102. package/dist/index.js +6 -0
  103. package/dist/occurrence_key.d.ts +6 -0
  104. package/dist/occurrence_key.d.ts.map +1 -0
  105. package/dist/occurrence_key.js +25 -0
  106. package/dist/occurrence_key.js.map +1 -0
  107. package/dist/port.d.ts +16 -0
  108. package/dist/port.d.ts.map +1 -0
  109. package/dist/scheduler.d.ts +25 -0
  110. package/dist/scheduler.d.ts.map +1 -0
  111. package/dist/scheduler.js +332 -0
  112. package/dist/scheduler.js.map +1 -0
  113. package/dist/types.d.ts +150 -0
  114. package/dist/types.d.ts.map +1 -0
  115. package/dist/types.js +29 -0
  116. package/dist/types.js.map +1 -0
  117. package/dist/tz.d.ts +23 -0
  118. package/dist/tz.d.ts.map +1 -0
  119. package/dist/tz.js +131 -0
  120. package/dist/tz.js.map +1 -0
  121. package/package.json +70 -4
  122. package/src/__tests__/alterations.test.ts +177 -0
  123. package/src/__tests__/anchored.test.ts +107 -0
  124. package/src/__tests__/days_of_month.test.ts +162 -0
  125. package/src/__tests__/days_of_week.test.ts +134 -0
  126. package/src/__tests__/days_of_year.test.ts +158 -0
  127. package/src/__tests__/dispatcher.test.ts +317 -0
  128. package/src/__tests__/instant.test.ts +50 -0
  129. package/src/__tests__/local_date_time.test.ts +139 -0
  130. package/src/__tests__/months_of_year.test.ts +229 -0
  131. package/src/__tests__/scheduler.test.ts +888 -0
  132. package/src/__tests__/tz.test.ts +201 -0
  133. package/src/__tests__/weeks_of_month.test.ts +195 -0
  134. package/src/__tests__/yearly.test.ts +108 -0
  135. package/src/alterations.ts +108 -0
  136. package/src/dispatcher.ts +184 -0
  137. package/src/dispatcher_store.ts +26 -0
  138. package/src/generators/anchored.ts +69 -0
  139. package/src/generators/days_of_month.ts +100 -0
  140. package/src/generators/days_of_week.ts +101 -0
  141. package/src/generators/days_of_year.ts +88 -0
  142. package/src/generators/instant.ts +18 -0
  143. package/src/generators/local_date_time.ts +38 -0
  144. package/src/generators/months_of_year.ts +143 -0
  145. package/src/generators/types.ts +26 -0
  146. package/src/generators/weeks_of_month.ts +133 -0
  147. package/src/generators/yearly.ts +73 -0
  148. package/src/in_memory_port.ts +70 -0
  149. package/src/index.ts +24 -0
  150. package/src/occurrence_key.ts +42 -0
  151. package/src/port.ts +31 -0
  152. package/src/scheduler.ts +499 -0
  153. package/src/types.ts +369 -0
  154. package/src/tz.ts +246 -0
  155. package/tsconfig.json +25 -0
@@ -0,0 +1,43 @@
1
+ import { addDaysInTz, computeSpanEnd, isNonexistentWallTime, utcToWallParts, wallTimeToUtc } from "../tz.js";
2
+ import { TooManyOccurrencesError, intersects } from "./types.js";
3
+ // src/generators/days_of_week.ts
4
+ function generateDaysOfWeek(rule, tz, windowStart, windowEnd, disambiguation = "compatible") {
5
+ if (rule.weekInterval <= 0) throw new Error(`DaysOfWeekRule.weekInterval must be > 0 (got ${rule.weekInterval})`);
6
+ if (rule.days.length === 0) throw new Error("DaysOfWeekRule.days must be non-empty");
7
+ if (rule.count != null && rule.count < 0) throw new Error(`DaysOfWeekRule.count must be >= 0 (got ${rule.count})`);
8
+ const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;
9
+ const effectiveEnd = Math.min(windowEnd, seriesEnd);
10
+ if (rule.seriesStart >= effectiveEnd) return [];
11
+ const days = [...rule.days].sort((a, b) => a - b);
12
+ const seriesStartParts = utcToWallParts(rule.seriesStart, tz);
13
+ const daysSinceSunday = seriesStartParts.dayOfWeek;
14
+ const weekAnchor = wallTimeToUtc(seriesStartParts.year, seriesStartParts.month, seriesStartParts.day - daysSinceSunday, 0, tz);
15
+ const out = [];
16
+ let count = 0;
17
+ let weekStart = weekAnchor;
18
+ while (weekStart < effectiveEnd) {
19
+ for (const dow of days) {
20
+ const dayUtc = addDaysInTz(weekStart, dow, tz);
21
+ const dayParts = utcToWallParts(dayUtc, tz);
22
+ if (disambiguation === "skip" && isNonexistentWallTime(dayParts.year, dayParts.month, dayParts.day, rule.timeOfDay, tz)) continue;
23
+ const occStart = wallTimeToUtc(dayParts.year, dayParts.month, dayParts.day, rule.timeOfDay, tz, disambiguation);
24
+ const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);
25
+ if (occStart < rule.seriesStart) continue;
26
+ if (occStart >= seriesEnd) continue;
27
+ if (rule.count != null && count >= rule.count) return out;
28
+ count++;
29
+ if (intersects(occStart, occEnd, windowStart, windowEnd)) {
30
+ out.push({
31
+ startTimestamp: occStart,
32
+ endTimestamp: occEnd
33
+ });
34
+ if (out.length > 1e4) throw new TooManyOccurrencesError("daysOfWeek");
35
+ }
36
+ }
37
+ weekStart = addDaysInTz(weekStart, 7 * rule.weekInterval, tz);
38
+ }
39
+ return out;
40
+ }
41
+ export { generateDaysOfWeek };
42
+
43
+ //# sourceMappingURL=days_of_week.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"days_of_week.js","names":[],"sources":["../../src/generators/days_of_week.ts"],"sourcesContent":["import type { DaysOfWeekRule, Disambiguation } from \"../types.js\";\nimport {\n addDaysInTz,\n computeSpanEnd,\n dayOfWeekInTz,\n isNonexistentWallTime,\n utcToWallParts,\n wallTimeToUtc,\n} from \"../tz.js\";\nimport {\n MAX_OCCURRENCES_PER_GENERATE,\n type Occurrence,\n TooManyOccurrencesError,\n intersects,\n} from \"./types.js\";\n\n// Iterate week-by-week (in wall time, in tz) starting from seriesStart's\n// week. For each scheduled week, emit the occurrences that fall on the\n// rule's days.\nexport function generateDaysOfWeek(\n rule: DaysOfWeekRule,\n tz: string | undefined,\n windowStart: number,\n windowEnd: number,\n disambiguation: Disambiguation = \"compatible\"\n): Occurrence[] {\n if (rule.weekInterval <= 0) {\n throw new Error(`DaysOfWeekRule.weekInterval must be > 0 (got ${rule.weekInterval})`);\n }\n if (rule.days.length === 0) {\n throw new Error(\"DaysOfWeekRule.days must be non-empty\");\n }\n if (rule.count != null && rule.count < 0) {\n throw new Error(`DaysOfWeekRule.count must be >= 0 (got ${rule.count})`);\n }\n\n const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;\n const effectiveEnd = Math.min(windowEnd, seriesEnd);\n if (rule.seriesStart >= effectiveEnd) return [];\n\n // Sort days for deterministic emit order within a week.\n const days = [...rule.days].sort((a, b) => a - b);\n\n // Anchor: snap seriesStart to the start of its week (Sunday) in tz.\n const seriesStartParts = utcToWallParts(rule.seriesStart, tz);\n const daysSinceSunday = seriesStartParts.dayOfWeek;\n const weekAnchor = wallTimeToUtc(\n seriesStartParts.year,\n seriesStartParts.month,\n seriesStartParts.day - daysSinceSunday,\n 0,\n tz\n );\n\n const out: Occurrence[] = [];\n let count = 0;\n // Step by `weekInterval` weeks at a time. Use addDaysInTz to handle DST\n // correctly (a week is 7 calendar days, not 7*86400000 ms).\n let weekStart = weekAnchor;\n while (weekStart < effectiveEnd) {\n for (const dow of days) {\n // Compute the day-of-week within this week in tz wall time.\n const dayUtc = addDaysInTz(weekStart, dow, tz);\n const dayParts = utcToWallParts(dayUtc, tz);\n if (\n disambiguation === \"skip\" &&\n isNonexistentWallTime(dayParts.year, dayParts.month, dayParts.day, rule.timeOfDay, tz)\n ) {\n continue;\n }\n const occStart = wallTimeToUtc(\n dayParts.year,\n dayParts.month,\n dayParts.day,\n rule.timeOfDay,\n tz,\n disambiguation\n );\n const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);\n\n // Must be on/after seriesStart and before seriesEnd.\n if (occStart < rule.seriesStart) continue;\n if (occStart >= seriesEnd) continue;\n\n if (rule.count != null && count >= rule.count) return out;\n count++;\n\n if (intersects(occStart, occEnd, windowStart, windowEnd)) {\n out.push({ startTimestamp: occStart, endTimestamp: occEnd });\n if (out.length > MAX_OCCURRENCES_PER_GENERATE) {\n throw new TooManyOccurrencesError(\"daysOfWeek\");\n }\n }\n }\n weekStart = addDaysInTz(weekStart, 7 * rule.weekInterval, tz);\n }\n return out;\n}\n\n// Re-export so consumers can sanity-check the rule's first day in tz.\nexport { dayOfWeekInTz };\n"],"mappings":";;;AAmBA,SAAgB,mBACd,MACA,IACA,aACA,WACA,iBAAiC,cACnB;CACd,IAAI,KAAK,gBAAgB,GACvB,MAAM,IAAI,MAAM,gDAAgD,KAAK,aAAa,EAAE;CAEtF,IAAI,KAAK,KAAK,WAAW,GACvB,MAAM,IAAI,MAAM,uCAAuC;CAEzD,IAAI,KAAK,SAAS,QAAQ,KAAK,QAAQ,GACrC,MAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,EAAE;CAGzE,MAAM,YAAY,KAAK,aAAa,OAAO;CAC3C,MAAM,eAAe,KAAK,IAAI,WAAW,SAAS;CAClD,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC;CAG9C,MAAM,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAGhD,MAAM,mBAAmB,eAAe,KAAK,aAAa,EAAE;CAC5D,MAAM,kBAAkB,iBAAiB;CACzC,MAAM,aAAa,cACjB,iBAAiB,MACjB,iBAAiB,OACjB,iBAAiB,MAAM,iBACvB,GACA,EACF;CAEA,MAAM,MAAoB,CAAC;CAC3B,IAAI,QAAQ;CAGZ,IAAI,YAAY;CAChB,OAAO,YAAY,cAAc;EAC/B,KAAK,MAAM,OAAO,MAAM;GAEtB,MAAM,SAAS,YAAY,WAAW,KAAK,EAAE;GAC7C,MAAM,WAAW,eAAe,QAAQ,EAAE;GAC1C,IACE,mBAAmB,UACnB,sBAAsB,SAAS,MAAM,SAAS,OAAO,SAAS,KAAK,KAAK,WAAW,EAAE,GAErF;GAEF,MAAM,WAAW,cACf,SAAS,MACT,SAAS,OACT,SAAS,KACT,KAAK,WACL,IACA,cACF;GACA,MAAM,SAAS,eAAe,UAAU,KAAK,UAAU,EAAE;GAGzD,IAAI,WAAW,KAAK,aAAa;GACjC,IAAI,YAAY,WAAW;GAE3B,IAAI,KAAK,SAAS,QAAQ,SAAS,KAAK,OAAO,OAAO;GACtD;GAEA,IAAI,WAAW,UAAU,QAAQ,aAAa,SAAS,GAAG;IACxD,IAAI,KAAK;KAAE,gBAAgB;KAAU,cAAc;IAAO,CAAC;IAC3D,IAAI,IAAI,SAAA,KACN,MAAM,IAAI,wBAAwB,YAAY;GAElD;EACF;EACA,YAAY,YAAY,WAAW,IAAI,KAAK,cAAc,EAAE;CAC9D;CACA,OAAO;AACT"}
@@ -0,0 +1,4 @@
1
+ import { DaysOfYearRule, Disambiguation } from '../types.js';
2
+ import { Occurrence } from './types.js';
3
+ export declare function generateDaysOfYear(rule: DaysOfYearRule, tz: string | undefined, windowStart: number, windowEnd: number, disambiguation?: Disambiguation): Occurrence[];
4
+ //# sourceMappingURL=days_of_year.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"days_of_year.d.ts","sourceRoot":"","sources":["../../src/generators/days_of_year.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElE,OAAO,EAEL,KAAK,UAAU,EAGhB,MAAM,YAAY,CAAC;AAKpB,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,cAAc,EACpB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,GAAE,cAA6B,GAC5C,UAAU,EAAE,CAqEd"}
@@ -0,0 +1,50 @@
1
+ import { computeSpanEnd, isNonexistentWallTime, utcToWallParts, wallTimeToUtc } from "../tz.js";
2
+ import { TooManyOccurrencesError, intersects } from "./types.js";
3
+ // src/generators/days_of_year.ts
4
+ function generateDaysOfYear(rule, tz, windowStart, windowEnd, disambiguation = "compatible") {
5
+ if (rule.yearInterval <= 0) throw new Error(`DaysOfYearRule.yearInterval must be > 0 (got ${rule.yearInterval})`);
6
+ if (rule.daysOfYear.length === 0) throw new Error("DaysOfYearRule.daysOfYear must be non-empty");
7
+ for (const d of rule.daysOfYear) if (d < 1 || d > 366) throw new Error(`DaysOfYearRule.daysOfYear entries must be in 1..366 (got ${d})`);
8
+ if (rule.count != null && rule.count < 0) throw new Error(`DaysOfYearRule.count must be >= 0 (got ${rule.count})`);
9
+ const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;
10
+ const effectiveEnd = Math.min(windowEnd, seriesEnd);
11
+ if (rule.seriesStart >= effectiveEnd) return [];
12
+ const days = [...new Set(rule.daysOfYear)].sort((a, b) => a - b);
13
+ const startYear = utcToWallParts(rule.seriesStart, tz).year;
14
+ const endYear = utcToWallParts(Math.min(effectiveEnd, Number.MAX_SAFE_INTEGER), tz).year;
15
+ const out = [];
16
+ let count = 0;
17
+ for (let year = startYear; year <= endYear; year += rule.yearInterval) {
18
+ const yearEmits = [];
19
+ for (const dayOfYear of days) {
20
+ const probe = new Date(Date.UTC(year, 0, dayOfYear));
21
+ if (probe.getUTCFullYear() !== year) continue;
22
+ const month = probe.getUTCMonth();
23
+ const day = probe.getUTCDate();
24
+ if (disambiguation === "skip" && isNonexistentWallTime(year, month, day, rule.timeOfDay, tz)) continue;
25
+ const occStart = wallTimeToUtc(year, month, day, rule.timeOfDay, tz, disambiguation);
26
+ const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);
27
+ if (occStart < rule.seriesStart) continue;
28
+ if (occStart >= seriesEnd) continue;
29
+ if (rule.count != null && count >= rule.count) {
30
+ yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);
31
+ out.push(...yearEmits);
32
+ return out;
33
+ }
34
+ count++;
35
+ if (intersects(occStart, occEnd, windowStart, windowEnd)) {
36
+ yearEmits.push({
37
+ startTimestamp: occStart,
38
+ endTimestamp: occEnd
39
+ });
40
+ if (out.length + yearEmits.length > 1e4) throw new TooManyOccurrencesError("daysOfYear");
41
+ }
42
+ }
43
+ yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);
44
+ out.push(...yearEmits);
45
+ }
46
+ return out;
47
+ }
48
+ export { generateDaysOfYear };
49
+
50
+ //# sourceMappingURL=days_of_year.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"days_of_year.js","names":[],"sources":["../../src/generators/days_of_year.ts"],"sourcesContent":["import type { DaysOfYearRule, Disambiguation } from \"../types.js\";\nimport { computeSpanEnd, isNonexistentWallTime, utcToWallParts, wallTimeToUtc } from \"../tz.js\";\nimport {\n MAX_OCCURRENCES_PER_GENERATE,\n type Occurrence,\n TooManyOccurrencesError,\n intersects,\n} from \"./types.js\";\n\n// Day-of-year recurrence. Day 1 = Jan 1. Day 366 only exists in leap\n// years and is SKIPPED in non-leap years (no clamp — \"366th day\" means\n// literally that).\nexport function generateDaysOfYear(\n rule: DaysOfYearRule,\n tz: string | undefined,\n windowStart: number,\n windowEnd: number,\n disambiguation: Disambiguation = \"compatible\"\n): Occurrence[] {\n if (rule.yearInterval <= 0) {\n throw new Error(`DaysOfYearRule.yearInterval must be > 0 (got ${rule.yearInterval})`);\n }\n if (rule.daysOfYear.length === 0) {\n throw new Error(\"DaysOfYearRule.daysOfYear must be non-empty\");\n }\n for (const d of rule.daysOfYear) {\n if (d < 1 || d > 366) {\n throw new Error(`DaysOfYearRule.daysOfYear entries must be in 1..366 (got ${d})`);\n }\n }\n if (rule.count != null && rule.count < 0) {\n throw new Error(`DaysOfYearRule.count must be >= 0 (got ${rule.count})`);\n }\n\n const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;\n const effectiveEnd = Math.min(windowEnd, seriesEnd);\n if (rule.seriesStart >= effectiveEnd) return [];\n\n const days = [...new Set(rule.daysOfYear)].sort((a, b) => a - b);\n\n const startYear = utcToWallParts(rule.seriesStart, tz).year;\n const endYear = utcToWallParts(Math.min(effectiveEnd, Number.MAX_SAFE_INTEGER), tz).year;\n\n const out: Occurrence[] = [];\n let count = 0;\n\n for (let year = startYear; year <= endYear; year += rule.yearInterval) {\n const yearEmits: Occurrence[] = [];\n\n for (const dayOfYear of days) {\n // Date.UTC(year, 0, N) treats N as \"Nth day from Jan 1\". If N is 366\n // in a non-leap year it rolls into year+1; detect and skip.\n const probe = new Date(Date.UTC(year, 0, dayOfYear));\n if (probe.getUTCFullYear() !== year) continue; // day 366 in non-leap year\n\n const month = probe.getUTCMonth();\n const day = probe.getUTCDate();\n if (\n disambiguation === \"skip\" &&\n isNonexistentWallTime(year, month, day, rule.timeOfDay, tz)\n ) {\n continue;\n }\n const occStart = wallTimeToUtc(year, month, day, rule.timeOfDay, tz, disambiguation);\n const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);\n\n if (occStart < rule.seriesStart) continue;\n if (occStart >= seriesEnd) continue;\n\n if (rule.count != null && count >= rule.count) {\n yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);\n out.push(...yearEmits);\n return out;\n }\n count++;\n\n if (intersects(occStart, occEnd, windowStart, windowEnd)) {\n yearEmits.push({ startTimestamp: occStart, endTimestamp: occEnd });\n if (out.length + yearEmits.length > MAX_OCCURRENCES_PER_GENERATE) {\n throw new TooManyOccurrencesError(\"daysOfYear\");\n }\n }\n }\n yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);\n out.push(...yearEmits);\n }\n return out;\n}\n"],"mappings":";;;AAYA,SAAgB,mBACd,MACA,IACA,aACA,WACA,iBAAiC,cACnB;CACd,IAAI,KAAK,gBAAgB,GACvB,MAAM,IAAI,MAAM,gDAAgD,KAAK,aAAa,EAAE;CAEtF,IAAI,KAAK,WAAW,WAAW,GAC7B,MAAM,IAAI,MAAM,6CAA6C;CAE/D,KAAK,MAAM,KAAK,KAAK,YACnB,IAAI,IAAI,KAAK,IAAI,KACf,MAAM,IAAI,MAAM,4DAA4D,EAAE,EAAE;CAGpF,IAAI,KAAK,SAAS,QAAQ,KAAK,QAAQ,GACrC,MAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,EAAE;CAGzE,MAAM,YAAY,KAAK,aAAa,OAAO;CAC3C,MAAM,eAAe,KAAK,IAAI,WAAW,SAAS;CAClD,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC;CAE9C,MAAM,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAE/D,MAAM,YAAY,eAAe,KAAK,aAAa,EAAE,CAAC,CAAC;CACvD,MAAM,UAAU,eAAe,KAAK,IAAI,cAAc,OAAO,gBAAgB,GAAG,EAAE,CAAC,CAAC;CAEpF,MAAM,MAAoB,CAAC;CAC3B,IAAI,QAAQ;CAEZ,KAAK,IAAI,OAAO,WAAW,QAAQ,SAAS,QAAQ,KAAK,cAAc;EACrE,MAAM,YAA0B,CAAC;EAEjC,KAAK,MAAM,aAAa,MAAM;GAG5B,MAAM,QAAQ,IAAI,KAAK,KAAK,IAAI,MAAM,GAAG,SAAS,CAAC;GACnD,IAAI,MAAM,eAAe,MAAM,MAAM;GAErC,MAAM,QAAQ,MAAM,YAAY;GAChC,MAAM,MAAM,MAAM,WAAW;GAC7B,IACE,mBAAmB,UACnB,sBAAsB,MAAM,OAAO,KAAK,KAAK,WAAW,EAAE,GAE1D;GAEF,MAAM,WAAW,cAAc,MAAM,OAAO,KAAK,KAAK,WAAW,IAAI,cAAc;GACnF,MAAM,SAAS,eAAe,UAAU,KAAK,UAAU,EAAE;GAEzD,IAAI,WAAW,KAAK,aAAa;GACjC,IAAI,YAAY,WAAW;GAE3B,IAAI,KAAK,SAAS,QAAQ,SAAS,KAAK,OAAO;IAC7C,UAAU,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc;IAC5D,IAAI,KAAK,GAAG,SAAS;IACrB,OAAO;GACT;GACA;GAEA,IAAI,WAAW,UAAU,QAAQ,aAAa,SAAS,GAAG;IACxD,UAAU,KAAK;KAAE,gBAAgB;KAAU,cAAc;IAAO,CAAC;IACjE,IAAI,IAAI,SAAS,UAAU,SAAA,KACzB,MAAM,IAAI,wBAAwB,YAAY;GAElD;EACF;EACA,UAAU,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc;EAC5D,IAAI,KAAK,GAAG,SAAS;CACvB;CACA,OAAO;AACT"}
@@ -0,0 +1,4 @@
1
+ import { InstantRule } from '../types.js';
2
+ import { Occurrence } from './types.js';
3
+ export declare function generateInstant(rule: InstantRule, tz: string | undefined, windowStart: number, windowEnd: number): Occurrence[];
4
+ //# sourceMappingURL=instant.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instant.d.ts","sourceRoot":"","sources":["../../src/generators/instant.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,YAAY,CAAC;AAKzD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,WAAW,EACjB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,GAChB,UAAU,EAAE,CAKd"}
@@ -0,0 +1,15 @@
1
+ import { computeSpanEnd } from "../tz.js";
2
+ import { intersects } from "./types.js";
3
+ // src/generators/instant.ts
4
+ function generateInstant(rule, tz, windowStart, windowEnd) {
5
+ const start = rule.startOn;
6
+ const end = computeSpanEnd(start, rule.timeSpan, tz);
7
+ if (!intersects(start, end, windowStart, windowEnd)) return [];
8
+ return [{
9
+ startTimestamp: start,
10
+ endTimestamp: end
11
+ }];
12
+ }
13
+ export { generateInstant };
14
+
15
+ //# sourceMappingURL=instant.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instant.js","names":[],"sources":["../../src/generators/instant.ts"],"sourcesContent":["import type { InstantRule } from \"../types.js\";\nimport { computeSpanEnd } from \"../tz.js\";\nimport { type Occurrence, intersects } from \"./types.js\";\n\n// A single occurrence at an absolute UTC instant. The template timezone does\n// not affect the start (the instant is already a fixed point on the timeline);\n// it only flexes an hourSpan end, via computeSpanEnd.\nexport function generateInstant(\n rule: InstantRule,\n tz: string | undefined,\n windowStart: number,\n windowEnd: number\n): Occurrence[] {\n const start = rule.startOn;\n const end = computeSpanEnd(start, rule.timeSpan, tz);\n if (!intersects(start, end, windowStart, windowEnd)) return [];\n return [{ startTimestamp: start, endTimestamp: end }];\n}\n"],"mappings":";;;AAOA,SAAgB,gBACd,MACA,IACA,aACA,WACc;CACd,MAAM,QAAQ,KAAK;CACnB,MAAM,MAAM,eAAe,OAAO,KAAK,UAAU,EAAE;CACnD,IAAI,CAAC,WAAW,OAAO,KAAK,aAAa,SAAS,GAAG,OAAO,CAAC;CAC7D,OAAO,CAAC;EAAE,gBAAgB;EAAO,cAAc;CAAI,CAAC;AACtD"}
@@ -0,0 +1,4 @@
1
+ import { Disambiguation, LocalDateTimeRule } from '../types.js';
2
+ import { Occurrence } from './types.js';
3
+ export declare function generateLocalDateTime(rule: LocalDateTimeRule, tz: string | undefined, windowStart: number, windowEnd: number, disambiguation?: Disambiguation): Occurrence[];
4
+ //# sourceMappingURL=local_date_time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local_date_time.d.ts","sourceRoot":"","sources":["../../src/generators/local_date_time.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAErE,OAAO,EAAE,KAAK,UAAU,EAAc,MAAM,YAAY,CAAC;AAOzD,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,GAAE,cAA6B,GAC5C,UAAU,EAAE,CAsBd"}
@@ -0,0 +1,20 @@
1
+ import { computeSpanEnd, isNonexistentWallTime, monthLength, wallTimeToUtc } from "../tz.js";
2
+ import { intersects } from "./types.js";
3
+ // src/generators/local_date_time.ts
4
+ function generateLocalDateTime(rule, tz, windowStart, windowEnd, disambiguation = "compatible") {
5
+ if (!Number.isInteger(rule.year)) throw new Error(`LocalDateTimeRule.year must be an integer (got ${rule.year})`);
6
+ if (rule.month < 0 || rule.month > 11) throw new Error(`LocalDateTimeRule.month must be in 0..11 (got ${rule.month})`);
7
+ if (rule.day < 1 || rule.day > 31) throw new Error(`LocalDateTimeRule.day must be in 1..31 (got ${rule.day})`);
8
+ const day = Math.min(rule.day, monthLength(rule.year, rule.month));
9
+ if (disambiguation === "skip" && isNonexistentWallTime(rule.year, rule.month, day, rule.timeOfDay, tz)) return [];
10
+ const start = wallTimeToUtc(rule.year, rule.month, day, rule.timeOfDay, tz, disambiguation);
11
+ const end = computeSpanEnd(start, rule.timeSpan, tz);
12
+ if (!intersects(start, end, windowStart, windowEnd)) return [];
13
+ return [{
14
+ startTimestamp: start,
15
+ endTimestamp: end
16
+ }];
17
+ }
18
+ export { generateLocalDateTime };
19
+
20
+ //# sourceMappingURL=local_date_time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local_date_time.js","names":[],"sources":["../../src/generators/local_date_time.ts"],"sourcesContent":["import type { Disambiguation, LocalDateTimeRule } from \"../types.js\";\nimport { computeSpanEnd, isNonexistentWallTime, monthLength, wallTimeToUtc } from \"../tz.js\";\nimport { type Occurrence, intersects } from \"./types.js\";\n\n// A single occurrence expressed in wall-clock terms, resolved through the\n// template timezone (DST-aware). `day` clamps to the month length. When tz is\n// undefined the wall-clock fields are interpreted as UTC. A spring-forward gap\n// or fall-back overlap on the start is resolved per `disambiguation` (see\n// tz.ts) — \"skip\" drops the occurrence entirely if its wall time doesn't exist.\nexport function generateLocalDateTime(\n rule: LocalDateTimeRule,\n tz: string | undefined,\n windowStart: number,\n windowEnd: number,\n disambiguation: Disambiguation = \"compatible\"\n): Occurrence[] {\n if (!Number.isInteger(rule.year)) {\n throw new Error(`LocalDateTimeRule.year must be an integer (got ${rule.year})`);\n }\n if (rule.month < 0 || rule.month > 11) {\n throw new Error(`LocalDateTimeRule.month must be in 0..11 (got ${rule.month})`);\n }\n if (rule.day < 1 || rule.day > 31) {\n throw new Error(`LocalDateTimeRule.day must be in 1..31 (got ${rule.day})`);\n }\n\n const day = Math.min(rule.day, monthLength(rule.year, rule.month));\n if (\n disambiguation === \"skip\" &&\n isNonexistentWallTime(rule.year, rule.month, day, rule.timeOfDay, tz)\n ) {\n return [];\n }\n const start = wallTimeToUtc(rule.year, rule.month, day, rule.timeOfDay, tz, disambiguation);\n const end = computeSpanEnd(start, rule.timeSpan, tz);\n if (!intersects(start, end, windowStart, windowEnd)) return [];\n return [{ startTimestamp: start, endTimestamp: end }];\n}\n"],"mappings":";;;AASA,SAAgB,sBACd,MACA,IACA,aACA,WACA,iBAAiC,cACnB;CACd,IAAI,CAAC,OAAO,UAAU,KAAK,IAAI,GAC7B,MAAM,IAAI,MAAM,kDAAkD,KAAK,KAAK,EAAE;CAEhF,IAAI,KAAK,QAAQ,KAAK,KAAK,QAAQ,IACjC,MAAM,IAAI,MAAM,iDAAiD,KAAK,MAAM,EAAE;CAEhF,IAAI,KAAK,MAAM,KAAK,KAAK,MAAM,IAC7B,MAAM,IAAI,MAAM,+CAA+C,KAAK,IAAI,EAAE;CAG5E,MAAM,MAAM,KAAK,IAAI,KAAK,KAAK,YAAY,KAAK,MAAM,KAAK,KAAK,CAAC;CACjE,IACE,mBAAmB,UACnB,sBAAsB,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,WAAW,EAAE,GAEpE,OAAO,CAAC;CAEV,MAAM,QAAQ,cAAc,KAAK,MAAM,KAAK,OAAO,KAAK,KAAK,WAAW,IAAI,cAAc;CAC1F,MAAM,MAAM,eAAe,OAAO,KAAK,UAAU,EAAE;CACnD,IAAI,CAAC,WAAW,OAAO,KAAK,aAAa,SAAS,GAAG,OAAO,CAAC;CAC7D,OAAO,CAAC;EAAE,gBAAgB;EAAO,cAAc;CAAI,CAAC;AACtD"}
@@ -0,0 +1,4 @@
1
+ import { Disambiguation, MonthsOfYearRule } from '../types.js';
2
+ import { Occurrence } from './types.js';
3
+ export declare function generateMonthsOfYear(rule: MonthsOfYearRule, tz: string | undefined, windowStart: number, windowEnd: number, disambiguation?: Disambiguation): Occurrence[];
4
+ //# sourceMappingURL=months_of_year.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"months_of_year.d.ts","sourceRoot":"","sources":["../../src/generators/months_of_year.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AASpE,OAAO,EAEL,KAAK,UAAU,EAGhB,MAAM,YAAY,CAAC;AASpB,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,GAAE,cAA6B,GAC5C,UAAU,EAAE,CAgGd"}
@@ -0,0 +1,64 @@
1
+ import { addMonthsInTz, computeSpanEnd, isNonexistentWallTime, monthLength, utcToWallParts, wallTimeToUtc } from "../tz.js";
2
+ import { TooManyOccurrencesError, intersects } from "./types.js";
3
+ // src/generators/months_of_year.ts
4
+ function generateMonthsOfYear(rule, tz, windowStart, windowEnd, disambiguation = "compatible") {
5
+ if (rule.yearInterval <= 0) throw new Error(`MonthsOfYearRule.yearInterval must be > 0 (got ${rule.yearInterval})`);
6
+ if (rule.months.length === 0) throw new Error("MonthsOfYearRule.months must be non-empty");
7
+ for (const m of rule.months) if (m < 0 || m > 11) throw new Error(`MonthsOfYearRule.months entries must be in 0..11 (got ${m})`);
8
+ if (rule.weeks.length === 0) throw new Error("MonthsOfYearRule.weeks must be non-empty");
9
+ for (const w of rule.weeks) if (w === 0 || w < -5 || w > 5) throw new Error(`MonthsOfYearRule.weeks entries must be in [-5..-1] or [1..5] (got ${w})`);
10
+ if (rule.days.length === 0) throw new Error("MonthsOfYearRule.days must be non-empty");
11
+ if (rule.count != null && rule.count < 0) throw new Error(`MonthsOfYearRule.count must be >= 0 (got ${rule.count})`);
12
+ const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;
13
+ const effectiveEnd = Math.min(windowEnd, seriesEnd);
14
+ if (rule.seriesStart >= effectiveEnd) return [];
15
+ const months = [...new Set(rule.months)].sort((a, b) => a - b);
16
+ const weeks = [...new Set(rule.weeks)];
17
+ const weekdays = [...new Set(rule.days)].sort((a, b) => a - b);
18
+ const seriesStartParts = utcToWallParts(rule.seriesStart, tz);
19
+ let yearAnchor = wallTimeToUtc(seriesStartParts.year, 0, 1, 0, tz);
20
+ const out = [];
21
+ let count = 0;
22
+ while (yearAnchor < effectiveEnd) {
23
+ const yp = utcToWallParts(yearAnchor, tz);
24
+ const yearEmits = [];
25
+ for (const month of months) for (const week of weeks) for (const dow of weekdays) {
26
+ const targetDay = _nthWeekdayOfMonth(yp.year, month, dow, week);
27
+ if (targetDay == null) continue;
28
+ if (disambiguation === "skip" && isNonexistentWallTime(yp.year, month, targetDay, rule.timeOfDay, tz)) continue;
29
+ const occStart = wallTimeToUtc(yp.year, month, targetDay, rule.timeOfDay, tz, disambiguation);
30
+ const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);
31
+ if (occStart < rule.seriesStart) continue;
32
+ if (occStart >= seriesEnd) continue;
33
+ if (rule.count != null && count >= rule.count) {
34
+ yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);
35
+ out.push(...yearEmits);
36
+ return out;
37
+ }
38
+ count++;
39
+ if (intersects(occStart, occEnd, windowStart, windowEnd)) {
40
+ yearEmits.push({
41
+ startTimestamp: occStart,
42
+ endTimestamp: occEnd
43
+ });
44
+ if (out.length + yearEmits.length > 1e4) throw new TooManyOccurrencesError("monthsOfYear");
45
+ }
46
+ }
47
+ yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);
48
+ out.push(...yearEmits);
49
+ yearAnchor = addMonthsInTz(yearAnchor, 12 * rule.yearInterval, tz);
50
+ }
51
+ return out;
52
+ }
53
+ function _nthWeekdayOfMonth(year, month, dow, n) {
54
+ const len = monthLength(year, month);
55
+ if (n > 0) {
56
+ const day = 1 + (dow - new Date(Date.UTC(year, month, 1)).getUTCDay() + 7) % 7 + (n - 1) * 7;
57
+ return day <= len ? day : null;
58
+ }
59
+ const day = len - (new Date(Date.UTC(year, month, len)).getUTCDay() - dow + 7) % 7 + (n + 1) * 7;
60
+ return day >= 1 ? day : null;
61
+ }
62
+ export { generateMonthsOfYear };
63
+
64
+ //# sourceMappingURL=months_of_year.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"months_of_year.js","names":[],"sources":["../../src/generators/months_of_year.ts"],"sourcesContent":["import type { Disambiguation, MonthsOfYearRule } from \"../types.js\";\nimport {\n addMonthsInTz,\n computeSpanEnd,\n isNonexistentWallTime,\n monthLength,\n utcToWallParts,\n wallTimeToUtc,\n} from \"../tz.js\";\nimport {\n MAX_OCCURRENCES_PER_GENERATE,\n type Occurrence,\n TooManyOccurrencesError,\n intersects,\n} from \"./types.js\";\n\n// Positional yearly recurrence — top of the positional cascade.\n// (months × weeks-of-month × weekdays, with yearInterval as cadence.)\n//\n// For each year in cadence, walk the selected months; in each month, find\n// the Nth weekday matches (e.g. \"2nd Tuesday\") for each (week, day) pair.\n// If a position doesn't exist that month (e.g. 5th Sunday in a 4-Sunday\n// month), silently skip — same policy as WeeksOfMonthRule.\nexport function generateMonthsOfYear(\n rule: MonthsOfYearRule,\n tz: string | undefined,\n windowStart: number,\n windowEnd: number,\n disambiguation: Disambiguation = \"compatible\"\n): Occurrence[] {\n if (rule.yearInterval <= 0) {\n throw new Error(`MonthsOfYearRule.yearInterval must be > 0 (got ${rule.yearInterval})`);\n }\n if (rule.months.length === 0) {\n throw new Error(\"MonthsOfYearRule.months must be non-empty\");\n }\n for (const m of rule.months) {\n if (m < 0 || m > 11) {\n throw new Error(`MonthsOfYearRule.months entries must be in 0..11 (got ${m})`);\n }\n }\n if (rule.weeks.length === 0) {\n throw new Error(\"MonthsOfYearRule.weeks must be non-empty\");\n }\n for (const w of rule.weeks) {\n if (w === 0 || w < -5 || w > 5) {\n throw new Error(`MonthsOfYearRule.weeks entries must be in [-5..-1] or [1..5] (got ${w})`);\n }\n }\n if (rule.days.length === 0) {\n throw new Error(\"MonthsOfYearRule.days must be non-empty\");\n }\n if (rule.count != null && rule.count < 0) {\n throw new Error(`MonthsOfYearRule.count must be >= 0 (got ${rule.count})`);\n }\n\n const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;\n const effectiveEnd = Math.min(windowEnd, seriesEnd);\n if (rule.seriesStart >= effectiveEnd) return [];\n\n const months = [...new Set(rule.months)].sort((a, b) => a - b);\n const weeks = [...new Set(rule.weeks)];\n const weekdays = [...new Set(rule.days)].sort((a, b) => a - b);\n\n // Anchor at the start of seriesStart's year (in tz), but actually anchor\n // at its first selected month within that year. We iterate year-by-year.\n const seriesStartParts = utcToWallParts(rule.seriesStart, tz);\n let yearAnchor = wallTimeToUtc(seriesStartParts.year, 0, 1, 0, tz);\n\n const out: Occurrence[] = [];\n let count = 0;\n\n while (yearAnchor < effectiveEnd) {\n const yp = utcToWallParts(yearAnchor, tz);\n const yearEmits: Occurrence[] = [];\n\n for (const month of months) {\n for (const week of weeks) {\n for (const dow of weekdays) {\n const targetDay = _nthWeekdayOfMonth(yp.year, month, dow, week);\n if (targetDay == null) continue; // Nth doesn't exist this month\n\n if (\n disambiguation === \"skip\" &&\n isNonexistentWallTime(yp.year, month, targetDay, rule.timeOfDay, tz)\n ) {\n continue;\n }\n const occStart = wallTimeToUtc(\n yp.year,\n month,\n targetDay,\n rule.timeOfDay,\n tz,\n disambiguation\n );\n const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);\n\n if (occStart < rule.seriesStart) continue;\n if (occStart >= seriesEnd) continue;\n\n if (rule.count != null && count >= rule.count) {\n yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);\n out.push(...yearEmits);\n return out;\n }\n count++;\n\n if (intersects(occStart, occEnd, windowStart, windowEnd)) {\n yearEmits.push({ startTimestamp: occStart, endTimestamp: occEnd });\n if (out.length + yearEmits.length > MAX_OCCURRENCES_PER_GENERATE) {\n throw new TooManyOccurrencesError(\"monthsOfYear\");\n }\n }\n }\n }\n }\n yearEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);\n out.push(...yearEmits);\n // Step yearInterval years. Use addMonthsInTz(12) so leap-year wall-clock\n // arithmetic is correct (it isn't strictly necessary at year granularity,\n // but matches the rest of the codebase).\n yearAnchor = addMonthsInTz(yearAnchor, 12 * rule.yearInterval, tz);\n }\n return out;\n}\n\n// Same helper as WeeksOfMonth uses. Returns day-of-month (1..31) for the\n// Nth occurrence of `dow` in the given month, or null if it doesn't exist.\nfunction _nthWeekdayOfMonth(year: number, month: number, dow: number, n: number): number | null {\n const len = monthLength(year, month);\n\n if (n > 0) {\n const firstDow = new Date(Date.UTC(year, month, 1)).getUTCDay();\n const offset = (dow - firstDow + 7) % 7;\n const day = 1 + offset + (n - 1) * 7;\n return day <= len ? day : null;\n }\n const lastDow = new Date(Date.UTC(year, month, len)).getUTCDay();\n const offset = (lastDow - dow + 7) % 7;\n const day = len - offset + (n + 1) * 7;\n return day >= 1 ? day : null;\n}\n"],"mappings":";;;AAuBA,SAAgB,qBACd,MACA,IACA,aACA,WACA,iBAAiC,cACnB;CACd,IAAI,KAAK,gBAAgB,GACvB,MAAM,IAAI,MAAM,kDAAkD,KAAK,aAAa,EAAE;CAExF,IAAI,KAAK,OAAO,WAAW,GACzB,MAAM,IAAI,MAAM,2CAA2C;CAE7D,KAAK,MAAM,KAAK,KAAK,QACnB,IAAI,IAAI,KAAK,IAAI,IACf,MAAM,IAAI,MAAM,yDAAyD,EAAE,EAAE;CAGjF,IAAI,KAAK,MAAM,WAAW,GACxB,MAAM,IAAI,MAAM,0CAA0C;CAE5D,KAAK,MAAM,KAAK,KAAK,OACnB,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,GAC3B,MAAM,IAAI,MAAM,qEAAqE,EAAE,EAAE;CAG7F,IAAI,KAAK,KAAK,WAAW,GACvB,MAAM,IAAI,MAAM,yCAAyC;CAE3D,IAAI,KAAK,SAAS,QAAQ,KAAK,QAAQ,GACrC,MAAM,IAAI,MAAM,4CAA4C,KAAK,MAAM,EAAE;CAG3E,MAAM,YAAY,KAAK,aAAa,OAAO;CAC3C,MAAM,eAAe,KAAK,IAAI,WAAW,SAAS;CAClD,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC;CAE9C,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAC7D,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,KAAK,KAAK,CAAC;CACrC,MAAM,WAAW,CAAC,GAAG,IAAI,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAI7D,MAAM,mBAAmB,eAAe,KAAK,aAAa,EAAE;CAC5D,IAAI,aAAa,cAAc,iBAAiB,MAAM,GAAG,GAAG,GAAG,EAAE;CAEjE,MAAM,MAAoB,CAAC;CAC3B,IAAI,QAAQ;CAEZ,OAAO,aAAa,cAAc;EAChC,MAAM,KAAK,eAAe,YAAY,EAAE;EACxC,MAAM,YAA0B,CAAC;EAEjC,KAAK,MAAM,SAAS,QAClB,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,OAAO,UAAU;GAC1B,MAAM,YAAY,mBAAmB,GAAG,MAAM,OAAO,KAAK,IAAI;GAC9D,IAAI,aAAa,MAAM;GAEvB,IACE,mBAAmB,UACnB,sBAAsB,GAAG,MAAM,OAAO,WAAW,KAAK,WAAW,EAAE,GAEnE;GAEF,MAAM,WAAW,cACf,GAAG,MACH,OACA,WACA,KAAK,WACL,IACA,cACF;GACA,MAAM,SAAS,eAAe,UAAU,KAAK,UAAU,EAAE;GAEzD,IAAI,WAAW,KAAK,aAAa;GACjC,IAAI,YAAY,WAAW;GAE3B,IAAI,KAAK,SAAS,QAAQ,SAAS,KAAK,OAAO;IAC7C,UAAU,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc;IAC5D,IAAI,KAAK,GAAG,SAAS;IACrB,OAAO;GACT;GACA;GAEA,IAAI,WAAW,UAAU,QAAQ,aAAa,SAAS,GAAG;IACxD,UAAU,KAAK;KAAE,gBAAgB;KAAU,cAAc;IAAO,CAAC;IACjE,IAAI,IAAI,SAAS,UAAU,SAAA,KACzB,MAAM,IAAI,wBAAwB,cAAc;GAEpD;EACF;EAGJ,UAAU,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc;EAC5D,IAAI,KAAK,GAAG,SAAS;EAIrB,aAAa,cAAc,YAAY,KAAK,KAAK,cAAc,EAAE;CACnE;CACA,OAAO;AACT;AAIA,SAAS,mBAAmB,MAAc,OAAe,KAAa,GAA0B;CAC9F,MAAM,MAAM,YAAY,MAAM,KAAK;CAEnC,IAAI,IAAI,GAAG;EAGT,MAAM,MAAM,KADI,MADC,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,UAC9B,IAAW,KAAK,KACZ,IAAI,KAAK;EACnC,OAAO,OAAO,MAAM,MAAM;CAC5B;CAGA,MAAM,MAAM,OAFI,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,UACrC,IAAU,MAAM,KAAK,KACT,IAAI,KAAK;CACrC,OAAO,OAAO,IAAI,MAAM;AAC1B"}
@@ -0,0 +1,10 @@
1
+ export interface Occurrence {
2
+ startTimestamp: number;
3
+ endTimestamp: number;
4
+ }
5
+ export declare const MAX_OCCURRENCES_PER_GENERATE = 10000;
6
+ export declare class TooManyOccurrencesError extends Error {
7
+ constructor(kind: string);
8
+ }
9
+ export declare function intersects(startA: number, endA: number, startB: number, endB: number): boolean;
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/generators/types.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,UAAU;IACzB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;CACtB;AAKD,eAAO,MAAM,4BAA4B,QAAS,CAAC;AAEnD,qBAAa,uBAAwB,SAAQ,KAAK;gBACpC,IAAI,EAAE,MAAM;CAMzB;AAGD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAE9F"}
@@ -0,0 +1,14 @@
1
+ // src/generators/types.ts
2
+ var MAX_OCCURRENCES_PER_GENERATE = 1e4;
3
+ var TooManyOccurrencesError = class extends Error {
4
+ constructor(kind) {
5
+ super(`Generator '${kind}' would emit more than ${MAX_OCCURRENCES_PER_GENERATE} occurrences for the requested window. Narrow the window, increase the interval, or set 'count' on the rule.`);
6
+ this.name = "TooManyOccurrencesError";
7
+ }
8
+ };
9
+ function intersects(startA, endA, startB, endB) {
10
+ return Math.max(startA, startB) < Math.min(endA, endB);
11
+ }
12
+ export { MAX_OCCURRENCES_PER_GENERATE, TooManyOccurrencesError, intersects };
13
+
14
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../src/generators/types.ts"],"sourcesContent":["// Generators emit raw start/end pairs sorted ascending by startTimestamp.\n// Stable per-occurrence keys are assigned downstream (occurrence_key.ts) so\n// keys can be derived consistently across rule kinds.\nexport interface Occurrence {\n startTimestamp: number;\n endTimestamp: number;\n}\n\n// Hard ceiling per generate() call. A misconfigured rule (e.g. 1ms anchored\n// interval over a year-long window) would otherwise produce billions of\n// occurrences; we'd rather throw a clear error than blow heap.\nexport const MAX_OCCURRENCES_PER_GENERATE = 10_000;\n\nexport class TooManyOccurrencesError extends Error {\n constructor(kind: string) {\n super(\n `Generator '${kind}' would emit more than ${MAX_OCCURRENCES_PER_GENERATE} occurrences for the requested window. Narrow the window, increase the interval, or set 'count' on the rule.`\n );\n this.name = \"TooManyOccurrencesError\";\n }\n}\n\n// Half-open intersection: [startA, endA) overlaps [startB, endB)?\nexport function intersects(startA: number, endA: number, startB: number, endB: number): boolean {\n return Math.max(startA, startB) < Math.min(endA, endB);\n}\n"],"mappings":";AAWA,IAAa,+BAA+B;AAE5C,IAAa,0BAAb,cAA6C,MAAM;CACjD,YAAY,MAAc;EACxB,MACE,cAAc,KAAK,yBAAyB,6BAA6B,6GAC3E;EACA,KAAK,OAAO;CACd;AACF;AAGA,SAAgB,WAAW,QAAgB,MAAc,QAAgB,MAAuB;CAC9F,OAAO,KAAK,IAAI,QAAQ,MAAM,IAAI,KAAK,IAAI,MAAM,IAAI;AACvD"}
@@ -0,0 +1,4 @@
1
+ import { Disambiguation, WeeksOfMonthRule } from '../types.js';
2
+ import { Occurrence } from './types.js';
3
+ export declare function generateWeeksOfMonth(rule: WeeksOfMonthRule, tz: string | undefined, windowStart: number, windowEnd: number, disambiguation?: Disambiguation): Occurrence[];
4
+ //# sourceMappingURL=weeks_of_month.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weeks_of_month.d.ts","sourceRoot":"","sources":["../../src/generators/weeks_of_month.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AASpE,OAAO,EAEL,KAAK,UAAU,EAGhB,MAAM,YAAY,CAAC;AAKpB,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,gBAAgB,EACtB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,GAAE,cAA6B,GAC5C,UAAU,EAAE,CAuFd"}
@@ -0,0 +1,61 @@
1
+ import { addMonthsInTz, computeSpanEnd, isNonexistentWallTime, monthLength, utcToWallParts, wallTimeToUtc } from "../tz.js";
2
+ import { TooManyOccurrencesError, intersects } from "./types.js";
3
+ // src/generators/weeks_of_month.ts
4
+ function generateWeeksOfMonth(rule, tz, windowStart, windowEnd, disambiguation = "compatible") {
5
+ if (rule.monthInterval <= 0) throw new Error(`WeeksOfMonthRule.monthInterval must be > 0 (got ${rule.monthInterval})`);
6
+ if (rule.weeks.length === 0) throw new Error("WeeksOfMonthRule.weeks must be non-empty");
7
+ for (const w of rule.weeks) if (w === 0 || w < -5 || w > 5) throw new Error(`WeeksOfMonthRule.weeks entries must be in [-5..-1] or [1..5] (got ${w})`);
8
+ if (rule.days.length === 0) throw new Error("WeeksOfMonthRule.days must be non-empty");
9
+ if (rule.count != null && rule.count < 0) throw new Error(`WeeksOfMonthRule.count must be >= 0 (got ${rule.count})`);
10
+ const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;
11
+ const effectiveEnd = Math.min(windowEnd, seriesEnd);
12
+ if (rule.seriesStart >= effectiveEnd) return [];
13
+ const days = [...rule.days].sort((a, b) => a - b);
14
+ const weeks = [...new Set(rule.weeks)];
15
+ const seriesStartParts = utcToWallParts(rule.seriesStart, tz);
16
+ let monthAnchor = wallTimeToUtc(seriesStartParts.year, seriesStartParts.month, 1, 0, tz);
17
+ const out = [];
18
+ let count = 0;
19
+ while (monthAnchor < effectiveEnd) {
20
+ const mp = utcToWallParts(monthAnchor, tz);
21
+ const monthEmits = [];
22
+ for (const week of weeks) for (const dow of days) {
23
+ const targetDay = _nthWeekdayOfMonth(mp.year, mp.month, dow, week);
24
+ if (targetDay == null) continue;
25
+ if (disambiguation === "skip" && isNonexistentWallTime(mp.year, mp.month, targetDay, rule.timeOfDay, tz)) continue;
26
+ const occStart = wallTimeToUtc(mp.year, mp.month, targetDay, rule.timeOfDay, tz, disambiguation);
27
+ const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);
28
+ if (occStart < rule.seriesStart) continue;
29
+ if (occStart >= seriesEnd) continue;
30
+ if (rule.count != null && count >= rule.count) {
31
+ monthEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);
32
+ out.push(...monthEmits);
33
+ return out;
34
+ }
35
+ count++;
36
+ if (intersects(occStart, occEnd, windowStart, windowEnd)) {
37
+ monthEmits.push({
38
+ startTimestamp: occStart,
39
+ endTimestamp: occEnd
40
+ });
41
+ if (out.length + monthEmits.length > 1e4) throw new TooManyOccurrencesError("weeksOfMonth");
42
+ }
43
+ }
44
+ monthEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);
45
+ out.push(...monthEmits);
46
+ monthAnchor = addMonthsInTz(monthAnchor, rule.monthInterval, tz);
47
+ }
48
+ return out;
49
+ }
50
+ function _nthWeekdayOfMonth(year, month, dow, n) {
51
+ const len = monthLength(year, month);
52
+ if (n > 0) {
53
+ const day = 1 + (dow - new Date(Date.UTC(year, month, 1)).getUTCDay() + 7) % 7 + (n - 1) * 7;
54
+ return day <= len ? day : null;
55
+ }
56
+ const day = len - (new Date(Date.UTC(year, month, len)).getUTCDay() - dow + 7) % 7 + (n + 1) * 7;
57
+ return day >= 1 ? day : null;
58
+ }
59
+ export { generateWeeksOfMonth };
60
+
61
+ //# sourceMappingURL=weeks_of_month.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"weeks_of_month.js","names":[],"sources":["../../src/generators/weeks_of_month.ts"],"sourcesContent":["import type { Disambiguation, WeeksOfMonthRule } from \"../types.js\";\nimport {\n addMonthsInTz,\n computeSpanEnd,\n isNonexistentWallTime,\n monthLength,\n utcToWallParts,\n wallTimeToUtc,\n} from \"../tz.js\";\nimport {\n MAX_OCCURRENCES_PER_GENERATE,\n type Occurrence,\n TooManyOccurrencesError,\n intersects,\n} from \"./types.js\";\n\n// \"Nth Tuesday of every month\", \"last Friday of every other month\", etc.\n// Iterate month-by-month at monthInterval cadence; for each repeatable day,\n// resolve the target wall date.\nexport function generateWeeksOfMonth(\n rule: WeeksOfMonthRule,\n tz: string | undefined,\n windowStart: number,\n windowEnd: number,\n disambiguation: Disambiguation = \"compatible\"\n): Occurrence[] {\n if (rule.monthInterval <= 0) {\n throw new Error(`WeeksOfMonthRule.monthInterval must be > 0 (got ${rule.monthInterval})`);\n }\n if (rule.weeks.length === 0) {\n throw new Error(\"WeeksOfMonthRule.weeks must be non-empty\");\n }\n for (const w of rule.weeks) {\n if (w === 0 || w < -5 || w > 5) {\n throw new Error(`WeeksOfMonthRule.weeks entries must be in [-5..-1] or [1..5] (got ${w})`);\n }\n }\n if (rule.days.length === 0) {\n throw new Error(\"WeeksOfMonthRule.days must be non-empty\");\n }\n if (rule.count != null && rule.count < 0) {\n throw new Error(`WeeksOfMonthRule.count must be >= 0 (got ${rule.count})`);\n }\n\n const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;\n const effectiveEnd = Math.min(windowEnd, seriesEnd);\n if (rule.seriesStart >= effectiveEnd) return [];\n\n const days = [...rule.days].sort((a, b) => a - b);\n // Dedup `weeks` so a duplicated entry doesn't double-emit. Don't sort —\n // we sort the per-month emits at the end of each month iteration anyway.\n const weeks = [...new Set(rule.weeks)];\n\n // Anchor at seriesStart's month (in tz).\n const seriesStartParts = utcToWallParts(rule.seriesStart, tz);\n let monthAnchor = wallTimeToUtc(seriesStartParts.year, seriesStartParts.month, 1, 0, tz);\n\n const out: Occurrence[] = [];\n let count = 0;\n\n while (monthAnchor < effectiveEnd) {\n const mp = utcToWallParts(monthAnchor, tz);\n const monthEmits: Occurrence[] = [];\n\n for (const week of weeks) {\n for (const dow of days) {\n const targetDay = _nthWeekdayOfMonth(mp.year, mp.month, dow, week);\n if (targetDay == null) continue; // e.g. 5th Friday in a 4-Friday month\n\n if (\n disambiguation === \"skip\" &&\n isNonexistentWallTime(mp.year, mp.month, targetDay, rule.timeOfDay, tz)\n ) {\n continue;\n }\n const occStart = wallTimeToUtc(\n mp.year,\n mp.month,\n targetDay,\n rule.timeOfDay,\n tz,\n disambiguation\n );\n const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);\n\n if (occStart < rule.seriesStart) continue;\n if (occStart >= seriesEnd) continue;\n\n if (rule.count != null && count >= rule.count) {\n // Sort and emit what we collected this month before returning.\n monthEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);\n out.push(...monthEmits);\n return out;\n }\n count++;\n\n if (intersects(occStart, occEnd, windowStart, windowEnd)) {\n monthEmits.push({ startTimestamp: occStart, endTimestamp: occEnd });\n if (out.length + monthEmits.length > MAX_OCCURRENCES_PER_GENERATE) {\n throw new TooManyOccurrencesError(\"weeksOfMonth\");\n }\n }\n }\n }\n // Sort within-month emits before appending. With multiple weeks (and\n // negative weeks mixed with positive), per-week iteration order doesn't\n // produce ascending startTimestamps.\n monthEmits.sort((a, b) => a.startTimestamp - b.startTimestamp);\n out.push(...monthEmits);\n monthAnchor = addMonthsInTz(monthAnchor, rule.monthInterval, tz);\n }\n return out;\n}\n\n// Returns the day-of-month (1..31) for the Nth weekday of the given month,\n// or null if it doesn't exist (e.g. asking for the 5th Tuesday of a 4-Tuesday\n// month). Negative N counts from the end: -1 = last, -2 = second-to-last.\nfunction _nthWeekdayOfMonth(year: number, month: number, dow: number, n: number): number | null {\n const len = monthLength(year, month);\n\n if (n > 0) {\n // Find the first occurrence of `dow` in the month, then step by 7s.\n const firstDow = new Date(Date.UTC(year, month, 1)).getUTCDay();\n const offset = (dow - firstDow + 7) % 7;\n const day = 1 + offset + (n - 1) * 7;\n return day <= len ? day : null;\n }\n // n < 0: count from end of month.\n const lastDow = new Date(Date.UTC(year, month, len)).getUTCDay();\n const offset = (lastDow - dow + 7) % 7;\n const day = len - offset + (n + 1) * 7;\n return day >= 1 ? day : null;\n}\n"],"mappings":";;;AAmBA,SAAgB,qBACd,MACA,IACA,aACA,WACA,iBAAiC,cACnB;CACd,IAAI,KAAK,iBAAiB,GACxB,MAAM,IAAI,MAAM,mDAAmD,KAAK,cAAc,EAAE;CAE1F,IAAI,KAAK,MAAM,WAAW,GACxB,MAAM,IAAI,MAAM,0CAA0C;CAE5D,KAAK,MAAM,KAAK,KAAK,OACnB,IAAI,MAAM,KAAK,IAAI,MAAM,IAAI,GAC3B,MAAM,IAAI,MAAM,qEAAqE,EAAE,EAAE;CAG7F,IAAI,KAAK,KAAK,WAAW,GACvB,MAAM,IAAI,MAAM,yCAAyC;CAE3D,IAAI,KAAK,SAAS,QAAQ,KAAK,QAAQ,GACrC,MAAM,IAAI,MAAM,4CAA4C,KAAK,MAAM,EAAE;CAG3E,MAAM,YAAY,KAAK,aAAa,OAAO;CAC3C,MAAM,eAAe,KAAK,IAAI,WAAW,SAAS;CAClD,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC;CAE9C,MAAM,OAAO,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,MAAM,GAAG,MAAM,IAAI,CAAC;CAGhD,MAAM,QAAQ,CAAC,GAAG,IAAI,IAAI,KAAK,KAAK,CAAC;CAGrC,MAAM,mBAAmB,eAAe,KAAK,aAAa,EAAE;CAC5D,IAAI,cAAc,cAAc,iBAAiB,MAAM,iBAAiB,OAAO,GAAG,GAAG,EAAE;CAEvF,MAAM,MAAoB,CAAC;CAC3B,IAAI,QAAQ;CAEZ,OAAO,cAAc,cAAc;EACjC,MAAM,KAAK,eAAe,aAAa,EAAE;EACzC,MAAM,aAA2B,CAAC;EAElC,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,OAAO,MAAM;GACtB,MAAM,YAAY,mBAAmB,GAAG,MAAM,GAAG,OAAO,KAAK,IAAI;GACjE,IAAI,aAAa,MAAM;GAEvB,IACE,mBAAmB,UACnB,sBAAsB,GAAG,MAAM,GAAG,OAAO,WAAW,KAAK,WAAW,EAAE,GAEtE;GAEF,MAAM,WAAW,cACf,GAAG,MACH,GAAG,OACH,WACA,KAAK,WACL,IACA,cACF;GACA,MAAM,SAAS,eAAe,UAAU,KAAK,UAAU,EAAE;GAEzD,IAAI,WAAW,KAAK,aAAa;GACjC,IAAI,YAAY,WAAW;GAE3B,IAAI,KAAK,SAAS,QAAQ,SAAS,KAAK,OAAO;IAE7C,WAAW,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc;IAC7D,IAAI,KAAK,GAAG,UAAU;IACtB,OAAO;GACT;GACA;GAEA,IAAI,WAAW,UAAU,QAAQ,aAAa,SAAS,GAAG;IACxD,WAAW,KAAK;KAAE,gBAAgB;KAAU,cAAc;IAAO,CAAC;IAClE,IAAI,IAAI,SAAS,WAAW,SAAA,KAC1B,MAAM,IAAI,wBAAwB,cAAc;GAEpD;EACF;EAKF,WAAW,MAAM,GAAG,MAAM,EAAE,iBAAiB,EAAE,cAAc;EAC7D,IAAI,KAAK,GAAG,UAAU;EACtB,cAAc,cAAc,aAAa,KAAK,eAAe,EAAE;CACjE;CACA,OAAO;AACT;AAKA,SAAS,mBAAmB,MAAc,OAAe,KAAa,GAA0B;CAC9F,MAAM,MAAM,YAAY,MAAM,KAAK;CAEnC,IAAI,IAAI,GAAG;EAIT,MAAM,MAAM,KADI,MADC,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,UAC9B,IAAW,KAAK,KACZ,IAAI,KAAK;EACnC,OAAO,OAAO,MAAM,MAAM;CAC5B;CAIA,MAAM,MAAM,OAFI,IAAI,KAAK,KAAK,IAAI,MAAM,OAAO,GAAG,CAAC,CAAC,CAAC,UACrC,IAAU,MAAM,KAAK,KACT,IAAI,KAAK;CACrC,OAAO,OAAO,IAAI,MAAM;AAC1B"}
@@ -0,0 +1,4 @@
1
+ import { Disambiguation, YearlyRule } from '../types.js';
2
+ import { Occurrence } from './types.js';
3
+ export declare function generateYearly(rule: YearlyRule, tz: string | undefined, windowStart: number, windowEnd: number, disambiguation?: Disambiguation): Occurrence[];
4
+ //# sourceMappingURL=yearly.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yearly.d.ts","sourceRoot":"","sources":["../../src/generators/yearly.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAQ9D,OAAO,EAEL,KAAK,UAAU,EAGhB,MAAM,YAAY,CAAC;AAIpB,wBAAgB,cAAc,CAC5B,IAAI,EAAE,UAAU,EAChB,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,cAAc,GAAE,cAA6B,GAC5C,UAAU,EAAE,CAiDd"}
@@ -0,0 +1,37 @@
1
+ import { computeSpanEnd, isNonexistentWallTime, monthLength, utcToWallParts, wallTimeToUtc } from "../tz.js";
2
+ import { TooManyOccurrencesError, intersects } from "./types.js";
3
+ // src/generators/yearly.ts
4
+ function generateYearly(rule, tz, windowStart, windowEnd, disambiguation = "compatible") {
5
+ if (rule.yearInterval <= 0) throw new Error(`YearlyRule.yearInterval must be > 0 (got ${rule.yearInterval})`);
6
+ if (rule.month < 0 || rule.month > 11) throw new Error(`YearlyRule.month must be in 0..11 (got ${rule.month})`);
7
+ if (rule.day < 1 || rule.day > 31) throw new Error(`YearlyRule.day must be in 1..31 (got ${rule.day})`);
8
+ if (rule.count != null && rule.count < 0) throw new Error(`YearlyRule.count must be >= 0 (got ${rule.count})`);
9
+ const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;
10
+ const effectiveEnd = Math.min(windowEnd, seriesEnd);
11
+ if (rule.seriesStart >= effectiveEnd) return [];
12
+ const startYear = utcToWallParts(rule.seriesStart, tz).year;
13
+ const endYear = utcToWallParts(Math.min(effectiveEnd, Number.MAX_SAFE_INTEGER), tz).year;
14
+ const out = [];
15
+ let count = 0;
16
+ for (let year = startYear; year <= endYear; year += rule.yearInterval) {
17
+ const day = Math.min(rule.day, monthLength(year, rule.month));
18
+ if (disambiguation === "skip" && isNonexistentWallTime(year, rule.month, day, rule.timeOfDay, tz)) continue;
19
+ const occStart = wallTimeToUtc(year, rule.month, day, rule.timeOfDay, tz, disambiguation);
20
+ const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);
21
+ if (occStart < rule.seriesStart) continue;
22
+ if (occStart >= seriesEnd) continue;
23
+ if (rule.count != null && count >= rule.count) break;
24
+ count++;
25
+ if (intersects(occStart, occEnd, windowStart, windowEnd)) {
26
+ out.push({
27
+ startTimestamp: occStart,
28
+ endTimestamp: occEnd
29
+ });
30
+ if (out.length > 1e4) throw new TooManyOccurrencesError("yearly");
31
+ }
32
+ }
33
+ return out;
34
+ }
35
+ export { generateYearly };
36
+
37
+ //# sourceMappingURL=yearly.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yearly.js","names":[],"sources":["../../src/generators/yearly.ts"],"sourcesContent":["import type { Disambiguation, YearlyRule } from \"../types.js\";\nimport {\n computeSpanEnd,\n isNonexistentWallTime,\n monthLength,\n utcToWallParts,\n wallTimeToUtc,\n} from \"../tz.js\";\nimport {\n MAX_OCCURRENCES_PER_GENERATE,\n type Occurrence,\n TooManyOccurrencesError,\n intersects,\n} from \"./types.js\";\n\n// Simple yearly recurrence: a single month + day. Day clamps to month\n// length (Feb 29 → Feb 28 in non-leap years, Apr 31 → Apr 30, etc.).\nexport function generateYearly(\n rule: YearlyRule,\n tz: string | undefined,\n windowStart: number,\n windowEnd: number,\n disambiguation: Disambiguation = \"compatible\"\n): Occurrence[] {\n if (rule.yearInterval <= 0) {\n throw new Error(`YearlyRule.yearInterval must be > 0 (got ${rule.yearInterval})`);\n }\n if (rule.month < 0 || rule.month > 11) {\n throw new Error(`YearlyRule.month must be in 0..11 (got ${rule.month})`);\n }\n if (rule.day < 1 || rule.day > 31) {\n throw new Error(`YearlyRule.day must be in 1..31 (got ${rule.day})`);\n }\n if (rule.count != null && rule.count < 0) {\n throw new Error(`YearlyRule.count must be >= 0 (got ${rule.count})`);\n }\n\n const seriesEnd = rule.seriesEnd ?? Number.POSITIVE_INFINITY;\n const effectiveEnd = Math.min(windowEnd, seriesEnd);\n if (rule.seriesStart >= effectiveEnd) return [];\n\n const startYear = utcToWallParts(rule.seriesStart, tz).year;\n const endYear = utcToWallParts(Math.min(effectiveEnd, Number.MAX_SAFE_INTEGER), tz).year;\n\n const out: Occurrence[] = [];\n let count = 0;\n\n for (let year = startYear; year <= endYear; year += rule.yearInterval) {\n const day = Math.min(rule.day, monthLength(year, rule.month));\n if (\n disambiguation === \"skip\" &&\n isNonexistentWallTime(year, rule.month, day, rule.timeOfDay, tz)\n ) {\n continue;\n }\n const occStart = wallTimeToUtc(year, rule.month, day, rule.timeOfDay, tz, disambiguation);\n const occEnd = computeSpanEnd(occStart, rule.timeSpan, tz);\n\n if (occStart < rule.seriesStart) continue;\n if (occStart >= seriesEnd) continue;\n\n if (rule.count != null && count >= rule.count) break;\n count++;\n\n if (intersects(occStart, occEnd, windowStart, windowEnd)) {\n out.push({ startTimestamp: occStart, endTimestamp: occEnd });\n if (out.length > MAX_OCCURRENCES_PER_GENERATE) {\n throw new TooManyOccurrencesError(\"yearly\");\n }\n }\n }\n return out;\n}\n"],"mappings":";;;AAiBA,SAAgB,eACd,MACA,IACA,aACA,WACA,iBAAiC,cACnB;CACd,IAAI,KAAK,gBAAgB,GACvB,MAAM,IAAI,MAAM,4CAA4C,KAAK,aAAa,EAAE;CAElF,IAAI,KAAK,QAAQ,KAAK,KAAK,QAAQ,IACjC,MAAM,IAAI,MAAM,0CAA0C,KAAK,MAAM,EAAE;CAEzE,IAAI,KAAK,MAAM,KAAK,KAAK,MAAM,IAC7B,MAAM,IAAI,MAAM,wCAAwC,KAAK,IAAI,EAAE;CAErE,IAAI,KAAK,SAAS,QAAQ,KAAK,QAAQ,GACrC,MAAM,IAAI,MAAM,sCAAsC,KAAK,MAAM,EAAE;CAGrE,MAAM,YAAY,KAAK,aAAa,OAAO;CAC3C,MAAM,eAAe,KAAK,IAAI,WAAW,SAAS;CAClD,IAAI,KAAK,eAAe,cAAc,OAAO,CAAC;CAE9C,MAAM,YAAY,eAAe,KAAK,aAAa,EAAE,CAAC,CAAC;CACvD,MAAM,UAAU,eAAe,KAAK,IAAI,cAAc,OAAO,gBAAgB,GAAG,EAAE,CAAC,CAAC;CAEpF,MAAM,MAAoB,CAAC;CAC3B,IAAI,QAAQ;CAEZ,KAAK,IAAI,OAAO,WAAW,QAAQ,SAAS,QAAQ,KAAK,cAAc;EACrE,MAAM,MAAM,KAAK,IAAI,KAAK,KAAK,YAAY,MAAM,KAAK,KAAK,CAAC;EAC5D,IACE,mBAAmB,UACnB,sBAAsB,MAAM,KAAK,OAAO,KAAK,KAAK,WAAW,EAAE,GAE/D;EAEF,MAAM,WAAW,cAAc,MAAM,KAAK,OAAO,KAAK,KAAK,WAAW,IAAI,cAAc;EACxF,MAAM,SAAS,eAAe,UAAU,KAAK,UAAU,EAAE;EAEzD,IAAI,WAAW,KAAK,aAAa;EACjC,IAAI,YAAY,WAAW;EAE3B,IAAI,KAAK,SAAS,QAAQ,SAAS,KAAK,OAAO;EAC/C;EAEA,IAAI,WAAW,UAAU,QAAQ,aAAa,SAAS,GAAG;GACxD,IAAI,KAAK;IAAE,gBAAgB;IAAU,cAAc;GAAO,CAAC;GAC3D,IAAI,IAAI,SAAA,KACN,MAAM,IAAI,wBAAwB,QAAQ;EAE9C;CACF;CACA,OAAO;AACT"}
@@ -0,0 +1,19 @@
1
+ import { SchedulerPort } from './port.js';
2
+ import { Alteration, ScheduleTemplate } from './types.js';
3
+ export declare class InMemorySchedulerPort<TPayload extends {
4
+ type: string;
5
+ }> implements SchedulerPort<TPayload> {
6
+ private _templates;
7
+ private _alterations;
8
+ listTemplates(_start: number, _end: number): Promise<ScheduleTemplate<TPayload>[]>;
9
+ getTemplate(id: string): Promise<ScheduleTemplate<TPayload> | null>;
10
+ addTemplate(template: ScheduleTemplate<TPayload>): Promise<void>;
11
+ updateTemplate(template: ScheduleTemplate<TPayload>): Promise<void>;
12
+ removeTemplate(id: string): Promise<void>;
13
+ listAlterations(_start: number, _end: number): Promise<Alteration<TPayload>[]>;
14
+ listAlterationsByTemplate(templateId: string): Promise<Alteration<TPayload>[]>;
15
+ addAlteration(alteration: Alteration<TPayload>): Promise<void>;
16
+ removeAlteration(id: string): Promise<void>;
17
+ removeAlterationsForTemplate(templateId: string): Promise<void>;
18
+ }
19
+ //# sourceMappingURL=in_memory_port.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in_memory_port.d.ts","sourceRoot":"","sources":["../src/in_memory_port.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAO/D,qBAAa,qBAAqB,CAAC,QAAQ,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAClE,YAAW,aAAa,CAAC,QAAQ,CAAC;IAElC,OAAO,CAAC,UAAU,CAAiD;IACnE,OAAO,CAAC,YAAY,CAA2C;IAEzD,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;IAIlF,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC;IAKnE,WAAW,CAAC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAOhE,cAAc,CAAC,QAAQ,EAAE,gBAAgB,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnE,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;IAI9E,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;IAI9E,aAAa,CAAC,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAO9D,gBAAgB,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,4BAA4B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAKtE"}
@@ -0,0 +1,45 @@
1
+ // src/in_memory_port.ts
2
+ var InMemorySchedulerPort = class {
3
+ _templates = /* @__PURE__ */ new Map();
4
+ _alterations = /* @__PURE__ */ new Map();
5
+ async listTemplates(_start, _end) {
6
+ return [...this._templates.values()].map(clone);
7
+ }
8
+ async getTemplate(id) {
9
+ const t = this._templates.get(id);
10
+ return t == null ? null : clone(t);
11
+ }
12
+ async addTemplate(template) {
13
+ if (this._templates.has(template.id)) throw new Error(`Template already exists: ${template.id}`);
14
+ this._templates.set(template.id, clone(template));
15
+ }
16
+ async updateTemplate(template) {
17
+ if (!this._templates.has(template.id)) throw new Error(`No template with id ${template.id}`);
18
+ this._templates.set(template.id, clone(template));
19
+ }
20
+ async removeTemplate(id) {
21
+ this._templates.delete(id);
22
+ }
23
+ async listAlterations(_start, _end) {
24
+ return [...this._alterations.values()].map(clone);
25
+ }
26
+ async listAlterationsByTemplate(templateId) {
27
+ return [...this._alterations.values()].filter((a) => a.templateId === templateId).map(clone);
28
+ }
29
+ async addAlteration(alteration) {
30
+ if (this._alterations.has(alteration.id)) throw new Error(`Alteration already exists: ${alteration.id}`);
31
+ this._alterations.set(alteration.id, clone(alteration));
32
+ }
33
+ async removeAlteration(id) {
34
+ this._alterations.delete(id);
35
+ }
36
+ async removeAlterationsForTemplate(templateId) {
37
+ for (const [id, a] of this._alterations) if (a.templateId === templateId) this._alterations.delete(id);
38
+ }
39
+ };
40
+ function clone(value) {
41
+ return JSON.parse(JSON.stringify(value));
42
+ }
43
+ export { InMemorySchedulerPort };
44
+
45
+ //# sourceMappingURL=in_memory_port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in_memory_port.js","names":[],"sources":["../src/in_memory_port.ts"],"sourcesContent":["import type { SchedulerPort } from \"./port.js\";\nimport type { Alteration, ScheduleTemplate } from \"./types.js\";\n\n// Reference port. Stores templates and alterations in plain Maps. Returns\n// deep-cloned copies so callers can't mutate internal state.\n//\n// Range queries return everything and let the Scheduler filter — correct,\n// but O(n) per query. A real backend would index on seriesStart/seriesEnd.\nexport class InMemorySchedulerPort<TPayload extends { type: string }>\n implements SchedulerPort<TPayload>\n{\n private _templates = new Map<string, ScheduleTemplate<TPayload>>();\n private _alterations = new Map<string, Alteration<TPayload>>();\n\n async listTemplates(_start: number, _end: number): Promise<ScheduleTemplate<TPayload>[]> {\n return [...this._templates.values()].map(clone);\n }\n\n async getTemplate(id: string): Promise<ScheduleTemplate<TPayload> | null> {\n const t = this._templates.get(id);\n return t == null ? null : clone(t);\n }\n\n async addTemplate(template: ScheduleTemplate<TPayload>): Promise<void> {\n if (this._templates.has(template.id)) {\n throw new Error(`Template already exists: ${template.id}`);\n }\n this._templates.set(template.id, clone(template));\n }\n\n async updateTemplate(template: ScheduleTemplate<TPayload>): Promise<void> {\n if (!this._templates.has(template.id)) {\n throw new Error(`No template with id ${template.id}`);\n }\n this._templates.set(template.id, clone(template));\n }\n\n async removeTemplate(id: string): Promise<void> {\n this._templates.delete(id);\n }\n\n async listAlterations(_start: number, _end: number): Promise<Alteration<TPayload>[]> {\n return [...this._alterations.values()].map(clone);\n }\n\n async listAlterationsByTemplate(templateId: string): Promise<Alteration<TPayload>[]> {\n return [...this._alterations.values()].filter((a) => a.templateId === templateId).map(clone);\n }\n\n async addAlteration(alteration: Alteration<TPayload>): Promise<void> {\n if (this._alterations.has(alteration.id)) {\n throw new Error(`Alteration already exists: ${alteration.id}`);\n }\n this._alterations.set(alteration.id, clone(alteration));\n }\n\n async removeAlteration(id: string): Promise<void> {\n this._alterations.delete(id);\n }\n\n async removeAlterationsForTemplate(templateId: string): Promise<void> {\n for (const [id, a] of this._alterations) {\n if (a.templateId === templateId) this._alterations.delete(id);\n }\n }\n}\n\nfunction clone<T>(value: T): T {\n return JSON.parse(JSON.stringify(value)) as T;\n}\n"],"mappings":";AAQA,IAAa,wBAAb,MAEA;CACE,6BAAqB,IAAI,IAAwC;CACjE,+BAAuB,IAAI,IAAkC;CAE7D,MAAM,cAAc,QAAgB,MAAqD;EACvF,OAAO,CAAC,GAAG,KAAK,WAAW,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK;CAChD;CAEA,MAAM,YAAY,IAAwD;EACxE,MAAM,IAAI,KAAK,WAAW,IAAI,EAAE;EAChC,OAAO,KAAK,OAAO,OAAO,MAAM,CAAC;CACnC;CAEA,MAAM,YAAY,UAAqD;EACrE,IAAI,KAAK,WAAW,IAAI,SAAS,EAAE,GACjC,MAAM,IAAI,MAAM,4BAA4B,SAAS,IAAI;EAE3D,KAAK,WAAW,IAAI,SAAS,IAAI,MAAM,QAAQ,CAAC;CAClD;CAEA,MAAM,eAAe,UAAqD;EACxE,IAAI,CAAC,KAAK,WAAW,IAAI,SAAS,EAAE,GAClC,MAAM,IAAI,MAAM,uBAAuB,SAAS,IAAI;EAEtD,KAAK,WAAW,IAAI,SAAS,IAAI,MAAM,QAAQ,CAAC;CAClD;CAEA,MAAM,eAAe,IAA2B;EAC9C,KAAK,WAAW,OAAO,EAAE;CAC3B;CAEA,MAAM,gBAAgB,QAAgB,MAA+C;EACnF,OAAO,CAAC,GAAG,KAAK,aAAa,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK;CAClD;CAEA,MAAM,0BAA0B,YAAqD;EACnF,OAAO,CAAC,GAAG,KAAK,aAAa,OAAO,CAAC,CAAC,CAAC,QAAQ,MAAM,EAAE,eAAe,UAAU,CAAC,CAAC,IAAI,KAAK;CAC7F;CAEA,MAAM,cAAc,YAAiD;EACnE,IAAI,KAAK,aAAa,IAAI,WAAW,EAAE,GACrC,MAAM,IAAI,MAAM,8BAA8B,WAAW,IAAI;EAE/D,KAAK,aAAa,IAAI,WAAW,IAAI,MAAM,UAAU,CAAC;CACxD;CAEA,MAAM,iBAAiB,IAA2B;EAChD,KAAK,aAAa,OAAO,EAAE;CAC7B;CAEA,MAAM,6BAA6B,YAAmC;EACpE,KAAK,MAAM,CAAC,IAAI,MAAM,KAAK,cACzB,IAAI,EAAE,eAAe,YAAY,KAAK,aAAa,OAAO,EAAE;CAEhE;AACF;AAEA,SAAS,MAAS,OAAa;CAC7B,OAAO,KAAK,MAAM,KAAK,UAAU,KAAK,CAAC;AACzC"}
@@ -0,0 +1,7 @@
1
+ export { Scheduler } from './scheduler.js';
2
+ export { InMemorySchedulerPort } from './in_memory_port.js';
3
+ export type { SchedulerPort } from './port.js';
4
+ export { Dispatcher, type DispatcherConfig } from './dispatcher.js';
5
+ export { type DispatcherStore, InMemoryDispatcherStore } from './dispatcher_store.js';
6
+ export { Day, Month, type RecurrenceRule, type InstantRule, type LocalDateTimeRule, type AnchoredRule, type DaysOfWeekRule, type WeeksOfMonthRule, type MonthsOfYearRule, type YearlyRule, type DaysOfMonthRule, type DaysOfYearRule, type ScheduleTemplate, type Alteration, type ScheduledEvent, type TimeSpan, type Disambiguation, } from './types.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACpE,OAAO,EAAE,KAAK,eAAe,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AACtF,OAAO,EACL,GAAG,EACH,KAAK,EACL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,cAAc,GACpB,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ import { Scheduler } from "./scheduler.js";
2
+ import { InMemorySchedulerPort } from "./in_memory_port.js";
3
+ import { Dispatcher } from "./dispatcher.js";
4
+ import { InMemoryDispatcherStore } from "./dispatcher_store.js";
5
+ import { Day, Month } from "./types.js";
6
+ export { Day, Dispatcher, InMemoryDispatcherStore, InMemorySchedulerPort, Month, Scheduler };
@@ -0,0 +1,6 @@
1
+ import { Occurrence } from './generators/types.js';
2
+ export interface KeyedOccurrence extends Occurrence {
3
+ occurrenceKey: string;
4
+ }
5
+ export declare function assignOccurrenceKeys(occurrences: readonly Occurrence[], tz: string | undefined): KeyedOccurrence[];
6
+ //# sourceMappingURL=occurrence_key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"occurrence_key.d.ts","sourceRoot":"","sources":["../src/occurrence_key.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAgBxD,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,wBAAgB,oBAAoB,CAClC,WAAW,EAAE,SAAS,UAAU,EAAE,EAClC,EAAE,EAAE,MAAM,GAAG,SAAS,GACrB,eAAe,EAAE,CAUnB"}