@pubid/pubid 0.1.7 → 0.1.9
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.
- package/artifact/corpus.json.gz +0 -0
- package/dist/flavors/cen_cenelec/grammar.js +10 -4
- package/dist/flavors/cen_cenelec/index.js +20 -1
- package/dist/flavors/cen_cenelec/model.d.ts +1 -0
- package/dist/flavors/cen_cenelec/model.js +4 -1
- package/dist/flavors/evs/grammar.js +53 -7
- package/dist/flavors/evs/index.js +74 -7
- package/dist/flavors/evs/model.d.ts +37 -1
- package/dist/flavors/evs/model.js +173 -11
- package/dist/flavors/iec/index.js +15 -3
- package/dist/flavors/iec/model.d.ts +1 -1
- package/dist/flavors/iec/model.js +12 -2
- package/dist/flavors/ieee/artifact_tree.d.ts +2 -0
- package/dist/flavors/ieee/artifact_tree.js +36 -0
- package/dist/flavors/ieee/grammar.js +99 -19
- package/dist/flavors/ieee/index.js +312 -18
- package/dist/flavors/ieee/model.d.ts +5 -0
- package/dist/flavors/ieee/model.js +130 -20
- package/dist/flavors/ieee/preprocessor.js +3 -6
- package/dist/flavors/nist/grammar.js +18 -9
- package/dist/flavors/nist/index.js +16 -7
- package/dist/flavors/nist/preprocessor.js +9 -1
- package/dist/parg/runtime.d.ts +25 -0
- package/dist/parg/runtime.js +76 -0
- package/dist/parg/suite.d.ts +4 -0
- package/dist/parg/suite.js +14 -0
- package/dist/urn/parsers.js +12 -1
- package/package.json +6 -4
- package/vendor/parg/adobe.json +1 -0
- package/vendor/parg/aiee.json +1 -0
- package/vendor/parg/amca.json +1 -0
- package/vendor/parg/ansi.json +1 -0
- package/vendor/parg/api.json +1 -0
- package/vendor/parg/ashrae.json +1 -0
- package/vendor/parg/asme.json +1 -0
- package/vendor/parg/astm.json +1 -0
- package/vendor/parg/bipm.json +1 -0
- package/vendor/parg/bsi.json +1 -0
- package/vendor/parg/calconnect.json +1 -0
- package/vendor/parg/ccsds.json +1 -0
- package/vendor/parg/cen_cenelec.json +1 -0
- package/vendor/parg/cie.json +1 -0
- package/vendor/parg/csa.json +1 -0
- package/vendor/parg/doi.json +1 -0
- package/vendor/parg/easc.json +1 -0
- package/vendor/parg/ecma.json +1 -0
- package/vendor/parg/etsi.json +1 -0
- package/vendor/parg/evs.json +1 -0
- package/vendor/parg/gb.json +1 -0
- package/vendor/parg/gost.json +1 -0
- package/vendor/parg/iala.json +1 -0
- package/vendor/parg/iana.json +1 -0
- package/vendor/parg/idf.json +1 -0
- package/vendor/parg/iec.json +1 -0
- package/vendor/parg/ieee.json +1 -0
- package/vendor/parg/ietf.json +1 -0
- package/vendor/parg/ire.json +1 -0
- package/vendor/parg/isbn.json +1 -0
- package/vendor/parg/iso.json +1 -0
- package/vendor/parg/itu.json +1 -0
- package/vendor/parg/jcgm.json +1 -0
- package/vendor/parg/jis.json +1 -0
- package/vendor/parg/nesc.json +1 -0
- package/vendor/parg/nist.json +1 -0
- package/vendor/parg/oasis.json +1 -0
- package/vendor/parg/ogc.json +1 -0
- package/vendor/parg/oiml.json +1 -0
- package/vendor/parg/omg.json +1 -0
- package/vendor/parg/parg.json +1 -0
- package/vendor/parg/plateau.json +1 -0
- package/vendor/parg/sae.json +1 -0
- package/vendor/parg/tgpp.json +1 -0
- package/vendor/parg/un.json +1 -0
- package/vendor/parg/w3c.json +1 -0
- package/vendor/parg/xsf.json +1 -0
- package/dist/pg/runtime.d.ts +0 -85
- package/dist/pg/runtime.js +0 -170
- package/dist/pg/suite.d.ts +0 -20
- package/dist/pg/suite.js +0 -90
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ParseFailed, parseGrammar } from "../../grammar/engine.js";
|
|
2
|
+
import { PubidRuntime } from "../../parg/runtime.js";
|
|
3
|
+
import { artifactToBuilderTree } from "./artifact_tree.js";
|
|
2
4
|
import { grammarImplementation } from "../index.js";
|
|
3
5
|
import { ieeeGrammar } from "./grammar.js";
|
|
4
6
|
import { preParse, preprocessIeee } from "./preprocessor.js";
|
|
5
7
|
import { applyUpdateCodes } from "./update_codes.js";
|
|
6
|
-
import { AdoptedStandardClass, AieeClass, AmendmentClass, ConformanceClass, CorrigendumClass, CsaDualPublishedClass, DualPublishedClass, IecIeeeCopublishedClass, IeeeCode, IeeeDraft, IeeeRelationship, IeeeTypedStage, InterpretationClass, IreClass, JointDevelopmentClass, MultiNumberedClass, NescDraftClass, NescEditionClass, NescHandbookClass, NescRedlineClass, NescStandardClass, ProjectDraftIdentifierClass, SiStandardClass, StandardClass, locateStage, } from "./model.js";
|
|
8
|
+
import { AdoptedStandardClass, AieeClass, AmendmentClass, ConformanceClass, CorrigendumClass, CsaDualPublishedClass, DualPublishedClass, IecIeeeCopublishedClass, IeeeCode, IeeeDraft, IeeeRelationship, IeeeTypedStage, InterpretationClass, IreClass, JointDevelopmentClass, MultiNumberedClass, NescDraftClass, NescEditionClass, NescHandbookClass, NescPreprintClass, NescRedlineClass, NescStandardClass, DRAFT_MONTH_NAMES, ProjectDraftIdentifierClass, SiStandardClass, StandardClass, locateStage, } from "./model.js";
|
|
7
9
|
/**
|
|
8
10
|
* Port of lib/pubid/ieee/{builder}.rb + Identifier.parse orchestration
|
|
9
11
|
* (pre-parser dispatch, adopted/dual constructors, sub-builders).
|
|
@@ -34,6 +36,7 @@ class IeeeBuilder {
|
|
|
34
36
|
originalInput = "";
|
|
35
37
|
build(parsed) {
|
|
36
38
|
const d = Array.isArray(parsed) ? mergeParsedArray(parsed) : parsed;
|
|
39
|
+
this.normalizeDraftDashYear(d);
|
|
37
40
|
if (d["ieee_portion"] !== undefined && d["csa_portion"] !== undefined) {
|
|
38
41
|
return this.buildCsaDualPublished(d);
|
|
39
42
|
}
|
|
@@ -55,6 +58,117 @@ class IeeeBuilder {
|
|
|
55
58
|
return this.buildSingleIdentifier(d, false);
|
|
56
59
|
}
|
|
57
60
|
// --- single identifier -----------------------------------------------------
|
|
61
|
+
// The artifact binds a dash-year draft tail as a second draft element
|
|
62
|
+
// ({draft_version: {dash_year: ...}}); the reference's builder hoists
|
|
63
|
+
// the dash fields and rejoins the version ("D9-2006", "/DPub2-2012").
|
|
64
|
+
normalizeDraftDashYear(d) {
|
|
65
|
+
const raw = d["draft"];
|
|
66
|
+
if (raw === undefined)
|
|
67
|
+
return;
|
|
68
|
+
const drafts = Array.isArray(raw) ? raw : [raw];
|
|
69
|
+
// The compound-stage captures nest inside the draft elements (the
|
|
70
|
+
// artifact's binding); the hand mirror bound them top-level, so the
|
|
71
|
+
// joint-designator block reads them from `parsed` directly.
|
|
72
|
+
for (const key of ["draft_iso_stage", "draft_iso_iteration", "draft_stage_d", "draft_stage_year"]) {
|
|
73
|
+
if (d[key] === undefined) {
|
|
74
|
+
for (const e of drafts) {
|
|
75
|
+
if (isObj(e) && e[key] !== undefined) {
|
|
76
|
+
d[key] = e[key];
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
for (const e of drafts) {
|
|
83
|
+
if (!isObj(e))
|
|
84
|
+
continue;
|
|
85
|
+
const dv = e["draft_version"];
|
|
86
|
+
if (!isObj(dv))
|
|
87
|
+
continue;
|
|
88
|
+
if (dv["dash_year"] !== undefined)
|
|
89
|
+
e["dash_year"] = dv["dash_year"];
|
|
90
|
+
if (dv["dash_month"] !== undefined)
|
|
91
|
+
e["dash_month"] = dv["dash_month"];
|
|
92
|
+
delete e["draft_version"];
|
|
93
|
+
}
|
|
94
|
+
// A numeric month trailing a draft is the draft's own date: it embeds
|
|
95
|
+
// in the designator ("D09, 04 2011" -> "D09-2011-04") rather than
|
|
96
|
+
// printing the long-format comma face (a month name keeps the comma,
|
|
97
|
+
// "D7.2, Nov 2006") - pubid ruling 2026-10-13.
|
|
98
|
+
if (d["dash_year"] === undefined && d["draft"] !== undefined) {
|
|
99
|
+
const m = d["month"] ?? d["trailing_month"];
|
|
100
|
+
const y = d["year"] ?? d["trailing_year"];
|
|
101
|
+
const mVal = extractValue(m);
|
|
102
|
+
const yVal = extractValue(y);
|
|
103
|
+
if (mVal !== undefined && /^\d{1,2}$/.test(String(mVal)) && yVal !== undefined) {
|
|
104
|
+
const host = drafts.find((e) => isObj(e) && e["draft_version"] !== undefined);
|
|
105
|
+
if (host !== undefined && isObj(host)) {
|
|
106
|
+
const hv = host["draft_version"];
|
|
107
|
+
const joined = Array.isArray(hv)
|
|
108
|
+
? hv.map((v) => (isObj(v) ? (v["value"] ?? "") : String(v))).join("")
|
|
109
|
+
: String(extractValue(hv) ?? "");
|
|
110
|
+
host["draft_version"] = [joined, String(yVal), String(mVal)]
|
|
111
|
+
.filter((s) => s !== "")
|
|
112
|
+
.join("-");
|
|
113
|
+
delete d["month"];
|
|
114
|
+
delete d["year"];
|
|
115
|
+
delete d["trailing_month"];
|
|
116
|
+
delete d["trailing_year"];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const dash = drafts.find((e) => isObj(e) && e["dash_year"] !== undefined) ??
|
|
121
|
+
(d["dash_year"] !== undefined ? d : undefined);
|
|
122
|
+
if (dash === undefined || d["year"] !== undefined)
|
|
123
|
+
return;
|
|
124
|
+
const objs = drafts.filter(isObj);
|
|
125
|
+
const joined = objs
|
|
126
|
+
.map((e) => e["draft_version"])
|
|
127
|
+
.filter((v) => v !== undefined)
|
|
128
|
+
.map((v) => (isObj(v) ? (v["value"] ?? "") : String(v)))
|
|
129
|
+
.join("");
|
|
130
|
+
const bareJointDraft = d["joint_publishers"] !== undefined &&
|
|
131
|
+
d["part"] === undefined && d["iso_stage"] === undefined &&
|
|
132
|
+
objs.some((e) => e["draft_version"] !== undefined);
|
|
133
|
+
const dashLed = joined.startsWith("-");
|
|
134
|
+
const dashYear = extractValue(dash["dash_year"]);
|
|
135
|
+
const dashMonth = dash["dash_month"];
|
|
136
|
+
if (bareJointDraft && dashLed) {
|
|
137
|
+
d["part"] = dashYear;
|
|
138
|
+
}
|
|
139
|
+
else if (dashMonth !== undefined || dashLed) {
|
|
140
|
+
// A dash_month beside a draft host is the draft's own date
|
|
141
|
+
// ("/R-i-2011-04" -> "D09-2011-04"); with no host it is the
|
|
142
|
+
// identifier's year/month.
|
|
143
|
+
const host = objs.find((e) => e["draft_version"] !== undefined);
|
|
144
|
+
const dm = extractValue(dashMonth);
|
|
145
|
+
if (dm !== undefined && host !== undefined) {
|
|
146
|
+
const hv = host["draft_version"];
|
|
147
|
+
const joined = Array.isArray(hv)
|
|
148
|
+
? hv.map((v) => (isObj(v) ? (v["value"] ?? "") : String(v))).join("")
|
|
149
|
+
: String(extractValue(hv) ?? "");
|
|
150
|
+
host["draft_version"] = [joined, dashYear, String(dm)].join("-");
|
|
151
|
+
delete dash["dash_year"];
|
|
152
|
+
delete dash["dash_month"];
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
d["year"] = dashYear;
|
|
156
|
+
d["month"] = dm;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const host = objs.find((e) => e["draft_version"] !== undefined);
|
|
161
|
+
if (host !== undefined) {
|
|
162
|
+
host["draft_version"] = `${joined}-${dashYear}`;
|
|
163
|
+
delete dash["dash_year"];
|
|
164
|
+
delete dash["dash_month"];
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
d["year"] = dashYear;
|
|
168
|
+
d["month"] = extractValue(dashMonth);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
58
172
|
buildSingleIdentifier(parsed, buildingSecondary) {
|
|
59
173
|
const parsedHash = asHash(parsed);
|
|
60
174
|
if (!buildingSecondary && parsedHash["primary_identifier"] !== undefined &&
|
|
@@ -98,6 +212,27 @@ class IeeeBuilder {
|
|
|
98
212
|
if (parsedHash["joint_publishers"] !== undefined || parsedHash["iso_stage"] !== undefined) {
|
|
99
213
|
return this.buildJointDevelopment(parsedHash);
|
|
100
214
|
}
|
|
215
|
+
// The ORDINAL-LESS D= designator on a multi-publisher row is the
|
|
216
|
+
// joint compound form ("ISO/IEC/IEEE P16326:2017/D=WD.4a"); the
|
|
217
|
+
// ordinal compound ("D8=DIS.3") is a project draft whatever the
|
|
218
|
+
// publishers — the D-ordinal is the draft, the stage the target.
|
|
219
|
+
if (parsedHash["draft_iso_stage"] !== undefined) {
|
|
220
|
+
const draftHash = parsedHash["draft"] !== undefined
|
|
221
|
+
? asHash(parsedHash["draft"])
|
|
222
|
+
: undefined;
|
|
223
|
+
const hasOrdinal = extractValue(parsedHash["draft_version"]) !== undefined ||
|
|
224
|
+
extractValue(draftHash?.["draft_version"]) !== undefined;
|
|
225
|
+
if (!hasOrdinal) {
|
|
226
|
+
const pubData = parsedHash["publishers"] !== undefined
|
|
227
|
+
? asHash(parsedHash["publishers"])
|
|
228
|
+
: undefined;
|
|
229
|
+
const copubs = pubData?.["copublishers"] !== undefined
|
|
230
|
+
? (Array.isArray(pubData["copublishers"]) ? pubData["copublishers"] : [pubData["copublishers"]])
|
|
231
|
+
: [];
|
|
232
|
+
if (copubs.length > 0)
|
|
233
|
+
return this.buildJointDevelopment(parsedHash);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
101
236
|
const attributes = this.extractAttributes(parsedHash);
|
|
102
237
|
if (parsedHash["relationship_type"] !== undefined || parsedHash["relationship_clause"] !== undefined) {
|
|
103
238
|
attributes["relationships"] = this.buildRelationships(parsedHash);
|
|
@@ -215,7 +350,12 @@ class IeeeBuilder {
|
|
|
215
350
|
codeStr = codeStr.replace(/^P/, "");
|
|
216
351
|
}
|
|
217
352
|
if (codeStr !== undefined && codeParts.length > 0) {
|
|
218
|
-
|
|
353
|
+
// Captures carry their own separator when present (the artifact's
|
|
354
|
+
// part/subpart bind ".18" / "-10"); bare tokens fall back to the
|
|
355
|
+
// hand grammar's part_sep. Joins verbatim like the reference's
|
|
356
|
+
// extract_attributes — a dashed "62271-37-082" stays dashed.
|
|
357
|
+
const partSep = extractValue(parsed["part_sep"]) ?? ".";
|
|
358
|
+
codeStr += codeParts.map((cp) => /^[._-]/.test(cp) ? cp : `${partSep}${cp}`).join("");
|
|
219
359
|
}
|
|
220
360
|
if (codeStr !== undefined && parsed["year"] === undefined && codeParts.length === 0) {
|
|
221
361
|
const m = /^(.+)-(\d{4})$/.exec(codeStr);
|
|
@@ -261,7 +401,15 @@ class IeeeBuilder {
|
|
|
261
401
|
/^IEEE\s/.test(this.originalInput)) {
|
|
262
402
|
typeValue = "Std";
|
|
263
403
|
}
|
|
264
|
-
|
|
404
|
+
// The canonical type word is the short form (C2 ruling):
|
|
405
|
+
// "IEEE Standard 495-2007" and "IEEE Std 495-2007" are the same
|
|
406
|
+
// identifier. A DRAFT type word never reaches the wire (the
|
|
407
|
+
// draft-ness rides draft_status + the draft component; "Draft Std"
|
|
408
|
+
// is banned from canonical output) - it still feeds
|
|
409
|
+
// determineStageAbbr below (the version-less D1 fabrication).
|
|
410
|
+
if (typeValue === "Standard")
|
|
411
|
+
typeValue = "Std";
|
|
412
|
+
if (typeValue !== undefined && !/^Draft/.test(typeValue))
|
|
265
413
|
attributes["type"] = typeValue;
|
|
266
414
|
const typedStageAbbr = this.determineStageAbbr(typeValue, parsed);
|
|
267
415
|
if (typedStageAbbr !== undefined) {
|
|
@@ -270,11 +418,13 @@ class IeeeBuilder {
|
|
|
270
418
|
attributes["typed_stage"] = new IeeeTypedStage(record);
|
|
271
419
|
}
|
|
272
420
|
attributes["draft_status"] = draftStatusValue;
|
|
273
|
-
for (const key of ["edition", "revision"]) {
|
|
421
|
+
for (const key of ["edition", "revision", "rev_sep"]) {
|
|
274
422
|
const value = extractValue(parsed[key]);
|
|
275
423
|
if (value !== undefined)
|
|
276
424
|
attributes[key] = value;
|
|
277
425
|
}
|
|
426
|
+
if (parsed["rev_bare"] !== undefined)
|
|
427
|
+
attributes["rev_bare"] = true;
|
|
278
428
|
if (attributes["edition_month"] === undefined) {
|
|
279
429
|
const month = extractValue(parsed["month"]);
|
|
280
430
|
if (month !== undefined)
|
|
@@ -299,6 +449,13 @@ class IeeeBuilder {
|
|
|
299
449
|
attributes["interpretation"] = true;
|
|
300
450
|
if (parsed["redline"] !== undefined)
|
|
301
451
|
attributes["redline"] = true;
|
|
452
|
+
// Glued identity year-month provenance (gem#520): the input tail is
|
|
453
|
+
// the glued "-YYYY-MM" on a draft-free, revision-free identity.
|
|
454
|
+
if (attributes["month"] !== undefined && attributes["year"] !== undefined &&
|
|
455
|
+
attributes["draft"] === undefined && attributes["revision"] === undefined &&
|
|
456
|
+
/-\d{4}-\d{2}$/.test(this.originalInput ?? "")) {
|
|
457
|
+
attributes["month_glued"] = true;
|
|
458
|
+
}
|
|
302
459
|
return attributes;
|
|
303
460
|
}
|
|
304
461
|
determineStageAbbr(typeValue, parsed) {
|
|
@@ -377,6 +534,12 @@ class IeeeBuilder {
|
|
|
377
534
|
isoIteration = extractValue(draftData["draft_iso_iteration"]);
|
|
378
535
|
month = extractValue(draftData["month"]);
|
|
379
536
|
year = extractValue(draftData["year"]);
|
|
537
|
+
// The apostrophe-year catalogue convention ("P1484.20.1/D7,
|
|
538
|
+
// May 07"): the 2-digit year expands with the <30 pivot so the
|
|
539
|
+
// hash carries an unambiguous year (the reference's builder).
|
|
540
|
+
if (year !== undefined && /^\d{2}$/.test(year)) {
|
|
541
|
+
year = `${Number(year) < 30 ? 20 : 19}${year}`;
|
|
542
|
+
}
|
|
380
543
|
day = extractValue(draftData["day"]);
|
|
381
544
|
if (this.originalInput !== "" && month !== undefined) {
|
|
382
545
|
commaBeforeMonth = new RegExp(`,\\s+${month.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`, "i")
|
|
@@ -390,6 +553,20 @@ class IeeeBuilder {
|
|
|
390
553
|
else {
|
|
391
554
|
version = extractValue(draftData);
|
|
392
555
|
}
|
|
556
|
+
// A REV-carrying draft embeds its print date into the designator
|
|
557
|
+
// with the month canonicalized numeric (pubid ruling 2026-10-14):
|
|
558
|
+
// "P802.11-REVmc/D8.0, Aug 2016" renders ".../D8.0-2016-08".
|
|
559
|
+
// Drafts without a REV keep the comma face.
|
|
560
|
+
if ((attributes["revision"] !== undefined || attributes["rev_bare"] === true) &&
|
|
561
|
+
month !== undefined && year !== undefined && version !== undefined) {
|
|
562
|
+
const monthNumber = DRAFT_MONTH_NAMES[String(month).replace(/\.$/, "")];
|
|
563
|
+
if (monthNumber !== undefined) {
|
|
564
|
+
// The canonical face zero-pads ("D8.0-2016-08"), matching the
|
|
565
|
+
// reference's REV_MONTH_NUMBERS.
|
|
566
|
+
version = `${version}-${year}-${monthNumber.padStart(2, "0")}`;
|
|
567
|
+
month = year = day = undefined;
|
|
568
|
+
}
|
|
569
|
+
}
|
|
393
570
|
if (version !== undefined || (isObj(draftData) && draftData["draft_iso_stage"] !== undefined)) {
|
|
394
571
|
const draftObj = new IeeeDraft({
|
|
395
572
|
version,
|
|
@@ -409,7 +586,11 @@ class IeeeBuilder {
|
|
|
409
586
|
return;
|
|
410
587
|
if (typeValue !== "Draft Std")
|
|
411
588
|
return;
|
|
412
|
-
|
|
589
|
+
// The reference stores the fabricated designator comma-joined with the
|
|
590
|
+
// identity year ("D1, 2012" — the gem's Draft#to_s), not space-joined.
|
|
591
|
+
attributes["draft"] = attributes["year"] === undefined
|
|
592
|
+
? "D1"
|
|
593
|
+
: `D1, ${attributes["year"]}`;
|
|
413
594
|
}
|
|
414
595
|
handleKeyedHash(parsed, key, attributes, numberKey, yearKey) {
|
|
415
596
|
if (isObj(parsed[key])) {
|
|
@@ -526,15 +707,17 @@ class IeeeBuilder {
|
|
|
526
707
|
baseParts.push(extractValue(baseData["type"]) ?? "");
|
|
527
708
|
}
|
|
528
709
|
let numberStr = extractValue(baseData["number"]) ?? "";
|
|
710
|
+
const baseSep = extractValue(baseData["part_sep"]) ?? ".";
|
|
529
711
|
if (baseData["part"] !== undefined) {
|
|
530
|
-
|
|
712
|
+
const pv = extractValue(baseData["part"]) ?? "";
|
|
713
|
+
numberStr += /^[._-]/.test(pv) ? pv : `${baseSep}${pv}`;
|
|
531
714
|
}
|
|
532
715
|
if (baseData["subpart"] !== undefined) {
|
|
533
716
|
const subparts = Array.isArray(baseData["subpart"]) ? baseData["subpart"] : [baseData["subpart"]];
|
|
534
717
|
for (const sp of subparts) {
|
|
535
718
|
const v = extractValue(sp);
|
|
536
719
|
if (v !== undefined)
|
|
537
|
-
numberStr +=
|
|
720
|
+
numberStr += /^[._-]/.test(v) ? v : `${baseSep}${v}`;
|
|
538
721
|
}
|
|
539
722
|
}
|
|
540
723
|
if (baseData["year"] !== undefined) {
|
|
@@ -618,15 +801,33 @@ class IeeeBuilder {
|
|
|
618
801
|
attributes["publisher"] = pubs[0];
|
|
619
802
|
attributes["copublisher"] = pubs.slice(1);
|
|
620
803
|
}
|
|
804
|
+
else if (parsed["publishers"] !== undefined) {
|
|
805
|
+
// Stage-bearing rows the artifact routes without a
|
|
806
|
+
// joint_publishers capture ("ISO/IEC/IEEE P26511/D8=DDIS.3"):
|
|
807
|
+
// the publishers hash carries the same information.
|
|
808
|
+
const pubData = asHash(parsed["publishers"]);
|
|
809
|
+
const lead = extractValue(pubData["publisher"]) ?? "";
|
|
810
|
+
const copubs = pubData["copublishers"] !== undefined
|
|
811
|
+
? (Array.isArray(pubData["copublishers"])
|
|
812
|
+
? pubData["copublishers"]
|
|
813
|
+
: [pubData["copublishers"]])
|
|
814
|
+
.map((cp) => extractValue(asHash(cp)["copublisher"]))
|
|
815
|
+
.filter((cp) => cp !== undefined)
|
|
816
|
+
: [];
|
|
817
|
+
attributes["publishers"] = [lead, ...copubs];
|
|
818
|
+
attributes["publisher"] = lead;
|
|
819
|
+
attributes["copublisher"] = copubs;
|
|
820
|
+
}
|
|
621
821
|
const codeParts = [];
|
|
622
822
|
if (parsed["part"] !== undefined)
|
|
623
823
|
codeParts.push(extractValue(parsed["part"]) ?? "");
|
|
624
824
|
let codeStr = extractValue(parsed["number"]);
|
|
625
825
|
if (codeStr !== undefined && codeParts.length > 0) {
|
|
626
826
|
// The ISO/IEC label's part may be dash-joined ("8802-9") - keep the
|
|
627
|
-
// printed separator.
|
|
827
|
+
// printed separator. Separator-carrying captures (the artifact's
|
|
828
|
+
// part binds ".2") join verbatim.
|
|
628
829
|
const sep = parsed["iec_label_dash"] !== undefined ? "-" : ".";
|
|
629
|
-
codeStr += `${sep}${
|
|
830
|
+
codeStr += codeParts.map((cp) => /^[._-]/.test(cp) ? cp : `${sep}${cp}`).join("");
|
|
630
831
|
}
|
|
631
832
|
// P = project (a draft): identity-bearing, preserved as spelled.
|
|
632
833
|
if (parsed["project_marker"] !== undefined && codeStr !== undefined) {
|
|
@@ -665,8 +866,39 @@ class IeeeBuilder {
|
|
|
665
866
|
}
|
|
666
867
|
if (parsed["draft_version"] !== undefined) {
|
|
667
868
|
const draftVer = (extractValue(parsed["draft_version"]) ?? "").replace(/^D/, "");
|
|
668
|
-
if (draftVer !== "")
|
|
669
|
-
|
|
869
|
+
if (draftVer !== "") {
|
|
870
|
+
// A date trailing the draft (", June 2010") belongs to the draft
|
|
871
|
+
// component (canonical month, comma form); the identity
|
|
872
|
+
// year/month the promotion filled from the same captures are
|
|
873
|
+
// vacated. Stage-first ISO rows are exempt: their canonical is
|
|
874
|
+
// the ISO face, which prints the date from the identity slots
|
|
875
|
+
// (", March 2017", pubid#216).
|
|
876
|
+
if (parsed["draft_month"] !== undefined && parsed["iso_stage"] === undefined) {
|
|
877
|
+
const draftObj = new IeeeDraft({
|
|
878
|
+
version: draftVer,
|
|
879
|
+
month: extractValue(parsed["draft_month"]),
|
|
880
|
+
year: extractValue(parsed["draft_year"]),
|
|
881
|
+
comma_before_month: true,
|
|
882
|
+
});
|
|
883
|
+
attributes["draft"] = draftObj.render();
|
|
884
|
+
if (parsed["year"] === undefined)
|
|
885
|
+
delete attributes["year"];
|
|
886
|
+
if (parsed["month"] === undefined)
|
|
887
|
+
delete attributes["month"];
|
|
888
|
+
}
|
|
889
|
+
else if (parsed["draft_year"] !== undefined && parsed["iso_stage"] === undefined) {
|
|
890
|
+
// The comma-year tail captures its separator (", 2013") —
|
|
891
|
+
// strip it (the #471 separator-in-capture rule). The stored
|
|
892
|
+
// form keeps the comma so it re-parses through the same tail.
|
|
893
|
+
const draftYear = (extractValue(parsed["draft_year"]) ?? "").replace(/^[, ]+/, "");
|
|
894
|
+
attributes["draft"] = `/D${draftVer}, ${draftYear}`;
|
|
895
|
+
if (parsed["year"] === undefined)
|
|
896
|
+
delete attributes["year"];
|
|
897
|
+
}
|
|
898
|
+
else {
|
|
899
|
+
attributes["ieee_draft"] = `D${draftVer}`;
|
|
900
|
+
}
|
|
901
|
+
}
|
|
670
902
|
}
|
|
671
903
|
// The "(E)" edition marker of an ISO/IEC label rides on the joint
|
|
672
904
|
// reference as parenthetical_content - either from the trailing
|
|
@@ -681,21 +913,37 @@ class IeeeBuilder {
|
|
|
681
913
|
if (attributes["parenthetical_content"] === undefined && parsed["edition_marker"] !== undefined) {
|
|
682
914
|
attributes["parenthetical_content"] = extractValue(parsed["edition_marker"]);
|
|
683
915
|
}
|
|
916
|
+
// A joint ISO-print redline is a distinct document of the same standard
|
|
917
|
+
// (pubid#215) - same flag semantics as the generic path.
|
|
918
|
+
if (parsed["redline"] !== undefined)
|
|
919
|
+
attributes["redline"] = true;
|
|
684
920
|
// The joint stage-draft clause (docs/IEEE-DRAFT-STAGES.md §1.3):
|
|
685
921
|
// variant 1's compound tail composes onto the IEEE ordinal
|
|
686
922
|
// ("D5=DIS.3"); variant 1b is the ordinal-less stage draft whose
|
|
687
923
|
// date rides inside the designator ("D=CDV:2020"). The doubled-D
|
|
688
924
|
// alias spelling echoes as spelled.
|
|
689
925
|
if (parsed["draft_iso_stage"] !== undefined) {
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
926
|
+
// The doubled-D alias ("=DDIS") is notation: the designator carries
|
|
927
|
+
// its own D-ordinal, the stage is the bare ISO/IEC token.
|
|
928
|
+
const rawStage = `${extractValue(parsed["draft_stage_d"]) ?? ""}${extractValue(parsed["draft_iso_stage"]) ?? ""}`;
|
|
929
|
+
const stageText = rawStage.startsWith("D") &&
|
|
930
|
+
["PWI", "NP", "WD", "CD", "CDV", "DIS", "FDIS"].includes(rawStage.slice(1))
|
|
931
|
+
? rawStage.slice(1)
|
|
932
|
+
: rawStage;
|
|
933
|
+
const jointVersion = extractValue(parsed["draft_version"]) ??
|
|
934
|
+
(parsed["draft"] !== undefined
|
|
935
|
+
? extractValue(asHash(parsed["draft"])["draft_version"])
|
|
936
|
+
: undefined);
|
|
937
|
+
let jointDraft = jointVersion !== undefined
|
|
938
|
+
? `D${jointVersion.replace(/^D/, "")}=${stageText}`
|
|
693
939
|
: `D=${stageText}`;
|
|
694
940
|
if (parsed["draft_iso_iteration"] !== undefined) {
|
|
695
941
|
jointDraft += `.${extractValue(parsed["draft_iso_iteration"])}`;
|
|
696
942
|
}
|
|
697
943
|
if (parsed["draft_stage_year"] !== undefined) {
|
|
698
|
-
|
|
944
|
+
// The capture carries its separator (":2020") — strip it (the
|
|
945
|
+
// #471 separator-in-capture rule).
|
|
946
|
+
jointDraft += `:${(extractValue(parsed["draft_stage_year"]) ?? "").replace(/^[\-:]/, "")}`;
|
|
699
947
|
}
|
|
700
948
|
attributes["ieee_draft"] = jointDraft;
|
|
701
949
|
}
|
|
@@ -791,6 +1039,29 @@ class IeeeBuilder {
|
|
|
791
1039
|
if (record !== undefined)
|
|
792
1040
|
attributes["typed_stage"] = new IeeeTypedStage(record);
|
|
793
1041
|
}
|
|
1042
|
+
// A plain IEEE-designator draft on joint publishers ("/D8, June
|
|
1043
|
+
// 2010") carries no ISO stage machinery: it builds as the project
|
|
1044
|
+
// draft its bare-IEEE twin and the D= designator rows already pin
|
|
1045
|
+
// (pubid#430) rather than the joint-development model.
|
|
1046
|
+
if (attributes["draft"] !== undefined &&
|
|
1047
|
+
parsed["iso_stage"] === undefined &&
|
|
1048
|
+
parsed["iec_stage"] === undefined &&
|
|
1049
|
+
parsed["amd_number"] === undefined) {
|
|
1050
|
+
const pubs = (attributes["publishers"] ?? []);
|
|
1051
|
+
const projectAttrs = {
|
|
1052
|
+
code: attributes["code"],
|
|
1053
|
+
draft: attributes["draft"],
|
|
1054
|
+
};
|
|
1055
|
+
if (pubs.length > 0) {
|
|
1056
|
+
projectAttrs["publisher"] = pubs[0];
|
|
1057
|
+
if (pubs.length > 1)
|
|
1058
|
+
projectAttrs["copublisher"] = pubs.slice(1);
|
|
1059
|
+
}
|
|
1060
|
+
if (attributes["draft_status"] !== undefined) {
|
|
1061
|
+
projectAttrs["draft_status"] = attributes["draft_status"];
|
|
1062
|
+
}
|
|
1063
|
+
return new ProjectDraftIdentifierClass(projectAttrs);
|
|
1064
|
+
}
|
|
794
1065
|
const joint = new JointDevelopmentClass(attributes);
|
|
795
1066
|
if (parsed["amd_number"] === undefined)
|
|
796
1067
|
return joint;
|
|
@@ -1046,7 +1317,12 @@ class IeeeBuilder {
|
|
|
1046
1317
|
// nested name_first variant captures as a hash) and reaches Standard
|
|
1047
1318
|
// via the code check; Edition is only the no-code fallback.
|
|
1048
1319
|
let klass = NescEditionClass;
|
|
1049
|
-
if (parsedHash["
|
|
1320
|
+
if (parsedHash["preprint"] !== undefined) {
|
|
1321
|
+
// Preprint is a draft STAGE of the C2 code — checked before the
|
|
1322
|
+
// Standard route: the c2-preprint tree carries :code "C2" too.
|
|
1323
|
+
klass = NescPreprintClass;
|
|
1324
|
+
}
|
|
1325
|
+
else if (parsedHash["draft"] !== undefined) {
|
|
1050
1326
|
klass = NescDraftClass;
|
|
1051
1327
|
}
|
|
1052
1328
|
else if (typeof parsedHash["variant"] === "string") {
|
|
@@ -1120,6 +1396,24 @@ function copublishedStructured(copublishedNumber) {
|
|
|
1120
1396
|
return attrs;
|
|
1121
1397
|
}
|
|
1122
1398
|
// --- parse orchestration -------------------------------------------------------
|
|
1399
|
+
// The grammar runtime is the baked PARG artifact (pubid-grammar
|
|
1400
|
+
// artifacts/ieee.json via the parsanol engine) — the same artifact the
|
|
1401
|
+
// gem runs, so grammar changes land once and this port cannot drift.
|
|
1402
|
+
// Only the preprocessor, builder, model and the AIEE sub-grammar root
|
|
1403
|
+
// (parseAieeDirect) remain hand-written.
|
|
1404
|
+
let cachedArtifactRuntime;
|
|
1405
|
+
function parseSource(input) {
|
|
1406
|
+
cachedArtifactRuntime ??= PubidRuntime.load("ieee");
|
|
1407
|
+
try {
|
|
1408
|
+
return artifactToBuilderTree(cachedArtifactRuntime.parseShape(input));
|
|
1409
|
+
}
|
|
1410
|
+
catch (e) {
|
|
1411
|
+
// The engine throws its own error class; the reference's fallback
|
|
1412
|
+
// logic keys on Parslet::ParseFailed, so normalize (the messageless
|
|
1413
|
+
// wasm throws included).
|
|
1414
|
+
throw new ParseFailed(e instanceof Error && e.message !== "" ? e.message : String(e), 0);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1123
1417
|
function ieeeParseSingle(input) {
|
|
1124
1418
|
const normalized = applyUpdateCodes(input);
|
|
1125
1419
|
// UpdateCodes may introduce the "; " double-label separator (the
|
|
@@ -1131,7 +1425,7 @@ function ieeeParseSingle(input) {
|
|
|
1131
1425
|
return buildDual(re.parts);
|
|
1132
1426
|
}
|
|
1133
1427
|
const cleaned = preprocessIeee(normalized);
|
|
1134
|
-
const tree =
|
|
1428
|
+
const tree = parseSource(cleaned);
|
|
1135
1429
|
const builder = new IeeeBuilder();
|
|
1136
1430
|
builder.originalInput = input;
|
|
1137
1431
|
return builder.build(tree);
|
|
@@ -1141,7 +1435,7 @@ function ieeeParseSingle(input) {
|
|
|
1141
1435
|
// update-codes rewrite (e.g. "AIEE Nos 72 and 73 - 1932") must not make
|
|
1142
1436
|
// a line parse that the reference rejects.
|
|
1143
1437
|
function ieeeParseSingleNoCodes(input) {
|
|
1144
|
-
const tree =
|
|
1438
|
+
const tree = parseSource(preprocessIeee(input));
|
|
1145
1439
|
const builder = new IeeeBuilder();
|
|
1146
1440
|
builder.originalInput = input;
|
|
1147
1441
|
return builder.build(tree);
|
|
@@ -40,6 +40,7 @@ export declare class IeeeCode {
|
|
|
40
40
|
static parse(codeStr: string): IeeeCode | undefined;
|
|
41
41
|
render(): string;
|
|
42
42
|
}
|
|
43
|
+
export declare const DRAFT_MONTH_NAMES: Record<string, string>;
|
|
43
44
|
export declare class IeeeDraft {
|
|
44
45
|
readonly version: string;
|
|
45
46
|
readonly revision: string | undefined;
|
|
@@ -83,10 +84,13 @@ export declare abstract class IeeeIdentifier extends BaseIdentifier {
|
|
|
83
84
|
readonly draft_status: string | undefined;
|
|
84
85
|
readonly draft: string | undefined;
|
|
85
86
|
readonly revision: string | undefined;
|
|
87
|
+
readonly rev_sep: string | undefined;
|
|
88
|
+
readonly rev_bare: boolean | undefined;
|
|
86
89
|
readonly edition: string | undefined;
|
|
87
90
|
readonly month: string | undefined;
|
|
88
91
|
readonly day: string | undefined;
|
|
89
92
|
readonly redline: boolean | undefined;
|
|
93
|
+
readonly month_glued: boolean | undefined;
|
|
90
94
|
readonly edition_month: string | undefined;
|
|
91
95
|
readonly space_before_draft: boolean | undefined;
|
|
92
96
|
readonly typed_stage: IeeeTypedStage | undefined;
|
|
@@ -142,3 +146,4 @@ export declare const NescHandbookClass: IdentifierStatic;
|
|
|
142
146
|
export declare const NescRedlineClass: IdentifierStatic;
|
|
143
147
|
export declare const NescStandardClass: IdentifierStatic;
|
|
144
148
|
export declare const NescDraftClass: IdentifierStatic;
|
|
149
|
+
export declare const NescPreprintClass: IdentifierStatic;
|