@pubid/pubid 0.1.8 → 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/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 +7 -0
- 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
|
@@ -117,7 +117,16 @@ export class IeeeCode {
|
|
|
117
117
|
return result;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
-
|
|
120
|
+
// Canonical month spelling (mirrors the gem's CANONICAL_ABBREVIATIONS):
|
|
121
|
+
// full names normalize onto the crawl abbreviation, and "September"
|
|
122
|
+
// keeps its IEEE "Sept" form — the 3-letter "Sep" folds onto it, so
|
|
123
|
+
// every spelling of September renders and hashes alike.
|
|
124
|
+
const DRAFT_MONTH_CANONICAL = {
|
|
125
|
+
January: "Jan", February: "Feb", March: "Mar", April: "Apr",
|
|
126
|
+
June: "Jun", July: "Jul", August: "Aug", September: "Sept",
|
|
127
|
+
October: "Oct", November: "Nov", December: "Dec", Sep: "Sept",
|
|
128
|
+
};
|
|
129
|
+
export const DRAFT_MONTH_NAMES = {
|
|
121
130
|
January: "1", February: "2", March: "3", April: "4", May: "5", June: "6",
|
|
122
131
|
July: "7", August: "8", September: "9", October: "10", November: "11",
|
|
123
132
|
December: "12", Jan: "1", Feb: "2", Mar: "3", Apr: "4", Jun: "6",
|
|
@@ -139,12 +148,27 @@ export class IeeeDraft {
|
|
|
139
148
|
this.commaBeforeMonthSet = "comma_before_month" in attrs;
|
|
140
149
|
this.version = String(attrs["version"] ?? "");
|
|
141
150
|
this.revision = attrs["revision"];
|
|
142
|
-
this.isoStage = attrs["iso_stage"];
|
|
143
151
|
this.isoIteration = attrs["iso_iteration"];
|
|
152
|
+
// The grammar's ordered alternation captures the stage WITH its
|
|
153
|
+
// draft-marker D when the spelling doubles it ("=DDIS"): the marker
|
|
154
|
+
// is notation, the stage is the bare ISO/IEC token (the reference's
|
|
155
|
+
// Draft constructor strips it).
|
|
156
|
+
let stage = attrs["iso_stage"];
|
|
157
|
+
if (stage !== undefined && stage.startsWith("D") &&
|
|
158
|
+
["PWI", "NP", "WD", "CD", "CDV", "DIS", "FDIS"].includes(stage.slice(1))) {
|
|
159
|
+
stage = stage.slice(1);
|
|
160
|
+
}
|
|
161
|
+
this.isoStage = stage;
|
|
144
162
|
this.year = attrs["year"];
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
163
|
+
// Canonical month spelling: the crawl abbreviation ("September" →
|
|
164
|
+
// "Sept"); the 3-letter "Sep" folds onto the IEEE "Sept" form, so
|
|
165
|
+
// every spelling of September renders — and hashes — alike.
|
|
166
|
+
const rawMonth = attrs["month"];
|
|
167
|
+
this.originalMonth = rawMonth !== undefined
|
|
168
|
+
? DRAFT_MONTH_CANONICAL[rawMonth.replace(/\.$/, "")] ?? rawMonth
|
|
169
|
+
: undefined;
|
|
170
|
+
this.month = rawMonth !== undefined
|
|
171
|
+
? DRAFT_MONTH_NAMES[String(this.originalMonth)] ?? String(this.originalMonth)
|
|
148
172
|
: undefined;
|
|
149
173
|
this.day = attrs["day"];
|
|
150
174
|
this.commaBeforeMonth = attrs["comma_before_month"] === true;
|
|
@@ -363,10 +387,17 @@ export class IeeeIdentifier extends BaseIdentifier {
|
|
|
363
387
|
draft_status: { type: "string" },
|
|
364
388
|
draft: { type: "string" },
|
|
365
389
|
revision: { type: "string" },
|
|
390
|
+
rev_sep: { type: "string" },
|
|
391
|
+
rev_bare: { type: "boolean" },
|
|
366
392
|
edition: { type: "string" },
|
|
367
393
|
month: { type: "string" },
|
|
368
394
|
day: { type: "string" },
|
|
369
395
|
redline: { type: "boolean", default: false },
|
|
396
|
+
// Provenance (gem#520): the month arrived glued to the identity year
|
|
397
|
+
// on the code ("ANSI/IEEE 21-1976-11") rather than as a trailing
|
|
398
|
+
// print date. The render keys on the month being numeric; this
|
|
399
|
+
// records how it arrived.
|
|
400
|
+
month_glued: { type: "boolean", default: false },
|
|
370
401
|
edition_month: { type: "string" },
|
|
371
402
|
space_before_draft: { type: "boolean", default: false },
|
|
372
403
|
typed_stage: { type: IeeeTypedStage },
|
|
@@ -384,7 +415,7 @@ export class IeeeIdentifier extends BaseIdentifier {
|
|
|
384
415
|
interpretation: { type: "boolean", default: false },
|
|
385
416
|
relationships: { type: "string", collection: true },
|
|
386
417
|
});
|
|
387
|
-
static mappings = keyValue({ wire: "publisher", to: "publisher" }, { wire: "copublisher", to: "copublisher" }, { wire: "year", to: "year" }, { wire: "type", to: "type" }, { wire: "draft_status", to: "draft_status" }, draftWire, { wire: "revision", to: "revision" }, { wire: "edition", to: "edition" }, { wire: "month", to: "month" }, { wire: "day", to: "day" }, { wire: "redline", to: "redline" }, { wire: "edition_month", to: "edition_month" }, { wire: "space_before_draft", to: "space_before_draft" }, typedStageWire, { wire: "parenthetical_content", to: "parenthetical_content" }, { wire: "nickname", to: "nickname" }, { wire: "adoption", to: "adoption" }, { wire: "amendment_to", to: "amendment_to" }, { wire: "note", to: "note" }, { wire: "iso_identifier", to: "iso_identifier" }, { wire: "revision_of", to: "revision_of" }, { wire: "ashrae_number", to: "ashrae_number" }, { wire: "ashrae_year", to: "ashrae_year" }, { wire: "crossref", to: "crossref" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "interpretation", to: "interpretation" }, {
|
|
418
|
+
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: "rev_sep", to: "rev_sep" }, { wire: "rev_bare", to: "rev_bare" }, { wire: "edition", to: "edition" }, { wire: "month", to: "month" }, { wire: "day", to: "day" }, { wire: "redline", to: "redline" }, { wire: "month_glued", to: "month_glued" }, { wire: "edition_month", to: "edition_month" }, { wire: "space_before_draft", to: "space_before_draft" }, typedStageWire, { wire: "parenthetical_content", to: "parenthetical_content" }, { wire: "nickname", to: "nickname" }, { wire: "adoption", to: "adoption" }, { wire: "amendment_to", to: "amendment_to" }, { wire: "note", to: "note" }, { wire: "iso_identifier", to: "iso_identifier" }, { wire: "revision_of", to: "revision_of" }, { wire: "ashrae_number", to: "ashrae_number" }, { wire: "ashrae_year", to: "ashrae_year" }, { wire: "crossref", to: "crossref" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "interpretation", to: "interpretation" }, {
|
|
388
419
|
wire: "relationships",
|
|
389
420
|
to: "relationships",
|
|
390
421
|
toWire: (model) => {
|
|
@@ -446,6 +477,12 @@ export function renderIeeeBase(id) {
|
|
|
446
477
|
let typeStr = id.type;
|
|
447
478
|
if (typeStr.startsWith("P"))
|
|
448
479
|
typeStr = typeStr.slice(1);
|
|
480
|
+
// A draft carries the word Draft alone in every face (the C2
|
|
481
|
+
// ruling): Std/Standard never renders on a draft - a status-less
|
|
482
|
+
// draft ("IEEE Draft Std P802.3/D2.0") renders "IEEE Draft
|
|
483
|
+
// P802.3/D2.0".
|
|
484
|
+
if (id.draft !== undefined && id.draft_status === undefined)
|
|
485
|
+
typeStr = "Draft";
|
|
449
486
|
if (typeStr.trim() !== "")
|
|
450
487
|
parts.push(typeStr);
|
|
451
488
|
}
|
|
@@ -455,6 +492,8 @@ export function renderIeeeBase(id) {
|
|
|
455
492
|
// dates (catalogue metadata, not identity); wider sets and
|
|
456
493
|
// space-separated dates print as spelled.
|
|
457
494
|
const iecIeeOnly = id.publisher === "IEC" && JSON.stringify(id.copublisher) === '["IEEE"]';
|
|
495
|
+
// Short format = numeric month (glued face); the comma face is a month name.
|
|
496
|
+
const gluedMonth = /^\d{1,2}$/.test(id.month ?? "");
|
|
458
497
|
if (codeObj !== undefined) {
|
|
459
498
|
let result = codeObj.render();
|
|
460
499
|
// Prepend P if this is a project AND code doesn't already have P.
|
|
@@ -467,11 +506,29 @@ export function renderIeeeBase(id) {
|
|
|
467
506
|
!result.startsWith("P")) {
|
|
468
507
|
result = `P${result}`;
|
|
469
508
|
}
|
|
470
|
-
|
|
509
|
+
// A base year dash-attaches to the code when nothing else carries
|
|
510
|
+
// it: no edition, no identity-month date - and either no draft at
|
|
511
|
+
// all, or a draft that carries its OWN date (the draft+corrigendum
|
|
512
|
+
// family: "PC37.09-1999/D7.2, Nov 2006").
|
|
513
|
+
// A numeric identity month is the SHORT format: the year stays on
|
|
514
|
+
// the code and the month dash-joins after it, whatever the input
|
|
515
|
+
// spelling ("IEEE P15026.1, 05 2014" renders "P15026.1-2014-05").
|
|
516
|
+
const yearOnCode = id.year !== undefined && id.edition === undefined &&
|
|
517
|
+
(id.month === undefined || gluedMonth) &&
|
|
518
|
+
(draftObj === undefined || draftObj.year !== undefined);
|
|
519
|
+
if (yearOnCode) {
|
|
471
520
|
result += `-${id.year}`;
|
|
472
521
|
}
|
|
522
|
+
if (gluedMonth && id.month !== undefined) {
|
|
523
|
+
result += `-${id.month}`;
|
|
524
|
+
}
|
|
525
|
+
// The lettered revision keeps its printed separator ("P802.11-REVmc"
|
|
526
|
+
// renders "P802.11-Revmc"); the bare word with no id still prints
|
|
527
|
+
// "Rev" (pubid ruling 2026-10-14).
|
|
473
528
|
if (id.revision !== undefined)
|
|
474
|
-
result +=
|
|
529
|
+
result += `${id.rev_sep ?? ""}Rev${id.revision}`;
|
|
530
|
+
if (id.rev_bare === true)
|
|
531
|
+
result += `${id.rev_sep ?? ""}Rev`;
|
|
475
532
|
if (draftObj !== undefined) {
|
|
476
533
|
let printed = draftObj.render();
|
|
477
534
|
// The draft designator carries its date on every lead
|
|
@@ -510,13 +567,21 @@ export function renderIeeeBase(id) {
|
|
|
510
567
|
parts.push(editionStr);
|
|
511
568
|
}
|
|
512
569
|
let result = parts.join(" ");
|
|
513
|
-
if (id.month !== undefined && !iecIeeOnly) {
|
|
570
|
+
if (id.month !== undefined && !gluedMonth && !iecIeeOnly) {
|
|
514
571
|
result += `, ${id.month}`;
|
|
515
572
|
if (id.day !== undefined)
|
|
516
573
|
result += ` ${id.day}`;
|
|
517
574
|
if (id.year !== undefined && id.edition === undefined)
|
|
518
575
|
result += ` ${id.year}`;
|
|
519
576
|
}
|
|
577
|
+
else if (id.year !== undefined && draftObj !== undefined && id.edition === undefined &&
|
|
578
|
+
draftObj?.year === undefined && !iecIeeOnly) {
|
|
579
|
+
// A year-only date trailing the draft ("ANSI N42.34/D9a, 2015")
|
|
580
|
+
// keeps its comma form instead of being silently dropped; a year
|
|
581
|
+
// whose draft carries its own date dash-attached to the code above
|
|
582
|
+
// and never repeats.
|
|
583
|
+
result += `, ${id.year}`;
|
|
584
|
+
}
|
|
520
585
|
const parentheticals = [];
|
|
521
586
|
if (id.reaffirmed !== undefined && id.reaffirmed.trim() !== "") {
|
|
522
587
|
parentheticals.push(`(R${id.reaffirmed})`);
|
|
@@ -559,6 +624,13 @@ class IeeeUrnGenerator extends BaseUrnGenerator {
|
|
|
559
624
|
push("redline");
|
|
560
625
|
if (special === undefined && id.interpretation === true)
|
|
561
626
|
push("int");
|
|
627
|
+
// A NESC preprint is a draft-stage document distinct from the
|
|
628
|
+
// published edition it precedes — without this component it would
|
|
629
|
+
// share the edition's URN (urn:ieee:ieee:C2:2012).
|
|
630
|
+
if (id.constructor.polymorphicName ===
|
|
631
|
+
"pubid:ieee:nesc-preprint") {
|
|
632
|
+
push("preprint");
|
|
633
|
+
}
|
|
562
634
|
if (id.ashrae_number !== undefined) {
|
|
563
635
|
let ashrae = `ashrae.${id.ashrae_number}`;
|
|
564
636
|
if (id.ashrae_year !== undefined)
|
|
@@ -836,8 +908,14 @@ export const SiStandardClass = ieeeClass({ kind: "si-standard" }, {
|
|
|
836
908
|
result += ` ${part}`;
|
|
837
909
|
}
|
|
838
910
|
}
|
|
839
|
-
if (id.month !== undefined && id.year !== undefined)
|
|
840
|
-
|
|
911
|
+
if (id.month !== undefined && id.year !== undefined) {
|
|
912
|
+
// Short format (numeric month) renders glued; the comma marks a
|
|
913
|
+
// month name (the long format).
|
|
914
|
+
if (/^\d{1,2}$/.test(id.month))
|
|
915
|
+
result += `-${id.year}-${id.month}`;
|
|
916
|
+
else
|
|
917
|
+
result += `, ${id.month} ${id.year}`;
|
|
918
|
+
}
|
|
841
919
|
else if (id.year !== undefined)
|
|
842
920
|
result += `-${id.year}`;
|
|
843
921
|
return result;
|
|
@@ -1030,16 +1108,28 @@ export const JointDevelopmentClass = ieeeClass({ kind: "joint-development" }, {
|
|
|
1030
1108
|
// P-state is identity-bearing and prints as spelled - it is never
|
|
1031
1109
|
// added or stripped here.
|
|
1032
1110
|
if (leadParty === "ISO") {
|
|
1111
|
+
// A D= designator row ("P26511/D8=DDIS.3") prints the designator
|
|
1112
|
+
// after the code, not the stage as a word; only genuine stage
|
|
1113
|
+
// rows print the stage position.
|
|
1114
|
+
const designatorDraft = id["ieee_draft"];
|
|
1115
|
+
const printsDesignator = designatorDraft !== undefined && /^D\d*=/.test(designatorDraft);
|
|
1033
1116
|
const parts = [];
|
|
1034
1117
|
if (publishers !== undefined && publishers.length > 0)
|
|
1035
1118
|
parts.push(publishers.join("/"));
|
|
1036
|
-
if (
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1119
|
+
if (!printsDesignator) {
|
|
1120
|
+
if (id.typed_stage !== undefined) {
|
|
1121
|
+
parts.push(id.typed_stage.record.iso_stage_equivalent ?? id.typed_stage.render());
|
|
1122
|
+
}
|
|
1123
|
+
else if (isoStage !== undefined) {
|
|
1124
|
+
parts.push(isoStage);
|
|
1125
|
+
}
|
|
1041
1126
|
}
|
|
1042
|
-
|
|
1127
|
+
let codeStr = codeObj?.render() ?? "";
|
|
1128
|
+
// A P-prefixed joint project prints its parts dot-joined on the
|
|
1129
|
+
// ISO face ("ISO/IEEE DIS P15500.1"), whatever separator the
|
|
1130
|
+
// parse captured ("IEC/IEEE FDIS P60214-2-2018(E)" aliases in).
|
|
1131
|
+
if (codeStr.startsWith("P"))
|
|
1132
|
+
codeStr = codeStr.replaceAll("-", ".");
|
|
1043
1133
|
if (codeStr !== "")
|
|
1044
1134
|
parts.push(codeStr);
|
|
1045
1135
|
let result = parts.join(" ");
|
|
@@ -1049,12 +1139,16 @@ export const JointDevelopmentClass = ieeeClass({ kind: "joint-development" }, {
|
|
|
1049
1139
|
// the ISO-led print; only the bare language/edition marker ("(E)")
|
|
1050
1140
|
// prints - a relationship narrative is metadata, not identity.
|
|
1051
1141
|
const jointDraft = id["ieee_draft"];
|
|
1052
|
-
if (jointDraft !== undefined && jointDraft
|
|
1142
|
+
if (jointDraft !== undefined && /^D\d*=/.test(jointDraft))
|
|
1053
1143
|
result += `/${jointDraft}`;
|
|
1054
1144
|
const marker = id["parenthetical_content"];
|
|
1055
1145
|
if (marker !== undefined && /^[A-Z](?:\s*[/&]\s*[A-Z])*$/.test(marker)) {
|
|
1056
1146
|
result += ` (${marker})`;
|
|
1057
1147
|
}
|
|
1148
|
+
// The joint ISO-print redline is a distinct document (pubid#215):
|
|
1149
|
+
// "15289:2015(E) - Redline".
|
|
1150
|
+
if (id.redline === true)
|
|
1151
|
+
result += " - Redline";
|
|
1058
1152
|
return result;
|
|
1059
1153
|
}
|
|
1060
1154
|
// IEEE format
|
|
@@ -1074,6 +1168,8 @@ export const JointDevelopmentClass = ieeeClass({ kind: "joint-development" }, {
|
|
|
1074
1168
|
let result = parts.join(" ");
|
|
1075
1169
|
if (id.year !== undefined)
|
|
1076
1170
|
result += `-${id.year}`;
|
|
1171
|
+
if (id.redline === true)
|
|
1172
|
+
result += " - Redline";
|
|
1077
1173
|
return result;
|
|
1078
1174
|
},
|
|
1079
1175
|
});
|
|
@@ -1215,11 +1311,25 @@ export const NescDraftClass = ieeeClass({ kind: "nesc-draft" }, {
|
|
|
1215
1311
|
extraMappings: NescMappings,
|
|
1216
1312
|
render: (id) => {
|
|
1217
1313
|
const parts = ["Draft National Electrical Safety Code"];
|
|
1218
|
-
if (id.month !== undefined && id.year !== undefined)
|
|
1219
|
-
|
|
1314
|
+
if (id.month !== undefined && id.year !== undefined) {
|
|
1315
|
+
if (/^\d{1,2}$/.test(id.month))
|
|
1316
|
+
parts.push(` ${id.number}-${id.year}-${id.month}`);
|
|
1317
|
+
else
|
|
1318
|
+
parts.push(`, ${id.month} ${id.year}`);
|
|
1319
|
+
}
|
|
1220
1320
|
return parts.join("");
|
|
1221
1321
|
},
|
|
1222
1322
|
});
|
|
1323
|
+
// The NESC's own term for its pre-edition drafts: a draft STAGE of the
|
|
1324
|
+
// C2 code, not a variant. Canonical spelling is dotted and prefixed;
|
|
1325
|
+
// the dash, catalogue slash-tail and verbose proposal spellings are
|
|
1326
|
+
// aliases.
|
|
1327
|
+
export const NescPreprintClass = ieeeClass({ kind: "nesc-preprint" }, {
|
|
1328
|
+
codeColumns: true,
|
|
1329
|
+
extraDefs: NescDefs,
|
|
1330
|
+
extraMappings: NescMappings,
|
|
1331
|
+
render: (id) => `IEEE Std ${["C2", id.year, "Preprint"].filter((p) => p !== undefined).join(".")}`,
|
|
1332
|
+
});
|
|
1223
1333
|
function nescNamePortion(id) {
|
|
1224
1334
|
let name = "National Electrical Safety Code";
|
|
1225
1335
|
if (id["registered"] === true)
|
|
@@ -259,9 +259,9 @@ function normalizeRevisionNotation(input) {
|
|
|
259
259
|
cleaned = cleaned.replace(/(\/D-?[0-9A-Za-z.]+)\s+[Rr][Ee][Vv]\s*(\d+)/, "$1/R-$2");
|
|
260
260
|
cleaned = cleaned.replace(/[-/_.]?\s?[Rr][Ee][Vv][-\s]?(\d+)(\/D-?[0-9A-Za-z.]+)/, "$2/R-$1");
|
|
261
261
|
cleaned = cleaned.replace(/(\d)[-._]?\s?[Rr][Ee][Vv]\s*(\d+)\s*$/, "$1/R-$2");
|
|
262
|
-
// Lettered inline revisions
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
// Lettered inline revisions are IDENTITY (pubid ruling 2026-10-14):
|
|
263
|
+
// the grammar captures them natively with their separator; the former
|
|
264
|
+
// strip rewrite here dropped the letters and is gone.
|
|
265
265
|
return cleaned;
|
|
266
266
|
}
|
|
267
267
|
function normalizeJointStageSpellings(input) {
|
|
@@ -271,7 +271,6 @@ function normalizeJointStageSpellings(input) {
|
|
|
271
271
|
const num = "(P?\\d+(?:[.-]\\d+)?)";
|
|
272
272
|
const tail = "(,? (?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Sept|Oct|Nov|Dec)[a-z]* \\d{4}|$|-\\d{4}(?:-\\d\\d)?)";
|
|
273
273
|
cleaned = cleaned.replace(/(\d)_D(\d)/g, "$1/D$2");
|
|
274
|
-
cleaned = cleaned.replace(/,(?=[A-Za-z])/, ", ");
|
|
275
274
|
cleaned = cleaned.replace(new RegExp(`^${pubs}${num}/(D[\\d.]+)/ ?${stage}\\b`), "$1$4 $2/$3");
|
|
276
275
|
cleaned = cleaned.replace(new RegExp(`^${pubs}${num}/ ${stage}${tail}`), "$1$3 $2$4");
|
|
277
276
|
cleaned = cleaned.replace(new RegExp(`^${pubs}${num}/${stage} (\\d{4})\\b`), "$1$3 $2-$4");
|
|
@@ -287,7 +286,6 @@ function normalizeJointStageSpellings(input) {
|
|
|
287
286
|
// The Parser.parse cleaning pipeline, in Ruby order.
|
|
288
287
|
export function preprocessIeee(input) {
|
|
289
288
|
let cleaned = input.replace(/\.pdf$/i, "");
|
|
290
|
-
cleaned = cleaned.replace(/_(FDIS|CDV|CD|DIS|WD|PWI|NP)/g, "/$1");
|
|
291
289
|
cleaned = cleaned.replace(/\s+/g, " ");
|
|
292
290
|
cleaned = cleaned.replace(/\b(ISO\/IEC\/IEEE|IEEE\/ISO\/IEC|IEEE\/IEC\/ISO|ISO\/IEEE|IEC\/IEEE|IEEE\/IEC|ISO\/IEC)\/ ?(FDIS|FCD|CDV|DIS\d?|CD\d?|WD|PWI|NP)\b/g, "$1 $2");
|
|
293
291
|
cleaned = normalizeRevisionNotation(cleaned);
|
|
@@ -363,7 +361,6 @@ export function preprocessIeee(input) {
|
|
|
363
361
|
if (/^(\d+[-.]\d+)\/D\d+/.test(cleaned)) {
|
|
364
362
|
cleaned = `IEEE P${cleaned}`;
|
|
365
363
|
}
|
|
366
|
-
cleaned = cleaned.replace(/\/Preprint\b/g, "");
|
|
367
364
|
cleaned = cleaned.replaceAll("Proposed Revision of", "Revision of");
|
|
368
365
|
cleaned = cleaned.replace(/\bammended\b/gi, "amended");
|
|
369
366
|
cleaned = cleaned.replace(/(\/INT|\/Cor\s+\d+-\d{4})\./g, "$1");
|
|
@@ -70,8 +70,14 @@ function buildRules() {
|
|
|
70
70
|
rule("simple_series", () => literalAlternation(SIMPLE_SERIES).as("series"));
|
|
71
71
|
rule("number_suffix", () => str("U")
|
|
72
72
|
.then(lowerLetter)
|
|
73
|
-
.or(
|
|
74
|
-
|
|
73
|
+
.or(
|
|
74
|
+
// An "r" directly followed by a digit is the revision marker
|
|
75
|
+
// (pubid#170), not a suffix — leave it for the edition rules.
|
|
76
|
+
str("r")
|
|
77
|
+
.then(digit)
|
|
78
|
+
.absent()
|
|
79
|
+
.then(letter, literalAlternation([
|
|
80
|
+
"ec", "ndex", "ndx", "nsert", "rrata", "raft", "pp", "s", "t",
|
|
75
81
|
"hi", "iet", "ort", "r", "p",
|
|
76
82
|
]).absent(), digits.maybe())));
|
|
77
83
|
rule("digits_with_suffix", () => digits.then(ref(rules, "number_suffix").then(digit.absent()).maybe()));
|
|
@@ -105,20 +111,23 @@ function buildRules() {
|
|
|
105
111
|
.absent()
|
|
106
112
|
.then(str("draft").absent(), (digits
|
|
107
113
|
.then(literalAlternation(["supp", "sup"]), digit.absent(), letter.absent())
|
|
108
|
-
.or(digits.then(str("r"), digits, str("U"), lowerLetter), digits.then(str("r"), digits, letter), digits.as("number_only").then(str("r"), digits.as("edition_id")), digits.then(str("_"), digits, dash, digits, upperLetter.maybe()), lowerLetter.then(dash, digits), digits.then(str("pt"), digits, dash.absent()), digits.then(upperLetter), digits
|
|
114
|
+
.or(digits.then(str("r"), digits, str("U"), lowerLetter), digits.then(str("r"), digits, letter), digits.as("number_only").then(str("r"), digits.then(dot.then(digits).maybe()).as("edition_id")), digits.then(str("_"), digits, dash, digits, upperLetter.maybe()), lowerLetter.then(dash, digits), digits.then(str("pt"), digits, dash.absent()), digits.then(upperLetter), digits
|
|
109
115
|
.as("number_only")
|
|
110
116
|
.then(str("r"), letter.as("letter"))
|
|
111
|
-
.as("revision_letter"), str("r").then(letter).as("revision_letter_suffix"), str("r")
|
|
117
|
+
.as("revision_letter"), str("r").then(letter).as("revision_letter_suffix"), str("r")
|
|
118
|
+
.then(digits.then(dot.then(digits).maybe()).as("edition_id"))
|
|
119
|
+
.as("revision_simple"), str("NCNR"), str("PERMIS"), str("BFRL"), upperLetter.repeat(1, 3), rules["digits_with_suffix"]
|
|
112
120
|
.then(dash.then(monthAbbrev(), digits, slash).absent()), lowerLetter.then(digit.absent()))).as("second_number")));
|
|
121
|
+
const dottedDigits = () => digits.then(dot.then(digits).maybe());
|
|
113
122
|
const editionInner = () => space
|
|
114
123
|
.maybe()
|
|
115
|
-
.then(str("e"),
|
|
124
|
+
.then(str("e"), dottedDigits().as("edition_id"))
|
|
116
125
|
.as("edition_e")
|
|
117
126
|
.or(space
|
|
118
|
-
.then(str("r"),
|
|
119
|
-
.as("edition_r_with_space_letter"), space.then(str("r"),
|
|
120
|
-
.then(
|
|
121
|
-
.as("edition_r_no_space_letter"), str("r").then(
|
|
127
|
+
.then(str("r"), dottedDigits().as("edition_id"), letter.as("edition_letter"))
|
|
128
|
+
.as("edition_r_with_space_letter"), space.then(str("r"), dottedDigits().as("edition_id")).as("edition_r_with_space"), str("r")
|
|
129
|
+
.then(dottedDigits().as("edition_id"), letter.as("edition_letter"))
|
|
130
|
+
.as("edition_r_no_space_letter"), str("r").then(dottedDigits().as("edition_id")).as("edition_r_no_space"), space
|
|
122
131
|
.maybe()
|
|
123
132
|
.then(str("rev"), space.maybe(), digits.as("edition_id"))
|
|
124
133
|
.as("edition_rev"), dash.then(match("[1-9]").as("edition_id"), digit.absent()).as("edition_historical"), dash
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { PubidRuntime, toBuilderTree } from "../../parg/runtime.js";
|
|
2
|
+
// The grammar runtime is the baked PARG artifact (pubid-grammar
|
|
3
|
+
// artifacts/nist.json via the parsanol engine) — the same artifact the
|
|
4
|
+
// gem runs, so grammar changes land once and this port cannot drift.
|
|
5
|
+
// Only the preprocessor, builder and model are ported code.
|
|
6
|
+
let cachedNistRuntime;
|
|
7
|
+
function cachedRuntime(input) {
|
|
8
|
+
cachedNistRuntime ??= PubidRuntime.load("nist");
|
|
9
|
+
return cachedNistRuntime.parseShape(input);
|
|
10
|
+
}
|
|
3
11
|
import { preprocessNist } from "./preprocessor.js";
|
|
4
12
|
import { NIST_CLASSES, NistCode, NistEdition, NistPart, NistStage, NistSupplement, NistTranslation, NistUpdate, NistVersion, NistVolume, SP_SUBSERIES, seriesPolicy, } from "./model.js";
|
|
5
13
|
/**
|
|
@@ -1238,11 +1246,12 @@ export function nistGrammarImplementation() {
|
|
|
1238
1246
|
return {
|
|
1239
1247
|
parse(input) {
|
|
1240
1248
|
const { cleaned, format } = preprocessNist(input);
|
|
1241
|
-
const
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1249
|
+
const base = cleaned.replace(/\s*\(all parts\)\s*$/, "");
|
|
1250
|
+
const tree = toBuilderTree(cachedRuntime(base));
|
|
1251
|
+
const marked = base !== cleaned
|
|
1252
|
+
? { ...tree, all_parts: true }
|
|
1253
|
+
: tree;
|
|
1254
|
+
return builder.build(marked, format);
|
|
1246
1255
|
},
|
|
1247
1256
|
};
|
|
1248
1257
|
}
|
|
@@ -192,8 +192,16 @@ export function preprocessNist(input) {
|
|
|
192
192
|
cleaned = cleaned.replace(/(\d)(v\d+[a-z]-[a-z])/g, "$1 $2");
|
|
193
193
|
cleaned = cleaned.replace(/(\d)(v\d+[A-Z])/g, "$1 $2");
|
|
194
194
|
cleaned = cleaned.replace(/(v\d+)([A-Z])-([A-Z])/g, (_m, v, a, b) => `${v}${a}-${b.toLowerCase()}`);
|
|
195
|
-
// normalize_edition_year_suffix
|
|
195
|
+
// normalize_edition_year_suffix — a dotted minor after the dot stays
|
|
196
|
+
// attached (pubid#170): "2006ed.1" → "e2006.1", never "e20061".
|
|
197
|
+
cleaned = cleaned.replace(/(\d{4})ed\.(\d+)/g, "e$1.$2");
|
|
196
198
|
cleaned = cleaned.replace(/(\d{4})ed\./g, "e$1");
|
|
199
|
+
// normalize_glued_dotted_edition — a glued dotted e-edition needs the
|
|
200
|
+
// space the spaced form has (pubid#170): "800-53e2.1" → "800-53 e2.1".
|
|
201
|
+
// The minor is 1-2 digits; a 4-digit tail is the additional-text year of
|
|
202
|
+
// "NBS CIRC 11e2.1915", which keeps its existing tree. Dot-less "800-53e2"
|
|
203
|
+
// keeps its number-bound tree.
|
|
204
|
+
cleaned = cleaned.replace(/(\d)e(\d+\.\d{1,2})(?!\d)/g, "$1 e$2");
|
|
197
205
|
// normalize_revision_with_letter
|
|
198
206
|
cleaned = cleaned.replace(/(\d+)(r\d{1,2})([a-z])(?=-|[A-Z]|$)/g, (_m, n, r, l) => `${n}${r}${l.toUpperCase()}`);
|
|
199
207
|
cleaned = cleaned.replace(/(\d+)(r\d{1,2})(?![a-zA-Z])(?=[A-Z]|-(?=[A-Z])|\/(?:upd|errata|insert))/g, "$1 $2");
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PargRuntime as EngineRuntime } from "parsanol";
|
|
2
|
+
export type { FieldRequirement, EntrySchema, Schema } from "parsanol";
|
|
3
|
+
export { PargRuntime } from "parsanol";
|
|
4
|
+
/** The artifacts directory: PARG_ARTIFACT_DIR, else the sibling
|
|
5
|
+
* pubid-grammar checkout of the pubid workspace, else the vendored copy
|
|
6
|
+
* shipped in the published package (refreshed by `npm run artifact`). */
|
|
7
|
+
export declare function artifactsDir(): string;
|
|
8
|
+
/** The pubid flavor runtime: loads baked artifacts from the workspace. */
|
|
9
|
+
export declare class PubidRuntime extends EngineRuntime {
|
|
10
|
+
static artifactsDir(): string;
|
|
11
|
+
static load(grammar: string, entry?: string): EngineRuntime;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The artifact emits capture leaves ({value, line, column, offset,
|
|
15
|
+
* length}) and a top-level sequence of capture hashes. This mirrors the
|
|
16
|
+
* gem's Pubid::Parg::Backend.to_builder_hash: scalarize leaves, fold the
|
|
17
|
+
* top-level list into one hash (last key wins — parslet's sequence fold).
|
|
18
|
+
*/
|
|
19
|
+
export declare function toBuilderTree(shape: unknown): unknown;
|
|
20
|
+
/**
|
|
21
|
+
* Strip the shape metadata an artifact parse carries (offset/line/column
|
|
22
|
+
* wrappers) down to the plain string/array capture tree the builders
|
|
23
|
+
* consume — the same tree shape the hand-written grammars produced.
|
|
24
|
+
*/
|
|
25
|
+
export declare function normalizeShape(node: unknown): unknown;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
//! The PARG artifact runtime for pubid: a thin adapter over the
|
|
2
|
+
//! published `parsanol` npm package (the wasm engine), adding the
|
|
3
|
+
//! pubid-workspace artifacts directory convention. No grammar code and
|
|
4
|
+
//! no vendored engine copy live in this repo; the baked artifact is
|
|
5
|
+
//! the contract and the engine ships from the registry.
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
import { PargRuntime as EngineRuntime } from "parsanol";
|
|
10
|
+
export { PargRuntime } from "parsanol";
|
|
11
|
+
/** Walk up from this module to the package root (which holds package.json). */
|
|
12
|
+
function packageRoot() {
|
|
13
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
for (; !existsSync(join(dir, "package.json")); dir = dirname(dir)) {
|
|
15
|
+
if (dir === dirname(dir))
|
|
16
|
+
throw new Error("package.json not found above the parg runtime");
|
|
17
|
+
}
|
|
18
|
+
return dir;
|
|
19
|
+
}
|
|
20
|
+
/** The artifacts directory: PARG_ARTIFACT_DIR, else the sibling
|
|
21
|
+
* pubid-grammar checkout of the pubid workspace, else the vendored copy
|
|
22
|
+
* shipped in the published package (refreshed by `npm run artifact`). */
|
|
23
|
+
export function artifactsDir() {
|
|
24
|
+
const env = process.env.PARG_ARTIFACT_DIR;
|
|
25
|
+
if (env)
|
|
26
|
+
return env;
|
|
27
|
+
const sibling = join(packageRoot(), "..", "pubid-grammar", "artifacts");
|
|
28
|
+
if (existsSync(sibling))
|
|
29
|
+
return sibling;
|
|
30
|
+
return join(packageRoot(), "vendor", "parg");
|
|
31
|
+
}
|
|
32
|
+
/** The pubid flavor runtime: loads baked artifacts from the workspace. */
|
|
33
|
+
export class PubidRuntime extends EngineRuntime {
|
|
34
|
+
static artifactsDir() {
|
|
35
|
+
return artifactsDir();
|
|
36
|
+
}
|
|
37
|
+
static load(grammar, entry) {
|
|
38
|
+
return EngineRuntime.fromFile(join(artifactsDir(), `${grammar}.json`), entry);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* The artifact emits capture leaves ({value, line, column, offset,
|
|
43
|
+
* length}) and a top-level sequence of capture hashes. This mirrors the
|
|
44
|
+
* gem's Pubid::Parg::Backend.to_builder_hash: scalarize leaves, fold the
|
|
45
|
+
* top-level list into one hash (last key wins — parslet's sequence fold).
|
|
46
|
+
*/
|
|
47
|
+
export function toBuilderTree(shape) {
|
|
48
|
+
const normalized = normalizeShape(shape);
|
|
49
|
+
if (Array.isArray(normalized) &&
|
|
50
|
+
normalized.length > 0 &&
|
|
51
|
+
normalized.every((n) => typeof n === "object" && n !== null && !Array.isArray(n))) {
|
|
52
|
+
return Object.assign({}, ...normalized);
|
|
53
|
+
}
|
|
54
|
+
return normalized;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Strip the shape metadata an artifact parse carries (offset/line/column
|
|
58
|
+
* wrappers) down to the plain string/array capture tree the builders
|
|
59
|
+
* consume — the same tree shape the hand-written grammars produced.
|
|
60
|
+
*/
|
|
61
|
+
export function normalizeShape(node) {
|
|
62
|
+
if (Array.isArray(node))
|
|
63
|
+
return node.map(normalizeShape);
|
|
64
|
+
if (typeof node === "object" && node !== null) {
|
|
65
|
+
const rec = node;
|
|
66
|
+
if (typeof rec["value"] === "string" && Object.keys(rec).length >= 1 &&
|
|
67
|
+
"offset" in rec) {
|
|
68
|
+
return rec["value"];
|
|
69
|
+
}
|
|
70
|
+
const out = {};
|
|
71
|
+
for (const [k, v] of Object.entries(rec))
|
|
72
|
+
out[k] = normalizeShape(v);
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
return node;
|
|
76
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { loadSuites, readSuite, runSuite, type Suite, type SuiteTest, type TestKind, } from "parsanol/suite";
|
|
2
|
+
export { PubidRuntime } from "./runtime.js";
|
|
3
|
+
/** The suites directory: PARG_SUITES_DIR, else beside the artifacts. */
|
|
4
|
+
export declare function suitesDir(): string;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//! pgtest suite runner: re-exports the engine suite machinery from the
|
|
2
|
+
//! published `parsanol` package; only the suites directory convention
|
|
3
|
+
//! (sibling pubid-grammar checkout) is pubid-specific.
|
|
4
|
+
export { loadSuites, readSuite, runSuite, } from "parsanol/suite";
|
|
5
|
+
export { PubidRuntime } from "./runtime.js";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
import { artifactsDir } from "./runtime.js";
|
|
8
|
+
/** The suites directory: PARG_SUITES_DIR, else beside the artifacts. */
|
|
9
|
+
export function suitesDir() {
|
|
10
|
+
const env = process.env.PARG_SUITES_DIR;
|
|
11
|
+
if (env)
|
|
12
|
+
return env;
|
|
13
|
+
return join(artifactsDir(), "..", "suites");
|
|
14
|
+
}
|
package/dist/urn/parsers.js
CHANGED
|
@@ -552,6 +552,13 @@ export const URN_PARSERS = {
|
|
|
552
552
|
const parts = splitParts(body);
|
|
553
553
|
const [, code, year] = parts;
|
|
554
554
|
let text = `IEEE Std ${code}`;
|
|
555
|
+
// A "-YYYY-MM" tail is a dated reference (year + numeric month),
|
|
556
|
+
// mirroring the gem's urn parser; it re-parses through the
|
|
557
|
+
// trailing-month-year clause so the render prints "21, 11 1976"
|
|
558
|
+
// like the reference.
|
|
559
|
+
const dated = /^(.*)-(\d{4})-(\d{2})$/.exec(text);
|
|
560
|
+
if (dated)
|
|
561
|
+
return parse(`${dated[1]}, ${dated[3]} ${dated[2]}`);
|
|
555
562
|
if (year)
|
|
556
563
|
text += `-${year}`;
|
|
557
564
|
return parse(text);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubid/pubid",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
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",
|
|
@@ -17,15 +17,17 @@
|
|
|
17
17
|
"artifact": "tsc -p tsconfig.json && node scripts/build-artifact.mjs"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
+
"parsanol": "^0.10.3",
|
|
20
21
|
"yaml": "^2.5.0"
|
|
21
22
|
},
|
|
22
23
|
"devDependencies": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
24
|
+
"@types/node": "^20.14.0",
|
|
25
|
+
"typescript": "^5.6.0"
|
|
25
26
|
},
|
|
26
27
|
"files": [
|
|
27
28
|
"dist",
|
|
28
|
-
"artifact"
|
|
29
|
+
"artifact",
|
|
30
|
+
"vendor/parg"
|
|
29
31
|
],
|
|
30
32
|
"keywords": [
|
|
31
33
|
"pubid",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"bindings":null,"version":"0.1.0","grammar":"PubidAdobe","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Entity":{"atom":48}},{"Entity":{"atom":30}},{"Entity":{"atom":9}},{"Str":{"pattern":"Adobe"}},{"Entity":{"atom":5}},{"Str":{"pattern":" "}},{"Str":{"pattern":"TN"}},{"Entity":{"atom":5}},{"Repetition":{"atom":7,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[3,4,6,8]}},{"Entity":{"atom":24}},{"Str":{"pattern":"Adobe"}},{"Entity":{"atom":5}},{"Str":{"pattern":"Technical"}},{"Entity":{"atom":5}},{"Str":{"pattern":"Note"}},{"Entity":{"atom":5}},{"Repetition":{"atom":16,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"#"}},{"Repetition":{"atom":18,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":5}},{"Repetition":{"atom":20,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[17,19,21]}},{"Repetition":{"atom":22,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[11,12,13,14,15,23]}},{"Entity":{"atom":29}},{"Str":{"pattern":"ATN"}},{"Entity":{"atom":5}},{"Repetition":{"atom":27,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[26,28]}},{"Alternative":{"atoms":[2,10,25]}},{"Entity":{"atom":32}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":31,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"number","atom":33}},{"Entity":{"atom":36}},{"Str":{"pattern":"."}},{"Entity":{"atom":42}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Re":{"pattern":"[_]"}},{"Alternative":{"atoms":[38,39,40,41]}},{"Repetition":{"atom":37,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"slug","atom":43}},{"Sequence":{"atoms":[35,44]}},{"Repetition":{"atom":45,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[1,34,46]}},{"Named":{"name":"tech_note","atom":47}},{"Entity":{"atom":53}},{"Entity":{"atom":32}},{"Repetition":{"atom":50,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"number","atom":51}},{"Named":{"name":"tech_note_bare","atom":52}},{"Entity":{"atom":87}},{"Str":{"pattern":"Adobe Publication "}},{"Repetition":{"atom":55,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":86}},{"Entity":{"atom":82}},{"Entity":{"atom":75}},{"Entity":{"atom":69}},{"Entity":{"atom":62}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Repetition":{"atom":61,"min":1,"max":null,"tag":"Repetition"}},{"Entity":{"atom":67}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Alternative":{"atoms":[65,66]}},{"Repetition":{"atom":64,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[63,68]}},{"Entity":{"atom":71}},{"Str":{"pattern":"-"}},{"Entity":{"atom":69}},{"Sequence":{"atoms":[70,72]}},{"Repetition":{"atom":73,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[60,74]}},{"Named":{"name":"slug","atom":59}},{"Entity":{"atom":71}},{"Entity":{"atom":32}},{"Repetition":{"atom":78,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"version","atom":79}},{"Sequence":{"atoms":[76,77,80]}},{"Named":{"name":"publication_version","atom":81}},{"Entity":{"atom":85}},{"Entity":{"atom":75}},{"Named":{"name":"slug","atom":84}},{"Alternative":{"atoms":[58,83]}},{"Sequence":{"atoms":[56,57]}},{"Alternative":{"atoms":[0,49,54]}}],"root":88},"bindings":[]}},"preprocess":{},"tables":{},"lint":{"order_warnings":["rule tech_note_prefix: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule tech_note_prefix: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule tech_note_prefix: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule publication_slug_or_version: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule identifier: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)"]},"default_entry":"identifier","render":{},"derive":{},"tests":[{"entry":"identifier","kind":"accept","input":"Adobe TN 15","expect":{}},{"entry":"identifier","kind":"accept","input":"ATN 30","expect":{}},{"entry":"identifier","kind":"accept","input":"Adobe Technical Note #12","expect":{}},{"entry":"identifier","kind":"reject","input":"###","expect":{}}],"docs":{},"source":"# Port of lib/pubid/adobe/parser.rb: tech notes (Adobe TN 5014, legacy\n# \"Adobe Technical Note #5014\", ATN5014, bare 5014) and publications\n# (adobe-glyph-list, adobe-japan1-7 with the version split tried first).\n\ngrammar PubidAdobe version \"0.1.0\" {\n tech_note_tn_prefix = \"Adobe\" space \"TN\" [space]\n tech_note_long_prefix = \"Adobe\" space \"Technical\" space \"Note\" [[space] [\"#\"] [space]]\n tech_note_atn_prefix = \"ATN\" [space]\n tech_note_prefix = tech_note_tn_prefix / tech_note_long_prefix / tech_note_atn_prefix\n # Capture precedence: (*rep) as name wraps the whole repetition, so a\n # digit run joins to one string instead of re-keying every character;\n # slug is captured exactly once (the bare form) or as a sibling of\n # version inside the publication_version capture.\n tech_note = (tech_note_prefix (1*digit) as number [(dot (1*slug_char) as slug)]) as tech_note\n bare_number = ((1*digit) as number) as tech_note_bare\n slug_segment = 1*lower1 *lowerd\n slug_text = slug_segment *(dash slug_segment)\n slug_inner = (slug_text) as slug\n publication_with_version = ((slug_text) as slug dash (1*digit) as version) as publication_version\n publication_slug_or_version = publication_with_version / slug_inner\n publication = [\"Adobe Publication \"] publication_slug_or_version\n identifier = tech_note / bare_number / publication\n slug_char = %x41-5A / %x61-7A / %x30-39 / %x5F\n lower1 = %x61-7A\n lowerd = %x61-7A / %x30-39\n digit = %x30-39\n space = \" \"\n dot = \".\"\n dash = \"-\"\n entry identifier: identifier\n\n test {\n accept \"Adobe TN 15\"\n accept \"ATN 30\"\n accept \"Adobe Technical Note #12\"\n reject \"###\"\n }\n}\n","checksum":"sha256:38e8488c3da1c0f4a36fe2f63d87fee551d9317c5dae62f56972da1efe842a52"}
|