@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,1237 @@
1
+ import { BaseIdentifier, registerType } from "../../model/identifier.js";
2
+ import { extendAttributes, keyValue } from "../../model/attribute.js";
3
+ import { BaseUrnGenerator } from "../../model/urn-generator.js";
4
+ export const TYPED_STAGES = [
5
+ { abbr: ["Std"], stage_code: "published", type_code: "standard" },
6
+ { abbr: ["D1"], stage_code: "working_draft", type_code: "draft", ieee_draft_equivalent: "D1", iso_stage_equivalent: "WD", approval_status: "unapproved", project_status: true },
7
+ { abbr: ["D2", "D3"], stage_code: "committee_draft", type_code: "draft", ieee_draft_equivalent: "D2-D3", iso_stage_equivalent: "CD", approval_status: "unapproved", project_status: true },
8
+ { abbr: ["D4", "D5", "D6"], stage_code: "draft_standard", type_code: "draft", ieee_draft_equivalent: "D4-D6", iso_stage_equivalent: "DIS", approval_status: "unapproved", project_status: true },
9
+ { abbr: ["D7", "D8", "D9"], stage_code: "final_draft", type_code: "draft", ieee_draft_equivalent: "D7-D9", iso_stage_equivalent: "FDIS", approval_status: "approved", project_status: true },
10
+ { abbr: ["PWI"], stage_code: "preliminary", type_code: "draft", ieee_draft_equivalent: "P", iso_stage_equivalent: "PWI", approval_status: "unapproved", project_status: true },
11
+ { abbr: ["NP"], stage_code: "new_proposal", type_code: "draft", ieee_draft_equivalent: "P", iso_stage_equivalent: "NP", approval_status: "unapproved", project_status: true },
12
+ { abbr: ["WD"], stage_code: "working_draft", type_code: "draft", ieee_draft_equivalent: "D1", iso_stage_equivalent: "WD", approval_status: "unapproved", project_status: true },
13
+ { abbr: ["CD", "CD1", "CD2", "CD3", "CD4"], stage_code: "committee_draft", type_code: "draft", ieee_draft_equivalent: "D2-D3", iso_stage_equivalent: "CD", approval_status: "unapproved", project_status: true },
14
+ { abbr: ["CDV"], stage_code: "committee_draft_for_vote", type_code: "draft", ieee_draft_equivalent: "D2-D3", iso_stage_equivalent: "CDV", approval_status: "unapproved", project_status: true },
15
+ { abbr: ["DIS"], stage_code: "draft_international_standard", type_code: "draft", ieee_draft_equivalent: "D5", iso_stage_equivalent: "DIS", approval_status: "unapproved", project_status: true },
16
+ { abbr: ["FDIS"], stage_code: "final_draft", type_code: "draft", ieee_draft_equivalent: "D8", iso_stage_equivalent: "FDIS", approval_status: "approved", project_status: true },
17
+ { abbr: ["No", "No."], stage_code: "published", type_code: "standard" },
18
+ { abbr: ["P"], stage_code: "draft", type_code: "draft", ieee_draft_equivalent: "P", approval_status: "unapproved", project_status: true },
19
+ { abbr: ["Draft"], stage_code: "draft", type_code: "draft", approval_status: "unapproved", project_status: true },
20
+ ];
21
+ const entrySubHash = (ts) => {
22
+ const out = { abbr: ts.abbr, stage_code: ts.stage_code, type_code: ts.type_code };
23
+ if (ts.iso_stage_equivalent !== undefined)
24
+ out["iso_stage_equivalent"] = ts.iso_stage_equivalent;
25
+ if (ts.ieee_draft_equivalent !== undefined)
26
+ out["ieee_draft_equivalent"] = ts.ieee_draft_equivalent;
27
+ if (ts.approval_status !== undefined)
28
+ out["approval_status"] = ts.approval_status;
29
+ if (ts.project_status)
30
+ out["project_status"] = ts.project_status;
31
+ return out;
32
+ };
33
+ const SUB_HASH_FOR = new Map(TYPED_STAGES.map((ts) => [ts.abbr[0], entrySubHash(ts)]));
34
+ export function locateStage(abbr) {
35
+ const up = abbr.toUpperCase();
36
+ return TYPED_STAGES.find((ts) => ts.abbr.some((a) => a.toUpperCase() === up));
37
+ }
38
+ export class IeeeTypedStage {
39
+ record;
40
+ constructor(record) {
41
+ this.record = record;
42
+ }
43
+ get abbr() {
44
+ return this.record.abbr;
45
+ }
46
+ get projectStatus() {
47
+ return this.record.project_status === true;
48
+ }
49
+ get ieeeDraftEquivalent() {
50
+ return this.record.ieee_draft_equivalent;
51
+ }
52
+ get typeCode() {
53
+ return this.record.type_code;
54
+ }
55
+ toWire() {
56
+ return entrySubHash(this.record);
57
+ }
58
+ render() {
59
+ return this.record.abbr[0] ?? "";
60
+ }
61
+ }
62
+ export class IeeeCode {
63
+ prefix;
64
+ number;
65
+ parts;
66
+ originalSeparator;
67
+ constructor(attrs) {
68
+ this.prefix = attrs["prefix"];
69
+ this.number = String(attrs["number"] ?? "");
70
+ this.parts = Array.isArray(attrs["parts"]) ? attrs["parts"] : [];
71
+ this.originalSeparator = attrs["original_separator"];
72
+ }
73
+ static parse(codeStr) {
74
+ if (codeStr === "")
75
+ return undefined;
76
+ const prefixMatch = /^([A-Z])/.exec(codeStr);
77
+ const prefix = prefixMatch !== null ? prefixMatch[1] : undefined;
78
+ const remainder = prefix !== undefined ? codeStr.slice(prefix.length) : codeStr;
79
+ let separator;
80
+ if (remainder.includes("."))
81
+ separator = ".";
82
+ else if (remainder.includes("-"))
83
+ separator = "-";
84
+ const components = remainder.split(/[.-]/);
85
+ const number = components.shift() ?? "";
86
+ return new IeeeCode({
87
+ prefix,
88
+ number,
89
+ parts: components,
90
+ original_separator: separator,
91
+ });
92
+ }
93
+ render() {
94
+ let result = "";
95
+ if (this.prefix !== undefined)
96
+ result += this.prefix;
97
+ result += this.number;
98
+ if (this.parts.length > 0) {
99
+ let separator = this.originalSeparator;
100
+ if (separator === undefined) {
101
+ if (this.prefix === "P" || (this.prefix === undefined && this.parts[0] !== undefined && this.parts[0].length > 3)) {
102
+ separator = "-";
103
+ }
104
+ else if (this.prefix !== undefined && this.prefix !== "P") {
105
+ separator = ".";
106
+ }
107
+ else if (this.prefix === undefined && this.number.length >= 5) {
108
+ separator = "-";
109
+ }
110
+ else {
111
+ separator = ".";
112
+ }
113
+ }
114
+ for (const part of this.parts)
115
+ result += separator + part;
116
+ }
117
+ return result;
118
+ }
119
+ }
120
+ const DRAFT_MONTH_NAMES = {
121
+ January: "1", February: "2", March: "3", April: "4", May: "5", June: "6",
122
+ July: "7", August: "8", September: "9", October: "10", November: "11",
123
+ December: "12", Jan: "1", Feb: "2", Mar: "3", Apr: "4", Jun: "6",
124
+ Jul: "7", Aug: "8", Sep: "9", Sept: "9", Oct: "10", Nov: "11", Dec: "12",
125
+ };
126
+ export class IeeeDraft {
127
+ version;
128
+ revision;
129
+ isoStage;
130
+ isoIteration;
131
+ year;
132
+ month;
133
+ day;
134
+ originalMonth;
135
+ commaBeforeMonth;
136
+ /** Distinguishes an explicit `false` from "not recorded" (Ruby's nil). */
137
+ commaBeforeMonthSet;
138
+ constructor(attrs) {
139
+ this.commaBeforeMonthSet = "comma_before_month" in attrs;
140
+ this.version = String(attrs["version"] ?? "");
141
+ this.revision = attrs["revision"];
142
+ this.isoStage = attrs["iso_stage"];
143
+ this.isoIteration = attrs["iso_iteration"];
144
+ this.year = attrs["year"];
145
+ this.originalMonth = attrs["month"];
146
+ this.month = attrs["month"] !== undefined
147
+ ? DRAFT_MONTH_NAMES[String(attrs["month"])] ?? String(attrs["month"])
148
+ : undefined;
149
+ this.day = attrs["day"];
150
+ this.commaBeforeMonth = attrs["comma_before_month"] === true;
151
+ }
152
+ static parse(value) {
153
+ if (value === "")
154
+ return undefined;
155
+ let body = value;
156
+ if (body.startsWith("/D"))
157
+ body = body.slice(2);
158
+ else if (body.startsWith("/"))
159
+ body = body.slice(1);
160
+ else if (body.startsWith("D") && body.length > 1)
161
+ body = body.slice(1);
162
+ // The compound stage suffix (docs/IEEE-DRAFT-STAGES.md §1.3):
163
+ // "=DIS.3" is canonical - D (draft) = DIS (the stage), iteration 3.
164
+ // "=DDIS.3", "=DDIS3", "=DDIS-3" (the stage echoed with its own D)
165
+ // are accepted aliases. Captures [stage, iteration].
166
+ const compound = /=D?(PWI|NP|WD|CDV|FDIS|DIS|CD)(?:[.-]?(\d+))?$/;
167
+ let isoStage;
168
+ let isoIteration;
169
+ const cm = compound.exec(body);
170
+ if (cm !== null) {
171
+ isoStage = cm[1];
172
+ isoIteration = cm[2];
173
+ body = body.slice(0, cm.index);
174
+ }
175
+ const monthAlt = Object.keys(DRAFT_MONTH_NAMES)
176
+ .sort((a, b) => b.length - a.length)
177
+ .map((m) => `${m.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\.?`)
178
+ .join("|");
179
+ const suffix = new RegExp(`(?:(, | )(${monthAlt})(?: (\\d{1,2}))?(?:, | )| )((?:19|20)\\d{2}[a-z]{0,2})$`);
180
+ const m = suffix.exec(body);
181
+ if (m === null) {
182
+ return new IeeeDraft({ version: body, iso_stage: isoStage, iso_iteration: isoIteration });
183
+ }
184
+ return new IeeeDraft({
185
+ version: body.slice(0, m.index),
186
+ month: m[2],
187
+ day: m[3],
188
+ year: m[4],
189
+ comma_before_month: m[1] === ", ",
190
+ iso_stage: isoStage,
191
+ iso_iteration: isoIteration,
192
+ });
193
+ }
194
+ render() {
195
+ let result = `/D${this.version}`;
196
+ if (this.isoStage !== undefined)
197
+ result += `=${this.isoStage}`;
198
+ if (this.isoStage !== undefined && this.isoIteration !== undefined) {
199
+ result += `.${this.isoIteration}`;
200
+ }
201
+ if (this.revision !== undefined)
202
+ result += `.${this.revision}`;
203
+ if (this.year !== undefined) {
204
+ const displayMonth = this.originalMonth;
205
+ if (displayMonth !== undefined) {
206
+ const useCommaBefore = this.commaBeforeMonthSet
207
+ ? this.commaBeforeMonth
208
+ : displayMonth.length > 4 && displayMonth !== "Sept";
209
+ result += useCommaBefore ? `, ${displayMonth}` : ` ${displayMonth}`;
210
+ if (this.day !== undefined)
211
+ result += ` ${this.day}`;
212
+ result += displayMonth.length <= 4 || displayMonth === "Sept" ? ` ${this.year}` : `, ${this.year}`;
213
+ }
214
+ else {
215
+ result += ` ${this.year}`;
216
+ }
217
+ }
218
+ return result;
219
+ }
220
+ }
221
+ // --- Wire helpers ------------------------------------------------------------
222
+ const typedStageWire = {
223
+ wire: "typed_stage",
224
+ to: "typed_stage",
225
+ toWire: (model) => (model["typed_stage"] instanceof IeeeTypedStage
226
+ ? model["typed_stage"].toWire()
227
+ : undefined),
228
+ fromWire: (hash) => {
229
+ const value = hash["typed_stage"];
230
+ if (value === undefined || typeof value !== "object" || Array.isArray(value))
231
+ return undefined;
232
+ const rec = value;
233
+ const abbr = Array.isArray(rec["abbr"]) ? rec["abbr"].map(String) : [];
234
+ const match = TYPED_STAGES.find((ts) => ts.abbr.length === abbr.length && ts.abbr.every((a, i) => a === abbr[i]));
235
+ return match !== undefined ? new IeeeTypedStage(match) : undefined;
236
+ },
237
+ };
238
+ const draftWire = {
239
+ wire: "draft",
240
+ to: "draft",
241
+ toWire: (model) => {
242
+ const draft = model["draft"];
243
+ if (typeof draft !== "string" || draft === "")
244
+ return undefined;
245
+ return draft.startsWith("/") ? draft.slice(1) : draft;
246
+ },
247
+ fromWire: (hash) => {
248
+ const value = hash["draft"];
249
+ if (typeof value !== "string" || value === "")
250
+ return undefined;
251
+ return IeeeDraft.parse(value)?.render() ?? undefined;
252
+ },
253
+ };
254
+ const nestedIdWire = (attrName) => ({
255
+ wire: attrName,
256
+ to: attrName,
257
+ });
258
+ export const RELATIONSHIP_PREFIXES = {
259
+ revision_of: "Revision of",
260
+ amendment_to: "Amendment to",
261
+ corrigendum_to: "Corrigendum to",
262
+ incorporates: "incorporates",
263
+ adoption_of: "Adoption of",
264
+ supplement_to: "Supplement to",
265
+ draft_amendment_to: "Draft Amendment to",
266
+ draft_revision_of: "Draft Revision of",
267
+ reaffirmation_of: "Reaffirmation of",
268
+ redesignation_of: "Redesignation of",
269
+ supersedes: "Supersedes",
270
+ previously_designated_as: "Previously designated as",
271
+ includes: "Includes",
272
+ };
273
+ export class IeeeRelationship {
274
+ relationshipType;
275
+ relatedIds;
276
+ intermediateAmendments;
277
+ approvedAmendmentsFlag;
278
+ constructor(relationshipType, relatedIds, intermediateAmendments, approvedAmendmentsFlag = false) {
279
+ this.relationshipType = relationshipType;
280
+ this.relatedIds = relatedIds;
281
+ this.intermediateAmendments = intermediateAmendments;
282
+ this.approvedAmendmentsFlag = approvedAmendmentsFlag;
283
+ }
284
+ render() {
285
+ if (this.relatedIds.length === 0)
286
+ return "";
287
+ const prefix = RELATIONSHIP_PREFIXES[this.relationshipType] ?? this.relationshipType;
288
+ const ids = this.relatedIds.length === 1
289
+ ? this.relatedIds[0].toHuman()
290
+ : this.relatedIds.length === 2
291
+ ? `${this.relatedIds[0].toHuman()} and ${this.relatedIds[1].toHuman()}`
292
+ : `${this.relatedIds.slice(0, -1).map((i) => i.toHuman()).join(", ")}, and ${this.relatedIds[this.relatedIds.length - 1].toHuman()}`;
293
+ return `${prefix} ${ids}`;
294
+ }
295
+ }
296
+ // --- Compaction (hash transforms on toHash/fromHash) --------------------------
297
+ function walkHash(node, visit) {
298
+ if (Array.isArray(node)) {
299
+ for (const item of node)
300
+ walkHash(item, visit);
301
+ return;
302
+ }
303
+ if (node !== null && typeof node === "object") {
304
+ visit(node);
305
+ for (const value of Object.values(node)) {
306
+ walkHash(value, visit);
307
+ }
308
+ }
309
+ }
310
+ function collapseIeeeHash(node) {
311
+ walkHash(node, (h) => {
312
+ const ts = h["typed_stage"];
313
+ if (ts !== null && typeof ts === "object" && !Array.isArray(ts)) {
314
+ const sub = ts;
315
+ const abbr = Array.isArray(sub["abbr"]) ? sub["abbr"][0] : undefined;
316
+ if (typeof abbr === "string") {
317
+ const expected = SUB_HASH_FOR.get(abbr);
318
+ if (expected !== undefined &&
319
+ JSON.stringify(canonicalJsonKeyOrder(expected)) === JSON.stringify(canonicalJsonKeyOrder(sub))) {
320
+ delete h["typed_stage"];
321
+ h["stage"] = abbr;
322
+ }
323
+ }
324
+ }
325
+ const draft = h["draft"];
326
+ if (typeof draft === "string" && draft.startsWith("/")) {
327
+ h["draft"] = draft.slice(1);
328
+ }
329
+ });
330
+ }
331
+ function canonicalJsonKeyOrder(sub) {
332
+ return JSON.parse(JSON.stringify(sub, Object.keys(sub).sort()));
333
+ }
334
+ function expandIeeeHash(hash) {
335
+ const deep = (node) => {
336
+ if (Array.isArray(node))
337
+ return node.map(deep);
338
+ if (node !== null && typeof node === "object") {
339
+ const src = node;
340
+ const out = {};
341
+ for (const [k, v] of Object.entries(src))
342
+ out[k] = deep(v);
343
+ if (typeof out["stage"] === "string") {
344
+ const sub = SUB_HASH_FOR.get(out["stage"]);
345
+ if (sub !== undefined) {
346
+ delete out["stage"];
347
+ out["typed_stage"] = { ...sub };
348
+ }
349
+ }
350
+ return out;
351
+ }
352
+ return node;
353
+ };
354
+ return deep(hash);
355
+ }
356
+ // --- The identifier base -----------------------------------------------------
357
+ export class IeeeIdentifier extends BaseIdentifier {
358
+ static attributes = extendAttributes(BaseIdentifier, {
359
+ publisher: { type: "string", default: "IEEE" },
360
+ copublisher: { type: "string", collection: true, default: [] },
361
+ year: { type: "string" },
362
+ type: { type: "string", default: "Std" },
363
+ draft_status: { type: "string" },
364
+ draft: { type: "string" },
365
+ revision: { type: "string" },
366
+ edition: { type: "string" },
367
+ month: { type: "string" },
368
+ day: { type: "string" },
369
+ redline: { type: "boolean", default: false },
370
+ edition_month: { type: "string" },
371
+ space_before_draft: { type: "boolean", default: false },
372
+ typed_stage: { type: IeeeTypedStage },
373
+ parenthetical_content: { type: "string" },
374
+ nickname: { type: "string" },
375
+ adoption: { type: "string" },
376
+ amendment_to: { type: "string" },
377
+ note: { type: "string" },
378
+ iso_identifier: { type: "string" },
379
+ revision_of: { type: "string" },
380
+ ashrae_number: { type: "string" },
381
+ ashrae_year: { type: "string" },
382
+ crossref: { type: "string" },
383
+ reaffirmed: { type: "string" },
384
+ interpretation: { type: "boolean", default: false },
385
+ relationships: { type: "string", collection: true },
386
+ });
387
+ static mappings = keyValue({ wire: "publisher", to: "publisher" }, { wire: "copublisher", to: "copublisher" }, { wire: "year", to: "year" }, { wire: "type", to: "type" }, { wire: "draft_status", to: "draft_status" }, draftWire, { wire: "revision", to: "revision" }, { wire: "edition", to: "edition" }, { wire: "month", to: "month" }, { wire: "day", to: "day" }, { wire: "redline", to: "redline" }, { wire: "edition_month", to: "edition_month" }, { wire: "space_before_draft", to: "space_before_draft" }, typedStageWire, { wire: "parenthetical_content", to: "parenthetical_content" }, { wire: "nickname", to: "nickname" }, { wire: "adoption", to: "adoption" }, { wire: "amendment_to", to: "amendment_to" }, { wire: "note", to: "note" }, { wire: "iso_identifier", to: "iso_identifier" }, { wire: "revision_of", to: "revision_of" }, { wire: "ashrae_number", to: "ashrae_number" }, { wire: "ashrae_year", to: "ashrae_year" }, { wire: "crossref", to: "crossref" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "interpretation", to: "interpretation" }, {
388
+ wire: "relationships",
389
+ to: "relationships",
390
+ toWire: (model) => {
391
+ const rel = model["relationships"];
392
+ if (rel === undefined || rel.length === 0)
393
+ return undefined;
394
+ return rel.map((r) => ({ relationship_type: r.relationshipType }));
395
+ },
396
+ fromWire: (hash) => {
397
+ const value = hash["relationships"];
398
+ if (!Array.isArray(value))
399
+ return undefined;
400
+ return value.map((r) => new IeeeRelationship(String(r["relationship_type"] ?? ""), [], []));
401
+ },
402
+ });
403
+ draftObjCache;
404
+ draftObject() {
405
+ if (this.draftObjCache !== undefined)
406
+ return this.draftObjCache;
407
+ if (this.draft === undefined || this.draft === "")
408
+ return undefined;
409
+ this.draftObjCache = IeeeDraft.parse(this.draft);
410
+ return this.draftObjCache;
411
+ }
412
+ get codeObj() {
413
+ return undefined;
414
+ }
415
+ root() {
416
+ return this;
417
+ }
418
+ yearForUrn() {
419
+ return this.year;
420
+ }
421
+ toHash() {
422
+ const hash = super.toHash();
423
+ collapseIeeeHash(hash);
424
+ return hash;
425
+ }
426
+ static fromHash(hash) {
427
+ return super.fromHash(expandIeeeHash(hash));
428
+ }
429
+ }
430
+ // --- render_base (the shared renderer core) ----------------------------------
431
+ export function renderIeeeBase(id) {
432
+ const parts = [];
433
+ if (id.copublisher !== undefined && id.copublisher.length > 0) {
434
+ parts.push([id.publisher, ...id.copublisher].join("/"));
435
+ }
436
+ else {
437
+ parts.push(id.publisher);
438
+ }
439
+ if (id.draft_status !== undefined)
440
+ parts.push(id.draft_status);
441
+ const shouldRenderType = /^(IEEE|AIEE)/.test(id.publisher ?? "");
442
+ const stageObj = id.typed_stage;
443
+ if (shouldRenderType && !(stageObj?.projectStatus === true) &&
444
+ id.type !== undefined && id.type.trim() !== "" && id.type !== "P" &&
445
+ !/unapproved/i.test(id.draft_status ?? "")) {
446
+ let typeStr = id.type;
447
+ if (typeStr.startsWith("P"))
448
+ typeStr = typeStr.slice(1);
449
+ if (typeStr.trim() !== "")
450
+ parts.push(typeStr);
451
+ }
452
+ const codeObj = id.codeObj;
453
+ const draftObj = id.draftObject();
454
+ // An exactly-IEC/IEEE co-published reference drops its comma project
455
+ // dates (catalogue metadata, not identity); wider sets and
456
+ // space-separated dates print as spelled.
457
+ const iecIeeOnly = id.publisher === "IEC" && JSON.stringify(id.copublisher) === '["IEEE"]';
458
+ if (codeObj !== undefined) {
459
+ let result = codeObj.render();
460
+ // Prepend P if this is a project AND code doesn't already have P.
461
+ // A recorded project marker (the source spelled the P on a
462
+ // non-IEEE-led publisher) prints regardless of the publisher.
463
+ if ((stageObj?.projectStatus === true && shouldRenderType ||
464
+ id.constructor.polymorphicName ===
465
+ "pubid:ieee:project-draft-identifier" &&
466
+ id["project_marker"] === true) &&
467
+ !result.startsWith("P")) {
468
+ result = `P${result}`;
469
+ }
470
+ if (id.year !== undefined && draftObj === undefined && id.edition === undefined && id.month === undefined) {
471
+ result += `-${id.year}`;
472
+ }
473
+ if (id.revision !== undefined)
474
+ result += `Rev${id.revision}`;
475
+ if (draftObj !== undefined) {
476
+ let printed = draftObj.render();
477
+ if (iecIeeOnly) {
478
+ printed = printed.split(", ")[0];
479
+ }
480
+ else if (id.publisher === "IEEE" && (id.draft_status ?? "") === "") {
481
+ // The long comma form for dated project drafts; the
482
+ // unapproved-draft keeps its pinned single-comma form.
483
+ printed = printed.replace(/, ([A-Z][a-z]+) (\d{4})$/, ", $1, $2");
484
+ }
485
+ // A space-separated draft year with no print date trailing is the
486
+ // dash form ("…/D1-2006").
487
+ printed = printed.replace(/^(D\d+) (\d{4})$/, "$1-$2");
488
+ result += id.space_before_draft === true ? ` ${printed}` : printed;
489
+ }
490
+ if (id.interpretation === true)
491
+ result += "/INT";
492
+ if (id.ashrae_number !== undefined) {
493
+ result += `/ASHRAE Guideline ${id.ashrae_number}`;
494
+ if (id.ashrae_year !== undefined)
495
+ result += `-${id.ashrae_year}`;
496
+ }
497
+ if (id.crossref !== undefined)
498
+ result += id.crossref;
499
+ parts.push(result);
500
+ }
501
+ else if (shouldRenderType && stageObj?.projectStatus === true) {
502
+ parts.push("P");
503
+ }
504
+ if (id.edition !== undefined) {
505
+ let editionStr = `Edition ${id.edition}`;
506
+ if (id.year !== undefined) {
507
+ editionStr += ` ${id.year}`;
508
+ if (id.edition_month !== undefined)
509
+ editionStr += `-${id.edition_month}`;
510
+ }
511
+ parts.push(editionStr);
512
+ }
513
+ let result = parts.join(" ");
514
+ if (id.month !== undefined && !iecIeeOnly) {
515
+ result += `, ${id.month}`;
516
+ if (id.day !== undefined)
517
+ result += ` ${id.day}`;
518
+ if (id.year !== undefined && id.edition === undefined)
519
+ result += ` ${id.year}`;
520
+ }
521
+ const parentheticals = [];
522
+ if (id.reaffirmed !== undefined && id.reaffirmed.trim() !== "") {
523
+ parentheticals.push(`(R${id.reaffirmed})`);
524
+ }
525
+ if (id.parenthetical_content !== undefined) {
526
+ parentheticals.push(`(${id.parenthetical_content})`);
527
+ }
528
+ if (parentheticals.length > 0)
529
+ result += ` ${parentheticals.join(" ")}`;
530
+ if (id.nickname !== undefined && id.nickname.trim() !== "")
531
+ result += ` [${id.nickname}]`;
532
+ if (id.redline === true)
533
+ result += " - Redline";
534
+ return result;
535
+ }
536
+ // --- URN generator -----------------------------------------------------------
537
+ let SPECIAL_URN_OF = () => undefined;
538
+ let CODE_THROUGH_BASE = () => false;
539
+ class IeeeUrnGenerator extends BaseUrnGenerator {
540
+ generate() {
541
+ const id = this.identifier;
542
+ const parts = ["urn", "ieee"];
543
+ const special = this.specialType();
544
+ const push = (value) => {
545
+ if (value !== undefined)
546
+ parts.push(value);
547
+ };
548
+ push(this.publisherComponent());
549
+ push(special);
550
+ push(this.typeComponent());
551
+ push(this.codeComponent());
552
+ push(this.yearComponent());
553
+ push(this.draftComponent());
554
+ if (id.edition !== undefined)
555
+ push(`ed.${id.edition}`);
556
+ push(this.monthDayComponent());
557
+ if (id.draft_status !== undefined)
558
+ push(id.draft_status.toLowerCase().replaceAll(" ", "."));
559
+ if (special === undefined && id.redline === true)
560
+ push("redline");
561
+ if (special === undefined && id.interpretation === true)
562
+ push("int");
563
+ if (id.ashrae_number !== undefined) {
564
+ let ashrae = `ashrae.${id.ashrae_number}`;
565
+ if (id.ashrae_year !== undefined)
566
+ ashrae += `-${id.ashrae_year}`;
567
+ push(ashrae);
568
+ }
569
+ if (id.crossref !== undefined)
570
+ push(`xref.${id.crossref}`);
571
+ if (id.relationships !== undefined && id.relationships.length > 0) {
572
+ push(`rel.${id.relationships.map((r) => r.render()).join("/")}`);
573
+ }
574
+ if (id.revision_of !== undefined)
575
+ push(`revof.${id.revision_of}`);
576
+ if (id.amendment_to !== undefined)
577
+ push(`amdto.${id.amendment_to}`);
578
+ if (id.adoption !== undefined)
579
+ push(`adopt.${id.adoption}`);
580
+ if (id.reaffirmed !== undefined)
581
+ push(`reaff.${id.reaffirmed}`);
582
+ if (id.note !== undefined)
583
+ push(`note.${id.note}`);
584
+ if (id.nickname !== undefined)
585
+ push(`nick.${id.nickname}`);
586
+ return parts.join(":");
587
+ }
588
+ specialType() {
589
+ return SPECIAL_URN_OF(this.identifier);
590
+ }
591
+ publisherComponent() {
592
+ // The IEC/IEEE co-published pair is definitional to the class and
593
+ // was previously lost ("urn:ieee:ieee" — no number, no draft).
594
+ if (this.identifier.constructor.polymorphicName ===
595
+ "pubid:ieee:iec-ieee-copublished") {
596
+ return "iec-ieee";
597
+ }
598
+ // Supplements delegate #publisher/#copublisher to their base (Ruby
599
+ // SupplementIdentifier); DualPublished derives publisher from BOTH
600
+ // members; MultiNumbered derives it from its primary.
601
+ const self = this.identifier;
602
+ const first = self["first_identifier"];
603
+ const second = self["second_identifier"];
604
+ const single = (self["ieee_identifier"] ?? self["primary_identifier"]);
605
+ const derived = first !== undefined && second !== undefined
606
+ ? [first.publisher, second.publisher]
607
+ : undefined;
608
+ // The Ruby reference reads the publisher through the wrapper (an
609
+ // adopted IRE id namespaces "ire") but the copublisher list RAW off
610
+ // this identifier: an amendment over a joint base carries publisher
611
+ // "ISO" and no copublishers of its own, so its URN namespace is
612
+ // "iso", not the base's joint slug.
613
+ const wrapped = (self["base"] ?? single);
614
+ const pubSource = derived !== undefined || wrapped === undefined
615
+ ? this.identifier
616
+ : wrapped;
617
+ const names = derived ?? (Array.isArray(pubSource.publisher) ? pubSource.publisher : [pubSource.publisher]);
618
+ const cleaned = names.map((p) => String(p).toLowerCase()).filter((p) => p !== "");
619
+ let pub = cleaned.length === 0 ? "ieee" : cleaned.join("-");
620
+ const rawCopub = this.identifier.copublisher;
621
+ if (rawCopub !== undefined && rawCopub.length > 0) {
622
+ pub = [pub, ...rawCopub.map((c) => String(c).toLowerCase())].join("-");
623
+ }
624
+ return pub;
625
+ }
626
+ typeComponent() {
627
+ // A joint stage draft carries the stage in its draft clause and the
628
+ // project P inside the code — a separate type segment would
629
+ // duplicate both.
630
+ const jointDraft = this.identifier["ieee_draft"];
631
+ if (jointDraft !== undefined && jointDraft.startsWith("D="))
632
+ return undefined;
633
+ const type = this.identifier.type;
634
+ if (type === undefined || type.trim() === "" || type === "Std")
635
+ return undefined;
636
+ return type.toLowerCase().replaceAll(" ", ".");
637
+ }
638
+ codeComponent() {
639
+ const id = this.identifier;
640
+ // The co-published code is number+parts+separators (no year — its
641
+ // own segment), e.g. "61886-1".
642
+ if (id.constructor.polymorphicName ===
643
+ "pubid:ieee:iec-ieee-copublished") {
644
+ const self = id;
645
+ const number = self["number"];
646
+ if (number === undefined || number === "")
647
+ return undefined;
648
+ const parts = self["parts"] ?? [];
649
+ const separators = self["separators"] ?? [];
650
+ let code = number;
651
+ separators.forEach((sep, i) => {
652
+ code += `${sep}${parts[i] ?? ""}`;
653
+ });
654
+ return code;
655
+ }
656
+ // Wrappers delegate code_obj to the identifier they wrap (Ruby
657
+ // AdoptedStandard/CsaDualPublished/MultiNumberedIdentifier).
658
+ const self = this.identifier;
659
+ // NB: NOT base — SupplementIdentifier delegates #code but leaves
660
+ // code_obj nil on the wrapper (identity-free corrigendum URNs) —
661
+ // except InterpretationIdentifier, whose override reaches the base.
662
+ const fallbacks = CODE_THROUGH_BASE(this.identifier)
663
+ ? ["ieee_identifier", "primary_identifier", "first_identifier", "base"]
664
+ : ["ieee_identifier", "primary_identifier", "first_identifier"];
665
+ const wrapped = fallbacks.map((k) => self[k]).find((v) => v instanceof IeeeIdentifier);
666
+ return (wrapped ?? this.identifier).codeObj?.render();
667
+ }
668
+ yearComponent() {
669
+ const id = this.identifier;
670
+ if (id.year !== undefined)
671
+ return id.year;
672
+ const root = id.root();
673
+ return root === id ? undefined : root.yearForUrn();
674
+ }
675
+ draftComponent() {
676
+ // The joint stage draft's stage rides in its ieee_draft clause
677
+ // ("D=CDV[:2020]"), emitted directly as the draft segment.
678
+ const jointDraft = this.identifier["ieee_draft"];
679
+ if (jointDraft !== undefined && jointDraft.startsWith("D="))
680
+ return `draft.${jointDraft}`;
681
+ const draftInfo = this.identifier["draft_info"];
682
+ if (draftInfo !== undefined &&
683
+ this.identifier.constructor.polymorphicName ===
684
+ "pubid:ieee:iec-ieee-copublished") {
685
+ return draftInfo === "" ? undefined : `draft.${draftInfo}`;
686
+ }
687
+ const draftObj = this.identifier.draftObject();
688
+ return draftObj === undefined ? undefined : `draft.${draftObj.render()}`;
689
+ }
690
+ monthDayComponent() {
691
+ const parts = [];
692
+ const id = this.identifier;
693
+ if (id.month !== undefined)
694
+ parts.push(id.month);
695
+ if (id.day !== undefined)
696
+ parts.push(id.day);
697
+ return parts.length === 0 ? undefined : parts.join("-");
698
+ }
699
+ }
700
+ const CODE_COLUMN_DEFS = {
701
+ number: { type: "string" },
702
+ prefix: { type: "string" },
703
+ parts: { type: "string", collection: true, default: [] },
704
+ separator: { type: "string" },
705
+ };
706
+ const CODE_COLUMN_MAPPINGS = keyValue({ wire: "number", to: "number" }, { wire: "prefix", to: "prefix" }, { wire: "parts", to: "parts" }, { wire: "separator", to: "separator" });
707
+ function ieeeClass(spec, opts = {}) {
708
+ const parentAttrs = () => opts.codeColumns === true
709
+ ? extendAttributes(IeeeIdentifier, CODE_COLUMN_DEFS)
710
+ : IeeeIdentifier.attributes;
711
+ const parentMappings = () => opts.codeColumns === true
712
+ ? [...IeeeIdentifier.mappings, ...CODE_COLUMN_MAPPINGS]
713
+ : [...IeeeIdentifier.mappings];
714
+ class IeeeConcrete extends IeeeIdentifier {
715
+ static polymorphicName = `pubid:ieee:${spec.kind}`;
716
+ static urnGenerator = IeeeUrnGenerator;
717
+ static get attributes() {
718
+ return opts.extraDefs === undefined
719
+ ? parentAttrs()
720
+ : extendAttributes({ attributes: parentAttrs() }, opts.extraDefs);
721
+ }
722
+ static get mappings() {
723
+ const base = opts.extraMappings === undefined
724
+ ? parentMappings()
725
+ : [...parentMappings(), ...opts.extraMappings];
726
+ return opts.wireDelete === undefined
727
+ ? base
728
+ : base.filter((m) => !opts.wireDelete.keys.includes(m.wire));
729
+ }
730
+ // The UNFILTERED list: nested serialization keeps the derived keys
731
+ // the top-level wire deletes (mirrors lutaml's nested transform,
732
+ // which serializes through the reader methods).
733
+ static get mappingsNested() {
734
+ return opts.extraMappings === undefined
735
+ ? parentMappings()
736
+ : [...parentMappings(), ...opts.extraMappings];
737
+ }
738
+ constructor(attrs = {}) {
739
+ super(attrs);
740
+ // Ruby lutaml materializes attribute defaults on every instance; the
741
+ // base constructor only assigns present keys, so fill scalar defaults
742
+ // the renderers read (publisher/type). toHash still drops them.
743
+ const self = this;
744
+ for (const [name, spec] of Object.entries(this.classAttributes())) {
745
+ if (self[name] === undefined && spec.default !== undefined && typeof spec.default !== "function") {
746
+ self[name] = spec.default;
747
+ }
748
+ }
749
+ }
750
+ render() {
751
+ return this.renderBody();
752
+ }
753
+ toHuman() {
754
+ return this.render();
755
+ }
756
+ renderBody() {
757
+ return (opts.render ?? renderIeeeBase)(this);
758
+ }
759
+ get codeObj() {
760
+ // Only CodeNumber leaves carry code columns; on a supplement the
761
+ // `number` attribute is the ORDINAL (Ruby SupplementIdentifier#code
762
+ // delegates to base, code_obj stays nil).
763
+ if (opts.codeColumns !== true)
764
+ return undefined;
765
+ const self = this;
766
+ const number = self["number"];
767
+ if (typeof number !== "string" || number === "")
768
+ return undefined;
769
+ return new IeeeCode({
770
+ prefix: self["prefix"],
771
+ number,
772
+ parts: self["parts"],
773
+ original_separator: self["separator"],
774
+ });
775
+ }
776
+ root() {
777
+ return opts.rootOf !== undefined
778
+ ? opts.rootOf(this)
779
+ : this;
780
+ }
781
+ yearForUrn() {
782
+ return opts.yearForUrnOf !== undefined
783
+ ? opts.yearForUrnOf(this)
784
+ : this.year;
785
+ }
786
+ }
787
+ registerType(IeeeConcrete);
788
+ if (opts.specialUrn !== undefined) {
789
+ const special = opts.specialUrn;
790
+ const prev = SPECIAL_URN_OF;
791
+ SPECIAL_URN_OF = (id) => {
792
+ if (id instanceof IeeeConcrete)
793
+ return special;
794
+ return prev(id);
795
+ };
796
+ }
797
+ if (opts.codeThroughBase === true) {
798
+ const prevCode = CODE_THROUGH_BASE;
799
+ CODE_THROUGH_BASE = (id) => (id instanceof IeeeConcrete ? true : prevCode(id));
800
+ }
801
+ return IeeeConcrete;
802
+ }
803
+ const childOf = (attrName) => (id) => id[attrName]?.root() ?? id;
804
+ const childYearOf = (attrName) => (id) => id[attrName]?.year;
805
+ // --- Supplements and wrappers -------------------------------------------------
806
+ export const SupplementBaseDefs = {
807
+ base: { type: IeeeIdentifier },
808
+ };
809
+ export const StandardClass = ieeeClass({ kind: "standard" }, { codeColumns: true });
810
+ export const ProjectDraftIdentifierClass = ieeeClass({ kind: "project-draft-identifier" }, {
811
+ codeColumns: true,
812
+ extraDefs: {
813
+ project_marker: { type: "boolean", default: false },
814
+ },
815
+ extraMappings: keyValue({ wire: "project_marker", to: "project_marker" }),
816
+ });
817
+ export const SiStandardClass = ieeeClass({ kind: "si-standard" }, {
818
+ codeColumns: true,
819
+ specialUrn: "si",
820
+ render: (id) => {
821
+ const parts = ["IEEE/ASTM"];
822
+ const isPsi = (id.typed_stage?.abbr ?? []).includes("PSI");
823
+ parts.push(isPsi ? "PSI" : "SI");
824
+ const codeObj = id.codeObj;
825
+ let codePart = codeObj?.render() ?? "";
826
+ const draftObj = id.draftObject();
827
+ if (draftObj !== undefined)
828
+ codePart += `/D${draftObj.version}`;
829
+ if (codeObj !== undefined)
830
+ parts.push(codePart);
831
+ let result = "";
832
+ for (const part of parts) {
833
+ if (result === "" || part.startsWith("-") || part.startsWith(",")) {
834
+ result += part;
835
+ }
836
+ else {
837
+ result += ` ${part}`;
838
+ }
839
+ }
840
+ if (id.month !== undefined && id.year !== undefined)
841
+ result += `, ${id.month} ${id.year}`;
842
+ else if (id.year !== undefined)
843
+ result += `-${id.year}`;
844
+ return result;
845
+ },
846
+ });
847
+ export const CorrigendumClass = ieeeClass({ kind: "corrigendum" }, {
848
+ extraDefs: SupplementBaseDefs,
849
+ extraMappings: keyValue(nestedIdWire("base"), { wire: "number", to: "number" }),
850
+ wireDelete: { keys: ["publisher", "copublisher"] },
851
+ render: (id) => {
852
+ const base = id["base"];
853
+ if (base === undefined)
854
+ return renderIeeeBase(id);
855
+ let result = base.toHuman();
856
+ result += "/Cor";
857
+ if (id.number !== undefined)
858
+ result += ". ";
859
+ if (id.number !== undefined)
860
+ result += id.number;
861
+ if (id.year !== undefined)
862
+ result += `-${id.year}`;
863
+ return result;
864
+ },
865
+ rootOf: childOf("base"),
866
+ });
867
+ export const AmendmentClass = ieeeClass({ kind: "amendment" }, {
868
+ extraDefs: SupplementBaseDefs,
869
+ extraMappings: keyValue(nestedIdWire("base"), { wire: "number", to: "number" }),
870
+ wireDelete: { keys: ["publisher", "copublisher"] },
871
+ render: (id) => {
872
+ const base = id["base"];
873
+ if (base === undefined)
874
+ return renderIeeeBase(id);
875
+ let result = base.toHuman();
876
+ result += "/Amd";
877
+ if (id.number !== undefined)
878
+ result += ` ${id.number}`;
879
+ if (id.year !== undefined)
880
+ result += `-${id.year}`;
881
+ return result;
882
+ },
883
+ rootOf: childOf("base"),
884
+ });
885
+ export const InterpretationClass = ieeeClass({ kind: "interpretation-identifier" }, {
886
+ specialUrn: "interpretation",
887
+ codeThroughBase: true,
888
+ extraDefs: SupplementBaseDefs,
889
+ extraMappings: keyValue(nestedIdWire("base")),
890
+ wireDelete: { keys: ["publisher", "copublisher"] },
891
+ render: (id) => {
892
+ const base = id["base"];
893
+ if (base === undefined)
894
+ return renderIeeeBase(id);
895
+ let result = base.toHuman();
896
+ result += "/INT";
897
+ if (id.year !== undefined)
898
+ result += `-${id.year}`;
899
+ return result;
900
+ },
901
+ rootOf: childOf("base"),
902
+ });
903
+ export const ConformanceClass = ieeeClass({ kind: "conformance-identifier" }, {
904
+ specialUrn: "conformance",
905
+ extraDefs: SupplementBaseDefs,
906
+ extraMappings: keyValue(nestedIdWire("base"), { wire: "number", to: "number" }),
907
+ wireDelete: { keys: ["publisher", "copublisher"] },
908
+ render: (id) => {
909
+ const base = id["base"];
910
+ if (base === undefined)
911
+ return renderIeeeBase(id);
912
+ let result = base.toHuman();
913
+ if (id.number !== undefined)
914
+ result += `/Conformance${id.number}`;
915
+ if (id.year !== undefined)
916
+ result += `-${id.year}`;
917
+ return result;
918
+ },
919
+ rootOf: childOf("base"),
920
+ });
921
+ const DualDefs = {
922
+ first_identifier: { type: IeeeIdentifier },
923
+ second_identifier: { type: IeeeIdentifier },
924
+ };
925
+ export const DualPublishedClass = ieeeClass({ kind: "dual-published" }, {
926
+ extraDefs: DualDefs,
927
+ extraMappings: keyValue(nestedIdWire("first_identifier"), nestedIdWire("second_identifier")),
928
+ wireDelete: { keys: ["publisher"] },
929
+ render: (id) => `${id["first_identifier"].toHuman()} and ${id["second_identifier"].toHuman()}`,
930
+ rootOf: childOf("first_identifier"),
931
+ yearForUrnOf: childYearOf("first_identifier"),
932
+ });
933
+ export const DualIdentifierClass = ieeeClass({ kind: "dual-identifier" }, {
934
+ extraDefs: DualDefs,
935
+ extraMappings: keyValue(nestedIdWire("first_identifier"), nestedIdWire("second_identifier")),
936
+ render: (id) => `${id["first_identifier"].toHuman()} and ${id["second_identifier"].toHuman()}`,
937
+ });
938
+ export const ParentheticalClass = ieeeClass({ kind: "parenthetical-identifier" }, {
939
+ extraDefs: {
940
+ base: { type: IeeeIdentifier },
941
+ parenthetical_identifier: { type: IeeeIdentifier },
942
+ },
943
+ extraMappings: keyValue(nestedIdWire("base"), nestedIdWire("parenthetical_identifier")),
944
+ render: (id) => {
945
+ let result = id["base"].toHuman();
946
+ if (id["parenthetical_identifier"] !== undefined) {
947
+ result += ` (${id["parenthetical_identifier"].toHuman()})`;
948
+ }
949
+ return result;
950
+ },
951
+ rootOf: childOf("base"),
952
+ });
953
+ export const AdoptedStandardClass = ieeeClass({ kind: "adopted-standard" }, {
954
+ extraDefs: {
955
+ ieee_identifier: { type: IeeeIdentifier },
956
+ adopted_identifiers: { type: IeeeIdentifier, collection: true },
957
+ },
958
+ extraMappings: keyValue(nestedIdWire("ieee_identifier"), nestedIdWire("adopted_identifiers")),
959
+ wireDelete: { keys: ["publisher"] },
960
+ render: (id) => {
961
+ const ieee = id["ieee_identifier"];
962
+ let result = ieee.toHuman();
963
+ const adopted = id["adopted_identifiers"];
964
+ if (adopted !== undefined && adopted.length > 0) {
965
+ result += ` (${adopted.map((a) => a.toHuman()).join(" and ")})`;
966
+ }
967
+ return result;
968
+ },
969
+ rootOf: childOf("ieee_identifier"),
970
+ yearForUrnOf: childYearOf("ieee_identifier"),
971
+ });
972
+ export const CsaDualPublishedClass = ieeeClass({ kind: "csa-dual-published" }, {
973
+ extraDefs: {
974
+ ieee_identifier: { type: IeeeIdentifier },
975
+ csa_string: { type: "string" },
976
+ },
977
+ // The wrapper serializes its DELEGATED year/typed_stage (Ruby lutaml
978
+ // reads through the reader methods) — the builder copies them onto the
979
+ // wrapper instance. csa_identifier is runtime-only (never serialized).
980
+ extraMappings: keyValue(nestedIdWire("ieee_identifier")),
981
+ render: (id) => {
982
+ const ieee = id["ieee_identifier"];
983
+ let csaStr = String(id["csa_string"] ?? "");
984
+ if (!csaStr.startsWith("CSA") && !csaStr.startsWith("CAN/"))
985
+ csaStr = `CSA ${csaStr}`;
986
+ return `${ieee.toHuman()}/${csaStr}`;
987
+ },
988
+ rootOf: childOf("ieee_identifier"),
989
+ yearForUrnOf: childYearOf("ieee_identifier"),
990
+ });
991
+ export const MultiNumberedClass = ieeeClass({ kind: "multi-numbered-identifier" }, {
992
+ extraDefs: {
993
+ primary_identifier: { type: IeeeIdentifier },
994
+ secondary_identifier: { type: IeeeIdentifier },
995
+ },
996
+ extraMappings: keyValue(nestedIdWire("primary_identifier"), nestedIdWire("secondary_identifier")),
997
+ wireDelete: { keys: ["publisher", "year"] },
998
+ render: (id) => {
999
+ const primary = id["primary_identifier"];
1000
+ const secondary = id["secondary_identifier"];
1001
+ if (secondary === undefined)
1002
+ return primary.toHuman();
1003
+ const secondaryCode = secondary.codeObj?.render() ?? "";
1004
+ if (secondaryCode.startsWith("C") && /^C\d+\./.test(secondaryCode)) {
1005
+ return `${primary.toHuman()}/${secondaryCode}`;
1006
+ }
1007
+ return `${primary.toHuman()} and ${secondary.toHuman()}`;
1008
+ },
1009
+ rootOf: childOf("primary_identifier"),
1010
+ });
1011
+ export const JointDevelopmentClass = ieeeClass({ kind: "joint-development" }, {
1012
+ codeColumns: true,
1013
+ extraDefs: {
1014
+ publishers: { type: "string", collection: true },
1015
+ lead_party: { type: "string" },
1016
+ iso_stage: { type: "string" },
1017
+ ieee_draft: { type: "string" },
1018
+ parenthetical_content: { type: "string" },
1019
+ },
1020
+ extraMappings: keyValue({ wire: "publishers", to: "publishers" }, { wire: "lead_party", to: "lead_party" }, { wire: "iso_stage", to: "iso_stage" }, { wire: "ieee_draft", to: "ieee_draft" }, { wire: "parenthetical_content", to: "parenthetical_content" }),
1021
+ wireDelete: { keys: ["publisher", "copublisher"] },
1022
+ render: (id) => {
1023
+ const publishers = id["publishers"];
1024
+ const leadParty = id["lead_party"];
1025
+ const isoStage = id["iso_stage"];
1026
+ const ieeeDraft = id["ieee_draft"];
1027
+ const codeObj = id.codeObj;
1028
+ // ISO-led renders the ISO format ALWAYS (the stage-less published
1029
+ // form "ISO/IEC/IEEE 12207.2:2020" prints colon-year, no stage).
1030
+ // IEEE semantics: P = project (a draft); no P = a standard. The
1031
+ // P-state is identity-bearing and prints as spelled - it is never
1032
+ // added or stripped here.
1033
+ if (leadParty === "ISO") {
1034
+ const parts = [];
1035
+ if (publishers !== undefined && publishers.length > 0)
1036
+ parts.push(publishers.join("/"));
1037
+ if (id.typed_stage !== undefined) {
1038
+ parts.push(id.typed_stage.record.iso_stage_equivalent ?? id.typed_stage.render());
1039
+ }
1040
+ else if (isoStage !== undefined) {
1041
+ parts.push(isoStage);
1042
+ }
1043
+ const codeStr = codeObj?.render() ?? "";
1044
+ if (codeStr !== "")
1045
+ parts.push(codeStr);
1046
+ let result = parts.join(" ");
1047
+ if (id.year !== undefined)
1048
+ result += `:${id.year}`;
1049
+ // The joint stage-draft clause ("D=WD.5") rides after the year in
1050
+ // the ISO-led print; only the bare language/edition marker ("(E)")
1051
+ // prints - a relationship narrative is metadata, not identity.
1052
+ const jointDraft = id["ieee_draft"];
1053
+ if (jointDraft !== undefined && jointDraft.startsWith("D="))
1054
+ result += `/${jointDraft}`;
1055
+ const marker = id["parenthetical_content"];
1056
+ if (marker !== undefined && /^[A-Z](?:\s*[/&]\s*[A-Z])*$/.test(marker)) {
1057
+ result += ` (${marker})`;
1058
+ }
1059
+ return result;
1060
+ }
1061
+ // IEEE format
1062
+ const parts = [];
1063
+ if (publishers !== undefined && publishers.length > 0)
1064
+ parts.push(publishers.join("/"));
1065
+ // The P-state prints as spelled (P = project draft; no P =
1066
+ // standard). Never added or stripped.
1067
+ let codeStr = codeObj?.render() ?? "";
1068
+ if (ieeeDraft !== undefined)
1069
+ codeStr += `/${ieeeDraft}`;
1070
+ else if (id.typed_stage?.ieeeDraftEquivalent !== undefined) {
1071
+ codeStr += `/${id.typed_stage.ieeeDraftEquivalent}`;
1072
+ }
1073
+ if (codeStr !== "")
1074
+ parts.push(codeStr);
1075
+ let result = parts.join(" ");
1076
+ if (id.year !== undefined)
1077
+ result += `-${id.year}`;
1078
+ return result;
1079
+ },
1080
+ });
1081
+ export const IecIeeeCopublishedClass = ieeeClass({ kind: "iec-ieee-copublished" }, {
1082
+ extraDefs: {
1083
+ number: { type: "string" },
1084
+ parts: { type: "string", collection: true, default: [] },
1085
+ separators: { type: "string", collection: true, default: [] },
1086
+ year_sep: { type: "string", default: "-" },
1087
+ draft_info: { type: "string" },
1088
+ iec_year: { type: "string" },
1089
+ date_info: { type: "string" },
1090
+ },
1091
+ extraMappings: keyValue({ wire: "number", to: "number" }, { wire: "parts", to: "parts" }, { wire: "separators", to: "separators" }, { wire: "year_sep", to: "year_sep" }, { wire: "draft_info", to: "draft_info" }, { wire: "iec_year", to: "iec_year" }, { wire: "date_info", to: "date_info" }),
1092
+ render: (id) => {
1093
+ let result = "IEC/IEEE";
1094
+ const number = id["number"];
1095
+ if (number !== undefined && number !== "") {
1096
+ const parts = id["parts"] ?? [];
1097
+ const separators = id["separators"] ?? [];
1098
+ let code = number;
1099
+ separators.forEach((sep, i) => {
1100
+ code += `${sep}${parts[i] ?? ""}`;
1101
+ });
1102
+ if (id.year !== undefined)
1103
+ code += `${id["year_sep"] ?? "-"}${id.year}`;
1104
+ result += ` ${code}`;
1105
+ }
1106
+ const draftInfo = id["draft_info"];
1107
+ if (draftInfo !== undefined)
1108
+ result += draftInfo;
1109
+ const iecYear = id["iec_year"];
1110
+ if (iecYear !== undefined)
1111
+ result += ` IEC:${iecYear}`;
1112
+ const dateInfo = id["date_info"];
1113
+ if (dateInfo !== undefined)
1114
+ result += ` ${dateInfo}`;
1115
+ return result;
1116
+ },
1117
+ });
1118
+ // --- AIEE / IRE / NESC -------------------------------------------------------
1119
+ export const AieeClass = ieeeClass({ kind: "aiee" }, {
1120
+ codeColumns: true,
1121
+ extraDefs: {
1122
+ publisher: { type: "string", default: "AIEE" },
1123
+ type: { type: "string", default: undefined },
1124
+ date_separator: { type: "string" },
1125
+ original_format: { type: "string" },
1126
+ },
1127
+ extraMappings: keyValue({ wire: "date_separator", to: "date_separator" }, { wire: "original_format", to: "original_format" }),
1128
+ render: (id) => {
1129
+ const result = [id.publisher];
1130
+ if (id.type !== undefined && id.type !== "")
1131
+ result.push(id.type);
1132
+ if (id.codeObj !== undefined)
1133
+ result.push(id.codeObj.render());
1134
+ let base = result.join(" ");
1135
+ const format = id["original_format"];
1136
+ if (id.year !== undefined) {
1137
+ const month = id.month;
1138
+ const dateSep = id["date_separator"];
1139
+ if (format === "short") {
1140
+ base += `-${id.year}`;
1141
+ }
1142
+ else if (format === "long" || month !== undefined || dateSep !== undefined) {
1143
+ const sep = dateSep ?? ",";
1144
+ base += `${sep} ${month !== undefined ? `${month} ` : ""}${id.year}`;
1145
+ }
1146
+ else {
1147
+ base += `-${id.year}`;
1148
+ }
1149
+ }
1150
+ return base;
1151
+ },
1152
+ });
1153
+ export const IreClass = ieeeClass({ kind: "ire" }, {
1154
+ codeColumns: true,
1155
+ extraDefs: {
1156
+ publisher: { type: "string", default: "IRE" },
1157
+ type: { type: "string", default: undefined },
1158
+ },
1159
+ render: (id) => {
1160
+ const shortYear = (() => {
1161
+ if (id.year === undefined)
1162
+ return undefined;
1163
+ const value = Number.parseInt(id.year, 10);
1164
+ return String(value >= 1900 && value <= 1999 ? value - 1900 : value);
1165
+ })();
1166
+ const result = [shortYear, id.publisher, id.type, id.codeObj?.render()]
1167
+ .filter((p) => p !== undefined && p !== "");
1168
+ return result.join(" ");
1169
+ },
1170
+ });
1171
+ const NescDefs = {
1172
+ variant: { type: "string" },
1173
+ registered: { type: "boolean" },
1174
+ abbr_suffix: { type: "boolean" },
1175
+ abbr_suffix_registered: { type: "boolean" },
1176
+ };
1177
+ const NescMappings = keyValue({ wire: "variant", to: "variant" }, { wire: "registered", to: "registered" }, { wire: "abbr_suffix", to: "abbr_suffix" }, { wire: "abbr_suffix_registered", to: "abbr_suffix_registered" });
1178
+ export const NescEditionClass = ieeeClass({ kind: "nesc-edition" }, {
1179
+ codeColumns: true,
1180
+ extraDefs: NescDefs,
1181
+ extraMappings: NescMappings,
1182
+ render: (id) => ["IEEE Std", id.year, nescNamePortion(id)].filter((p) => p !== undefined).join(" "),
1183
+ });
1184
+ export const NescHandbookClass = ieeeClass({ kind: "nesc-handbook" }, {
1185
+ codeColumns: true,
1186
+ extraDefs: { ...NescDefs, edition: { type: "string", default: undefined } },
1187
+ extraMappings: NescMappings,
1188
+ render: (id) => {
1189
+ const abbr = id.registered === true ? "NESC(R)" : "NESC";
1190
+ const parts = [["IEEE Std", id.year, `${abbr} Handbook`].filter((p) => p !== undefined).join(" ")];
1191
+ if (id.edition !== undefined)
1192
+ parts.push(`, ${id.edition}`);
1193
+ return parts.join("");
1194
+ },
1195
+ });
1196
+ export const NescRedlineClass = ieeeClass({ kind: "nesc-redline" }, {
1197
+ codeColumns: true,
1198
+ extraDefs: NescDefs,
1199
+ extraMappings: NescMappings,
1200
+ render: (id) => [id.year, "NESC Redline"].filter((p) => p !== undefined).join(" "),
1201
+ });
1202
+ export const NescStandardClass = ieeeClass({ kind: "nesc-standard" }, {
1203
+ codeColumns: true,
1204
+ extraDefs: NescDefs,
1205
+ extraMappings: NescMappings,
1206
+ render: (id) => {
1207
+ let codePart = "C2";
1208
+ if (id.year !== undefined)
1209
+ codePart += `-${id.year}`;
1210
+ return `${codePart} National Electrical Safety Code`;
1211
+ },
1212
+ });
1213
+ export const NescDraftClass = ieeeClass({ kind: "nesc-draft" }, {
1214
+ codeColumns: true,
1215
+ extraDefs: NescDefs,
1216
+ extraMappings: NescMappings,
1217
+ render: (id) => {
1218
+ const parts = ["Draft National Electrical Safety Code"];
1219
+ if (id.month !== undefined && id.year !== undefined)
1220
+ parts.push(`, ${id.month} ${id.year}`);
1221
+ return parts.join("");
1222
+ },
1223
+ });
1224
+ function nescNamePortion(id) {
1225
+ let name = "National Electrical Safety Code";
1226
+ if (id["registered"] === true)
1227
+ name += "(R)";
1228
+ if (id["abbr_suffix"] === true) {
1229
+ let suffix = "NESC";
1230
+ if (id["abbr_suffix_registered"] === true)
1231
+ suffix += "(R)";
1232
+ name += ` (${suffix})`;
1233
+ }
1234
+ return name;
1235
+ }
1236
+ // The RedlinedStandard wrapper exists in Ruby but is unreachable (a redline
1237
+ // is a flat `redline: true` Standard); not registered.