@pubid/pubid 0.1.3 → 0.1.4

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 (183) 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 +24 -0
  80. package/dist/flavors/gb/index.js +111 -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 +626 -0
  107. package/dist/flavors/ieee/index.d.ts +3 -0
  108. package/dist/flavors/ieee/index.js +1186 -0
  109. package/dist/flavors/ieee/model.d.ts +142 -0
  110. package/dist/flavors/ieee/model.js +1148 -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 +191 -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 +180 -0
  155. package/dist/flavors/oiml/implementation.d.ts +9 -0
  156. package/dist/flavors/oiml/implementation.js +16 -0
  157. package/dist/flavors/oiml/model.d.ts +4 -0
  158. package/dist/flavors/oiml/model.js +462 -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/model/attribute.d.ts +54 -0
  174. package/dist/model/attribute.js +53 -0
  175. package/dist/model/builder.d.ts +39 -0
  176. package/dist/model/builder.js +124 -0
  177. package/dist/model/component.d.ts +70 -0
  178. package/dist/model/component.js +170 -0
  179. package/dist/model/identifier.d.ts +83 -0
  180. package/dist/model/identifier.js +270 -0
  181. package/dist/model/urn-generator.d.ts +27 -0
  182. package/dist/model/urn-generator.js +91 -0
  183. package/package.json +1 -1
