@elaraai/east 0.0.1-beta.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 (251) hide show
  1. package/LICENSE.md +682 -0
  2. package/README.md +276 -0
  3. package/dist/src/analyze.d.ts +95 -0
  4. package/dist/src/analyze.d.ts.map +1 -0
  5. package/dist/src/analyze.js +1110 -0
  6. package/dist/src/analyze.js.map +1 -0
  7. package/dist/src/ast.d.ts +263 -0
  8. package/dist/src/ast.d.ts.map +1 -0
  9. package/dist/src/ast.js +151 -0
  10. package/dist/src/ast.js.map +1 -0
  11. package/dist/src/ast_to_ir.d.ts +24 -0
  12. package/dist/src/ast_to_ir.d.ts.map +1 -0
  13. package/dist/src/ast_to_ir.js +834 -0
  14. package/dist/src/ast_to_ir.js.map +1 -0
  15. package/dist/src/builtins.d.ts +18 -0
  16. package/dist/src/builtins.d.ts.map +1 -0
  17. package/dist/src/builtins.js +1105 -0
  18. package/dist/src/builtins.js.map +1 -0
  19. package/dist/src/comparison.d.ts +28 -0
  20. package/dist/src/comparison.d.ts.map +1 -0
  21. package/dist/src/comparison.js +1017 -0
  22. package/dist/src/comparison.js.map +1 -0
  23. package/dist/src/compile.d.ts +22 -0
  24. package/dist/src/compile.d.ts.map +1 -0
  25. package/dist/src/compile.js +3260 -0
  26. package/dist/src/compile.js.map +1 -0
  27. package/dist/src/containers/ref.d.ts +106 -0
  28. package/dist/src/containers/ref.d.ts.map +1 -0
  29. package/dist/src/containers/ref.js +100 -0
  30. package/dist/src/containers/ref.js.map +1 -0
  31. package/dist/src/containers/sortedmap.d.ts +165 -0
  32. package/dist/src/containers/sortedmap.d.ts.map +1 -0
  33. package/dist/src/containers/sortedmap.js +237 -0
  34. package/dist/src/containers/sortedmap.js.map +1 -0
  35. package/dist/src/containers/sortedset.d.ts +185 -0
  36. package/dist/src/containers/sortedset.d.ts.map +1 -0
  37. package/dist/src/containers/sortedset.js +312 -0
  38. package/dist/src/containers/sortedset.js.map +1 -0
  39. package/dist/src/containers/variant.d.ts +131 -0
  40. package/dist/src/containers/variant.d.ts.map +1 -0
  41. package/dist/src/containers/variant.js +68 -0
  42. package/dist/src/containers/variant.js.map +1 -0
  43. package/dist/src/datetime_format/parse.d.ts +50 -0
  44. package/dist/src/datetime_format/parse.d.ts.map +1 -0
  45. package/dist/src/datetime_format/parse.js +908 -0
  46. package/dist/src/datetime_format/parse.js.map +1 -0
  47. package/dist/src/datetime_format/print.d.ts +35 -0
  48. package/dist/src/datetime_format/print.d.ts.map +1 -0
  49. package/dist/src/datetime_format/print.js +157 -0
  50. package/dist/src/datetime_format/print.js.map +1 -0
  51. package/dist/src/datetime_format/tokenize.d.ts +76 -0
  52. package/dist/src/datetime_format/tokenize.d.ts.map +1 -0
  53. package/dist/src/datetime_format/tokenize.js +271 -0
  54. package/dist/src/datetime_format/tokenize.js.map +1 -0
  55. package/dist/src/datetime_format/types.d.ts +99 -0
  56. package/dist/src/datetime_format/types.d.ts.map +1 -0
  57. package/dist/src/datetime_format/types.js +103 -0
  58. package/dist/src/datetime_format/types.js.map +1 -0
  59. package/dist/src/datetime_format/validate.d.ts +51 -0
  60. package/dist/src/datetime_format/validate.d.ts.map +1 -0
  61. package/dist/src/datetime_format/validate.js +208 -0
  62. package/dist/src/datetime_format/validate.js.map +1 -0
  63. package/dist/src/default.d.ts +21 -0
  64. package/dist/src/default.d.ts.map +1 -0
  65. package/dist/src/default.js +82 -0
  66. package/dist/src/default.js.map +1 -0
  67. package/dist/src/eastir.d.ts +33 -0
  68. package/dist/src/eastir.d.ts.map +1 -0
  69. package/dist/src/eastir.js +92 -0
  70. package/dist/src/eastir.js.map +1 -0
  71. package/dist/src/error.d.ts +13 -0
  72. package/dist/src/error.d.ts.map +1 -0
  73. package/dist/src/error.js +8 -0
  74. package/dist/src/error.js.map +1 -0
  75. package/dist/src/expr/array.d.ts +1711 -0
  76. package/dist/src/expr/array.d.ts.map +1 -0
  77. package/dist/src/expr/array.js +1805 -0
  78. package/dist/src/expr/array.js.map +1 -0
  79. package/dist/src/expr/ast.d.ts +17 -0
  80. package/dist/src/expr/ast.d.ts.map +1 -0
  81. package/dist/src/expr/ast.js +302 -0
  82. package/dist/src/expr/ast.js.map +1 -0
  83. package/dist/src/expr/blob.d.ts +141 -0
  84. package/dist/src/expr/blob.d.ts.map +1 -0
  85. package/dist/src/expr/blob.js +198 -0
  86. package/dist/src/expr/blob.js.map +1 -0
  87. package/dist/src/expr/block.d.ts +201 -0
  88. package/dist/src/expr/block.d.ts.map +1 -0
  89. package/dist/src/expr/block.js +1505 -0
  90. package/dist/src/expr/block.js.map +1 -0
  91. package/dist/src/expr/boolean.d.ts +207 -0
  92. package/dist/src/expr/boolean.d.ts.map +1 -0
  93. package/dist/src/expr/boolean.js +261 -0
  94. package/dist/src/expr/boolean.js.map +1 -0
  95. package/dist/src/expr/datetime.d.ts +544 -0
  96. package/dist/src/expr/datetime.d.ts.map +1 -0
  97. package/dist/src/expr/datetime.js +980 -0
  98. package/dist/src/expr/datetime.js.map +1 -0
  99. package/dist/src/expr/dict.d.ts +1242 -0
  100. package/dist/src/expr/dict.d.ts.map +1 -0
  101. package/dist/src/expr/dict.js +1492 -0
  102. package/dist/src/expr/dict.js.map +1 -0
  103. package/dist/src/expr/expr.d.ts +95 -0
  104. package/dist/src/expr/expr.d.ts.map +1 -0
  105. package/dist/src/expr/expr.js +171 -0
  106. package/dist/src/expr/expr.js.map +1 -0
  107. package/dist/src/expr/float.d.ts +357 -0
  108. package/dist/src/expr/float.d.ts.map +1 -0
  109. package/dist/src/expr/float.js +637 -0
  110. package/dist/src/expr/float.js.map +1 -0
  111. package/dist/src/expr/function.d.ts +46 -0
  112. package/dist/src/expr/function.d.ts.map +1 -0
  113. package/dist/src/expr/function.js +58 -0
  114. package/dist/src/expr/function.js.map +1 -0
  115. package/dist/src/expr/index.d.ts +450 -0
  116. package/dist/src/expr/index.d.ts.map +1 -0
  117. package/dist/src/expr/index.js +423 -0
  118. package/dist/src/expr/index.js.map +1 -0
  119. package/dist/src/expr/integer.d.ts +256 -0
  120. package/dist/src/expr/integer.d.ts.map +1 -0
  121. package/dist/src/expr/integer.js +311 -0
  122. package/dist/src/expr/integer.js.map +1 -0
  123. package/dist/src/expr/libs/array.d.ts +106 -0
  124. package/dist/src/expr/libs/array.d.ts.map +1 -0
  125. package/dist/src/expr/libs/array.js +140 -0
  126. package/dist/src/expr/libs/array.js.map +1 -0
  127. package/dist/src/expr/libs/blob.d.ts +42 -0
  128. package/dist/src/expr/libs/blob.d.ts.map +1 -0
  129. package/dist/src/expr/libs/blob.js +70 -0
  130. package/dist/src/expr/libs/blob.js.map +1 -0
  131. package/dist/src/expr/libs/datetime.d.ts +479 -0
  132. package/dist/src/expr/libs/datetime.d.ts.map +1 -0
  133. package/dist/src/expr/libs/datetime.js +624 -0
  134. package/dist/src/expr/libs/datetime.js.map +1 -0
  135. package/dist/src/expr/libs/dict.d.ts +66 -0
  136. package/dist/src/expr/libs/dict.d.ts.map +1 -0
  137. package/dist/src/expr/libs/dict.js +77 -0
  138. package/dist/src/expr/libs/dict.js.map +1 -0
  139. package/dist/src/expr/libs/float.d.ts +299 -0
  140. package/dist/src/expr/libs/float.d.ts.map +1 -0
  141. package/dist/src/expr/libs/float.js +564 -0
  142. package/dist/src/expr/libs/float.js.map +1 -0
  143. package/dist/src/expr/libs/integer.d.ts +228 -0
  144. package/dist/src/expr/libs/integer.d.ts.map +1 -0
  145. package/dist/src/expr/libs/integer.js +398 -0
  146. package/dist/src/expr/libs/integer.js.map +1 -0
  147. package/dist/src/expr/libs/set.d.ts +59 -0
  148. package/dist/src/expr/libs/set.d.ts.map +1 -0
  149. package/dist/src/expr/libs/set.js +69 -0
  150. package/dist/src/expr/libs/set.js.map +1 -0
  151. package/dist/src/expr/libs/string.d.ts +71 -0
  152. package/dist/src/expr/libs/string.d.ts.map +1 -0
  153. package/dist/src/expr/libs/string.js +75 -0
  154. package/dist/src/expr/libs/string.js.map +1 -0
  155. package/dist/src/expr/never.d.ts +15 -0
  156. package/dist/src/expr/never.d.ts.map +1 -0
  157. package/dist/src/expr/never.js +12 -0
  158. package/dist/src/expr/never.js.map +1 -0
  159. package/dist/src/expr/null.d.ts +15 -0
  160. package/dist/src/expr/null.d.ts.map +1 -0
  161. package/dist/src/expr/null.js +12 -0
  162. package/dist/src/expr/null.js.map +1 -0
  163. package/dist/src/expr/ref.d.ts +103 -0
  164. package/dist/src/expr/ref.d.ts.map +1 -0
  165. package/dist/src/expr/ref.js +131 -0
  166. package/dist/src/expr/ref.js.map +1 -0
  167. package/dist/src/expr/regex_validation.d.ts +25 -0
  168. package/dist/src/expr/regex_validation.d.ts.map +1 -0
  169. package/dist/src/expr/regex_validation.js +130 -0
  170. package/dist/src/expr/regex_validation.js.map +1 -0
  171. package/dist/src/expr/set.d.ts +1071 -0
  172. package/dist/src/expr/set.d.ts.map +1 -0
  173. package/dist/src/expr/set.js +1137 -0
  174. package/dist/src/expr/set.js.map +1 -0
  175. package/dist/src/expr/string.d.ts +414 -0
  176. package/dist/src/expr/string.d.ts.map +1 -0
  177. package/dist/src/expr/string.js +683 -0
  178. package/dist/src/expr/string.js.map +1 -0
  179. package/dist/src/expr/struct.d.ts +48 -0
  180. package/dist/src/expr/struct.d.ts.map +1 -0
  181. package/dist/src/expr/struct.js +65 -0
  182. package/dist/src/expr/struct.js.map +1 -0
  183. package/dist/src/expr/types.d.ts +68 -0
  184. package/dist/src/expr/types.d.ts.map +1 -0
  185. package/dist/src/expr/types.js +6 -0
  186. package/dist/src/expr/types.js.map +1 -0
  187. package/dist/src/expr/variant.d.ts +137 -0
  188. package/dist/src/expr/variant.d.ts.map +1 -0
  189. package/dist/src/expr/variant.js +105 -0
  190. package/dist/src/expr/variant.js.map +1 -0
  191. package/dist/src/fuzz.d.ts +80 -0
  192. package/dist/src/fuzz.d.ts.map +1 -0
  193. package/dist/src/fuzz.js +300 -0
  194. package/dist/src/fuzz.js.map +1 -0
  195. package/dist/src/index.d.ts +21 -0
  196. package/dist/src/index.d.ts.map +1 -0
  197. package/dist/src/index.js +21 -0
  198. package/dist/src/index.js.map +1 -0
  199. package/dist/src/internal.d.ts +36 -0
  200. package/dist/src/internal.d.ts.map +1 -0
  201. package/dist/src/internal.js +11 -0
  202. package/dist/src/internal.js.map +1 -0
  203. package/dist/src/ir.d.ts +1571 -0
  204. package/dist/src/ir.d.ts.map +1 -0
  205. package/dist/src/ir.js +56 -0
  206. package/dist/src/ir.js.map +1 -0
  207. package/dist/src/location.d.ts +48 -0
  208. package/dist/src/location.d.ts.map +1 -0
  209. package/dist/src/location.js +62 -0
  210. package/dist/src/location.js.map +1 -0
  211. package/dist/src/platform.d.ts +21 -0
  212. package/dist/src/platform.d.ts.map +1 -0
  213. package/dist/src/platform.js +8 -0
  214. package/dist/src/platform.js.map +1 -0
  215. package/dist/src/serialization/beast.d.ts +39 -0
  216. package/dist/src/serialization/beast.d.ts.map +1 -0
  217. package/dist/src/serialization/beast.js +555 -0
  218. package/dist/src/serialization/beast.js.map +1 -0
  219. package/dist/src/serialization/beast2-stream.d.ts +38 -0
  220. package/dist/src/serialization/beast2-stream.d.ts.map +1 -0
  221. package/dist/src/serialization/beast2-stream.js +665 -0
  222. package/dist/src/serialization/beast2-stream.js.map +1 -0
  223. package/dist/src/serialization/beast2.d.ts +41 -0
  224. package/dist/src/serialization/beast2.d.ts.map +1 -0
  225. package/dist/src/serialization/beast2.js +489 -0
  226. package/dist/src/serialization/beast2.js.map +1 -0
  227. package/dist/src/serialization/binary-utils.d.ts +151 -0
  228. package/dist/src/serialization/binary-utils.d.ts.map +1 -0
  229. package/dist/src/serialization/binary-utils.js +929 -0
  230. package/dist/src/serialization/binary-utils.js.map +1 -0
  231. package/dist/src/serialization/east.d.ts +84 -0
  232. package/dist/src/serialization/east.d.ts.map +1 -0
  233. package/dist/src/serialization/east.js +1802 -0
  234. package/dist/src/serialization/east.js.map +1 -0
  235. package/dist/src/serialization/index.d.ts +11 -0
  236. package/dist/src/serialization/index.d.ts.map +1 -0
  237. package/dist/src/serialization/index.js +12 -0
  238. package/dist/src/serialization/index.js.map +1 -0
  239. package/dist/src/serialization/json.d.ts +36 -0
  240. package/dist/src/serialization/json.d.ts.map +1 -0
  241. package/dist/src/serialization/json.js +849 -0
  242. package/dist/src/serialization/json.js.map +1 -0
  243. package/dist/src/type_of_type.d.ts +115 -0
  244. package/dist/src/type_of_type.d.ts.map +1 -0
  245. package/dist/src/type_of_type.js +362 -0
  246. package/dist/src/type_of_type.js.map +1 -0
  247. package/dist/src/types.d.ts +648 -0
  248. package/dist/src/types.d.ts.map +1 -0
  249. package/dist/src/types.js +1631 -0
  250. package/dist/src/types.js.map +1 -0
  251. package/package.json +87 -0
