@pubid/pubid 0.1.3 → 0.1.5

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 (185) hide show
  1. package/artifact/corpus.json.gz +0 -0
  2. package/dist/conformance/cli.js +5 -1
  3. package/dist/flavors/amca/grammar.d.ts +4 -0
  4. package/dist/flavors/amca/grammar.js +87 -0
  5. package/dist/flavors/amca/index.d.ts +4 -0
  6. package/dist/flavors/amca/index.js +76 -0
  7. package/dist/flavors/amca/model.d.ts +29 -0
  8. package/dist/flavors/amca/model.js +146 -0
  9. package/dist/flavors/ansi/index.d.ts +24 -0
  10. package/dist/flavors/ansi/index.js +147 -0
  11. package/dist/flavors/api/grammar.d.ts +4 -0
  12. package/dist/flavors/api/grammar.js +79 -0
  13. package/dist/flavors/api/index.d.ts +4 -0
  14. package/dist/flavors/api/index.js +71 -0
  15. package/dist/flavors/api/model.d.ts +27 -0
  16. package/dist/flavors/api/model.js +114 -0
  17. package/dist/flavors/ashrae/grammar.d.ts +2 -0
  18. package/dist/flavors/ashrae/grammar.js +667 -0
  19. package/dist/flavors/ashrae/index.d.ts +4 -0
  20. package/dist/flavors/ashrae/index.js +306 -0
  21. package/dist/flavors/ashrae/model.d.ts +87 -0
  22. package/dist/flavors/ashrae/model.js +335 -0
  23. package/dist/flavors/ashrae/preprocessor.d.ts +7 -0
  24. package/dist/flavors/ashrae/preprocessor.js +44 -0
  25. package/dist/flavors/asme/grammar.d.ts +2 -0
  26. package/dist/flavors/asme/grammar.js +200 -0
  27. package/dist/flavors/asme/index.d.ts +4 -0
  28. package/dist/flavors/asme/index.js +138 -0
  29. package/dist/flavors/asme/model.d.ts +34 -0
  30. package/dist/flavors/asme/model.js +123 -0
  31. package/dist/flavors/astm/grammar.d.ts +2 -0
  32. package/dist/flavors/astm/grammar.js +110 -0
  33. package/dist/flavors/astm/index.d.ts +2 -0
  34. package/dist/flavors/astm/index.js +127 -0
  35. package/dist/flavors/astm/model.d.ts +42 -0
  36. package/dist/flavors/astm/model.js +263 -0
  37. package/dist/flavors/bipm/index.d.ts +30 -0
  38. package/dist/flavors/bipm/index.js +434 -0
  39. package/dist/flavors/bsi/grammar.d.ts +4 -0
  40. package/dist/flavors/bsi/grammar.js +535 -0
  41. package/dist/flavors/bsi/index.d.ts +4 -0
  42. package/dist/flavors/bsi/index.js +941 -0
  43. package/dist/flavors/bsi/model.d.ts +127 -0
  44. package/dist/flavors/bsi/model.js +863 -0
  45. package/dist/flavors/calconnect/index.d.ts +21 -0
  46. package/dist/flavors/calconnect/index.js +113 -0
  47. package/dist/flavors/cen_cenelec/grammar.d.ts +4 -0
  48. package/dist/flavors/cen_cenelec/grammar.js +107 -0
  49. package/dist/flavors/cen_cenelec/index.d.ts +5 -0
  50. package/dist/flavors/cen_cenelec/index.js +263 -0
  51. package/dist/flavors/cen_cenelec/model.d.ts +45 -0
  52. package/dist/flavors/cen_cenelec/model.js +490 -0
  53. package/dist/flavors/cie/grammar.d.ts +5 -0
  54. package/dist/flavors/cie/grammar.js +127 -0
  55. package/dist/flavors/cie/index.d.ts +2 -0
  56. package/dist/flavors/cie/index.js +311 -0
  57. package/dist/flavors/cie/model.d.ts +122 -0
  58. package/dist/flavors/cie/model.js +464 -0
  59. package/dist/flavors/csa/grammar.d.ts +6 -0
  60. package/dist/flavors/csa/grammar.js +239 -0
  61. package/dist/flavors/csa/index.d.ts +2 -0
  62. package/dist/flavors/csa/index.js +634 -0
  63. package/dist/flavors/csa/model.d.ts +33 -0
  64. package/dist/flavors/csa/model.js +505 -0
  65. package/dist/flavors/doi/index.d.ts +13 -0
  66. package/dist/flavors/doi/index.js +65 -0
  67. package/dist/flavors/easc/index.d.ts +4 -0
  68. package/dist/flavors/easc/index.js +107 -0
  69. package/dist/flavors/ecma/index.d.ts +4 -0
  70. package/dist/flavors/ecma/index.js +117 -0
  71. package/dist/flavors/etsi/index.d.ts +14 -0
  72. package/dist/flavors/etsi/index.js +307 -0
  73. package/dist/flavors/evs/grammar.d.ts +2 -0
  74. package/dist/flavors/evs/grammar.js +22 -0
  75. package/dist/flavors/evs/index.d.ts +2 -0
  76. package/dist/flavors/evs/index.js +24 -0
  77. package/dist/flavors/evs/model.d.ts +19 -0
  78. package/dist/flavors/evs/model.js +36 -0
  79. package/dist/flavors/gb/index.d.ts +31 -0
  80. package/dist/flavors/gb/index.js +159 -0
  81. package/dist/flavors/gost/grammar.d.ts +2 -0
  82. package/dist/flavors/gost/grammar.js +46 -0
  83. package/dist/flavors/gost/index.d.ts +2 -0
  84. package/dist/flavors/gost/index.js +165 -0
  85. package/dist/flavors/gost/model.d.ts +61 -0
  86. package/dist/flavors/gost/model.js +147 -0
  87. package/dist/flavors/gost/prefix_routes.d.ts +15 -0
  88. package/dist/flavors/gost/prefix_routes.js +192 -0
  89. package/dist/flavors/iala/index.d.ts +32 -0
  90. package/dist/flavors/iala/index.js +300 -0
  91. package/dist/flavors/iana/index.d.ts +19 -0
  92. package/dist/flavors/iana/index.js +71 -0
  93. package/dist/flavors/idf/grammar.d.ts +2 -0
  94. package/dist/flavors/idf/grammar.js +71 -0
  95. package/dist/flavors/idf/index.d.ts +2 -0
  96. package/dist/flavors/idf/index.js +100 -0
  97. package/dist/flavors/idf/model.d.ts +54 -0
  98. package/dist/flavors/idf/model.js +359 -0
  99. package/dist/flavors/iec/grammar.d.ts +3 -0
  100. package/dist/flavors/iec/grammar.js +187 -0
  101. package/dist/flavors/iec/index.d.ts +4 -0
  102. package/dist/flavors/iec/index.js +507 -0
  103. package/dist/flavors/iec/model.d.ts +54 -0
  104. package/dist/flavors/iec/model.js +437 -0
  105. package/dist/flavors/ieee/grammar.d.ts +2 -0
  106. package/dist/flavors/ieee/grammar.js +697 -0
  107. package/dist/flavors/ieee/index.d.ts +3 -0
  108. package/dist/flavors/ieee/index.js +1258 -0
  109. package/dist/flavors/ieee/model.d.ts +144 -0
  110. package/dist/flavors/ieee/model.js +1237 -0
  111. package/dist/flavors/ieee/preprocessor.d.ts +8 -0
  112. package/dist/flavors/ieee/preprocessor.js +410 -0
  113. package/dist/flavors/ieee/update_codes.d.ts +8 -0
  114. package/dist/flavors/ieee/update_codes.js +197 -0
  115. package/dist/flavors/ietf/index.d.ts +30 -0
  116. package/dist/flavors/ietf/index.js +151 -0
  117. package/dist/flavors/iho/index.d.ts +4 -0
  118. package/dist/flavors/iho/index.js +126 -0
  119. package/dist/flavors/index.d.ts +9 -0
  120. package/dist/flavors/index.js +136 -0
  121. package/dist/flavors/isbn/index.d.ts +13 -0
  122. package/dist/flavors/isbn/index.js +97 -0
  123. package/dist/flavors/iso/grammar.d.ts +2 -0
  124. package/dist/flavors/iso/grammar.js +207 -0
  125. package/dist/flavors/iso/index.d.ts +2 -0
  126. package/dist/flavors/iso/index.js +343 -0
  127. package/dist/flavors/iso/model.d.ts +159 -0
  128. package/dist/flavors/iso/model.js +802 -0
  129. package/dist/flavors/iso/stages.generated.d.ts +13 -0
  130. package/dist/flavors/iso/stages.generated.js +391 -0
  131. package/dist/flavors/itu/grammar.d.ts +4 -0
  132. package/dist/flavors/itu/grammar.js +205 -0
  133. package/dist/flavors/itu/index.d.ts +2 -0
  134. package/dist/flavors/itu/index.js +224 -0
  135. package/dist/flavors/itu/model.d.ts +184 -0
  136. package/dist/flavors/itu/model.js +599 -0
  137. package/dist/flavors/jcgm/index.d.ts +7 -0
  138. package/dist/flavors/jcgm/index.js +300 -0
  139. package/dist/flavors/jis/index.d.ts +4 -0
  140. package/dist/flavors/jis/index.js +267 -0
  141. package/dist/flavors/nist/grammar.d.ts +2 -0
  142. package/dist/flavors/nist/grammar.js +287 -0
  143. package/dist/flavors/nist/index.d.ts +2 -0
  144. package/dist/flavors/nist/index.js +1244 -0
  145. package/dist/flavors/nist/model.d.ts +155 -0
  146. package/dist/flavors/nist/model.js +823 -0
  147. package/dist/flavors/nist/preprocessor.d.ts +11 -0
  148. package/dist/flavors/nist/preprocessor.js +281 -0
  149. package/dist/flavors/oasis/index.d.ts +23 -0
  150. package/dist/flavors/oasis/index.js +110 -0
  151. package/dist/flavors/ogc/index.d.ts +20 -0
  152. package/dist/flavors/ogc/index.js +75 -0
  153. package/dist/flavors/oiml/grammar.d.ts +2 -0
  154. package/dist/flavors/oiml/grammar.js +206 -0
  155. package/dist/flavors/oiml/implementation.d.ts +9 -0
  156. package/dist/flavors/oiml/implementation.js +45 -0
  157. package/dist/flavors/oiml/model.d.ts +23 -0
  158. package/dist/flavors/oiml/model.js +592 -0
  159. package/dist/flavors/omg/index.d.ts +14 -0
  160. package/dist/flavors/omg/index.js +73 -0
  161. package/dist/flavors/plateau/index.d.ts +4 -0
  162. package/dist/flavors/plateau/index.js +97 -0
  163. package/dist/flavors/tgpp/index.d.ts +4 -0
  164. package/dist/flavors/tgpp/index.js +122 -0
  165. package/dist/flavors/un/index.d.ts +13 -0
  166. package/dist/flavors/un/index.js +90 -0
  167. package/dist/flavors/w3c/index.d.ts +14 -0
  168. package/dist/flavors/w3c/index.js +148 -0
  169. package/dist/flavors/xsf/index.d.ts +18 -0
  170. package/dist/flavors/xsf/index.js +65 -0
  171. package/dist/grammar/engine.d.ts +78 -0
  172. package/dist/grammar/engine.js +351 -0
  173. package/dist/index.d.ts +1 -0
  174. package/dist/index.js +3 -0
  175. package/dist/model/attribute.d.ts +54 -0
  176. package/dist/model/attribute.js +53 -0
  177. package/dist/model/builder.d.ts +39 -0
  178. package/dist/model/builder.js +124 -0
  179. package/dist/model/component.d.ts +70 -0
  180. package/dist/model/component.js +170 -0
  181. package/dist/model/identifier.d.ts +84 -0
  182. package/dist/model/identifier.js +270 -0
  183. package/dist/model/urn-generator.d.ts +27 -0
  184. package/dist/model/urn-generator.js +91 -0
  185. package/package.json +1 -1
