@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,505 @@
|
|
|
1
|
+
import { BaseIdentifier, registerType } from "../../model/identifier.js";
|
|
2
|
+
import { keyValue, extendAttributes } from "../../model/attribute.js";
|
|
3
|
+
import { BaseUrnGenerator } from "../../model/urn-generator.js";
|
|
4
|
+
/**
|
|
5
|
+
* Port of lib/pubid/csa: SingleIdentifier (with the flat key_value
|
|
6
|
+
* wire), the single-document types (Standard, Series, Cec), the
|
|
7
|
+
* wrappers (CanadianAdopted, CsaAdopted), and the containers
|
|
8
|
+
* (Package, Bundled, Combined), plus the renderer and URN generator.
|
|
9
|
+
*/
|
|
10
|
+
const SINGLE_ATTRS = {
|
|
11
|
+
number: { type: "string" },
|
|
12
|
+
no_number: { type: "string" },
|
|
13
|
+
year: { type: "string" },
|
|
14
|
+
year_format: { type: "string" },
|
|
15
|
+
year_prefix: { type: "string" },
|
|
16
|
+
original_year_4digit: { type: "boolean", default: false },
|
|
17
|
+
french: { type: "boolean" },
|
|
18
|
+
reaffirmation: { type: "string" },
|
|
19
|
+
original_reaffirmation_4digit: { type: "boolean", default: false },
|
|
20
|
+
has_publisher: { type: "boolean" },
|
|
21
|
+
series_prefix: { type: "string" },
|
|
22
|
+
series: { type: "boolean" },
|
|
23
|
+
package: { type: "string" },
|
|
24
|
+
publisher_prefix: { type: "string" },
|
|
25
|
+
code_only: { type: "boolean", default: false },
|
|
26
|
+
};
|
|
27
|
+
const SINGLE_MAPPINGS = keyValue({ wire: "number", to: "number" }, { wire: "no_number", to: "no_number" }, { wire: "year", to: "year" }, { wire: "year_format", to: "year_format" }, { wire: "year_prefix", to: "year_prefix" }, { wire: "original_year_4digit", to: "original_year_4digit" }, { wire: "french", to: "french" }, { wire: "reaffirmation", to: "reaffirmation" }, { wire: "original_reaffirmation_4digit", to: "original_reaffirmation_4digit" }, { wire: "has_publisher", to: "has_publisher" }, { wire: "series_prefix", to: "series_prefix" }, { wire: "series", to: "series" }, { wire: "package", to: "package" }, { wire: "publisher_prefix", to: "publisher_prefix" }, { wire: "code_only", to: "code_only" });
|
|
28
|
+
export class CsaIdentifier extends BaseIdentifier {
|
|
29
|
+
root() {
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export class CsaSingleIdentifier extends CsaIdentifier {
|
|
34
|
+
static attributes = extendAttributes(BaseIdentifier, SINGLE_ATTRS);
|
|
35
|
+
static mappings = SINGLE_MAPPINGS;
|
|
36
|
+
}
|
|
37
|
+
// --- Renderer helpers ----------------------------------------------------------------
|
|
38
|
+
function publisherPrefixFor(id) {
|
|
39
|
+
if (id.code_only === true)
|
|
40
|
+
return "";
|
|
41
|
+
return id.publisher_prefix ?? "CSA";
|
|
42
|
+
}
|
|
43
|
+
function displayYear(id) {
|
|
44
|
+
const yearStr = id.year ?? "";
|
|
45
|
+
if (id.original_year_4digit === true)
|
|
46
|
+
return yearStr;
|
|
47
|
+
if (id.year_prefix !== undefined && /^[MF]$/.test(id.year_prefix)
|
|
48
|
+
&& yearStr.length === 4 && yearStr.startsWith("19")) {
|
|
49
|
+
return yearStr.slice(2);
|
|
50
|
+
}
|
|
51
|
+
if (yearStr.length === 4 && yearStr.startsWith("20"))
|
|
52
|
+
return yearStr.slice(2);
|
|
53
|
+
if (yearStr.length === 4 && yearStr.startsWith("19")) {
|
|
54
|
+
return yearStr.slice(2);
|
|
55
|
+
}
|
|
56
|
+
return yearStr;
|
|
57
|
+
}
|
|
58
|
+
function yearPortion(id) {
|
|
59
|
+
const separator = id.year_format === "dash" ? "-" : ":";
|
|
60
|
+
let part = separator;
|
|
61
|
+
if (id.year_prefix !== undefined)
|
|
62
|
+
part += id.year_prefix;
|
|
63
|
+
else if (id.french === true && id.year_format !== "dash")
|
|
64
|
+
part += "F";
|
|
65
|
+
return part + displayYear(id);
|
|
66
|
+
}
|
|
67
|
+
function renderReaffirmation(id, yearPrints4digit = false) {
|
|
68
|
+
const reaffirmationWas4digit = id.original_reaffirmation_4digit === true;
|
|
69
|
+
const value = id.reaffirmation ?? "";
|
|
70
|
+
const reaffirmationStr = reaffirmationWas4digit
|
|
71
|
+
? value
|
|
72
|
+
: value.length === 4 && (value.startsWith("19") || value.startsWith("20"))
|
|
73
|
+
? value.slice(2)
|
|
74
|
+
: value;
|
|
75
|
+
// The spacing follows the PRINTED year, not the parsed spelling: a
|
|
76
|
+
// 4-digit printed year glues ("C108.1.2-M1981(R2013)"), a 2-digit
|
|
77
|
+
// printed year takes a space ("C22.2 NO. 125-M84 (R2004)").
|
|
78
|
+
return yearPrints4digit || !reaffirmationWas4digit
|
|
79
|
+
? `(R${reaffirmationStr})`
|
|
80
|
+
: ` (R${reaffirmationStr})`;
|
|
81
|
+
}
|
|
82
|
+
function renderBase(id) {
|
|
83
|
+
const prefix = publisherPrefixFor(id);
|
|
84
|
+
const parts = [];
|
|
85
|
+
if (prefix !== "")
|
|
86
|
+
parts.push(prefix);
|
|
87
|
+
let codePart = id.number ?? "";
|
|
88
|
+
if (id.no_number !== undefined)
|
|
89
|
+
codePart += ` NO. ${id.no_number}`;
|
|
90
|
+
if (id.series_prefix !== undefined)
|
|
91
|
+
codePart += ` ${id.series_prefix} SERIES`;
|
|
92
|
+
else if (id.series === true)
|
|
93
|
+
codePart += " SERIES";
|
|
94
|
+
if (codePart !== "")
|
|
95
|
+
parts.push(codePart);
|
|
96
|
+
if (id.year !== undefined && parts.length > 0) {
|
|
97
|
+
parts[parts.length - 1] += yearPortion(id);
|
|
98
|
+
}
|
|
99
|
+
let result;
|
|
100
|
+
if (prefix !== "" && prefix.endsWith("-")) {
|
|
101
|
+
// No space after a dash-ending prefix (CAN/CSA-, CAN3-, CSA-).
|
|
102
|
+
result = parts.join("");
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
result = parts.join(" ");
|
|
106
|
+
}
|
|
107
|
+
if (id.reaffirmation !== undefined && id.reaffirmation !== "") {
|
|
108
|
+
result += renderReaffirmation(id, id.original_year_4digit === true);
|
|
109
|
+
}
|
|
110
|
+
if (id.package !== undefined)
|
|
111
|
+
result += id.package;
|
|
112
|
+
return result;
|
|
113
|
+
}
|
|
114
|
+
class CsaUrnGenerator extends BaseUrnGenerator {
|
|
115
|
+
generate() {
|
|
116
|
+
const id = this.identifier;
|
|
117
|
+
const parts = ["urn", "csa"];
|
|
118
|
+
const prefix = id.code_only === true
|
|
119
|
+
? ""
|
|
120
|
+
: id.publisher_prefix !== undefined
|
|
121
|
+
? id.publisher_prefix.toLowerCase()
|
|
122
|
+
: "csa";
|
|
123
|
+
parts.push(prefix);
|
|
124
|
+
if (id.number !== undefined)
|
|
125
|
+
parts.push(id.number);
|
|
126
|
+
if (id.no_number !== undefined)
|
|
127
|
+
parts.push(`no.${id.no_number}`);
|
|
128
|
+
if (id.series === true)
|
|
129
|
+
parts.push(`series.${id.series}`);
|
|
130
|
+
if (id.series_prefix !== undefined)
|
|
131
|
+
parts.push(`series.${id.series_prefix}`);
|
|
132
|
+
if (id.year !== undefined) {
|
|
133
|
+
let year = id.year;
|
|
134
|
+
if (year.length === 4 && year.startsWith("20"))
|
|
135
|
+
year = year.slice(2);
|
|
136
|
+
if (id.year_prefix !== undefined)
|
|
137
|
+
year = `${id.year_prefix}${year}`;
|
|
138
|
+
parts.push(year);
|
|
139
|
+
}
|
|
140
|
+
if (id.reaffirmation !== undefined)
|
|
141
|
+
parts.push(`reaff.${id.reaffirmation}`);
|
|
142
|
+
if (id.package !== undefined)
|
|
143
|
+
parts.push(`pkg.${id.package}`);
|
|
144
|
+
if (id.year_format === "dash")
|
|
145
|
+
parts.push("format.dash");
|
|
146
|
+
if (id.french === true)
|
|
147
|
+
parts.push("french");
|
|
148
|
+
return parts.join(":");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
void CsaUrnGenerator;
|
|
152
|
+
// --- The single-document types ---------------------------------------------------------
|
|
153
|
+
function singleClass(kind, render) {
|
|
154
|
+
class CsaConcrete extends CsaSingleIdentifier {
|
|
155
|
+
static polymorphicName = `pubid:csa:${kind}`;
|
|
156
|
+
static urnGenerator = CsaUrnGenerator;
|
|
157
|
+
render() {
|
|
158
|
+
return render(this);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
registerType(CsaConcrete);
|
|
162
|
+
return CsaConcrete;
|
|
163
|
+
}
|
|
164
|
+
export const StandardClass = singleClass("standard", renderBase);
|
|
165
|
+
export const SeriesClass = (() => {
|
|
166
|
+
class Series extends CsaSingleIdentifier {
|
|
167
|
+
static polymorphicName = "pubid:csa:series";
|
|
168
|
+
static urnGenerator = CsaUrnGenerator;
|
|
169
|
+
render() {
|
|
170
|
+
let result = publisherPrefixFor(this);
|
|
171
|
+
result = result === "" ? "" : (result.endsWith("-") ? result : `${result} `);
|
|
172
|
+
result += this.number ?? "";
|
|
173
|
+
result += " ";
|
|
174
|
+
if (this.series_prefix !== undefined && this.series_prefix !== "") {
|
|
175
|
+
result += `${this.series_prefix} `;
|
|
176
|
+
}
|
|
177
|
+
result += "SERIES";
|
|
178
|
+
if (this.year !== undefined) {
|
|
179
|
+
const separator = this.year_format === "dash" ? "-" : ":";
|
|
180
|
+
let part = separator;
|
|
181
|
+
if (this.year_prefix !== undefined)
|
|
182
|
+
part += this.year_prefix;
|
|
183
|
+
else if (this.french === true && this.year_format !== "dash")
|
|
184
|
+
part += "F";
|
|
185
|
+
const yearStr = this.year;
|
|
186
|
+
part += yearStr.length === 4 && yearStr.startsWith("20") ? yearStr.slice(2) : yearStr;
|
|
187
|
+
result += part;
|
|
188
|
+
}
|
|
189
|
+
if (this.reaffirmation !== undefined && this.reaffirmation !== "") {
|
|
190
|
+
result += renderReaffirmation(this);
|
|
191
|
+
}
|
|
192
|
+
return result;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
registerType(Series);
|
|
196
|
+
return Series;
|
|
197
|
+
})();
|
|
198
|
+
export const CecClass = (() => {
|
|
199
|
+
class Cec extends CsaSingleIdentifier {
|
|
200
|
+
static polymorphicName = "pubid:csa:cec";
|
|
201
|
+
static urnGenerator = CsaUrnGenerator;
|
|
202
|
+
static attributes = extendAttributes(CsaSingleIdentifier, {
|
|
203
|
+
cec_part: { type: "string" },
|
|
204
|
+
});
|
|
205
|
+
static mappings = [
|
|
206
|
+
...SINGLE_MAPPINGS,
|
|
207
|
+
{ wire: "cec_part", to: "cec_part" },
|
|
208
|
+
];
|
|
209
|
+
constructor(attrs = {}) {
|
|
210
|
+
super(attrs);
|
|
211
|
+
// Cec#number derives from its parts (the Ruby method override).
|
|
212
|
+
if (this.cec_part !== undefined && this.no_number !== undefined) {
|
|
213
|
+
this["number"] = `${this.cec_part}-${this.no_number}`;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
render() {
|
|
217
|
+
const prefix = publisherPrefixFor(this);
|
|
218
|
+
const parts = [];
|
|
219
|
+
if (prefix !== "")
|
|
220
|
+
parts.push(prefix);
|
|
221
|
+
if (this.cec_part !== undefined)
|
|
222
|
+
parts.push(this.cec_part);
|
|
223
|
+
parts.push("NO.");
|
|
224
|
+
if (this.no_number !== undefined)
|
|
225
|
+
parts.push(this.no_number);
|
|
226
|
+
let result;
|
|
227
|
+
if (prefix === "") {
|
|
228
|
+
result = parts.join(" ");
|
|
229
|
+
}
|
|
230
|
+
else if (!prefix.endsWith("-")) {
|
|
231
|
+
result = parts.join(" ");
|
|
232
|
+
}
|
|
233
|
+
else if (parts.length <= 2) {
|
|
234
|
+
result = parts.join("");
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
result = parts[0] + parts.slice(1).join(" ");
|
|
238
|
+
}
|
|
239
|
+
if (this.year !== undefined) {
|
|
240
|
+
const separator = this.year_format === "dash" ? "-" : ":";
|
|
241
|
+
let part = separator;
|
|
242
|
+
const yearStr = this.year;
|
|
243
|
+
const display = yearStr.length === 4 && (yearStr.startsWith("20") || yearStr.startsWith("19"))
|
|
244
|
+
? yearStr.slice(2)
|
|
245
|
+
: yearStr;
|
|
246
|
+
if (this.year_prefix !== undefined)
|
|
247
|
+
part += `${this.year_prefix}${display}`;
|
|
248
|
+
else if (this.french === true && this.year_format !== "dash")
|
|
249
|
+
part += `F${display}`;
|
|
250
|
+
else
|
|
251
|
+
part += display;
|
|
252
|
+
result += part;
|
|
253
|
+
}
|
|
254
|
+
if (this.reaffirmation !== undefined && this.reaffirmation !== "") {
|
|
255
|
+
result += renderReaffirmation(this);
|
|
256
|
+
}
|
|
257
|
+
return result;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
registerType(Cec);
|
|
261
|
+
return Cec;
|
|
262
|
+
})();
|
|
263
|
+
// --- The wrappers ---------------------------------------------------------------------
|
|
264
|
+
export const CanadianAdoptedClass = (() => {
|
|
265
|
+
class CanadianAdopted extends CsaIdentifier {
|
|
266
|
+
static polymorphicName = "pubid:csa:canadian-adopted";
|
|
267
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
268
|
+
base: { type: CsaIdentifier },
|
|
269
|
+
reaffirmation: { type: "string" },
|
|
270
|
+
original_reaffirmation_4digit: { type: "boolean", default: false },
|
|
271
|
+
year_format: { type: "string" },
|
|
272
|
+
});
|
|
273
|
+
static mappings = keyValue({ wire: "base", to: "base" }, { wire: "reaffirmation", to: "reaffirmation" }, { wire: "original_reaffirmation_4digit", to: "original_reaffirmation_4digit" }, { wire: "year_format", to: "year_format" });
|
|
274
|
+
root() {
|
|
275
|
+
return this.base?.root() ?? this;
|
|
276
|
+
}
|
|
277
|
+
render() {
|
|
278
|
+
const base = this.base;
|
|
279
|
+
const basePrefix = base?.publisher_prefix;
|
|
280
|
+
let result;
|
|
281
|
+
if (basePrefix === "CAN3-" || (basePrefix === "CAN/CSA-" && base instanceof SeriesClass)) {
|
|
282
|
+
result = base.toHuman();
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
result = `CAN/${base?.toHuman() ?? ""}`;
|
|
286
|
+
}
|
|
287
|
+
const baseReaffirm = base?.reaffirmation;
|
|
288
|
+
if (this.reaffirmation !== undefined && baseReaffirm === undefined) {
|
|
289
|
+
const yearWas2digit = base?.original_year_4digit !== true;
|
|
290
|
+
const was4digit = this.original_reaffirmation_4digit === true;
|
|
291
|
+
const value = this.reaffirmation;
|
|
292
|
+
const reaffirmationStr = was4digit
|
|
293
|
+
? value
|
|
294
|
+
: value.length === 4 && (value.startsWith("19") || value.startsWith("20"))
|
|
295
|
+
? value.slice(2)
|
|
296
|
+
: value;
|
|
297
|
+
result += yearWas2digit && was4digit ? ` (R${reaffirmationStr})` : `(R${reaffirmationStr})`;
|
|
298
|
+
}
|
|
299
|
+
return result;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
registerType(CanadianAdopted);
|
|
303
|
+
return CanadianAdopted;
|
|
304
|
+
})();
|
|
305
|
+
export const CsaAdoptedClass = (() => {
|
|
306
|
+
class CsaAdopted extends CsaIdentifier {
|
|
307
|
+
static polymorphicName = "pubid:csa:csa-adopted";
|
|
308
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
309
|
+
base: { type: CsaIdentifier },
|
|
310
|
+
reaffirmation: { type: "string" },
|
|
311
|
+
original_reaffirmation_4digit: { type: "boolean", default: false },
|
|
312
|
+
year_format: { type: "string" },
|
|
313
|
+
publisher_prefix: { type: "string" },
|
|
314
|
+
});
|
|
315
|
+
static mappings = keyValue({ wire: "base", to: "base" }, { wire: "reaffirmation", to: "reaffirmation" }, { wire: "original_reaffirmation_4digit", to: "original_reaffirmation_4digit" }, { wire: "year_format", to: "year_format" }, { wire: "publisher_prefix", to: "publisher_prefix" });
|
|
316
|
+
root() {
|
|
317
|
+
return this.base?.root() ?? this;
|
|
318
|
+
}
|
|
319
|
+
render() {
|
|
320
|
+
let baseStr = this.base?.toHuman() ?? "";
|
|
321
|
+
const yearMatch = baseStr.match(/:(\d{4})\b/);
|
|
322
|
+
if (yearMatch !== null) {
|
|
323
|
+
const year = yearMatch[1];
|
|
324
|
+
if (year.startsWith("20") || year.startsWith("19")) {
|
|
325
|
+
baseStr = baseStr.replace(`:${year}`, `:${year.slice(2)}`);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
baseStr = baseStr.replace(/\/Amd\s+(\d+)([:/-])(\d{2,4})\b/g, (_m, num, sep, year) => {
|
|
329
|
+
const short = year.length === 4 && (year.startsWith("20") || year.startsWith("19"))
|
|
330
|
+
? year.slice(2)
|
|
331
|
+
: year;
|
|
332
|
+
return `/A${num}${sep}${short}`;
|
|
333
|
+
});
|
|
334
|
+
let result;
|
|
335
|
+
if (this.publisher_prefix !== undefined && this.publisher_prefix.endsWith("-")) {
|
|
336
|
+
result = `${this.publisher_prefix}${baseStr}`;
|
|
337
|
+
}
|
|
338
|
+
else {
|
|
339
|
+
result = `CSA ${baseStr}`;
|
|
340
|
+
}
|
|
341
|
+
if (this.reaffirmation !== undefined)
|
|
342
|
+
result += ` (R${this.reaffirmation})`;
|
|
343
|
+
return result;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
registerType(CsaAdopted);
|
|
347
|
+
return CsaAdopted;
|
|
348
|
+
})();
|
|
349
|
+
// --- The containers --------------------------------------------------------------------
|
|
350
|
+
export const PackageClass = (() => {
|
|
351
|
+
class Package extends CsaIdentifier {
|
|
352
|
+
static polymorphicName = "pubid:csa:package";
|
|
353
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
354
|
+
base: { type: CsaIdentifier },
|
|
355
|
+
package_materials: { type: "string" },
|
|
356
|
+
package_keyword: { type: "string" },
|
|
357
|
+
materials_after_keyword: { type: "boolean", default: true },
|
|
358
|
+
});
|
|
359
|
+
static mappings = keyValue({ wire: "base", to: "base" }, { wire: "package_materials", to: "package_materials" }, { wire: "package_keyword", to: "package_keyword" }, { wire: "materials_after_keyword", to: "materials_after_keyword" });
|
|
360
|
+
root() {
|
|
361
|
+
return this.base?.root() ?? this;
|
|
362
|
+
}
|
|
363
|
+
render() {
|
|
364
|
+
let result = this.base?.toHuman() ?? "";
|
|
365
|
+
if (this.package_materials !== undefined && this.package_materials !== "") {
|
|
366
|
+
if (this.materials_after_keyword === true) {
|
|
367
|
+
result += " PACKAGE";
|
|
368
|
+
result += ` ${this.package_materials}`;
|
|
369
|
+
}
|
|
370
|
+
else if (/\sPACKAGE\s*$/i.test(this.package_materials)) {
|
|
371
|
+
result += ` ${this.package_materials}`;
|
|
372
|
+
}
|
|
373
|
+
else {
|
|
374
|
+
result += ` ${this.package_materials}`;
|
|
375
|
+
result += ` ${this.package_keyword}`;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
result += " PACKAGE";
|
|
380
|
+
}
|
|
381
|
+
return result;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
registerType(Package);
|
|
385
|
+
return Package;
|
|
386
|
+
})();
|
|
387
|
+
export const BundledClass = (() => {
|
|
388
|
+
class Bundled extends CsaIdentifier {
|
|
389
|
+
static polymorphicName = "pubid:csa:bundled";
|
|
390
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
391
|
+
base: { type: CsaIdentifier },
|
|
392
|
+
bundled_with: { type: CsaIdentifier, collection: true },
|
|
393
|
+
reaffirmation: { type: "string" },
|
|
394
|
+
original_reaffirmation_4digit: { type: "boolean", default: false },
|
|
395
|
+
year_format: { type: "string" },
|
|
396
|
+
});
|
|
397
|
+
static mappings = keyValue({ wire: "base", to: "base" }, { wire: "bundled_with", to: "bundled_with" }, { wire: "reaffirmation", to: "reaffirmation" }, { wire: "original_reaffirmation_4digit", to: "original_reaffirmation_4digit" }, { wire: "year_format", to: "year_format" });
|
|
398
|
+
root() {
|
|
399
|
+
return this.base?.root() ?? this;
|
|
400
|
+
}
|
|
401
|
+
render() {
|
|
402
|
+
const baseSingle = this.base;
|
|
403
|
+
const parts = [];
|
|
404
|
+
if (baseSingle !== undefined && baseSingle.constructor === CecClass) {
|
|
405
|
+
// Bundled renders a Cec base through its normalized code, with
|
|
406
|
+
// no "NO." (bundled.rb).
|
|
407
|
+
const prefix = baseSingle.publisher_prefix ?? "CSA";
|
|
408
|
+
const needsSpace = !prefix.endsWith("-");
|
|
409
|
+
let yearDisplay;
|
|
410
|
+
if (baseSingle.year !== undefined) {
|
|
411
|
+
const yearStr = baseSingle.year;
|
|
412
|
+
yearDisplay = yearStr.length === 4 && yearStr.startsWith("20") ? yearStr.slice(2) : yearStr;
|
|
413
|
+
}
|
|
414
|
+
parts.push(`${needsSpace ? `${prefix} ` : prefix}${baseSingle.number ?? ""}:${yearDisplay ?? ""}`);
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
parts.push(this.base?.toHuman() ?? "");
|
|
418
|
+
}
|
|
419
|
+
for (const bundled of this.bundled_with ?? []) {
|
|
420
|
+
const single = bundled;
|
|
421
|
+
parts.push(renderBundledPortion(single));
|
|
422
|
+
}
|
|
423
|
+
let result = parts.join(" + ");
|
|
424
|
+
if (this.reaffirmation !== undefined) {
|
|
425
|
+
const baseSingle = this.base;
|
|
426
|
+
const yearWas2digit = baseSingle?.original_year_4digit !== true;
|
|
427
|
+
const was4digit = this.reaffirmation.length === 4
|
|
428
|
+
&& (this.reaffirmation.startsWith("19") || this.reaffirmation.startsWith("20"));
|
|
429
|
+
result += yearWas2digit && was4digit
|
|
430
|
+
? ` (R${this.reaffirmation})`
|
|
431
|
+
: `(R${this.reaffirmation})`;
|
|
432
|
+
}
|
|
433
|
+
return result;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
registerType(Bundled);
|
|
437
|
+
return Bundled;
|
|
438
|
+
})();
|
|
439
|
+
function renderBundledPortion(id) {
|
|
440
|
+
let part = id.number ?? "";
|
|
441
|
+
if (id.year !== undefined)
|
|
442
|
+
part += yearPortion(id);
|
|
443
|
+
return part;
|
|
444
|
+
}
|
|
445
|
+
export const CombinedClass = (() => {
|
|
446
|
+
class Combined extends CsaIdentifier {
|
|
447
|
+
static polymorphicName = "pubid:csa:combined";
|
|
448
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
449
|
+
identifiers: { type: CsaIdentifier, collection: true },
|
|
450
|
+
reaffirmation: { type: "string" },
|
|
451
|
+
original_reaffirmation_4digit: { type: "boolean", default: false },
|
|
452
|
+
package: { type: "string" },
|
|
453
|
+
year_format: { type: "string" },
|
|
454
|
+
separator: { type: "string", default: "/" },
|
|
455
|
+
});
|
|
456
|
+
static mappings = keyValue({ wire: "identifiers", to: "identifiers" }, { wire: "reaffirmation", to: "reaffirmation" }, { wire: "original_reaffirmation_4digit", to: "original_reaffirmation_4digit" }, { wire: "package", to: "package" }, { wire: "year_format", to: "year_format" }, { wire: "separator", to: "separator" });
|
|
457
|
+
root() {
|
|
458
|
+
return this.identifiers?.[0]?.root() ?? this;
|
|
459
|
+
}
|
|
460
|
+
render() {
|
|
461
|
+
const ids = this.identifiers ?? [];
|
|
462
|
+
const parts = (this.separator === ", ")
|
|
463
|
+
? ids.map((i) => i.toHuman())
|
|
464
|
+
: ids.map((i, index) => (index === 0 ? i.toHuman() : renderContinuation(i)));
|
|
465
|
+
let result = parts.join(this.separator ?? "/");
|
|
466
|
+
if (this.reaffirmation !== undefined) {
|
|
467
|
+
const primary = ids[0];
|
|
468
|
+
const yearWas2digit = primary?.original_year_4digit !== true;
|
|
469
|
+
const was4digit = this.reaffirmation.length === 4
|
|
470
|
+
&& (this.reaffirmation.startsWith("19") || this.reaffirmation.startsWith("20"));
|
|
471
|
+
result += yearWas2digit && was4digit
|
|
472
|
+
? ` (R${this.reaffirmation})`
|
|
473
|
+
: `(R${this.reaffirmation})`;
|
|
474
|
+
}
|
|
475
|
+
if (this.package !== undefined)
|
|
476
|
+
result += this.package;
|
|
477
|
+
return result;
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
registerType(Combined);
|
|
481
|
+
return Combined;
|
|
482
|
+
})();
|
|
483
|
+
function renderContinuation(id) {
|
|
484
|
+
const parts = [];
|
|
485
|
+
if (id.has_publisher === true) {
|
|
486
|
+
parts.push(id.publisher_prefix ?? "CSA");
|
|
487
|
+
}
|
|
488
|
+
let codePart = id.number ?? "";
|
|
489
|
+
if (id.no_number !== undefined)
|
|
490
|
+
codePart += ` NO. ${id.no_number}`;
|
|
491
|
+
if (id.series_prefix !== undefined)
|
|
492
|
+
codePart += ` ${id.series_prefix} SERIES`;
|
|
493
|
+
else if (id.series === true)
|
|
494
|
+
codePart += " SERIES";
|
|
495
|
+
if (id.year !== undefined)
|
|
496
|
+
codePart += yearPortion(id);
|
|
497
|
+
if (codePart !== "")
|
|
498
|
+
parts.push(codePart);
|
|
499
|
+
if (id.has_publisher === true && parts.length > 1) {
|
|
500
|
+
const prefix = parts[0];
|
|
501
|
+
return prefix.endsWith("-") ? prefix + parts.slice(1).join(" ") : parts.join(" ");
|
|
502
|
+
}
|
|
503
|
+
return parts.join(" ");
|
|
504
|
+
}
|
|
505
|
+
// --- The URN generator ------------------------------------------------------------------
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Grammar } from "../../grammar/engine.js";
|
|
2
|
+
import type { FlavorImplementation } from "../../conformance/implementation.js";
|
|
3
|
+
import { BaseIdentifier } from "../../model/identifier.js";
|
|
4
|
+
export declare const doiGrammar: Grammar;
|
|
5
|
+
export declare class DoiIdentifier extends BaseIdentifier {
|
|
6
|
+
static polymorphicName: string;
|
|
7
|
+
static attributes: import("../../model/attribute.js").AttributeTable;
|
|
8
|
+
static mappings: import("../../model/attribute.js").FieldMapping[];
|
|
9
|
+
render(): string;
|
|
10
|
+
readonly prefix: string;
|
|
11
|
+
readonly suffix: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function doiGrammarImplementation(): FlavorImplementation;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { match, str } from "../../grammar/engine.js";
|
|
2
|
+
import { ParseFailed, parseGrammar } from "../../grammar/engine.js";
|
|
3
|
+
import { BaseIdentifier, registerType } from "../../model/identifier.js";
|
|
4
|
+
import { extendAttributes, keyValue } from "../../model/attribute.js";
|
|
5
|
+
import { BaseBuilder } from "../../model/builder.js";
|
|
6
|
+
/**
|
|
7
|
+
* 1:1 port of lib/pubid/doi/ on the unified model. DOIs per ISO 26324;
|
|
8
|
+
* the Ruby flavor has no urn_generator, so toUrn() resolves to the base
|
|
9
|
+
* template ("urn:doi" — no attribute hits a template slot).
|
|
10
|
+
*/
|
|
11
|
+
function buildRules() {
|
|
12
|
+
const rules = {};
|
|
13
|
+
const rule = (name, build) => {
|
|
14
|
+
rules[name] = build();
|
|
15
|
+
};
|
|
16
|
+
const slash = str("/");
|
|
17
|
+
rule("url_prefix", () => str("https://").or(str("http://")).maybe().then(str("doi.org").maybe()));
|
|
18
|
+
rule("scheme_prefix", () => str("doi:").or(str("DOI:")).or(str("Doi:")).maybe());
|
|
19
|
+
const dot = str(".");
|
|
20
|
+
rule("prefix", () => str("10").then(dot, match("[0-9]").repeat(2, Infinity).as("prefix_digits")));
|
|
21
|
+
rule("suffix", () => match("[A-Za-z0-9._\\-/()]").repeat(1, Infinity).as("suffix"));
|
|
22
|
+
rule("identifier", () => rules["url_prefix"]
|
|
23
|
+
.maybe()
|
|
24
|
+
.then(rules["scheme_prefix"].maybe(), slash.maybe(), rules["prefix"], slash, rules["suffix"]));
|
|
25
|
+
rule("root", () => rules["identifier"]);
|
|
26
|
+
return rules;
|
|
27
|
+
}
|
|
28
|
+
export const doiGrammar = {
|
|
29
|
+
rules: buildRules(),
|
|
30
|
+
root: "root",
|
|
31
|
+
};
|
|
32
|
+
export class DoiIdentifier extends BaseIdentifier {
|
|
33
|
+
static polymorphicName = "pubid:doi:resource";
|
|
34
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
35
|
+
prefix: { type: "string" },
|
|
36
|
+
suffix: { type: "string" },
|
|
37
|
+
});
|
|
38
|
+
static mappings = keyValue({ wire: "prefix", to: "prefix" }, { wire: "suffix", to: "suffix" });
|
|
39
|
+
render() {
|
|
40
|
+
return `doi:${this.prefix}/${this.suffix}`;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
registerType(DoiIdentifier);
|
|
44
|
+
class DoiBuilder extends BaseBuilder {
|
|
45
|
+
defaultIdentifierClass() {
|
|
46
|
+
return DoiIdentifier;
|
|
47
|
+
}
|
|
48
|
+
cast(key, value) {
|
|
49
|
+
if (key === "prefix_digits")
|
|
50
|
+
return { prefix: `10.${String(value)}` };
|
|
51
|
+
return value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function doiGrammarImplementation() {
|
|
55
|
+
const builder = new DoiBuilder();
|
|
56
|
+
return {
|
|
57
|
+
parse(input) {
|
|
58
|
+
const tree = parseGrammar(doiGrammar, input);
|
|
59
|
+
if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
|
|
60
|
+
throw new ParseFailed("DOI: unexpected parse tree", 0);
|
|
61
|
+
}
|
|
62
|
+
return builder.build(tree);
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|