@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.
Files changed (185) hide show
  1. package/artifact/corpus.json.gz +0 -0
  2. package/dist/conformance/cli.js +5 -1
  3. package/dist/flavors/amca/grammar.d.ts +4 -0
  4. package/dist/flavors/amca/grammar.js +87 -0
  5. package/dist/flavors/amca/index.d.ts +4 -0
  6. package/dist/flavors/amca/index.js +76 -0
  7. package/dist/flavors/amca/model.d.ts +29 -0
  8. package/dist/flavors/amca/model.js +146 -0
  9. package/dist/flavors/ansi/index.d.ts +24 -0
  10. package/dist/flavors/ansi/index.js +147 -0
  11. package/dist/flavors/api/grammar.d.ts +4 -0
  12. package/dist/flavors/api/grammar.js +79 -0
  13. package/dist/flavors/api/index.d.ts +4 -0
  14. package/dist/flavors/api/index.js +71 -0
  15. package/dist/flavors/api/model.d.ts +27 -0
  16. package/dist/flavors/api/model.js +114 -0
  17. package/dist/flavors/ashrae/grammar.d.ts +2 -0
  18. package/dist/flavors/ashrae/grammar.js +667 -0
  19. package/dist/flavors/ashrae/index.d.ts +4 -0
  20. package/dist/flavors/ashrae/index.js +306 -0
  21. package/dist/flavors/ashrae/model.d.ts +87 -0
  22. package/dist/flavors/ashrae/model.js +335 -0
  23. package/dist/flavors/ashrae/preprocessor.d.ts +7 -0
  24. package/dist/flavors/ashrae/preprocessor.js +44 -0
  25. package/dist/flavors/asme/grammar.d.ts +2 -0
  26. package/dist/flavors/asme/grammar.js +200 -0
  27. package/dist/flavors/asme/index.d.ts +4 -0
  28. package/dist/flavors/asme/index.js +138 -0
  29. package/dist/flavors/asme/model.d.ts +34 -0
  30. package/dist/flavors/asme/model.js +123 -0
  31. package/dist/flavors/astm/grammar.d.ts +2 -0
  32. package/dist/flavors/astm/grammar.js +110 -0
  33. package/dist/flavors/astm/index.d.ts +2 -0
  34. package/dist/flavors/astm/index.js +127 -0
  35. package/dist/flavors/astm/model.d.ts +42 -0
  36. package/dist/flavors/astm/model.js +263 -0
  37. package/dist/flavors/bipm/index.d.ts +30 -0
  38. package/dist/flavors/bipm/index.js +434 -0
  39. package/dist/flavors/bsi/grammar.d.ts +4 -0
  40. package/dist/flavors/bsi/grammar.js +535 -0
  41. package/dist/flavors/bsi/index.d.ts +4 -0
  42. package/dist/flavors/bsi/index.js +941 -0
  43. package/dist/flavors/bsi/model.d.ts +127 -0
  44. package/dist/flavors/bsi/model.js +863 -0
  45. package/dist/flavors/calconnect/index.d.ts +21 -0
  46. package/dist/flavors/calconnect/index.js +113 -0
  47. package/dist/flavors/cen_cenelec/grammar.d.ts +4 -0
  48. package/dist/flavors/cen_cenelec/grammar.js +107 -0
  49. package/dist/flavors/cen_cenelec/index.d.ts +5 -0
  50. package/dist/flavors/cen_cenelec/index.js +263 -0
  51. package/dist/flavors/cen_cenelec/model.d.ts +45 -0
  52. package/dist/flavors/cen_cenelec/model.js +490 -0
  53. package/dist/flavors/cie/grammar.d.ts +5 -0
  54. package/dist/flavors/cie/grammar.js +127 -0
  55. package/dist/flavors/cie/index.d.ts +2 -0
  56. package/dist/flavors/cie/index.js +311 -0
  57. package/dist/flavors/cie/model.d.ts +122 -0
  58. package/dist/flavors/cie/model.js +464 -0
  59. package/dist/flavors/csa/grammar.d.ts +6 -0
  60. package/dist/flavors/csa/grammar.js +239 -0
  61. package/dist/flavors/csa/index.d.ts +2 -0
  62. package/dist/flavors/csa/index.js +634 -0
  63. package/dist/flavors/csa/model.d.ts +33 -0
  64. package/dist/flavors/csa/model.js +505 -0
  65. package/dist/flavors/doi/index.d.ts +13 -0
  66. package/dist/flavors/doi/index.js +65 -0
  67. package/dist/flavors/easc/index.d.ts +4 -0
  68. package/dist/flavors/easc/index.js +107 -0
  69. package/dist/flavors/ecma/index.d.ts +4 -0
  70. package/dist/flavors/ecma/index.js +117 -0
  71. package/dist/flavors/etsi/index.d.ts +14 -0
  72. package/dist/flavors/etsi/index.js +307 -0
  73. package/dist/flavors/evs/grammar.d.ts +2 -0
  74. package/dist/flavors/evs/grammar.js +22 -0
  75. package/dist/flavors/evs/index.d.ts +2 -0
  76. package/dist/flavors/evs/index.js +24 -0
  77. package/dist/flavors/evs/model.d.ts +19 -0
  78. package/dist/flavors/evs/model.js +36 -0
  79. package/dist/flavors/gb/index.d.ts +31 -0
  80. package/dist/flavors/gb/index.js +159 -0
  81. package/dist/flavors/gost/grammar.d.ts +2 -0
  82. package/dist/flavors/gost/grammar.js +46 -0
  83. package/dist/flavors/gost/index.d.ts +2 -0
  84. package/dist/flavors/gost/index.js +165 -0
  85. package/dist/flavors/gost/model.d.ts +61 -0
  86. package/dist/flavors/gost/model.js +147 -0
  87. package/dist/flavors/gost/prefix_routes.d.ts +15 -0
  88. package/dist/flavors/gost/prefix_routes.js +192 -0
  89. package/dist/flavors/iala/index.d.ts +32 -0
  90. package/dist/flavors/iala/index.js +300 -0
  91. package/dist/flavors/iana/index.d.ts +19 -0
  92. package/dist/flavors/iana/index.js +71 -0
  93. package/dist/flavors/idf/grammar.d.ts +2 -0
  94. package/dist/flavors/idf/grammar.js +71 -0
  95. package/dist/flavors/idf/index.d.ts +2 -0
  96. package/dist/flavors/idf/index.js +100 -0
  97. package/dist/flavors/idf/model.d.ts +54 -0
  98. package/dist/flavors/idf/model.js +359 -0
  99. package/dist/flavors/iec/grammar.d.ts +3 -0
  100. package/dist/flavors/iec/grammar.js +187 -0
  101. package/dist/flavors/iec/index.d.ts +4 -0
  102. package/dist/flavors/iec/index.js +507 -0
  103. package/dist/flavors/iec/model.d.ts +54 -0
  104. package/dist/flavors/iec/model.js +437 -0
  105. package/dist/flavors/ieee/grammar.d.ts +2 -0
  106. package/dist/flavors/ieee/grammar.js +697 -0
  107. package/dist/flavors/ieee/index.d.ts +3 -0
  108. package/dist/flavors/ieee/index.js +1258 -0
  109. package/dist/flavors/ieee/model.d.ts +144 -0
  110. package/dist/flavors/ieee/model.js +1237 -0
  111. package/dist/flavors/ieee/preprocessor.d.ts +8 -0
  112. package/dist/flavors/ieee/preprocessor.js +410 -0
  113. package/dist/flavors/ieee/update_codes.d.ts +8 -0
  114. package/dist/flavors/ieee/update_codes.js +197 -0
  115. package/dist/flavors/ietf/index.d.ts +30 -0
  116. package/dist/flavors/ietf/index.js +151 -0
  117. package/dist/flavors/iho/index.d.ts +4 -0
  118. package/dist/flavors/iho/index.js +126 -0
  119. package/dist/flavors/index.d.ts +9 -0
  120. package/dist/flavors/index.js +136 -0
  121. package/dist/flavors/isbn/index.d.ts +13 -0
  122. package/dist/flavors/isbn/index.js +97 -0
  123. package/dist/flavors/iso/grammar.d.ts +2 -0
  124. package/dist/flavors/iso/grammar.js +207 -0
  125. package/dist/flavors/iso/index.d.ts +2 -0
  126. package/dist/flavors/iso/index.js +343 -0
  127. package/dist/flavors/iso/model.d.ts +159 -0
  128. package/dist/flavors/iso/model.js +802 -0
  129. package/dist/flavors/iso/stages.generated.d.ts +13 -0
  130. package/dist/flavors/iso/stages.generated.js +391 -0
  131. package/dist/flavors/itu/grammar.d.ts +4 -0
  132. package/dist/flavors/itu/grammar.js +205 -0
  133. package/dist/flavors/itu/index.d.ts +2 -0
  134. package/dist/flavors/itu/index.js +224 -0
  135. package/dist/flavors/itu/model.d.ts +184 -0
  136. package/dist/flavors/itu/model.js +599 -0
  137. package/dist/flavors/jcgm/index.d.ts +7 -0
  138. package/dist/flavors/jcgm/index.js +300 -0
  139. package/dist/flavors/jis/index.d.ts +4 -0
  140. package/dist/flavors/jis/index.js +267 -0
  141. package/dist/flavors/nist/grammar.d.ts +2 -0
  142. package/dist/flavors/nist/grammar.js +287 -0
  143. package/dist/flavors/nist/index.d.ts +2 -0
  144. package/dist/flavors/nist/index.js +1244 -0
  145. package/dist/flavors/nist/model.d.ts +155 -0
  146. package/dist/flavors/nist/model.js +823 -0
  147. package/dist/flavors/nist/preprocessor.d.ts +11 -0
  148. package/dist/flavors/nist/preprocessor.js +281 -0
  149. package/dist/flavors/oasis/index.d.ts +23 -0
  150. package/dist/flavors/oasis/index.js +110 -0
  151. package/dist/flavors/ogc/index.d.ts +20 -0
  152. package/dist/flavors/ogc/index.js +75 -0
  153. package/dist/flavors/oiml/grammar.d.ts +2 -0
  154. package/dist/flavors/oiml/grammar.js +206 -0
  155. package/dist/flavors/oiml/implementation.d.ts +9 -0
  156. package/dist/flavors/oiml/implementation.js +45 -0
  157. package/dist/flavors/oiml/model.d.ts +23 -0
  158. package/dist/flavors/oiml/model.js +592 -0
  159. package/dist/flavors/omg/index.d.ts +14 -0
  160. package/dist/flavors/omg/index.js +73 -0
  161. package/dist/flavors/plateau/index.d.ts +4 -0
  162. package/dist/flavors/plateau/index.js +97 -0
  163. package/dist/flavors/tgpp/index.d.ts +4 -0
  164. package/dist/flavors/tgpp/index.js +122 -0
  165. package/dist/flavors/un/index.d.ts +13 -0
  166. package/dist/flavors/un/index.js +90 -0
  167. package/dist/flavors/w3c/index.d.ts +14 -0
  168. package/dist/flavors/w3c/index.js +148 -0
  169. package/dist/flavors/xsf/index.d.ts +18 -0
  170. package/dist/flavors/xsf/index.js +65 -0
  171. package/dist/grammar/engine.d.ts +78 -0
  172. package/dist/grammar/engine.js +351 -0
  173. package/dist/index.d.ts +1 -0
  174. package/dist/index.js +3 -0
  175. package/dist/model/attribute.d.ts +54 -0
  176. package/dist/model/attribute.js +53 -0
  177. package/dist/model/builder.d.ts +39 -0
  178. package/dist/model/builder.js +124 -0
  179. package/dist/model/component.d.ts +70 -0
  180. package/dist/model/component.js +170 -0
  181. package/dist/model/identifier.d.ts +84 -0
  182. package/dist/model/identifier.js +270 -0
  183. package/dist/model/urn-generator.d.ts +27 -0
  184. package/dist/model/urn-generator.js +91 -0
  185. package/package.json +1 -1
