@pubid/pubid 0.1.3 → 0.1.4

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