@@ -0,0 +1,908 @@
1
+ /**
2
+ * Copyright (c) 2025 Elara AI Pty Ltd
3
+ * Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
4
+ */
5
+ /**
6
+ * Month names in English for parsing.
7
+ */
8
+ const MONTH_NAMES_FULL = [
9
+ "january", "february", "march", "april", "may", "june",
10
+ "july", "august", "september", "october", "november", "december"
11
+ ];
12
+ const MONTH_NAMES_SHORT = [
13
+ "jan", "feb", "mar", "apr", "may", "jun",
14
+ "jul", "aug", "sep", "oct", "nov", "dec"
15
+ ];
16
+ /**
17
+ * Weekday names in English for parsing (currently ignored during parsing).
18
+ */
19
+ const WEEKDAY_NAMES_FULL = [
20
+ "sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"
21
+ ];
22
+ const WEEKDAY_NAMES_SHORT = [
23
+ "sun", "mon", "tue", "wed", "thu", "fri", "sat"
24
+ ];
25
+ const WEEKDAY_NAMES_MIN = [
26
+ "su", "mo", "tu", "we", "th", "fr", "sa"
27
+ ];
28
+ /**
29
+ * Parses a datetime string according to format tokens.
30
+ *
31
+ * @param input - The string to parse
32
+ * @param tokens - Array of format tokens specifying the expected format
33
+ * @returns Parse result containing either the Date or an error with position
34
+ *
35
+ * @remarks
36
+ * All dates are treated as UTC (naive datetimes with no timezone information).
37
+ * The parsed components are used to construct a Date using Date.UTC().
38
+ *
39
+ * Weekday tokens (dd, ddd, dddd) are currently ignored during parsing - they
40
+ * are consumed from the input but not validated against the actual weekday.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * const tokens = tokenizeDateTimeFormat("YYYY-MM-DD");
45
+ * const result = parseDateTimeFormatted("2025-01-15", tokens);
46
+ * if (result.success) {
47
+ * console.log(result.value); // Date object for 2025-01-15T00:00:00.000Z
48
+ * } else {
49
+ * console.log(`Parse error at position ${result.position}: ${result.error}`);
50
+ * }
51
+ * ```
52
+ */
53
+ export function parseDateTimeFormatted(input, tokens) {
54
+ let position = 0;
55
+ // Datetime components - will validate redundancy and check for gaps
56
+ let year = null;
57
+ let month = null;
58
+ let day = null;
59
+ let hour = null;
60
+ let minute = null;
61
+ let second = null;
62
+ let millisecond = null;
63
+ let isPM = null;
64
+ let hour12 = null; // Track 12-hour format separately
65
+ let parsedWeekday = null; // Track parsed weekday for validation
66
+ for (const token of tokens) {
67
+ if (position > input.length) {
68
+ return {
69
+ success: false,
70
+ error: `Unexpected end of input`,
71
+ position
72
+ };
73
+ }
74
+ switch (token.type) {
75
+ case "year4": {
76
+ const match = input.slice(position, position + 4);
77
+ if (match.length < 4 || !/^\d{4}$/.test(match)) {
78
+ return {
79
+ success: false,
80
+ error: `Expected 4-digit year`,
81
+ position
82
+ };
83
+ }
84
+ const parsedYear = parseInt(match, 10);
85
+ if (year !== null && year !== parsedYear) {
86
+ return {
87
+ success: false,
88
+ error: `Year specified multiple times with different values: ${year} and ${parsedYear}`,
89
+ position
90
+ };
91
+ }
92
+ year = parsedYear;
93
+ position += 4;
94
+ break;
95
+ }
96
+ case "year2": {
97
+ const match = input.slice(position, position + 2);
98
+ if (match.length < 2 || !/^\d{2}$/.test(match)) {
99
+ return {
100
+ success: false,
101
+ error: `Expected 2-digit year`,
102
+ position
103
+ };
104
+ }
105
+ const yy = parseInt(match, 10);
106
+ // 2-digit year: 00-99 -> 2000-2099 (simple heuristic)
107
+ const parsedYear = 2000 + yy;
108
+ if (year !== null && year !== parsedYear) {
109
+ return {
110
+ success: false,
111
+ error: `Year specified multiple times with different values: ${year} and ${parsedYear}`,
112
+ position
113
+ };
114
+ }
115
+ year = parsedYear;
116
+ position += 2;
117
+ break;
118
+ }
119
+ case "month2": {
120
+ const match = input.slice(position, position + 2);
121
+ if (match.length < 2 || !/^\d{2}$/.test(match)) {
122
+ return {
123
+ success: false,
124
+ error: `Expected 2-digit month (01-12)`,
125
+ position
126
+ };
127
+ }
128
+ const parsedMonth = parseInt(match, 10);
129
+ if (parsedMonth < 1 || parsedMonth > 12) {
130
+ return {
131
+ success: false,
132
+ error: `Month out of range (got ${parsedMonth}, expected 01-12)`,
133
+ position
134
+ };
135
+ }
136
+ if (month !== null && month !== parsedMonth) {
137
+ return {
138
+ success: false,
139
+ error: `Month specified multiple times with different values: ${month} and ${parsedMonth}`,
140
+ position
141
+ };
142
+ }
143
+ month = parsedMonth;
144
+ position += 2;
145
+ break;
146
+ }
147
+ case "month1": {
148
+ // Try 2 digits first, then 1
149
+ let match = input.slice(position, position + 2);
150
+ let parsedMonth;
151
+ if (/^\d{2}$/.test(match)) {
152
+ parsedMonth = parseInt(match, 10);
153
+ position += 2;
154
+ }
155
+ else {
156
+ match = input.slice(position, position + 1);
157
+ if (!/^\d$/.test(match)) {
158
+ return {
159
+ success: false,
160
+ error: `Expected 1 or 2-digit month`,
161
+ position
162
+ };
163
+ }
164
+ parsedMonth = parseInt(match, 10);
165
+ position += 1;
166
+ }
167
+ if (parsedMonth < 1 || parsedMonth > 12) {
168
+ return {
169
+ success: false,
170
+ error: `Month out of range (got ${parsedMonth}, expected 1-12)`,
171
+ position: position - match.length
172
+ };
173
+ }
174
+ if (month !== null && month !== parsedMonth) {
175
+ return {
176
+ success: false,
177
+ error: `Month specified multiple times with different values: ${month} and ${parsedMonth}`,
178
+ position: position - match.length
179
+ };
180
+ }
181
+ month = parsedMonth;
182
+ break;
183
+ }
184
+ case "monthNameFull": {
185
+ let matched = false;
186
+ let parsedMonth = null;
187
+ for (let i = 0; i < MONTH_NAMES_FULL.length; i++) {
188
+ const name = MONTH_NAMES_FULL[i];
189
+ const slice = input.slice(position, position + name.length).toLowerCase();
190
+ if (slice === name) {
191
+ parsedMonth = i + 1;
192
+ position += name.length;
193
+ matched = true;
194
+ break;
195
+ }
196
+ }
197
+ if (!matched) {
198
+ return {
199
+ success: false,
200
+ error: `Expected full month name (e.g., "January")`,
201
+ position
202
+ };
203
+ }
204
+ if (month !== null && month !== parsedMonth) {
205
+ return {
206
+ success: false,
207
+ error: `Month specified multiple times with different values: ${month} and ${parsedMonth}`,
208
+ position
209
+ };
210
+ }
211
+ month = parsedMonth;
212
+ break;
213
+ }
214
+ case "monthNameShort": {
215
+ let matched = false;
216
+ let parsedMonth = null;
217
+ for (let i = 0; i < MONTH_NAMES_SHORT.length; i++) {
218
+ const name = MONTH_NAMES_SHORT[i];
219
+ const slice = input.slice(position, position + name.length).toLowerCase();
220
+ if (slice === name) {
221
+ parsedMonth = i + 1;
222
+ position += name.length;
223
+ matched = true;
224
+ break;
225
+ }
226
+ }
227
+ if (!matched) {
228
+ return {
229
+ success: false,
230
+ error: `Expected short month name (e.g., "Jan")`,
231
+ position
232
+ };
233
+ }
234
+ if (month !== null && month !== parsedMonth) {
235
+ return {
236
+ success: false,
237
+ error: `Month specified multiple times with different values: ${month} and ${parsedMonth}`,
238
+ position
239
+ };
240
+ }
241
+ month = parsedMonth;
242
+ break;
243
+ }
244
+ case "day2": {
245
+ const match = input.slice(position, position + 2);
246
+ if (match.length < 2 || !/^\d{2}$/.test(match)) {
247
+ return {
248
+ success: false,
249
+ error: `Expected 2-digit day (01-31)`,
250
+ position
251
+ };
252
+ }
253
+ const parsedDay = parseInt(match, 10);
254
+ if (parsedDay < 1 || parsedDay > 31) {
255
+ return {
256
+ success: false,
257
+ error: `Day out of range (got ${parsedDay}, expected 01-31)`,
258
+ position
259
+ };
260
+ }
261
+ if (day !== null && day !== parsedDay) {
262
+ return {
263
+ success: false,
264
+ error: `Day specified multiple times with different values: ${day} and ${parsedDay}`,
265
+ position
266
+ };
267
+ }
268
+ day = parsedDay;
269
+ position += 2;
270
+ break;
271
+ }
272
+ case "day1": {
273
+ // Try 2 digits first, then 1
274
+ let match = input.slice(position, position + 2);
275
+ let parsedDay;
276
+ if (/^\d{2}$/.test(match)) {
277
+ parsedDay = parseInt(match, 10);
278
+ position += 2;
279
+ }
280
+ else {
281
+ match = input.slice(position, position + 1);
282
+ if (!/^\d$/.test(match)) {
283
+ return {
284
+ success: false,
285
+ error: `Expected 1 or 2-digit day`,
286
+ position
287
+ };
288
+ }
289
+ parsedDay = parseInt(match, 10);
290
+ position += 1;
291
+ }
292
+ if (parsedDay < 1 || parsedDay > 31) {
293
+ return {
294
+ success: false,
295
+ error: `Day out of range (got ${parsedDay}, expected 1-31)`,
296
+ position: position - match.length
297
+ };
298
+ }
299
+ if (day !== null && day !== parsedDay) {
300
+ return {
301
+ success: false,
302
+ error: `Day specified multiple times with different values: ${day} and ${parsedDay}`,
303
+ position: position - match.length
304
+ };
305
+ }
306
+ day = parsedDay;
307
+ break;
308
+ }
309
+ // Weekday parsing - store for validation after Date construction
310
+ case "weekdayNameFull": {
311
+ let matched = false;
312
+ for (let i = 0; i < WEEKDAY_NAMES_FULL.length; i++) {
313
+ const name = WEEKDAY_NAMES_FULL[i];
314
+ const slice = input.slice(position, position + name.length).toLowerCase();
315
+ if (slice === name) {
316
+ // Map to JavaScript getDay() values: 0=Sunday, 1=Monday, ..., 6=Saturday
317
+ const weekdayValue = i;
318
+ if (parsedWeekday !== null && parsedWeekday !== weekdayValue) {
319
+ return {
320
+ success: false,
321
+ error: `Weekday specified multiple times with different values`,
322
+ position
323
+ };
324
+ }
325
+ parsedWeekday = weekdayValue;
326
+ position += name.length;
327
+ matched = true;
328
+ break;
329
+ }
330
+ }
331
+ if (!matched) {
332
+ return {
333
+ success: false,
334
+ error: `Expected full weekday name (e.g., "Monday")`,
335
+ position
336
+ };
337
+ }
338
+ break;
339
+ }
340
+ case "weekdayNameShort": {
341
+ let matched = false;
342
+ for (let i = 0; i < WEEKDAY_NAMES_SHORT.length; i++) {
343
+ const name = WEEKDAY_NAMES_SHORT[i];
344
+ const slice = input.slice(position, position + name.length).toLowerCase();
345
+ if (slice === name) {
346
+ // Map to JavaScript getDay() values: 0=Sunday, 1=Monday, ..., 6=Saturday
347
+ const weekdayValue = i;
348
+ if (parsedWeekday !== null && parsedWeekday !== weekdayValue) {
349
+ return {
350
+ success: false,
351
+ error: `Weekday specified multiple times with different values`,
352
+ position
353
+ };
354
+ }
355
+ parsedWeekday = weekdayValue;
356
+ position += name.length;
357
+ matched = true;
358
+ break;
359
+ }
360
+ }
361
+ if (!matched) {
362
+ return {
363
+ success: false,
364
+ error: `Expected short weekday name (e.g., "Mon")`,
365
+ position
366
+ };
367
+ }
368
+ break;
369
+ }
370
+ case "weekdayNameMin": {
371
+ let matched = false;
372
+ for (let i = 0; i < WEEKDAY_NAMES_MIN.length; i++) {
373
+ const name = WEEKDAY_NAMES_MIN[i];
374
+ const slice = input.slice(position, position + name.length).toLowerCase();
375
+ if (slice === name) {
376
+ // Map to JavaScript getDay() values: 0=Sunday, 1=Monday, ..., 6=Saturday
377
+ const weekdayValue = i;
378
+ if (parsedWeekday !== null && parsedWeekday !== weekdayValue) {
379
+ return {
380
+ success: false,
381
+ error: `Weekday specified multiple times with different values`,
382
+ position
383
+ };
384
+ }
385
+ parsedWeekday = weekdayValue;
386
+ position += name.length;
387
+ matched = true;
388
+ break;
389
+ }
390
+ }
391
+ if (!matched) {
392
+ return {
393
+ success: false,
394
+ error: `Expected minimal weekday name (e.g., "Mo")`,
395
+ position
396
+ };
397
+ }
398
+ break;
399
+ }
400
+ case "hour24_2": {
401
+ const match = input.slice(position, position + 2);
402
+ if (match.length < 2 || !/^\d{2}$/.test(match)) {
403
+ return {
404
+ success: false,
405
+ error: `Expected 2-digit hour (00-23)`,
406
+ position
407
+ };
408
+ }
409
+ const parsedHour = parseInt(match, 10);
410
+ if (parsedHour > 23) {
411
+ return {
412
+ success: false,
413
+ error: `Hour out of range (got ${parsedHour}, expected 00-23)`,
414
+ position
415
+ };
416
+ }
417
+ if (hour !== null && hour !== parsedHour) {
418
+ return {
419
+ success: false,
420
+ error: `Hour (24-hour) specified multiple times with different values: ${hour} and ${parsedHour}`,
421
+ position
422
+ };
423
+ }
424
+ hour = parsedHour;
425
+ position += 2;
426
+ break;
427
+ }
428
+ case "hour24_1": {
429
+ // Try 2 digits first, then 1
430
+ let match = input.slice(position, position + 2);
431
+ let parsedHour;
432
+ if (/^\d{2}$/.test(match)) {
433
+ parsedHour = parseInt(match, 10);
434
+ position += 2;
435
+ }
436
+ else {
437
+ match = input.slice(position, position + 1);
438
+ if (!/^\d$/.test(match)) {
439
+ return {
440
+ success: false,
441
+ error: `Expected 1 or 2-digit hour`,
442
+ position
443
+ };
444
+ }
445
+ parsedHour = parseInt(match, 10);
446
+ position += 1;
447
+ }
448
+ if (parsedHour > 23) {
449
+ return {
450
+ success: false,
451
+ error: `Hour out of range (got ${parsedHour}, expected 0-23)`,
452
+ position: position - match.length
453
+ };
454
+ }
455
+ if (hour !== null && hour !== parsedHour) {
456
+ return {
457
+ success: false,
458
+ error: `Hour (24-hour) specified multiple times with different values: ${hour} and ${parsedHour}`,
459
+ position: position - match.length
460
+ };
461
+ }
462
+ hour = parsedHour;
463
+ break;
464
+ }
465
+ case "hour12_2": {
466
+ const match = input.slice(position, position + 2);
467
+ if (match.length < 2 || !/^\d{2}$/.test(match)) {
468
+ return {
469
+ success: false,
470
+ error: `Expected 2-digit hour (01-12)`,
471
+ position
472
+ };
473
+ }
474
+ const parsedHour12 = parseInt(match, 10);
475
+ if (parsedHour12 < 1 || parsedHour12 > 12) {
476
+ return {
477
+ success: false,
478
+ error: `Hour out of range (got ${parsedHour12}, expected 01-12)`,
479
+ position
480
+ };
481
+ }
482
+ if (hour12 !== null && hour12 !== parsedHour12) {
483
+ return {
484
+ success: false,
485
+ error: `Hour (12-hour) specified multiple times with different values: ${hour12} and ${parsedHour12}`,
486
+ position
487
+ };
488
+ }
489
+ hour12 = parsedHour12;
490
+ position += 2;
491
+ break;
492
+ }
493
+ case "hour12_1": {
494
+ // Try 2 digits first, then 1
495
+ let match = input.slice(position, position + 2);
496
+ let parsedHour12;
497
+ if (/^\d{2}$/.test(match)) {
498
+ parsedHour12 = parseInt(match, 10);
499
+ position += 2;
500
+ }
501
+ else {
502
+ match = input.slice(position, position + 1);
503
+ if (!/^\d$/.test(match)) {
504
+ return {
505
+ success: false,
506
+ error: `Expected 1 or 2-digit hour`,
507
+ position
508
+ };
509
+ }
510
+ parsedHour12 = parseInt(match, 10);
511
+ position += 1;
512
+ }
513
+ if (parsedHour12 < 1 || parsedHour12 > 12) {
514
+ return {
515
+ success: false,
516
+ error: `Hour out of range (got ${parsedHour12}, expected 1-12)`,
517
+ position: position - match.length
518
+ };
519
+ }
520
+ if (hour12 !== null && hour12 !== parsedHour12) {
521
+ return {
522
+ success: false,
523
+ error: `Hour (12-hour) specified multiple times with different values: ${hour12} and ${parsedHour12}`,
524
+ position: position - match.length
525
+ };
526
+ }
527
+ hour12 = parsedHour12;
528
+ break;
529
+ }
530
+ case "minute2": {
531
+ const match = input.slice(position, position + 2);
532
+ if (match.length < 2 || !/^\d{2}$/.test(match)) {
533
+ return {
534
+ success: false,
535
+ error: `Expected 2-digit minute (00-59)`,
536
+ position
537
+ };
538
+ }
539
+ const parsedMinute = parseInt(match, 10);
540
+ if (parsedMinute > 59) {
541
+ return {
542
+ success: false,
543
+ error: `Minute out of range (got ${parsedMinute}, expected 00-59)`,
544
+ position
545
+ };
546
+ }
547
+ if (minute !== null && minute !== parsedMinute) {
548
+ return {
549
+ success: false,
550
+ error: `Minute specified multiple times with different values: ${minute} and ${parsedMinute}`,
551
+ position
552
+ };
553
+ }
554
+ minute = parsedMinute;
555
+ position += 2;
556
+ break;
557
+ }
558
+ case "minute1": {
559
+ // Try 2 digits first, then 1
560
+ let match = input.slice(position, position + 2);
561
+ let parsedMinute;
562
+ if (/^\d{2}$/.test(match)) {
563
+ parsedMinute = parseInt(match, 10);
564
+ position += 2;
565
+ }
566
+ else {
567
+ match = input.slice(position, position + 1);
568
+ if (!/^\d$/.test(match)) {
569
+ return {
570
+ success: false,
571
+ error: `Expected 1 or 2-digit minute`,
572
+ position
573
+ };
574
+ }
575
+ parsedMinute = parseInt(match, 10);
576
+ position += 1;
577
+ }
578
+ if (parsedMinute > 59) {
579
+ return {
580
+ success: false,
581
+ error: `Minute out of range (got ${parsedMinute}, expected 0-59)`,
582
+ position: position - match.length
583
+ };
584
+ }
585
+ if (minute !== null && minute !== parsedMinute) {
586
+ return {
587
+ success: false,
588
+ error: `Minute specified multiple times with different values: ${minute} and ${parsedMinute}`,
589
+ position: position - match.length
590
+ };
591
+ }
592
+ minute = parsedMinute;
593
+ break;
594
+ }
595
+ case "second2": {
596
+ const match = input.slice(position, position + 2);
597
+ if (match.length < 2 || !/^\d{2}$/.test(match)) {
598
+ return {
599
+ success: false,
600
+ error: `Expected 2-digit second (00-59)`,
601
+ position
602
+ };
603
+ }
604
+ const parsedSecond = parseInt(match, 10);
605
+ if (parsedSecond > 59) {
606
+ return {
607
+ success: false,
608
+ error: `Second out of range (got ${parsedSecond}, expected 00-59)`,
609
+ position
610
+ };
611
+ }
612
+ if (second !== null && second !== parsedSecond) {
613
+ return {
614
+ success: false,
615
+ error: `Second specified multiple times with different values: ${second} and ${parsedSecond}`,
616
+ position
617
+ };
618
+ }
619
+ second = parsedSecond;
620
+ position += 2;
621
+ break;
622
+ }
623
+ case "second1": {
624
+ // Try 2 digits first, then 1
625
+ let match = input.slice(position, position + 2);
626
+ let parsedSecond;
627
+ if (/^\d{2}$/.test(match)) {
628
+ parsedSecond = parseInt(match, 10);
629
+ position += 2;
630
+ }
631
+ else {
632
+ match = input.slice(position, position + 1);
633
+ if (!/^\d$/.test(match)) {
634
+ return {
635
+ success: false,
636
+ error: `Expected 1 or 2-digit second`,
637
+ position
638
+ };
639
+ }
640
+ parsedSecond = parseInt(match, 10);
641
+ position += 1;
642
+ }
643
+ if (parsedSecond > 59) {
644
+ return {
645
+ success: false,
646
+ error: `Second out of range (got ${parsedSecond}, expected 0-59)`,
647
+ position: position - match.length
648
+ };
649
+ }
650
+ if (second !== null && second !== parsedSecond) {
651
+ return {
652
+ success: false,
653
+ error: `Second specified multiple times with different values: ${second} and ${parsedSecond}`,
654
+ position: position - match.length
655
+ };
656
+ }
657
+ second = parsedSecond;
658
+ break;
659
+ }
660
+ case "millisecond3": {
661
+ const match = input.slice(position, position + 3);
662
+ if (match.length < 3 || !/^\d{3}$/.test(match)) {
663
+ return {
664
+ success: false,
665
+ error: `Expected 3-digit millisecond (000-999)`,
666
+ position
667
+ };
668
+ }
669
+ const parsedMillisecond = parseInt(match, 10);
670
+ if (millisecond !== null && millisecond !== parsedMillisecond) {
671
+ return {
672
+ success: false,
673
+ error: `Millisecond specified multiple times with different values: ${millisecond} and ${parsedMillisecond}`,
674
+ position
675
+ };
676
+ }
677
+ millisecond = parsedMillisecond;
678
+ position += 3;
679
+ break;
680
+ }
681
+ case "ampmUpper": {
682
+ const match = input.slice(position, position + 2).toUpperCase();
683
+ if (match === "AM") {
684
+ isPM = false;
685
+ position += 2;
686
+ }
687
+ else if (match === "PM") {
688
+ isPM = true;
689
+ position += 2;
690
+ }
691
+ else {
692
+ return {
693
+ success: false,
694
+ error: `Expected "AM" or "PM"`,
695
+ position
696
+ };
697
+ }
698
+ break;
699
+ }
700
+ case "ampmLower": {
701
+ const match = input.slice(position, position + 2).toLowerCase();
702
+ if (match === "am") {
703
+ isPM = false;
704
+ position += 2;
705
+ }
706
+ else if (match === "pm") {
707
+ isPM = true;
708
+ position += 2;
709
+ }
710
+ else {
711
+ return {
712
+ success: false,
713
+ error: `Expected "am" or "pm"`,
714
+ position
715
+ };
716
+ }
717
+ break;
718
+ }
719
+ case "literal": {
720
+ const expected = token.value;
721
+ const actual = input.slice(position, position + expected.length);
722
+ if (actual !== expected) {
723
+ return {
724
+ success: false,
725
+ error: `Expected literal "${expected}", got "${actual}"`,
726
+ position
727
+ };
728
+ }
729
+ position += expected.length;
730
+ break;
731
+ }
732
+ default: {
733
+ // TypeScript exhaustiveness check
734
+ const _exhaustive = token;
735
+ return {
736
+ success: false,
737
+ error: `Unknown token type: ${_exhaustive.type}`,
738
+ position
739
+ };
740
+ }
741
+ }
742
+ }
743
+ // Check for unconsumed input
744
+ if (position < input.length) {
745
+ return {
746
+ success: false,
747
+ error: `Unexpected trailing characters: "${input.slice(position)}"`,
748
+ position
749
+ };
750
+ }
751
+ // Prefix validation: Fill in defaults while checking for gaps in the component hierarchy
752
+ // The hierarchy is: Year → Month → Day → Hour → Minute → Second → Millisecond
753
+ // We check for gaps and fill in defaults from most significant to least significant
754
+ // Check if we have ANY date components to determine if this is a time-only format
755
+ const hasAnyDateComponent = year !== null || month !== null || day !== null;
756
+ let foundGap = false;
757
+ // Date components
758
+ if (year === null) {
759
+ if (hasAnyDateComponent) {
760
+ foundGap = true;
761
+ }
762
+ year = 1970; // Default epoch year for time-only formats
763
+ }
764
+ if (month === null) {
765
+ if (hasAnyDateComponent) {
766
+ foundGap = true;
767
+ }
768
+ month = 1;
769
+ }
770
+ else if (foundGap) {
771
+ // Can't have month if we already found a gap (e.g., no year)
772
+ return {
773
+ success: false,
774
+ error: `Invalid format: cannot have month without year`,
775
+ position: 0
776
+ };
777
+ }
778
+ if (day === null) {
779
+ if (hasAnyDateComponent) {
780
+ foundGap = true;
781
+ }
782
+ day = 1;
783
+ }
784
+ else if (foundGap) {
785
+ // Can't have day if we already found a gap
786
+ return {
787
+ success: false,
788
+ error: `Invalid format: cannot have day without year and month`,
789
+ position: 0
790
+ };
791
+ }
792
+ // Hour validation and conversion: handle hour24 vs hour12+AM/PM redundancy
793
+ if (hour !== null && hour12 !== null) {
794
+ // Both hour24 and hour12 specified - validate they match
795
+ let expectedHour24;
796
+ if (isPM === null) {
797
+ // hour12 without AM/PM is ambiguous - can't validate
798
+ return {
799
+ success: false,
800
+ error: `12-hour format specified without AM/PM indicator`,
801
+ position: 0
802
+ };
803
+ }
804
+ // Convert hour12 + isPM to hour24
805
+ if (isPM) {
806
+ expectedHour24 = hour12 === 12 ? 12 : hour12 + 12; // 12 PM -> 12, 1 PM -> 13
807
+ }
808
+ else {
809
+ expectedHour24 = hour12 === 12 ? 0 : hour12; // 12 AM -> 0, 1 AM -> 1
810
+ }
811
+ if (hour !== expectedHour24) {
812
+ return {
813
+ success: false,
814
+ error: `Hour mismatch: 24-hour format specifies ${hour}, but 12-hour format with ${isPM ? 'PM' : 'AM'} implies ${expectedHour24}`,
815
+ position: 0
816
+ };
817
+ }
818
+ }
819
+ else if (hour === null && hour12 !== null) {
820
+ // Only hour12 specified - convert to hour24
821
+ if (isPM === null) {
822
+ return {
823
+ success: false,
824
+ error: `12-hour format specified without AM/PM indicator`,
825
+ position: 0
826
+ };
827
+ }
828
+ if (isPM) {
829
+ hour = hour12 === 12 ? 12 : hour12 + 12; // 12 PM -> 12, 1 PM -> 13
830
+ }
831
+ else {
832
+ hour = hour12 === 12 ? 0 : hour12; // 12 AM -> 0, 1 AM -> 1
833
+ }
834
+ }
835
+ // Continue with time components
836
+ if (hour === null) {
837
+ foundGap = true;
838
+ hour = 0;
839
+ }
840
+ else if (foundGap) {
841
+ return {
842
+ success: false,
843
+ error: `Invalid format: cannot have hour without year, month, and day (or use time-only format)`,
844
+ position: 0
845
+ };
846
+ }
847
+ if (minute === null) {
848
+ foundGap = true;
849
+ minute = 0;
850
+ }
851
+ else if (foundGap) {
852
+ return {
853
+ success: false,
854
+ error: `Invalid format: cannot have minute without hour`,
855
+ position: 0
856
+ };
857
+ }
858
+ if (second === null) {
859
+ foundGap = true;
860
+ second = 0;
861
+ }
862
+ else if (foundGap) {
863
+ return {
864
+ success: false,
865
+ error: `Invalid format: cannot have second without minute`,
866
+ position: 0
867
+ };
868
+ }
869
+ if (millisecond === null) {
870
+ millisecond = 0;
871
+ }
872
+ else if (foundGap) {
873
+ return {
874
+ success: false,
875
+ error: `Invalid format: cannot have millisecond without second`,
876
+ position: 0
877
+ };
878
+ }
879
+ // Construct Date using UTC
880
+ const date = new Date(Date.UTC(year, month - 1, day, hour, minute, second, millisecond));
881
+ // Validate the date is actually valid (e.g., not Feb 31)
882
+ if (date.getUTCFullYear() !== year ||
883
+ date.getUTCMonth() !== month - 1 ||
884
+ date.getUTCDate() !== day) {
885
+ return {
886
+ success: false,
887
+ error: `Invalid date: ${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`,
888
+ position: 0
889
+ };
890
+ }
891
+ // Validate weekday if it was parsed
892
+ if (parsedWeekday !== null) {
893
+ const actualWeekday = date.getUTCDay();
894
+ if (actualWeekday !== parsedWeekday) {
895
+ const weekdayNames = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
896
+ return {
897
+ success: false,
898
+ error: `Weekday mismatch: parsed "${weekdayNames[parsedWeekday]}" but date is actually "${weekdayNames[actualWeekday]}"`,
899
+ position: 0
900
+ };
901
+ }
902
+ }
903
+ return {
904
+ success: true,
905
+ value: date
906
+ };
907
+ }
908
+ //# sourceMappingURL=parse.js.map