@@ -0,0 +1,30 @@
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
+ export declare const ietfGrammar: Grammar;
6
+ declare abstract class IetfIdentifier extends BaseIdentifier {
7
+ readonly number: string | undefined;
8
+ /** Fail loudly on a nil number rather than keying the index under "". */
9
+ requireNumber(): string;
10
+ }
11
+ declare class IetfUrnGenerator extends BaseUrnGenerator<IetfIdentifier> {
12
+ generate(): string;
13
+ }
14
+ export declare class IetfRfc extends IetfIdentifier {
15
+ static polymorphicName: string;
16
+ static attributes: import("../../model/attribute.js").AttributeTable;
17
+ static mappings: import("../../model/attribute.js").FieldMapping[];
18
+ static urnGenerator: typeof IetfUrnGenerator;
19
+ render(): string;
20
+ }
21
+ export declare class IetfInternetDraft extends IetfIdentifier {
22
+ static polymorphicName: string;
23
+ static attributes: import("../../model/attribute.js").AttributeTable;
24
+ static mappings: import("../../model/attribute.js").FieldMapping[];
25
+ static urnGenerator: typeof IetfUrnGenerator;
26
+ readonly version: string | undefined;
27
+ render(): string;
28
+ }
29
+ export declare function ietfGrammarImplementation(): FlavorImplementation;
30
+ export {};
@@ -0,0 +1,151 @@
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/ietf/ on the unified model — 2,526 corpus rows.
8
+ * Three flat families keyed by leading token: RFC, the BCP/STD/FYI
9
+ * sub-series (series derived from the class, never stored — `_type`
10
+ * already carries it), and Internet-Drafts (slug including "draft-" in
11
+ * `number`, optional trailing two-digit `version`). URNs:
12
+ * urn:ietf:rfc:n / urn:ietf:{bcp|std|fyi}:n / urn:ietf:id:draft-slug[:v].
13
+ */
14
+ function buildRules() {
15
+ const rules = {};
16
+ const rule = (name, build) => {
17
+ rules[name] = build();
18
+ };
19
+ const digits = match("[0-9]").repeat(1, Infinity);
20
+ // "RFC 2119" and the zero-padded space-less spelling rfc-index.xml
21
+ // emits ("RFC0001") — the Builder strips the pad.
22
+ rule("rfc", () => str("RFC").then(str(" ").maybe(), digits.as("number")));
23
+ // "BCP 3" / "STD 66" / "FYI 1", plus the padded "<is-also>STD0066"
24
+ // form relaton builds cross-references from, unnormalized.
25
+ rule("subseries", () => str("BCP")
26
+ .or(str("STD"), str("FYI"))
27
+ .as("series")
28
+ .then(str(" ").maybe(), digits.as("number")));
29
+ // Draft slug characters plus the two historical shapes the corpus
30
+ // carries: a dot inside a topic token and uppercase protocol names.
31
+ rule("draft_rest", () => match("[a-zA-Z0-9+_.\\-]").repeat(1, Infinity).as("draft_rest"));
32
+ rule("draft", () => str("draft-").then(rules["draft_rest"]));
33
+ rule("identifier", () => rules["rfc"].or(rules["subseries"], rules["draft"]));
34
+ rule("root", () => rules["identifier"]);
35
+ return rules;
36
+ }
37
+ export const ietfGrammar = { rules: buildRules(), root: "root" };
38
+ class IetfIdentifier extends BaseIdentifier {
39
+ /** Fail loudly on a nil number rather than keying the index under "". */
40
+ requireNumber() {
41
+ if (this.number === undefined || this.number === "") {
42
+ throw new ParseFailed(`Cannot render ${this.constructor.polymorphicName} with an empty number`, 0);
43
+ }
44
+ return this.number;
45
+ }
46
+ }
47
+ class IetfUrnGenerator extends BaseUrnGenerator {
48
+ generate() {
49
+ const id = this.identifier;
50
+ if (id instanceof IetfRfc)
51
+ return `urn:ietf:rfc:${id.requireNumber()}`;
52
+ if (id instanceof IetfInternetDraft) {
53
+ const base = `urn:ietf:id:${id.requireNumber()}`;
54
+ return id.version === undefined ? base : `${base}:${id.version}`;
55
+ }
56
+ if (id instanceof IetfSubseriesBase) {
57
+ return `urn:ietf:${id.seriesToken().toLowerCase()}:${id.requireNumber()}`;
58
+ }
59
+ throw new ParseFailed("IETF: not a concrete identifier", 0);
60
+ }
61
+ }
62
+ class IetfSubseriesBase extends IetfIdentifier {
63
+ static attributes = extendAttributes(BaseIdentifier, {
64
+ number: { type: "string" },
65
+ });
66
+ static mappings = keyValue({ wire: "number", to: "number" });
67
+ static urnGenerator = IetfUrnGenerator;
68
+ render() {
69
+ return `${this.seriesToken()} ${this.requireNumber()}`;
70
+ }
71
+ }
72
+ export class IetfRfc extends IetfIdentifier {
73
+ static polymorphicName = "pubid:ietf:rfc";
74
+ static attributes = extendAttributes(BaseIdentifier, {
75
+ number: { type: "string" },
76
+ });
77
+ static mappings = keyValue({ wire: "number", to: "number" });
78
+ static urnGenerator = IetfUrnGenerator;
79
+ render() {
80
+ return `RFC ${this.requireNumber()}`;
81
+ }
82
+ }
83
+ registerType(IetfRfc);
84
+ function subseriesClass(kind, token) {
85
+ class IetfSubseriesKind extends IetfSubseriesBase {
86
+ static polymorphicName = `pubid:ietf:${kind}`;
87
+ seriesToken() {
88
+ return token;
89
+ }
90
+ }
91
+ registerType(IetfSubseriesKind);
92
+ return IetfSubseriesKind;
93
+ }
94
+ const SUBSERIES_CLASSES = {
95
+ bcp: subseriesClass("bcp", "BCP"),
96
+ std: subseriesClass("std", "STD"),
97
+ fyi: subseriesClass("fyi", "FYI"),
98
+ };
99
+ export class IetfInternetDraft extends IetfIdentifier {
100
+ static polymorphicName = "pubid:ietf:internet-draft";
101
+ static attributes = extendAttributes(BaseIdentifier, {
102
+ number: { type: "string" },
103
+ version: { type: "string" },
104
+ });
105
+ static mappings = keyValue({ wire: "number", to: "number" }, { wire: "version", to: "version" });
106
+ static urnGenerator = IetfUrnGenerator;
107
+ render() {
108
+ const number = this.requireNumber();
109
+ return this.version === undefined ? number : `${number}-${this.version}`;
110
+ }
111
+ }
112
+ registerType(IetfInternetDraft);
113
+ const SUBSERIES_TOKENS = {
114
+ BCP: "bcp",
115
+ STD: "std",
116
+ FYI: "fyi",
117
+ };
118
+ /** Strip the rfc-index.xml zero-pad ("STD0066" → "66"; "000" stays "0"). */
119
+ function unpad(number) {
120
+ return number.replace(/^0+(?=\d)/, "");
121
+ }
122
+ /**
123
+ * A draft version is a trailing "-NN" of exactly two digits at the very
124
+ * end: a three-digit topic tail ("…-256") keeps its char-before-last-two
125
+ * a digit, not "-", so it stays in the slug.
126
+ */
127
+ function splitDraftVersion(full) {
128
+ if (full.length > 3 && full.at(-3) === "-" && /^\d\d$/.test(full.slice(-2))) {
129
+ return [full.slice(0, -3), full.slice(-2)];
130
+ }
131
+ return [full, undefined];
132
+ }
133
+ export function ietfGrammarImplementation() {
134
+ return {
135
+ parse(input) {
136
+ const tree = parseGrammar(ietfGrammar, input);
137
+ if (typeof tree !== "object" || tree === null) {
138
+ throw new ParseFailed("IETF: unexpected parse tree", 0);
139
+ }
140
+ if (tree["draft_rest"] !== undefined) {
141
+ const [slug, version] = splitDraftVersion(`draft-${String(tree["draft_rest"])}`);
142
+ return new IetfInternetDraft({ number: slug, ...(version !== undefined ? { version } : {}) });
143
+ }
144
+ if (tree["series"] !== undefined) {
145
+ const klass = SUBSERIES_CLASSES[SUBSERIES_TOKENS[String(tree["series"])]];
146
+ return new klass({ number: unpad(String(tree["number"])) });
147
+ }
148
+ return new IetfRfc({ number: unpad(String(tree["number"])) });
149
+ },
150
+ };
151
+ }
@@ -0,0 +1,4 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
3
+ export declare const ihoGrammar: Grammar;
4
+ export declare function ihoGrammarImplementation(): FlavorImplementation;
@@ -0,0 +1,126 @@
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
+ const KIND_LETTERS = {
8
+ standard: "S",
9
+ publication: "P",
10
+ miscellaneous: "M",
11
+ bibliographic: "B",
12
+ "circular-letter": "C",
13
+ };
14
+ function buildRules() {
15
+ const rules = {};
16
+ const rule = (name, build) => {
17
+ rules[name] = build();
18
+ };
19
+ const space = str(" ");
20
+ const dash = str("-");
21
+ const dot = str(".");
22
+ const digits = match("[0-9]").repeat(1, Infinity);
23
+ rule("series", () => str("S").or(str("P"), str("M"), str("B"), str("C")).as("type"));
24
+ rule("number_suffix", () => str(":").then(digits).or(str("/").then(digits)).or(dash.then(digits)).or(match("[A-Z]")));
25
+ rule("number", () => digits.then(rules["number_suffix"].maybe()).as("number"));
26
+ rule("appendix", () => space
27
+ .then(str("Appendix").or(str("Ap.")))
28
+ .then(space, match("[A-Z]").then(dash, digits).or(digits).or(match("[A-Z]")).as("appendix")));
29
+ rule("part", () => space.then(str("Part")).then(space, digits.then(match("[a-zA-Z]").repeat(0, Infinity)).as("part").or(match("[A-Z]").as("part"))));
30
+ rule("annex", () => space.then(str("Annex")).then(space, match("[A-Z]").as("annex")));
31
+ rule("supplement", () => space.then(str("Suppl")).then(space, digits.as("supplement")));
32
+ rule("version", () => space.then(digits.then(dot, digits, dot, digits).as("version")));
33
+ rule("identifier", () => str("IHO")
34
+ .then(space)
35
+ .maybe()
36
+ .then(rules["series"], dash, rules["number"])
37
+ .then(rules["appendix"].maybe())
38
+ .then(rules["part"].maybe())
39
+ .then(rules["annex"].maybe())
40
+ .then(rules["supplement"].maybe())
41
+ .then(rules["version"].maybe()));
42
+ rule("root", () => rules["identifier"]);
43
+ return rules;
44
+ }
45
+ export const ihoGrammar = { rules: buildRules(), root: "root" };
46
+ function ihoClass(kind) {
47
+ const letter = KIND_LETTERS[kind];
48
+ class IhoKindIdentifier extends BaseIdentifier {
49
+ static polymorphicName = `pubid:iho:${kind}`;
50
+ static attributes = extendAttributes(BaseIdentifier, {
51
+ number: { type: "string" },
52
+ appendix: { type: "string" },
53
+ part: { type: "string" },
54
+ annex: { type: "string" },
55
+ supplement: { type: "string" },
56
+ version: { type: "string" },
57
+ });
58
+ static mappings = keyValue({ wire: "number", to: "number" }, { wire: "appendix", to: "appendix" }, { wire: "part", to: "part" }, { wire: "annex", to: "annex" }, { wire: "supplement", to: "supplement" }, { wire: "version", to: "version" });
59
+ render() {
60
+ let result = `IHO ${letter}-${this.number}`;
61
+ if (this.appendix !== undefined)
62
+ result += ` Ap. ${this.appendix}`;
63
+ if (this.part !== undefined)
64
+ result += ` Part ${this.part}`;
65
+ if (this.annex !== undefined)
66
+ result += ` Annex ${this.annex}`;
67
+ if (this.supplement !== undefined)
68
+ result += ` Suppl ${this.supplement}`;
69
+ if (this.version !== undefined)
70
+ result += ` ${this.version}`;
71
+ return result;
72
+ }
73
+ }
74
+ class IhoUrnGenerator extends BaseUrnGenerator {
75
+ generate() {
76
+ const id = this.identifier;
77
+ const parts = ["urn", "iho", letter.toLowerCase(), id.number];
78
+ if (id.appendix !== undefined)
79
+ parts.push(`ap.${id.appendix}`);
80
+ if (id.part !== undefined)
81
+ parts.push(`part.${id.part}`);
82
+ if (id.annex !== undefined)
83
+ parts.push(`annex.${id.annex}`);
84
+ if (id.supplement !== undefined)
85
+ parts.push(`suppl.${id.supplement}`);
86
+ if (id.version !== undefined)
87
+ parts.push(id.version);
88
+ return parts.join(":");
89
+ }
90
+ }
91
+ IhoKindIdentifier.urnGenerator = IhoUrnGenerator;
92
+ registerType(IhoKindIdentifier);
93
+ return IhoKindIdentifier;
94
+ }
95
+ const KIND_CLASSES = {
96
+ standard: ihoClass("standard"),
97
+ publication: ihoClass("publication"),
98
+ miscellaneous: ihoClass("miscellaneous"),
99
+ bibliographic: ihoClass("bibliographic"),
100
+ "circular-letter": ihoClass("circular-letter"),
101
+ };
102
+ const LETTER_TO_CLASS = new Map(Object.keys(KIND_LETTERS).map((kind) => [KIND_LETTERS[kind], KIND_CLASSES[kind]]));
103
+ class IhoBuilder extends BaseBuilder {
104
+ selectClass(data) {
105
+ const kind = LETTER_TO_CLASS.get(String(data["type"]));
106
+ if (kind === undefined) {
107
+ throw new ParseFailed(`IHO: unknown series ${String(data["type"])}`, 0);
108
+ }
109
+ return kind;
110
+ }
111
+ defaultIdentifierClass() {
112
+ return KIND_CLASSES["standard"];
113
+ }
114
+ }
115
+ export function ihoGrammarImplementation() {
116
+ const builder = new IhoBuilder();
117
+ return {
118
+ parse(input) {
119
+ const tree = parseGrammar(ihoGrammar, input);
120
+ if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
121
+ throw new ParseFailed("IHO: unexpected parse tree", 0);
122
+ }
123
+ return builder.build(tree);
124
+ },
125
+ };
126
+ }
@@ -0,0 +1,9 @@
1
+ import type { FlavorImplementation } from "../conformance/implementation.js";
2
+ /**
3
+ * The grammar-wave registry: flavors whose Ruby grammar has been ported
4
+ * to a TypeScript implementation. A flavor listed here parses
5
+ * open-endedly (real-world spellings beyond the corpus); the
6
+ * conformance gate enforces parity with the corpus floor for it. Every
7
+ * flavor NOT listed falls back to corpus mode.
8
+ */
9
+ export declare function grammarImplementation(flavor: string): FlavorImplementation | undefined;
@@ -0,0 +1,136 @@
1
+ import { oimlGrammarImplementation } from "./oiml/implementation.js";
2
+ import { xsfGrammarImplementation } from "./xsf/index.js";
3
+ import { doiGrammarImplementation } from "./doi/index.js";
4
+ import { ianaGrammarImplementation } from "./iana/index.js";
5
+ import { unGrammarImplementation } from "./un/index.js";
6
+ import { plateauGrammarImplementation } from "./plateau/index.js";
7
+ import { w3cGrammarImplementation } from "./w3c/index.js";
8
+ import { omgGrammarImplementation } from "./omg/index.js";
9
+ import { ogcGrammarImplementation } from "./ogc/index.js";
10
+ import { isbnGrammarImplementation } from "./isbn/index.js";
11
+ import { eascGrammarImplementation } from "./easc/index.js";
12
+ import { ecmaGrammarImplementation } from "./ecma/index.js";
13
+ import { tgppGrammarImplementation } from "./tgpp/index.js";
14
+ import { ansiGrammarImplementation } from "./ansi/index.js";
15
+ import { oasisGrammarImplementation } from "./oasis/index.js";
16
+ import { ihoGrammarImplementation } from "./iho/index.js";
17
+ import { calconnectGrammarImplementation } from "./calconnect/index.js";
18
+ import { gbGrammarImplementation } from "./gb/index.js";
19
+ import { jcgmGrammarImplementation } from "./jcgm/index.js";
20
+ import { etsiGrammarImplementation } from "./etsi/index.js";
21
+ import { jisGrammarImplementation } from "./jis/index.js";
22
+ import { iecGrammarImplementation } from "./iec/index.js";
23
+ import { cieGrammarImplementation } from "./cie/index.js";
24
+ import { bipmGrammarImplementation } from "./bipm/index.js";
25
+ import { isoGrammarImplementation } from "./iso/index.js";
26
+ import { nistGrammarImplementation } from "./nist/index.js";
27
+ import { ieeeGrammarImplementation } from "./ieee/index.js";
28
+ import { cenCenelecGrammarImplementation } from "./cen_cenelec/index.js";
29
+ import { astmGrammarImplementation } from "./astm/index.js";
30
+ import { idfGrammarImplementation } from "./idf/index.js";
31
+ import { gostGrammarImplementation } from "./gost/index.js";
32
+ import { evsGrammarImplementation } from "./evs/index.js";
33
+ import { ashraeGrammarImplementation } from "./ashrae/index.js";
34
+ import { bsiGrammarImplementation } from "./bsi/index.js";
35
+ import { csaGrammarImplementation } from "./csa/index.js";
36
+ import { asmeGrammarImplementation } from "./asme/index.js";
37
+ import { amcaGrammarImplementation } from "./amca/index.js";
38
+ import { apiGrammarImplementation } from "./api/index.js";
39
+ import { ituGrammarImplementation } from "./itu/index.js";
40
+ import { ietfGrammarImplementation } from "./ietf/index.js";
41
+ import { ialaGrammarImplementation } from "./iala/index.js";
42
+ /**
43
+ * The grammar-wave registry: flavors whose Ruby grammar has been ported
44
+ * to a TypeScript implementation. A flavor listed here parses
45
+ * open-endedly (real-world spellings beyond the corpus); the
46
+ * conformance gate enforces parity with the corpus floor for it. Every
47
+ * flavor NOT listed falls back to corpus mode.
48
+ */
49
+ export function grammarImplementation(flavor) {
50
+ switch (flavor) {
51
+ case "oiml":
52
+ return oimlGrammarImplementation();
53
+ case "xsf":
54
+ return xsfGrammarImplementation();
55
+ case "doi":
56
+ return doiGrammarImplementation();
57
+ case "iana":
58
+ return ianaGrammarImplementation();
59
+ case "un":
60
+ return unGrammarImplementation();
61
+ case "plateau":
62
+ return plateauGrammarImplementation();
63
+ case "w3c":
64
+ return w3cGrammarImplementation();
65
+ case "omg":
66
+ return omgGrammarImplementation();
67
+ case "ogc":
68
+ return ogcGrammarImplementation();
69
+ case "isbn":
70
+ return isbnGrammarImplementation();
71
+ case "easc":
72
+ return eascGrammarImplementation();
73
+ case "ecma":
74
+ return ecmaGrammarImplementation();
75
+ case "tgpp":
76
+ return tgppGrammarImplementation();
77
+ case "ansi":
78
+ return ansiGrammarImplementation();
79
+ case "oasis":
80
+ return oasisGrammarImplementation();
81
+ case "iho":
82
+ return ihoGrammarImplementation();
83
+ case "calconnect":
84
+ return calconnectGrammarImplementation();
85
+ case "gb":
86
+ return gbGrammarImplementation();
87
+ case "jcgm":
88
+ return jcgmGrammarImplementation();
89
+ case "etsi":
90
+ return etsiGrammarImplementation();
91
+ case "jis":
92
+ return jisGrammarImplementation();
93
+ case "iec":
94
+ return iecGrammarImplementation();
95
+ case "cie":
96
+ return cieGrammarImplementation();
97
+ case "bipm":
98
+ return bipmGrammarImplementation();
99
+ case "iso":
100
+ return isoGrammarImplementation();
101
+ case "nist":
102
+ return nistGrammarImplementation();
103
+ case "ieee":
104
+ return ieeeGrammarImplementation();
105
+ case "cen_cenelec":
106
+ return cenCenelecGrammarImplementation();
107
+ case "astm":
108
+ return astmGrammarImplementation();
109
+ case "idf":
110
+ return idfGrammarImplementation();
111
+ case "gost":
112
+ return gostGrammarImplementation();
113
+ case "evs":
114
+ return evsGrammarImplementation();
115
+ case "ashrae":
116
+ return ashraeGrammarImplementation();
117
+ case "bsi":
118
+ return bsiGrammarImplementation();
119
+ case "csa":
120
+ return csaGrammarImplementation();
121
+ case "asme":
122
+ return asmeGrammarImplementation();
123
+ case "amca":
124
+ return amcaGrammarImplementation();
125
+ case "api":
126
+ return apiGrammarImplementation();
127
+ case "itu":
128
+ return ituGrammarImplementation();
129
+ case "ietf":
130
+ return ietfGrammarImplementation();
131
+ case "iala":
132
+ return ialaGrammarImplementation();
133
+ default:
134
+ return undefined;
135
+ }
136
+ }
@@ -0,0 +1,13 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ import type { FlavorImplementation } from "../../conformance/implementation.js";
3
+ import { BaseIdentifier } from "../../model/identifier.js";
4
+ export declare const isbnGrammar: Grammar;
5
+ export declare class IsbnIdentifier extends BaseIdentifier {
6
+ static polymorphicName: string;
7
+ static attributes: import("../../model/attribute.js").AttributeTable;
8
+ static mappings: import("../../model/attribute.js").FieldMapping[];
9
+ readonly raw: string;
10
+ readonly hyphenated: string | undefined;
11
+ render(): string;
12
+ }
13
+ export declare function isbnGrammarImplementation(): FlavorImplementation;
@@ -0,0 +1,97 @@
1
+ import { match, str } from "../../grammar/engine.js";
2
+ import { ParseFailed, parseGrammar } from "../../grammar/engine.js";
3
+ import { BaseIdentifier, registerType } from "../../model/identifier.js";
4
+ import { extendAttributes, keyValue } from "../../model/attribute.js";
5
+ import { BaseBuilder } from "../../model/builder.js";
6
+ /**
7
+ * 1:1 port of lib/pubid/isbn/ on the unified model. ISBN-10/13 per ISO
8
+ * 2108; the builder validates length and the ISO 2108 check digit and
9
+ * surfaces failures as parse errors (Ruby Builder parity). The Ruby
10
+ * flavor has no urn_generator → the base template emits "urn:isbn".
11
+ */
12
+ function buildRules() {
13
+ const rules = {};
14
+ const rule = (name, build) => {
15
+ rules[name] = build();
16
+ };
17
+ const space = str(" ");
18
+ const colon = str(":");
19
+ const hyphen = str("-");
20
+ const digit = match("[0-9]");
21
+ const xDigit = digit.or(str("X"));
22
+ const digitGroup = digit.repeat(1, Infinity);
23
+ rule("isbn_prefix", () => str("ISBN")
24
+ .then(space.or(space.maybe().then(colon, space.maybe())))
25
+ .maybe());
26
+ rule("isbn_body", () => digitGroup
27
+ .then(hyphen.then(digitGroup).repeat(0, Infinity))
28
+ .then(hyphen.then(xDigit).maybe())
29
+ .as("body")
30
+ .or(digit.repeat(9, 12).then(xDigit.maybe()).as("body")));
31
+ rule("identifier", () => rules["isbn_prefix"].then(rules["isbn_body"]));
32
+ rule("root", () => rules["identifier"]);
33
+ return rules;
34
+ }
35
+ export const isbnGrammar = { rules: buildRules(), root: "root" };
36
+ export class IsbnIdentifier extends BaseIdentifier {
37
+ static polymorphicName = "pubid:isbn:book";
38
+ static attributes = extendAttributes(BaseIdentifier, {
39
+ raw: { type: "string" },
40
+ hyphenated: { type: "string" },
41
+ });
42
+ static mappings = keyValue({ wire: "raw", to: "raw" }, { wire: "hyphenated", to: "hyphenated" });
43
+ render() {
44
+ return `ISBN ${this.hyphenated ?? this.raw}`;
45
+ }
46
+ }
47
+ registerType(IsbnIdentifier);
48
+ const VALID_LENGTH = /^(?:\d{9}[\dX]|\d{13})$/;
49
+ function validCheckDigit(full) {
50
+ // ISBN-10: weights 10..1 mod 11, 10 renders as "X".
51
+ // ISBN-13: alternating weights 1/3 mod 10.
52
+ const digits = full.toUpperCase().replace(/[^0-9X]/g, "");
53
+ if (digits.length === 10) {
54
+ let sum = 0;
55
+ for (let i = 0; i < 9; i++)
56
+ sum += Number(digits[i]) * (10 - i);
57
+ const computed = (11 - (sum % 11)) % 11;
58
+ return (computed === 10 ? "X" : String(computed)) === digits[9];
59
+ }
60
+ if (digits.length === 13) {
61
+ let sum = 0;
62
+ for (let i = 0; i < 12; i++)
63
+ sum += Number(digits[i]) * (i % 2 === 0 ? 1 : 3);
64
+ return String((10 - (sum % 10)) % 10) === digits[12];
65
+ }
66
+ return false;
67
+ }
68
+ class IsbnBuilder extends BaseBuilder {
69
+ defaultIdentifierClass() {
70
+ return IsbnIdentifier;
71
+ }
72
+ cast(key, value) {
73
+ if (key !== "body")
74
+ return value;
75
+ const hyphenatedInput = String(value);
76
+ const raw = hyphenatedInput.replaceAll("-", "");
77
+ if (!VALID_LENGTH.test(raw)) {
78
+ throw new ParseFailed(`ISBN must be 10 or 13 digits (got ${raw.length})`, 0);
79
+ }
80
+ if (!validCheckDigit(raw)) {
81
+ throw new ParseFailed(`ISBN check digit invalid for ${raw}`, 0);
82
+ }
83
+ return hyphenatedInput.includes("-") ? { raw, hyphenated: hyphenatedInput } : { raw };
84
+ }
85
+ }
86
+ export function isbnGrammarImplementation() {
87
+ const builder = new IsbnBuilder();
88
+ return {
89
+ parse(input) {
90
+ const tree = parseGrammar(isbnGrammar, input);
91
+ if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
92
+ throw new ParseFailed("ISBN: unexpected parse tree", 0);
93
+ }
94
+ return builder.build(tree);
95
+ },
96
+ };
97
+ }
@@ -0,0 +1,2 @@
1
+ import { Grammar } from "../../grammar/engine.js";
2
+ export declare const isoGrammar: Grammar;