@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,434 @@
|
|
|
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
|
+
/**
|
|
7
|
+
* 1:1 port of lib/pubid/bipm/ — 90 corpus rows across six families:
|
|
8
|
+
* committee documents (REC/RES/DECN/ACT/DECL in short and long EN/FR
|
|
9
|
+
* forms), meetings (EN ordinals, FR <sup>e</sup> réunion), the
|
|
10
|
+
* Metrologia journal, the SI Brochure and its derived products, mises
|
|
11
|
+
* en pratique (incl. Rapport BIPM-YYYY/NN), and CC guides. Historic
|
|
12
|
+
* group names (CCDS) and two-letter language codes (EN/FR) normalize
|
|
13
|
+
* at parse time and never reach the hash.
|
|
14
|
+
*/
|
|
15
|
+
const GROUPS = [
|
|
16
|
+
"CIPM", "CGPM", "JCRB", "CCTF", "CCQM", "CCT", "CCL", "CCAUV",
|
|
17
|
+
"CCU", "CCM", "CCEM", "CCPR", "CCRI",
|
|
18
|
+
];
|
|
19
|
+
const GROUP_ALIASES = { CCDS: "CCTF" };
|
|
20
|
+
const PARSEABLE_GROUPS = [...GROUPS, ...Object.keys(GROUP_ALIASES)];
|
|
21
|
+
const TYPE_CODES = ["REC", "RES", "DECN", "ACT", "DECL"];
|
|
22
|
+
const TYPE_NAME_EN = {
|
|
23
|
+
REC: "Recommendation", RES: "Resolution", DECN: "Decision",
|
|
24
|
+
ACT: "Action", DECL: "Statement",
|
|
25
|
+
};
|
|
26
|
+
const TYPE_NAME_FR = {
|
|
27
|
+
REC: "Recommandation", RES: "Résolution", DECN: "Décision",
|
|
28
|
+
ACT: "Action", DECL: "Statement",
|
|
29
|
+
};
|
|
30
|
+
const TYPE_WORD_ALIASES = {
|
|
31
|
+
Declaration: "DECL", "Déclaration": "DECL",
|
|
32
|
+
};
|
|
33
|
+
const TYPE_WORD_TO_CODE = (() => {
|
|
34
|
+
const map = { ...TYPE_WORD_ALIASES };
|
|
35
|
+
for (const code of TYPE_CODES) {
|
|
36
|
+
map[code] = code;
|
|
37
|
+
map[TYPE_NAME_EN[code]] = code;
|
|
38
|
+
map[TYPE_NAME_FR[code]] = code;
|
|
39
|
+
}
|
|
40
|
+
return map;
|
|
41
|
+
})();
|
|
42
|
+
const LANGUAGE_ALIASES = { EN: "E", FR: "F" };
|
|
43
|
+
/** Longest-first literal alternation, so "CCTF" beats "CCT". */
|
|
44
|
+
function alternation(tokens) {
|
|
45
|
+
const sorted = [...tokens].sort((a, b) => b.length - a.length);
|
|
46
|
+
return sorted.map((t) => str(t)).reduce((a, b) => a.or(b));
|
|
47
|
+
}
|
|
48
|
+
function buildRules() {
|
|
49
|
+
const rules = {};
|
|
50
|
+
const rule = (name, build) => {
|
|
51
|
+
rules[name] = build();
|
|
52
|
+
};
|
|
53
|
+
const space = str(" ");
|
|
54
|
+
const digits = match("[0-9]").repeat(1, Infinity);
|
|
55
|
+
const alnum = match("[0-9A-Za-z]").repeat(1, Infinity);
|
|
56
|
+
rule("number", () => digits.then(str("-").then(digits).repeat(0, Infinity)).as("number"));
|
|
57
|
+
rule("year", () => match("[0-9]").repeat(4, 4).as("year"));
|
|
58
|
+
// Two-letter consumer codes first, so "EN" is never a bare "E".
|
|
59
|
+
const lang = () => alternation(["EN", "FR", "E", "F"]).as("language");
|
|
60
|
+
rule("year_paren", () => str("(").then(rules["year"], str(", ").then(lang()).maybe(), str(")")));
|
|
61
|
+
rule("year_paren_nolang", () => str("(").then(rules["year"], str(")")));
|
|
62
|
+
rule("group", () => alternation(PARSEABLE_GROUPS).as("group"));
|
|
63
|
+
rule("type_abbrev", () => alternation([...TYPE_CODES]).as("type_word"));
|
|
64
|
+
rule("type_name_en", () => alternation([...new Set([...Object.values(TYPE_NAME_EN), "Declaration"])]).as("type_word"));
|
|
65
|
+
rule("type_name_fr", () => alternation([...new Set([...Object.values(TYPE_NAME_FR), "Déclaration"])]).as("type_word"));
|
|
66
|
+
const connective = () => str("de la").or(str("du"));
|
|
67
|
+
const ordinal = () => str("st").or(str("nd"), str("rd"), str("th"));
|
|
68
|
+
const meetingWordFr = () => str("Réunion").or(str("réunion"));
|
|
69
|
+
// The trailing date is optional so "CCTF REC 2" parses date-less.
|
|
70
|
+
rule("committee_short", () => rules["group"]
|
|
71
|
+
.then(space, rules["type_abbrev"], space.then(rules["number"]).maybe(), space.then(rules["year_paren"]).maybe())
|
|
72
|
+
.as("committee_short"));
|
|
73
|
+
rule("committee_long_en", () => rules["group"]
|
|
74
|
+
.then(space, rules["type_name_en"], space.then(rules["number"]).maybe(), space.then(rules["year_paren_nolang"]).maybe())
|
|
75
|
+
.as("committee_long_en"));
|
|
76
|
+
rule("committee_long_fr", () => rules["type_name_fr"]
|
|
77
|
+
.then(space.then(rules["number"]).maybe(), space, connective(), space, rules["group"], space.then(rules["year_paren_nolang"]).maybe())
|
|
78
|
+
.as("committee_long_fr"));
|
|
79
|
+
// Loose consumer form: a French type name in group-leading order.
|
|
80
|
+
rule("committee_group_fr", () => rules["group"]
|
|
81
|
+
.then(space, rules["type_name_fr"], space.then(rules["number"]).maybe(), space.then(rules["year_paren_nolang"]).maybe())
|
|
82
|
+
.as("committee_long_fr"));
|
|
83
|
+
// Bare MRA form: group + number, no type word ("CIPM 2005-06").
|
|
84
|
+
rule("committee_bare", () => rules["group"]
|
|
85
|
+
.then(space, rules["number"], space.then(rules["year_paren"]).maybe())
|
|
86
|
+
.as("committee_bare"));
|
|
87
|
+
rule("meeting_en", () => rules["group"]
|
|
88
|
+
.then(space, rules["number"], ordinal(), space, str("Meeting"), space.then(rules["year_paren"]).maybe())
|
|
89
|
+
.or(rules["group"].then(space, str("Meeting"), space, rules["number"], space.then(rules["year_paren"]).maybe()))
|
|
90
|
+
.as("meeting_en"));
|
|
91
|
+
rule("meeting_fr", () => rules["group"]
|
|
92
|
+
.then(space, rules["number"], str("<sup>e</sup>"), space, str("réunion"), space.then(rules["year_paren"]).maybe())
|
|
93
|
+
.or(rules["group"].then(space, rules["number"], str("e"), space, meetingWordFr(), space.then(rules["year_paren"]).maybe()), rules["group"].then(space, meetingWordFr(), space, rules["number"], space.then(rules["year_paren"]).maybe()))
|
|
94
|
+
.as("meeting_fr"));
|
|
95
|
+
rule("metrologia", () => str("Metrologia")
|
|
96
|
+
.then(space
|
|
97
|
+
.then(digits.as("volume"), space
|
|
98
|
+
.then(alnum.as("issue"), space.then(alnum.as("article")).maybe())
|
|
99
|
+
.maybe())
|
|
100
|
+
.maybe())
|
|
101
|
+
.as("metrologia"));
|
|
102
|
+
rule("edition", () => digits.then(str("e")).as("edition"));
|
|
103
|
+
rule("version", () => str("v").then(match("[0-9.]").repeat(1, Infinity)).as("version"));
|
|
104
|
+
rule("years", () => digits.then(str("/").then(digits).maybe()).as("years"));
|
|
105
|
+
rule("si_brochure", () => str("BIPM SI Brochure")
|
|
106
|
+
.or(str("SI Brochure"))
|
|
107
|
+
.then(space, str("sur le SI").then(space).maybe(), rules["edition"], space, rules["version"], space, str("("), rules["years"], str(", "), lang(), str(")"))
|
|
108
|
+
.as("si_brochure"));
|
|
109
|
+
rule("brochure_variant", () => str("Appendix")
|
|
110
|
+
.then(space, digits)
|
|
111
|
+
.or(str("Concise"), str("FAQ"))
|
|
112
|
+
.as("variant"));
|
|
113
|
+
rule("si_brochure_variant", () => str("BIPM SI Brochure")
|
|
114
|
+
.or(str("SI Brochure"))
|
|
115
|
+
.then(space, rules["brochure_variant"])
|
|
116
|
+
.as("si_brochure_variant"));
|
|
117
|
+
rule("si_brochure_section", () => str("BIPM SI Brochure")
|
|
118
|
+
.or(str("SI Brochure"))
|
|
119
|
+
.then(space.then(str("Part"), space, digits.as("part")).maybe())
|
|
120
|
+
.as("si_brochure_section"));
|
|
121
|
+
// Shared "Appendix N [Annex N] Part N[.M]" tail of MEPs and guides.
|
|
122
|
+
rule("appendix_part", () => str("Appendix").then(space, digits.as("appendix"), space.then(str("Annex"), space, digits.as("annex")).maybe(), space, str("Part"), space, digits.then(str(".").then(digits).maybe()).as("part")));
|
|
123
|
+
rule("mep_code", () => match("[0-9A-Za-z]").repeat(1, Infinity).as("mep_code"));
|
|
124
|
+
rule("report_code", () => str("BIPM-").then(digits, str("/"), digits).as("report_code"));
|
|
125
|
+
const mepBody = () => str("SI MEP").then(space, rules["mep_code"]).or(str("Rapport").then(space, rules["report_code"]));
|
|
126
|
+
rule("mep", () => str("BIPM")
|
|
127
|
+
.then(space, mepBody(), space, rules["appendix_part"])
|
|
128
|
+
.or(mepBody())
|
|
129
|
+
.as("mep"));
|
|
130
|
+
rule("guide_kind", () => str("MeP").or(str("RSI")).as("guide_kind"));
|
|
131
|
+
const guideBody = () => rules["group"].then(str("-GD-"), rules["guide_kind"], str("-"), digits.as("number"));
|
|
132
|
+
rule("guide", () => str("BIPM")
|
|
133
|
+
.then(space, guideBody(), space, rules["appendix_part"])
|
|
134
|
+
.or(guideBody())
|
|
135
|
+
.as("guide"));
|
|
136
|
+
rule("group_leading", () => rules["meeting_en"].or(rules["meeting_fr"], rules["committee_short"], rules["committee_long_en"], rules["committee_group_fr"], rules["committee_bare"]));
|
|
137
|
+
rule("identifier", () => rules["metrologia"].or(rules["si_brochure"], rules["si_brochure_variant"], rules["si_brochure_section"], rules["mep"], rules["guide"], rules["committee_long_fr"], rules["group_leading"]));
|
|
138
|
+
rule("root", () => rules["identifier"]);
|
|
139
|
+
return rules;
|
|
140
|
+
}
|
|
141
|
+
export const bipmGrammar = { rules: buildRules(), root: "root" };
|
|
142
|
+
/** data/bipm/update_codes.yaml — full-line legacy spellings. */
|
|
143
|
+
const UPDATE_CODES = {
|
|
144
|
+
"CIPM/2005-06(REV)": "CIPM 2005-06",
|
|
145
|
+
"CIPM 2005-06(REV)": "CIPM 2005-06",
|
|
146
|
+
};
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
// Model
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
const BIPM_ATTRS = {
|
|
151
|
+
group: { type: "string" },
|
|
152
|
+
type_code: { type: "string" },
|
|
153
|
+
number: { type: "string" },
|
|
154
|
+
year: { type: "integer" },
|
|
155
|
+
language: { type: "string" },
|
|
156
|
+
form: { type: "string", default: "short" },
|
|
157
|
+
issue: { type: "string" },
|
|
158
|
+
article: { type: "string" },
|
|
159
|
+
edition: { type: "string" },
|
|
160
|
+
version: { type: "string" },
|
|
161
|
+
years: { type: "string" },
|
|
162
|
+
variant: { type: "string" },
|
|
163
|
+
mep_code: { type: "string" },
|
|
164
|
+
report_code: { type: "string" },
|
|
165
|
+
guide_kind: { type: "string" },
|
|
166
|
+
appendix: { type: "string" },
|
|
167
|
+
annex: { type: "string" },
|
|
168
|
+
part: { type: "string" },
|
|
169
|
+
};
|
|
170
|
+
const BIPM_MAPPINGS = keyValue({ wire: "group", to: "group" }, { wire: "type_code", to: "type_code" }, { wire: "number", to: "number" }, { wire: "year", to: "year" }, { wire: "language", to: "language" }, { wire: "form", to: "form" }, { wire: "issue", to: "issue" }, { wire: "article", to: "article" }, { wire: "edition", to: "edition" }, { wire: "version", to: "version" }, { wire: "years", to: "years" }, { wire: "variant", to: "variant" }, { wire: "mep_code", to: "mep_code" }, { wire: "report_code", to: "report_code" }, { wire: "guide_kind", to: "guide_kind" }, { wire: "appendix", to: "appendix" }, { wire: "annex", to: "annex" }, { wire: "part", to: "part" });
|
|
171
|
+
/** Naive source-data ordinals: 1→st, 2→nd, 3→rd, else→th (11→"11st"). */
|
|
172
|
+
function ordinalSuffix(number) {
|
|
173
|
+
const first = number.split("-")[0] ?? "";
|
|
174
|
+
const last = first.at(-1);
|
|
175
|
+
if (last === "1")
|
|
176
|
+
return "st";
|
|
177
|
+
if (last === "2")
|
|
178
|
+
return "nd";
|
|
179
|
+
if (last === "3")
|
|
180
|
+
return "rd";
|
|
181
|
+
return "th";
|
|
182
|
+
}
|
|
183
|
+
function frenchConnective(group) {
|
|
184
|
+
return group === "CGPM" ? "de la" : "du";
|
|
185
|
+
}
|
|
186
|
+
export class BipmIdentifier extends BaseIdentifier {
|
|
187
|
+
static attributes = extendAttributes(BaseIdentifier, BIPM_ATTRS);
|
|
188
|
+
static mappings = BIPM_MAPPINGS;
|
|
189
|
+
numberSegment() {
|
|
190
|
+
return this.number === undefined ? "" : ` ${this.number}`;
|
|
191
|
+
}
|
|
192
|
+
yearSegment(lang = "") {
|
|
193
|
+
return this.year === undefined ? "" : ` (${this.year}${lang})`;
|
|
194
|
+
}
|
|
195
|
+
fullContentWrap(body) {
|
|
196
|
+
if (this.part === undefined)
|
|
197
|
+
return body;
|
|
198
|
+
const annex = this.annex === undefined ? "" : ` Annex ${this.annex}`;
|
|
199
|
+
return `BIPM ${body} Appendix ${this.appendix}${annex} Part ${this.part}`;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
class BipmUrnGenerator extends BaseUrnGenerator {
|
|
203
|
+
generate() {
|
|
204
|
+
const id = this.identifier;
|
|
205
|
+
if (id instanceof BipmCommitteeDocument) {
|
|
206
|
+
const parts = [
|
|
207
|
+
"urn", "bipm", id.group?.toLowerCase() ?? "",
|
|
208
|
+
id.type_code?.toLowerCase() ?? "", id.number ?? "",
|
|
209
|
+
];
|
|
210
|
+
if (id.year !== undefined)
|
|
211
|
+
parts.push(String(id.year));
|
|
212
|
+
return parts.join(":");
|
|
213
|
+
}
|
|
214
|
+
if (id instanceof BipmMeeting) {
|
|
215
|
+
const parts = ["urn", "bipm", id.group?.toLowerCase() ?? "", "meeting", id.number ?? ""];
|
|
216
|
+
if (id.year !== undefined)
|
|
217
|
+
parts.push(String(id.year));
|
|
218
|
+
return parts.join(":");
|
|
219
|
+
}
|
|
220
|
+
if (id instanceof BipmMetrologiaArticle) {
|
|
221
|
+
const parts = ["urn", "bipm", "metrologia", String(id.volume())];
|
|
222
|
+
if (id.issue !== undefined)
|
|
223
|
+
parts.push(id.issue);
|
|
224
|
+
if (id.article !== undefined)
|
|
225
|
+
parts.push(id.article);
|
|
226
|
+
return parts.join(":");
|
|
227
|
+
}
|
|
228
|
+
if (id instanceof BipmSiBrochure) {
|
|
229
|
+
return [
|
|
230
|
+
"urn", "bipm", "si-brochure", id.language?.toLowerCase() ?? "",
|
|
231
|
+
id.edition ?? "", id.version ?? "", id.years ?? "",
|
|
232
|
+
].join(":");
|
|
233
|
+
}
|
|
234
|
+
throw new ParseFailed(`Cannot build URN for BIPM identifier: ${id.constructor.polymorphicName}`, 0);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
class BipmCommitteeDocument extends BipmIdentifier {
|
|
238
|
+
static polymorphicName = "pubid:bipm:committee-document";
|
|
239
|
+
static urnGenerator = BipmUrnGenerator;
|
|
240
|
+
render() {
|
|
241
|
+
if (this.form === "long") {
|
|
242
|
+
if (this.language === "F") {
|
|
243
|
+
const name = TYPE_NAME_FR[this.type_code ?? ""] ?? "";
|
|
244
|
+
return `${name}${this.numberSegment()} ${frenchConnective(this.group ?? "")} ${this.group}${this.yearSegment()}`;
|
|
245
|
+
}
|
|
246
|
+
const name = TYPE_NAME_EN[this.type_code ?? ""] ?? "";
|
|
247
|
+
return `${this.group ?? ""} ${name}${this.numberSegment()}${this.yearSegment()}`;
|
|
248
|
+
}
|
|
249
|
+
const lang = this.language === undefined ? "" : `, ${this.language}`;
|
|
250
|
+
const type = this.type_code === undefined ? "" : ` ${this.type_code}`;
|
|
251
|
+
return `${this.group ?? ""}${type}${this.numberSegment()}${this.yearSegment(lang)}`;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
registerType(BipmCommitteeDocument);
|
|
255
|
+
class BipmMeeting extends BipmIdentifier {
|
|
256
|
+
static polymorphicName = "pubid:bipm:meeting";
|
|
257
|
+
static urnGenerator = BipmUrnGenerator;
|
|
258
|
+
render() {
|
|
259
|
+
if (this.language === "F") {
|
|
260
|
+
return `${this.group ?? ""} ${this.number ?? ""}<sup>e</sup> réunion${this.yearSegment()}`;
|
|
261
|
+
}
|
|
262
|
+
return `${this.group ?? ""} ${this.number ?? ""}${ordinalSuffix(this.number ?? "")} Meeting${this.yearSegment()}`;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
registerType(BipmMeeting);
|
|
266
|
+
class BipmMetrologiaArticle extends BipmIdentifier {
|
|
267
|
+
static polymorphicName = "pubid:bipm:metrologia-article";
|
|
268
|
+
static urnGenerator = BipmUrnGenerator;
|
|
269
|
+
/** The volume IS the index key — derived from `number`, never stored. */
|
|
270
|
+
volume() {
|
|
271
|
+
return this.number === undefined ? undefined : Number(this.number);
|
|
272
|
+
}
|
|
273
|
+
render() {
|
|
274
|
+
let result = "Metrologia";
|
|
275
|
+
if (this.volume() !== undefined)
|
|
276
|
+
result += ` ${this.volume()}`;
|
|
277
|
+
if (this.issue !== undefined)
|
|
278
|
+
result += ` ${this.issue}`;
|
|
279
|
+
if (this.article !== undefined)
|
|
280
|
+
result += ` ${this.article}`;
|
|
281
|
+
return result;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
registerType(BipmMetrologiaArticle);
|
|
285
|
+
class BipmSiBrochure extends BipmIdentifier {
|
|
286
|
+
static polymorphicName = "pubid:bipm:si-brochure";
|
|
287
|
+
static urnGenerator = BipmUrnGenerator;
|
|
288
|
+
render() {
|
|
289
|
+
if (this.variant !== undefined)
|
|
290
|
+
return `BIPM SI Brochure ${this.variant}`;
|
|
291
|
+
if (this.edition === undefined) {
|
|
292
|
+
const part = this.part === undefined ? "" : ` Part ${this.part}`;
|
|
293
|
+
return `BIPM SI Brochure${part}`;
|
|
294
|
+
}
|
|
295
|
+
const phrase = this.language === "F" ? "sur le SI " : "";
|
|
296
|
+
const lang = this.language === undefined ? "" : `, ${this.language}`;
|
|
297
|
+
return `BIPM SI Brochure ${phrase}${this.edition} ${this.version} (${this.years}${lang})`;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
registerType(BipmSiBrochure);
|
|
301
|
+
class BipmMep extends BipmIdentifier {
|
|
302
|
+
static polymorphicName = "pubid:bipm:mep";
|
|
303
|
+
static urnGenerator = BipmUrnGenerator;
|
|
304
|
+
render() {
|
|
305
|
+
const body = this.report_code !== undefined
|
|
306
|
+
? `Rapport ${this.report_code}`
|
|
307
|
+
: `SI MEP ${this.mep_code}`;
|
|
308
|
+
return this.fullContentWrap(body);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
registerType(BipmMep);
|
|
312
|
+
class BipmGuide extends BipmIdentifier {
|
|
313
|
+
static polymorphicName = "pubid:bipm:guide";
|
|
314
|
+
static urnGenerator = BipmUrnGenerator;
|
|
315
|
+
render() {
|
|
316
|
+
return this.fullContentWrap(`${this.group}-GD-${this.guide_kind}-${this.number}`);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
registerType(BipmGuide);
|
|
320
|
+
// ---------------------------------------------------------------------------
|
|
321
|
+
// Builder
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
324
|
+
const s = (v) => v === undefined || v === null ? undefined : String(v);
|
|
325
|
+
function flatten(data) {
|
|
326
|
+
return Array.isArray(data) ? Object.assign({}, ...data) : data;
|
|
327
|
+
}
|
|
328
|
+
const normalizeGroup = (token) => GROUP_ALIASES[token] ?? token;
|
|
329
|
+
const normalizeLanguage = (token) => token === undefined ? undefined : LANGUAGE_ALIASES[token] ?? token;
|
|
330
|
+
class BipmBuilder {
|
|
331
|
+
build(data) {
|
|
332
|
+
const tree = flatten(data);
|
|
333
|
+
const node = (key) => {
|
|
334
|
+
const v = tree[key];
|
|
335
|
+
return isObj(v) ? flatten(v) : {};
|
|
336
|
+
};
|
|
337
|
+
if (tree["committee_short"] !== undefined)
|
|
338
|
+
return this.buildCommittee(node("committee_short"), "short");
|
|
339
|
+
if (tree["committee_long_en"] !== undefined)
|
|
340
|
+
return this.buildCommittee(node("committee_long_en"), "long", "E");
|
|
341
|
+
if (tree["committee_bare"] !== undefined)
|
|
342
|
+
return this.buildCommittee(node("committee_bare"), "short");
|
|
343
|
+
if (tree["committee_long_fr"] !== undefined)
|
|
344
|
+
return this.buildCommittee(node("committee_long_fr"), "long", "F");
|
|
345
|
+
if (tree["meeting_en"] !== undefined)
|
|
346
|
+
return this.buildMeeting(node("meeting_en"));
|
|
347
|
+
if (tree["meeting_fr"] !== undefined)
|
|
348
|
+
return this.buildMeeting(node("meeting_fr"), "F");
|
|
349
|
+
if (tree["metrologia"] !== undefined) {
|
|
350
|
+
const n = node("metrologia");
|
|
351
|
+
return new BipmMetrologiaArticle({
|
|
352
|
+
number: s(n["volume"]),
|
|
353
|
+
issue: s(n["issue"]),
|
|
354
|
+
article: s(n["article"]),
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
if (tree["si_brochure"] !== undefined) {
|
|
358
|
+
const n = node("si_brochure");
|
|
359
|
+
const edition = s(n["edition"]);
|
|
360
|
+
return new BipmSiBrochure({
|
|
361
|
+
number: edition,
|
|
362
|
+
edition,
|
|
363
|
+
version: s(n["version"]),
|
|
364
|
+
years: s(n["years"]),
|
|
365
|
+
language: normalizeLanguage(s(n["language"])),
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
if (tree["si_brochure_variant"] !== undefined) {
|
|
369
|
+
const variant = s(node("si_brochure_variant")["variant"]);
|
|
370
|
+
return new BipmSiBrochure({ number: variant, variant });
|
|
371
|
+
}
|
|
372
|
+
if (tree["si_brochure_section"] !== undefined) {
|
|
373
|
+
const n = node("si_brochure_section");
|
|
374
|
+
return new BipmSiBrochure({ part: s(n["part"]) });
|
|
375
|
+
}
|
|
376
|
+
if (tree["mep"] !== undefined) {
|
|
377
|
+
const n = node("mep");
|
|
378
|
+
const mepCode = s(n["mep_code"]);
|
|
379
|
+
const reportCode = s(n["report_code"]);
|
|
380
|
+
return new BipmMep({
|
|
381
|
+
number: mepCode ?? reportCode,
|
|
382
|
+
mep_code: mepCode,
|
|
383
|
+
report_code: reportCode,
|
|
384
|
+
appendix: s(n["appendix"]),
|
|
385
|
+
annex: s(n["annex"]),
|
|
386
|
+
part: s(n["part"]),
|
|
387
|
+
});
|
|
388
|
+
}
|
|
389
|
+
if (tree["guide"] !== undefined) {
|
|
390
|
+
const n = node("guide");
|
|
391
|
+
return new BipmGuide({
|
|
392
|
+
group: normalizeGroup(s(n["group"])),
|
|
393
|
+
guide_kind: s(n["guide_kind"]),
|
|
394
|
+
number: s(n["number"]),
|
|
395
|
+
appendix: s(n["appendix"]),
|
|
396
|
+
part: s(n["part"]),
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
throw new ParseFailed(`Unrecognized BIPM parse tree: ${JSON.stringify(tree)}`, 0);
|
|
400
|
+
}
|
|
401
|
+
buildCommittee(n, form, language) {
|
|
402
|
+
const year = s(n["year"]);
|
|
403
|
+
return new BipmCommitteeDocument({
|
|
404
|
+
group: normalizeGroup(s(n["group"])),
|
|
405
|
+
type_code: TYPE_WORD_TO_CODE[s(n["type_word"]) ?? ""],
|
|
406
|
+
number: s(n["number"]),
|
|
407
|
+
...(year !== undefined ? { year: Number(year) } : {}),
|
|
408
|
+
language: normalizeLanguage(language ?? s(n["language"])),
|
|
409
|
+
form,
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
buildMeeting(n, language) {
|
|
413
|
+
const year = s(n["year"]);
|
|
414
|
+
return new BipmMeeting({
|
|
415
|
+
group: normalizeGroup(s(n["group"])),
|
|
416
|
+
number: s(n["number"]),
|
|
417
|
+
...(year !== undefined ? { year: Number(year) } : {}),
|
|
418
|
+
language: normalizeLanguage(language ?? s(n["language"])),
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
export function bipmGrammarImplementation() {
|
|
423
|
+
const builder = new BipmBuilder();
|
|
424
|
+
return {
|
|
425
|
+
parse(input) {
|
|
426
|
+
const normalized = UPDATE_CODES[input] ?? input;
|
|
427
|
+
const tree = parseGrammar(bipmGrammar, normalized);
|
|
428
|
+
if (typeof tree !== "object" || tree === null) {
|
|
429
|
+
throw new ParseFailed("BIPM: unexpected parse tree", 0);
|
|
430
|
+
}
|
|
431
|
+
return builder.build(tree);
|
|
432
|
+
},
|
|
433
|
+
};
|
|
434
|
+
}
|