@pubid/pubid 0.1.38 → 0.1.40
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/implementation.d.ts +3 -0
- package/dist/flavors/doi_pfs/index.d.ts +35 -0
- package/dist/flavors/doi_pfs/index.js +61 -0
- package/dist/flavors/index.js +3 -0
- package/dist/flavors/jis/index.js +64 -20
- package/dist/flavors/nist/index.js +36 -6
- package/dist/flavors/nist/model.js +16 -1
- package/dist/model/attribute.d.ts +3 -0
- package/dist/model/identifier.d.ts +7 -0
- package/dist/model/identifier.js +17 -0
- package/dist/pubid-urn/schemas/doi_pfs.d.ts +8 -0
- package/dist/pubid-urn/schemas/doi_pfs.js +14 -0
- package/dist/pubid-urn/schemas/index.d.ts +1 -1
- package/dist/pubid-urn/schemas/index.js +3 -1
- package/dist/pubid-urn/schemas/jis.js +10 -3
- package/package.json +1 -1
- package/vendor/parg/calconnect_pfs.json +1 -0
- package/vendor/parg/cen_pfs.json +1 -0
- package/vendor/parg/doi_pfs.json +1 -0
- package/vendor/parg/etsi_pfs.json +1 -0
- package/vendor/parg/iho.json +1 -1
- package/vendor/parg/jis.json +1 -1
- package/vendor/parg/nist.json +1 -1
package/artifact/corpus.json.gz
CHANGED
|
Binary file
|
|
@@ -24,5 +24,8 @@ export interface Identifier {
|
|
|
24
24
|
toUrn(): string | undefined;
|
|
25
25
|
/** Deserialize the canonical hash; the idempotency gate relies on it. */
|
|
26
26
|
fromHash(hash: Record<string, unknown>): Identifier;
|
|
27
|
+
/** Ruby ==: canonical equality skipping equalityIgnored attributes
|
|
28
|
+
* (the (E) position is spelling, the language itself is not). */
|
|
29
|
+
equals?(other: Identifier): boolean;
|
|
27
30
|
}
|
|
28
31
|
export type ImplementationRegistry = Map<string, FlavorImplementation>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { FlavorImplementation } from "../../conformance/implementation.js";
|
|
2
|
+
import { BaseIdentifier } from "../../model/identifier.js";
|
|
3
|
+
/**
|
|
4
|
+
* The PFS-compiled doi flavor (pubid/pubid#706 §2.2) — one definition
|
|
5
|
+
* file, both engines: the grammar runtime is the SAME baked artifact the
|
|
6
|
+
* Ruby flavor runs (pubid-grammar artifacts/doi_pfs.json, compiled from
|
|
7
|
+
* definitions/doi.pfs), loaded through the artifact runtime, so grammar
|
|
8
|
+
* changes land once and this side cannot drift. Nothing is hand-rolled:
|
|
9
|
+
* the model is declared attributes (serialization derives from
|
|
10
|
+
* BaseIdentifier), the builder is the shared one, and the render body is
|
|
11
|
+
* the definition's canonical template. The parity gate
|
|
12
|
+
* (test/doi-pfs-parity.test.ts) pins byte-identity with the coded
|
|
13
|
+
* {@linkcode import("../doi").DoiIdentifier} over the shared conformance
|
|
14
|
+
* set.
|
|
15
|
+
*/
|
|
16
|
+
export declare class DoiPfsIdentifier extends BaseIdentifier {
|
|
17
|
+
/**
|
|
18
|
+
* The SCHEME-canonical wire tag (declared in the definition): to_hash
|
|
19
|
+
* is byte-identical with the coded flavor. Deliberately NOT registered
|
|
20
|
+
* in the global type map — one scheme, one `_type`, one global
|
|
21
|
+
* resolution (the coded class); {@linkcode fromHash} routes the tag
|
|
22
|
+
* back here flavor-locally, mirroring Ruby's DOI_TYPE_MAP.
|
|
23
|
+
*/
|
|
24
|
+
static polymorphicName: string;
|
|
25
|
+
static attributes: import("../../model/attribute.js").AttributeTable;
|
|
26
|
+
static mappings: import("../../model/attribute.js").FieldMapping[];
|
|
27
|
+
render(): string;
|
|
28
|
+
readonly prefix: string;
|
|
29
|
+
readonly suffix: string;
|
|
30
|
+
/** The alias's own from_hash: the scheme tag routes HERE, while the
|
|
31
|
+
* global resolution keeps answering the coded class (coexistence, not
|
|
32
|
+
* cutover). */
|
|
33
|
+
static fromHash(hash: Record<string, unknown>): BaseIdentifier;
|
|
34
|
+
}
|
|
35
|
+
export declare function doiPfsGrammarImplementation(): FlavorImplementation;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ParseFailed } from "../../grammar/engine.js";
|
|
2
|
+
import { PubidRuntime } from "../../parg/runtime.js";
|
|
3
|
+
import { BaseIdentifier } from "../../model/identifier.js";
|
|
4
|
+
import { extendAttributes, keyValue } from "../../model/attribute.js";
|
|
5
|
+
/**
|
|
6
|
+
* The PFS-compiled doi flavor (pubid/pubid#706 §2.2) — one definition
|
|
7
|
+
* file, both engines: the grammar runtime is the SAME baked artifact the
|
|
8
|
+
* Ruby flavor runs (pubid-grammar artifacts/doi_pfs.json, compiled from
|
|
9
|
+
* definitions/doi.pfs), loaded through the artifact runtime, so grammar
|
|
10
|
+
* changes land once and this side cannot drift. Nothing is hand-rolled:
|
|
11
|
+
* the model is declared attributes (serialization derives from
|
|
12
|
+
* BaseIdentifier), the builder is the shared one, and the render body is
|
|
13
|
+
* the definition's canonical template. The parity gate
|
|
14
|
+
* (test/doi-pfs-parity.test.ts) pins byte-identity with the coded
|
|
15
|
+
* {@linkcode import("../doi").DoiIdentifier} over the shared conformance
|
|
16
|
+
* set.
|
|
17
|
+
*/
|
|
18
|
+
export class DoiPfsIdentifier extends BaseIdentifier {
|
|
19
|
+
/**
|
|
20
|
+
* The SCHEME-canonical wire tag (declared in the definition): to_hash
|
|
21
|
+
* is byte-identical with the coded flavor. Deliberately NOT registered
|
|
22
|
+
* in the global type map — one scheme, one `_type`, one global
|
|
23
|
+
* resolution (the coded class); {@linkcode fromHash} routes the tag
|
|
24
|
+
* back here flavor-locally, mirroring Ruby's DOI_TYPE_MAP.
|
|
25
|
+
*/
|
|
26
|
+
static polymorphicName = "pubid:doi:resource";
|
|
27
|
+
static attributes = extendAttributes(BaseIdentifier, {
|
|
28
|
+
prefix: { type: "string" },
|
|
29
|
+
suffix: { type: "string" },
|
|
30
|
+
});
|
|
31
|
+
static mappings = keyValue({ wire: "prefix", to: "prefix" }, { wire: "suffix", to: "suffix" });
|
|
32
|
+
render() {
|
|
33
|
+
return `doi:${this.prefix}/${this.suffix}`;
|
|
34
|
+
}
|
|
35
|
+
/** The alias's own from_hash: the scheme tag routes HERE, while the
|
|
36
|
+
* global resolution keeps answering the coded class (coexistence, not
|
|
37
|
+
* cutover). */
|
|
38
|
+
static fromHash(hash) {
|
|
39
|
+
return new DoiPfsIdentifier(this.applyMappings(this.inflateScalarComponents(hash)));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The artifact's declared bindings (prefix -> prefix, suffix -> suffix)
|
|
44
|
+
* carry the whole printed prefix face ("10.1000") — the doi.pfs pattern
|
|
45
|
+
* captures the "10." face the coded grammar re-assembles — so the bound
|
|
46
|
+
* map lands on the model fields directly, no builder cast.
|
|
47
|
+
*/
|
|
48
|
+
let cachedRuntime;
|
|
49
|
+
export function doiPfsGrammarImplementation() {
|
|
50
|
+
return {
|
|
51
|
+
parse(input) {
|
|
52
|
+
cachedRuntime ??= PubidRuntime.load("doi_pfs");
|
|
53
|
+
const bound = cachedRuntime.parseAndBind(input);
|
|
54
|
+
if (bound === null || typeof bound !== "object") {
|
|
55
|
+
throw new ParseFailed("doi_pfs: the artifact rejected the input", 0);
|
|
56
|
+
}
|
|
57
|
+
const identifier = new DoiPfsIdentifier(bound);
|
|
58
|
+
return identifier;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
package/dist/flavors/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { lookupUrnParser, parseUrnFor } from "../urn/parsers.js";
|
|
|
2
2
|
import { oimlGrammarImplementation } from "./oiml/implementation.js";
|
|
3
3
|
import { xsfGrammarImplementation } from "./xsf/index.js";
|
|
4
4
|
import { doiGrammarImplementation } from "./doi/index.js";
|
|
5
|
+
import { doiPfsGrammarImplementation } from "./doi_pfs/index.js";
|
|
5
6
|
import { ianaGrammarImplementation } from "./iana/index.js";
|
|
6
7
|
import { unGrammarImplementation } from "./un/index.js";
|
|
7
8
|
import { plateauGrammarImplementation } from "./plateau/index.js";
|
|
@@ -81,6 +82,8 @@ function grammarImplementationSwitch(flavor) {
|
|
|
81
82
|
return xsfGrammarImplementation();
|
|
82
83
|
case "doi":
|
|
83
84
|
return doiGrammarImplementation();
|
|
85
|
+
case "doi_pfs":
|
|
86
|
+
return doiPfsGrammarImplementation();
|
|
84
87
|
case "iana":
|
|
85
88
|
return ianaGrammarImplementation();
|
|
86
89
|
case "un":
|
|
@@ -14,7 +14,12 @@ import { BaseUrnGenerator } from "../../model/urn-generator.js";
|
|
|
14
14
|
*
|
|
15
15
|
* WES (welding-engineering-standard, pubid#638) rides the same flavor:
|
|
16
16
|
* "WES <number>[-parts][:year[R]]…" with no series letter and no JIS
|
|
17
|
-
* prefix — the code itself carries the "WES" root.
|
|
17
|
+
* prefix — the code itself carries the "WES" root. A WES id may also
|
|
18
|
+
* carry a TR/TS type after the root ("WES TR 2032:2024", its own
|
|
19
|
+
* welding-engineering-technical-report/-specification classes,
|
|
20
|
+
* pubid#716) and a language before the year ("WES 1112(E):2022",
|
|
21
|
+
* bound only when a colon follows; recorded as language_before_year,
|
|
22
|
+
* which equality ignores — the two (E) positions are one document).
|
|
18
23
|
*/
|
|
19
24
|
function buildRules() {
|
|
20
25
|
const rules = {};
|
|
@@ -61,11 +66,18 @@ function buildRules() {
|
|
|
61
66
|
.then(rules["symbol_clause"].maybe()));
|
|
62
67
|
// WES (Japan Welding Engineering Society) rides the JIS flavor with the
|
|
63
68
|
// same tail but no prefix and no series letter; the root tries it first,
|
|
64
|
-
// as the reference grammar does.
|
|
69
|
+
// as the reference grammar does. A WES id may also carry a TR/TS type
|
|
70
|
+
// after the root ("WES TR 2032:2024") and a language before the year
|
|
71
|
+
// ("WES 1112(E):2022" — bound only when a colon follows, so
|
|
72
|
+
// "WES 1112(E)" with no year still reads as no language).
|
|
73
|
+
rule("wes_type", () => (str("TR").or(str("TS"))).as("wes_type").then(space));
|
|
74
|
+
rule("wes_language", () => jpLparen.or(str("(")).then(match("[EJ]").as("wes_language"), jpRparen.or(str(")"))).then(colon.present()));
|
|
65
75
|
rule("wes_identifier", () => str("WES").as("wes")
|
|
66
76
|
.then(space)
|
|
77
|
+
.then(rules["wes_type"].maybe())
|
|
67
78
|
.then(rules["number"])
|
|
68
79
|
.then(rules["parts"])
|
|
80
|
+
.then(rules["wes_language"].maybe())
|
|
69
81
|
.then(rules["year"].maybe())
|
|
70
82
|
.then(rules["language"].maybe())
|
|
71
83
|
.then(rules["all_parts"].maybe())
|
|
@@ -95,6 +107,13 @@ class JisIdentifier extends BaseIdentifier {
|
|
|
95
107
|
yearWithReaffirmation() {
|
|
96
108
|
return `${this.year}${this.reaffirmed === true ? "R" : ""}`;
|
|
97
109
|
}
|
|
110
|
+
/** The ":year[R]" and "(lang)" tail, in the order the source used
|
|
111
|
+
* (ruby year_and_language). */
|
|
112
|
+
yearAndLanguage() {
|
|
113
|
+
const yearPart = this.year !== undefined ? `:${this.yearWithReaffirmation()}` : "";
|
|
114
|
+
const langPart = this.language !== undefined ? `(${this.language})` : "";
|
|
115
|
+
return this.language_before_year === true ? langPart + yearPart : yearPart + langPart;
|
|
116
|
+
}
|
|
98
117
|
symbolSuffix() {
|
|
99
118
|
if (this.symbol === undefined)
|
|
100
119
|
return "";
|
|
@@ -104,7 +123,7 @@ class JisIdentifier extends BaseIdentifier {
|
|
|
104
123
|
return "";
|
|
105
124
|
}
|
|
106
125
|
}
|
|
107
|
-
const JIS_MAPPINGS = keyValue({ wire: "series", to: "series" }, { wire: "number", to: "number" }, { wire: "parts", to: "parts" }, { wire: "year", to: "year" }, { wire: "language", to: "language" }, { wire: "all_parts", to: "all_parts" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "symbol", to: "symbol" });
|
|
126
|
+
const JIS_MAPPINGS = keyValue({ wire: "series", to: "series" }, { wire: "number", to: "number" }, { wire: "parts", to: "parts" }, { wire: "year", to: "year" }, { wire: "language", to: "language" }, { wire: "language_before_year", to: "language_before_year" }, { wire: "all_parts", to: "all_parts" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "symbol", to: "symbol" });
|
|
108
127
|
function jisClass(kind) {
|
|
109
128
|
const isSupplement = kind === "amendment" || kind === "corrigendum" || kind === "explanation";
|
|
110
129
|
class JisKindIdentifier extends JisIdentifier {
|
|
@@ -122,6 +141,7 @@ function jisClass(kind) {
|
|
|
122
141
|
parts: { type: "string", collection: true },
|
|
123
142
|
year: { type: "integer" },
|
|
124
143
|
language: { type: "string" },
|
|
144
|
+
language_before_year: { type: "boolean", equalityIgnored: true },
|
|
125
145
|
all_parts: { type: "boolean", default: false },
|
|
126
146
|
reaffirmed: { type: "boolean" },
|
|
127
147
|
symbol: { type: "string" },
|
|
@@ -137,10 +157,7 @@ function jisClass(kind) {
|
|
|
137
157
|
const typePrefix = KIND_PREFIXES[kind];
|
|
138
158
|
let result = typePrefix === undefined ? "JIS" : `JIS ${typePrefix}`;
|
|
139
159
|
result += ` ${this.code()}`;
|
|
140
|
-
|
|
141
|
-
result += `:${this.yearWithReaffirmation()}`;
|
|
142
|
-
if (this.language !== undefined)
|
|
143
|
-
result += `(${this.language})`;
|
|
160
|
+
result += this.yearAndLanguage();
|
|
144
161
|
if (this.all_parts === true)
|
|
145
162
|
result += "(規格群)";
|
|
146
163
|
return result + this.symbolSuffix();
|
|
@@ -167,36 +184,43 @@ const KIND_CLASSES = {
|
|
|
167
184
|
corrigendum: jisClass("corrigendum"),
|
|
168
185
|
explanation: jisClass("explanation"),
|
|
169
186
|
};
|
|
187
|
+
const WES_TYPE_PREFIXES = {
|
|
188
|
+
"welding-engineering-standard": undefined,
|
|
189
|
+
"welding-engineering-technical-report": "TR",
|
|
190
|
+
"welding-engineering-technical-specification": "TS",
|
|
191
|
+
};
|
|
170
192
|
// WES 7700-1:2019 — JSA sells Welding Engineering Standards next to JIS,
|
|
171
193
|
// so they parse through the JIS flavor, but the id carries no series
|
|
172
|
-
// letter and no JIS prefix ("WES" is the root of the designation).
|
|
173
|
-
|
|
194
|
+
// letter and no JIS prefix ("WES" is the root of the designation). The
|
|
195
|
+
// TR/TS type token after the root picks the WES TR / WES TS classes
|
|
196
|
+
// (pubid#716): "WES TR 2032" is not "WES 2032" and not "TR Z 2032".
|
|
197
|
+
function wesClass(kind) {
|
|
174
198
|
class JisWesIdentifier extends JisIdentifier {
|
|
175
|
-
static polymorphicName =
|
|
199
|
+
static polymorphicName = `pubid:jis:${kind}`;
|
|
176
200
|
static attributes = extendAttributes(BaseIdentifier, {
|
|
177
201
|
number: { type: "string" },
|
|
178
202
|
parts: { type: "string", collection: true },
|
|
179
203
|
year: { type: "integer" },
|
|
180
204
|
language: { type: "string" },
|
|
205
|
+
language_before_year: { type: "boolean", equalityIgnored: true },
|
|
181
206
|
all_parts: { type: "boolean", default: false },
|
|
182
207
|
reaffirmed: { type: "boolean" },
|
|
183
208
|
symbol: { type: "string" },
|
|
184
209
|
});
|
|
185
|
-
static mappings = keyValue({ wire: "number", to: "number" }, { wire: "parts", to: "parts" }, { wire: "year", to: "year" }, { wire: "language", to: "language" }, { wire: "all_parts", to: "all_parts" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "symbol", to: "symbol" });
|
|
210
|
+
static mappings = keyValue({ wire: "number", to: "number" }, { wire: "parts", to: "parts" }, { wire: "year", to: "year" }, { wire: "language", to: "language" }, { wire: "language_before_year", to: "language_before_year" }, { wire: "all_parts", to: "all_parts" }, { wire: "reaffirmed", to: "reaffirmed" }, { wire: "symbol", to: "symbol" });
|
|
186
211
|
code() {
|
|
187
212
|
if (this.base !== undefined)
|
|
188
213
|
return this.base.code();
|
|
189
|
-
|
|
214
|
+
const prefix = WES_TYPE_PREFIXES[kind];
|
|
215
|
+
const root = prefix === undefined ? "WES" : `WES ${prefix}`;
|
|
216
|
+
let result = `${root} ${this.number}`;
|
|
190
217
|
if (this.parts !== undefined)
|
|
191
218
|
result += this.parts.map((p) => `-${p}`).join("");
|
|
192
219
|
return result;
|
|
193
220
|
}
|
|
194
221
|
render() {
|
|
195
222
|
let result = this.code() ?? "";
|
|
196
|
-
|
|
197
|
-
result += `:${this.yearWithReaffirmation()}`;
|
|
198
|
-
if (this.language !== undefined)
|
|
199
|
-
result += `(${this.language})`;
|
|
223
|
+
result += this.yearAndLanguage();
|
|
200
224
|
if (this.all_parts === true)
|
|
201
225
|
result += "(規格群)";
|
|
202
226
|
return result + this.symbolSuffix();
|
|
@@ -205,7 +229,11 @@ function wesClass() {
|
|
|
205
229
|
registerType(JisWesIdentifier);
|
|
206
230
|
return JisWesIdentifier;
|
|
207
231
|
}
|
|
208
|
-
const
|
|
232
|
+
const WES_CLASSES = {
|
|
233
|
+
"welding-engineering-standard": wesClass("welding-engineering-standard"),
|
|
234
|
+
"welding-engineering-technical-report": wesClass("welding-engineering-technical-report"),
|
|
235
|
+
"welding-engineering-technical-specification": wesClass("welding-engineering-technical-specification"),
|
|
236
|
+
};
|
|
209
237
|
class JisUrnGenerator extends BaseUrnGenerator {
|
|
210
238
|
generate() {
|
|
211
239
|
const id = this.identifier;
|
|
@@ -226,7 +254,7 @@ class JisUrnGenerator extends BaseUrnGenerator {
|
|
|
226
254
|
return parts.join(":");
|
|
227
255
|
}
|
|
228
256
|
}
|
|
229
|
-
for (const klass of [...Object.values(KIND_CLASSES),
|
|
257
|
+
for (const klass of [...Object.values(KIND_CLASSES), ...Object.values(WES_CLASSES)]) {
|
|
230
258
|
klass.urnGenerator = JisUrnGenerator;
|
|
231
259
|
}
|
|
232
260
|
function isObj(v) {
|
|
@@ -294,13 +322,29 @@ class JisBuilder {
|
|
|
294
322
|
};
|
|
295
323
|
if (tree["year"] !== undefined && tree["year"] !== null)
|
|
296
324
|
attrs["year"] = Number(tree["year"]);
|
|
297
|
-
|
|
325
|
+
const wesType = tree["wes_type"] === undefined || tree["wes_type"] === null ? undefined : String(tree["wes_type"]);
|
|
326
|
+
const kind = wesType === "TR"
|
|
327
|
+
? "welding-engineering-technical-report"
|
|
328
|
+
: wesType === "TS"
|
|
329
|
+
? "welding-engineering-technical-specification"
|
|
330
|
+
: "welding-engineering-standard";
|
|
331
|
+
// "wes_language" is a language printed before the year
|
|
332
|
+
// ("WES 1112(E):2022"); an id carries one language, not two.
|
|
333
|
+
if (tree["wes_language"] !== undefined && tree["wes_language"] !== null) {
|
|
334
|
+
if (tree["language"] !== undefined && tree["language"] !== null) {
|
|
335
|
+
throw new ParseFailed("JIS: a WES id carries one language, not two", 0);
|
|
336
|
+
}
|
|
337
|
+
attrs["language"] = String(tree["wes_language"]);
|
|
338
|
+
attrs["language_before_year"] = true;
|
|
339
|
+
}
|
|
340
|
+
else if (tree["language"] !== undefined && tree["language"] !== null) {
|
|
298
341
|
attrs["language"] = String(tree["language"]);
|
|
342
|
+
}
|
|
299
343
|
if (tree["all_parts"] !== undefined)
|
|
300
344
|
attrs["all_parts"] = true;
|
|
301
345
|
if (tree["reaffirmed"] !== undefined && tree["reaffirmed"] !== null)
|
|
302
346
|
attrs["reaffirmed"] = true;
|
|
303
|
-
return new
|
|
347
|
+
return new WES_CLASSES[kind](attrs);
|
|
304
348
|
}
|
|
305
349
|
buildSupplement(tree, kind, key, prefix) {
|
|
306
350
|
const supp = isObj(tree[key]) ? tree[key] : {};
|
|
@@ -180,6 +180,18 @@ function locateIdentifierKlass(h) {
|
|
|
180
180
|
return classForKind("dated-document");
|
|
181
181
|
}
|
|
182
182
|
let series = s(h["series"]);
|
|
183
|
+
// The default-series plain-number branch (pubid#711): the grammar's
|
|
184
|
+
// trailing alternatives accept a bare report number ("800-90B") and
|
|
185
|
+
// its publisher-led spelling ("NIST 800-90B") with NO series token.
|
|
186
|
+
// The SP series is the default: the docid-derived citation of
|
|
187
|
+
// NIST.SP.800-90B is exactly the bare docnumber "800-90B", and the
|
|
188
|
+
// Builder fills the same SP series the spelled form carries, so the
|
|
189
|
+
// two spellings are one identity to a lookup. No other branch can
|
|
190
|
+
// arrive here series-less (dated shapes returned above; every
|
|
191
|
+
// series-bearing branch captures :series).
|
|
192
|
+
if (series === undefined) {
|
|
193
|
+
return classForKind("special-publication");
|
|
194
|
+
}
|
|
183
195
|
if (series?.startsWith("NBS ") === true || series?.startsWith("NBS.") === true || series?.startsWith("NIST.") === true) {
|
|
184
196
|
const separator = series.startsWith("NBS ") ? "NBS " : series.startsWith("NBS.") ? "NBS." : "NIST.";
|
|
185
197
|
let simple = series.slice(separator.length);
|
|
@@ -857,6 +869,21 @@ class NistBuilder {
|
|
|
857
869
|
const klass = locateIdentifierKlass(h);
|
|
858
870
|
const policy = seriesPolicy(s(h["series"]));
|
|
859
871
|
const identifier = new klass();
|
|
872
|
+
// The default-series plain-number branch (pubid#711): the grammar's
|
|
873
|
+
// trailing alternatives carry no series token ("800-90B" /
|
|
874
|
+
// "NIST 800-90B"), so the identity gains the class's default series
|
|
875
|
+
// and parses == to the spelled "NIST SP 800-90B" form. The bare
|
|
876
|
+
// publisher rides the series-default-publisher fill at the tail
|
|
877
|
+
// (the #704 shape: filled after publisher_was_parsed is recorded,
|
|
878
|
+
// so the bare face keeps rendering bare). The policy stays the
|
|
879
|
+
// series-less Base one — Ruby's Series.for reads parsed_hash, not
|
|
880
|
+
// the filled attribute (SP's own policy is Base anyway).
|
|
881
|
+
if (h["series"] === undefined) {
|
|
882
|
+
const defaultSeries = klass.nistDefaultSeries;
|
|
883
|
+
if (defaultSeries !== undefined) {
|
|
884
|
+
identifier["series"] = new NistCode({ value: defaultSeries });
|
|
885
|
+
}
|
|
886
|
+
}
|
|
860
887
|
const attrs = {};
|
|
861
888
|
const toEdition = (v) => {
|
|
862
889
|
if (isObj(v)) {
|
|
@@ -1123,16 +1150,19 @@ class NistBuilder {
|
|
|
1123
1150
|
self["supplement"] = NistSupplement.fromRaw(supp.value, supp.hasRevision);
|
|
1124
1151
|
}
|
|
1125
1152
|
}
|
|
1126
|
-
//
|
|
1153
|
+
// apply_series_default_publisher (the #704 rule): a series that
|
|
1154
|
+
// implies its publisher (bare "FIPS 197" is "NIST FIPS 197"; bare
|
|
1155
|
+
// "800-90B" is "NIST SP 800-90B" — pubid#712) gets it now, after the
|
|
1156
|
+
// publisher_was_parsed: false above, so the two spellings are ==
|
|
1157
|
+
// while the bare face keeps rendering bare (the printed-publisher
|
|
1158
|
+
// views read the flag, not the filled value). Runs only when the
|
|
1159
|
+
// publisher is absent AND unspelled — at this point that is exactly
|
|
1160
|
+
// `publisher === undefined` (the flag was recorded false above iff
|
|
1161
|
+
// no publisher was parsed).
|
|
1127
1162
|
if (self["publisher"] === undefined) {
|
|
1128
1163
|
const defaultPublisher = identifier.constructor.nistDefaultPublisher;
|
|
1129
1164
|
if (defaultPublisher !== undefined && defaultPublisher !== "") {
|
|
1130
1165
|
self["publisher"] = defaultPublisher;
|
|
1131
|
-
if (self["publisher_was_parsed"] === false) {
|
|
1132
|
-
// Circular/RPT/MP render "NBS <series>" through the default even
|
|
1133
|
-
// when not parsed — keep the flag false (Ruby publisher_was_parsed
|
|
1134
|
-
// stays false but to_short_style uses default only via series).
|
|
1135
|
-
}
|
|
1136
1166
|
}
|
|
1137
1167
|
}
|
|
1138
1168
|
return identifier;
|
|
@@ -680,6 +680,11 @@ function nistClass(spec) {
|
|
|
680
680
|
class NistConcrete extends (spec.supplementSeam === true ? NistSupplementIdentifier : NistIdentifier) {
|
|
681
681
|
static polymorphicName = `pubid:nist:${spec.kind}`;
|
|
682
682
|
static urnGenerator = NistUrnGenerator;
|
|
683
|
+
/** Ruby `self.default_series` (pubid#711) — read by the Builder. */
|
|
684
|
+
static nistDefaultSeries = spec.defaultSeries;
|
|
685
|
+
/** Ruby `self.series_default_publisher` (#704/#712) — read by the
|
|
686
|
+
* Builder's series-default-publisher fill. */
|
|
687
|
+
static nistDefaultPublisher = spec.seriesDefaultPublisher;
|
|
683
688
|
seriesCode() {
|
|
684
689
|
return spec.seriesCode;
|
|
685
690
|
}
|
|
@@ -819,7 +824,17 @@ export class NistSupplementIdentifier extends NistIdentifier {
|
|
|
819
824
|
}
|
|
820
825
|
}
|
|
821
826
|
const TYPE_SPECS = [
|
|
822
|
-
{
|
|
827
|
+
{
|
|
828
|
+
kind: "special-publication", seriesCode: "SP",
|
|
829
|
+
// The default-series plain-number branch (pubid#711): a citation
|
|
830
|
+
// shaped like the docnumber ("800-90B", publisher-led
|
|
831
|
+
// "NIST 800-90B") names an SP document — the docid-derived
|
|
832
|
+
// citation of NIST.SP.800-90B is exactly "800-90B" — and a bare
|
|
833
|
+
// plain-number parse carries the series' NIST publisher (the #704
|
|
834
|
+
// shape), so it is == to the spelled "NIST SP 800-90B" form a
|
|
835
|
+
// lookup compares against.
|
|
836
|
+
defaultSeries: "SP", seriesDefaultPublisher: "NIST",
|
|
837
|
+
},
|
|
823
838
|
{ kind: "federal-information-processing-standards", seriesCode: "FIPS", defaultPublisher: "", style: "fips" },
|
|
824
839
|
{ kind: "interagency-report", seriesCode: "IR", forceShort: true },
|
|
825
840
|
{ kind: "handbook", seriesCode: "HB" },
|
|
@@ -18,6 +18,9 @@ export interface AttributeSpec {
|
|
|
18
18
|
collection?: boolean;
|
|
19
19
|
/** Materialize [] when the input hash omits the key (tgpp parts). */
|
|
20
20
|
initializeEmpty?: boolean;
|
|
21
|
+
/** Ruby `equality_ignored`: the attribute serializes, but `==` skips it
|
|
22
|
+
* (jis language_before_year — where the source printed "(E)" is spelling). */
|
|
23
|
+
equalityIgnored?: boolean;
|
|
21
24
|
}
|
|
22
25
|
export type AttributeTable = Record<string, AttributeSpec>;
|
|
23
26
|
/**
|
|
@@ -62,6 +62,13 @@ export declare abstract class BaseIdentifier {
|
|
|
62
62
|
* `PubidUrn.parse(this.toPubidUrn()).toHash == this.toHash`. */
|
|
63
63
|
toPubidUrn(): string;
|
|
64
64
|
fromHash(hash: Record<string, unknown>): BaseIdentifier;
|
|
65
|
+
/** Ruby == (lutaml equality with `equality_ignored`): canonical-hash
|
|
66
|
+
* equality that skips the attributes a flavor declares
|
|
67
|
+
* equalityIgnored. The skipped keys stay in to_hash — it is ==, not
|
|
68
|
+
* serialization, that reads the flag. */
|
|
69
|
+
equals(other: BaseIdentifier): boolean;
|
|
70
|
+
/** The canonical hash minus every equalityIgnored attribute's wire key. */
|
|
71
|
+
protected equalityHash(): Record<string, unknown>;
|
|
65
72
|
/** SubsetMatch: an all-parts reference skips the part attributes. */
|
|
66
73
|
subsetAllPartsWildcard(): boolean;
|
|
67
74
|
protected classAttributes(): AttributeTable;
|
package/dist/model/identifier.js
CHANGED
|
@@ -116,6 +116,23 @@ export class BaseIdentifier {
|
|
|
116
116
|
fromHash(hash) {
|
|
117
117
|
return this.constructor.fromHash(hash);
|
|
118
118
|
}
|
|
119
|
+
/** Ruby == (lutaml equality with `equality_ignored`): canonical-hash
|
|
120
|
+
* equality that skips the attributes a flavor declares
|
|
121
|
+
* equalityIgnored. The skipped keys stay in to_hash — it is ==, not
|
|
122
|
+
* serialization, that reads the flag. */
|
|
123
|
+
equals(other) {
|
|
124
|
+
return canonicalKey(this.equalityHash()) === canonicalKey(other.equalityHash());
|
|
125
|
+
}
|
|
126
|
+
/** The canonical hash minus every equalityIgnored attribute's wire key. */
|
|
127
|
+
equalityHash() {
|
|
128
|
+
const hash = { ...this.toHash() };
|
|
129
|
+
for (const [name, spec] of Object.entries(this.classAttributes())) {
|
|
130
|
+
if (spec.equalityIgnored !== true)
|
|
131
|
+
continue;
|
|
132
|
+
delete hash[this.wireKeyFor(name).wire];
|
|
133
|
+
}
|
|
134
|
+
return hash;
|
|
135
|
+
}
|
|
119
136
|
/** SubsetMatch: an all-parts reference skips the part attributes. */
|
|
120
137
|
subsetAllPartsWildcard() {
|
|
121
138
|
return Boolean(this["all_parts"]);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pubid-scheme URN schema of DOI_PFS — the transcription
|
|
3
|
+
* of lib/pubid/<flavor>/pubid_urn_schema.rb (pubid#656, completed by
|
|
4
|
+
* #670; design in docs/URN-SCHEMES.adoc). GENERATED by
|
|
5
|
+
* scripts/port-urn-schemas.rb from the ruby declaration: edit the ruby
|
|
6
|
+
* schema and regenerate, never this table by hand.
|
|
7
|
+
*/
|
|
8
|
+
export declare const doiPfsSchema: import("../schema.js").FlavorSchema;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pubid-scheme URN schema of DOI_PFS — the transcription
|
|
3
|
+
* of lib/pubid/<flavor>/pubid_urn_schema.rb (pubid#656, completed by
|
|
4
|
+
* #670; design in docs/URN-SCHEMES.adoc). GENERATED by
|
|
5
|
+
* scripts/port-urn-schemas.rb from the ruby declaration: edit the ruby
|
|
6
|
+
* schema and regenerate, never this table by hand.
|
|
7
|
+
*/
|
|
8
|
+
import { define } from "../index.js";
|
|
9
|
+
export const doiPfsSchema = define("doi_pfs", (s) => {
|
|
10
|
+
s.atom("prefix", "prefix");
|
|
11
|
+
s.atom("suffix", "suffix");
|
|
12
|
+
s.type("pubid:doi_pfs:identifier", "id", { core: [] });
|
|
13
|
+
s.type("pubid:doi_pfs:resource", "resource", { core: [] });
|
|
14
|
+
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The registry of all
|
|
2
|
+
* The registry of all 45 flavor pubid-urn schema tables — the TS mirror
|
|
3
3
|
* of lib/pubid.rb's autoloaded Pubid::<Flavor>::PubidUrnSchema chain.
|
|
4
4
|
* Declared tables only: importing this module has no side effects; the
|
|
5
5
|
* pubid-urn module builds its flavor lookup lazily from this array.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The registry of all
|
|
2
|
+
* The registry of all 45 flavor pubid-urn schema tables — the TS mirror
|
|
3
3
|
* of lib/pubid.rb's autoloaded Pubid::<Flavor>::PubidUrnSchema chain.
|
|
4
4
|
* Declared tables only: importing this module has no side effects; the
|
|
5
5
|
* pubid-urn module builds its flavor lookup lazily from this array.
|
|
@@ -19,6 +19,7 @@ import { cencenelecSchema } from "./cencenelec.js";
|
|
|
19
19
|
import { cieSchema } from "./cie.js";
|
|
20
20
|
import { csaSchema } from "./csa.js";
|
|
21
21
|
import { doiSchema } from "./doi.js";
|
|
22
|
+
import { doiPfsSchema } from "./doi_pfs.js";
|
|
22
23
|
import { eascSchema } from "./easc.js";
|
|
23
24
|
import { ecmaSchema } from "./ecma.js";
|
|
24
25
|
import { etsiSchema } from "./etsi.js";
|
|
@@ -65,6 +66,7 @@ export const PUBID_URN_SCHEMAS = [
|
|
|
65
66
|
cieSchema,
|
|
66
67
|
csaSchema,
|
|
67
68
|
doiSchema,
|
|
69
|
+
doiPfsSchema,
|
|
68
70
|
eascSchema,
|
|
69
71
|
ecmaSchema,
|
|
70
72
|
etsiSchema,
|
|
@@ -11,14 +11,21 @@ export const jisSchema = define("jis", (s) => {
|
|
|
11
11
|
s.atom("parts", "part", "list");
|
|
12
12
|
s.atom("year", "year", "int");
|
|
13
13
|
s.atom("reaffirmed", "reaffirmed", "bool");
|
|
14
|
+
s.atom("language", "lang");
|
|
15
|
+
s.facet("language_before_year", "langfirst", "bool");
|
|
14
16
|
s.type("pubid:jis:all-parts", "all");
|
|
15
|
-
s.type("pubid:jis:amendment", "amd");
|
|
16
|
-
s.type("pubid:jis:corrigendum", "cor");
|
|
17
|
-
s.type("pubid:jis:explanation", "e"
|
|
17
|
+
s.type("pubid:jis:amendment", "amd", { core: [["number", "int"]] });
|
|
18
|
+
s.type("pubid:jis:corrigendum", "cor", { core: [["number", "int"]] });
|
|
19
|
+
s.type("pubid:jis:explanation", "e", {
|
|
20
|
+
core: [],
|
|
21
|
+
atoms: [["number", "n", "int"]],
|
|
22
|
+
});
|
|
18
23
|
s.type("pubid:jis:identifier", "id");
|
|
19
24
|
s.type("pubid:jis:japanese-industrial-standard", "jis");
|
|
20
25
|
s.type("pubid:jis:standard", "std");
|
|
21
26
|
s.type("pubid:jis:technical-report", "tr");
|
|
22
27
|
s.type("pubid:jis:technical-specification", "ts");
|
|
23
28
|
s.type("pubid:jis:welding-engineering-standard", "wes");
|
|
29
|
+
s.type("pubid:jis:welding-engineering-technical-report", "westr");
|
|
30
|
+
s.type("pubid:jis:welding-engineering-technical-specification", "wests");
|
|
24
31
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubid/pubid",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.40",
|
|
4
4
|
"description": "TypeScript PubID identifiers: resolution, normalization and canonical hashes for every identifier in the pubid-testsuite corpus (41 standards bodies), with a conformance runner mirroring the Ruby reference",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"bindings":null,"version":"0.1.0","grammar":"PubidCalconnectPfs","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Str":{"pattern":"CC"}},{"Str":{"pattern":"/"}},{"Entity":{"atom":8}},{"Entity":{"atom":6}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Alternative":{"atoms":[4,5]}},{"Repetition":{"atom":3,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"series","atom":7}},{"Sequence":{"atoms":[1,2]}},{"Repetition":{"atom":9,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":" "}},{"Entity":{"atom":24}},{"Entity":{"atom":14}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":13,"min":1,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"."}},{"Str":{"pattern":"-"}},{"Alternative":{"atoms":[16,17]}},{"Entity":{"atom":14}},{"Repetition":{"atom":19,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[18,20]}},{"Repetition":{"atom":21,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[15,22]}},{"Named":{"name":"number","atom":23}},{"Str":{"pattern":":"}},{"Entity":{"atom":29}},{"Entity":{"atom":14}},{"Repetition":{"atom":27,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"year","atom":28}},{"Str":{"pattern":"-"}},{"Entity":{"atom":34}},{"Entity":{"atom":14}},{"Repetition":{"atom":32,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"month","atom":33}},{"Str":{"pattern":"-"}},{"Entity":{"atom":39}},{"Entity":{"atom":14}},{"Repetition":{"atom":37,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"day","atom":38}},{"Sequence":{"atoms":[30,31,35,36]}},{"Repetition":{"atom":40,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[25,26,41]}},{"Repetition":{"atom":42,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[0,10,11,12,43]}}],"root":44},"bindings":[{"capture":"series","path":"series","type":"string","card":null,"preprocess":null},{"capture":"number","path":"number","type":"string","card":null,"preprocess":null},{"capture":"year","path":"year","type":"string","card":null,"preprocess":null},{"capture":"month","path":"month","type":"string","card":null,"preprocess":null},{"capture":"day","path":"day","type":"string","card":null,"preprocess":null}]}},"preprocess":{},"tables":{},"lint":{"order_warnings":[]},"default_entry":"identifier","render":{},"derive":{},"tests":[{"entry":"identifier","kind":"accept","input":"CC 18011","expect":{}},{"entry":"identifier","kind":"accept","input":"CC 18011:2018","expect":{}},{"entry":"identifier","kind":"accept","input":"CC 11001:2024","expect":{}},{"entry":"identifier","kind":"accept","input":"CC/DIR 10006:2019","expect":{}},{"entry":"identifier","kind":"accept","input":"CC/Adv 0707.1:2007","expect":{}},{"entry":"identifier","kind":"accept","input":"CC/A 0812-1:2008","expect":{}},{"entry":"identifier","kind":"accept","input":"CC/WD 51017:2024-07-23","expect":{}},{"entry":"identifier","kind":"reject","input":"nonsense","expect":{}},{"entry":"identifier","kind":"reject","input":"CC","expect":{}},{"entry":"identifier","kind":"reject","input":"CC/WD","expect":{}},{"entry":"identifier","kind":"reject","input":"CC 18011:","expect":{}},{"entry":"identifier","kind":"reject","input":"CC 18011:2024-","expect":{}},{"entry":"identifier","kind":"example","input":"CC 18011","expect":{"number":"18011"}},{"entry":"identifier","kind":"example","input":"CC 18011:2018","expect":{"number":"18011","year":"2018"}},{"entry":"identifier","kind":"example","input":"CC 11001:2024","expect":{"number":"11001","year":"2024"}},{"entry":"identifier","kind":"example","input":"CC/DIR 10006:2019","expect":{"series":"DIR","number":"10006","year":"2019"}},{"entry":"identifier","kind":"example","input":"CC/Adv 0707.1:2007","expect":{"series":"Adv","number":"0707.1","year":"2007"}},{"entry":"identifier","kind":"example","input":"CC/A 0812-1:2008","expect":{"series":"A","number":"0812-1","year":"2008"}},{"entry":"identifier","kind":"example","input":"CC/WD 51017:2024-07-23","expect":{"series":"WD","number":"51017","year":"2024","month":"07","day":"23"}}],"docs":{},"source":"# PFS-generated grammar — DO NOT EDIT BY HAND.\n# Source: definitions/calconnect.pfs (pfs:1) sha256:2e864f0185a1a2f18a392f2f401ad3c9d65d1f32a9ec3f3f04f7dfca9b2226c4\n# Compiler: pubid/grammar/pfs 0.1.0\n# Flavor key: calconnect_pfs (grammar PubidCalconnectPfs)\n# Regenerate: ruby scripts/pfs compile definitions/calconnect.pfs --as calconnect_pfs\n\ngrammar PubidCalconnectPfs version \"0.1.0\" edition 2 {\n\n # Grammar fragments: named lexical terms declared under `grammar:`.\n digit = %x30-39\n letter = %x41-5A / %x61-7A\n space = \" \"\n slash = \"/\"\n colon = \":\"\n dash = \"-\"\n\n # Fields: one capture rule per declared field; the whole pattern\n # is the capture.\n calconnect_series = (1*letter) as series\n calconnect_number = (1*digit [(\".\" / \"-\") 1*digit]) as number\n calconnect_year = (1*digit) as year\n calconnect_month = (1*digit) as month\n calconnect_day = (1*digit) as day\n\n # Identifier rule: the canonical template first, then the\n # declared alternates (parse-in spellings; they normalize to the\n # canonical render face).\n identifier = \"CC\" [\"/\" calconnect_series] \" \" calconnect_number [\":\" calconnect_year [\"-\" calconnect_month \"-\" calconnect_day]]\n entry identifier: identifier\n\n # Typed model bindings: every bound capture lands on the\n # consumer model's field of the same name.\n bindings identifier {\n series -> series (string)\n number -> number (string)\n year -> year (string)\n month -> month (string)\n day -> day (string)\n }\n\n # REQUIRED examples from the definition — accepts, rejects, and\n # the capture expectations the compiler replayed at compile time.\n test {\n accept \"CC 18011\"\n accept \"CC 18011:2018\"\n accept \"CC 11001:2024\"\n accept \"CC/DIR 10006:2019\"\n accept \"CC/Adv 0707.1:2007\"\n accept \"CC/A 0812-1:2008\"\n accept \"CC/WD 51017:2024-07-23\"\n reject \"nonsense\"\n reject \"CC\"\n reject \"CC/WD\"\n reject \"CC 18011:\"\n reject \"CC 18011:2024-\"\n example \"CC 18011\" { number: \"18011\" }\n example \"CC 18011:2018\" { number: \"18011\" year: \"2018\" }\n example \"CC 11001:2024\" { number: \"11001\" year: \"2024\" }\n example \"CC/DIR 10006:2019\" { series: \"DIR\" number: \"10006\" year: \"2019\" }\n example \"CC/Adv 0707.1:2007\" { series: \"Adv\" number: \"0707.1\" year: \"2007\" }\n example \"CC/A 0812-1:2008\" { series: \"A\" number: \"0812-1\" year: \"2008\" }\n example \"CC/WD 51017:2024-07-23\" { series: \"WD\" number: \"51017\" year: \"2024\" month: \"07\" day: \"23\" }\n }\n}\n","source_hash":"35a33d659c86202186a5e6beb8c7df58af7bd6667dd55b6cb3cecb8855713b85","unicode_tables":"onigmo (Ruby 3.4.8)","compiler_version":"1.3.126","edition":2,"semantics_hash":"sha256:9fbceffd1828c207a9ec854699d0801fad9e52521a972e39dc1838fb80440dc8","checksum":"sha256:6557fd4360e2deab7ca4062b72e5cd6e60b6e3cd0252cb5b1e30d66f3905f467"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"bindings":null,"version":"0.1.0","grammar":"PubidCenPfs","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Str":{"pattern":"EN"}},{"Str":{"pattern":" "}},{"Entity":{"atom":8}},{"Re":{"pattern":"[\\x31-\\x39]"}},{"Entity":{"atom":5}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":4,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[3,6]}},{"Named":{"name":"number","atom":7}},{"Str":{"pattern":"-"}},{"Entity":{"atom":13}},{"Entity":{"atom":5}},{"Repetition":{"atom":11,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"part","atom":12}},{"Sequence":{"atoms":[9,10]}},{"Repetition":{"atom":14,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":":"}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Repetition":{"atom":18,"min":4,"max":null,"tag":"Repetition"}},{"Named":{"name":"year","atom":19}},{"Sequence":{"atoms":[16,17]}},{"Repetition":{"atom":21,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[0,1,2,15,22]}}],"root":23},"bindings":[{"capture":"number","path":"number","type":"string","card":null,"preprocess":null},{"capture":"part","path":"part","type":"string","card":null,"preprocess":null},{"capture":"year","path":"year","type":"string","card":null,"preprocess":null}]}},"preprocess":{},"tables":{},"lint":{"order_warnings":[]},"default_entry":"identifier","render":{},"derive":{},"tests":[{"entry":"identifier","kind":"accept","input":"EN 1325","expect":{}},{"entry":"identifier","kind":"accept","input":"EN 12464-1:2011","expect":{}},{"entry":"identifier","kind":"accept","input":"EN 1177:2018","expect":{}},{"entry":"identifier","kind":"reject","input":"EN","expect":{}},{"entry":"identifier","kind":"reject","input":"EN ISO 9001:2015","expect":{}},{"entry":"identifier","kind":"reject","input":"nonsense","expect":{}},{"entry":"identifier","kind":"reject","input":"CEN/TS 12345","expect":{}},{"entry":"identifier","kind":"example","input":"EN 1325","expect":{"number":"1325"}},{"entry":"identifier","kind":"example","input":"EN 12464-1:2011","expect":{"number":"12464","part":"1","year":"2011"}},{"entry":"identifier","kind":"example","input":"EN 1177:2018","expect":{"number":"1177","year":"2018"}}],"docs":{},"source":"# PFS-generated grammar — DO NOT EDIT BY HAND.\n# Source: definitions/cen.pfs (pfs:1) sha256:bc1edd5874f8938b5f946416a2b052d9d9b9df3d99f6c20a3d88fcab9ae1d70c\n# Compiler: pubid/grammar/pfs 0.1.0\n# Flavor key: cen_pfs (grammar PubidCenPfs)\n# Regenerate: ruby scripts/pfs compile definitions/cen.pfs --as cen_pfs\n# Module: iso.inner v1 (sha256:6f04cf475f1c...)\n# Module: en.overlay v1 (sha256:851af8c5f31b...)\n# Module: national.prefix v1 (sha256:c7aa2f2442e8...)\n# Module: supplements.core v1 (sha256:9fa9656375c7...)\n\ngrammar PubidCenPfs version \"0.1.0\" edition 2 {\n\n # Grammar fragments: named lexical terms declared under `grammar:`.\n iso_space = \" \"\n iso_colon = \":\"\n iso_dash = \"-\"\n iso_year = 4*digit\n iso_part = 1*digit [\"-\" 1*digit]\n iso_number = 1*(\"0\" %x31-39) *digit [iso_dash iso_part]\n iso_document = \"ISO\" iso_space iso_number [iso_colon iso_year]\n en_space = \" \"\n en_draft = (\"pr\" / \"Fpr\")\n en_face = [en_draft] \"EN\"\n en_adoption = en_face en_space iso_document\n supplement_number = 1*digit\n supplement_year = 4*digit\n supplement_month = 2*digit\n digit = %x30-39\n space = \" \"\n slash = \"/\"\n colon = \":\"\n dash = \"-\"\n\n # Fields: one capture rule per declared field; the whole pattern\n # is the capture.\n cen_cenelec_number = ((%x31-39) *digit) as number\n cen_cenelec_part = (1*digit) as part\n cen_cenelec_year = (4*digit) as year\n\n # Identifier rule: the canonical template first, then the\n # declared alternates (parse-in spellings; they normalize to the\n # canonical render face).\n identifier = \"EN\" \" \" cen_cenelec_number [\"-\" cen_cenelec_part] [\":\" cen_cenelec_year]\n entry identifier: identifier\n\n # Typed model bindings: every bound capture lands on the\n # consumer model's field of the same name.\n bindings identifier {\n number -> number (string)\n part -> part (string)\n year -> year (string)\n }\n\n # REQUIRED examples from the definition — accepts, rejects, and\n # the capture expectations the compiler replayed at compile time.\n test {\n accept \"EN 1325\"\n accept \"EN 12464-1:2011\"\n accept \"EN 1177:2018\"\n reject \"EN\"\n reject \"EN ISO 9001:2015\"\n reject \"nonsense\"\n reject \"CEN/TS 12345\"\n example \"EN 1325\" { number: \"1325\" }\n example \"EN 12464-1:2011\" { number: \"12464\" part: \"1\" year: \"2011\" }\n example \"EN 1177:2018\" { number: \"1177\" year: \"2018\" }\n }\n}\n","source_hash":"4b84b6acda6f62fbbff60e0ff603d72e3ff00b71906914855633b6f0404869db","unicode_tables":"onigmo (Ruby 3.4.8)","compiler_version":"1.3.126","edition":2,"semantics_hash":"sha256:4363f170082d3242a35648e8b019037e9670c804d4ea951a51487697eb0c4cee","checksum":"sha256:e19eae585ed8ee560c88d97c8289d827384d21214db02634bc3eeff5a0296ac9"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"bindings":null,"version":"0.1.0","grammar":"PubidDoiPfs","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Str":{"pattern":"doi:"}},{"Entity":{"atom":8}},{"Str":{"pattern":"10"}},{"Str":{"pattern":"."}},{"Entity":{"atom":5}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":4,"min":2,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[2,3,6]}},{"Named":{"name":"prefix","atom":7}},{"Str":{"pattern":"/"}},{"Entity":{"atom":23}},{"Entity":{"atom":21}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Re":{"pattern":"[.]"}},{"Re":{"pattern":"[_]"}},{"Re":{"pattern":"[\\-]"}},{"Re":{"pattern":"[/]"}},{"Re":{"pattern":"[(]"}},{"Re":{"pattern":"[)]"}},{"Alternative":{"atoms":[12,13,14,15,16,17,18,19,20]}},{"Repetition":{"atom":11,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"suffix","atom":22}},{"Sequence":{"atoms":[0,1,9,10]}},{"Entity":{"atom":33}},{"Str":{"pattern":"https://"}},{"Str":{"pattern":"http://"}},{"Alternative":{"atoms":[26,27]}},{"Repetition":{"atom":28,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"doi.org"}},{"Repetition":{"atom":30,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[29,31]}},{"Repetition":{"atom":32,"min":0,"max":1,"tag":"Maybe"}},{"Named":{"name":"url_prefix","atom":25}},{"Repetition":{"atom":34,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":41}},{"Str":{"pattern":"doi:"}},{"Str":{"pattern":"DOI:"}},{"Str":{"pattern":"Doi:"}},{"Alternative":{"atoms":[37,38,39]}},{"Repetition":{"atom":40,"min":0,"max":1,"tag":"Maybe"}},{"Named":{"name":"scheme_prefix","atom":36}},{"Repetition":{"atom":42,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":45}},{"Str":{"pattern":"/"}},{"Named":{"name":"slash","atom":44}},{"Repetition":{"atom":46,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":8}},{"Str":{"pattern":"/"}},{"Entity":{"atom":23}},{"Sequence":{"atoms":[35,43,47,48,49,50]}},{"Alternative":{"atoms":[24,51]}}],"root":52},"bindings":[{"capture":"prefix","path":"prefix","type":"string","card":null,"preprocess":null},{"capture":"suffix","path":"suffix","type":"string","card":null,"preprocess":null}]}},"preprocess":{},"tables":{},"lint":{"order_warnings":["rule identifier: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)"]},"default_entry":"identifier","render":{},"derive":{},"tests":[{"entry":"identifier","kind":"accept","input":"doi:10.1000/182","expect":{}},{"entry":"identifier","kind":"accept","input":"10.1006/jmbi.1998.2354","expect":{}},{"entry":"identifier","kind":"accept","input":"DOI:10.6028/NIST.2022-04-15.001","expect":{}},{"entry":"identifier","kind":"accept","input":"https://doi.org/10.1000/182","expect":{}},{"entry":"identifier","kind":"reject","input":"doi:","expect":{}},{"entry":"identifier","kind":"reject","input":"doi:10","expect":{}},{"entry":"identifier","kind":"reject","input":"doi:10.X/abc","expect":{}},{"entry":"identifier","kind":"reject","input":"doi:10.1000/","expect":{}},{"entry":"identifier","kind":"reject","input":"nonsense","expect":{}},{"entry":"identifier","kind":"example","input":"doi:10.1000/182","expect":{"prefix":"10.1000","suffix":"182"}},{"entry":"identifier","kind":"example","input":"10.1006/jmbi.1998.2354","expect":{"prefix":"10.1006","suffix":"jmbi.1998.2354"}},{"entry":"identifier","kind":"example","input":"DOI:10.6028/NIST.2022-04-15.001","expect":{"prefix":"10.6028","suffix":"NIST.2022-04-15.001"}},{"entry":"identifier","kind":"example","input":"https://doi.org/10.1000/182","expect":{"prefix":"10.1000","suffix":"182"}}],"docs":{},"source":"# PFS-generated grammar — DO NOT EDIT BY HAND.\n# Source: definitions/doi.pfs (pfs:1) sha256:60abc3c403c61019d727ee44d9a72591c1549672451e6609a72d36189cae6340\n# Compiler: pubid/grammar/pfs 0.1.0\n# Flavor key: doi_pfs (grammar PubidDoiPfs)\n# Regenerate: ruby scripts/pfs compile definitions/doi.pfs --as doi_pfs\n\ngrammar PubidDoiPfs version \"0.1.0\" edition 2 {\n\n # Grammar fragments: named lexical terms declared under `grammar:`.\n digit = %x30-39\n suffix_char = %x30-39 / %x41-5A / %x61-7A / %x2E / %x5F / %x2D / %x2F / %x28 / %x29\n slash = \"/\"\n url_prefix = [[\"https://\" / \"http://\"] [\"doi.org\"]]\n scheme_prefix = [\"doi:\" / \"DOI:\" / \"Doi:\"]\n\n # Fields: one capture rule per declared field; the whole pattern\n # is the capture.\n doi_prefix = (\"10\" \".\" 2*digit) as prefix\n doi_suffix = (1*suffix_char) as suffix\n\n # Identifier rule: the canonical template first, then the\n # declared alternates (parse-in spellings; they normalize to the\n # canonical render face).\n identifier = {\n \"doi:\" doi_prefix \"/\" doi_suffix\n / [url_prefix] [scheme_prefix] [slash] doi_prefix \"/\" doi_suffix\n }\n entry identifier: identifier\n\n # Typed model bindings: every bound capture lands on the\n # consumer model's field of the same name.\n bindings identifier {\n prefix -> prefix (string)\n suffix -> suffix (string)\n }\n\n # REQUIRED examples from the definition — accepts, rejects, and\n # the capture expectations the compiler replayed at compile time.\n test {\n accept \"doi:10.1000/182\"\n accept \"10.1006/jmbi.1998.2354\"\n accept \"DOI:10.6028/NIST.2022-04-15.001\"\n accept \"https://doi.org/10.1000/182\"\n reject \"doi:\"\n reject \"doi:10\"\n reject \"doi:10.X/abc\"\n reject \"doi:10.1000/\"\n reject \"nonsense\"\n example \"doi:10.1000/182\" { prefix: \"10.1000\" suffix: \"182\" }\n example \"10.1006/jmbi.1998.2354\" { prefix: \"10.1006\" suffix: \"jmbi.1998.2354\" }\n example \"DOI:10.6028/NIST.2022-04-15.001\" { prefix: \"10.6028\" suffix: \"NIST.2022-04-15.001\" }\n example \"https://doi.org/10.1000/182\" { prefix: \"10.1000\" suffix: \"182\" }\n }\n}\n","source_hash":"c872de21dfa95b1add4eed4785182c6e661fc79a0a8c15c07eb6209621a20f2c","unicode_tables":"onigmo (Ruby 3.4.8)","compiler_version":"1.3.126","edition":2,"semantics_hash":"sha256:06d0039460d751282b122dd5834bd505046c2cb32605c051ac296f2c29f964b3","checksum":"sha256:25f3643ce0fe181ae16b91a87a43177d495079ed590c6eee3c3cf36825e1fc05"}
|