@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,592 @@
1
+ import { ParseFailed } from "../../grammar/engine.js";
2
+ import { BaseIdentifier, registerType, resolveType } from "../../model/identifier.js";
3
+ import { extendAttributes, keyValue } from "../../model/attribute.js";
4
+ import { BaseUrnGenerator } from "../../model/urn-generator.js";
5
+ const KIND_BY_TYPE = {
6
+ B: "basic-publication",
7
+ D: "document",
8
+ E: "expert-report",
9
+ G: "guide",
10
+ R: "recommendation",
11
+ S: "seminar-report",
12
+ V: "vocabulary",
13
+ };
14
+ const TYPE_STRINGS = {
15
+ "basic-publication": "B",
16
+ "certification-system": "CS",
17
+ document: "D",
18
+ "expert-report": "E",
19
+ guide: "G",
20
+ recommendation: "R",
21
+ "seminar-report": "S",
22
+ vocabulary: "V",
23
+ };
24
+ function isObj(v) {
25
+ return typeof v === "object" && v !== null && !Array.isArray(v);
26
+ }
27
+ function str(v) {
28
+ return v === undefined || v === null ? undefined : String(v);
29
+ }
30
+ /** Ruby Builder#extract_language. */
31
+ function extractLanguage(langData) {
32
+ if (isObj(langData))
33
+ return str(langData["language"]);
34
+ return str(langData);
35
+ }
36
+ /** ---- shared attribute tables (snake_case = default wire names) ---- */
37
+ const SINGLE_ATTRS = {
38
+ publisher: { type: "string" },
39
+ language: { type: "string" },
40
+ parsed_format: { type: "string", default: "short" },
41
+ number: { type: "string" },
42
+ part: { type: "string" },
43
+ subpart: { type: "string" },
44
+ suffix: { type: "string" },
45
+ space_suffix: { type: "boolean", default: false },
46
+ year: { type: "string" },
47
+ edition: { type: "string" },
48
+ stage: { type: "string" },
49
+ iteration: { type: "string" },
50
+ };
51
+ class OimlBase extends BaseIdentifier {
52
+ effectiveFormat() {
53
+ return this.parsed_format === "long" ? "long" : "short";
54
+ }
55
+ }
56
+ /** ---- single documents (CodeNumber + Bulletin) ---- */
57
+ class OimlSingle extends OimlBase {
58
+ /** Ruby Identifiers::CodeNumber#code. */
59
+ composedCode() {
60
+ if (this.number === undefined)
61
+ return undefined;
62
+ let result = this.number;
63
+ if (this.part)
64
+ result += `-${this.part}`;
65
+ if (this.subpart)
66
+ result += `-${this.subpart}`;
67
+ if (this.suffix)
68
+ result += `${this.space_suffix ? " " : "-"}${this.suffix}`;
69
+ return result;
70
+ }
71
+ typeString() {
72
+ return TYPE_STRINGS[this.constructor.polymorphicName.slice("pubid:oiml:".length)] ?? "R";
73
+ }
74
+ /** renderSingle — the formatOverride threads through supplement rendering. */
75
+ render(formatOverride) {
76
+ const format = formatOverride ?? this.effectiveFormat();
77
+ let result = `${this.publisher} ${this.typeString()} ${this.composedCode()}`;
78
+ let usingEditionFormat = false;
79
+ if (this.edition && this.year) {
80
+ result += ` ${this.edition} Edition ${this.year}`;
81
+ usingEditionFormat = true;
82
+ }
83
+ else if (this.edition) {
84
+ result += ` ${this.edition}`;
85
+ usingEditionFormat = true;
86
+ }
87
+ else if (this.year) {
88
+ if (format === "long") {
89
+ result += ` Edition ${this.year}`;
90
+ usingEditionFormat = true;
91
+ }
92
+ else {
93
+ result += `:${this.year}`;
94
+ }
95
+ }
96
+ if (this.stage || this.iteration) {
97
+ result += " ";
98
+ if (this.iteration)
99
+ result += this.iteration;
100
+ if (this.stage)
101
+ result += this.stage;
102
+ }
103
+ if (this.language) {
104
+ result +=
105
+ usingEditionFormat || this.parsed_format === "short_with_space"
106
+ ? ` (${this.language})`
107
+ : `(${this.language})`;
108
+ }
109
+ return result;
110
+ }
111
+ }
112
+ /** ---- OIML-CS certification-system documents ---- */
113
+ const CS_ATTRS = {
114
+ ...SINGLE_ATTRS,
115
+ family: { type: "string" },
116
+ amendment: { type: "string" },
117
+ space_separator: { type: "boolean", default: false },
118
+ };
119
+ const CS_MAPPINGS = keyValue(...Object.keys(CS_ATTRS).map((name) => ({ wire: name, to: name })));
120
+ // "OIML-CS PD-05 Edition 6 (Amendment 1)": the number keeps its printed
121
+ // zero padding; the print states an edition instead of a year.
122
+ class OimlCertificationSystem extends OimlSingle {
123
+ static polymorphicName = "pubid:oiml:certification-system";
124
+ static attributes = extendAttributes(BaseIdentifier, CS_ATTRS);
125
+ static mappings = CS_MAPPINGS;
126
+ render() {
127
+ let result = `${this.publisher}-CS ${this.family}` +
128
+ `${this.space_separator ? " " : "-"}${this.number} Edition ${this.edition}`;
129
+ if (this.amendment)
130
+ result += ` (Amendment ${this.amendment})`;
131
+ return result;
132
+ }
133
+ }
134
+ registerType(OimlCertificationSystem);
135
+ function oimlSingleClass(kind) {
136
+ const isBulletin = kind === "bulletin";
137
+ class OimlSingleIdentifier extends OimlSingle {
138
+ static polymorphicName = `pubid:oiml:${kind}`;
139
+ static attributes = isBulletin
140
+ ? extendAttributes(BaseIdentifier, { ...SINGLE_ATTRS, sequence: { type: "string" } })
141
+ : extendAttributes(BaseIdentifier, SINGLE_ATTRS);
142
+ render(formatOverride) {
143
+ if (!isBulletin)
144
+ return super.render(formatOverride);
145
+ // renderBulletin
146
+ if (this.parsed_format === "citation" &&
147
+ this.year &&
148
+ this.number &&
149
+ this.sequence) {
150
+ return `${this.publisher} Bulletin ${toRoman(Number(this.year) - 1959)}(${Number(this.number)}) ${this.year}${this.number}${this.sequence}`;
151
+ }
152
+ let result = `${this.publisher} Bulletin`;
153
+ if (this.year) {
154
+ result += ` ${this.year}`;
155
+ if (this.number)
156
+ result += `-${this.number}`;
157
+ if (this.sequence)
158
+ result += `-${this.sequence}`;
159
+ }
160
+ if (this.language)
161
+ result += ` (${this.language})`;
162
+ return result;
163
+ }
164
+ }
165
+ registerType(OimlSingleIdentifier);
166
+ return OimlSingleIdentifier;
167
+ }
168
+ const SUPP_ATTRS = {
169
+ language: { type: "string" },
170
+ parsed_format: { type: "string", default: "short" },
171
+ base: { type: OimlSingle },
172
+ supp_year: { type: "string" },
173
+ number: { type: "string" },
174
+ trailing: { type: "boolean", default: false },
175
+ joined: { type: "boolean", default: false },
176
+ letter: { type: "string" },
177
+ year_on_base: { type: "boolean", default: false },
178
+ };
179
+ const SUPP_MAPPINGS = keyValue({ wire: "language", to: "language" }, { wire: "parsed_format", to: "parsed_format" }, { wire: "base", to: "base" }, { wire: "year", to: "supp_year" }, { wire: "number", to: "number" }, { wire: "trailing", to: "trailing" }, { wire: "joined", to: "joined" }, { wire: "letter", to: "letter" }, { wire: "year_on_base", to: "year_on_base" });
180
+ /** ---- supplements (Amendment / Errata) and Annex ---- */
181
+ class OimlSupplement extends OimlBase {
182
+ supplementType() {
183
+ const kind = this.constructor.polymorphicName.slice("pubid:oiml:".length);
184
+ if (kind === "annex")
185
+ return this.letter ? `Annex ${this.letter}` : "Annexes";
186
+ return kind === "errata" ? "Errata" : "Amendment";
187
+ }
188
+ render() {
189
+ const kind = this.constructor.polymorphicName.slice("pubid:oiml:".length);
190
+ if (kind === "annex")
191
+ return this.renderAnnex();
192
+ return this.renderSupplement();
193
+ }
194
+ /** renderSupplement */
195
+ renderSupplement() {
196
+ if (this.joined) {
197
+ let result = `${stripLanguage(this.base.render())}+${this.supplementType()}`;
198
+ if (this.supp_year)
199
+ result += `:${this.supp_year}`;
200
+ if (this.language)
201
+ result += ` (${this.language})`;
202
+ return result;
203
+ }
204
+ if (this.trailing) {
205
+ let result = `${stripLanguage(this.base.render())} ${this.supplementType()}`;
206
+ if (this.number)
207
+ result += ` ${this.number}`;
208
+ if (this.language)
209
+ result += ` (${this.language})`;
210
+ return result;
211
+ }
212
+ const baseFormat = this.effectiveFormat() !== "short"
213
+ ? this.effectiveFormat()
214
+ : this.base.parsed_format === "long"
215
+ ? "long"
216
+ : "short";
217
+ const baseStr = stripLanguage(this.base.render(baseFormat));
218
+ let result = `${this.supplementType()} (${this.supp_year}) to ${baseStr}`;
219
+ if (this.language)
220
+ result += ` (${this.language})`;
221
+ return result;
222
+ }
223
+ /** renderAnnex */
224
+ renderAnnex() {
225
+ if (this.year_on_base) {
226
+ const marker = this.letter ? `Annex ${this.letter}` : "Annexes";
227
+ let result = `${stripLanguage(this.base.render())} ${marker}`;
228
+ if (this.language)
229
+ result += ` (${this.language})`;
230
+ return result;
231
+ }
232
+ const annexFormat = this.effectiveFormat();
233
+ const baseStr = this.base
234
+ .render(this.base.parsed_format === "long" ? "long" : "short")
235
+ .replace(/:.*/, "")
236
+ .replace(/\s+Edition\s+\d{4}/, "")
237
+ .replace(/\(.*\)/, "")
238
+ .trim();
239
+ let result = baseStr;
240
+ if (this.letter) {
241
+ result += ` Annex ${this.letter}`;
242
+ if (this.supp_year)
243
+ result += ` Edition ${this.supp_year}`;
244
+ }
245
+ else {
246
+ result += " Annexes";
247
+ if (this.supp_year) {
248
+ if (annexFormat === "long") {
249
+ result += ` Edition ${this.supp_year}`;
250
+ }
251
+ else {
252
+ result += `:${this.supp_year}`;
253
+ }
254
+ }
255
+ }
256
+ if (this.language)
257
+ result += ` (${this.language})`;
258
+ return result;
259
+ }
260
+ }
261
+ function oimlSupplementClass(kind) {
262
+ class OimlSupplementIdentifier extends OimlSupplement {
263
+ static polymorphicName = `pubid:oiml:${kind}`;
264
+ static attributes = extendAttributes(BaseIdentifier, SUPP_ATTRS);
265
+ static mappings = SUPP_MAPPINGS;
266
+ }
267
+ registerType(OimlSupplementIdentifier);
268
+ return OimlSupplementIdentifier;
269
+ }
270
+ const KIND_CLASSES = {};
271
+ for (const kind of [
272
+ "recommendation", "basic-publication", "document", "guide", "vocabulary",
273
+ "expert-report", "seminar-report", "bulletin",
274
+ ]) {
275
+ KIND_CLASSES[kind] = oimlSingleClass(kind);
276
+ }
277
+ KIND_CLASSES["certification-system"] = OimlCertificationSystem;
278
+ KIND_CLASSES["amendment"] = oimlSupplementClass("amendment");
279
+ KIND_CLASSES["errata"] = oimlSupplementClass("errata");
280
+ KIND_CLASSES["annex"] = oimlSupplementClass("annex");
281
+ /** ---- URN generator (lib/pubid/oiml/urn_generator.rb, all kinds) ---- */
282
+ class OimlUrnGenerator extends BaseUrnGenerator {
283
+ generate() {
284
+ const id = this.identifier;
285
+ const kind = id.constructor.polymorphicName.slice("pubid:oiml:".length);
286
+ if (kind === "bulletin") {
287
+ const b = id;
288
+ const parts = ["urn", "oiml", "bulletin"];
289
+ if (b.year) {
290
+ let locator = b.year;
291
+ if (b.number)
292
+ locator += `-${b.number}`;
293
+ if (b.sequence)
294
+ locator += `-${b.sequence}`;
295
+ parts.push(locator);
296
+ }
297
+ if (id.language)
298
+ parts.push(id.language.toLowerCase());
299
+ return parts.join(":");
300
+ }
301
+ // Certification-system documents: the family-number pair is the
302
+ // document identity ("cs:pd-05"); the printed edition and trailing
303
+ // amendment are print states, not URN segments.
304
+ if (kind === "certification-system") {
305
+ const cs = id;
306
+ return ["urn", "oiml", "cs", `${(cs.family ?? "").toLowerCase()}-${cs.number ?? ""}`].join(":");
307
+ }
308
+ const isSupp = kind === "amendment" || kind === "errata" || kind === "annex";
309
+ const single = (isSupp ? id.base : id);
310
+ const parts = ["urn", "oiml"];
311
+ // Ruby: `return "r" unless identifier.type` — a supplement has no
312
+ // type letter, so its URN carries the default "r" (corpus quirk).
313
+ parts.push(isSupp ? "r" : (TYPE_STRINGS[kind] ?? "r").toLowerCase());
314
+ // Ruby SupplementIdentifier#code delegates to the wrapped standard.
315
+ const code = single.composedCode();
316
+ if (code)
317
+ parts.push(code);
318
+ // The trailing-word form keeps the publication year on the base
319
+ // ("R 138:2009 Amendment 1"); the supplement itself carries only the
320
+ // ordinal.
321
+ const year = id.year ??
322
+ id.supp_year ??
323
+ (isSupp ? single.year : undefined);
324
+ if (year)
325
+ parts.push(year);
326
+ const stage = id.stage;
327
+ if (stage)
328
+ parts.push(stage.toLowerCase());
329
+ const iteration = id.iteration;
330
+ if (iteration)
331
+ parts.push(iteration);
332
+ if (id.language)
333
+ parts.push(id.language.toLowerCase());
334
+ // Ruby's supplement branch appends the ordinal after the language.
335
+ if (isSupp) {
336
+ const ordinal = id.number;
337
+ if (ordinal)
338
+ parts.push(ordinal);
339
+ }
340
+ return parts.join(":");
341
+ }
342
+ }
343
+ for (const klass of Object.values(KIND_CLASSES)) {
344
+ klass.urnGenerator = OimlUrnGenerator;
345
+ }
346
+ /** ---- builder (lib/pubid/oiml/builder.rb) ---- */
347
+ // OIML co-publishes some documents jointly with another SDO (ISO so
348
+ // far); the printed reference carries both identifiers joined by "|":
349
+ // "ISO 4064-1:2024|OIML R 49-1:2024". The URN is the OIML side's.
350
+ export class OimlDualPublished extends OimlBase {
351
+ static polymorphicName = "pubid:oiml:dual-published";
352
+ static get attributes() {
353
+ return extendAttributes(OimlBase, {
354
+ // "string" keeps objects passing through the scalar coercion
355
+ // untouched (the ieee AdoptedStandard precedent for cross-flavor
356
+ // members); the constructor coerces bare hashes via the registry.
357
+ first: { type: "string" },
358
+ second: { type: "string" },
359
+ });
360
+ }
361
+ static get mappings() {
362
+ return [
363
+ { wire: "first", to: "first" },
364
+ { wire: "second", to: "second" },
365
+ ];
366
+ }
367
+ constructor(attrs = {}) {
368
+ super(attrs);
369
+ // The members are cross-flavor (the co-publisher's side arrives as a
370
+ // bare hash with _type); coerce through the registry - the abstract
371
+ // BaseIdentifier attribute type cannot dispatch polymorphically.
372
+ const coerceMember = (v) => {
373
+ if (v instanceof BaseIdentifier)
374
+ return v;
375
+ if (typeof v === "object" && v !== null && "_type" in v) {
376
+ const klass = resolveType(v["_type"]);
377
+ if (klass !== undefined) {
378
+ return klass.fromHash(v);
379
+ }
380
+ }
381
+ return undefined;
382
+ };
383
+ const self = this;
384
+ const f = coerceMember(self["first"]);
385
+ const s = coerceMember(self["second"]);
386
+ if (f !== undefined)
387
+ self["first"] = f;
388
+ if (s !== undefined)
389
+ self["second"] = s;
390
+ }
391
+ render() {
392
+ return `${this.first.toHuman()}|${this.second.toHuman()}`;
393
+ }
394
+ toUrn() {
395
+ // The URN is the OIML side's, whichever position it prints in.
396
+ const oimlSide = this.second instanceof OimlBase ? this.second : this.first;
397
+ return oimlSide.toUrn();
398
+ }
399
+ root() {
400
+ return this.second instanceof OimlBase ? this.second : this.first;
401
+ }
402
+ }
403
+ registerType(OimlDualPublished);
404
+ export function buildOimlIdentifier(tree) {
405
+ if (!isObj(tree))
406
+ throw new ParseFailed("OIML: unexpected parse tree", 0);
407
+ if (tree["cs_series"] !== undefined)
408
+ return buildCs(tree);
409
+ if (tree["amd_marker"] !== undefined)
410
+ return buildShortAmendment(tree);
411
+ if (tree["base"] !== undefined)
412
+ return buildSupplement(tree);
413
+ return buildBaseDocument(tree);
414
+ }
415
+ // OIML-CS documents: family (PD/OD/CID), zero-padded number, the
416
+ // printed "Edition N", and an optional parenthesized trailing
417
+ // amendment. The family-number separator is a spelling flag.
418
+ function buildCs(tree) {
419
+ const attrs = {
420
+ publisher: str(tree["publisher"]) ?? "OIML",
421
+ parsed_format: "short",
422
+ };
423
+ const family = str(tree["cs_family"]);
424
+ if (family !== undefined)
425
+ attrs["family"] = family;
426
+ const number = str(tree["number"]);
427
+ if (number !== undefined)
428
+ attrs["number"] = number;
429
+ const edition = str(tree["edition"]);
430
+ if (edition !== undefined)
431
+ attrs["edition"] = edition;
432
+ const amendment = str(tree["cs_amendment"]);
433
+ if (amendment !== undefined)
434
+ attrs["amendment"] = amendment;
435
+ attrs["space_separator"] = tree["cs_separator"] === " ";
436
+ return new KIND_CLASSES["certification-system"](attrs);
437
+ }
438
+ function buildShortAmendment(tree) {
439
+ const baseCode = isObj(tree["base_code"]) ? tree["base_code"] : undefined;
440
+ const base = buildBaseDocument({
441
+ publisher: tree["publisher"],
442
+ type: tree["type"],
443
+ number: baseCode?.["number"],
444
+ part: baseCode?.["part"],
445
+ subpart: baseCode?.["subpart"],
446
+ });
447
+ const editionFormat = isObj(tree["edition_format"]) ? tree["edition_format"] : undefined;
448
+ const yearValue = editionFormat ? editionFormat["year"] : tree["year"];
449
+ const attrs = {
450
+ publisher: "OIML",
451
+ base,
452
+ parsed_format: editionFormat ? "long" : "short",
453
+ };
454
+ const suppYear = str(yearValue);
455
+ if (suppYear !== undefined)
456
+ attrs["supp_year"] = suppYear;
457
+ const language = extractLanguage(tree["language"]);
458
+ if (language !== undefined)
459
+ attrs["language"] = language;
460
+ return new KIND_CLASSES["amendment"](attrs);
461
+ }
462
+ function buildSupplement(tree) {
463
+ const marker = str(tree["trailing_marker"]);
464
+ const plusMarker = str(tree["plus_marker"]);
465
+ let kind;
466
+ if (tree["annex_letter"] !== undefined || tree["annex_marker"] !== undefined) {
467
+ kind = "annex";
468
+ }
469
+ else if (marker === "Errata" || plusMarker === "Errata") {
470
+ kind = "errata";
471
+ }
472
+ else {
473
+ kind = "amendment";
474
+ }
475
+ const base = buildOimlIdentifier(tree["base"]);
476
+ const editionFormat = isObj(tree["edition_format"]) ? tree["edition_format"] : undefined;
477
+ const yearValue = editionFormat ? editionFormat["year"] : tree["year"];
478
+ const attrs = {
479
+ publisher: "OIML",
480
+ base,
481
+ parsed_format: editionFormat ? "long" : "short",
482
+ };
483
+ const suppYear = str(yearValue);
484
+ if (suppYear !== undefined)
485
+ attrs["supp_year"] = suppYear;
486
+ const language = extractLanguage(tree["language"]);
487
+ if (language !== undefined)
488
+ attrs["language"] = language;
489
+ const ordinal = str(tree["number"]);
490
+ if (ordinal !== undefined)
491
+ attrs["number"] = ordinal;
492
+ if (marker !== undefined)
493
+ attrs["trailing"] = true;
494
+ if (plusMarker !== undefined)
495
+ attrs["joined"] = true;
496
+ const letter = str(tree["annex_letter"]);
497
+ if (letter !== undefined)
498
+ attrs["letter"] = letter;
499
+ // Annex with no year of its own but a dated base: the year belongs to
500
+ // the base and must render glued to it.
501
+ if (kind === "annex" && !yearValue && base.year)
502
+ attrs["year_on_base"] = true;
503
+ return new KIND_CLASSES[kind](attrs);
504
+ }
505
+ function buildBaseDocument(tree) {
506
+ const type = str(tree["type"]);
507
+ const kind = type === "Bulletin" ? "bulletin" : KIND_BY_TYPE[type ?? ""] ?? "recommendation";
508
+ const attrs = {
509
+ publisher: str(tree["publisher"]) ?? "OIML",
510
+ };
511
+ const number = str(tree["number"]);
512
+ if (number !== undefined)
513
+ attrs["number"] = number;
514
+ const part = str(tree["part"]);
515
+ if (part !== undefined)
516
+ attrs["part"] = part;
517
+ const subpart = str(tree["subpart"]);
518
+ if (subpart !== undefined)
519
+ attrs["subpart"] = subpart;
520
+ const codeSuffix = str(tree["code_suffix"]);
521
+ if (codeSuffix !== undefined)
522
+ attrs["suffix"] = codeSuffix;
523
+ if ("space_suffix" in tree)
524
+ attrs["space_suffix"] = true;
525
+ const editionFormat = isObj(tree["edition_format"]) ? tree["edition_format"] : undefined;
526
+ let yearValue;
527
+ if (editionFormat) {
528
+ yearValue = editionFormat["year"];
529
+ const edition = str(editionFormat["edition"]);
530
+ if (edition !== undefined)
531
+ attrs["edition"] = edition;
532
+ }
533
+ else {
534
+ yearValue = tree["year"];
535
+ }
536
+ const year = str(yearValue);
537
+ if (year !== undefined)
538
+ attrs["year"] = year;
539
+ if (kind === "bulletin")
540
+ applyBulletinLocator(attrs, tree);
541
+ attrs["parsed_format"] = editionFormat
542
+ ? "long"
543
+ : tree["space_before_lang"] !== undefined
544
+ ? "short_with_space"
545
+ : tree["article_id"] !== undefined
546
+ ? "citation"
547
+ : "short";
548
+ const stage = str(tree["stage"]);
549
+ if (stage !== undefined)
550
+ attrs["stage"] = stage;
551
+ const iteration = str(tree["iteration"]);
552
+ if (iteration !== undefined)
553
+ attrs["iteration"] = iteration;
554
+ const language = extractLanguage(tree["language"]);
555
+ if (language !== undefined)
556
+ attrs["language"] = language;
557
+ return new KIND_CLASSES[kind](attrs);
558
+ }
559
+ function applyBulletinLocator(attrs, tree) {
560
+ const articleId = str(tree["article_id"]);
561
+ if (articleId) {
562
+ attrs["year"] = articleId.slice(0, 4);
563
+ attrs["number"] = articleId.slice(4, 6);
564
+ attrs["sequence"] = articleId.slice(6, 8);
565
+ return;
566
+ }
567
+ const issue = str(tree["issue"]);
568
+ if (issue !== undefined)
569
+ attrs["number"] = issue;
570
+ const sequence = str(tree["sequence"]);
571
+ if (sequence !== undefined)
572
+ attrs["sequence"] = sequence;
573
+ }
574
+ /** ---- shared render helpers ---- */
575
+ function stripLanguage(s) {
576
+ return s.replace(/\s*\([^)]+\)\s*$/, "").trim();
577
+ }
578
+ function toRoman(n) {
579
+ const table = [
580
+ [1000, "M"], [900, "CM"], [500, "D"], [400, "CD"], [100, "C"],
581
+ [90, "XC"], [50, "L"], [40, "XL"], [10, "X"], [9, "IX"],
582
+ [5, "V"], [4, "IV"], [1, "I"],
583
+ ];
584
+ let out = "";
585
+ for (const [value, sym] of table) {
586
+ while (n >= value) {
587
+ out += sym;
588
+ n -= value;
589
+ }
590
+ }
591
+ return out;
592
+ }
@@ -0,0 +1,14 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
3
+ import { BaseIdentifier } from "../../model/identifier.js";
4
+ export declare const omgGrammar: Grammar;
5
+ export declare class OmgIdentifier extends BaseIdentifier {
6
+ static polymorphicName: string;
7
+ static attributes: import("../../model/attribute.js").AttributeTable;
8
+ static mappings: import("../../model/attribute.js").FieldMapping[];
9
+ readonly acronym: string;
10
+ readonly version: string | undefined;
11
+ readonly part: string | undefined;
12
+ render(): string;
13
+ }
14
+ export declare function omgGrammarImplementation(): FlavorImplementation;
@@ -0,0 +1,73 @@
1
+ import { match, str } from "../../grammar/engine.js";
2
+ import { ParseFailed, parseGrammar } from "../../grammar/engine.js";
3
+ import { BaseIdentifier, registerType } from "../../model/identifier.js";
4
+ import { extendAttributes, keyValue } from "../../model/attribute.js";
5
+ import { BaseBuilder } from "../../model/builder.js";
6
+ /**
7
+ * 1:1 port of lib/pubid/omg/ on the unified model. The Ruby flavor has
8
+ * no urn_generator, so toUrn() resolves to the base template: only
9
+ * `part` hits a slot, deriving "urn:omg:-PDF" / bare "urn:omg".
10
+ */
11
+ function buildRules() {
12
+ const rules = {};
13
+ const rule = (name, build) => {
14
+ rules[name] = build();
15
+ };
16
+ const space = str(" ");
17
+ const acronymChar = match("[A-Za-z0-9+]");
18
+ const wordBoundary = match("[A-Za-z0-9]").absent();
19
+ const beta = str(" beta").then(wordBoundary, space.then(match("[0-9]").repeat(1, Infinity), wordBoundary).maybe());
20
+ const partSeparator = space.or(str("/"));
21
+ rule("acronym", () => match("[A-Za-z]")
22
+ .then(acronymChar.repeat(0, Infinity), match("[-/]")
23
+ .then(acronymChar.repeat(1, Infinity))
24
+ .repeat(0, Infinity))
25
+ .as("acronym"));
26
+ rule("version", () => match("[0-9]")
27
+ .repeat(1, Infinity)
28
+ .then(str(".").then(match("[0-9]").repeat(1, Infinity)).repeat(0, Infinity), beta.maybe())
29
+ .as("version"));
30
+ rule("part", () => match("[A-Za-z0-9]").repeat(1, Infinity).as("part"));
31
+ rule("identifier", () => str("OMG").then(space, rules["acronym"], space
32
+ .then(rules["version"], partSeparator.then(rules["part"]).maybe())
33
+ .or(space.then(rules["part"]))
34
+ .maybe()));
35
+ rule("root", () => rules["identifier"]);
36
+ return rules;
37
+ }
38
+ export const omgGrammar = { rules: buildRules(), root: "root" };
39
+ export class OmgIdentifier extends BaseIdentifier {
40
+ static polymorphicName = "pubid:omg:specification";
41
+ static attributes = extendAttributes(BaseIdentifier, {
42
+ acronym: { type: "string" },
43
+ version: { type: "string" },
44
+ part: { type: "string" },
45
+ });
46
+ static mappings = keyValue({ wire: "acronym", to: "acronym" }, { wire: "version", to: "version" }, { wire: "part", to: "part" });
47
+ render() {
48
+ let result = `OMG ${this.acronym}`;
49
+ if (this.version !== undefined)
50
+ result += ` ${this.version}`;
51
+ if (this.part !== undefined)
52
+ result += ` ${this.part}`;
53
+ return result;
54
+ }
55
+ }
56
+ registerType(OmgIdentifier);
57
+ class OmgBuilder extends BaseBuilder {
58
+ defaultIdentifierClass() {
59
+ return OmgIdentifier;
60
+ }
61
+ }
62
+ export function omgGrammarImplementation() {
63
+ const builder = new OmgBuilder();
64
+ return {
65
+ parse(input) {
66
+ const tree = parseGrammar(omgGrammar, input);
67
+ if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
68
+ throw new ParseFailed("OMG: unexpected parse tree", 0);
69
+ }
70
+ return builder.build(tree);
71
+ },
72
+ };
73
+ }
@@ -0,0 +1,4 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
3
+ export declare const plateauGrammar: Grammar;
4
+ export declare function plateauGrammarImplementation(): FlavorImplementation;