@@ -0,0 +1,206 @@
1
+ import { match, ref, str, } from "../../grammar/engine.js";
2
+ /**
3
+ * 1:1 port of lib/pubid/oiml/parser.rb (including CommonParseRules).
4
+ * Rule names match the Ruby rule names so the two files can be diffed
5
+ * side by side while porting.
6
+ */
7
+ function buildRules() {
8
+ const rules = {};
9
+ const rule = (name, build) => {
10
+ rules[name] = build();
11
+ };
12
+ // --- CommonParseRules ---
13
+ rule("space", () => str(" "));
14
+ rule("space?", () => ref(rules, "space").maybe());
15
+ rule("digits", () => match("\\d").repeat(1));
16
+ rule("year", () => match("\\d").repeat(4, 4).as("year"));
17
+ rule("comma", () => str(", "));
18
+ rule("comma?", () => ref(rules, "comma").maybe());
19
+ rule("comma_space", () => ref(rules, "comma").or(ref(rules, "space")));
20
+ rule("dash", () => str("-"));
21
+ rule("dot", () => str("."));
22
+ rule("words_digits", () => match("[\\dA-Za-z]").repeat(1));
23
+ rule("words", () => match("[A-Za-z]").repeat(1));
24
+ rule("words?", () => ref(rules, "words").maybe());
25
+ rule("year_digits", () => str("19").or(str("20")).then(match("\\d").repeat(2, 2), ref(rules, "digits").absent()));
26
+ rule("month_digits", () => match("\\d").repeat(2, 2));
27
+ rule("day_digits", () => match("\\d").repeat(2, 2));
28
+ rule("originator", () => ref(rules, "organization")
29
+ .as("publisher")
30
+ .then(ref(rules, "space?")
31
+ .then(str("/"), ref(rules, "organization").as("copublisher"))
32
+ .repeat(0)));
33
+ rule("comma_month_year", () => ref(rules, "comma").then(ref(rules, "words").as("month"), str(" "), ref(rules, "year_digits").as("year")));
34
+ rule("year_month", () => ref(rules, "year_digits").then(ref(rules, "dash"), ref(rules, "month_digits")));
35
+ // organization: OIML's parser never uses it (publisher is the literal
36
+ // "OIML"); provide a minimal definition so refs resolve.
37
+ rule("organization", () => str("OIML"));
38
+ // --- Additional basic rules not in CommonParseRules ---
39
+ rule("colon", () => str(":"));
40
+ rule("lparen", () => str("("));
41
+ rule("rparen", () => str(")"));
42
+ rule("slash", () => str("/"));
43
+ // Main identifier pattern - check supplements first
44
+ rule("identifier", () => ref(rules, "amendment_identifier")
45
+ .or(ref(rules, "amendment_short"))
46
+ .or(ref(rules, "annex_letter_identifier"))
47
+ .or(ref(rules, "annex_identifier"))
48
+ .or(ref(rules, "plus_supplement_identifier"))
49
+ .or(ref(rules, "trailing_supplement_identifier"))
50
+ .or(ref(rules, "cs_identifier"))
51
+ .or(ref(rules, "bulletin_identifier"))
52
+ .or(ref(rules, "base")));
53
+ // Publisher - always "OIML"
54
+ rule("publisher", () => str("OIML").as("publisher").then(ref(rules, "space")));
55
+ // Document type - single letter. Strict family set: OIML publishes
56
+ // R D B G E V S documents (the estate grammar's family letters);
57
+ // any other letter is a rejection, not a flavor.
58
+ rule("doc_type", () => match("[BDEGRSV]").as("type").then(ref(rules, "space")));
59
+ // Bulletin locator - structured YYYY[-II[-SS]]
60
+ rule("bulletin_date", () => ref(rules, "space")
61
+ .then(ref(rules, "year_digits").as("year"))
62
+ .then(ref(rules, "dash").then(ref(rules, "two_digits").as("issue")).maybe())
63
+ .then(ref(rules, "dash").then(ref(rules, "two_digits").as("sequence")).maybe()));
64
+ rule("two_digits", () => match("\\d").repeat(2, 2));
65
+ rule("roman_numeral", () => match("[IVXLCDM]").repeat(1).as("volume_roman"));
66
+ // Citation form: LXVII(2) 20260211
67
+ rule("bulletin_citation", () => ref(rules, "space")
68
+ .then(ref(rules, "roman_numeral"))
69
+ .then(ref(rules, "lparen"), ref(rules, "digits").as("issue_arabic"), ref(rules, "rparen"))
70
+ .then(str(" "), match("\\d").repeat(8, 8).as("article_id")));
71
+ rule("bulletin_identifier", () => ref(rules, "publisher")
72
+ .then(str("Bulletin").as("type"))
73
+ .then(ref(rules, "bulletin_citation").or(ref(rules, "bulletin_date")).maybe())
74
+ .then(ref(rules, "language_portion").maybe().as("language")));
75
+ rule("number_only", () => ref(rules, "digits").as("number"));
76
+ rule("part_number", () => ref(rules, "dash").then(ref(rules, "digits")
77
+ .then(ref(rules, "slash").then(ref(rules, "dash"), ref(rules, "digits")).repeat(0))
78
+ .as("part")));
79
+ rule("subpart_number", () => ref(rules, "dash").then(ref(rules, "digits").as("subpart")));
80
+ rule("named_suffix", () => ref(rules, "dash")
81
+ .then(str("GUM")
82
+ .then(ref(rules, "space"), ref(rules, "digits"))
83
+ .or(match("[A-Za-z]").repeat(1).then(str("_").maybe(), ref(rules, "digits")).repeat(0))
84
+ .as("code_suffix"))
85
+ .or(str(" ").then(str("Brochure").as("code_suffix"), str("").as("space_suffix"))));
86
+ rule("full_number", () => ref(rules, "number_only")
87
+ .then(ref(rules, "part_number"), ref(rules, "subpart_number"), ref(rules, "named_suffix").maybe())
88
+ .or(ref(rules, "number_only").then(ref(rules, "part_number"), ref(rules, "named_suffix").maybe()))
89
+ .or(ref(rules, "number_only").then(ref(rules, "named_suffix").maybe())));
90
+ rule("edition_number", () => str("6th")
91
+ .or(str("5th"))
92
+ .or(str("4th"))
93
+ .or(str("3rd"))
94
+ .or(str("2nd"))
95
+ .or(str("1st"))
96
+ .or(match("\\d").repeat(1).then(str("th").or(str("nd")).or(str("rd")).or(str("st"))))
97
+ .as("edition"));
98
+ rule("edition_text", () => str("Edition").or(str("edition")));
99
+ rule("edition_portion", () => str(", ")
100
+ .or(ref(rules, "space"))
101
+ .then(ref(rules, "edition_number").maybe(), ref(rules, "space?"), ref(rules, "edition_text"), ref(rules, "space?"), ref(rules, "year_digits").as("year"))
102
+ .as("edition_format"));
103
+ rule("date", () => ref(rules, "edition_portion")
104
+ // pubid#403: both sides of the colon are whitespace-tolerant
105
+ .or(ref(rules, "space?").then(ref(rules, "colon"), ref(rules, "space?"), ref(rules, "year_digits").as("year")))
106
+ .or(ref(rules, "space?").then(ref(rules, "lparen"), ref(rules, "year_digits").as("year"), ref(rules, "rparen"))));
107
+ rule("stage_iteration", () => match("\\d").repeat(1).then(str("."), match("\\d").repeat(1)).or(match("\\d").repeat(1)).as("iteration"));
108
+ rule("stage_abbr", () => str("WD").or(str("CD")).as("stage"));
109
+ rule("draft_stage", () => ref(rules, "space").then(ref(rules, "stage_iteration").maybe(), ref(rules, "stage_abbr")));
110
+ // Language codes: two-letter OIML codes before the single letters
111
+ rule("lang_single", () => match("[EFRXDSCAU]"));
112
+ rule("lang_multi_oiml", () => str("PO").or(str("PT")).or(str("PE")).or(str("SR")));
113
+ rule("lang_multi", () => match("[a-z]").repeat(2, 2));
114
+ // Full-word language markers as OIML prints them ("(Fra)", "(Eng)"),
115
+ // three or more letters, any case. Kept verbatim on the identifier;
116
+ // the URN lowercases.
117
+ rule("lang_word", () => match("[A-Za-z]").repeat(3));
118
+ rule("language_code", () => ref(rules, "lang_single")
119
+ .then(ref(rules, "slash"), ref(rules, "lang_single"))
120
+ .or(ref(rules, "lang_multi_oiml"))
121
+ .or(ref(rules, "lang_word"))
122
+ .or(ref(rules, "lang_single"))
123
+ .or(ref(rules, "lang_multi"))
124
+ .as("language"));
125
+ rule("language_with_space", () => ref(rules, "space")
126
+ .then(ref(rules, "lparen"), ref(rules, "language_code"), ref(rules, "rparen"))
127
+ .then(str("").as("space_before_lang")));
128
+ rule("language_without_space", () => ref(rules, "lparen").then(ref(rules, "language_code"), ref(rules, "rparen")));
129
+ rule("language_portion", () => ref(rules, "language_with_space").or(ref(rules, "language_without_space")));
130
+ // Amendment identifier - "Amendment (YYYY) to BASE"
131
+ rule("amendment_identifier", () => str("Amendment")
132
+ .then(ref(rules, "space"), ref(rules, "lparen"), ref(rules, "year_digits").as("year"), ref(rules, "rparen"))
133
+ .then(str(" "), str("to"), str(" "))
134
+ .then(ref(rules, "base_without_language").as("base"))
135
+ .then(ref(rules, "language_portion").maybe().as("language")));
136
+ rule("amendment_short", () => ref(rules, "publisher")
137
+ .then(ref(rules, "doc_type"))
138
+ .then(ref(rules, "full_number").as("base_code"))
139
+ .then(str(" "), str("Amendment").as("amd_marker"))
140
+ .then(str(" ")
141
+ .then(ref(rules, "edition_text"), ref(rules, "space?"), ref(rules, "year_digits").as("year"))
142
+ .as("edition_format")
143
+ .or(ref(rules, "colon").then(ref(rules, "space?"), ref(rules, "year_digits").as("year"))))
144
+ .then(ref(rules, "language_portion").maybe().as("language")));
145
+ rule("trailing_supplement_identifier", () => ref(rules, "base_without_language")
146
+ .as("base")
147
+ .then(str(" "), str("Amendment").or(str("Errata")).as("trailing_marker"))
148
+ .then(str(" ").then(ref(rules, "digits").as("number")).maybe(), ref(rules, "language_portion").maybe().as("language")));
149
+ // OIML-CS certification-system documents. Two head spellings
150
+ // ("OIML-CS" / "OIML CS") and two family-number separators
151
+ // ("PD-05" / "PD 05"), an "Edition N" instead of a year, and an
152
+ // optional parenthesized trailing amendment - "(Amendment 1)".
153
+ rule("cs_identifier", () => str("OIML")
154
+ .as("publisher")
155
+ .then(ref(rules, "dash")
156
+ .then(str("CS"))
157
+ .or(str(" ").then(str("CS")))
158
+ .as("cs_series"))
159
+ .then(ref(rules, "space"))
160
+ .then(str("PD").or(str("OD")).or(str("CID")).as("cs_family"))
161
+ .then(ref(rules, "dash").or(str(" ")).as("cs_separator"))
162
+ .then(ref(rules, "digits").as("number"))
163
+ .then(str(" "), str("Edition"), str(" "), ref(rules, "digits").as("edition"))
164
+ .then(str(" ")
165
+ .then(ref(rules, "lparen"), str("Amendment"), str(" "), ref(rules, "digits").as("cs_amendment"), ref(rules, "rparen"))
166
+ .maybe()));
167
+ rule("plus_supplement_identifier", () => ref(rules, "base_without_language")
168
+ .as("base")
169
+ .then(str("+"), str("Amendment").or(str("Errata")).as("plus_marker"))
170
+ .then(ref(rules, "colon").then(ref(rules, "year_digits").as("year")).maybe())
171
+ .then(ref(rules, "language_portion").maybe().as("language")));
172
+ rule("annex_identifier", () => ref(rules, "base_without_language")
173
+ .as("base")
174
+ .then(str(" "), str("Annexes").as("annex_marker"))
175
+ .then(str(" ")
176
+ .then(ref(rules, "edition_text"), str(" "), ref(rules, "year_digits").as("year"))
177
+ .as("edition_format")
178
+ .or(ref(rules, "colon").then(ref(rules, "year_digits").as("year")))
179
+ .maybe())
180
+ .then(ref(rules, "language_portion").maybe().as("language")));
181
+ rule("annex_letter_value", () => match("[A-Z]").then(ref(rules, "dash").then(match("[A-Z]")).maybe()).as("annex_letter"));
182
+ rule("annex_letter_identifier", () => ref(rules, "base_without_language")
183
+ .as("base")
184
+ .then(str(" "), str("Annex"), str(" "), ref(rules, "annex_letter_value"))
185
+ .then(str(" ")
186
+ .then(ref(rules, "edition_text"), str(" "), ref(rules, "year_digits").as("year"))
187
+ .or(ref(rules, "colon").then(ref(rules, "year_digits").as("year")))
188
+ .maybe())
189
+ .then(ref(rules, "language_portion").maybe().as("language")));
190
+ rule("base_without_language", () => ref(rules, "publisher")
191
+ .then(ref(rules, "doc_type"))
192
+ .then(ref(rules, "full_number"))
193
+ .then(ref(rules, "date").maybe())
194
+ .then(ref(rules, "draft_stage").maybe()));
195
+ rule("base", () => ref(rules, "publisher")
196
+ .then(ref(rules, "doc_type"))
197
+ .then(ref(rules, "full_number"))
198
+ .then(ref(rules, "date").maybe())
199
+ .then(ref(rules, "draft_stage").maybe())
200
+ .then(ref(rules, "language_portion").maybe()));
201
+ return rules;
202
+ }
203
+ export const oimlGrammar = {
204
+ rules: buildRules(),
205
+ root: "identifier",
206
+ };
@@ -0,0 +1,9 @@
1
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
2
+ import { ParseFailed } from "../../grammar/engine.js";
3
+ /**
4
+ * Grammar-backed OIML on the unified model: the model classes are
5
+ * BaseIdentifier subclasses, so they satisfy the Identifier adapter
6
+ * directly (toHash/toHuman/toUrn/fromHash come from the model).
7
+ */
8
+ export declare function oimlGrammarImplementation(): FlavorImplementation;
9
+ export { ParseFailed };
@@ -0,0 +1,45 @@
1
+ import { ParseFailed, parseGrammar } from "../../grammar/engine.js";
2
+ import { oimlGrammar } from "./grammar.js";
3
+ import { buildOimlIdentifier, OimlDualPublished } from "./model.js";
4
+ import { grammarImplementation } from "../index.js";
5
+ // The co-publisher prefix (only ISO confirmed so far; the gem routes via
6
+ // Pubid.parse's prefix table).
7
+ function flavorOf(input) {
8
+ return input.toUpperCase().startsWith("ISO ") ? "iso" : "iso";
9
+ }
10
+ /**
11
+ * Grammar-backed OIML on the unified model: the model classes are
12
+ * BaseIdentifier subclasses, so they satisfy the Identifier adapter
13
+ * directly (toHash/toHuman/toUrn/fromHash come from the model).
14
+ */
15
+ export function oimlGrammarImplementation() {
16
+ return {
17
+ parse(input) {
18
+ // The co-published form carries both identifiers joined by "|":
19
+ // "ISO 4064-1:2024|OIML R 49-1:2024". The first side is another
20
+ // flavor's identifier (routed by prefix, the Ruby Pubid.parse
21
+ // counterpart); the second is the OIML side.
22
+ if (input.includes("|") && !input.startsWith("|") && !input.endsWith("|")) {
23
+ // Each side may be either flavor ("ISO …|OIML R …" and the
24
+ // reversed print): the OIML side parses through this grammar, the
25
+ // co-publisher's through its own (routed by prefix).
26
+ const parts = input.split("|");
27
+ const members = parts.map((part) => {
28
+ const s = part.trim();
29
+ if (s.toUpperCase().startsWith("OIML")) {
30
+ return buildOimlIdentifier(parseGrammar(oimlGrammar, s));
31
+ }
32
+ const impl = grammarImplementation(flavorOf(s));
33
+ if (impl === undefined)
34
+ throw new ParseFailed(`OIML: no flavor for ${s}`, 0);
35
+ return impl.parse(s);
36
+ });
37
+ if (members.length === 2 && members[0] !== undefined && members[1] !== undefined) {
38
+ return new OimlDualPublished({ first: members[0], second: members[1] });
39
+ }
40
+ }
41
+ return buildOimlIdentifier(parseGrammar(oimlGrammar, input));
42
+ },
43
+ };
44
+ }
45
+ export { ParseFailed };
@@ -0,0 +1,23 @@
1
+ import type { Tree } from "../../grammar/engine.js";
2
+ import { BaseIdentifier } from "../../model/identifier.js";
3
+ import type { AttributeTable } from "../../model/attribute.js";
4
+ declare abstract class OimlBase extends BaseIdentifier {
5
+ readonly publisher: string | undefined;
6
+ readonly language: string | undefined;
7
+ readonly parsed_format: string | undefined;
8
+ effectiveFormat(): "long" | "short";
9
+ }
10
+ /** ---- builder (lib/pubid/oiml/builder.rb) ---- */
11
+ export declare class OimlDualPublished extends OimlBase {
12
+ static polymorphicName: string;
13
+ static get attributes(): AttributeTable;
14
+ static get mappings(): never[];
15
+ readonly first: BaseIdentifier;
16
+ readonly second: BaseIdentifier;
17
+ constructor(attrs?: Record<string, unknown>);
18
+ render(): string;
19
+ toUrn(): string;
20
+ root(): BaseIdentifier;
21
+ }
22
+ export declare function buildOimlIdentifier(tree: Tree): BaseIdentifier;
23
+ export {};