]> Lady’s Gitweb - Sutra/blob - xsd/productions.js
Initial commit
[Sutra] / xsd / productions.js
1 // ♓️🪡 सूत्र ∷ xsd/productions.js
2 // ====================================================================
3 //
4 // Copyright © 2023 Lady [@ Lady’s Computer].
5 //
6 // This Source Code Form is subject to the terms of the Mozilla Public
7 // License, v. 2.0. If a copy of the MPL was not distributed with this
8 // file, You can obtain one at <https://mozilla.org/MPL/2.0/>.
9
10 import {
11 Matcher,
12 objectCreate,
13 rawString,
14 stringSplit,
15 substring,
16 } from "../deps.js";
17
18 const dayOfMonthValuesConstraint = (day, month, year = "1972") => {
19 const d = +day;
20 const m = +month;
21 const y = +year;
22 return m === 4 || m === 6 || m === 9 || m === 11
23 ? d <= 30
24 : m === 2 && (y % 4 || !(y % 100) && y % 400)
25 ? d <= 28
26 : m === 2 && (!(y % 400) || !(y % 4) && y % 100)
27 ? d <= 29
28 : true;
29 };
30
31 export const {
32 /** `[1] stringRep ::= Char*` */
33 stringRep,
34
35 /** `[2] booleanRep ::= 'true' | 'false' | '1' | '0'` */
36 booleanRep,
37
38 /** `[3] decimalLexicalRep ::= decimalPtNumeral | noDecimalPtNumeral` */
39 decimalLexicalRep,
40
41 /** `[4] floatRep ::= noDecimalPtNumeral | decimalPtNumeral | scientificNotationNumeral | numericalSpecialRep` */
42 floatRep,
43
44 /** `[5] doubleRep ::= noDecimalPtNumeral | decimalPtNumeral | scientificNotationNumeral | numericalSpecialRep` */
45 doubleRep,
46
47 /** `[6] duYearFrag ::= unsignedNoDecimalPtNumeral 'Y'` */
48 duYearFrag,
49
50 /** `[7] duMonthFrag ::= unsignedNoDecimalPtNumeral 'M'` */
51 duMonthFrag,
52
53 /** `[8] duDayFrag ::= unsignedNoDecimalPtNumeral 'D'` */
54 duDayFrag,
55
56 /** `[9] duHourFrag ::= unsignedNoDecimalPtNumeral 'H'` */
57 duHourFrag,
58
59 /** `[10] duMinuteFrag ::= unsignedNoDecimalPtNumeral 'M'` */
60 duMinuteFrag,
61
62 /**
63 * `[11] duSecondFrag ::= (unsignedNoDecimalPtNumeral | unsignedFullDecimalPtNumeral) 'S'`
64 *
65 * ※ The X·S·D specification specifies unsignedDecimalPtNumeral, not
66 * unsignedFullDecimalPtNumeral, but the specification text and
67 * provided regular expressions imply that the latter was intended.
68 */
69 duSecondFrag,
70
71 /** `[12] duYearMonthFrag ::= (duYearFrag duMonthFrag?) | duMonthFrag` */
72 duYearMonthFrag,
73
74 /** `[13] duTimeFrag ::= 'T' ((duHourFrag duMinuteFrag? duSecondFrag?) | (duMinuteFrag duSecondFrag?) | duSecondFrag)` */
75 duTimeFrag,
76
77 /** `[14] duDayTimeFrag ::= (duDayFrag duTimeFrag?) | duTimeFrag` */
78 duDayTimeFrag,
79
80 /** `[15] durationLexicalRep ::= '-'? 'P' ((duYearMonthFrag duDayTimeFrag?) | duDayTimeFrag)` */
81 durationLexicalRep,
82
83 /**
84 * `[16] dateTimeLexicalRep ::= yearFrag '-' monthFrag '-' dayFrag 'T' ((hourFrag ':' minuteFrag ':' secondFrag) | endOfDayFrag) timezoneFrag?`
85 *
86 * **Constraint: Day-of-month Values**
87 *
88 * The ·day· value must be no more than 30 if ·month· is one of 4, 6,
89 * 9, or 11; no more than 28 if ·month· is 2 and ·year· is not
90 * divisible by 4, or is divisible by 100 but not by 400; and no more
91 * than 29 if ·month· is 2 and ·year· is divisible by 400, or by 4
92 * but not by 100.
93 *
94 * **Constraint: Day-of-month Representations**
95 *
96 * Within a dateTimeLexicalRep, a dayFrag must not begin with the
97 * digit '3' or be '29' unless the value to which it would map would
98 * satisfy the value constraint on ·day· values ("Constraint:
99 * Day-of-month Values") given above.
100 */
101 dateTimeLexicalRep,
102
103 /** `[17] timeLexicalRep ::= ((hourFrag ':' minuteFrag ':' secondFrag) | endOfDayFrag) timezoneFrag?` */
104 timeLexicalRep,
105
106 /**
107 * `[18] dateLexicalRep ::= yearFrag '-' monthFrag '-' dayFrag timezoneFrag?`
108 *
109 * **Constraint: Day-of-month Values**
110 *
111 * The ·day· value must be no more than 30 if ·month· is one of 4, 6,
112 * 9, or 11; no more than 28 if ·month· is 2 and ·year· is not
113 * divisible by 4, or is divisible by 100 but not by 400; and no more
114 * than 29 if ·month· is 2 and ·year· is divisible by 400, or by 4
115 * but not by 100.
116 *
117 * **Constraint: Day-of-month Representations**
118 *
119 * Within a dateLexicalRep, a dayFrag must not begin with the digit
120 * '3' or be '29' unless the value to which it would map would
121 * satisfy the value constraint on ·day· values ("Constraint:
122 * Day-of-month Values") given above.
123 */
124 dateLexicalRep,
125
126 /** `[19] gYearMonthLexicalRep ::= yearFrag '-' monthFrag timezoneFrag?` */
127 gYearMonthLexicalRep,
128
129 /** `[20] gYearLexicalRep ::= yearFrag timezoneFrag?` */
130 gYearLexicalRep,
131
132 /**
133 * `[21] gMonthDayLexicalRep ::= '--' monthFrag '-' dayFrag timezoneFrag?`
134 *
135 * **Constraint: Day-of-month Values**
136 *
137 * The ·day· value must be no more than 30 if ·month· is one of 4, 6,
138 * 9, or 11, and no more than 29 if ·month· is 2.
139 *
140 * **Constraint: Day-of-month Representations**
141 *
142 * Within a gMonthDayLexicalRep, a dayFrag must not begin with the
143 * digit '3' or be '29' unless the value to which it would map would
144 * satisfy the value constraint on ·day· values ("Constraint:
145 * Day-of-month Values") given above.
146 */
147 gMonthDayLexicalRep,
148
149 /** `[22] gDayLexicalRep ::= '---' dayFrag timezoneFrag?` */
150 gDayLexicalRep,
151
152 /** `[23] gMonthLexicalRep ::= '--' monthFrag timezoneFrag?` */
153 gMonthLexicalRep,
154
155 /** `[24] hexDigit ::= [0-9a-fA-F]` */
156 hexDigit,
157
158 /** `[25] hexOctet ::= hexDigit hexDigit` */
159 hexOctet,
160
161 /** `[26] hexBinary ::= hexOctet*` */
162 hexBinary,
163
164 /** `[27] Base64Binary ::= (B64quad* B64final)?` */
165 Base64Binary,
166
167 /** `[28] B64quad ::= (B64 B64 B64 B64)` */
168 B64quad,
169
170 /** `[29] B64final ::= B64finalquad | Padded16 | Padded8` */
171 B64final,
172
173 /** `[30] B64finalquad ::= (B64 B64 B64 B64char)` */
174 B64finalquad,
175
176 /** `[31] Padded16 ::= B64 B64 B16 '='` */
177 Padded16,
178
179 /** `[32] Padded8 ::= B64 B04 '=' #x20? '='` */
180 Padded8,
181
182 /** `[33] B64 ::= B64char #x20?` */
183 B64,
184
185 /** `[34] B64char ::= [A-Za-z0-9+/]` */
186 B64char,
187
188 /** `[35] B16 ::= B16char #x20?` */
189 B16,
190
191 /** `[36] B16char ::= [AEIMQUYcgkosw048]` */
192 B16char,
193
194 /** `[37] B04 ::= B04char #x20?` */
195 B04,
196
197 /** `[38] B04char ::= [AQgw]` */
198 B04char,
199
200 /** `[39] Canonical-base64Binary ::= CanonicalQuad* CanonicalPadded?` */
201 Canonical·base64Binary,
202
203 /** `[40] CanonicalQuad ::= B64char B64char B64char B64char` */
204 CanonicalQuad,
205
206 /** `[41] CanonicalPadded ::= B64char B64char B16char '=' | B64char B04char '=='` */
207 CanonicalPadded,
208
209 /** `[42] yearMonthDurationLexicalRep ::= '-'? 'P' duYearMonthFrag` */
210 yearMonthDurationLexicalRep,
211
212 /** `[43] dayTimeDurationLexicalRep ::= '-'? 'P' duDayTimeFrag` */
213 dayTimeDurationLexicalRep,
214
215 /**
216 * `[44] dateTimeStampLexicalRep ::= yearFrag '-' monthFrag '-' dayFrag 'T' ((hourFrag ':' minuteFrag ':' secondFrag) | endOfDayFrag) timezoneFrag`
217 *
218 * **Constraint: Day-of-month Values**
219 *
220 * The ·day· value must be no more than 30 if ·month· is one of 4, 6,
221 * 9, or 11; no more than 28 if ·month· is 2 and ·year· is not
222 * divisible by 4, or is divisible by 100 but not by 400; and no more
223 * than 29 if ·month· is 2 and ·year· is divisible by 400, or by 4
224 * but not by 100.
225 *
226 * **Constraint: Day-of-month Representations**
227 *
228 * Within a dateTimeStampLexicalRep, a dayFrag must not begin with
229 * the digit '3' or be '29' unless the value to which it would map
230 * would satisfy the value constraint on ·day· values ("Constraint:
231 * Day-of-month Values") given above.
232 */
233 dateTimeStampLexicalRep,
234
235 /** `[45] digit ::= [0-9]` */
236 digit,
237
238 /** `[46] unsignedNoDecimalPtNumeral ::= digit+` */
239 unsignedNoDecimalPtNumeral,
240
241 /** `[47] noDecimalPtNumeral ::= ('+' | '-')? unsignedNoDecimalPtNumeral` */
242 noDecimalPtNumeral,
243
244 /** `[48] fracFrag ::= digit+` */
245 fracFrag,
246
247 /** `[49] unsignedDecimalPtNumeral ::= (unsignedNoDecimalPtNumeral '.' fracFrag?) | ('.' fracFrag)` */
248 unsignedDecimalPtNumeral,
249
250 /** `[50] unsignedFullDecimalPtNumeral ::= unsignedNoDecimalPtNumeral '.' fracFrag` */
251 unsignedFullDecimalPtNumeral,
252
253 /** `[51] decimalPtNumeral ::= ('+' | '-')? unsignedDecimalPtNumeral` */
254 decimalPtNumeral,
255
256 /** `[52] unsignedScientificNotationNumeral ::= (unsignedNoDecimalPtNumeral | unsignedDecimalPtNumeral) ('e' | 'E') noDecimalPtNumeral` */
257 unsignedScientificNotationNumeral,
258
259 /** `[53] scientificNotationNumeral ::= ('+' | '-')? unsignedScientificNotationNumeral` */
260 scientificNotationNumeral,
261
262 /** `[54] minimalNumericalSpecialRep ::= 'INF' | '-INF' | 'NaN'` */
263 minimalNumericalSpecialRep,
264
265 /** `[55] numericalSpecialRep ::= ('+' | '-')? unsignedScientificNotationNumeral` */
266 numericalSpecialRep,
267
268 /** `[56] yearFrag ::= '-'? (([1-9] digit digit digit+)) | ('0' digit digit digit))` */
269 yearFrag,
270
271 /** `[57] monthFrag ::= ('0' [1-9]) | ('1' [0-2])` */
272 monthFrag,
273
274 /** `[58] dayFrag ::= ('0' [1-9]) | ([12] digit) | ('3' [01])` */
275 dayFrag,
276
277 /** `[59] hourFrag ::= ([01] digit) | ('2' [0-3])` */
278 hourFrag,
279
280 /** `[60] minuteFrag ::= [0-5] digit` */
281 minuteFrag,
282
283 /** `[61] secondFrag ::= ([0-5] digit) ('.' digit+)?` */
284 secondFrag,
285
286 /** `[62] endOfDayFrag ::= '24:00:00' ('.' '0'+)?` */
287 endOfDayFrag,
288
289 /** `[63] timezoneFrag ::= 'Z' | ('+' | '-') (('0' digit | '1' [0-3]) ':' minuteFrag | '14:00')` */
290 timezoneFrag,
291 } = (() => {
292 const matchers = objectCreate(null);
293 const match =
294 (name, constraint = null) => (strings, ...substitutions) => {
295 const source = `(?:${rawString(strings, ...substitutions)})`;
296 matchers[name] = new Matcher(`^${source}$`, name, constraint);
297 return source;
298 };
299
300 const stringRep = match(
301 "stringRep",
302 )`[^\u{0}\u{D800}-\u{DFFF}\u{FFFE}\u{FFFF}]*`;
303 const booleanRep = match("booleanRep")`true|false|1|0`;
304 const digit = match("digit")`[0-9]`;
305 const unsignedNoDecimalPtNumeral = match(
306 "unsignedNoDecimalPtNumeral",
307 )`${digit}+`;
308 const noDecimalPtNumeral = match(
309 "noDecimalPtNumeral",
310 )`[+-]?${unsignedNoDecimalPtNumeral}`;
311 const fracFrag = match("fracFrag")`${digit}+`;
312 const unsignedDecimalPtNumeral = match(
313 "unsignedDecimalPtNumeral",
314 )`${unsignedNoDecimalPtNumeral}\.${fracFrag}?|\.${fracFrag}`;
315 const unsignedFullDecimalPtNumeral = match(
316 "unsignedFullDecimalPtNumeral",
317 )`${unsignedNoDecimalPtNumeral}\.${fracFrag}`;
318 const decimalPtNumeral = match(
319 "decimalPtNumeral",
320 )`[+-]?${unsignedDecimalPtNumeral}`;
321 const unsignedScientificNotationNumeral = match(
322 "unsignedScientificNotationNumeral",
323 )`(?:${unsignedNoDecimalPtNumeral}|${unsignedDecimalPtNumeral})[eE]${noDecimalPtNumeral}`;
324 const scientificNotationNumeral = match(
325 "scientificNotationNumeral",
326 )`[+-]?${unsignedScientificNotationNumeral}`;
327 const minimalNumericalSpecialRep = match(
328 "minimalNumericalSpecialRep",
329 )`INF|-INF|NaN`;
330 const numericalSpecialRep = match(
331 "numericalSpecialRep",
332 )`\+INF|${minimalNumericalSpecialRep}`;
333 const decimalLexicalRep = match(
334 "decimalLexicalRep",
335 )`${decimalPtNumeral}|${noDecimalPtNumeral}`;
336 const floatRep = match(
337 "floatRep",
338 )`${noDecimalPtNumeral}|${decimalPtNumeral}|${scientificNotationNumeral}|${numericalSpecialRep}`;
339 const doubleRep = match(
340 "doubleRep",
341 )`${noDecimalPtNumeral}|${decimalPtNumeral}|${scientificNotationNumeral}|${numericalSpecialRep}`;
342 const duYearFrag = match(
343 "duYearFrag",
344 )`${unsignedNoDecimalPtNumeral}Y`;
345 const duMonthFrag = match(
346 "duMonthFrag",
347 )`${unsignedNoDecimalPtNumeral}M`;
348 const duDayFrag = match("duDayFrag")`${unsignedNoDecimalPtNumeral}D`;
349 const duHourFrag = match(
350 "duHourFrag",
351 )`${unsignedNoDecimalPtNumeral}H`;
352 const duMinuteFrag = match(
353 "duMinuteFrag",
354 )`${unsignedNoDecimalPtNumeral}M`;
355 const duSecondFrag = match(
356 "duSecondFrag",
357 )`(?:${unsignedNoDecimalPtNumeral}|${unsignedFullDecimalPtNumeral})S`;
358 const duYearMonthFrag = match(
359 "duYearMonthFrag",
360 )`${duYearFrag}${duMonthFrag}?|${duMonthFrag}`;
361 const duTimeFrag = match(
362 "duTimeFrag",
363 )`T(?:${duHourFrag}${duMinuteFrag}?${duSecondFrag}?|${duMinuteFrag}${duSecondFrag}?|${duSecondFrag})`;
364 const duDayTimeFrag = match(
365 "duDayTimeFrag",
366 )`${duDayFrag}${duTimeFrag}?|${duTimeFrag}`;
367 const durationLexicalRep = match(
368 "durationLexicalRep",
369 )`-?P(?:${duYearMonthFrag}${duDayTimeFrag}?|${duDayTimeFrag})`;
370 const yearFrag = match(
371 "yearFrag",
372 )`-?(?:[1-9]${digit}{3,}|0${digit}{3})`;
373 const monthFrag = match("monthFrag")`0[1-9]|1[0-2]`;
374 const dayFrag = match("dayFrag")`0[1-9]|[12]${digit}|3[01]`;
375 const hourFrag = match("hourFrag")`[01]${digit}|2[0-3]`;
376 const minuteFrag = match("minuteFrag")`[0-5]${digit}`;
377 const secondFrag = match(
378 "secondFrag",
379 )`[0-5]${digit}(?:\.${digit}+)?`;
380 const endOfDayFrag = match("endOfDayFrag")`24:00:00(?:\.0+)?`;
381 const timezoneFrag = match(
382 "timezoneFrag",
383 )`Z|[+-](?:(?:0${digit}|1[0-3]):${minuteFrag}|14:00)`;
384 const dateTimeLexicalRep = match("dateTimeLexicalRep", ($) => {
385 const components = stringSplit($, "-");
386 return components[0] === ""
387 ? dayOfMonthValuesConstraint(
388 substring(components[3], 0, 2),
389 components[2],
390 `-${components[1]}`,
391 )
392 : dayOfMonthValuesConstraint(
393 substring(components[2], 0, 2),
394 components[1],
395 components[0],
396 );
397 })`${yearFrag}-${monthFrag}-${dayFrag}T(?:${hourFrag}:${minuteFrag}:${secondFrag}|${endOfDayFrag})${timezoneFrag}?`;
398 const timeLexicalRep = match(
399 "timeLexicalRep",
400 )`(?:${hourFrag}:${minuteFrag}:${secondFrag}|${endOfDayFrag})${timezoneFrag}?`;
401 const dateLexicalRep = match("dateLexicalRep", ($) => {
402 const components = stringSplit($, "-");
403 return components[0] === ""
404 ? dayOfMonthValuesConstraint(
405 substring(components[3], 0, 2),
406 components[2],
407 `-${components[1]}`,
408 )
409 : dayOfMonthValuesConstraint(
410 substring(components[2], 0, 2),
411 components[1],
412 components[0],
413 );
414 })`${yearFrag}-${monthFrag}-${dayFrag}${timezoneFrag}?`;
415 const gYearMonthLexicalRep = match(
416 "gYearMonthLexicalRep",
417 )`${yearFrag}-${monthFrag}${timezoneFrag}?`;
418 const gYearLexicalRep = match(
419 "gYearLexicalRep",
420 )`${yearFrag}${timezoneFrag}?`;
421 const gMonthDayLexicalRep = match("gMonthDayLexicalRep", ($) => {
422 const components = stringSplit(substring($, 2), "-");
423 return dayOfMonthValuesConstraint(
424 substring(components[1], 0, 2),
425 components[0],
426 );
427 })`--${monthFrag}-${dayFrag}${timezoneFrag}?`;
428 const gDayLexicalRep = match(
429 "gDayLexicalRep",
430 )`---${dayFrag}${timezoneFrag}?`;
431 const gMonthLexicalRep = match(
432 "gMonthLexicalRep",
433 )`--${monthFrag}${timezoneFrag}?`;
434 const hexDigit = match("hexDigit")`[0-9a-fA-F]`;
435 const hexOctet = match("hexOctet")`${hexDigit}{2}`;
436 const hexBinary = match("hexBinary")`${hexOctet}*`;
437 const B04char = match("B04char")`[AQgw]`;
438 const B04 = match("B04")`${B04char}\u{20}?`;
439 const B16char = match("B16char")`[AEIMQUYcgkosw048]`;
440 const B16 = match("B16")`${B16char}\u{20}?`;
441 const B64char = match("B64char")`[A-Za-z0-9+/]`;
442 const B64 = match("B64")`${B64char}\u{20}?`;
443 const Padded8 = match("Padded8")`${B64}${B04}=\u{20}?=`;
444 const Padded16 = match("Padded16")`${B64}{2}${B16}=`;
445 const B64finalquad = match("B64finalquad")`${B64}{3}${B64char}`;
446 const B64final = match(
447 "B64final",
448 )`${B64finalquad}|${Padded16}|${Padded8}`;
449 const B64quad = match("B64quad")`${B64}{4}`;
450 const Base64Binary = match(
451 "Base64Binary",
452 )`(?:${B64quad}*${B64final})?`;
453 const CanonicalPadded = match(
454 "CanonicalPadded",
455 )`${B64char}{2}${B16char}=|${B64char}${B04char}==`;
456 const CanonicalQuad = match("CanonicalQuad")`${B64char}{4}`;
457 const Canonical·base64Binary = match(
458 "Canonical·base64Binary",
459 )`${CanonicalQuad}*${CanonicalPadded}?`;
460 const yearMonthDurationLexicalRep = match(
461 "yearMonthDurationLexicalRep",
462 )`-?P${duYearMonthFrag}`;
463 const dayTimeDurationLexicalRep = match(
464 "dayTimeDurationLexicalRep",
465 )`-?P${duDayTimeFrag}`;
466 const dateTimeStampLexicalRep = match(
467 "dateTimeStampLexicalRep",
468 ($) => {
469 const components = stringSplit($, "-");
470 return components[0] === ""
471 ? dayOfMonthValuesConstraint(
472 substring(components[3], 0, 2),
473 components[2],
474 `-${components[1]}`,
475 )
476 : dayOfMonthValuesConstraint(
477 substring(components[2], 0, 2),
478 components[1],
479 components[0],
480 );
481 },
482 )`${yearFrag}-${monthFrag}-${dayFrag}T(?:${hourFrag}:${minuteFrag}:${secondFrag}|${endOfDayFrag})${timezoneFrag}`;
483
484 return matchers;
485 })();
This page took 0.098102 seconds and 5 git commands to generate.