@pubid/pubid 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/artifact/corpus.json.gz +0 -0
- package/dist/conformance/cli.js +5 -1
- package/dist/flavors/amca/grammar.d.ts +4 -0
- package/dist/flavors/amca/grammar.js +87 -0
- package/dist/flavors/amca/index.d.ts +4 -0
- package/dist/flavors/amca/index.js +76 -0
- package/dist/flavors/amca/model.d.ts +29 -0
- package/dist/flavors/amca/model.js +146 -0
- package/dist/flavors/ansi/index.d.ts +24 -0
- package/dist/flavors/ansi/index.js +147 -0
- package/dist/flavors/api/grammar.d.ts +4 -0
- package/dist/flavors/api/grammar.js +79 -0
- package/dist/flavors/api/index.d.ts +4 -0
- package/dist/flavors/api/index.js +71 -0
- package/dist/flavors/api/model.d.ts +27 -0
- package/dist/flavors/api/model.js +114 -0
- package/dist/flavors/ashrae/grammar.d.ts +2 -0
- package/dist/flavors/ashrae/grammar.js +667 -0
- package/dist/flavors/ashrae/index.d.ts +4 -0
- package/dist/flavors/ashrae/index.js +306 -0
- package/dist/flavors/ashrae/model.d.ts +87 -0
- package/dist/flavors/ashrae/model.js +335 -0
- package/dist/flavors/ashrae/preprocessor.d.ts +7 -0
- package/dist/flavors/ashrae/preprocessor.js +44 -0
- package/dist/flavors/asme/grammar.d.ts +2 -0
- package/dist/flavors/asme/grammar.js +200 -0
- package/dist/flavors/asme/index.d.ts +4 -0
- package/dist/flavors/asme/index.js +138 -0
- package/dist/flavors/asme/model.d.ts +34 -0
- package/dist/flavors/asme/model.js +123 -0
- package/dist/flavors/astm/grammar.d.ts +2 -0
- package/dist/flavors/astm/grammar.js +110 -0
- package/dist/flavors/astm/index.d.ts +2 -0
- package/dist/flavors/astm/index.js +127 -0
- package/dist/flavors/astm/model.d.ts +42 -0
- package/dist/flavors/astm/model.js +263 -0
- package/dist/flavors/bipm/index.d.ts +30 -0
- package/dist/flavors/bipm/index.js +434 -0
- package/dist/flavors/bsi/grammar.d.ts +4 -0
- package/dist/flavors/bsi/grammar.js +535 -0
- package/dist/flavors/bsi/index.d.ts +4 -0
- package/dist/flavors/bsi/index.js +941 -0
- package/dist/flavors/bsi/model.d.ts +127 -0
- package/dist/flavors/bsi/model.js +863 -0
- package/dist/flavors/calconnect/index.d.ts +21 -0
- package/dist/flavors/calconnect/index.js +113 -0
- package/dist/flavors/cen_cenelec/grammar.d.ts +4 -0
- package/dist/flavors/cen_cenelec/grammar.js +107 -0
- package/dist/flavors/cen_cenelec/index.d.ts +5 -0
- package/dist/flavors/cen_cenelec/index.js +263 -0
- package/dist/flavors/cen_cenelec/model.d.ts +45 -0
- package/dist/flavors/cen_cenelec/model.js +490 -0
- package/dist/flavors/cie/grammar.d.ts +5 -0
- package/dist/flavors/cie/grammar.js +127 -0
- package/dist/flavors/cie/index.d.ts +2 -0
- package/dist/flavors/cie/index.js +311 -0
- package/dist/flavors/cie/model.d.ts +122 -0
- package/dist/flavors/cie/model.js +464 -0
- package/dist/flavors/csa/grammar.d.ts +6 -0
- package/dist/flavors/csa/grammar.js +239 -0
- package/dist/flavors/csa/index.d.ts +2 -0
- package/dist/flavors/csa/index.js +634 -0
- package/dist/flavors/csa/model.d.ts +33 -0
- package/dist/flavors/csa/model.js +505 -0
- package/dist/flavors/doi/index.d.ts +13 -0
- package/dist/flavors/doi/index.js +65 -0
- package/dist/flavors/easc/index.d.ts +4 -0
- package/dist/flavors/easc/index.js +107 -0
- package/dist/flavors/ecma/index.d.ts +4 -0
- package/dist/flavors/ecma/index.js +117 -0
- package/dist/flavors/etsi/index.d.ts +14 -0
- package/dist/flavors/etsi/index.js +307 -0
- package/dist/flavors/evs/grammar.d.ts +2 -0
- package/dist/flavors/evs/grammar.js +22 -0
- package/dist/flavors/evs/index.d.ts +2 -0
- package/dist/flavors/evs/index.js +24 -0
- package/dist/flavors/evs/model.d.ts +19 -0
- package/dist/flavors/evs/model.js +36 -0
- package/dist/flavors/gb/index.d.ts +31 -0
- package/dist/flavors/gb/index.js +159 -0
- package/dist/flavors/gost/grammar.d.ts +2 -0
- package/dist/flavors/gost/grammar.js +46 -0
- package/dist/flavors/gost/index.d.ts +2 -0
- package/dist/flavors/gost/index.js +165 -0
- package/dist/flavors/gost/model.d.ts +61 -0
- package/dist/flavors/gost/model.js +147 -0
- package/dist/flavors/gost/prefix_routes.d.ts +15 -0
- package/dist/flavors/gost/prefix_routes.js +192 -0
- package/dist/flavors/iala/index.d.ts +32 -0
- package/dist/flavors/iala/index.js +300 -0
- package/dist/flavors/iana/index.d.ts +19 -0
- package/dist/flavors/iana/index.js +71 -0
- package/dist/flavors/idf/grammar.d.ts +2 -0
- package/dist/flavors/idf/grammar.js +71 -0
- package/dist/flavors/idf/index.d.ts +2 -0
- package/dist/flavors/idf/index.js +100 -0
- package/dist/flavors/idf/model.d.ts +54 -0
- package/dist/flavors/idf/model.js +359 -0
- package/dist/flavors/iec/grammar.d.ts +3 -0
- package/dist/flavors/iec/grammar.js +187 -0
- package/dist/flavors/iec/index.d.ts +4 -0
- package/dist/flavors/iec/index.js +507 -0
- package/dist/flavors/iec/model.d.ts +54 -0
- package/dist/flavors/iec/model.js +437 -0
- package/dist/flavors/ieee/grammar.d.ts +2 -0
- package/dist/flavors/ieee/grammar.js +697 -0
- package/dist/flavors/ieee/index.d.ts +3 -0
- package/dist/flavors/ieee/index.js +1258 -0
- package/dist/flavors/ieee/model.d.ts +144 -0
- package/dist/flavors/ieee/model.js +1237 -0
- package/dist/flavors/ieee/preprocessor.d.ts +8 -0
- package/dist/flavors/ieee/preprocessor.js +410 -0
- package/dist/flavors/ieee/update_codes.d.ts +8 -0
- package/dist/flavors/ieee/update_codes.js +197 -0
- package/dist/flavors/ietf/index.d.ts +30 -0
- package/dist/flavors/ietf/index.js +151 -0
- package/dist/flavors/iho/index.d.ts +4 -0
- package/dist/flavors/iho/index.js +126 -0
- package/dist/flavors/index.d.ts +9 -0
- package/dist/flavors/index.js +136 -0
- package/dist/flavors/isbn/index.d.ts +13 -0
- package/dist/flavors/isbn/index.js +97 -0
- package/dist/flavors/iso/grammar.d.ts +2 -0
- package/dist/flavors/iso/grammar.js +207 -0
- package/dist/flavors/iso/index.d.ts +2 -0
- package/dist/flavors/iso/index.js +343 -0
- package/dist/flavors/iso/model.d.ts +159 -0
- package/dist/flavors/iso/model.js +802 -0
- package/dist/flavors/iso/stages.generated.d.ts +13 -0
- package/dist/flavors/iso/stages.generated.js +391 -0
- package/dist/flavors/itu/grammar.d.ts +4 -0
- package/dist/flavors/itu/grammar.js +205 -0
- package/dist/flavors/itu/index.d.ts +2 -0
- package/dist/flavors/itu/index.js +224 -0
- package/dist/flavors/itu/model.d.ts +184 -0
- package/dist/flavors/itu/model.js +599 -0
- package/dist/flavors/jcgm/index.d.ts +7 -0
- package/dist/flavors/jcgm/index.js +300 -0
- package/dist/flavors/jis/index.d.ts +4 -0
- package/dist/flavors/jis/index.js +267 -0
- package/dist/flavors/nist/grammar.d.ts +2 -0
- package/dist/flavors/nist/grammar.js +287 -0
- package/dist/flavors/nist/index.d.ts +2 -0
- package/dist/flavors/nist/index.js +1244 -0
- package/dist/flavors/nist/model.d.ts +155 -0
- package/dist/flavors/nist/model.js +823 -0
- package/dist/flavors/nist/preprocessor.d.ts +11 -0
- package/dist/flavors/nist/preprocessor.js +281 -0
- package/dist/flavors/oasis/index.d.ts +23 -0
- package/dist/flavors/oasis/index.js +110 -0
- package/dist/flavors/ogc/index.d.ts +20 -0
- package/dist/flavors/ogc/index.js +75 -0
- package/dist/flavors/oiml/grammar.d.ts +2 -0
- package/dist/flavors/oiml/grammar.js +206 -0
- package/dist/flavors/oiml/implementation.d.ts +9 -0
- package/dist/flavors/oiml/implementation.js +45 -0
- package/dist/flavors/oiml/model.d.ts +23 -0
- package/dist/flavors/oiml/model.js +592 -0
- package/dist/flavors/omg/index.d.ts +14 -0
- package/dist/flavors/omg/index.js +73 -0
- package/dist/flavors/plateau/index.d.ts +4 -0
- package/dist/flavors/plateau/index.js +97 -0
- package/dist/flavors/tgpp/index.d.ts +4 -0
- package/dist/flavors/tgpp/index.js +122 -0
- package/dist/flavors/un/index.d.ts +13 -0
- package/dist/flavors/un/index.js +90 -0
- package/dist/flavors/w3c/index.d.ts +14 -0
- package/dist/flavors/w3c/index.js +148 -0
- package/dist/flavors/xsf/index.d.ts +18 -0
- package/dist/flavors/xsf/index.js +65 -0
- package/dist/grammar/engine.d.ts +78 -0
- package/dist/grammar/engine.js +351 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -0
- package/dist/model/attribute.d.ts +54 -0
- package/dist/model/attribute.js +53 -0
- package/dist/model/builder.d.ts +39 -0
- package/dist/model/builder.js +124 -0
- package/dist/model/component.d.ts +70 -0
- package/dist/model/component.js +170 -0
- package/dist/model/identifier.d.ts +84 -0
- package/dist/model/identifier.js +270 -0
- package/dist/model/urn-generator.d.ts +27 -0
- package/dist/model/urn-generator.js +91 -0
- package/package.json +1 -1
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
import { BaseIdentifier, registerType } from "../../model/identifier.js";
|
|
2
|
+
import { extendAttributes, keyValue } from "../../model/attribute.js";
|
|
3
|
+
import { PubidDate } from "../../model/component.js";
|
|
4
|
+
import { BaseUrnGenerator } from "../../model/urn-generator.js";
|
|
5
|
+
export const TYPED_STAGES = [
|
|
6
|
+
{ code: "pwien", stage_code: "preliminary", type_code: "en", abbr: "pWI EN" },
|
|
7
|
+
{ code: "pren", stage_code: "proposal", type_code: "en", abbr: "prEN" },
|
|
8
|
+
{ code: "fpren", stage_code: "final_proposal", type_code: "en", abbr: "FprEN" },
|
|
9
|
+
{ code: "fven", stage_code: "formal_vote", type_code: "en", abbr: "FV prEN" },
|
|
10
|
+
{ code: "ven", stage_code: "vote", type_code: "en", abbr: "vEN" },
|
|
11
|
+
{ code: "puben", stage_code: "published", type_code: "en", abbr: "EN" },
|
|
12
|
+
{ code: "rven", stage_code: "review", type_code: "en", abbr: "rvEN" },
|
|
13
|
+
{ code: "racen", stage_code: "reactivation", type_code: "en", abbr: "racEN" },
|
|
14
|
+
{ code: "wden", stage_code: "withdrawn", type_code: "en", abbr: "wdEN" },
|
|
15
|
+
{ code: "pubts", stage_code: "published", type_code: "ts", abbr: "TS" },
|
|
16
|
+
{ code: "prts", stage_code: "proposal", type_code: "ts", abbr: "prTS" },
|
|
17
|
+
{ code: "pubtr", stage_code: "published", type_code: "tr", abbr: "TR" },
|
|
18
|
+
{ code: "pubcwa", stage_code: "published", type_code: "cwa", abbr: "CWA" },
|
|
19
|
+
{ code: "pubguide", stage_code: "published", type_code: "guide", abbr: "Guide" },
|
|
20
|
+
{ code: "pubhd", stage_code: "published", type_code: "hd", abbr: "HD" },
|
|
21
|
+
{ code: "pubes", stage_code: "published", type_code: "es", abbr: "ES" },
|
|
22
|
+
{ code: "pubcr", stage_code: "published", type_code: "cr", abbr: "CR" },
|
|
23
|
+
{ code: "pubenv", stage_code: "published", type_code: "env", abbr: "ENV" },
|
|
24
|
+
];
|
|
25
|
+
export const DEFAULT_TYPED_STAGE = TYPED_STAGES.find((s) => s.code === "puben");
|
|
26
|
+
export function locateStage(abbr) {
|
|
27
|
+
const up = abbr.toUpperCase();
|
|
28
|
+
return TYPED_STAGES.find((s) => s.abbr.toUpperCase() === up);
|
|
29
|
+
}
|
|
30
|
+
export function locateStageByCode(code) {
|
|
31
|
+
return TYPED_STAGES.find((s) => s.code === code);
|
|
32
|
+
}
|
|
33
|
+
export const PUBLISHER_TYPES = ["CWA", "HD", "ES", "CR", "ENV"];
|
|
34
|
+
const TYPE_CLASS = {
|
|
35
|
+
en: "european-norm",
|
|
36
|
+
ts: "technical-specification",
|
|
37
|
+
tr: "technical-report",
|
|
38
|
+
guide: "guide",
|
|
39
|
+
cwa: "cen-workshop-agreement",
|
|
40
|
+
hd: "harmonization-document",
|
|
41
|
+
es: "european-specification",
|
|
42
|
+
cr: "cen-report",
|
|
43
|
+
env: "european-prestandard",
|
|
44
|
+
};
|
|
45
|
+
const CLASS_SHORT = {
|
|
46
|
+
"european-norm": "EN",
|
|
47
|
+
"technical-specification": "TS",
|
|
48
|
+
"technical-report": "TR",
|
|
49
|
+
guide: "Guide",
|
|
50
|
+
"cen-workshop-agreement": "CWA",
|
|
51
|
+
"harmonization-document": "HD",
|
|
52
|
+
"cenelec-harmonization-document": "HD",
|
|
53
|
+
"european-specification": "ES",
|
|
54
|
+
"cen-report": "CR",
|
|
55
|
+
"european-prestandard": "ENV",
|
|
56
|
+
};
|
|
57
|
+
export function locateTypeClass(typeCode) {
|
|
58
|
+
const key = typeCode;
|
|
59
|
+
return key in TYPE_CLASS ? key : undefined;
|
|
60
|
+
}
|
|
61
|
+
const dateWire = {
|
|
62
|
+
wire: "date",
|
|
63
|
+
to: "date",
|
|
64
|
+
toWire: (model) => {
|
|
65
|
+
const date = model["date"];
|
|
66
|
+
if (date === undefined)
|
|
67
|
+
return undefined;
|
|
68
|
+
// The shared flattener turns a single-field date into the bare "year"
|
|
69
|
+
// scalar; a month keeps the nested form.
|
|
70
|
+
if (date.month === undefined)
|
|
71
|
+
return { year: date.year };
|
|
72
|
+
return { year: date.year, month: date.month };
|
|
73
|
+
},
|
|
74
|
+
fromWire: (hash) => {
|
|
75
|
+
const nested = hash["date"];
|
|
76
|
+
if (nested !== undefined && typeof nested === "object" && nested !== null) {
|
|
77
|
+
const rec = nested;
|
|
78
|
+
return new PubidDate({ year: rec["year"], month: rec["month"] });
|
|
79
|
+
}
|
|
80
|
+
const year = hash["year"];
|
|
81
|
+
if (typeof year === "string" && year !== "")
|
|
82
|
+
return new PubidDate({ year });
|
|
83
|
+
return undefined;
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
const stageWire = {
|
|
87
|
+
wire: "stage",
|
|
88
|
+
to: "typedStage",
|
|
89
|
+
toWire: (model) => {
|
|
90
|
+
const stage = model["typedStage"];
|
|
91
|
+
return stage?.code;
|
|
92
|
+
},
|
|
93
|
+
fromWire: (hash) => {
|
|
94
|
+
const code = hash["stage"];
|
|
95
|
+
if (typeof code !== "string")
|
|
96
|
+
return undefined;
|
|
97
|
+
return locateStageByCode(code);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
export class CenIdentifier extends BaseIdentifier {
|
|
101
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
102
|
+
number: { type: "string" },
|
|
103
|
+
part: { type: "string" },
|
|
104
|
+
date: { type: PubidDate },
|
|
105
|
+
typedStage: { type: "string" },
|
|
106
|
+
type: { type: "string" },
|
|
107
|
+
publisher: { type: "string" },
|
|
108
|
+
copublishers: { type: "string", collection: true },
|
|
109
|
+
});
|
|
110
|
+
static mappings = keyValue({ wire: "number", to: "number" }, { wire: "part", to: "part" }, dateWire, stageWire, { wire: "publisher", to: "publisher" }, { wire: "copublishers", to: "copublishers" });
|
|
111
|
+
root() {
|
|
112
|
+
return this;
|
|
113
|
+
}
|
|
114
|
+
toUrn() {
|
|
115
|
+
return new CenUrnGenerator(this).generate();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function draftAbbr(id) {
|
|
119
|
+
const abbr = id.typedStage?.abbr;
|
|
120
|
+
return abbr === "prEN" || abbr === "FprEN" ? abbr : undefined;
|
|
121
|
+
}
|
|
122
|
+
function supplementToken(id) {
|
|
123
|
+
const self = id;
|
|
124
|
+
const prefix = self["_supplement"] === "corrigendum" ? "AC" : "A";
|
|
125
|
+
let result = `${prefix}${self["number"] ?? ""}`;
|
|
126
|
+
if (self["year"] !== undefined && self["year"] !== "") {
|
|
127
|
+
result += `:${self["year"]}`;
|
|
128
|
+
if (self["month"] !== undefined && self["month"] !== "")
|
|
129
|
+
result += `-${self["month"]}`;
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
function renderSingle(id, classShort) {
|
|
134
|
+
const parts = [];
|
|
135
|
+
const isDraftStage = draftAbbr(id) !== undefined;
|
|
136
|
+
const typeShort = isDraftStage
|
|
137
|
+
? id.typedStage.type_code.toUpperCase()
|
|
138
|
+
: id.type ?? classShort ?? "EN";
|
|
139
|
+
let useSlashBeforeType = false;
|
|
140
|
+
if (PUBLISHER_TYPES.includes(typeShort)) {
|
|
141
|
+
parts.push(id.typedStage !== undefined && id.typedStage.abbr !== typeShort
|
|
142
|
+
? id.typedStage.abbr
|
|
143
|
+
: typeShort);
|
|
144
|
+
}
|
|
145
|
+
else if (isDraftStage) {
|
|
146
|
+
parts.push(id.typedStage.abbr);
|
|
147
|
+
}
|
|
148
|
+
else if (id.publisher !== undefined) {
|
|
149
|
+
parts.push(id.publisher);
|
|
150
|
+
useSlashBeforeType = true;
|
|
151
|
+
}
|
|
152
|
+
if (id.copublishers !== undefined && id.copublishers.length > 0) {
|
|
153
|
+
const copubStr = id.copublishers.join("/");
|
|
154
|
+
if (parts.length > 0) {
|
|
155
|
+
parts[parts.length - 1] = `${parts[parts.length - 1]}/${copubStr}`;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
parts.push(copubStr);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
if (typeShort !== "EN" && typeShort !== "Guide" && !PUBLISHER_TYPES.includes(typeShort)) {
|
|
162
|
+
parts.push(useSlashBeforeType && parts.length > 0 ? `/${typeShort}` : typeShort);
|
|
163
|
+
}
|
|
164
|
+
else if (typeShort === "Guide") {
|
|
165
|
+
parts.push("Guide");
|
|
166
|
+
}
|
|
167
|
+
if (id.number !== undefined) {
|
|
168
|
+
parts.push(id.part !== undefined ? `${id.number}-${id.part}` : id.number);
|
|
169
|
+
}
|
|
170
|
+
let result = "";
|
|
171
|
+
parts.forEach((part, idx) => {
|
|
172
|
+
if (idx > 0 && !part.startsWith("/"))
|
|
173
|
+
result += " ";
|
|
174
|
+
result += part;
|
|
175
|
+
});
|
|
176
|
+
if (id.date !== undefined && id.date.present()) {
|
|
177
|
+
result += `:${id.date.render()}`;
|
|
178
|
+
}
|
|
179
|
+
return result;
|
|
180
|
+
}
|
|
181
|
+
function renderAdopted(id) {
|
|
182
|
+
const publishers = [id.publisher, ...(id.copublishers ?? [])].filter((p) => p !== undefined && p !== "");
|
|
183
|
+
const draft = draftAbbr(id);
|
|
184
|
+
if (draft !== undefined && publishers.length > 0)
|
|
185
|
+
publishers[0] = draft;
|
|
186
|
+
let result = publishers.join("/");
|
|
187
|
+
const adopted = id["adopted"];
|
|
188
|
+
if (adopted !== undefined)
|
|
189
|
+
result += ` ${adopted.toHuman()}`;
|
|
190
|
+
return result;
|
|
191
|
+
}
|
|
192
|
+
const ISO_TYPE_SEGMENT = {
|
|
193
|
+
"technical-specification": "ts",
|
|
194
|
+
"technical-report": "tr",
|
|
195
|
+
guide: "guide",
|
|
196
|
+
};
|
|
197
|
+
/** MR string of a nested iso/iec document read from its wire hash. */
|
|
198
|
+
function mrFromHash(hash) {
|
|
199
|
+
const type = String(hash["_type"] ?? "");
|
|
200
|
+
const segments = [];
|
|
201
|
+
if (type.startsWith("pubid:iso")) {
|
|
202
|
+
// ISO's MR string dashes copublishers onto the publisher slot
|
|
203
|
+
// ("iso-iec.27017.2026"); IEC's does not.
|
|
204
|
+
const copubs = Array.isArray(hash["copublishers"]) ? hash["copublishers"].map(String) : [];
|
|
205
|
+
segments.push(["iso", ...copubs.map((c) => c.toLowerCase())].join("-"));
|
|
206
|
+
}
|
|
207
|
+
else if (type.startsWith("pubid:iec")) {
|
|
208
|
+
segments.push("iec");
|
|
209
|
+
}
|
|
210
|
+
const typeSuffix = type.split(":")[2] ?? "";
|
|
211
|
+
const typeSegment = ISO_TYPE_SEGMENT[typeSuffix];
|
|
212
|
+
if (typeSegment !== undefined)
|
|
213
|
+
segments.push(typeSegment);
|
|
214
|
+
const identity = [hash["number"], hash["part"], hash["subpart"]]
|
|
215
|
+
.map((s) => String(s ?? ""))
|
|
216
|
+
.filter((s) => s !== "")
|
|
217
|
+
.join("-");
|
|
218
|
+
if (identity !== "")
|
|
219
|
+
segments.push(identity);
|
|
220
|
+
if (hash["year"] !== undefined)
|
|
221
|
+
segments.push(String(hash["year"]));
|
|
222
|
+
const base = hash["base"];
|
|
223
|
+
if (base !== undefined && typeof base === "object" && !Array.isArray(base)) {
|
|
224
|
+
const baseMr = mrFromHash(base);
|
|
225
|
+
const suffixTag = typeSuffix.endsWith("amendment") ? "amd" : "cor";
|
|
226
|
+
const suffix = [hash["number"], hash["year"]]
|
|
227
|
+
.map((s) => String(s ?? ""))
|
|
228
|
+
.filter((s) => s !== "")
|
|
229
|
+
.map((s, i) => (i === 0 ? s : `.${s}`))
|
|
230
|
+
.join("");
|
|
231
|
+
return suffix === "" ? `${baseMr}_${suffixTag}` : `${baseMr}_${suffixTag}.${suffix}`;
|
|
232
|
+
}
|
|
233
|
+
return segments.join(".");
|
|
234
|
+
}
|
|
235
|
+
// --- URN -----------------------------------------------------------------------
|
|
236
|
+
class CenUrnGenerator extends BaseUrnGenerator {
|
|
237
|
+
generate() {
|
|
238
|
+
return this.urnFor(this.identifier);
|
|
239
|
+
}
|
|
240
|
+
urnFor(id) {
|
|
241
|
+
const self = id;
|
|
242
|
+
const base = self["base"];
|
|
243
|
+
if (base !== undefined) {
|
|
244
|
+
return [this.urnFor(base), ...this.supplementSegments(id)].join(":");
|
|
245
|
+
}
|
|
246
|
+
const identifiers = self["identifiers"];
|
|
247
|
+
if (identifiers !== undefined) {
|
|
248
|
+
const [first, ...rest] = identifiers;
|
|
249
|
+
return [
|
|
250
|
+
this.urnFor(first),
|
|
251
|
+
...rest.flatMap((s) => ["plus", ...this.supplementSegments(s)]),
|
|
252
|
+
].join(":");
|
|
253
|
+
}
|
|
254
|
+
const adopted = self["adopted"];
|
|
255
|
+
if (adopted !== undefined) {
|
|
256
|
+
const body = [this.mrPublisher(id), this.adoptedMr(adopted)]
|
|
257
|
+
.filter((s) => s !== undefined && s !== "")
|
|
258
|
+
.join(".")
|
|
259
|
+
.replaceAll(".", ":")
|
|
260
|
+
.replaceAll("_", ":");
|
|
261
|
+
const segments = [`urn:cen:${body}`];
|
|
262
|
+
const code = id.typedStage?.stage_code;
|
|
263
|
+
if (code !== undefined && code !== "published")
|
|
264
|
+
segments.push(`stage.${code}`);
|
|
265
|
+
return segments.join(":");
|
|
266
|
+
}
|
|
267
|
+
return this.baseUrn(id);
|
|
268
|
+
}
|
|
269
|
+
supplementSegments(id) {
|
|
270
|
+
const self = id;
|
|
271
|
+
if (self["_supplement"] === "fragment") {
|
|
272
|
+
return ["frag", String(self["number"] ?? "")].filter((s) => s !== "");
|
|
273
|
+
}
|
|
274
|
+
if (self["_supplement"] === "corrigendum") {
|
|
275
|
+
const segments = ["cor", self["number"], this.supplementDate(self)];
|
|
276
|
+
return segments.map((s) => String(s ?? "")).filter((s) => s !== "");
|
|
277
|
+
}
|
|
278
|
+
const segments = ["amd", self["number"], self["year"]];
|
|
279
|
+
return segments.map((s) => String(s ?? "")).filter((s) => s !== "");
|
|
280
|
+
}
|
|
281
|
+
supplementDate(id) {
|
|
282
|
+
const year = id["year"];
|
|
283
|
+
if (year === undefined || year === "")
|
|
284
|
+
return undefined;
|
|
285
|
+
return [year, id["month"]].filter((m) => m !== undefined && m !== "").join("-");
|
|
286
|
+
}
|
|
287
|
+
mrPublisher(id) {
|
|
288
|
+
return (id.publisher ?? "en").toLowerCase();
|
|
289
|
+
}
|
|
290
|
+
/** The adopted document's MR string (iso/iec supplement recursion). */
|
|
291
|
+
adoptedMr(adopted) {
|
|
292
|
+
return mrFromHash(adopted.toHash());
|
|
293
|
+
}
|
|
294
|
+
baseUrn(id) {
|
|
295
|
+
const parts = ["urn", "cen", (id.publisher ?? "en").toLowerCase()];
|
|
296
|
+
if (id.copublishers !== undefined && id.copublishers.length > 0) {
|
|
297
|
+
parts[2] = `${parts[2]}-${id.copublishers.map((c) => c.toLowerCase()).join("-")}`;
|
|
298
|
+
}
|
|
299
|
+
if (id.number !== undefined) {
|
|
300
|
+
parts.push(id.part !== undefined ? `${id.number}-${id.part}` : id.number);
|
|
301
|
+
}
|
|
302
|
+
if (id.date !== undefined && id.date.present()) {
|
|
303
|
+
parts.push(id.date.render("urn"));
|
|
304
|
+
}
|
|
305
|
+
const code = id.typedStage?.stage_code;
|
|
306
|
+
if (code !== undefined && code !== "published")
|
|
307
|
+
parts.push(`stage.${code}`);
|
|
308
|
+
return parts.join(":");
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
function documentClass(spec) {
|
|
312
|
+
const defaultPublisher = PUBLISHER_TYPES.includes(spec.short) ? spec.short : "EN";
|
|
313
|
+
class CenConcrete extends CenIdentifier {
|
|
314
|
+
static polymorphicName = `pubid:cencenelec:${spec.kind}`;
|
|
315
|
+
static urnGenerator = CenUrnGenerator;
|
|
316
|
+
static get attributes() {
|
|
317
|
+
return extendAttributes(CenIdentifier, {
|
|
318
|
+
publisher: { type: "string", default: defaultPublisher },
|
|
319
|
+
type: { type: "string", default: spec.short },
|
|
320
|
+
adopted: { type: CenIdentifier },
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
static get mappings() {
|
|
324
|
+
return [...CenIdentifier.mappings, { wire: "adopted", to: "adopted" }];
|
|
325
|
+
}
|
|
326
|
+
constructor(attrs = {}) {
|
|
327
|
+
super(attrs);
|
|
328
|
+
// An ENV adoption renders "ENV <adopted>" (render_european_prestandard).
|
|
329
|
+
if (this.adopted !== undefined) {
|
|
330
|
+
this["_envAdopted"] = true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
render() {
|
|
334
|
+
if (this.adopted !== undefined) {
|
|
335
|
+
return `${spec.short} ${this.adopted.toHuman()}`;
|
|
336
|
+
}
|
|
337
|
+
return renderSingle(this, spec.short);
|
|
338
|
+
}
|
|
339
|
+
root() {
|
|
340
|
+
return this;
|
|
341
|
+
}
|
|
342
|
+
toUrn() {
|
|
343
|
+
if (this.adopted !== undefined) {
|
|
344
|
+
const body = [spec.short.toLowerCase(), this.adoptedUrnBody()]
|
|
345
|
+
.filter((s) => s !== "")
|
|
346
|
+
.join(":");
|
|
347
|
+
return `urn:cen:${body}`;
|
|
348
|
+
}
|
|
349
|
+
return super.toUrn();
|
|
350
|
+
}
|
|
351
|
+
adoptedUrnBody() {
|
|
352
|
+
const adopted = this.adopted;
|
|
353
|
+
const rawPub = adopted["publisher"];
|
|
354
|
+
const pub = (typeof rawPub === "string"
|
|
355
|
+
? rawPub
|
|
356
|
+
: typeof rawPub?.publisher === "string"
|
|
357
|
+
? rawPub.publisher
|
|
358
|
+
: String(rawPub?.body ?? "")).toLowerCase();
|
|
359
|
+
const rawType = adopted["type"];
|
|
360
|
+
const typeKey = this.adopted.constructor.typeKey;
|
|
361
|
+
const type = typeKey !== undefined && typeKey !== "is"
|
|
362
|
+
? typeKey
|
|
363
|
+
: (typeof rawType === "string" ? rawType : String(rawType?.abbr ?? "")).toLowerCase();
|
|
364
|
+
const segments = [
|
|
365
|
+
pub,
|
|
366
|
+
type,
|
|
367
|
+
[adopted["number"], adopted["part"], adopted["subpart"]]
|
|
368
|
+
.map((s) => String(s ?? ""))
|
|
369
|
+
.filter((s) => s !== "")
|
|
370
|
+
.join("-"),
|
|
371
|
+
adopted["year"] ?? this.adopted?.date?.year,
|
|
372
|
+
]
|
|
373
|
+
.map((s) => String(s ?? ""))
|
|
374
|
+
.filter((s) => s !== "");
|
|
375
|
+
return segments.join(":");
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
registerType(CenConcrete);
|
|
379
|
+
return CenConcrete;
|
|
380
|
+
}
|
|
381
|
+
export const CEN_DOCUMENT_CLASSES = new Map(Object.keys(TYPE_CLASS).map((key) => [
|
|
382
|
+
key,
|
|
383
|
+
documentClass({ kind: TYPE_CLASS[key], short: CLASS_SHORT[TYPE_CLASS[key]] }),
|
|
384
|
+
]));
|
|
385
|
+
// The CENELEC HD variant has its own _type; the builder routes plain HD to
|
|
386
|
+
// the CEN class (Ruby's registry finds it first).
|
|
387
|
+
export const CenelecHarmonizationDocumentClass = documentClass({
|
|
388
|
+
kind: "cenelec-harmonization-document",
|
|
389
|
+
short: "HD",
|
|
390
|
+
});
|
|
391
|
+
function supplementClass(kind, extraDefs) {
|
|
392
|
+
class CenSupplement extends CenIdentifier {
|
|
393
|
+
static polymorphicName = `pubid:cencenelec:${kind}`;
|
|
394
|
+
static urnGenerator = CenUrnGenerator;
|
|
395
|
+
static get attributes() {
|
|
396
|
+
return extendAttributes(CenIdentifier, {
|
|
397
|
+
base: { type: CenIdentifier },
|
|
398
|
+
...extraDefs,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
static get mappings() {
|
|
402
|
+
return [
|
|
403
|
+
...CenIdentifier.mappings.filter((m) => m.wire !== "publisher" && m.wire !== "copublishers" && m.wire !== "date" && m.wire !== "stage" && m.wire !== "type"),
|
|
404
|
+
{ wire: "base", to: "base" },
|
|
405
|
+
{ wire: "number", to: "number" },
|
|
406
|
+
{ wire: "year", to: "year" },
|
|
407
|
+
...(kind === "corrigendum" ? [{ wire: "month", to: "month" }] : []),
|
|
408
|
+
];
|
|
409
|
+
}
|
|
410
|
+
constructor(attrs = {}) {
|
|
411
|
+
super(attrs);
|
|
412
|
+
this["_supplement"] = kind;
|
|
413
|
+
}
|
|
414
|
+
render() {
|
|
415
|
+
const self = this;
|
|
416
|
+
self["_supplement"] = kind;
|
|
417
|
+
if (kind === "fragment") {
|
|
418
|
+
return `${this.base?.toHuman() ?? ""} FRAG${this.number ?? ""}`;
|
|
419
|
+
}
|
|
420
|
+
return `${this.base?.toHuman() ?? ""}/${supplementToken(this)}`;
|
|
421
|
+
}
|
|
422
|
+
root() {
|
|
423
|
+
return this.base?.root() ?? this;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
registerType(CenSupplement);
|
|
427
|
+
return CenSupplement;
|
|
428
|
+
}
|
|
429
|
+
export const AmendmentClass = supplementClass("amendment", { year: { type: "string" } });
|
|
430
|
+
export const CorrigendumClass = supplementClass("corrigendum", { year: { type: "string" }, month: { type: "string" } });
|
|
431
|
+
export const FragmentClass = supplementClass("fragment", {});
|
|
432
|
+
export const ConsolidatedIdentifierClass = (() => {
|
|
433
|
+
class CenConsolidated extends CenIdentifier {
|
|
434
|
+
static polymorphicName = "pubid:cencenelec:consolidated-identifier";
|
|
435
|
+
static urnGenerator = CenUrnGenerator;
|
|
436
|
+
static get attributes() {
|
|
437
|
+
return extendAttributes(CenIdentifier, {
|
|
438
|
+
identifiers: { type: CenIdentifier, collection: true },
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
static get mappings() {
|
|
442
|
+
return [{ wire: "identifiers", to: "identifiers" }];
|
|
443
|
+
}
|
|
444
|
+
render() {
|
|
445
|
+
const [base, ...supplements] = this.identifiers;
|
|
446
|
+
return ((base?.toHuman() ?? "") +
|
|
447
|
+
supplements
|
|
448
|
+
.map((sub) => {
|
|
449
|
+
const self = sub;
|
|
450
|
+
return `+${supplementToken(sub)}`;
|
|
451
|
+
})
|
|
452
|
+
.join(""));
|
|
453
|
+
}
|
|
454
|
+
root() {
|
|
455
|
+
return this.identifiers[0]?.root() ?? this;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
registerType(CenConsolidated);
|
|
459
|
+
return CenConsolidated;
|
|
460
|
+
})();
|
|
461
|
+
export const AdoptedEuropeanNormClass = (() => {
|
|
462
|
+
class CenAdopted extends CenIdentifier {
|
|
463
|
+
static polymorphicName = "pubid:cencenelec:adopted-european-norm";
|
|
464
|
+
static urnGenerator = CenUrnGenerator;
|
|
465
|
+
static get attributes() {
|
|
466
|
+
return extendAttributes(CenIdentifier, {
|
|
467
|
+
publisher: { type: "string", default: "EN" },
|
|
468
|
+
adopted: { type: CenIdentifier },
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
static get mappings() {
|
|
472
|
+
return [
|
|
473
|
+
{ wire: "publisher", to: "publisher" },
|
|
474
|
+
{ wire: "copublishers", to: "copublishers" },
|
|
475
|
+
stageWire,
|
|
476
|
+
{ wire: "adopted", to: "adopted" },
|
|
477
|
+
];
|
|
478
|
+
}
|
|
479
|
+
render() {
|
|
480
|
+
return renderAdopted(this);
|
|
481
|
+
}
|
|
482
|
+
root() {
|
|
483
|
+
return this;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
registerType(CenAdopted);
|
|
487
|
+
return CenAdopted;
|
|
488
|
+
})();
|
|
489
|
+
export const EuropeanPrestandardClass = CEN_DOCUMENT_CLASSES.get("env");
|
|
490
|
+
export const EuropeanNormClass = CEN_DOCUMENT_CLASSES.get("en");
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Grammar } from "../../grammar/engine.js";
|
|
2
|
+
/** Parser.parse's preprocessing: strip, drop #-comments, collapse runs,
|
|
3
|
+
* insert the missing colon in "/E2007"-style language-years. */
|
|
4
|
+
export declare function preprocessCie(input: string): string;
|
|
5
|
+
export declare const cieGrammar: Grammar;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { match, ref, str } from "../../grammar/engine.js";
|
|
2
|
+
/**
|
|
3
|
+
* Port of lib/pubid/cie/parser.rb — the CIE grammar's 17 alternatives,
|
|
4
|
+
* longest/most-specific first (PEG ordered choice). The dual-style date
|
|
5
|
+
* era is carried by WHICH rule matched (current_date ":" vs
|
|
6
|
+
* legacy_date "-"), wrapped in its own marker so the builder can derive
|
|
7
|
+
* `style` without a separate separator field.
|
|
8
|
+
*/
|
|
9
|
+
function buildRules() {
|
|
10
|
+
const rules = {};
|
|
11
|
+
const rule = (name, build) => {
|
|
12
|
+
rules[name] = build();
|
|
13
|
+
};
|
|
14
|
+
const digit = match("[0-9]");
|
|
15
|
+
const digits = digit.repeat(1, Infinity);
|
|
16
|
+
const upper = match("[A-Z]");
|
|
17
|
+
const space = str(" ");
|
|
18
|
+
const dash = str("-");
|
|
19
|
+
const colon = str(":");
|
|
20
|
+
const dot = str(".");
|
|
21
|
+
const slash = str("/");
|
|
22
|
+
const comma = str(",");
|
|
23
|
+
// Year 1900-2099.
|
|
24
|
+
const yearDigits = str("19").or(str("20")).then(digit.repeat(2, 2));
|
|
25
|
+
rule("legacy_date", () => dash.then(yearDigits.as("year")).as("legacy_date"));
|
|
26
|
+
rule("current_date", () => colon.then(yearDigits.as("year")).as("current_date"));
|
|
27
|
+
rule("date", () => rules["current_date"].or(rules["legacy_date"]));
|
|
28
|
+
// Legacy NUMBER-YEAR ("001-1980"), optionally with "(RU-2020)".
|
|
29
|
+
rule("legacy_code_with_year", () => str("CIE").then(space, digits.as("number"), dash, yearDigits.as("year"), ref(rules, "language_paren_year").or(str("")).as("trailing_lang")));
|
|
30
|
+
rule("code_with_iteration", () => digits.as("number").then(dot, digits.as("iteration")));
|
|
31
|
+
rule("code_with_part_and_iteration_slash", () => digits.as("number").then(slash, digits.as("part"), dot, digits.as("iteration")));
|
|
32
|
+
rule("code_with_part_and_iteration_dash", () => digits
|
|
33
|
+
.as("number")
|
|
34
|
+
.then(dash, digits.as("part"), dot, digits.as("iteration"), dash.absent()));
|
|
35
|
+
// Part 1-3 digits, never a 4-digit year and never dot/dash after.
|
|
36
|
+
rule("code_with_part_dash", () => digits
|
|
37
|
+
.as("number")
|
|
38
|
+
.then(dash, digit.repeat(1, 3).as("part"), str("").as("dash_sep"), str("19").or(str("20")).absent(), dot.or(dash).absent()));
|
|
39
|
+
rule("code_with_part_slash", () => digits
|
|
40
|
+
.as("number")
|
|
41
|
+
.then(slash, digits.as("part"), str("").as("slash_sep"), dot.absent()));
|
|
42
|
+
rule("code_simple", () => digits.as("number"));
|
|
43
|
+
rule("code", () => rules["code_with_part_and_iteration_slash"]
|
|
44
|
+
.or(rules["code_with_part_and_iteration_dash"], rules["code_with_iteration"], rules["code_with_part_slash"], rules["code_with_part_dash"], rules["code_simple"]));
|
|
45
|
+
// Language formats: /E (slash), (DE) (paren), (RU-2021) (paren_year).
|
|
46
|
+
rule("language_slash", () => slash.then(upper.as("lang_code")).as("language_slash"));
|
|
47
|
+
rule("language_paren", () => str("(")
|
|
48
|
+
.then(match("[A-Za-z]").repeat(1, 3).as("lang_code"), str(")"))
|
|
49
|
+
.as("language_paren"));
|
|
50
|
+
rule("language_paren_year", () => space
|
|
51
|
+
.maybe()
|
|
52
|
+
.then(str("("), upper.repeat(2, Infinity).as("lang_code"), dash, yearDigits.as("trans_year"), str(")"))
|
|
53
|
+
.as("language_paren_year"));
|
|
54
|
+
rule("language", () => rules["language_paren_year"]
|
|
55
|
+
.or(rules["language_paren"], rules["language_slash"]));
|
|
56
|
+
const sPrefix = () => str("S").then(space);
|
|
57
|
+
const stageCode = () => str("FDIS").or(str("DIS"), str("DS")).then(space);
|
|
58
|
+
const docType = () => str("TR").or(str("TS"));
|
|
59
|
+
// Proceedings paper code: 1+ uppercase letters (OP, PO, PP, …).
|
|
60
|
+
const paperCode = () => match("[A-Z]").repeat(1, Infinity).as("paper_code");
|
|
61
|
+
// Techstreet opaque conference variant; lowercase-alnum so it cannot
|
|
62
|
+
// collide with /E, /Cor or /IEC tails.
|
|
63
|
+
rule("variant_slug", () => slash.then(match("[0-9a-z]").repeat(1, Infinity).as("variant")));
|
|
64
|
+
// "CIE x043-OP01".
|
|
65
|
+
rule("conf_proceedings", () => str("CIE").then(space, str("x"), digits.as("conf_number"), dash, paperCode(), digits.as("paper_number")));
|
|
66
|
+
// "CIE OP02 1-5".
|
|
67
|
+
rule("standalone_proceedings", () => str("CIE").then(space, paperCode(), digits.as("paper_number"), space, digits.then(dash, digits).as("page_range")));
|
|
68
|
+
rule("d_series_identifier", () => str("CIE").then(space, str("D").as("d_prefix"), digits.as("number"), rules["date"]));
|
|
69
|
+
// "CIE S 007/1998" — narrow number(+iteration) so part_slash can't
|
|
70
|
+
// greedily eat the /year.
|
|
71
|
+
rule("standard_with_slash_year", () => str("CIE").then(space, stageCode().maybe().as("stage"), sPrefix().maybe().as("s_prefix"), digits.as("number").then(dot.then(digits.as("iteration")).maybe()), slash, yearDigits.as("slash_year")));
|
|
72
|
+
// "DIS 025-SP1/E:2019".
|
|
73
|
+
rule("dis_with_supplement", () => str("CIE").then(space, stageCode().as("stage"), sPrefix().maybe().as("s_prefix"), digits.as("base_number"), dash, str("SP"), digits.as("supplement_number"), dot.then(digits.as("supplement_part")).maybe(), slash, upper.as("lang_code"), colon.as("lang_colon"), yearDigits.as("year")));
|
|
74
|
+
rule("standard_identifier", () => str("CIE").then(space, stageCode().maybe().as("stage"), sPrefix().maybe().as("s_prefix"), rules["code"], rules["language"]
|
|
75
|
+
.then(rules["date"])
|
|
76
|
+
.as("lang_before")
|
|
77
|
+
.or(rules["date"].then(rules["language"].maybe()).as("date_then_lang"), rules["date"])
|
|
78
|
+
.maybe()));
|
|
79
|
+
// "CIE S 014-4/E:2007" (language/year, no ISO reference).
|
|
80
|
+
rule("standard_with_language_year", () => str("CIE").then(space, stageCode().maybe().as("stage"), sPrefix().maybe().as("s_prefix"), rules["code"], slash, upper.as("lang_code"), colon.as("lang_colon"), yearDigits.as("year")));
|
|
81
|
+
rule("conference_identifier", () => str("CIE").then(space, str("x").as("conference"), digits.as("conf_number"), rules["date"], space.then(str("Amendment"), space, digits.as("amd_number")).maybe(), rules["variant_slug"].maybe()));
|
|
82
|
+
// "CIE ISO 11664-1:2019(E)" — the absent-guard rejects "ISO/CIE".
|
|
83
|
+
rule("joint_with_iso", () => str("CIE")
|
|
84
|
+
.then(space, str("ISO").as("copublisher"), slash.then(str("CIE")).absent(), space, docType().then(space).maybe().as("doc_type"), stageCode().maybe().as("stage"), digits.as("number"), dash.then(digits.as("part")).maybe(), colon.or(dash).then(yearDigits.as("year")).maybe(), rules["language"].maybe()));
|
|
85
|
+
rule("joint_with_iso_cie", () => str("CIE").then(space, str("ISO/CIE").as("copublisher"), space, docType().then(space).maybe().as("doc_type"), digits.as("number"), colon.then(yearDigits.as("year")).maybe(), rules["language"].maybe()));
|
|
86
|
+
// IEC always joins the part with a dot and the year with a dash.
|
|
87
|
+
rule("joint_with_iec", () => str("CIE").then(space, str("IEC").as("copublisher"), space, digits.as("number"), dot, digits.as("part"), dash, yearDigits.as("year")));
|
|
88
|
+
// "CIE S 008/E:2001 (ISO 8995-1:2002(E))".
|
|
89
|
+
rule("identical_with_iso", () => str("CIE").then(space, sPrefix().maybe().as("s_prefix"), digits.as("number"), dot.then(digits.as("iteration"))
|
|
90
|
+
.or(dash.then(digits.as("part")))
|
|
91
|
+
.maybe(), slash
|
|
92
|
+
.then(upper
|
|
93
|
+
.as("lang_code")
|
|
94
|
+
.then(colon.as("lang_colon"), yearDigits.as("year"))
|
|
95
|
+
.or(upper.as("lang_code").then(yearDigits.as("year")), yearDigits.as("slash_year")))
|
|
96
|
+
.maybe(), space, str("(ISO"), space, match("[0-9A-Z:/.\\-]")
|
|
97
|
+
.repeat(1, Infinity)
|
|
98
|
+
.then(str("(").then(match("[A-Z]").repeat(1, Infinity), str(")")).maybe())
|
|
99
|
+
.as("iso_reference"), str(")")));
|
|
100
|
+
// "CIE S 009:2002/IEC 62471:2006".
|
|
101
|
+
rule("dual_with_iec", () => str("CIE").then(space, sPrefix().maybe().as("s_prefix"), digits.as("number"), colon, yearDigits.as("year"), slash, str("IEC"), space, match("[^)\\n]").repeat(1, Infinity).as("iec_identifier")));
|
|
102
|
+
rule("supplement_identifier", () => str("CIE").then(space, digits.as("base_number"), dash, str("SP"), digits.as("supplement_number"), dot.then(digits.as("supplement_part")).maybe(), colon, yearDigits.as("year")));
|
|
103
|
+
rule("corrigendum_identifier", () => str("CIE")
|
|
104
|
+
.then(space, digits.as("base_number"), dash
|
|
105
|
+
.then(str("SP"), digits.as("base_supplement"), dot.then(digits.as("base_supplement_part")).maybe())
|
|
106
|
+
.maybe(), colon, yearDigits.as("base_year"), slash, str("Cor"), digits.as("cor_number"), colon, yearDigits.as("cor_year")));
|
|
107
|
+
rule("bundle_identifier", () => str("CIE").then(space, digits.as("first_number"), dash, str("SP"), digits, dot, digits, colon, yearDigits, comma.then(digits.as("next_number"), dash, str("SP"), digits, dot, digits, colon, yearDigits)
|
|
108
|
+
.repeat(1, Infinity)
|
|
109
|
+
.as("bundle_items")));
|
|
110
|
+
rule("tutorial_bundle", () => str("CIE Tutorials Bundle").then(space, digits.as("bundle_number")));
|
|
111
|
+
rule("identifier", () => rules["tutorial_bundle"]
|
|
112
|
+
.or(rules["bundle_identifier"], rules["joint_with_iso_cie"], rules["joint_with_iso"], rules["joint_with_iec"], rules["identical_with_iso"], rules["dis_with_supplement"], rules["dual_with_iec"], rules["corrigendum_identifier"], rules["supplement_identifier"], rules["standard_with_language_year"], rules["standard_with_slash_year"], rules["d_series_identifier"], rules["conf_proceedings"], rules["standalone_proceedings"],
|
|
113
|
+
// Before standard_identifier, to catch the 001-1980 pattern.
|
|
114
|
+
rules["legacy_code_with_year"], rules["conference_identifier"], rules["standard_identifier"]));
|
|
115
|
+
rule("root", () => rules["identifier"]);
|
|
116
|
+
return rules;
|
|
117
|
+
}
|
|
118
|
+
/** Parser.parse's preprocessing: strip, drop #-comments, collapse runs,
|
|
119
|
+
* insert the missing colon in "/E2007"-style language-years. */
|
|
120
|
+
export function preprocessCie(input) {
|
|
121
|
+
return input
|
|
122
|
+
.trim()
|
|
123
|
+
.replace(/\s*#.*$/, "")
|
|
124
|
+
.replace(/\s+/g, " ")
|
|
125
|
+
.replace(/\/(E|F|G|DE|ES|CN|RU|FR)(\d{4})/g, "/$1:$2");
|
|
126
|
+
}
|
|
127
|
+
export const cieGrammar = { rules: buildRules(), root: "root" };
|