@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,300 @@
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 { BaseUrnGenerator } from "../../model/urn-generator.js";
6
+ import { BaseBuilder } from "../../model/builder.js";
7
+ import { PubidDate, Language } from "../../model/component.js";
8
+ /**
9
+ * Port of lib/pubid/jcgm/ on the unified model. Five concrete classes
10
+ * (guide, gum-guide, meeting, amendment, corrigendum); the date
11
+ * serializes FLAT as year/month/day through the converter mapping trio
12
+ * (Ruby's year_to_kv pattern); the ordinal suffix ("11st") is computed
13
+ * from the number at render time; supplements hold a nested base. The
14
+ * typed_stage is runtime-derived from the class (never serialized).
15
+ */
16
+ function buildRules() {
17
+ const rules = {};
18
+ const rule = (name, build) => {
19
+ rules[name] = build();
20
+ };
21
+ const space = str(" ");
22
+ const digits = match("[0-9]").repeat(1, Infinity);
23
+ // CommonParseRules year_digits: 19xx/20xx not followed by a digit.
24
+ const yearDigits = str("19").or(str("20")).then(match("\\d").repeat(2, 2), digits.absent());
25
+ const monthDigits = match("[0-9]").repeat(2, 2);
26
+ const dayDigits = match("[0-9]").repeat(2, 2);
27
+ const fullDate = yearDigits.then(str("-"), monthDigits, str("-"), dayDigits).as("date");
28
+ const datePortion = str(":").then(fullDate.or(yearDigits.as("date")));
29
+ rule("publisher", () => str("JCGM").as("publisher"));
30
+ rule("number_portion", () => str("GUM-").then(digits.as("gum_number")).or(digits.as("number")));
31
+ rule("language_portion", () => str("(")
32
+ .then((str("E/F").or(str("F/E")).or(match("[A-Z]"))).as("languages"), str(")")));
33
+ rule("base", () => rules["publisher"]
34
+ .then(space, rules["number_portion"])
35
+ .then(datePortion.maybe())
36
+ .then(rules["language_portion"].maybe()));
37
+ rule("ordinal_suffix", () => str("st").or(str("nd"), str("rd"), str("th")));
38
+ rule("meeting_identifier", () => rules["publisher"]
39
+ .then(space, digits.as("number"), rules["ordinal_suffix"])
40
+ .then(space, str("Meeting").as("type_with_stage"))
41
+ .then(space.then(str("("), yearDigits.as("date"), str(")")).maybe()));
42
+ rule("corrigendum_identifier", () => rules["base"].as("base").then(space, str("Corrigendum").as("type_with_stage")));
43
+ rule("numbered_corrigendum_identifier", () => rules["base"]
44
+ .as("base")
45
+ .then(str("/"), str("Cor").as("type_with_stage"))
46
+ .then(space, digits.as("number"))
47
+ .then(datePortion.maybe()));
48
+ rule("amendment_identifier", () => rules["base"]
49
+ .as("base")
50
+ .then(str("/"), str("Amd").as("type_with_stage"))
51
+ .then(space, digits.as("number"))
52
+ .then(datePortion.maybe()));
53
+ rule("named_number", () => (str("GUM").or(str("VIM").then(str("-").then(digits).maybe()))).as("number"));
54
+ rule("named_guide_identifier", () => rules["publisher"].then(space, rules["named_number"]));
55
+ rule("identifier", () => rules["meeting_identifier"]
56
+ .or(rules["amendment_identifier"])
57
+ .or(rules["corrigendum_identifier"])
58
+ .or(rules["numbered_corrigendum_identifier"])
59
+ .or(rules["base"])
60
+ .or(rules["named_guide_identifier"]));
61
+ rule("root", () => rules["identifier"]);
62
+ return rules;
63
+ }
64
+ export const jcgmGrammar = { rules: buildRules(), root: "root" };
65
+ const JCGM_ATTRS = {
66
+ number: { type: "string" },
67
+ part: { type: "string" },
68
+ subpart: { type: "string" },
69
+ date: { type: PubidDate },
70
+ languages: { type: Language, collection: true, initializeEmpty: true },
71
+ };
72
+ // The calconnect-style converter trio: the date serializes FLAT as
73
+ // year/month/day.
74
+ const DATE_MAPPINGS = keyValue({
75
+ wire: "year",
76
+ to: "date",
77
+ toWire: (m) => m["date"]?.year,
78
+ fromWire: (h) => h["year"] === undefined || h["year"] === null
79
+ ? undefined
80
+ : new PubidDate({
81
+ year: String(h["year"]),
82
+ month: h["month"],
83
+ day: h["day"],
84
+ }),
85
+ }, { wire: "month", to: "date", toWire: (m) => m["date"]?.month, fromWire: () => undefined }, { wire: "day", to: "date", toWire: (m) => m["date"]?.day, fromWire: () => undefined });
86
+ class JcgmIdentifier extends BaseIdentifier {
87
+ /** generate_base_urn shape: urn:jcgm:<number>[:part...]:date... */
88
+ baseUrnParts() {
89
+ const parts = ["urn", "jcgm"];
90
+ if (this.number !== undefined)
91
+ parts.push(this.number);
92
+ if (this.part !== undefined)
93
+ parts.push(`-${this.part}`);
94
+ if (this.subpart !== undefined)
95
+ parts.push(`-${this.subpart}`);
96
+ const rendered = this.date?.render("urn");
97
+ if (rendered !== undefined && rendered !== "")
98
+ parts.push(rendered);
99
+ return parts;
100
+ }
101
+ /** The date as printed (PubidDate#to_s): "2008" / "2022-11-28". */
102
+ dateToS() {
103
+ return this.date?.render() ?? "";
104
+ }
105
+ languagePortion() {
106
+ return this.languages.length === 0
107
+ ? ""
108
+ : `(${this.languages.map((l) => l.originalCode ?? l.code).join("/")})`;
109
+ }
110
+ /** English ordinal suffix computed from the number (11st, 12nd, 13rd…). */
111
+ ordinalSuffix() {
112
+ if (this.number === undefined)
113
+ return "th";
114
+ const mod = Number(this.number) % 10;
115
+ return mod === 1 ? "st" : mod === 2 ? "nd" : mod === 3 ? "rd" : "th";
116
+ }
117
+ }
118
+ function jcgmClass(kind, attrs, mappings) {
119
+ class JcgmKindIdentifier extends JcgmIdentifier {
120
+ static polymorphicName = `pubid:jcgm:${kind}`;
121
+ static attributes = extendAttributes(BaseIdentifier, attrs);
122
+ static mappings = mappings;
123
+ render() {
124
+ const id = this;
125
+ switch (kind) {
126
+ case "meeting": {
127
+ const base = `JCGM ${id.number}${this.ordinalSuffix()} Meeting`;
128
+ const year = id.date?.year;
129
+ return year === undefined ? base : `${base} (${year})`;
130
+ }
131
+ case "amendment": {
132
+ let result = `${id.base?.render() ?? ""}/Amd`;
133
+ if (id.number !== undefined)
134
+ result += ` ${id.number}`;
135
+ const d = this.dateToS();
136
+ if (d !== "")
137
+ result += `:${d}`;
138
+ return result;
139
+ }
140
+ case "corrigendum": {
141
+ if (id.number !== undefined) {
142
+ const d = this.dateToS();
143
+ return `${id.base?.render() ?? ""}/Cor ${id.number}${d === "" ? "" : `:${d}`}`;
144
+ }
145
+ return `${id.base?.render() ?? ""} Corrigendum`;
146
+ }
147
+ case "gum-guide": {
148
+ let result = `JCGM GUM-${id.number}`;
149
+ const d = this.dateToS();
150
+ if (d !== "")
151
+ result += `:${d}`;
152
+ result += this.languagePortion();
153
+ return result;
154
+ }
155
+ default: {
156
+ let result = "JCGM";
157
+ let portion = id.number ?? "";
158
+ const d = this.dateToS();
159
+ if (portion !== "" && d !== "")
160
+ portion += `:${d}`;
161
+ if (portion !== "")
162
+ result += ` ${portion}`;
163
+ result += this.languagePortion();
164
+ return result;
165
+ }
166
+ }
167
+ }
168
+ }
169
+ registerType(JcgmKindIdentifier);
170
+ return JcgmKindIdentifier;
171
+ }
172
+ const KIND_CLASSES = {
173
+ guide: jcgmClass("guide", JCGM_ATTRS, keyValue({ wire: "number", to: "number" }, { wire: "part", to: "part" }, { wire: "subpart", to: "subpart" }, ...DATE_MAPPINGS, { wire: "languages", to: "languages" })),
174
+ "gum-guide": jcgmClass("gum-guide", JCGM_ATTRS, keyValue({ wire: "number", to: "number" }, { wire: "part", to: "part" }, { wire: "subpart", to: "subpart" }, ...DATE_MAPPINGS, { wire: "languages", to: "languages" })),
175
+ meeting: jcgmClass("meeting", JCGM_ATTRS, keyValue({ wire: "number", to: "number" }, ...DATE_MAPPINGS)),
176
+ amendment: jcgmClass("amendment", { ...JCGM_ATTRS, base: { type: undefined } }, keyValue({ wire: "number", to: "number" }, ...DATE_MAPPINGS, { wire: "base", to: "base" })),
177
+ corrigendum: jcgmClass("corrigendum", { ...JCGM_ATTRS, base: { type: undefined } }, keyValue({ wire: "number", to: "number" }, ...DATE_MAPPINGS, { wire: "base", to: "base" })),
178
+ };
179
+ // base attr needs the abstract self-type for polymorphic coercion.
180
+ KIND_CLASSES["amendment"].attributes["base"] = { type: JcgmIdentifier };
181
+ KIND_CLASSES["corrigendum"].attributes["base"] = { type: JcgmIdentifier };
182
+ class JcgmUrnGenerator extends BaseUrnGenerator {
183
+ generate() {
184
+ const kind = this.identifier.constructor.polymorphicName.slice("pubid:jcgm:".length);
185
+ if (kind === "meeting") {
186
+ const parts = ["urn", "jcgm", "meeting"];
187
+ if (this.identifier.number)
188
+ parts.push(this.identifier.number);
189
+ const year = this.identifier.date?.year;
190
+ if (year !== undefined)
191
+ parts.push(year);
192
+ return parts.join(":");
193
+ }
194
+ if (kind === "amendment" || kind === "corrigendum") {
195
+ const base = this.identifier.base;
196
+ if (!base)
197
+ return "urn:jcgm:unknown";
198
+ const parts = [...base.baseUrnParts()];
199
+ parts.push(kind);
200
+ if (this.identifier.number)
201
+ parts.push(this.identifier.number);
202
+ const rendered = this.identifier.date?.render("urn");
203
+ if (rendered !== undefined && rendered !== "")
204
+ parts.push(rendered);
205
+ return parts.join(":");
206
+ }
207
+ // generate_base_urn: GUM guides carry the "gum.N" number form;
208
+ // guide/gum_guide type codes are implied and never appended.
209
+ if (kind === "gum-guide" && this.identifier.number !== undefined) {
210
+ const parts = ["urn", "jcgm", `gum.${this.identifier.number}`];
211
+ const rendered = this.identifier.date?.render("urn");
212
+ if (rendered !== undefined && rendered !== "")
213
+ parts.push(rendered);
214
+ if (this.identifier.languages.length > 0) {
215
+ parts.push(this.identifier.languages.map((l) => l.code).join(","));
216
+ }
217
+ return parts.join(":");
218
+ }
219
+ const parts = [...this.identifier.baseUrnParts()];
220
+ if (this.identifier.languages.length > 0) {
221
+ parts.push(this.identifier.languages.map((l) => l.code).join(","));
222
+ }
223
+ return parts.join(":");
224
+ }
225
+ }
226
+ for (const klass of Object.values(KIND_CLASSES)) {
227
+ klass.urnGenerator = JcgmUrnGenerator;
228
+ }
229
+ function isObj(v) {
230
+ return typeof v === "object" && v !== null && !Array.isArray(v);
231
+ }
232
+ function parseLanguages(value) {
233
+ const raw = String(value);
234
+ return raw.split("/").map((code) => {
235
+ const original = code.trim();
236
+ const mapped = Language.CHAR_MAP[original] ?? original.toLowerCase();
237
+ return new Language({ code: mapped, originalCode: original });
238
+ });
239
+ }
240
+ function buildDate(value) {
241
+ if (value === undefined || value === null)
242
+ return undefined;
243
+ const dateStr = String(value);
244
+ const parts = dateStr.split("-");
245
+ return new PubidDate({ year: parts[0], month: parts[1], day: parts[2] });
246
+ }
247
+ class JcgmBuilder extends BaseBuilder {
248
+ defaultIdentifierClass() {
249
+ return KIND_CLASSES["guide"];
250
+ }
251
+ selectClass(data) {
252
+ const hasBase = data["base"] !== undefined;
253
+ const typeWithStage = data["type_with_stage"] === undefined || data["type_with_stage"] === null
254
+ ? undefined
255
+ : String(data["type_with_stage"]);
256
+ if (hasBase) {
257
+ if (typeWithStage === undefined)
258
+ return KIND_CLASSES["amendment"];
259
+ return typeWithStage === "Amd" ? KIND_CLASSES["amendment"] : KIND_CLASSES["corrigendum"];
260
+ }
261
+ if (data["gum_number"] !== undefined)
262
+ return KIND_CLASSES["gum-guide"];
263
+ if (typeWithStage === "Meeting")
264
+ return KIND_CLASSES["meeting"];
265
+ return KIND_CLASSES["guide"];
266
+ }
267
+ build(data) {
268
+ const flat = Array.isArray(data) ? Object.assign({}, ...data) : data;
269
+ const klass = this.selectClass(flat);
270
+ const attrs = {};
271
+ if (flat["base"] !== undefined) {
272
+ attrs["base"] = this.build(flat["base"]);
273
+ }
274
+ if (flat["gum_number"] !== undefined)
275
+ attrs["number"] = String(flat["gum_number"]);
276
+ else if (flat["number"] !== undefined)
277
+ attrs["number"] = String(flat["number"]);
278
+ if (flat["date"] !== undefined) {
279
+ const date = buildDate(flat["date"]);
280
+ if (date)
281
+ attrs["date"] = date;
282
+ }
283
+ if (flat["languages"] !== undefined)
284
+ attrs["languages"] = parseLanguages(flat["languages"]);
285
+ return new klass(attrs);
286
+ }
287
+ }
288
+ export function jcgmGrammarImplementation() {
289
+ const builder = new JcgmBuilder();
290
+ return {
291
+ parse(input) {
292
+ const tree = parseGrammar(jcgmGrammar, input);
293
+ if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
294
+ throw new ParseFailed("JCGM: unexpected parse tree", 0);
295
+ }
296
+ return builder.build(tree);
297
+ },
298
+ };
299
+ }
300
+ export { isObj };
@@ -0,0 +1,4 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
3
+ export declare const jisGrammar: Grammar;
4
+ export declare function jisGrammarImplementation(): FlavorImplementation;
@@ -0,0 +1,267 @@
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 { BaseUrnGenerator } from "../../model/urn-generator.js";
6
+ /**
7
+ * Port of lib/pubid/jis/ on the unified model — 10,555 corpus rows.
8
+ * "JIS[ TR|TS] <series> <number>[-parts][:year[R]][(E|J)][(規格群)]
9
+ * [/AMD|EXPL|CORRIGENDUM …] [SYMBOL <value>]". Full-width Japanese
10
+ * separators parse and normalize; year is an INTEGER in the hash; the
11
+ * code ("B 0205-1") lives in the series/number/parts columns and is
12
+ * composed on demand. URN: urn:jis:<code>[:year][:lang]["all"]? with a
13
+ * supplement notation appended lowercased.
14
+ */
15
+ function buildRules() {
16
+ const rules = {};
17
+ const rule = (name, build) => {
18
+ rules[name] = build();
19
+ };
20
+ const jpDash = str("ー");
21
+ const jpSpace = str(" ");
22
+ const jpColon = str(":");
23
+ const jpLparen = str("(");
24
+ const jpRparen = str(")");
25
+ const space = str(" ").or(jpSpace);
26
+ const dash = str("-").or(jpDash);
27
+ const colon = str(":").or(jpColon);
28
+ const digits = match("[0-9]").repeat(1, Infinity);
29
+ rule("jis_prefix", () => str("JIS").then(space.or(str("/")).maybe()));
30
+ rule("type_prefix", () => (str("TR").or(str("TS"))).as("type").then(space.or(str("/"))));
31
+ rule("series", () => match("[A-Z]").as("series"));
32
+ rule("number", () => digits.as("number"));
33
+ rule("part", () => dash.then(digits.as("part")));
34
+ rule("parts", () => rules["part"].repeat(0, Infinity).as("parts"));
35
+ rule("reaffirmed", () => str("R").maybe().as("reaffirmed"));
36
+ rule("year", () => colon.then(digits.as("year"), rules["reaffirmed"]));
37
+ rule("language", () => jpLparen.or(str("(")).then(match("[EJ]").as("language"), jpRparen.or(str(")"))));
38
+ rule("all_parts", () => jpLparen.then(str("規格群"), jpRparen)
39
+ .or(str("(").then(str("規格群"), str(")")))
40
+ .as("all_parts"));
41
+ rule("amendment", () => str("/").then((str("AMENDMENT").or(str("AMD"))).as("amd_type"), space, digits.as("amd_number"), colon, digits.as("amd_year"), str("R").maybe().as("amd_reaffirmed")));
42
+ rule("explanation", () => str("/").then((str("EXPLANATION").or(str("EXPL"))).as("expl_type"), space.then(digits.as("expl_number")).maybe()));
43
+ rule("corrigendum", () => str("/").then((str("CORRIGENDUM").or(str("CORR"))).as("corr_type"), space, digits.as("corr_number"), colon, digits.as("corr_year"), str("R").maybe().as("corr_reaffirmed")));
44
+ rule("supplement", () => rules["amendment"].as("amendment")
45
+ .or(rules["explanation"].as("explanation"))
46
+ .or(rules["corrigendum"].as("corrigendum")));
47
+ rule("symbol_clause", () => space.then(str("SYMBOL").as("symbol_present"), space.then(match("[^\\n]").repeat(1, Infinity).as("symbol_value")).maybe()));
48
+ rule("identifier", () => rules["jis_prefix"]
49
+ .maybe()
50
+ .then(rules["type_prefix"].maybe())
51
+ .then(space.maybe(), rules["series"], space.maybe(), rules["number"])
52
+ .then(rules["parts"])
53
+ .then(rules["year"].maybe())
54
+ .then(rules["language"].maybe())
55
+ .then(rules["all_parts"].maybe())
56
+ .then(rules["supplement"].maybe())
57
+ .then(rules["symbol_clause"].maybe()));
58
+ rule("root", () => rules["identifier"]);
59
+ return rules;
60
+ }
61
+ export const jisGrammar = { rules: buildRules(), root: "root" };
62
+ const KIND_PREFIXES = {
63
+ "japanese-industrial-standard": undefined,
64
+ "technical-report": "TR",
65
+ "technical-specification": "TS",
66
+ };
67
+ class JisIdentifier extends BaseIdentifier {
68
+ /** The rendered document code, e.g. "B 0205-1". */
69
+ code() {
70
+ if (this.base !== undefined)
71
+ return this.base.code();
72
+ if (this.series === undefined || this.number === undefined)
73
+ return undefined;
74
+ let result = `${this.series} ${this.number}`;
75
+ if (this.parts !== undefined)
76
+ result += this.parts.map((p) => `-${p}`).join("");
77
+ return result;
78
+ }
79
+ yearWithReaffirmation() {
80
+ return `${this.year}${this.reaffirmed === true ? "R" : ""}`;
81
+ }
82
+ symbolSuffix() {
83
+ if (this.symbol === undefined)
84
+ return "";
85
+ return this.symbol === "" ? " SYMBOL" : ` SYMBOL ${this.symbol}`;
86
+ }
87
+ supplementNotation() {
88
+ return "";
89
+ }
90
+ }
91
+ const JIS_MAPPINGS = keyValue({ wire: "series", to: "series" }, { wire: "number", to: "number" }, { wire: "parts", to: "parts" }, { wire: "year", to: "year" }, { wire: "language", to: "language" }, { wire: "all_parts", to: "all_parts" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "symbol", to: "symbol" });
92
+ function jisClass(kind) {
93
+ const isSupplement = kind === "amendment" || kind === "corrigendum" || kind === "explanation";
94
+ class JisKindIdentifier extends JisIdentifier {
95
+ static polymorphicName = `pubid:jis:${kind}`;
96
+ static attributes = isSupplement
97
+ ? extendAttributes(BaseIdentifier, {
98
+ base: { type: JisIdentifier },
99
+ number: { type: "integer" },
100
+ year: { type: "integer" },
101
+ reaffirmed: { type: "boolean" },
102
+ })
103
+ : extendAttributes(BaseIdentifier, {
104
+ series: { type: "string" },
105
+ number: { type: "string" },
106
+ parts: { type: "string", collection: true },
107
+ year: { type: "integer" },
108
+ language: { type: "string" },
109
+ all_parts: { type: "boolean", default: false },
110
+ reaffirmed: { type: "boolean" },
111
+ symbol: { type: "string" },
112
+ });
113
+ static mappings = isSupplement
114
+ ? keyValue({ wire: "number", to: "number" }, { wire: "year", to: "year" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "base", to: "base" })
115
+ : JIS_MAPPINGS;
116
+ render() {
117
+ if (isSupplement) {
118
+ const result = `${this.base?.render() ?? ""}/${this.supplementNotation()}`;
119
+ return result + this.symbolSuffix();
120
+ }
121
+ const typePrefix = KIND_PREFIXES[kind];
122
+ let result = typePrefix === undefined ? "JIS" : `JIS ${typePrefix}`;
123
+ result += ` ${this.code()}`;
124
+ if (this.year !== undefined)
125
+ result += `:${this.yearWithReaffirmation()}`;
126
+ if (this.language !== undefined)
127
+ result += `(${this.language})`;
128
+ if (this.all_parts === true)
129
+ result += "(規格群)";
130
+ return result + this.symbolSuffix();
131
+ }
132
+ supplementNotation() {
133
+ if (kind === "amendment")
134
+ return `AMD ${this.number}:${this.yearWithReaffirmation()}`;
135
+ if (kind === "corrigendum")
136
+ return `CORRIGENDUM ${this.number}:${this.yearWithReaffirmation()}`;
137
+ if (kind === "explanation") {
138
+ return this.number === undefined ? "EXPL" : `EXPL ${this.number}`;
139
+ }
140
+ return "";
141
+ }
142
+ }
143
+ registerType(JisKindIdentifier);
144
+ return JisKindIdentifier;
145
+ }
146
+ const KIND_CLASSES = {
147
+ "japanese-industrial-standard": jisClass("japanese-industrial-standard"),
148
+ "technical-report": jisClass("technical-report"),
149
+ "technical-specification": jisClass("technical-specification"),
150
+ amendment: jisClass("amendment"),
151
+ corrigendum: jisClass("corrigendum"),
152
+ explanation: jisClass("explanation"),
153
+ };
154
+ class JisUrnGenerator extends BaseUrnGenerator {
155
+ generate() {
156
+ const id = this.identifier;
157
+ const parts = ["urn", "jis"];
158
+ const code = id.code();
159
+ if (code !== undefined)
160
+ parts.push(code);
161
+ if (id.year !== undefined)
162
+ parts.push(String(id.year));
163
+ if (id.language !== undefined)
164
+ parts.push(id.language.toLowerCase());
165
+ if (id.all_parts === true)
166
+ parts.push("all");
167
+ const notation = id.supplementNotation();
168
+ if (id.base !== undefined && notation !== "") {
169
+ parts.push(notation.toLowerCase());
170
+ }
171
+ return parts.join(":");
172
+ }
173
+ }
174
+ for (const klass of Object.values(KIND_CLASSES)) {
175
+ klass.urnGenerator = JisUrnGenerator;
176
+ }
177
+ function isObj(v) {
178
+ return typeof v === "object" && v !== null && !Array.isArray(v);
179
+ }
180
+ function extractParts(raw) {
181
+ if (Array.isArray(raw)) {
182
+ return raw.map((p) => (isObj(p) ? String(p["part"]) : String(p)));
183
+ }
184
+ if (isObj(raw) && raw["part"] !== undefined)
185
+ return [String(raw["part"])];
186
+ return [];
187
+ }
188
+ class JisBuilder {
189
+ build(data) {
190
+ const tree = (Array.isArray(data) ? Object.assign({}, ...data) : data);
191
+ const identifier = this.dispatch(tree);
192
+ // The SYMBOL clause attaches to the outermost identifier.
193
+ if (tree["symbol_present"] !== undefined) {
194
+ identifier["symbol"] =
195
+ tree["symbol_value"] === undefined || tree["symbol_value"] === null
196
+ ? ""
197
+ : String(tree["symbol_value"]);
198
+ }
199
+ return identifier;
200
+ }
201
+ dispatch(tree) {
202
+ if (tree["amendment"] !== undefined)
203
+ return this.buildSupplement(tree, "amendment", "amendment", "amd");
204
+ if (tree["corrigendum"] !== undefined)
205
+ return this.buildSupplement(tree, "corrigendum", "corrigendum", "corr");
206
+ if (tree["explanation"] !== undefined)
207
+ return this.buildExplanation(tree);
208
+ return this.buildSingle(tree);
209
+ }
210
+ baseData(tree, key) {
211
+ const out = { ...tree };
212
+ delete out[key];
213
+ return out;
214
+ }
215
+ buildSingle(tree) {
216
+ const type = tree["type"] === undefined || tree["type"] === null ? undefined : String(tree["type"]);
217
+ const kind = type === "TR" ? "technical-report" : type === "TS" ? "technical-specification" : "japanese-industrial-standard";
218
+ const attrs = {
219
+ series: String(tree["series"]),
220
+ number: String(tree["number"]),
221
+ parts: extractParts(tree["parts"]),
222
+ };
223
+ if (tree["year"] !== undefined && tree["year"] !== null)
224
+ attrs["year"] = Number(tree["year"]);
225
+ if (tree["language"] !== undefined && tree["language"] !== null)
226
+ attrs["language"] = String(tree["language"]);
227
+ if (tree["all_parts"] !== undefined)
228
+ attrs["all_parts"] = true;
229
+ if (tree["reaffirmed"] !== undefined && tree["reaffirmed"] !== null)
230
+ attrs["reaffirmed"] = true;
231
+ return new KIND_CLASSES[kind](attrs);
232
+ }
233
+ buildSupplement(tree, kind, key, prefix) {
234
+ const supp = isObj(tree[key]) ? tree[key] : {};
235
+ const base = this.buildSingle(this.baseData(tree, key));
236
+ const attrs = {
237
+ base,
238
+ number: Number(supp[`${prefix}_number`]),
239
+ year: Number(supp[`${prefix}_year`]),
240
+ };
241
+ if (supp[`${prefix}_reaffirmed`] !== undefined && supp[`${prefix}_reaffirmed`] !== null) {
242
+ attrs["reaffirmed"] = true;
243
+ }
244
+ return new KIND_CLASSES[kind](attrs);
245
+ }
246
+ buildExplanation(tree) {
247
+ const supp = isObj(tree["explanation"]) ? tree["explanation"] : {};
248
+ const base = this.buildSingle(this.baseData(tree, "explanation"));
249
+ const attrs = { base, year: base.year };
250
+ if (supp["expl_number"] !== undefined && supp["expl_number"] !== null) {
251
+ attrs["number"] = Number(supp["expl_number"]);
252
+ }
253
+ return new KIND_CLASSES["explanation"](attrs);
254
+ }
255
+ }
256
+ export function jisGrammarImplementation() {
257
+ const builder = new JisBuilder();
258
+ return {
259
+ parse(input) {
260
+ const tree = parseGrammar(jisGrammar, input);
261
+ if (typeof tree !== "object" || tree === null) {
262
+ throw new ParseFailed("JIS: unexpected parse tree", 0);
263
+ }
264
+ return builder.build(tree);
265
+ },
266
+ };
267
+ }
@@ -0,0 +1,2 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ export declare const nistGrammar: Grammar;