@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
package/artifact/corpus.json.gz
CHANGED
|
Binary file
|
package/dist/conformance/cli.js
CHANGED
|
@@ -2,6 +2,7 @@ import { loadCorpus } from "../corpus/loader.js";
|
|
|
2
2
|
import { PendingRegistry } from "./pending.js";
|
|
3
3
|
import { runCorpus } from "./runner.js";
|
|
4
4
|
import { corpusModeImplementation } from "../implementations/corpus-mode.js";
|
|
5
|
+
import { grammarImplementation } from "../flavors/index.js";
|
|
5
6
|
/**
|
|
6
7
|
* The conformance entry point. TESTSUITE_DIR points at a pubid-testsuite
|
|
7
8
|
* checkout's tests/ directory (CI checks it out at the pinned ref).
|
|
@@ -19,7 +20,10 @@ export function main(argv) {
|
|
|
19
20
|
// gate then enforces parity with the corpus floor.
|
|
20
21
|
const implementations = new Map([...corpus.flavors].map(([flavor, payloads]) => [
|
|
21
22
|
flavor,
|
|
22
|
-
|
|
23
|
+
// Grammar waves replace corpus mode per flavor: a flavor with a
|
|
24
|
+
// ported grammar parses open-endedly, and the same gate enforces
|
|
25
|
+
// parity with the corpus floor.
|
|
26
|
+
grammarImplementation(flavor) ?? corpusModeImplementation(payloads.cases),
|
|
23
27
|
]));
|
|
24
28
|
const pending = PendingRegistry.load(pendingPath);
|
|
25
29
|
const report = runCorpus(corpus, implementations, pending);
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { match, ref, str } from "../../grammar/engine.js";
|
|
2
|
+
/**
|
|
3
|
+
* Port of lib/pubid/amca/parser.rb — 1:1. Root: identifier.
|
|
4
|
+
*
|
|
5
|
+
* Branch order: interpretation, publication, standard.
|
|
6
|
+
*/
|
|
7
|
+
function buildRules() {
|
|
8
|
+
const rules = {};
|
|
9
|
+
const rule = (name, build) => {
|
|
10
|
+
rules[name] = build();
|
|
11
|
+
};
|
|
12
|
+
rule("space", () => str(" "));
|
|
13
|
+
rule("dash", () => str("-"));
|
|
14
|
+
rule("slash", () => str("/"));
|
|
15
|
+
rule("lparen", () => str("("));
|
|
16
|
+
rule("rparen", () => str(")"));
|
|
17
|
+
rule("dot", () => str("."));
|
|
18
|
+
rule("digit", () => match("[0-9]"));
|
|
19
|
+
rule("digits", () => ref(rules, "digit").repeat(1, Infinity));
|
|
20
|
+
rule("letter", () => match("[A-Za-z]"));
|
|
21
|
+
rule("year_digits", () => str("19").or(str("20")).then(ref(rules, "digit").repeat(2, 2))
|
|
22
|
+
.or(ref(rules, "digit").repeat(2, 2)));
|
|
23
|
+
rule("copublisher", () => str("ANSI").then(ref(rules, "slash")).then(str("AMCA"))
|
|
24
|
+
.or(str("AMCA")));
|
|
25
|
+
rule("additional_copublisher", () => ref(rules, "slash")
|
|
26
|
+
.then(ref(rules, "letter").repeat(2, 10))
|
|
27
|
+
.then(ref(rules, "space"))
|
|
28
|
+
.then(ref(rules, "digits"))
|
|
29
|
+
.then((ref(rules, "dash").then(ref(rules, "digits"))).maybe()));
|
|
30
|
+
rule("code", () => (ref(rules, "digits")
|
|
31
|
+
.then((ref(rules, "dash").then(ref(rules, "letter"))).maybe())
|
|
32
|
+
.then((ref(rules, "dot").then(ref(rules, "digits"))).maybe())).as("code"));
|
|
33
|
+
rule("type", () => str("Standard").or(str("Publication")));
|
|
34
|
+
rule("reaffirmation", () => ref(rules, "lparen").then(str("R")).then(ref(rules, "digits").as("reaffirmed")).then(ref(rules, "rparen")));
|
|
35
|
+
// Consumed but never captured (the Ruby rule has no .as).
|
|
36
|
+
rule("suffix", () => str("R").or(str("P")));
|
|
37
|
+
rule("revision", () => ref(rules, "lparen").then(str("Rev")).then(ref(rules, "dot").maybe())
|
|
38
|
+
.then(ref(rules, "space"))
|
|
39
|
+
.then(ref(rules, "digits").then(ref(rules, "dash")).then(ref(rules, "digits")).as("revision"))
|
|
40
|
+
.then(ref(rules, "rparen")));
|
|
41
|
+
rule("interpretation_code", () => ref(rules, "letter").repeat(2, Infinity).as("interpretation_code")
|
|
42
|
+
.or(ref(rules, "digits").as("interpretation_code")));
|
|
43
|
+
rule("interp_keyword", () => ref(rules, "space").then(str("Interp")));
|
|
44
|
+
const copubSpace = () => ref(rules, "copublisher").as("copublisher").maybe().then(ref(rules, "space"));
|
|
45
|
+
rule("interpretation_identifier", () => (copubSpace()
|
|
46
|
+
.then(ref(rules, "code"))
|
|
47
|
+
.then(ref(rules, "space"))
|
|
48
|
+
.then(ref(rules, "interpretation_code").then(ref(rules, "interp_keyword"))
|
|
49
|
+
.or(str("–").or(ref(rules, "dash"))
|
|
50
|
+
.then(ref(rules, "digits").as("interpretation_year"))
|
|
51
|
+
.then(ref(rules, "interp_keyword").maybe())))).as("interpretation")
|
|
52
|
+
.or(copubSpace()
|
|
53
|
+
.then(ref(rules, "code"))
|
|
54
|
+
.then(ref(rules, "interp_keyword"))
|
|
55
|
+
.as("interpretation")));
|
|
56
|
+
rule("publication_identifier", () => (copubSpace()
|
|
57
|
+
.then(str("Publication").as("publication_keyword"))
|
|
58
|
+
.then(ref(rules, "space"))
|
|
59
|
+
.then(ref(rules, "code"))
|
|
60
|
+
.then((ref(rules, "dash").then(ref(rules, "year_digits").as("year"))).maybe())
|
|
61
|
+
.then((ref(rules, "space").then(ref(rules, "revision"))).maybe())
|
|
62
|
+
.then((ref(rules, "space").then(ref(rules, "reaffirmation"))).maybe())).as("publication"));
|
|
63
|
+
rule("standard_identifier", () => (copubSpace()
|
|
64
|
+
.then(ref(rules, "type").as("type").maybe())
|
|
65
|
+
.then(ref(rules, "space").maybe())
|
|
66
|
+
.then(ref(rules, "code"))
|
|
67
|
+
.then((ref(rules, "dash").then(ref(rules, "year_digits").as("year"))).maybe())
|
|
68
|
+
.then((ref(rules, "space").then(ref(rules, "additional_copublisher"))).maybe())
|
|
69
|
+
.then(ref(rules, "suffix").maybe())
|
|
70
|
+
.then((ref(rules, "space").then(ref(rules, "reaffirmation"))).maybe())).as("standard"));
|
|
71
|
+
rule("identifier", () => ref(rules, "interpretation_identifier")
|
|
72
|
+
.or(ref(rules, "publication_identifier"))
|
|
73
|
+
.or(ref(rules, "standard_identifier")));
|
|
74
|
+
return rules;
|
|
75
|
+
}
|
|
76
|
+
export const amcaGrammar = {
|
|
77
|
+
rules: buildRules(),
|
|
78
|
+
root: "identifier",
|
|
79
|
+
};
|
|
80
|
+
/** Parser.parse normalization. */
|
|
81
|
+
export function preprocessAmca(input) {
|
|
82
|
+
let cleaned = input.trim();
|
|
83
|
+
cleaned = cleaned.replaceAll(/\s+/g, " ");
|
|
84
|
+
cleaned = cleaned.replaceAll("–", "-");
|
|
85
|
+
cleaned = cleaned.replace(/[,.]$/, "");
|
|
86
|
+
return cleaned;
|
|
87
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Tree } from "../../grammar/engine.js";
|
|
2
|
+
import type { FlavorImplementation, Identifier } from "../../conformance/implementation.js";
|
|
3
|
+
export declare function buildAmcaIdentifier(tree: Tree): Identifier;
|
|
4
|
+
export declare function amcaGrammarImplementation(): FlavorImplementation;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { parseGrammar } from "../../grammar/engine.js";
|
|
2
|
+
import { amcaGrammar, preprocessAmca } from "./grammar.js";
|
|
3
|
+
import { InterpretationClass, PublicationClass, StandardClass } from "./model.js";
|
|
4
|
+
/**
|
|
5
|
+
* Port of lib/pubid/amca/builder.rb — dispatch plus the flat
|
|
6
|
+
* attribute extraction.
|
|
7
|
+
*/
|
|
8
|
+
const isObj = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
9
|
+
const strv = (v) => {
|
|
10
|
+
if (v === undefined || v === null)
|
|
11
|
+
return undefined;
|
|
12
|
+
if (Array.isArray(v)) {
|
|
13
|
+
if (v.length === 0)
|
|
14
|
+
return undefined;
|
|
15
|
+
const joined = v.flat(10).map(String).join("");
|
|
16
|
+
return joined.length > 0 ? joined : undefined;
|
|
17
|
+
}
|
|
18
|
+
const s = String(v).trim();
|
|
19
|
+
return s.length > 0 ? s : undefined;
|
|
20
|
+
};
|
|
21
|
+
function flatten(data) {
|
|
22
|
+
return Array.isArray(data) ? Object.assign({}, ...data) : data;
|
|
23
|
+
}
|
|
24
|
+
function extractAttributes(parsed) {
|
|
25
|
+
const attributes = {};
|
|
26
|
+
if (parsed["copublisher"] !== undefined) {
|
|
27
|
+
attributes["copublisher"] = strv(parsed["copublisher"]);
|
|
28
|
+
}
|
|
29
|
+
if (parsed["code"] !== undefined) {
|
|
30
|
+
attributes["number"] = strv(parsed["code"]);
|
|
31
|
+
}
|
|
32
|
+
if (attributes["year"] === undefined && parsed["year"] !== undefined) {
|
|
33
|
+
attributes["year"] = strv(parsed["year"]);
|
|
34
|
+
}
|
|
35
|
+
if (parsed["suffix"] !== undefined) {
|
|
36
|
+
attributes["suffix"] = strv(parsed["suffix"]);
|
|
37
|
+
}
|
|
38
|
+
if (parsed["reaffirmed"] !== undefined) {
|
|
39
|
+
attributes["reaffirmed"] = strv(parsed["reaffirmed"]);
|
|
40
|
+
}
|
|
41
|
+
return attributes;
|
|
42
|
+
}
|
|
43
|
+
export function buildAmcaIdentifier(tree) {
|
|
44
|
+
const root = flatten(tree);
|
|
45
|
+
if (root["publication"] !== undefined || root["publication_keyword"] !== undefined || root["revision"] !== undefined) {
|
|
46
|
+
const parsed = (isObj(root["publication"]) ? root["publication"] : root);
|
|
47
|
+
const attributes = extractAttributes(parsed);
|
|
48
|
+
if (parsed["revision"] !== undefined) {
|
|
49
|
+
attributes["revision"] = strv(parsed["revision"]);
|
|
50
|
+
}
|
|
51
|
+
return new PublicationClass(attributes);
|
|
52
|
+
}
|
|
53
|
+
if (root["interpretation"] !== undefined || root["interpretation_code"] !== undefined || root["interp_keyword"] !== undefined) {
|
|
54
|
+
const parsed = (isObj(root["interpretation"]) ? root["interpretation"] : root);
|
|
55
|
+
const attributes = extractAttributes(parsed);
|
|
56
|
+
if (parsed["interpretation_code"] !== undefined) {
|
|
57
|
+
attributes["interpretation_code"] = strv(parsed["interpretation_code"]);
|
|
58
|
+
}
|
|
59
|
+
if (attributes["year"] === undefined && parsed["interpretation_year"] !== undefined) {
|
|
60
|
+
attributes["year"] = strv(parsed["interpretation_year"]);
|
|
61
|
+
}
|
|
62
|
+
return new InterpretationClass(attributes);
|
|
63
|
+
}
|
|
64
|
+
if (root["standard"] !== undefined) {
|
|
65
|
+
return new StandardClass(extractAttributes(root["standard"]));
|
|
66
|
+
}
|
|
67
|
+
return new StandardClass(extractAttributes(root));
|
|
68
|
+
}
|
|
69
|
+
export function amcaGrammarImplementation() {
|
|
70
|
+
return {
|
|
71
|
+
parse(input) {
|
|
72
|
+
const tree = parseGrammar(amcaGrammar, preprocessAmca(input));
|
|
73
|
+
return buildAmcaIdentifier(tree);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { BaseIdentifier } from "../../model/identifier.js";
|
|
2
|
+
import type { IdentifierStatic } from "../../model/identifier.js";
|
|
3
|
+
import { type AttributeTable, type FieldMapping } from "../../model/attribute.js";
|
|
4
|
+
/**
|
|
5
|
+
* Port of lib/pubid/amca: the base class with the shared flat wire,
|
|
6
|
+
* the three leaf types (Standard, Publication, Interpretation), the
|
|
7
|
+
* renderer and the URN generator.
|
|
8
|
+
*/
|
|
9
|
+
interface TypeMeta {
|
|
10
|
+
key: string;
|
|
11
|
+
title: string;
|
|
12
|
+
short: string | null;
|
|
13
|
+
}
|
|
14
|
+
export declare abstract class AmcaIdentifier extends BaseIdentifier {
|
|
15
|
+
static attributes: AttributeTable;
|
|
16
|
+
static mappings: FieldMapping[];
|
|
17
|
+
readonly publisher: string | undefined;
|
|
18
|
+
readonly copublisher: string | undefined;
|
|
19
|
+
readonly year: string | undefined;
|
|
20
|
+
readonly suffix: string | undefined;
|
|
21
|
+
readonly reaffirmed: string | undefined;
|
|
22
|
+
constructor(attrs?: Record<string, unknown>);
|
|
23
|
+
abstract typeMeta(): TypeMeta;
|
|
24
|
+
render(): string;
|
|
25
|
+
}
|
|
26
|
+
export declare const StandardClass: IdentifierStatic;
|
|
27
|
+
export declare const PublicationClass: IdentifierStatic;
|
|
28
|
+
export declare const InterpretationClass: IdentifierStatic;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,146 @@
|
|
|
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
|
+
const BASE_ATTRS = {
|
|
5
|
+
publisher: { type: "string", default: "AMCA" },
|
|
6
|
+
copublisher: { type: "string" },
|
|
7
|
+
year: { type: "string" },
|
|
8
|
+
suffix: { type: "string" },
|
|
9
|
+
reaffirmed: { type: "string" },
|
|
10
|
+
};
|
|
11
|
+
const BASE_MAPPINGS = keyValue({ wire: "publisher", to: "publisher" }, { wire: "copublisher", to: "copublisher" }, { wire: "year", to: "year" }, { wire: "suffix", to: "suffix" }, { wire: "reaffirmed", to: "reaffirmed" });
|
|
12
|
+
export class AmcaIdentifier extends BaseIdentifier {
|
|
13
|
+
static attributes = extendAttributes(BaseIdentifier, BASE_ATTRS);
|
|
14
|
+
static mappings = BASE_MAPPINGS;
|
|
15
|
+
constructor(attrs = {}) {
|
|
16
|
+
super(attrs);
|
|
17
|
+
const self = this;
|
|
18
|
+
if (self["publisher"] === undefined)
|
|
19
|
+
self["publisher"] = "AMCA";
|
|
20
|
+
}
|
|
21
|
+
render() {
|
|
22
|
+
return renderBase(this);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function renderDocument(id, title) {
|
|
26
|
+
// "AMCA Standard 803-02 (R2008)": the year joins the number with a
|
|
27
|
+
// bare dash; the reaffirmation prints with the R prefix.
|
|
28
|
+
let result = [id.copublisher, title, id.number ?? ""].filter((p) => p !== "").join(" ");
|
|
29
|
+
if (id.year !== undefined)
|
|
30
|
+
result += `-${id.year}`;
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
function renderBase(id) {
|
|
34
|
+
let result = renderDocument(id, id.typeMeta().title);
|
|
35
|
+
if (id.reaffirmed !== undefined)
|
|
36
|
+
result += ` (R${id.reaffirmed})`;
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
class AmcaUrnGenerator extends BaseUrnGenerator {
|
|
40
|
+
generate() {
|
|
41
|
+
const id = this.identifier;
|
|
42
|
+
const parts = ["urn", "amca"];
|
|
43
|
+
if (id.number !== undefined)
|
|
44
|
+
parts.push(id.number);
|
|
45
|
+
if (id.year !== undefined)
|
|
46
|
+
parts.push(id.year);
|
|
47
|
+
if (id.suffix !== undefined)
|
|
48
|
+
parts.push(id.suffix.toLowerCase());
|
|
49
|
+
const code = id.interpretation_code;
|
|
50
|
+
if (code !== undefined)
|
|
51
|
+
parts.push(`interp.${code.toLowerCase()}`);
|
|
52
|
+
const revision = id.revision;
|
|
53
|
+
if (revision !== undefined)
|
|
54
|
+
parts.push(`rev.${revision}`);
|
|
55
|
+
if (id.reaffirmed !== undefined)
|
|
56
|
+
parts.push(`reaff.${id.reaffirmed}`);
|
|
57
|
+
if (id.copublisher !== undefined)
|
|
58
|
+
parts.push(`copub.${id.copublisher.toLowerCase()}`);
|
|
59
|
+
parts[1] = id.publisher !== undefined ? id.publisher.toLowerCase() : "amca";
|
|
60
|
+
parts.push(id.typeMeta().key);
|
|
61
|
+
return parts.join(":");
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
export const StandardClass = (() => {
|
|
65
|
+
class Standard extends AmcaIdentifier {
|
|
66
|
+
static polymorphicName = "pubid:amca:standard";
|
|
67
|
+
static urnGenerator = AmcaUrnGenerator;
|
|
68
|
+
static attributes = extendAttributes(AmcaIdentifier, {
|
|
69
|
+
number: { type: "string" },
|
|
70
|
+
});
|
|
71
|
+
static mappings = [
|
|
72
|
+
...BASE_MAPPINGS,
|
|
73
|
+
{ wire: "number", to: "number" },
|
|
74
|
+
];
|
|
75
|
+
typeMeta() {
|
|
76
|
+
return { key: "standard", title: "Standard", short: null };
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
registerType(Standard);
|
|
80
|
+
return Standard;
|
|
81
|
+
})();
|
|
82
|
+
export const PublicationClass = (() => {
|
|
83
|
+
class Publication extends AmcaIdentifier {
|
|
84
|
+
static polymorphicName = "pubid:amca:publication";
|
|
85
|
+
static urnGenerator = AmcaUrnGenerator;
|
|
86
|
+
static attributes = extendAttributes(AmcaIdentifier, {
|
|
87
|
+
number: { type: "string" },
|
|
88
|
+
revision: { type: "string" },
|
|
89
|
+
});
|
|
90
|
+
static mappings = [
|
|
91
|
+
...BASE_MAPPINGS,
|
|
92
|
+
{ wire: "number", to: "number" },
|
|
93
|
+
{ wire: "revision", to: "revision" },
|
|
94
|
+
];
|
|
95
|
+
typeMeta() {
|
|
96
|
+
return { key: "publication", title: "Publication", short: null };
|
|
97
|
+
}
|
|
98
|
+
render() {
|
|
99
|
+
// The revision and the reaffirmation are separate optional
|
|
100
|
+
// groups in the grammar, so either or both can appear.
|
|
101
|
+
let result = renderDocument(this, "Publication");
|
|
102
|
+
if (this.revision !== undefined)
|
|
103
|
+
result += ` (Rev. ${this.revision})`;
|
|
104
|
+
if (this.reaffirmed !== undefined)
|
|
105
|
+
result += ` (R${this.reaffirmed})`;
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
registerType(Publication);
|
|
110
|
+
return Publication;
|
|
111
|
+
})();
|
|
112
|
+
export const InterpretationClass = (() => {
|
|
113
|
+
class Interpretation extends AmcaIdentifier {
|
|
114
|
+
static polymorphicName = "pubid:amca:interpretation";
|
|
115
|
+
static urnGenerator = AmcaUrnGenerator;
|
|
116
|
+
static attributes = extendAttributes(AmcaIdentifier, {
|
|
117
|
+
number: { type: "string" },
|
|
118
|
+
interpretation_code: { type: "string" },
|
|
119
|
+
});
|
|
120
|
+
static mappings = [
|
|
121
|
+
...BASE_MAPPINGS,
|
|
122
|
+
{ wire: "number", to: "number" },
|
|
123
|
+
{ wire: "interpretation_code", to: "interpretation_code" },
|
|
124
|
+
];
|
|
125
|
+
typeMeta() {
|
|
126
|
+
return { key: "interpretation", title: "Interpretation", short: "Interp" };
|
|
127
|
+
}
|
|
128
|
+
render() {
|
|
129
|
+
let result = [this.copublisher, this.number ?? ""].filter((p) => p !== "").join(" ");
|
|
130
|
+
if (this.interpretation_code !== undefined) {
|
|
131
|
+
result += ` ${this.interpretation_code} Interp`;
|
|
132
|
+
}
|
|
133
|
+
else if (this.year !== undefined) {
|
|
134
|
+
result += ` – ${this.year}`;
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
result += " Interp";
|
|
138
|
+
}
|
|
139
|
+
if (this.suffix !== undefined)
|
|
140
|
+
result += ` ${this.suffix}`;
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
registerType(Interpretation);
|
|
145
|
+
return Interpretation;
|
|
146
|
+
})();
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Grammar } from "../../grammar/engine.js";
|
|
2
|
+
import type { FlavorImplementation } from "../../conformance/implementation.js";
|
|
3
|
+
import { BaseIdentifier } from "../../model/identifier.js";
|
|
4
|
+
import { BaseUrnGenerator } from "../../model/urn-generator.js";
|
|
5
|
+
import { Publisher, Language } from "../../model/component.js";
|
|
6
|
+
export declare const ansiGrammar: Grammar;
|
|
7
|
+
declare class AnsiUrnGenerator extends BaseUrnGenerator<AnsiIdentifier> {
|
|
8
|
+
generate(): string;
|
|
9
|
+
}
|
|
10
|
+
export declare class AnsiIdentifier extends BaseIdentifier {
|
|
11
|
+
static polymorphicName: string;
|
|
12
|
+
static attributes: import("../../model/attribute.js").AttributeTable;
|
|
13
|
+
static mappings: import("../../model/attribute.js").FieldMapping[];
|
|
14
|
+
static urnGenerator: typeof AnsiUrnGenerator;
|
|
15
|
+
readonly number: string;
|
|
16
|
+
readonly part: string | undefined;
|
|
17
|
+
readonly year: string | undefined;
|
|
18
|
+
readonly publisher: Publisher;
|
|
19
|
+
readonly copublishers: Publisher[];
|
|
20
|
+
readonly languages: Language[];
|
|
21
|
+
render(): string;
|
|
22
|
+
}
|
|
23
|
+
export declare function ansiGrammarImplementation(): FlavorImplementation;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { match, str } from "../../grammar/engine.js";
|
|
2
|
+
import { ParseFailed, parseGrammar } from "../../grammar/engine.js";
|
|
3
|
+
import { BaseIdentifier, registerType } from "../../model/identifier.js";
|
|
4
|
+
import { extendAttributes, keyValue } from "../../model/attribute.js";
|
|
5
|
+
import { BaseUrnGenerator } from "../../model/urn-generator.js";
|
|
6
|
+
import { BaseBuilder } from "../../model/builder.js";
|
|
7
|
+
import { Publisher, Language } from "../../model/component.js";
|
|
8
|
+
/**
|
|
9
|
+
* 1:1 port of lib/pubid/ansi/ on the unified model. Copublishers
|
|
10
|
+
* (controlled vocabulary) rewrite the URN namespace; the dash segment
|
|
11
|
+
* serializes as `part` (Ruby Builder split-on-dash), the ":YYYY" form as
|
|
12
|
+
* `year`; "Std" is consumed and dropped; languages round-trip.
|
|
13
|
+
*/
|
|
14
|
+
const ORGANIZATIONS = ["ISO", "IEC", "IEEE", "SAE", "ASME", "ASTM"];
|
|
15
|
+
function buildRules() {
|
|
16
|
+
const rules = {};
|
|
17
|
+
const rule = (name, build) => {
|
|
18
|
+
rules[name] = build();
|
|
19
|
+
};
|
|
20
|
+
const space = str(" ");
|
|
21
|
+
const spaceQ = space.maybe();
|
|
22
|
+
const digits = match("[0-9]").repeat(1, Infinity);
|
|
23
|
+
const dashDigits = str("-").then(digits).maybe();
|
|
24
|
+
rule("copublishers", () => str("/")
|
|
25
|
+
.then(spaceQ, ORGANIZATIONS.reduce((acc, org) => acc.or(str(org)), str(ORGANIZATIONS[0])).as("copublisher"))
|
|
26
|
+
.repeat(1, Infinity)
|
|
27
|
+
.as("copublishers"));
|
|
28
|
+
rule("std_keyword", () => str("Std").then(space).maybe());
|
|
29
|
+
rule("number_with_part", () => match("[A-Z]")
|
|
30
|
+
.repeat(1, Infinity)
|
|
31
|
+
.then(digits, str(".").then(digits).repeat(0, 3), match("[A-Z]").maybe(), dashDigits)
|
|
32
|
+
.or(digits.then(str(".").then(digits, match("[a-z]").maybe()).repeat(0, 2), dashDigits))
|
|
33
|
+
.as("number_with_part"));
|
|
34
|
+
rule("year_digits", () => str("19").or(str("20")).then(match("\\d").repeat(2, 2), digits.absent()));
|
|
35
|
+
rule("date", () => str(":").then(rules["year_digits"].as("date")));
|
|
36
|
+
rule("language", () => str("(")
|
|
37
|
+
.then(match("[a-z]")
|
|
38
|
+
.repeat(2, Infinity)
|
|
39
|
+
.then(str(",").maybe())
|
|
40
|
+
.repeat(0, Infinity)
|
|
41
|
+
.as("languages"), str(")")));
|
|
42
|
+
rule("identifier_with_copublishers", () => str("ANSI")
|
|
43
|
+
.as("publisher")
|
|
44
|
+
.then(rules["copublishers"], space, rules["std_keyword"])
|
|
45
|
+
.then(rules["number_with_part"])
|
|
46
|
+
.then(rules["date"].maybe())
|
|
47
|
+
.then(rules["language"].maybe()));
|
|
48
|
+
rule("identifier_sole", () => str("ANSI")
|
|
49
|
+
.as("publisher")
|
|
50
|
+
.then(space, rules["std_keyword"], rules["number_with_part"])
|
|
51
|
+
.then(rules["date"].maybe())
|
|
52
|
+
.then(rules["language"].maybe()));
|
|
53
|
+
rule("identifier", () => rules["identifier_with_copublishers"].or(rules["identifier_sole"]));
|
|
54
|
+
rule("root", () => rules["identifier"]);
|
|
55
|
+
return rules;
|
|
56
|
+
}
|
|
57
|
+
export const ansiGrammar = { rules: buildRules(), root: "root" };
|
|
58
|
+
class AnsiUrnGenerator extends BaseUrnGenerator {
|
|
59
|
+
generate() {
|
|
60
|
+
const id = this.identifier;
|
|
61
|
+
const parts = ["urn", "ansi", id.number];
|
|
62
|
+
if (id.part !== undefined)
|
|
63
|
+
parts.push(`-${id.part}`);
|
|
64
|
+
if (id.year !== undefined)
|
|
65
|
+
parts.push(id.year);
|
|
66
|
+
if (id.copublishers.length > 0) {
|
|
67
|
+
parts[1] = ["ansi", ...id.copublishers.map((c) => c.body.toLowerCase())].join("-");
|
|
68
|
+
}
|
|
69
|
+
if (id.languages.length > 0) {
|
|
70
|
+
parts.push(id.languages.map((l) => l.code).join(","));
|
|
71
|
+
}
|
|
72
|
+
return parts.join(":");
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export class AnsiIdentifier extends BaseIdentifier {
|
|
76
|
+
static polymorphicName = "pubid:ansi:standard";
|
|
77
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
78
|
+
number: { type: "string" },
|
|
79
|
+
part: { type: "string" },
|
|
80
|
+
year: { type: "string" },
|
|
81
|
+
copublishers: { type: Publisher, collection: true, initializeEmpty: true },
|
|
82
|
+
languages: { type: Language, collection: true, initializeEmpty: true },
|
|
83
|
+
});
|
|
84
|
+
static mappings = keyValue({ wire: "number", to: "number" }, { wire: "part", to: "part" }, { wire: "year", to: "year" }, { wire: "publisher", to: "publisher" }, { wire: "copublishers", to: "copublishers" }, { wire: "languages", to: "languages" });
|
|
85
|
+
static urnGenerator = AnsiUrnGenerator;
|
|
86
|
+
render() {
|
|
87
|
+
const publisherPortion = this.copublishers.length > 0
|
|
88
|
+
? [this.publisher.body, ...this.copublishers.map((p) => p.body)].join("/")
|
|
89
|
+
: this.publisher.body;
|
|
90
|
+
let numberPortion = this.number;
|
|
91
|
+
if (this.part !== undefined)
|
|
92
|
+
numberPortion += `-${this.part}`;
|
|
93
|
+
if (this.year !== undefined)
|
|
94
|
+
numberPortion += `:${this.year}`;
|
|
95
|
+
let result = `${publisherPortion} ${numberPortion}`;
|
|
96
|
+
if (this.languages.length > 0)
|
|
97
|
+
result += `(${this.languages.map((l) => l.code).join(",")})`;
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
registerType(AnsiIdentifier);
|
|
102
|
+
function extractCopublishers(raw) {
|
|
103
|
+
const list = Array.isArray(raw) ? raw : [raw];
|
|
104
|
+
return list.map((p) => {
|
|
105
|
+
const body = typeof p === "object" && p !== null && "copublisher" in p
|
|
106
|
+
? String(p["copublisher"])
|
|
107
|
+
: String(p);
|
|
108
|
+
return new Publisher({ body });
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
class AnsiBuilder extends BaseBuilder {
|
|
112
|
+
defaultIdentifierClass() {
|
|
113
|
+
return AnsiIdentifier;
|
|
114
|
+
}
|
|
115
|
+
cast(key, value) {
|
|
116
|
+
if (key === "number_with_part") {
|
|
117
|
+
// Ruby Builder: split on "-", first segment = number, second = part.
|
|
118
|
+
const segments = String(value).split("-");
|
|
119
|
+
return segments[1] === undefined ? { number: segments[0] } : { number: segments[0], part: segments[1] };
|
|
120
|
+
}
|
|
121
|
+
if (key === "publisher") {
|
|
122
|
+
return { publisher: new Publisher({ body: String(value) }) };
|
|
123
|
+
}
|
|
124
|
+
if (key === "copublishers") {
|
|
125
|
+
return { copublishers: extractCopublishers(value) };
|
|
126
|
+
}
|
|
127
|
+
if (key === "date") {
|
|
128
|
+
return { year: String(value) };
|
|
129
|
+
}
|
|
130
|
+
if (key === "languages") {
|
|
131
|
+
return { languages: this.parseLanguages(value) };
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function ansiGrammarImplementation() {
|
|
137
|
+
const builder = new AnsiBuilder();
|
|
138
|
+
return {
|
|
139
|
+
parse(input) {
|
|
140
|
+
const tree = parseGrammar(ansiGrammar, input);
|
|
141
|
+
if (typeof tree !== "object" || tree === null || Array.isArray(tree)) {
|
|
142
|
+
throw new ParseFailed("ANSI: unexpected parse tree", 0);
|
|
143
|
+
}
|
|
144
|
+
return builder.build(tree);
|
|
145
|
+
},
|
|
146
|
+
};
|
|
147
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { match, ref, str } from "../../grammar/engine.js";
|
|
2
|
+
/**
|
|
3
|
+
* Port of lib/pubid/api/parser.rb — 1:1. Root: identifier.
|
|
4
|
+
*
|
|
5
|
+
* Branch order: combined, MPMS, typed, typeless.
|
|
6
|
+
*/
|
|
7
|
+
function buildRules() {
|
|
8
|
+
const rules = {};
|
|
9
|
+
const rule = (name, build) => {
|
|
10
|
+
rules[name] = build();
|
|
11
|
+
};
|
|
12
|
+
rule("space", () => str(" "));
|
|
13
|
+
rule("dash", () => str("-"));
|
|
14
|
+
rule("slash", () => str("/"));
|
|
15
|
+
rule("colon", () => str(":"));
|
|
16
|
+
rule("dot", () => str("."));
|
|
17
|
+
rule("digit", () => match("[0-9]"));
|
|
18
|
+
rule("digits", () => ref(rules, "digit").repeat(1, Infinity));
|
|
19
|
+
rule("letter", () => match("[A-Z]"));
|
|
20
|
+
rule("letters", () => ref(rules, "letter").repeat(1, Infinity));
|
|
21
|
+
rule("publisher", () => str("API").then(ref(rules, "space")));
|
|
22
|
+
rule("doc_type", () => str("MPMS").or(str("BULL")).or(str("SPEC")).or(str("STD"))
|
|
23
|
+
.or(str("RP")).or(str("TR")).or(str("COS")).or(str("PUBL"))
|
|
24
|
+
.as("type"));
|
|
25
|
+
rule("chapter_notation", () => ref(rules, "space").then(str("CH")).then(ref(rules, "space"))
|
|
26
|
+
.then(ref(rules, "digits").as("chapter")));
|
|
27
|
+
rule("number_with_part", () => match("[0-9A-Z]").repeat(1, Infinity).as("number")
|
|
28
|
+
.then((ref(rules, "dash").then((match("[0-9A-Z]").repeat(1, Infinity)).as("part"))).maybe()));
|
|
29
|
+
rule("digits_with_letter", () => ref(rules, "digits").then(ref(rules, "letter").maybe()));
|
|
30
|
+
rule("year", () => ref(rules, "digit").repeat(4, 4).as("year"));
|
|
31
|
+
rule("date_dash", () => ref(rules, "dash").then(ref(rules, "year")));
|
|
32
|
+
rule("date_colon", () => ref(rules, "colon").then(ref(rules, "year")));
|
|
33
|
+
rule("reaffirmation", () => ref(rules, "space").then(str("(R")).then(ref(rules, "year")).then(str(")")));
|
|
34
|
+
rule("part_notation", () => str(", Part ").then(ref(rules, "digits").as("part_number")));
|
|
35
|
+
rule("edition_notation", () => str(", ")
|
|
36
|
+
.then(ref(rules, "digits").as("edition_number"))
|
|
37
|
+
.then(str("st").or(str("nd")).or(str("rd")).or(str("th")))
|
|
38
|
+
.then(str(" edition")));
|
|
39
|
+
rule("mpms_identifier", () => ref(rules, "publisher")
|
|
40
|
+
.then(str("MPMS").as("type"))
|
|
41
|
+
.then(ref(rules, "chapter_notation"))
|
|
42
|
+
.then((ref(rules, "dot").then(ref(rules, "digits_with_letter").as("section"))).maybe())
|
|
43
|
+
.then((ref(rules, "dot").then(ref(rules, "digits_with_letter").as("subsection"))).maybe())
|
|
44
|
+
.then(ref(rules, "date_dash").or(ref(rules, "date_colon")).maybe()));
|
|
45
|
+
const docTail = () => ref(rules, "number_with_part")
|
|
46
|
+
.then(ref(rules, "part_notation").maybe())
|
|
47
|
+
.then(ref(rules, "date_dash").or(ref(rules, "date_colon")).maybe());
|
|
48
|
+
rule("typed_identifier", () => ref(rules, "publisher")
|
|
49
|
+
.then(ref(rules, "doc_type"))
|
|
50
|
+
.then(ref(rules, "space"))
|
|
51
|
+
.then(docTail())
|
|
52
|
+
.then(ref(rules, "reaffirmation").maybe()));
|
|
53
|
+
rule("typeless_identifier", () => ref(rules, "publisher")
|
|
54
|
+
.then(docTail())
|
|
55
|
+
.then(ref(rules, "reaffirmation").maybe()));
|
|
56
|
+
rule("second_identifier", () => ref(rules, "doc_type")
|
|
57
|
+
.then(ref(rules, "space"))
|
|
58
|
+
.then(docTail()));
|
|
59
|
+
rule("combined_identifier", () => ref(rules, "mpms_identifier")
|
|
60
|
+
.or(ref(rules, "typed_identifier"))
|
|
61
|
+
.or(ref(rules, "typeless_identifier"))
|
|
62
|
+
.as("first")
|
|
63
|
+
.then(ref(rules, "slash"))
|
|
64
|
+
.then(ref(rules, "second_identifier").as("second"))
|
|
65
|
+
.then(ref(rules, "edition_notation").maybe()));
|
|
66
|
+
rule("identifier", () => ref(rules, "combined_identifier")
|
|
67
|
+
.or(ref(rules, "mpms_identifier"))
|
|
68
|
+
.or(ref(rules, "typed_identifier"))
|
|
69
|
+
.or(ref(rules, "typeless_identifier")));
|
|
70
|
+
return rules;
|
|
71
|
+
}
|
|
72
|
+
export const apiGrammar = {
|
|
73
|
+
rules: buildRules(),
|
|
74
|
+
root: "identifier",
|
|
75
|
+
};
|
|
76
|
+
/** Parser#parse normalization: the MPMP typo. */
|
|
77
|
+
export function preprocessApi(input) {
|
|
78
|
+
return input.replaceAll("API MPMP", "API MPMS");
|
|
79
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Tree } from "../../grammar/engine.js";
|
|
2
|
+
import type { FlavorImplementation, Identifier } from "../../conformance/implementation.js";
|
|
3
|
+
export declare function buildApiIdentifier(tree: Tree): Identifier;
|
|
4
|
+
export declare function apiGrammarImplementation(): FlavorImplementation;
|