@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,21 @@
|
|
|
1
|
+
import { Grammar } from "../../grammar/engine.js";
|
|
2
|
+
import type { FlavorImplementation } from "../../conformance/implementation.js";
|
|
3
|
+
import { BaseIdentifier } from "../../model/identifier.js";
|
|
4
|
+
import { BaseUrnGenerator } from "../../model/urn-generator.js";
|
|
5
|
+
import { PubidDate } from "../../model/component.js";
|
|
6
|
+
export declare const calconnectGrammar: Grammar;
|
|
7
|
+
declare class CalconnectUrnGenerator extends BaseUrnGenerator<CalconnectIdentifier> {
|
|
8
|
+
generate(): string;
|
|
9
|
+
}
|
|
10
|
+
export declare class CalconnectIdentifier extends BaseIdentifier {
|
|
11
|
+
static polymorphicName: string;
|
|
12
|
+
static attributes: import("../../model/attribute.js").AttributeTable;
|
|
13
|
+
static mappings: import("../../model/attribute.js").FieldMapping[];
|
|
14
|
+
static urnGenerator: typeof CalconnectUrnGenerator;
|
|
15
|
+
readonly series: string | undefined;
|
|
16
|
+
readonly number: string;
|
|
17
|
+
readonly date: PubidDate | undefined;
|
|
18
|
+
render(): string;
|
|
19
|
+
}
|
|
20
|
+
export declare function calconnectGrammarImplementation(): FlavorImplementation;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
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 { BaseUrnGenerator } from "../../model/urn-generator.js";
|
|
6
|
+
import { BaseBuilder } from "../../model/builder.js";
|
|
7
|
+
import { PubidDate } from "../../model/component.js";
|
|
8
|
+
/**
|
|
9
|
+
* Port of lib/pubid/calconnect/ on the unified model — the flavor that
|
|
10
|
+
* motivated it. Shape: CC[/<series>] <number>[:<date>]. The publication
|
|
11
|
+
* date is a PubidDate serialized FLAT as year/month/day through three
|
|
12
|
+
* converter mappings (Ruby's `map "year", with: {to: :year_to_kv}` trio);
|
|
13
|
+
* a partial (date-less) reference simply has no date attribute. URN:
|
|
14
|
+
* urn:calconnect[:<series>]:<number>[:<full date>].
|
|
15
|
+
*/
|
|
16
|
+
function buildRules() {
|
|
17
|
+
const rules = {};
|
|
18
|
+
const rule = (name, build) => {
|
|
19
|
+
rules[name] = build();
|
|
20
|
+
};
|
|
21
|
+
const digits = match("[0-9]").repeat(1, Infinity);
|
|
22
|
+
const series = match("[A-Za-z]").repeat(1, Infinity).as("series");
|
|
23
|
+
rule("series", () => series);
|
|
24
|
+
rule("number", () => digits.then(str(".").or(str("-")).then(digits).maybe()).as("number"));
|
|
25
|
+
rule("date", () => digits.as("year").then(str("-").then(digits.as("month"), str("-"), digits.as("day")).maybe()));
|
|
26
|
+
rule("identifier", () => str("CC")
|
|
27
|
+
.then(str("/").then(series).maybe())
|
|
28
|
+
.then(str(" "), rules["number"])
|
|
29
|
+
.then(str(":").then(rules["date"]).maybe()));
|
|
30
|
+
rule("root", () => rules["identifier"]);
|
|
31
|
+
return rules;
|
|
32
|
+
}
|
|
33
|
+
export const calconnectGrammar = { rules: buildRules(), root: "root" };
|
|
34
|
+
class CalconnectUrnGenerator extends BaseUrnGenerator {
|
|
35
|
+
generate() {
|
|
36
|
+
const id = this.identifier;
|
|
37
|
+
const parts = ["urn", "calconnect"];
|
|
38
|
+
if (id.series !== undefined)
|
|
39
|
+
parts.push(id.series);
|
|
40
|
+
parts.push(id.number);
|
|
41
|
+
const date = id.date?.render();
|
|
42
|
+
if (date !== undefined && date !== "")
|
|
43
|
+
parts.push(date);
|
|
44
|
+
return parts.join(":");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
export class CalconnectIdentifier extends BaseIdentifier {
|
|
48
|
+
static polymorphicName = "pubid:calconnect:standard";
|
|
49
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
50
|
+
series: { type: "string" },
|
|
51
|
+
number: { type: "string" },
|
|
52
|
+
});
|
|
53
|
+
static mappings = keyValue({ wire: "series", to: "series" }, { wire: "number", to: "number" }, {
|
|
54
|
+
wire: "year",
|
|
55
|
+
to: "date",
|
|
56
|
+
toWire: (m) => m["date"]?.year,
|
|
57
|
+
fromWire: (h) => h["year"] === undefined || h["year"] === null
|
|
58
|
+
? undefined
|
|
59
|
+
: new PubidDate({
|
|
60
|
+
year: String(h["year"]),
|
|
61
|
+
month: h["month"],
|
|
62
|
+
day: h["day"],
|
|
63
|
+
}),
|
|
64
|
+
}, { wire: "month", to: "date", toWire: (m) => m["date"]?.month, fromWire: () => undefined }, { wire: "day", to: "date", toWire: (m) => m["date"]?.day, fromWire: () => undefined });
|
|
65
|
+
static urnGenerator = CalconnectUrnGenerator;
|
|
66
|
+
render() {
|
|
67
|
+
const prefix = this.series === undefined ? "CC " : `CC/${this.series} `;
|
|
68
|
+
const date = this.date?.render();
|
|
69
|
+
return `${prefix}${this.number}${date === undefined || date === "" ? "" : `:${date}`}`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
registerType(CalconnectIdentifier);
|
|
73
|
+
class CalconnectBuilder extends BaseBuilder {
|
|
74
|
+
defaultIdentifierClass() {
|
|
75
|
+
return CalconnectIdentifier;
|
|
76
|
+
}
|
|
77
|
+
cast(key, value) {
|
|
78
|
+
// The date needs year+month+day combined; assembled in build().
|
|
79
|
+
if (key === "year" || key === "month" || key === "day")
|
|
80
|
+
return null;
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
build(data) {
|
|
84
|
+
const flat = Array.isArray(data) ? Object.assign({}, ...data) : data;
|
|
85
|
+
const attrs = {};
|
|
86
|
+
if (flat["series"] !== undefined && flat["series"] !== null)
|
|
87
|
+
attrs["series"] = String(flat["series"]);
|
|
88
|
+
if (flat["number"] === undefined || flat["number"] === null) {
|
|
89
|
+
throw new ParseFailed("CalConnect: no number", 0);
|
|
90
|
+
}
|
|
91
|
+
attrs["number"] = String(flat["number"]);
|
|
92
|
+
if (flat["year"] !== undefined && flat["year"] !== null) {
|
|
93
|
+
attrs["date"] = new PubidDate({
|
|
94
|
+
year: String(flat["year"]),
|
|
95
|
+
month: flat["month"] === undefined || flat["month"] === null ? undefined : String(flat["month"]),
|
|
96
|
+
day: flat["day"] === undefined || flat["day"] === null ? undefined : String(flat["day"]),
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return new CalconnectIdentifier(attrs);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function calconnectGrammarImplementation() {
|
|
103
|
+
const builder = new CalconnectBuilder();
|
|
104
|
+
return {
|
|
105
|
+
parse(input) {
|
|
106
|
+
const tree = parseGrammar(calconnectGrammar, input);
|
|
107
|
+
if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
|
|
108
|
+
throw new ParseFailed("CalConnect: unexpected parse tree", 0);
|
|
109
|
+
}
|
|
110
|
+
return builder.build(tree);
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { match, ref, str } from "../../grammar/engine.js";
|
|
2
|
+
/**
|
|
3
|
+
* Port of lib/pubid/cen_cenelec/parser.rb — 1:1. Root alternation:
|
|
4
|
+
* fragment_identifier | (stage_prefix|publisher) adopted? type? number
|
|
5
|
+
* supplements? edition?.
|
|
6
|
+
*/
|
|
7
|
+
function buildRules() {
|
|
8
|
+
const rules = {};
|
|
9
|
+
const rule = (name, build) => {
|
|
10
|
+
rules[name] = build();
|
|
11
|
+
};
|
|
12
|
+
const digit = match("[0-9]");
|
|
13
|
+
const digits = digit.repeat(1, Infinity);
|
|
14
|
+
const space = str(" ");
|
|
15
|
+
const dash = str("-");
|
|
16
|
+
const slash = str("/");
|
|
17
|
+
const plus = str("+");
|
|
18
|
+
const colon = str(":");
|
|
19
|
+
const anyChar = match("[\\s\\S]");
|
|
20
|
+
const publisherToken = (name) => str(name);
|
|
21
|
+
rule("publisher", () => publisherToken("CWA").or(publisherToken("HD"), publisherToken("ES"), publisherToken("CR"), publisherToken("ENV")).as("publisher")
|
|
22
|
+
.or(publisherToken("EN").as("publisher").then(slash.then(publisherToken("CLC").as("copublisher")).maybe()))
|
|
23
|
+
.or(publisherToken("CEN").as("publisher").then(slash.then(publisherToken("CLC").as("copublisher")).maybe()))
|
|
24
|
+
.or(publisherToken("CLC").as("publisher").then(slash.then(publisherToken("CEN").as("copublisher")).maybe()))
|
|
25
|
+
.or(publisherToken("EN").as("publisher")));
|
|
26
|
+
rule("stage_prefix", () => str("FprEN").or(str("prEN")).as("type_with_stage"));
|
|
27
|
+
rule("type", () => str("Guide").or(str("GUIDE"), str("TR"), str("TS")).as("type"));
|
|
28
|
+
rule("number", () => digits.as("number"));
|
|
29
|
+
rule("part", () => dash.then(match("[0-9-]").repeat(1, Infinity).as("part")));
|
|
30
|
+
rule("parts", () => ref(rules, "part").repeat(0, Infinity).as("parts"));
|
|
31
|
+
rule("year", () => colon.then(digit.repeat(4, 4).as("year")));
|
|
32
|
+
rule("month_digits", () => str("01").or(str("02"), str("03"), str("04"), str("05"), str("06"), str("07"), str("08"), str("09"), str("10"), str("11"), str("12")).as("month"));
|
|
33
|
+
rule("year_with_month", () => colon.then(digit.repeat(4, 4).as("year")).then(dash).then(ref(rules, "month_digits")));
|
|
34
|
+
rule("date", () => ref(rules, "year_with_month").or(ref(rules, "year")));
|
|
35
|
+
rule("amendment", () => plus.as("amd_sep_plus").or(slash.as("amd_sep_slash"))
|
|
36
|
+
.then(str("A"))
|
|
37
|
+
.then(digits.as("amd_number"))
|
|
38
|
+
.then(colon.then(digit.repeat(4, 4).as("amd_year")).maybe()));
|
|
39
|
+
rule("corrigendum", () => plus.as("amd_sep_plus").or(slash.as("amd_sep_slash"))
|
|
40
|
+
.then(str("AC"))
|
|
41
|
+
.then(digits.maybe().as("cor_number"))
|
|
42
|
+
.then(ref(rules, "year_with_month")
|
|
43
|
+
.or(colon.then(digit.repeat(4, 4).as("year")))
|
|
44
|
+
.maybe()));
|
|
45
|
+
rule("supplement", () => ref(rules, "amendment").or(ref(rules, "corrigendum")).as("supplement"));
|
|
46
|
+
rule("supplements", () => ref(rules, "supplement").repeat(0, Infinity).as("supplements"));
|
|
47
|
+
rule("edition", () => space.then(str("ED")).then(digits.as("edition")));
|
|
48
|
+
rule("fragment_identifier", () =>
|
|
49
|
+
// Spelled-out keyword form: EN 60038 AMD1 FRAG2.
|
|
50
|
+
ref(rules, "stage_prefix").or(ref(rules, "publisher"))
|
|
51
|
+
.then(space)
|
|
52
|
+
.then(ref(rules, "number"))
|
|
53
|
+
.then(ref(rules, "parts"))
|
|
54
|
+
.then(space)
|
|
55
|
+
.then(str("AMD"))
|
|
56
|
+
.then(digits.as("amendment_number"))
|
|
57
|
+
.then(space)
|
|
58
|
+
.then(str("FRAG"))
|
|
59
|
+
.then(digits.as("fragment_number"))
|
|
60
|
+
.or(
|
|
61
|
+
// Compact supplement notation: the base may carry a year, the
|
|
62
|
+
// amendment uses the /A1 or +A1 join (with an optional year of
|
|
63
|
+
// its own) instead of the spelled-out keyword.
|
|
64
|
+
ref(rules, "stage_prefix").or(ref(rules, "publisher"))
|
|
65
|
+
.then(space)
|
|
66
|
+
.then(ref(rules, "number"))
|
|
67
|
+
.then(ref(rules, "parts"))
|
|
68
|
+
.then((ref(rules, "year")).maybe())
|
|
69
|
+
.then(str("/").or(str("+")))
|
|
70
|
+
.then(str("A"))
|
|
71
|
+
.then(digits.as("amendment_number"))
|
|
72
|
+
.then((str(":").then(digits.as("amendment_year"))).maybe())
|
|
73
|
+
.then(space)
|
|
74
|
+
.then(str("FRAG"))
|
|
75
|
+
.then(digits.as("fragment_number"))));
|
|
76
|
+
rule("adopted_org_prefix", () => str("ISO").or(str("IEC"), str("CISPR")));
|
|
77
|
+
rule("adopted_string", () => ref(rules, "adopted_org_prefix")
|
|
78
|
+
.then(ref(rules, "supplement").absent()
|
|
79
|
+
.then(ref(rules, "edition").absent())
|
|
80
|
+
.then(anyChar)
|
|
81
|
+
.repeat(0, Infinity))
|
|
82
|
+
.as("adopted_string"));
|
|
83
|
+
rule("identifier", () => ref(rules, "fragment_identifier").or(ref(rules, "stage_prefix").or(ref(rules, "publisher"))
|
|
84
|
+
.then(space.then(ref(rules, "adopted_string")).maybe())
|
|
85
|
+
.then(space.then(ref(rules, "type")).or(slash.then(ref(rules, "type"))).maybe())
|
|
86
|
+
.then(space.then(ref(rules, "number")).then(ref(rules, "parts"))
|
|
87
|
+
.then(ref(rules, "year").maybe())
|
|
88
|
+
.maybe())
|
|
89
|
+
.then(ref(rules, "supplements"))
|
|
90
|
+
.then(ref(rules, "edition").maybe())));
|
|
91
|
+
return rules;
|
|
92
|
+
}
|
|
93
|
+
export const cenCenelecGrammar = {
|
|
94
|
+
rules: buildRules(),
|
|
95
|
+
root: "identifier",
|
|
96
|
+
};
|
|
97
|
+
/** Parser.parse normalization (parser.rb self.parse). */
|
|
98
|
+
export function preprocessCenCenelec(input) {
|
|
99
|
+
let normalized = input.replace(/[‑]/g, "-");
|
|
100
|
+
normalized = normalized.replace(/#.*$/, "").trim();
|
|
101
|
+
normalized = normalized.replace(/\s*\([^)]*corrigendum[^)]*\)/i, "");
|
|
102
|
+
normalized = normalized
|
|
103
|
+
.replaceAll("CEN-CLC", "CEN/CLC")
|
|
104
|
+
.replaceAll("CLC-CEN", "CLC/CEN")
|
|
105
|
+
.replaceAll("GUIDE", "Guide");
|
|
106
|
+
return normalized;
|
|
107
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { Tree } from "../../grammar/engine.js";
|
|
2
|
+
import type { FlavorImplementation, Identifier } from "../../conformance/implementation.js";
|
|
3
|
+
/** The tree → identifier pipeline, shared with composed flavors (evs). */
|
|
4
|
+
export declare function buildCenIdentifier(tree: Tree): Identifier;
|
|
5
|
+
export declare function cenCenelecGrammarImplementation(): FlavorImplementation;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { parseGrammar } from "../../grammar/engine.js";
|
|
2
|
+
import { grammarImplementation } from "../index.js";
|
|
3
|
+
import { cenCenelecGrammar, preprocessCenCenelec } from "./grammar.js";
|
|
4
|
+
import { AdoptedEuropeanNormClass, AmendmentClass, CEN_DOCUMENT_CLASSES, ConsolidatedIdentifierClass, CorrigendumClass, DEFAULT_TYPED_STAGE, EuropeanPrestandardClass, FragmentClass, PUBLISHER_TYPES, locateStage, locateTypeClass, } from "./model.js";
|
|
5
|
+
/**
|
|
6
|
+
* Port of lib/pubid/cen_cenelec/builder.rb — the parse-tree → identifier
|
|
7
|
+
* pipeline: base document (adopted / ENV adoption / implicit IEC adoption /
|
|
8
|
+
* plain), then the supplement wrapping (slash → standalone, plus →
|
|
9
|
+
* consolidated) and the fragment path.
|
|
10
|
+
*/
|
|
11
|
+
const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
12
|
+
const str = (v) => {
|
|
13
|
+
if (v === undefined || v === null)
|
|
14
|
+
return undefined;
|
|
15
|
+
const s = String(v);
|
|
16
|
+
return s.length > 0 ? s : undefined;
|
|
17
|
+
};
|
|
18
|
+
const presentString = (v) => {
|
|
19
|
+
const s = str(v);
|
|
20
|
+
return s === undefined || s === "" ? undefined : s;
|
|
21
|
+
};
|
|
22
|
+
function flattenArray(data) {
|
|
23
|
+
return Object.assign({}, ...data);
|
|
24
|
+
}
|
|
25
|
+
class CenBuilder {
|
|
26
|
+
build(data) {
|
|
27
|
+
const d = Array.isArray(data) ? flattenArray(data) : data;
|
|
28
|
+
if (d["fragment_number"] !== undefined) {
|
|
29
|
+
return this.buildFragmentIdentifier(d);
|
|
30
|
+
}
|
|
31
|
+
const base = this.buildBaseDocument(d);
|
|
32
|
+
if (this.hasSlashSupplements(d)) {
|
|
33
|
+
return this.buildStandaloneSupplement(base, d);
|
|
34
|
+
}
|
|
35
|
+
const supplementsData = this.extractSupplements(d);
|
|
36
|
+
if (supplementsData.length > 0) {
|
|
37
|
+
return this.wrapWithConsolidated(base, supplementsData);
|
|
38
|
+
}
|
|
39
|
+
return base;
|
|
40
|
+
}
|
|
41
|
+
buildBaseDocument(d) {
|
|
42
|
+
if (d["adopted_string"] !== undefined) {
|
|
43
|
+
if (str(d["publisher"]) === "ENV") {
|
|
44
|
+
return this.buildEnvAdoptedIdentifier(d);
|
|
45
|
+
}
|
|
46
|
+
return this.buildAdoptedIdentifier(d);
|
|
47
|
+
}
|
|
48
|
+
if (str(d["publisher"]) === "EN" &&
|
|
49
|
+
(Array.isArray(d["parts"]) ? d["parts"].length === 0 : true) &&
|
|
50
|
+
!this.hasSupplements(d)) {
|
|
51
|
+
const adopted = this.buildImplicitAdoption(d);
|
|
52
|
+
if (adopted !== undefined)
|
|
53
|
+
return adopted;
|
|
54
|
+
}
|
|
55
|
+
const baseData = { ...d };
|
|
56
|
+
delete baseData["supplements"];
|
|
57
|
+
return this.buildPlainIdentifier(baseData);
|
|
58
|
+
}
|
|
59
|
+
hasSupplements(d) {
|
|
60
|
+
return this.hasSlashSupplements(d) || this.extractSupplements(d).length > 0;
|
|
61
|
+
}
|
|
62
|
+
buildPlainIdentifier(baseData) {
|
|
63
|
+
const klass = this.locateIdentifierKlass(baseData);
|
|
64
|
+
const attrs = this.assignAttributes(baseData);
|
|
65
|
+
return new klass(attrs);
|
|
66
|
+
}
|
|
67
|
+
locateIdentifierKlass(d) {
|
|
68
|
+
if (d["adopted_string"] !== undefined)
|
|
69
|
+
return AdoptedEuropeanNormClass;
|
|
70
|
+
const publisherStr = str(d["publisher"]) ?? "";
|
|
71
|
+
if (PUBLISHER_TYPES.includes(publisherStr)) {
|
|
72
|
+
const typedStage = locateStage(publisherStr);
|
|
73
|
+
if (typedStage !== undefined) {
|
|
74
|
+
const kind = locateTypeClass(typedStage.type_code);
|
|
75
|
+
if (kind !== undefined)
|
|
76
|
+
return CEN_DOCUMENT_CLASSES.get(kind);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const typeOrStage = str(d["type_with_stage"]) ?? str(d["type"]) ?? str(d["stage"]) ?? "";
|
|
80
|
+
const typedStage = locateStage(typeOrStage) ?? DEFAULT_TYPED_STAGE;
|
|
81
|
+
return CEN_DOCUMENT_CLASSES.get(locateTypeClass(typedStage.type_code) ?? "en");
|
|
82
|
+
}
|
|
83
|
+
assignAttributes(baseData) {
|
|
84
|
+
const attrs = {};
|
|
85
|
+
if (baseData["type_with_stage"] !== undefined) {
|
|
86
|
+
const typedStage = locateStage(str(baseData["type_with_stage"]) ?? "") ?? DEFAULT_TYPED_STAGE;
|
|
87
|
+
attrs["typedStage"] = typedStage;
|
|
88
|
+
attrs["type"] = typedStage.type_code === "en" ? "EN" : typedStage.abbr;
|
|
89
|
+
}
|
|
90
|
+
if (baseData["type"] !== undefined) {
|
|
91
|
+
attrs["type"] = str(baseData["type"]);
|
|
92
|
+
}
|
|
93
|
+
if (baseData["publisher"] !== undefined) {
|
|
94
|
+
attrs["publisher"] = str(baseData["publisher"]);
|
|
95
|
+
}
|
|
96
|
+
if (baseData["copublisher"] !== undefined) {
|
|
97
|
+
attrs["copublishers"] = [str(baseData["copublisher"])];
|
|
98
|
+
}
|
|
99
|
+
if (baseData["number"] !== undefined) {
|
|
100
|
+
attrs["number"] = str(baseData["number"]);
|
|
101
|
+
}
|
|
102
|
+
if (Array.isArray(baseData["parts"]) && baseData["parts"].length > 0) {
|
|
103
|
+
const first = baseData["parts"][0];
|
|
104
|
+
attrs["part"] = isObj(first) ? str(first["part"]) : str(first);
|
|
105
|
+
}
|
|
106
|
+
const year = str(baseData["year"]);
|
|
107
|
+
if (year !== undefined) {
|
|
108
|
+
const month = str(baseData["month"]);
|
|
109
|
+
attrs["date"] = new PubidDateRef(month !== undefined ? { year, month } : { year });
|
|
110
|
+
}
|
|
111
|
+
return attrs;
|
|
112
|
+
}
|
|
113
|
+
parseAdoptedString(adoptedStr) {
|
|
114
|
+
if (adoptedStr.startsWith("ISO/IEC") || adoptedStr.includes("ISO/IEC") || adoptedStr.startsWith("ISO")) {
|
|
115
|
+
const impl = grammarImplementation("iso");
|
|
116
|
+
if (impl === undefined)
|
|
117
|
+
throw new Error("iso implementation unavailable");
|
|
118
|
+
return impl.parse(adoptedStr);
|
|
119
|
+
}
|
|
120
|
+
if (adoptedStr.startsWith("IEC")) {
|
|
121
|
+
const impl = grammarImplementation("iec");
|
|
122
|
+
if (impl === undefined)
|
|
123
|
+
throw new Error("iec implementation unavailable");
|
|
124
|
+
return impl.parse(adoptedStr);
|
|
125
|
+
}
|
|
126
|
+
return undefined;
|
|
127
|
+
}
|
|
128
|
+
buildAdoptedIdentifier(d) {
|
|
129
|
+
const adoptedStr = str(d["adopted_string"])?.trim();
|
|
130
|
+
const adoptedId = adoptedStr !== undefined ? this.parseAdoptedString(adoptedStr) : undefined;
|
|
131
|
+
const copublishers = Array.isArray(d["copublishers"])
|
|
132
|
+
? d["copublishers"].map((c) => str(c["copublisher"]))
|
|
133
|
+
: d["copublisher"] !== undefined
|
|
134
|
+
? [str(d["copublisher"])]
|
|
135
|
+
: [];
|
|
136
|
+
const attrs = { adopted: adoptedId };
|
|
137
|
+
if (d["type_with_stage"] !== undefined) {
|
|
138
|
+
const typedStage = locateStage(str(d["type_with_stage"]) ?? "") ?? DEFAULT_TYPED_STAGE;
|
|
139
|
+
attrs["typedStage"] = typedStage;
|
|
140
|
+
attrs["type"] = "EN";
|
|
141
|
+
}
|
|
142
|
+
if (d["publisher"] !== undefined) {
|
|
143
|
+
attrs["publisher"] = str(d["publisher"]);
|
|
144
|
+
}
|
|
145
|
+
if (copublishers.length > 0) {
|
|
146
|
+
attrs["copublishers"] = copublishers.filter((c) => c !== undefined);
|
|
147
|
+
}
|
|
148
|
+
return new AdoptedEuropeanNormClass(attrs);
|
|
149
|
+
}
|
|
150
|
+
buildEnvAdoptedIdentifier(d) {
|
|
151
|
+
const adoptedStr = str(d["adopted_string"])?.trim();
|
|
152
|
+
const adoptedId = adoptedStr !== undefined ? this.parseAdoptedString(adoptedStr) : undefined;
|
|
153
|
+
return new EuropeanPrestandardClass({
|
|
154
|
+
publisher: "ENV",
|
|
155
|
+
adopted: adoptedId,
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
buildImplicitAdoption(d) {
|
|
159
|
+
const numStr = (str(d["number"]) ?? "").trim();
|
|
160
|
+
if (!/^\d{1,6}$/.test(numStr))
|
|
161
|
+
return undefined;
|
|
162
|
+
const num = Number.parseInt(numStr, 10);
|
|
163
|
+
if (!(num >= 60000 && num <= 79999))
|
|
164
|
+
return undefined;
|
|
165
|
+
const impl = grammarImplementation("iec");
|
|
166
|
+
if (impl === undefined)
|
|
167
|
+
return undefined;
|
|
168
|
+
return new AdoptedEuropeanNormClass({
|
|
169
|
+
publisher: "EN",
|
|
170
|
+
adopted: impl.parse(`IEC ${numStr}`),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
buildFragmentIdentifier(d) {
|
|
174
|
+
const baseData = { ...d };
|
|
175
|
+
delete baseData["amendment_number"];
|
|
176
|
+
delete baseData["fragment_number"];
|
|
177
|
+
delete baseData["amendment_year"];
|
|
178
|
+
const base = this.buildPlainIdentifier(baseData);
|
|
179
|
+
// The compact spelling can carry the amendment's own year
|
|
180
|
+
// (EN 60038/A1:2009 FRAG2); the AMD-keyword spelling cannot.
|
|
181
|
+
const amendment = new AmendmentClass({
|
|
182
|
+
base,
|
|
183
|
+
number: str(d["amendment_number"]),
|
|
184
|
+
...(str(d["amendment_year"]) !== undefined ? { year: str(d["amendment_year"]) } : {}),
|
|
185
|
+
});
|
|
186
|
+
return new FragmentClass({
|
|
187
|
+
base: amendment,
|
|
188
|
+
number: str(d["fragment_number"]),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
supplementDataOf(s) {
|
|
192
|
+
if (isObj(s) && s["supplement"] !== undefined)
|
|
193
|
+
return s["supplement"];
|
|
194
|
+
return s;
|
|
195
|
+
}
|
|
196
|
+
extractSupplements(d) {
|
|
197
|
+
const supps = d["supplements"];
|
|
198
|
+
if (!Array.isArray(supps) || supps.length === 0)
|
|
199
|
+
return [];
|
|
200
|
+
return supps
|
|
201
|
+
.map((s) => this.supplementDataOf(s))
|
|
202
|
+
.filter((suppData) => suppData["amd_sep_plus"] !== undefined)
|
|
203
|
+
.map((suppData) => ({
|
|
204
|
+
type: (suppData["amd_number"] !== undefined ? "amendment" : "corrigendum"),
|
|
205
|
+
number: str(suppData["amd_number"]) ?? str(suppData["cor_number"]),
|
|
206
|
+
year: str(suppData["amd_year"]) ?? str(suppData["year"]),
|
|
207
|
+
month: str(suppData["month"]),
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
hasSlashSupplements(d) {
|
|
211
|
+
const supps = d["supplements"];
|
|
212
|
+
if (!Array.isArray(supps) || supps.length === 0)
|
|
213
|
+
return false;
|
|
214
|
+
return supps.some((s) => this.supplementDataOf(s)["amd_sep_slash"] !== undefined);
|
|
215
|
+
}
|
|
216
|
+
buildStandaloneSupplement(base, d) {
|
|
217
|
+
const supps = d["supplements"];
|
|
218
|
+
const suppData = this.supplementDataOf(supps[0]);
|
|
219
|
+
if (suppData["amd_number"] !== undefined) {
|
|
220
|
+
return new AmendmentClass({
|
|
221
|
+
base,
|
|
222
|
+
number: str(suppData["amd_number"]),
|
|
223
|
+
year: presentString(suppData["amd_year"]),
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
return new CorrigendumClass({
|
|
227
|
+
base,
|
|
228
|
+
number: presentString(suppData["cor_number"]),
|
|
229
|
+
year: presentString(suppData["year"]),
|
|
230
|
+
month: presentString(suppData["month"]),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
wrapWithConsolidated(base, supplementsData) {
|
|
234
|
+
const supplementIds = supplementsData.map((supp) => supp.type === "amendment"
|
|
235
|
+
? new AmendmentClass({
|
|
236
|
+
number: presentString(supp.number),
|
|
237
|
+
year: presentString(supp.year),
|
|
238
|
+
})
|
|
239
|
+
: new CorrigendumClass({
|
|
240
|
+
number: presentString(supp.number),
|
|
241
|
+
year: presentString(supp.year),
|
|
242
|
+
month: presentString(supp.month),
|
|
243
|
+
}));
|
|
244
|
+
return new ConsolidatedIdentifierClass({
|
|
245
|
+
identifiers: [base, ...supplementIds],
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
import { PubidDate as PubidDateRef } from "../../model/component.js";
|
|
250
|
+
/** The tree → identifier pipeline, shared with composed flavors (evs). */
|
|
251
|
+
export function buildCenIdentifier(tree) {
|
|
252
|
+
return new CenBuilder().build(tree);
|
|
253
|
+
}
|
|
254
|
+
export function cenCenelecGrammarImplementation() {
|
|
255
|
+
const builder = new CenBuilder();
|
|
256
|
+
return {
|
|
257
|
+
parse(input) {
|
|
258
|
+
const cleaned = preprocessCenCenelec(input);
|
|
259
|
+
const tree = parseGrammar(cenCenelecGrammar, cleaned);
|
|
260
|
+
return builder.build(tree);
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { BaseIdentifier } from "../../model/identifier.js";
|
|
2
|
+
import type { IdentifierStatic } from "../../model/identifier.js";
|
|
3
|
+
import { type FieldMapping } from "../../model/attribute.js";
|
|
4
|
+
import { PubidDate } from "../../model/component.js";
|
|
5
|
+
/**
|
|
6
|
+
* Port of lib/pubid/cen_cenelec: the flat wire shape (publisher and
|
|
7
|
+
* copublishers as bare strings, a supplement's number/year/month on the
|
|
8
|
+
* same keys as a document, a draft stage as one code), the class family
|
|
9
|
+
* (documents, supplements, consolidated, adopted) and the renderer/URN.
|
|
10
|
+
*/
|
|
11
|
+
export interface CenTypedStage {
|
|
12
|
+
code: string;
|
|
13
|
+
stage_code: string;
|
|
14
|
+
type_code: string;
|
|
15
|
+
abbr: string;
|
|
16
|
+
}
|
|
17
|
+
export declare const TYPED_STAGES: CenTypedStage[];
|
|
18
|
+
export declare const DEFAULT_TYPED_STAGE: CenTypedStage;
|
|
19
|
+
export declare function locateStage(abbr: string): CenTypedStage | undefined;
|
|
20
|
+
export declare function locateStageByCode(code: string): CenTypedStage | undefined;
|
|
21
|
+
export declare const PUBLISHER_TYPES: string[];
|
|
22
|
+
export type TypeKey = "en" | "ts" | "tr" | "guide" | "cwa" | "hd" | "es" | "cr" | "env";
|
|
23
|
+
export declare function locateTypeClass(typeCode: string): TypeKey | undefined;
|
|
24
|
+
export declare abstract class CenIdentifier extends BaseIdentifier {
|
|
25
|
+
static attributes: import("../../model/attribute.js").AttributeTable;
|
|
26
|
+
static mappings: FieldMapping[];
|
|
27
|
+
readonly number: string | undefined;
|
|
28
|
+
readonly part: string | undefined;
|
|
29
|
+
readonly date: PubidDate | undefined;
|
|
30
|
+
readonly typedStage: CenTypedStage | undefined;
|
|
31
|
+
readonly type: string | undefined;
|
|
32
|
+
readonly publisher: string | undefined;
|
|
33
|
+
readonly copublishers: string[] | undefined;
|
|
34
|
+
root(): CenIdentifier;
|
|
35
|
+
toUrn(): string;
|
|
36
|
+
}
|
|
37
|
+
export declare const CEN_DOCUMENT_CLASSES: Map<string, IdentifierStatic>;
|
|
38
|
+
export declare const CenelecHarmonizationDocumentClass: IdentifierStatic;
|
|
39
|
+
export declare const AmendmentClass: IdentifierStatic;
|
|
40
|
+
export declare const CorrigendumClass: IdentifierStatic;
|
|
41
|
+
export declare const FragmentClass: IdentifierStatic;
|
|
42
|
+
export declare const ConsolidatedIdentifierClass: IdentifierStatic;
|
|
43
|
+
export declare const AdoptedEuropeanNormClass: IdentifierStatic;
|
|
44
|
+
export declare const EuropeanPrestandardClass: IdentifierStatic;
|
|
45
|
+
export declare const EuropeanNormClass: IdentifierStatic;
|