@@ -0,0 +1,31 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
3
+ import { BaseIdentifier } from "../../model/identifier.js";
4
+ import { PubidDate, Publisher } from "../../model/component.js";
5
+ export declare const gbGrammar: Grammar;
6
+ export declare class GbIdentifier extends BaseIdentifier {
7
+ static polymorphicName: string;
8
+ static attributes: import("../../model/attribute.js").AttributeTable;
9
+ static mappings: import("../../model/attribute.js").FieldMapping[];
10
+ static flatScalarComponents: {
11
+ publisher: string;
12
+ };
13
+ static flatScalarFields: {
14
+ publisher: string;
15
+ };
16
+ readonly publisher: Publisher;
17
+ readonly mandate: string | undefined;
18
+ readonly number: string;
19
+ readonly part: string | undefined;
20
+ readonly date: PubidDate | undefined;
21
+ render(): string;
22
+ }
23
+ export declare class GbAllPartsIdentifier extends BaseIdentifier {
24
+ static polymorphicName: string;
25
+ static get attributes(): import("../../model/attribute.js").AttributeTable;
26
+ static get mappings(): never[];
27
+ readonly identifiers: GbIdentifier[];
28
+ render(): string;
29
+ toUrn(): string;
30
+ }
31
+ export declare function gbGrammarImplementation(): FlavorImplementation;
@@ -0,0 +1,159 @@
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
+ import { PubidDate, Publisher } from "../../model/component.js";
7
+ /**
8
+ * Port of lib/pubid/gb/ on the unified model. The series code lives in
9
+ * the inherited `publisher` (a Publisher, flattened to its body scalar
10
+ * via the class's flat-scalar entry — the CEN precedent); mandate is
11
+ * split out of an inline /T|/Z; date flattens to `year` (shared rule).
12
+ * No Ruby urn_generator: the BASE template derives
13
+ * urn:gb:<publisher>:<number>[:-part][:year] with the publisher
14
+ * lowercased.
15
+ */
16
+ function buildRules() {
17
+ const rules = {};
18
+ const rule = (name, build) => {
19
+ rules[name] = build();
20
+ };
21
+ const space = str(" ");
22
+ const digits = match("[0-9]").repeat(1, Infinity);
23
+ rule("publisher_code", () =>
24
+ // Social-group form: "T/" then uppercase letters/digits.
25
+ (str("T/").then(match("[A-Z0-9]").repeat(1, Infinity))).as("publisher_code")
26
+ // Confidential national series: lowercase "n" is part of the code
27
+ // (PEG: before the uppercase-only branch, no backtracking).
28
+ .or((str("GBn").then(str("/T").or(str("/Z")).maybe())).as("publisher_code"))
29
+ // Standard form: 1-3 letters, optional slash-T-or-Z.
30
+ .or((match("[A-Z]")
31
+ .repeat(1, 3)
32
+ .then(str("/T").or(str("/Z")).maybe()).as("publisher_code"))));
33
+ rule("mandate_suffix", () => str("/").then(str("T").or(str("Z")).as("mandate")).maybe());
34
+ rule("number", () => digits.as("number"));
35
+ rule("part", () => str(".").then(digits.as("part")));
36
+ rule("year", () => str("-").or(str("—")).then(match("[0-9]").repeat(4, 4).as("year")).maybe());
37
+ rule("all_parts_flag", () => space.then(str("("), str("all parts"), str(")")).as("all_parts"));
38
+ rule("identifier", () => rules["publisher_code"]
39
+ .then(space)
40
+ .then(rules["mandate_suffix"])
41
+ .then(rules["number"])
42
+ .then(rules["part"].maybe())
43
+ .then(rules["year"])
44
+ .then(rules["all_parts_flag"].maybe()));
45
+ rule("root", () => rules["identifier"]);
46
+ return rules;
47
+ }
48
+ export const gbGrammar = { rules: buildRules(), root: "root" };
49
+ export class GbIdentifier extends BaseIdentifier {
50
+ static polymorphicName = "pubid:gb:standard";
51
+ static attributes = extendAttributes(BaseIdentifier, {
52
+ publisher: { type: Publisher },
53
+ mandate: { type: "string" },
54
+ number: { type: "string" },
55
+ part: { type: "string" },
56
+ });
57
+ static mappings = keyValue({
58
+ wire: "publisher",
59
+ to: "publisher",
60
+ // The flat wire form is the Publisher's body scalar; rebuild the
61
+ // component on deserialize (lutaml coerces it on the Ruby side).
62
+ fromWire: (hash) => {
63
+ const value = hash["publisher"];
64
+ return typeof value === "string" ? new Publisher({ body: value }) : value;
65
+ },
66
+ }, { wire: "mandate", to: "mandate" }, { wire: "number", to: "number" }, { wire: "part", to: "part" }, { wire: "date", to: "date" });
67
+ // GB's flat-scalar entry: the Publisher serializes as its body scalar.
68
+ static flatScalarComponents = { publisher: "publisher" };
69
+ static flatScalarFields = { publisher: "body" };
70
+ render() {
71
+ let code = this.publisher.body;
72
+ if (this.mandate !== undefined && !code.includes("/"))
73
+ code += `/${this.mandate}`;
74
+ let numberPortion = this.number;
75
+ if (this.part !== undefined)
76
+ numberPortion += `.${this.part}`;
77
+ if (this.date !== undefined && this.date.year !== undefined)
78
+ numberPortion += `-${this.date.year}`;
79
+ return `${code} ${numberPortion}`;
80
+ }
81
+ }
82
+ registerType(GbIdentifier);
83
+ // The document a member names: without its part and its edition (the
84
+ // attributes an all-parts reference ignores).
85
+ function gbDocumentOf(member) {
86
+ const r = member;
87
+ return new GbIdentifier({
88
+ publisher: r["publisher"],
89
+ mandate: r["mandate"],
90
+ number: r["number"],
91
+ });
92
+ }
93
+ // "GB/T 5606 (all parts)" names every part of one document: the wrapper
94
+ // holds the member identifiers (gem #433 - the mark is a class, not a
95
+ // flag), renders the document plus the suffix, and URNs as the document.
96
+ export class GbAllPartsIdentifier extends BaseIdentifier {
97
+ static polymorphicName = "pubid:gb:all-parts";
98
+ static get attributes() {
99
+ return extendAttributes(BaseIdentifier, {
100
+ identifiers: { type: GbIdentifier, collection: true },
101
+ });
102
+ }
103
+ static get mappings() {
104
+ return [{ wire: "identifiers", to: "identifiers" }];
105
+ }
106
+ render() {
107
+ const first = this.identifiers[0];
108
+ return `${first === undefined ? "" : gbDocumentOf(first).render()} (all parts)`;
109
+ }
110
+ toUrn() {
111
+ const first = this.identifiers[0];
112
+ return gbDocumentOf(first).toUrn();
113
+ }
114
+ }
115
+ registerType(GbAllPartsIdentifier);
116
+ class GbBuilder extends BaseBuilder {
117
+ defaultIdentifierClass() {
118
+ return GbIdentifier;
119
+ }
120
+ build(tree) {
121
+ const id = super.build(tree);
122
+ if (tree["all_parts"] === undefined)
123
+ return id;
124
+ // "(all parts)" wraps the document it parsed.
125
+ return new GbAllPartsIdentifier({
126
+ identifiers: [id],
127
+ });
128
+ }
129
+ cast(key, value) {
130
+ if (key === "publisher_code") {
131
+ // Split an inline /T or /Z mandate out of the code.
132
+ const code = String(value);
133
+ const m = /^(.*?)\/(T|Z)$/.exec(code);
134
+ return m
135
+ ? { publisher: new Publisher({ body: m[1] }), mandate: m[2] }
136
+ : { publisher: new Publisher({ body: code }) };
137
+ }
138
+ if (key === "year") {
139
+ return value === undefined || value === null ? null : { date: new PubidDate({ year: String(value) }) };
140
+ }
141
+ if (key === "all_parts") {
142
+ // Presence marker only: the wrapper carries the members.
143
+ return value;
144
+ }
145
+ return value;
146
+ }
147
+ }
148
+ export function gbGrammarImplementation() {
149
+ const builder = new GbBuilder();
150
+ return {
151
+ parse(input) {
152
+ const tree = parseGrammar(gbGrammar, input);
153
+ if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
154
+ throw new ParseFailed("GB: unexpected parse tree", 0);
155
+ }
156
+ return builder.build(tree);
157
+ },
158
+ };
159
+ }
@@ -0,0 +1,2 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ export declare const gostGrammar: Grammar;
@@ -0,0 +1,46 @@
1
+ import { match, ref, str } from "../../grammar/engine.js";
2
+ /**
3
+ * Port of lib/pubid/gost/parser.rb — 1:1. Root: identifier.
4
+ *
5
+ * Captures: gost_word, scope_r (R/Р), prefix_text (copublisher/subtype
6
+ * as a raw string, split by the builder), raw (number+year digit runs),
7
+ * adopted_raw (the foreign id after "/"), adopted_reference_raw (the
8
+ * parenthesized harmonization list).
9
+ */
10
+ function buildRules() {
11
+ const rules = {};
12
+ const rule = (name, build) => {
13
+ rules[name] = build();
14
+ };
15
+ const space = str(" ");
16
+ rule("dot", () => str("."));
17
+ rule("year_sep", () => str("-").or(str("—")).or(str("–")).then(space.maybe()));
18
+ rule("gost_word", () => str("GOST").or(str("ГОСТ")).as("gost_word").then(space));
19
+ rule("scope_r", () => match("R").or(match("Р")).as("scope_r").then(space));
20
+ rule("prefix_text", () => match("[A-ZА-Яa-zа-я/]")
21
+ .repeat(1, Infinity)
22
+ .then(space.then(match("[A-ZА-Яa-zа-я/]").repeat(1, Infinity)).repeat(0, Infinity))
23
+ .as("prefix_text")
24
+ .then(space));
25
+ rule("digits", () => match("[0-9]").repeat(1, Infinity));
26
+ rule("raw_body", () => ref(rules, "digits")
27
+ .then(ref(rules, "dot").or(ref(rules, "year_sep")).then(ref(rules, "digits")).repeat(0, Infinity))
28
+ .as("raw"));
29
+ rule("adopted_part", () => space.maybe().then(str("/")).then(match(".").repeat(1, Infinity).as("adopted_raw")));
30
+ rule("adopted_reference_part", () => space
31
+ .maybe()
32
+ .then(str("("))
33
+ .then(match("[^)]").repeat(1, Infinity).as("adopted_reference_raw"))
34
+ .then(str(")")));
35
+ rule("identifier", () => ref(rules, "gost_word")
36
+ .then(ref(rules, "scope_r").maybe())
37
+ .then(ref(rules, "prefix_text").maybe())
38
+ .then(ref(rules, "raw_body"))
39
+ .then(ref(rules, "adopted_part").maybe())
40
+ .then(ref(rules, "adopted_reference_part").maybe()));
41
+ return rules;
42
+ }
43
+ export const gostGrammar = {
44
+ rules: buildRules(),
45
+ root: "identifier",
46
+ };
@@ -0,0 +1,2 @@
1
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
2
+ export declare function gostGrammarImplementation(): FlavorImplementation;
@@ -0,0 +1,165 @@
1
+ import { parseGrammar } from "../../grammar/engine.js";
2
+ import { grammarImplementation } from "../index.js";
3
+ import { gostGrammar } from "./grammar.js";
4
+ import { PREFIX_ROUTES } from "./prefix_routes.js";
5
+ import { ForeignReference, Harmonized, IdenticalAdoption, InterstateStandard, NationalStandard, } from "./model.js";
6
+ const COPUBLISHER_MAP = {
7
+ "ИСО": "ISO", "МЭК": "IEC", "ЕН": "EN",
8
+ "ИСО/МЭК": "ISO/IEC", "МЭК/ИСО": "IEC/ISO",
9
+ "ИСО/ТУ": "ISO/TS", "ИСО/ТО": "ISO/TR",
10
+ "МЭК/ТУ": "IEC/TS", "МЭК/ТО": "IEC/TR",
11
+ "ИСО/МЭК/ТУ": "ISO/IEC/TS",
12
+ };
13
+ const SUBTYPE_MAP = {
14
+ "МФС": "ISP", "ТУ": "TS", "ТО": "TR",
15
+ };
16
+ const NUMBER_YEAR_SPLIT = /^(.+?)\s*[-—–]\s*(\d{2}|\d{4})$/;
17
+ // The gem's try_each_flavor iterates Registry.flavor_names.sort; this
18
+ // mirrors that order over the TS grammar registry (the still-unported
19
+ // flavors are skipped). bsi's grammar parses bare ISO/IEC/IEEE
20
+ // references (adopted inside BS documents) and returns the owning
21
+ // flavor's identifier — that is what routes the joint "ISO/IEC …"
22
+ // adoptions to the ISO flavor ahead of IEC.
23
+ const FOREIGN_FALLBACK_ORDER = [
24
+ "tgpp", "ansi", "astm", "bipm",
25
+ "bsi",
26
+ "calconnect", "ccsds", "cen_cenelec", "cie", "doi", "easc", "ecma",
27
+ "etsi", "gb", "iala", "iana", "idf", "iec", "ieee", "ietf", "iho",
28
+ "isbn", "iso", "itu", "jcgm", "jis", "nist", "oasis", "ogc", "oiml",
29
+ "omg", "plateau", "un", "w3c", "xsf",
30
+ ];
31
+ const str = (v) => {
32
+ if (v === undefined || v === null)
33
+ return undefined;
34
+ const s = Array.isArray(v) ? v.map(String).join("") : String(v);
35
+ return s.length > 0 ? s : undefined;
36
+ };
37
+ function flatten(tree) {
38
+ return Array.isArray(tree) ? Object.assign({}, ...tree) : tree;
39
+ }
40
+ function buildIdentifier(tree) {
41
+ return buildFrom(flatten(tree));
42
+ }
43
+ function buildFrom(d) {
44
+ const russian = d["scope_r"] !== undefined;
45
+ const [copublisher, subtype] = splitPrefix(str(d["prefix_text"]));
46
+ const [number, year] = splitNumberYear(str(d["raw"]));
47
+ const klass = (russian ? NationalStandard : InterstateStandard);
48
+ const base = new klass({
49
+ ...(copublisher !== undefined ? { copublisher } : {}),
50
+ ...(subtype !== undefined ? { subtype } : {}),
51
+ ...(number !== undefined ? { number } : {}),
52
+ ...(year !== undefined ? { year } : {}),
53
+ });
54
+ return withForeignAdoption(base, d);
55
+ }
56
+ function withForeignAdoption(base, d) {
57
+ return wrapHarmonized(wrapIdenticalAdoption(base, d), d);
58
+ }
59
+ function wrapIdenticalAdoption(base, d) {
60
+ const adoptedRaw = str(d["adopted_raw"]);
61
+ if (adoptedRaw === undefined)
62
+ return base;
63
+ const adopted = parseForeign(adoptedRaw);
64
+ const klass = IdenticalAdoption;
65
+ return new klass({ base, adopted });
66
+ }
67
+ function wrapHarmonized(base, d) {
68
+ const referenceRaw = str(d["adopted_reference_raw"]);
69
+ if (referenceRaw === undefined)
70
+ return base;
71
+ const adopted = referenceRaw
72
+ .split(",")
73
+ .map((s) => s.trim())
74
+ .map(normalizeForeign)
75
+ .map(adoptIdentifier);
76
+ const klass = Harmonized;
77
+ return new klass({ base, adoptedIdentifiers: adopted });
78
+ }
79
+ function adoptIdentifier(raw) {
80
+ return parseForeign(raw) ?? new ForeignReference({ raw });
81
+ }
82
+ function splitPrefix(text) {
83
+ if (text === undefined)
84
+ return [undefined, undefined];
85
+ const tokens = text.trim().split(/\s+/);
86
+ const copublisher = normalizeCopublisher(tokens[0]);
87
+ const subtype = tokens.length > 1 ? normalizeSubtype(tokens.slice(1).join(" ")) : undefined;
88
+ return [copublisher, subtype];
89
+ }
90
+ function normalizeCopublisher(raw) {
91
+ if (raw === undefined)
92
+ return undefined;
93
+ return COPUBLISHER_MAP[raw] ?? raw.toUpperCase();
94
+ }
95
+ function normalizeSubtype(raw) {
96
+ if (raw === undefined)
97
+ return undefined;
98
+ return SUBTYPE_MAP[raw] ?? raw;
99
+ }
100
+ // Longest keys first so "ИСО/МЭК" wins over "ИСО".
101
+ function normalizeForeign(raw) {
102
+ for (const cyr of Object.keys(COPUBLISHER_MAP).sort((a, b) => b.length - a.length)) {
103
+ if (raw.startsWith(cyr + " ") || raw.startsWith(cyr + "/")) {
104
+ return COPUBLISHER_MAP[cyr] + raw.slice(cyr.length);
105
+ }
106
+ }
107
+ return raw;
108
+ }
109
+ function splitNumberYear(raw) {
110
+ if (raw === undefined)
111
+ return [undefined, undefined];
112
+ const m = NUMBER_YEAR_SPLIT.exec(raw);
113
+ if (m === null)
114
+ return [raw, undefined];
115
+ return [m[1], m[2]];
116
+ }
117
+ // The single flavor owning the longest matching prefix; undefined when
118
+ // no prefix matches or the prefix is jointly owned (joint forms go
119
+ // through the fallback loop).
120
+ function prefixOwner(raw) {
121
+ let match;
122
+ for (const prefix of Object.keys(PREFIX_ROUTES)) {
123
+ if ((raw.startsWith(`${prefix} `) || raw === prefix) &&
124
+ (match === undefined || prefix.length > match.length)) {
125
+ match = prefix;
126
+ }
127
+ }
128
+ if (match === undefined)
129
+ return undefined;
130
+ const owners = PREFIX_ROUTES[match] ?? [];
131
+ return owners.length === 1 ? owners[0] : undefined;
132
+ }
133
+ function tryParse(flavor, raw) {
134
+ const impl = grammarImplementation(flavor);
135
+ if (impl === undefined)
136
+ return undefined;
137
+ try {
138
+ return impl.parse(raw);
139
+ }
140
+ catch {
141
+ return undefined;
142
+ }
143
+ }
144
+ function parseForeign(raw) {
145
+ const owner = prefixOwner(raw);
146
+ if (owner !== undefined) {
147
+ const parsed = tryParse(owner, raw);
148
+ if (parsed !== undefined)
149
+ return parsed;
150
+ }
151
+ for (const flavor of FOREIGN_FALLBACK_ORDER) {
152
+ const parsed = tryParse(flavor, raw);
153
+ if (parsed !== undefined)
154
+ return parsed;
155
+ }
156
+ return undefined;
157
+ }
158
+ export function gostGrammarImplementation() {
159
+ return {
160
+ parse(input) {
161
+ const tree = parseGrammar(gostGrammar, input.trim());
162
+ return buildIdentifier(tree);
163
+ },
164
+ };
165
+ }
@@ -0,0 +1,61 @@
1
+ import { BaseIdentifier } from "../../model/identifier.js";
2
+ import { type FieldMapping } from "../../model/attribute.js";
3
+ import { BaseUrnGenerator } from "../../model/urn-generator.js";
4
+ /**
5
+ * Port of lib/pubid/gost: the five identifier classes
6
+ * (interstate/national standard, identical adoption, harmonized,
7
+ * foreign reference), the renderer and the URN generator.
8
+ *
9
+ * GOST shape: GOST [R ][<copublisher> ][<subtype> ]<number>[-<year>]
10
+ * [/<adopted>][(<refs>)]
11
+ */
12
+ export declare abstract class GostIdentifier extends BaseIdentifier {
13
+ static attributes: import("../../model/attribute.js").AttributeTable;
14
+ static mappings: FieldMapping[];
15
+ readonly copublisher: string | undefined;
16
+ readonly subtype: string | undefined;
17
+ readonly number: string | undefined;
18
+ readonly year: string | undefined;
19
+ }
20
+ declare class GostUrnGenerator extends BaseUrnGenerator<GostIdentifier> {
21
+ generate(): string;
22
+ }
23
+ export declare class InterstateStandard extends GostIdentifier {
24
+ static polymorphicName: string;
25
+ static urnGenerator: typeof GostUrnGenerator;
26
+ render(): string;
27
+ }
28
+ export declare class NationalStandard extends GostIdentifier {
29
+ static polymorphicName: string;
30
+ static urnGenerator: typeof GostUrnGenerator;
31
+ render(): string;
32
+ }
33
+ export declare class ForeignReference extends GostIdentifier {
34
+ static polymorphicName: string;
35
+ static get attributes(): import("../../model/attribute.js").AttributeTable;
36
+ static mappings: FieldMapping[];
37
+ readonly raw: string | undefined;
38
+ render(): string;
39
+ }
40
+ declare function delegatedWireFields(model: BaseIdentifier, hash: Record<string, unknown>): void;
41
+ export declare class Harmonized extends GostIdentifier {
42
+ static polymorphicName: string;
43
+ static urnGenerator: typeof GostUrnGenerator;
44
+ static get attributes(): import("../../model/attribute.js").AttributeTable;
45
+ static mappings: FieldMapping[];
46
+ static compactHash: typeof delegatedWireFields;
47
+ readonly base: GostIdentifier | undefined;
48
+ readonly adoptedIdentifiers: GostIdentifier[] | undefined;
49
+ render(): string;
50
+ }
51
+ export declare class IdenticalAdoption extends GostIdentifier {
52
+ static polymorphicName: string;
53
+ static urnGenerator: typeof GostUrnGenerator;
54
+ static get attributes(): import("../../model/attribute.js").AttributeTable;
55
+ static mappings: FieldMapping[];
56
+ static compactHash: typeof delegatedWireFields;
57
+ readonly base: GostIdentifier | undefined;
58
+ readonly adopted: GostIdentifier | undefined;
59
+ render(): string;
60
+ }
61
+ export {};
@@ -0,0 +1,147 @@
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/gost: the five identifier classes
6
+ * (interstate/national standard, identical adoption, harmonized,
7
+ * foreign reference), the renderer and the URN generator.
8
+ *
9
+ * GOST shape: GOST [R ][<copublisher> ][<subtype> ]<number>[-<year>]
10
+ * [/<adopted>][(<refs>)]
11
+ */
12
+ export class GostIdentifier extends BaseIdentifier {
13
+ static attributes = extendAttributes(BaseIdentifier, {
14
+ copublisher: { type: "string" },
15
+ subtype: { type: "string" },
16
+ number: { type: "string" },
17
+ year: { type: "string" },
18
+ });
19
+ // publisher defaults to "GOST" but is deliberately NOT mapped: the
20
+ // Ruby class declares it without a key_value entry, so it never
21
+ // serializes (a default-equal scalar would drop anyway).
22
+ static mappings = keyValue({ wire: "copublisher", to: "copublisher" }, { wire: "subtype", to: "subtype" }, { wire: "number", to: "number" }, { wire: "year", to: "year" });
23
+ }
24
+ function renderStandard(id) {
25
+ const national = id instanceof NationalStandard;
26
+ return [
27
+ "GOST",
28
+ national ? " R" : "",
29
+ id.copublisher !== undefined ? ` ${id.copublisher}` : "",
30
+ id.subtype !== undefined ? ` ${id.subtype}` : "",
31
+ ` ${id.number ?? ""}`,
32
+ id.year !== undefined ? `-${id.year}` : "",
33
+ ].join("");
34
+ }
35
+ class GostUrnGenerator extends BaseUrnGenerator {
36
+ generate() {
37
+ let id = this.identifier;
38
+ while (id instanceof Harmonized || id instanceof IdenticalAdoption) {
39
+ id = id.base;
40
+ }
41
+ if (!(id instanceof InterstateStandard) && !(id instanceof NationalStandard)) {
42
+ throw new Error(`Unknown GOST identifier class: ${id.constructor.name}`);
43
+ }
44
+ const parts = ["urn", "gost", "std"];
45
+ if (id instanceof NationalStandard)
46
+ parts.push("r");
47
+ if (id.number !== undefined)
48
+ parts.push(id.number);
49
+ if (id.year !== undefined)
50
+ parts.push(id.year);
51
+ return parts.join(":");
52
+ }
53
+ }
54
+ export class InterstateStandard extends GostIdentifier {
55
+ static polymorphicName = "pubid:gost:interstate-standard";
56
+ static urnGenerator = GostUrnGenerator;
57
+ render() {
58
+ return renderStandard(this);
59
+ }
60
+ }
61
+ export class NationalStandard extends GostIdentifier {
62
+ static polymorphicName = "pubid:gost:national-standard";
63
+ static urnGenerator = GostUrnGenerator;
64
+ render() {
65
+ return renderStandard(this);
66
+ }
67
+ }
68
+ export class ForeignReference extends GostIdentifier {
69
+ static polymorphicName = "pubid:gost:foreign-reference";
70
+ // raw is instance-only: never declared on the wire (the Ruby class
71
+ // declares the attribute without a key_value mapping).
72
+ static get attributes() {
73
+ return extendAttributes(GostIdentifier, { raw: { type: "string" } });
74
+ }
75
+ static mappings = [];
76
+ render() {
77
+ return this.raw ?? "";
78
+ }
79
+ }
80
+ // number/year/copublisher/subtype delegate to base (Ruby overrides the
81
+ // getters); the delegated values ride along on the wire via the
82
+ // compactHash hook.
83
+ function delegatedWireFields(model, hash) {
84
+ const base = model.base;
85
+ if (base === undefined)
86
+ return;
87
+ if (base.number !== undefined)
88
+ hash["number"] = base.number;
89
+ if (base.year !== undefined)
90
+ hash["year"] = base.year;
91
+ if (base.copublisher !== undefined)
92
+ hash["copublisher"] = base.copublisher;
93
+ if (base.subtype !== undefined)
94
+ hash["subtype"] = base.subtype;
95
+ }
96
+ export class Harmonized extends GostIdentifier {
97
+ static polymorphicName = "pubid:gost:harmonized";
98
+ static urnGenerator = GostUrnGenerator;
99
+ static get attributes() {
100
+ return extendAttributes(GostIdentifier, {
101
+ base: { type: GostIdentifier },
102
+ adoptedIdentifiers: {
103
+ type: GostIdentifier,
104
+ collection: true,
105
+ },
106
+ });
107
+ }
108
+ static mappings = [
109
+ ...GostIdentifier.mappings,
110
+ { wire: "base", to: "base" },
111
+ { wire: "adopted_identifiers", to: "adoptedIdentifiers" },
112
+ ];
113
+ static compactHash = delegatedWireFields;
114
+ render() {
115
+ const base = this.base?.toHuman() ?? "";
116
+ const adopted = (this.adoptedIdentifiers ?? []).map((a) => a.toHuman()).join(", ");
117
+ return adopted === "" ? base : `${base} (${adopted})`;
118
+ }
119
+ }
120
+ export class IdenticalAdoption extends GostIdentifier {
121
+ static polymorphicName = "pubid:gost:identical-adoption";
122
+ static urnGenerator = GostUrnGenerator;
123
+ static get attributes() {
124
+ return extendAttributes(GostIdentifier, {
125
+ base: { type: GostIdentifier },
126
+ adopted: { type: GostIdentifier },
127
+ });
128
+ }
129
+ static mappings = [
130
+ ...GostIdentifier.mappings,
131
+ { wire: "base", to: "base" },
132
+ { wire: "adopted", to: "adopted" },
133
+ ];
134
+ static compactHash = delegatedWireFields;
135
+ render() {
136
+ return `${this.base?.toHuman() ?? ""}/${this.adopted?.toHuman() ?? ""}`;
137
+ }
138
+ }
139
+ for (const klass of [
140
+ InterstateStandard,
141
+ NationalStandard,
142
+ ForeignReference,
143
+ Harmonized,
144
+ IdenticalAdoption,
145
+ ]) {
146
+ registerType(klass);
147
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * GENERATED from the Ruby gem (Pubid.prefix_flavors after
3
+ * eager_load_flavors!) — the prefix→flavors routing table. Regenerate
4
+ * from the pubid gem with:
5
+ * bundle exec ruby -e 'require "pubid"; Pubid.eager_load_flavors!;
6
+ * require "json"; puts JSON.pretty_generate(Pubid.prefix_flavors
7
+ * .transform_values { |v| v.sort })'
8
+ * Do not edit by hand.
9
+ *
10
+ * Used by the gost flavor's foreign-adoption routing (prefix_owner in
11
+ * index.ts): the single flavor owning the longest matching prefix parses
12
+ * the adopted identifier; joint prefixes (ISO/IEC, ANSI/AMCA…) fall
13
+ * through to the sorted fallback loop.
14
+ */
15
+ export declare const PREFIX_ROUTES: Record<string, string[]>;