@pubid/pubid 0.1.12 → 0.1.14
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/dist/flavors/ieee/index.js +171 -11
- package/dist/flavors/ieee/model.js +7 -1
- package/dist/flavors/ieee/preprocessor.js +30 -15
- package/dist/flavors/ieee/update_codes.js +0 -2
- package/dist/flavors/itu/model.js +10 -1
- package/dist/flavors/nist/index.js +4 -3
- package/dist/flavors/nist/model.js +4 -2
- package/package.json +1 -1
|
@@ -284,6 +284,14 @@ class IeeeBuilder {
|
|
|
284
284
|
determineIdentifierClass(attributes) {
|
|
285
285
|
if (attributes["publisher"] === "AIEE")
|
|
286
286
|
return AieeClass;
|
|
287
|
+
// A stage-bearing row is a joint development whatever its type
|
|
288
|
+
// code: the stage is the printed identity ("IEEE P15026.2/FDIS",
|
|
289
|
+
// pubid#203) and only the joint model carries iso_stage and the D=
|
|
290
|
+
// designator (the reference's chooser).
|
|
291
|
+
if (attributes["iso_stage"] !== undefined ||
|
|
292
|
+
(attributes["ieee_draft"] ?? "").startsWith("D=")) {
|
|
293
|
+
return JointDevelopmentClass;
|
|
294
|
+
}
|
|
287
295
|
const typeCode = attributes["type"];
|
|
288
296
|
if (typeCode === "P")
|
|
289
297
|
return ProjectDraftIdentifierClass;
|
|
@@ -438,6 +446,33 @@ class IeeeBuilder {
|
|
|
438
446
|
if (day !== undefined)
|
|
439
447
|
attributes["day"] = day;
|
|
440
448
|
this.handleDraft(parsed, attributes);
|
|
449
|
+
this.foldDraftDateTail(attributes);
|
|
450
|
+
// The bare-IEEE fdraft clause (pubid#203): a slash-led stage word
|
|
451
|
+
// after the code ("IEEE P15026.2/FDIS, August 2010") rides the D=
|
|
452
|
+
// designator with the IEEE date convention ("D=FDIS-201008"); the
|
|
453
|
+
// ISO face is not elected (the reference's fdraft rule).
|
|
454
|
+
const fdraft = parsed["fdraft"];
|
|
455
|
+
if (fdraft !== undefined && typeof fdraft === "object" && !Array.isArray(fdraft)) {
|
|
456
|
+
const fdStage = extractValue(fdraft["fdraft_stage"]);
|
|
457
|
+
if (fdStage !== undefined) {
|
|
458
|
+
const fdYear = extractValue(fdraft["year"]);
|
|
459
|
+
const fdMonth = extractValue(fdraft["month"]);
|
|
460
|
+
let date = "";
|
|
461
|
+
if (fdYear !== undefined) {
|
|
462
|
+
date = `-${fdYear}`;
|
|
463
|
+
const monthNum = fdMonth !== undefined
|
|
464
|
+
? DRAFT_MONTH_NAMES[String(fdMonth).replace(/\.$/, "")]
|
|
465
|
+
: undefined;
|
|
466
|
+
if (monthNum !== undefined)
|
|
467
|
+
date += monthNum.padStart(2, "0");
|
|
468
|
+
}
|
|
469
|
+
attributes["publishers"] ??= [attributes["publisher"] ?? "IEEE"];
|
|
470
|
+
attributes["ieee_draft"] = `D=${fdStage}${date}`;
|
|
471
|
+
const fdRecord = locateStage(fdStage);
|
|
472
|
+
if (fdRecord !== undefined)
|
|
473
|
+
attributes["typed_stage"] = new IeeeTypedStage(fdRecord);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
441
476
|
this.applyDefaultDraftVersion(attributes, typeValue);
|
|
442
477
|
this.handleKeyedHash(parsed, "corrigendum", attributes, "cor_number", "cor_year");
|
|
443
478
|
this.handleKeyedHash(parsed, "amendment", attributes, "amd_number", "amd_year");
|
|
@@ -533,23 +568,39 @@ class IeeeBuilder {
|
|
|
533
568
|
if (draftData["draft_version"] !== undefined) {
|
|
534
569
|
const dv = draftData["draft_version"];
|
|
535
570
|
version = Array.isArray(dv) ? dv.map((v) => extractValue(v) ?? "").join("") : extractValue(dv);
|
|
571
|
+
// The reference's designator normalization (gem#552): a leading
|
|
572
|
+
// hyphen drops, and a three-digit-plus zero-padded designator
|
|
573
|
+
// sheds its zero ("/013.0" -> "13.0" — the 2026-10-19 ruling;
|
|
574
|
+
// the strip is scoped to the dotted designator class — "D043"/
|
|
575
|
+
// "D09"/"D0.16" keep their conventional widths).
|
|
536
576
|
if (version !== undefined)
|
|
537
|
-
version = version.replace(/^-/, "");
|
|
577
|
+
version = version.replace(/^-/, "").replace(/^0(?=\d+\.\d)/, "");
|
|
538
578
|
}
|
|
539
579
|
revision = extractValue(draftData["revision"]);
|
|
540
580
|
isoStage = extractValue(draftData["draft_iso_stage"]);
|
|
541
581
|
isoIteration = extractValue(draftData["draft_iso_iteration"]);
|
|
542
582
|
// FDIS/CDV/… are ISO/IEC stage tokens, not draft ordinals (C1
|
|
543
|
-
// ruling, testsuite#2). "/DDIS" and "/
|
|
583
|
+
// ruling, testsuite#2). "/DDIS" and "/DFCD" are hallucinated
|
|
544
584
|
// concatenations — the designator D does not merge onto a stage
|
|
545
585
|
// word. The draft of a stage rides the iso_stage slot, which
|
|
546
586
|
// Draft#to_s renders as the D= designator face ("…/D=DIS-2020").
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
version = undefined;
|
|
550
|
-
}
|
|
587
|
+
// The glued month-name date ("-June2010", the 2026-10-19 FCD
|
|
588
|
+
// ruling) rides the designator's date slot with the month numeric.
|
|
551
589
|
month = extractValue(draftData["month"]);
|
|
552
590
|
year = extractValue(draftData["year"]);
|
|
591
|
+
if (version !== undefined) {
|
|
592
|
+
// The stage iteration rides glued onto the word ("DIS2" — the
|
|
593
|
+
// lossless face, pubid#477; the 2026-10-19 DIS2 ruling).
|
|
594
|
+
const stageDate = /^(FDIS|FCD|CDV|DIS|CD|WD|PWI|NP)(\d+)?(?:-([A-Za-z]+)(\d{4}))?$/.exec(version);
|
|
595
|
+
if (stageDate !== null) {
|
|
596
|
+
isoStage = stageDate[1] + (stageDate[2] ?? "");
|
|
597
|
+
if (stageDate[3] !== undefined) {
|
|
598
|
+
month = DRAFT_MONTH_NAMES[stageDate[3]] !== undefined ? stageDate[3] : month;
|
|
599
|
+
year = stageDate[4];
|
|
600
|
+
}
|
|
601
|
+
version = undefined;
|
|
602
|
+
}
|
|
603
|
+
}
|
|
553
604
|
// The apostrophe-year catalogue convention ("P1484.20.1/D7,
|
|
554
605
|
// May 07"): the 2-digit year expands with the <30 pivot so the
|
|
555
606
|
// hash carries an unambiguous year (the reference's builder).
|
|
@@ -598,6 +649,42 @@ class IeeeBuilder {
|
|
|
598
649
|
attributes["draft"] = draftObj.render();
|
|
599
650
|
}
|
|
600
651
|
}
|
|
652
|
+
// A draft-date that routed to the identity slots (the grammar's
|
|
653
|
+
// month/year captures beside a bare draft ordinal) folds onto the
|
|
654
|
+
// draft designator: a REV-carrier embeds it numerically
|
|
655
|
+
// ("P1310Rev3/D2, February 2011" renders "D2-2011-02" — the
|
|
656
|
+
// reference's builder), a plain draft keeps the printed face routed
|
|
657
|
+
// through the draft's own parse so the month canonicalizes to the
|
|
658
|
+
// crawl abbreviation ("D08, September 2018" renders "D08, Sept,
|
|
659
|
+
// 2018"; a space-faced input stays space-faced).
|
|
660
|
+
foldDraftDateTail(attributes) {
|
|
661
|
+
const month = attributes["month"];
|
|
662
|
+
const year = attributes["year"];
|
|
663
|
+
const draft = attributes["draft"];
|
|
664
|
+
if (typeof month !== "string" || typeof year !== "string" ||
|
|
665
|
+
typeof draft !== "string" || !/^\/D[^ =,]+$/.test(draft)) {
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const draftNum = draft.slice(2);
|
|
669
|
+
if (attributes["revision"] !== undefined || attributes["rev_bare"] === true) {
|
|
670
|
+
const monthNum = DRAFT_MONTH_NAMES[String(month).replace(/\.$/, "")];
|
|
671
|
+
if (monthNum === undefined)
|
|
672
|
+
return;
|
|
673
|
+
attributes["draft"] =
|
|
674
|
+
new IeeeDraft({ version: `${draftNum}-${year}-${monthNum.padStart(2, "0")}` }).render();
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
const escaped = month.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
678
|
+
const commaFace = this.originalInput !== "" &&
|
|
679
|
+
new RegExp(`,\\s+${escaped}`, "i").test(this.originalInput);
|
|
680
|
+
const reparsed = IeeeDraft.parse(`${draftNum}${commaFace ? ", " : " "}${month} ${year}`);
|
|
681
|
+
if (reparsed === undefined)
|
|
682
|
+
return;
|
|
683
|
+
attributes["draft"] = reparsed.render();
|
|
684
|
+
}
|
|
685
|
+
delete attributes["month"];
|
|
686
|
+
delete attributes["year"];
|
|
687
|
+
}
|
|
601
688
|
applyDefaultDraftVersion(attributes, typeValue) {
|
|
602
689
|
if (attributes["draft"] !== undefined)
|
|
603
690
|
return;
|
|
@@ -885,6 +972,18 @@ class IeeeBuilder {
|
|
|
885
972
|
if (attributes["month"] === undefined)
|
|
886
973
|
attributes["month"] = extractValue(parsed["draft_month"]);
|
|
887
974
|
}
|
|
975
|
+
// A status word ("Unapproved") marks the draft (pubid#318).
|
|
976
|
+
const jointDraftStatus = extractValue(parsed["draft_status"]);
|
|
977
|
+
if (jointDraftStatus !== undefined)
|
|
978
|
+
attributes["draft_status"] = jointDraftStatus;
|
|
979
|
+
// A dash_year tail ("/D-3-2007") is the identity year when the
|
|
980
|
+
// slots are otherwise empty — the ISO face prints it colon-joined
|
|
981
|
+
// ("ISO/IEC/IEEE FDIS P15288:2007", the reference's 9258 flow).
|
|
982
|
+
if (attributes["year"] === undefined && parsed["dash_year"] !== undefined) {
|
|
983
|
+
const dashYear = (extractValue(parsed["dash_year"]) ?? "").replace(/^[-:]/, "");
|
|
984
|
+
if (/^\d{4}$/.test(dashYear))
|
|
985
|
+
attributes["year"] = dashYear;
|
|
986
|
+
}
|
|
888
987
|
// The IEEE-led tail word-stage ("IEEE/ISO/IEC P15026-3/CD,
|
|
889
988
|
// December 2021") composes the D= designator with the glued
|
|
890
989
|
// 6-digit date — the identity its D= twin spelling parses to (the
|
|
@@ -925,7 +1024,22 @@ class IeeeBuilder {
|
|
|
925
1024
|
}
|
|
926
1025
|
if (parsed["draft_version"] !== undefined) {
|
|
927
1026
|
const draftVer = (extractValue(parsed["draft_version"]) ?? "").replace(/^D/, "");
|
|
928
|
-
|
|
1027
|
+
// FCD is an ISO stage (the 2026-10-19 ruling): a glued month-name
|
|
1028
|
+
// date rides the designator's date slot with the month numeric —
|
|
1029
|
+
// the D= designator face, never the "DFCD" glue.
|
|
1030
|
+
const stageDate = /^(FDIS|FCD|CDV|DIS|CD|WD|PWI|NP)(\d+)?(?:-([A-Za-z]+)(\d{4}))?$/.exec(draftVer);
|
|
1031
|
+
if (stageDate !== null) {
|
|
1032
|
+
const monthNum = stageDate[3] !== undefined ? DRAFT_MONTH_NAMES[stageDate[3]] : undefined;
|
|
1033
|
+
const stageWord = stageDate[1] + (stageDate[2] ?? "");
|
|
1034
|
+
attributes["ieee_draft"] =
|
|
1035
|
+
stageDate[3] !== undefined && monthNum !== undefined
|
|
1036
|
+
? `D=${stageWord}-${stageDate[4]}${monthNum.padStart(2, "0")}`
|
|
1037
|
+
: `D=${stageWord}`;
|
|
1038
|
+
delete attributes["draft"];
|
|
1039
|
+
delete attributes["year"];
|
|
1040
|
+
delete attributes["month"];
|
|
1041
|
+
}
|
|
1042
|
+
else if (draftVer !== "") {
|
|
929
1043
|
// A date trailing the draft (", June 2010") belongs to the draft
|
|
930
1044
|
// component (canonical month, comma form); the identity
|
|
931
1045
|
// year/month the promotion filled from the same captures are
|
|
@@ -1115,11 +1229,45 @@ class IeeeBuilder {
|
|
|
1115
1229
|
}
|
|
1116
1230
|
return new StandardClass(printedAttrs);
|
|
1117
1231
|
}
|
|
1232
|
+
// A stage word with a glued year tail ("/D=CD2-201802") rides the
|
|
1233
|
+
// D= designator with the IEEE lead (the reference's builder, the
|
|
1234
|
+
// pubid#203 class) — the tail's capture carries its separator.
|
|
1235
|
+
if (parsed["iso_stage"] !== undefined && parsed["draft_stage_year"] !== undefined) {
|
|
1236
|
+
const stageWord = extractValue(parsed["iso_stage"]) ?? "";
|
|
1237
|
+
const pubs = (attributes["publishers"] ?? []);
|
|
1238
|
+
if (pubs.length === 0) {
|
|
1239
|
+
attributes["publishers"] = ["IEEE"];
|
|
1240
|
+
attributes["publisher"] = "IEEE";
|
|
1241
|
+
attributes["copublisher"] = [];
|
|
1242
|
+
}
|
|
1243
|
+
attributes["ieee_draft"] = `D=${stageWord}${extractValue(parsed["draft_stage_year"]) ?? ""}`;
|
|
1244
|
+
const stageRecord = locateStage(stageWord);
|
|
1245
|
+
if (stageRecord !== undefined) {
|
|
1246
|
+
attributes["typed_stage"] = new IeeeTypedStage(stageRecord);
|
|
1247
|
+
}
|
|
1248
|
+
attributes["lead_party"] = "IEEE";
|
|
1249
|
+
delete attributes["year"];
|
|
1250
|
+
delete attributes["month"];
|
|
1251
|
+
}
|
|
1118
1252
|
if (parsed["iso_stage"] !== undefined) {
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1253
|
+
// A bare-IEEE project carrying a stage never elects the ISO lead
|
|
1254
|
+
// (the reference's bare_ieee_project gate): the lead stays IEEE.
|
|
1255
|
+
const bareIeeeProject = parsed["project_marker"] !== undefined &&
|
|
1256
|
+
attributes["publisher"] === "IEEE" &&
|
|
1257
|
+
(attributes["copublisher"] ?? []).length === 0;
|
|
1258
|
+
if (!bareIeeeProject)
|
|
1259
|
+
attributes["lead_party"] = "ISO";
|
|
1260
|
+
let stageAbbr = extractValue(parsed["iso_stage"]);
|
|
1261
|
+
// The IEC "/V<version>" iteration rides glued onto the stage word
|
|
1262
|
+
// ("_CDV/V3" -> "CDV3") — the family's lossless spelling (the
|
|
1263
|
+
// reference's builder, pubid#477).
|
|
1264
|
+
const stageIteration = extractValue(parsed["iso_stage_iteration"]);
|
|
1265
|
+
if (stageAbbr !== undefined && stageIteration !== undefined) {
|
|
1266
|
+
stageAbbr += stageIteration;
|
|
1267
|
+
}
|
|
1268
|
+
if (!bareIeeeProject)
|
|
1269
|
+
attributes["iso_stage"] = stageAbbr;
|
|
1270
|
+
if (stageAbbr !== undefined && !bareIeeeProject) {
|
|
1123
1271
|
const record = locateStage(stageAbbr);
|
|
1124
1272
|
if (record !== undefined)
|
|
1125
1273
|
attributes["typed_stage"] = new IeeeTypedStage(record);
|
|
@@ -1185,6 +1333,18 @@ class IeeeBuilder {
|
|
|
1185
1333
|
}
|
|
1186
1334
|
return new ProjectDraftIdentifierClass(projectAttrs);
|
|
1187
1335
|
}
|
|
1336
|
+
// The iso_published joint rows normalize the publisher order to
|
|
1337
|
+
// ISO-first (the reference: "IEEE/ISO/IEC 8802-3:2021/Amd 4-2021"
|
|
1338
|
+
// builds the base [ISO, IEC, IEEE], lead ISO); the CD-stage rows and
|
|
1339
|
+
// the IEEE-led project rows preserve the printed order (P90003 stays
|
|
1340
|
+
// IEEE/ISO/IEC).
|
|
1341
|
+
if (parsed["iso_published"] !== undefined && parsed["iso_stage"] === undefined &&
|
|
1342
|
+
Array.isArray(attributes["publishers"])) {
|
|
1343
|
+
const pubs = attributes["publishers"];
|
|
1344
|
+
attributes["publishers"] = [...pubs.filter((p) => p !== "IEEE"), ...pubs.filter((p) => p === "IEEE")];
|
|
1345
|
+
attributes["publisher"] = attributes["publishers"][0];
|
|
1346
|
+
attributes["copublisher"] = attributes["publishers"].slice(1);
|
|
1347
|
+
}
|
|
1188
1348
|
const joint = new JointDevelopmentClass(attributes);
|
|
1189
1349
|
if (parsed["amd_number"] === undefined)
|
|
1190
1350
|
return joint;
|
|
@@ -1114,8 +1114,9 @@ export const JointDevelopmentClass = ieeeClass({ kind: "joint-development" }, {
|
|
|
1114
1114
|
iso_stage: { type: "string" },
|
|
1115
1115
|
ieee_draft: { type: "string" },
|
|
1116
1116
|
parenthetical_content: { type: "string" },
|
|
1117
|
+
draft_status: { type: "string" },
|
|
1117
1118
|
},
|
|
1118
|
-
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" }),
|
|
1119
|
+
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" }, { wire: "draft_status", to: "draft_status" }),
|
|
1119
1120
|
wireDelete: { keys: ["publisher", "copublisher"] },
|
|
1120
1121
|
render: (id) => {
|
|
1121
1122
|
const publishers = id["publishers"];
|
|
@@ -1194,6 +1195,11 @@ export const JointDevelopmentClass = ieeeClass({ kind: "joint-development" }, {
|
|
|
1194
1195
|
const parts = [];
|
|
1195
1196
|
if (publishers !== undefined && publishers.length > 0)
|
|
1196
1197
|
parts.push(publishers.join("/"));
|
|
1198
|
+
// A status word ("Unapproved") marks the draft (pubid#318) — it
|
|
1199
|
+
// prints after the publishers on the joint IEEE face.
|
|
1200
|
+
const draftStatus = id["draft_status"];
|
|
1201
|
+
if (draftStatus !== undefined)
|
|
1202
|
+
parts.push(draftStatus);
|
|
1197
1203
|
// The P-state prints as spelled (P = project draft; no P =
|
|
1198
1204
|
// standard). Never added or stripped.
|
|
1199
1205
|
let codeStr = codeObj?.render() ?? "";
|
|
@@ -226,14 +226,11 @@ function normalizeRelatonSuffixes(input) {
|
|
|
226
226
|
cleaned = `${m[1]}${date}${draftPart}/R-${m[3]}`;
|
|
227
227
|
}
|
|
228
228
|
}
|
|
229
|
-
// /D-N
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
cleaned = `${m[1]}-${m[3]}${m[4] !== undefined ? `-${m[4]}` : ""}/D${m[2]}`;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
229
|
+
// The "/D-N-YYYY" draft-dash-date spelling is NOT repositioned: the
|
|
230
|
+
// artifact grammar reads it natively (draft + printed_dash_year) and
|
|
231
|
+
// the joint route renders the reference's dash-year face. The former
|
|
232
|
+
// reposition onto the number predated the artifact and broke the
|
|
233
|
+
// joint classification (the year left the designator's slot).
|
|
237
234
|
// /E-N editions: "/E-2-2023-02" → "Edition 2.0 2023-02".
|
|
238
235
|
{
|
|
239
236
|
const re = /^(.*?)\/E-(\d+)(?:-((?:19|20)\d\d)(?:-(0[1-9]|1[0-2]))?)?$/;
|
|
@@ -255,10 +252,14 @@ function normalizeRelatonSuffixes(input) {
|
|
|
255
252
|
}
|
|
256
253
|
function normalizeRevisionNotation(input) {
|
|
257
254
|
let cleaned = input;
|
|
258
|
-
//
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
255
|
+
// The reference's two glue-normalizing gsubs (parser.rb): a "REV.x"/
|
|
256
|
+
// "REV-x" after-word separator and a digit-glued "2rev1" normalize to
|
|
257
|
+
// a spaced boundary; the render keeps the glued face. The former
|
|
258
|
+
// /R-<n> reposition rules predate the artifact grammar and diverged
|
|
259
|
+
// from the reference (they ate "-rev1" spellings the artifact
|
|
260
|
+
// captures natively, which cost the glued-date rows their parse).
|
|
261
|
+
cleaned = cleaned.replace(/(REV|Rev|rev)[.\-](?=[A-Za-z])/g, "$1");
|
|
262
|
+
cleaned = cleaned.replace(/(\d)(REV|Rev|rev)/g, "$1 $2");
|
|
262
263
|
// The joint IEEE/CSA catalogue spells the type word before the
|
|
263
264
|
// project number ("IEEE/CSA Draft P844.1/D2, Sept, 2016"): the P
|
|
264
265
|
// already carries the project semantics (docs/IEEE-DRAFT-STAGES.md
|
|
@@ -322,6 +323,12 @@ function normalizeJointStageSpellings(input) {
|
|
|
322
323
|
// dash-date, and rewriting it onto the number breaks the parse.
|
|
323
324
|
cleaned = cleaned.replace(new RegExp(`^${pubs}${num}/ ?${stage}(-(?:19|20)\\d\\d(?:-\\d\\d)?)`), "$1$3 $2$4");
|
|
324
325
|
cleaned = cleaned.replace(new RegExp(`^${pubs}${stage} ${num}/? ?(D\\d+)\\b`), "$1$2 $3/$4");
|
|
326
|
+
// The dash-stage-with-part spelling ("ISO/IEC/IEEE P15288-DIS-1403",
|
|
327
|
+
// "… P12207-FDIS-1707, June 2017"): the stage glues between the number
|
|
328
|
+
// and the part. The reference renders the stage-first dot face
|
|
329
|
+
// ("DIS P15288.1403") — re-spell so the stage-first route parses it
|
|
330
|
+
// (a stage WITHOUT a trailing part, "P29119-2-DIS", routes elsewhere).
|
|
331
|
+
cleaned = cleaned.replace(new RegExp(`^${pubs}P?(\\d+)-(FDIS|DIS|CDV|CD|WD)(\\d*)-(\\d+(?:\\.\\d+)*)((?:, [A-Za-z]+ \\d{4})?)$`), "$1$3$4 P$2.$5$6");
|
|
325
332
|
return cleaned;
|
|
326
333
|
}
|
|
327
334
|
// The Parser.parse cleaning pipeline, in Ruby order.
|
|
@@ -341,11 +348,19 @@ export function preprocessIeee(input) {
|
|
|
341
348
|
cleaned = cleaned.replaceAll("’", "'");
|
|
342
349
|
cleaned = cleaned.replaceAll("&amp;", "&");
|
|
343
350
|
cleaned = cleaned.replaceAll("&", "&");
|
|
344
|
-
|
|
351
|
+
// The "P&V" print tail is NOT parenthesized: the artifact captures it
|
|
352
|
+
// and the builder discards it (the reference renders "ANSI/IEEE
|
|
353
|
+
// 500-1984" bare) — the former wrap made the parenthetical print.
|
|
345
354
|
cleaned = cleaned.replace(/(\d+\.\d+)\s+(\d+\.)/g, "$1$2");
|
|
346
355
|
cleaned = cleaned.replace(/\b(1|2)\s+(\d{3})\b/g, "$1$2");
|
|
347
|
-
|
|
348
|
-
|
|
356
|
+
// The month-year glue split ("June2010" -> "June 2010") is NOT the
|
|
357
|
+
// reference's behavior — the reference keeps the glue (the FCD ruling:
|
|
358
|
+
// "FCD-June2010" is the stage + the glued month-name date), and the
|
|
359
|
+
// split cost the FCD rows their classification.
|
|
360
|
+
// The 8802-family IEEE-led joint prefix reorders to the ISO/IEC/IEEE
|
|
361
|
+
// label (the reference's Fix 2AA): "IEEE/ISO/IEC 8802-1Q-2020" parses
|
|
362
|
+
// under the ISO/IEC label and the amendment route renders ISO-first.
|
|
363
|
+
cleaned = cleaned.replace(/^IEEE\/ISO\/IEC\s+(8802[\w.-]+)/, "ISO/IEC/IEEE $1");
|
|
349
364
|
cleaned = normalizeJointStageSpellings(cleaned);
|
|
350
365
|
cleaned = cleaned.replace(/(IEC\s+\d+(?:-\d+)?(?::\d{4})?(?:\s+(?:First\s+)?[Ee]dition\s+\d+(?:\.\d+)?\s+\d{4}-\d{2})?)\s+(IEEE\s+Std\s+\S+|IEEE\s+\S+)/g, "$1; $2");
|
|
351
366
|
cleaned = cleaned.replace(/^(IEC\s+\d+(?:-\d+)?):\d{4}(\s+(?:First\s+)?[Ee]dition\s+\d+(?:\.\d+)?\s+\d{4}-\d{2})/, "$1$2");
|
|
@@ -99,14 +99,12 @@ export const UPDATE_CODES = [
|
|
|
99
99
|
{ plain: "ISO/IEC/IEEE CD P26513/D1, August 2015", replacement: "ISO/IEC/IEEE P26513/D1, August 2015" },
|
|
100
100
|
{ plain: "IEEE Std P1073.1.3.4/D3.0", replacement: "IEEE Std P11073.00101" },
|
|
101
101
|
{ plain: "IEEE P802.1Qbu/03.0, July 2015", replacement: "IEEE P802.1Qbu/D-3.0-2015" },
|
|
102
|
-
{ plain: "IEEE P802.11aqTM/013.0 October 2017", replacement: "IEEE P802.11aqTM/D-13.0-2017" },
|
|
103
102
|
{ plain: "IEC/IEEE P62271-37-013:2015 D13.4", replacement: "IEC/IEEE P62271.37-013/D-13.4-2015" },
|
|
104
103
|
{ plain: "ISO/IEC/IEEE DIS P42020:201x(E), June 2017", replacement: "ISO/IEC/IEEE DIS P42020-2017-06" },
|
|
105
104
|
{ plain: "ISO/IEC/IEEE DIS P16326/201x, December 2018", replacement: "ISO/IEC/IEEE DIS P16326-2018-12" },
|
|
106
105
|
{ plain: "ISO/IEC/IEEE/P21839, 2019(E)", replacement: "ISO/IEC/IEEE P21839-2019" },
|
|
107
106
|
{ plain: "ISO/IEC/IEEE CD2 P12207-2: 201x(E), February 2019", replacement: "ISO/IEC/IEEE CD2 P12207.2-2019-02" },
|
|
108
107
|
{ plain: "ISO/IEC/IEEE P42010.WD4:2019(E)", replacement: "ISO/IEC/IEEE P42010/D-4-2019" },
|
|
109
|
-
{ plain: "IEC/IEEE P63195_CDV/V3, February 2020", replacement: "IEC/IEEE CDV P63195-2020-02" },
|
|
110
108
|
{ plain: "ISO/IEC/IEEE/P16085_DIS, March 2020", replacement: "ISO/IEC/IEEE DIS P16085-2020-03" },
|
|
111
109
|
{ plain: "ANSI/IEEE Std: Outdoor Apparatus Bushings", replacement: "ANSI/IEEE Std 21-1976-11" },
|
|
112
110
|
{ plain: "Draft National Electrical Safety Code, January 2016", replacement: "IEEE PC2-2016-01" },
|
|
@@ -185,6 +185,7 @@ const yearMapping = () => ({
|
|
|
185
185
|
: new PubidDate({
|
|
186
186
|
year: String(h["year"]),
|
|
187
187
|
month: h["month"] === undefined || h["month"] === null ? undefined : String(h["month"]),
|
|
188
|
+
day: h["day"] === undefined || h["day"] === null ? undefined : String(h["day"]),
|
|
188
189
|
}),
|
|
189
190
|
});
|
|
190
191
|
const monthMapping = () => ({
|
|
@@ -193,13 +194,21 @@ const monthMapping = () => ({
|
|
|
193
194
|
toWire: (m) => m["date"]?.month,
|
|
194
195
|
fromWire: () => undefined,
|
|
195
196
|
});
|
|
197
|
+
// An Operational Bulletin's printed day ("15.III.2016") serializes flat,
|
|
198
|
+
// mirroring the reference's hash ("year"/"month"/"day" siblings).
|
|
199
|
+
const dayMapping = () => ({
|
|
200
|
+
wire: "day",
|
|
201
|
+
to: "date",
|
|
202
|
+
toWire: (m) => m["date"]?.day,
|
|
203
|
+
fromWire: () => undefined,
|
|
204
|
+
});
|
|
196
205
|
/** StandardSerialization — the single-document whitelist. */
|
|
197
206
|
const STANDARD_MAPPINGS = keyValue({ wire: "sector", to: "sector" }, { wire: "series", to: "series" }, codeKey("imp_marker", (c) => c.imp_marker), {
|
|
198
207
|
wire: "number",
|
|
199
208
|
to: "code",
|
|
200
209
|
toWire: (m) => codeOf(m)?.number,
|
|
201
210
|
fromWire: (h) => ituCodeFromHash(h),
|
|
202
|
-
}, codeKey("series_suffix", (c) => c.series_suffix), codeKey("series_suffix_spaced", (c) => (c.series_suffix_spaced ? true : undefined)), codeKey("subseries", (c) => c.subseries), codeKey("parts", (c) => (c.parts.length > 0 ? c.parts : undefined)), codeKey("qualifier", (c) => c.qualifier), codeKey("qualifier_glued", (c) => (c.qualifier_glued ? true : undefined)), { wire: "series_word", to: "series_word" }, { wire: "series_dash", to: "series_dash" }, { wire: "attachment", to: "attachment" }, { wire: "range_end", to: "range_end" }, { wire: "version", to: "version" }, yearMapping(), monthMapping(), { wire: "language", to: "language" }, { wire: "common_text_twin", to: "common_text_twin" });
|
|
211
|
+
}, codeKey("series_suffix", (c) => c.series_suffix), codeKey("series_suffix_spaced", (c) => (c.series_suffix_spaced ? true : undefined)), codeKey("subseries", (c) => c.subseries), codeKey("parts", (c) => (c.parts.length > 0 ? c.parts : undefined)), codeKey("qualifier", (c) => c.qualifier), codeKey("qualifier_glued", (c) => (c.qualifier_glued ? true : undefined)), { wire: "series_word", to: "series_word" }, { wire: "series_dash", to: "series_dash" }, { wire: "attachment", to: "attachment" }, { wire: "range_end", to: "range_end" }, { wire: "version", to: "version" }, yearMapping(), monthMapping(), dayMapping(), { wire: "language", to: "language" }, { wire: "common_text_twin", to: "common_text_twin" });
|
|
203
212
|
/**
|
|
204
213
|
* The Supplement block: sector/series/series_word are emitted ONLY for
|
|
205
214
|
* the base-less series-only form; with a base they are redundant
|
|
@@ -373,9 +373,10 @@ function cast(type, value, h, policy, series = "") {
|
|
|
373
373
|
return undefined;
|
|
374
374
|
const stripped = v.trim();
|
|
375
375
|
const code = TRANSLATION_MAP[stripped.toLowerCase()] ?? stripped.toLowerCase();
|
|
376
|
-
// The gem's
|
|
377
|
-
// the
|
|
378
|
-
|
|
376
|
+
// The gem's Translation#to_s (short) renders the parenthesised
|
|
377
|
+
// suffix — the 1.x corpus shape ("(spa)", pubid#497); the wire
|
|
378
|
+
// serializes that form.
|
|
379
|
+
return { translation_component: new NistTranslation({ code }), translation: `(${code})` };
|
|
379
380
|
}
|
|
380
381
|
case "version": {
|
|
381
382
|
const v = s(value);
|
|
@@ -157,8 +157,10 @@ export class NistTranslation {
|
|
|
157
157
|
toWire() {
|
|
158
158
|
return { code: this.code };
|
|
159
159
|
}
|
|
160
|
+
// The 1.x corpus shape: the trailing parenthesised suffix "(spa)"
|
|
161
|
+
// (pubid#497); the mr face keeps the dotted form (".spa").
|
|
160
162
|
render(format = "short") {
|
|
161
|
-
return format === "mr" ? `.${this.code}` : `
|
|
163
|
+
return format === "mr" ? `.${this.code}` : `(${this.code})`;
|
|
162
164
|
}
|
|
163
165
|
}
|
|
164
166
|
export class NistStage {
|
|
@@ -467,7 +469,7 @@ export class NistIdentifier extends BaseIdentifier {
|
|
|
467
469
|
if (this.errata !== undefined)
|
|
468
470
|
result += this.errata;
|
|
469
471
|
if (this.index !== undefined)
|
|
470
|
-
result += "
|
|
472
|
+
result += "indx";
|
|
471
473
|
if (this.insert !== undefined)
|
|
472
474
|
result += "insert";
|
|
473
475
|
if (this.section !== undefined)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubid/pubid",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.14",
|
|
4
4
|
"description": "TypeScript PubID identifiers: resolution, normalization and canonical hashes for every identifier in the pubid-testsuite corpus (41 standards bodies), with a conformance runner mirroring the Ruby reference",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|