@pubid/pubid 0.1.37 → 0.1.39
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/flavors/doi_pfs/index.d.ts +35 -0
- package/dist/flavors/doi_pfs/index.js +61 -0
- package/dist/flavors/ecma/index.js +35 -1
- package/dist/flavors/iec/grammar.js +39 -2
- package/dist/flavors/iec/index.js +110 -0
- package/dist/flavors/iec/model.js +29 -4
- package/dist/flavors/iho/index.js +126 -5
- package/dist/flavors/index.js +3 -0
- package/dist/flavors/iso/grammar.d.ts +5 -0
- package/dist/flavors/iso/grammar.js +68 -1
- package/dist/flavors/iso/index.js +65 -1
- package/dist/flavors/iso/model.js +7 -1
- package/dist/flavors/iso/stages.generated.js +1 -1
- package/dist/flavors/nist/index.js +36 -6
- package/dist/flavors/nist/model.js +34 -3
- package/dist/flavors/nist/preprocessor.js +11 -0
- package/dist/flavors/plateau/index.js +21 -2
- 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/iho.js +3 -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/plateau.js +1 -0
- 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/iec.json +1 -1
- package/vendor/parg/iso.json +1 -1
- package/vendor/parg/nist.json +1 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { match, ref, str } from "../../grammar/engine.js";
|
|
2
2
|
import { stageTokens } from "./model.js";
|
|
3
|
+
import { ISO_TYPED_STAGES } from "./stages.generated.js";
|
|
3
4
|
/**
|
|
4
5
|
* Port of lib/pubid/iso/parser.rb. The identifier alternation order is
|
|
5
6
|
* load-bearing (PEG ordered choice): nsb_iso | tc_document |
|
|
@@ -9,6 +10,11 @@ import { stageTokens } from "./model.js";
|
|
|
9
10
|
* supplement tables exactly like the Ruby TYPED_STAGES constants.
|
|
10
11
|
*/
|
|
11
12
|
const SUPPLEMENT_TYPE_KEYS = ["amd", "cor", "suppl", "ext", "add"];
|
|
13
|
+
/** The DAM-family ballot stage codes (grammar table
|
|
14
|
+
* typed_stages_ballots: PDAM, DAM, DAmd, FDAM, FDAmd, FPDAM — exactly
|
|
15
|
+
* these entries' abbrs); the TYPE-first ballot branch stays scoped to
|
|
16
|
+
* the ballot family. */
|
|
17
|
+
export const BALLOT_STAGE_CODES = ["pdam", "damd", "fdamd", "fpdam"];
|
|
12
18
|
const BASE_STAGE_TOKENS = stageTokens().filter((t) => {
|
|
13
19
|
// Supplement tokens are excluded from the base table by type key, but
|
|
14
20
|
// stageTokens() is type-agnostic here; the split is done via the
|
|
@@ -208,7 +214,68 @@ function buildRules() {
|
|
|
208
214
|
.as("base")
|
|
209
215
|
.then(space.maybe(), str("|"), space.maybe(), rules["idf_identifier"])
|
|
210
216
|
.as("joint_identifier"));
|
|
211
|
-
|
|
217
|
+
// Historic TYPE-first ballot faces (decode-to-modern, owner ruling
|
|
218
|
+
// 2026-11-12): the DAM-family token in TYPE position — "ISO/IEC FDAM 1
|
|
219
|
+
// 14496-12:2004", "ISO/PDAM 19973-2" — and the space-attached ballot
|
|
220
|
+
// face "ISO 15877-5:2009 FDAM 1". Both branches sit LAST in the
|
|
221
|
+
// identifier alternation, so they are purely additive: every face an
|
|
222
|
+
// earlier branch parses keeps its exact parse. The ballot token
|
|
223
|
+
// captures as ballot_type_with_stage; a number on the TYPE token is
|
|
224
|
+
// space-bounded (ballot_number) so "PDAM 19973-2" keeps 19973 in the
|
|
225
|
+
// base; an on-base stamp's number/date capture as ballot_stamp_* (the
|
|
226
|
+
// stamp token itself matches uncaptured — the ballot's stage comes
|
|
227
|
+
// from the TYPE token and the decode keeps no spelling). The builder
|
|
228
|
+
// folds the captures into ONE amendment layer over the whole base, the
|
|
229
|
+
// number taken from the TYPE token, the stamp, or the implied 1.
|
|
230
|
+
const ballotStageTokens = ISO_TYPED_STAGES
|
|
231
|
+
.filter((st) => BALLOT_STAGE_CODES.includes(st.code))
|
|
232
|
+
.flatMap((st) => st.abbr);
|
|
233
|
+
const ballotTypeAlt = literalAlternation(ballotStageTokens).as("ballot_type_with_stage");
|
|
234
|
+
rule("ballot_type_with_stage", () => ballotTypeAlt);
|
|
235
|
+
// An on-base stamp riding a ballot face ("/Amd 9:2001", "/Amd.1",
|
|
236
|
+
// "/Am1:2006"): it carries the amendment's number and ballot date
|
|
237
|
+
// while its own token letters are decode-away (matched uncaptured).
|
|
238
|
+
// The stamp's date captures under its own ballot_stamp_* names —
|
|
239
|
+
// reusing the base date capture would collide with second_part's at
|
|
240
|
+
// the sequence merge and the stamp's year would eat the base's.
|
|
241
|
+
rule("ballot_stamp", () => str("/")
|
|
242
|
+
.then(literalAlternation(supplementTypeTokens))
|
|
243
|
+
.then(space
|
|
244
|
+
.maybe()
|
|
245
|
+
.then(digit.repeat(1, 5).as("ballot_stamp_number"))
|
|
246
|
+
.then(str(":")
|
|
247
|
+
.or(dash)
|
|
248
|
+
.then(yearDigits
|
|
249
|
+
.then(dash.then(monthDigits).maybe(), dash.then(dayDigits).maybe())
|
|
250
|
+
.as("ballot_stamp_date"))
|
|
251
|
+
.or(str(":")
|
|
252
|
+
.or(dash)
|
|
253
|
+
.then(str("--").or(str("—")).as("ballot_stamp_undated_marker")))
|
|
254
|
+
.maybe())
|
|
255
|
+
.or(str(".").then(digits.as("ballot_stamp_dot_number")))));
|
|
256
|
+
// "ISO/IEC FDAM 1 14496-12:2004", "ISO/PDAM 19973-2": the ballot
|
|
257
|
+
// token first, then the base kept whole. The TYPE-token number is
|
|
258
|
+
// space-bounded on both sides — mandatory trailing space — so
|
|
259
|
+
// "PDAM 19973-2" cannot read 19973 as the ballot number: with no
|
|
260
|
+
// second space the group backtracks and 19973 parses in second_part.
|
|
261
|
+
rule("ballot_supplement_identifier", () => rules["prefix_with_copublishers"]
|
|
262
|
+
.then(space.maybe(), str("/").maybe(), ballotTypeAlt, space.then(digit.repeat(1, Infinity).as("ballot_number")).then(space).maybe(), space.maybe(), rules["type_with_stage"].maybe(), space.maybe(), rules["second_part"], rules["ballot_stamp"].maybe()));
|
|
263
|
+
// The space-attached ballot face: "ISO 15877-5:2009 FDAM 1" — the
|
|
264
|
+
// base designation first, then the ballot token attached by a space.
|
|
265
|
+
// The base front is inlined (not identifier_copublishers_no_third):
|
|
266
|
+
// that rule ends in third_part_edition, whose own optional space
|
|
267
|
+
// would consume the separator the ballot token needs. No base
|
|
268
|
+
// edition is served here — none of the stored or owner-cited ballot
|
|
269
|
+
// faces carries one.
|
|
270
|
+
rule("ballot_space_supplement_identifier", () => rules["guide_prefix"]
|
|
271
|
+
.as("type_with_stage_fr")
|
|
272
|
+
.then(space)
|
|
273
|
+
.maybe()
|
|
274
|
+
.then(rules["prefix_with_copublishers"].maybe(), space.maybe(), str("/").maybe(), rules["type_with_stage"].maybe(), space.maybe(), rules["second_part"], space, ballotTypeAlt, space.then(digit.repeat(1, Infinity).as("ballot_number")).maybe()));
|
|
275
|
+
rule("identifier", () => rules["bare_tc_document"].or(rules["nsb_iso_identifier"], rules["tc_document"], rules["directives_identifiers"], rules["jcgm_identifier"], rules["iso_r_supplement_identifier"], rules["iso_r_identifier"], rules["supplement_supplement_supplement_identifier"], rules["supplement_supplement_identifier"], rules["supplement_identifier"], rules["joint_identifier"], rules["identifier_copublishers"],
|
|
276
|
+
// The historic ballot faces go last — purely additive branches
|
|
277
|
+
// (an input an earlier member parses keeps that parse).
|
|
278
|
+
rules["ballot_supplement_identifier"], rules["ballot_space_supplement_identifier"]));
|
|
212
279
|
rule("root", () => rules["identifier"]);
|
|
213
280
|
return rules;
|
|
214
281
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ParseFailed, parseGrammar } from "../../grammar/engine.js";
|
|
2
2
|
import { PubidDate, Language, Iteration } from "../../model/component.js";
|
|
3
|
-
import { isoGrammar } from "./grammar.js";
|
|
3
|
+
import { isoGrammar, BALLOT_STAGE_CODES } from "./grammar.js";
|
|
4
4
|
import { IsoBundledIdentifier, IsoDirectives, IsoDirectivesSupplement, IsoEdition, IsoPublisher, IsoSupplementIdentifier, IsoTcDocument, isoClassForType, locateStage, } from "./model.js";
|
|
5
5
|
import { ISO_TYPED_STAGES } from "./stages.generated.js";
|
|
6
6
|
/**
|
|
@@ -232,6 +232,15 @@ class IsoBuilder {
|
|
|
232
232
|
}
|
|
233
233
|
buildStandard(treeIn) {
|
|
234
234
|
const tree = { ...treeIn };
|
|
235
|
+
// Historic TYPE-first ballot face ("ISO/IEC FDAM 1 14496-12:2004",
|
|
236
|
+
// "ISO/PDAM 19973-2", "ISO 15877-5:2009 FDAM 1"): the ballot_* keys
|
|
237
|
+
// are one amendment layer over the whole base, never a second
|
|
238
|
+
// supplement layer (the stored twins keep one level), so the layer
|
|
239
|
+
// is assembled here, before the supplement branch could read the
|
|
240
|
+
// ballot token as an outer wrapper.
|
|
241
|
+
if (tree["ballot_type_with_stage"] !== undefined) {
|
|
242
|
+
return this.buildBallotSupplement(tree);
|
|
243
|
+
}
|
|
235
244
|
// Legacy ISO/R: publisher ISO + type "R".
|
|
236
245
|
if (tree["iso_r_prefix"] !== undefined) {
|
|
237
246
|
tree["publisher"] = "ISO";
|
|
@@ -280,8 +289,63 @@ class IsoBuilder {
|
|
|
280
289
|
attrs["base"] = this.build(tree["base"]);
|
|
281
290
|
}
|
|
282
291
|
const identifier = new klass(attrs);
|
|
292
|
+
// The owner's no-number rule, applied on every construction path
|
|
293
|
+
// that routes through this builder (parse, URN, bundle members): a
|
|
294
|
+
// DAM-family ballot-stage amendment token with no number anywhere
|
|
295
|
+
// names Amendment 1 ("ISO 19973-2/PDAM", "ISO/IEC PDAM 12207"). The
|
|
296
|
+
// number is identity-bearing, so the default lands at build time and
|
|
297
|
+
// the wire hash serializes it — parse and fromHash(toHash) agree
|
|
298
|
+
// because both carry the filled number. The ballot stages are
|
|
299
|
+
// matched by the typed stage's code (the per-typed-stage key) —
|
|
300
|
+
// PDAM's stageCode is "cd", the harmonized range it lives in.
|
|
301
|
+
if (typeKey === "amd" && attrs["number"] === undefined &&
|
|
302
|
+
BALLOT_STAGE_CODES.includes(attrs["typedStageState"]?.entry.code ?? "")) {
|
|
303
|
+
identifier["number"] = "1";
|
|
304
|
+
}
|
|
283
305
|
return identifier;
|
|
284
306
|
}
|
|
307
|
+
/**
|
|
308
|
+
* Historic TYPE-first ballot face (owner ruling 2026-11-12, Option B
|
|
309
|
+
* decode-to-modern): "[P|F]?DAM [N] BASE [stamp]" decodes to ONE
|
|
310
|
+
* amendment over the WHOLE base, rendered as the canonical on-base
|
|
311
|
+
* slash face. The stage comes from the ballot token; the number from
|
|
312
|
+
* the TYPE token, then the on-base stamp, then the owner's no-number
|
|
313
|
+
* rule (a ballot face with no number anywhere names Amendment 1); the
|
|
314
|
+
* stamp's date is the ballot supplement's date. The base keeps every
|
|
315
|
+
* component it carried: a legacy slash-part stays a part of the base
|
|
316
|
+
* number ("ISO/IEC FPDAM 9075/1" → base "9075-1"), and the base's own
|
|
317
|
+
* type token stays the base's ("ISO/IEC PDAM TR 9573-11" → base
|
|
318
|
+
* "TR 9573-11") — nothing migrates into the supplement slot. The
|
|
319
|
+
* stamp's token letters (Amd/Am/…) are decode-away: the ballot's
|
|
320
|
+
* stage is the TYPE token's.
|
|
321
|
+
*/
|
|
322
|
+
buildBallotSupplement(tree) {
|
|
323
|
+
const fields = {
|
|
324
|
+
type_with_stage: s(tree["ballot_type_with_stage"]),
|
|
325
|
+
};
|
|
326
|
+
const number = s(tree["ballot_number"]) ??
|
|
327
|
+
s(tree["ballot_stamp_number"]) ??
|
|
328
|
+
s(tree["ballot_stamp_dot_number"]) ??
|
|
329
|
+
"1";
|
|
330
|
+
fields["number_with_part"] = number;
|
|
331
|
+
// The on-base stamp: its date (or undated marker) is the ballot
|
|
332
|
+
// supplement's; its number feeds the precedence above; its token
|
|
333
|
+
// letters were matched uncaptured and decode away.
|
|
334
|
+
const stampDate = s(tree["ballot_stamp_date"]);
|
|
335
|
+
if (stampDate !== undefined) {
|
|
336
|
+
const [year, month, day] = stampDate.split("-");
|
|
337
|
+
fields["date"] = new PubidDate({ year, month, day });
|
|
338
|
+
}
|
|
339
|
+
else if (tree["ballot_stamp_undated_marker"] !== undefined) {
|
|
340
|
+
fields["date"] = new PubidDate({ undated: true });
|
|
341
|
+
}
|
|
342
|
+
const rest = {};
|
|
343
|
+
for (const [key, value] of Object.entries(tree)) {
|
|
344
|
+
if (!key.startsWith("ballot_"))
|
|
345
|
+
rest[key] = value;
|
|
346
|
+
}
|
|
347
|
+
return this.build({ ...fields, base: rest });
|
|
348
|
+
}
|
|
285
349
|
buildDirectives(tree, state) {
|
|
286
350
|
const attrs = this.baseAttrs(tree);
|
|
287
351
|
const publisher = this.publisherOf(tree);
|
|
@@ -102,8 +102,14 @@ export class IsoIdentifier extends BaseIdentifier {
|
|
|
102
102
|
const ts = this.typedStageState;
|
|
103
103
|
if (ts === undefined)
|
|
104
104
|
return false;
|
|
105
|
-
if (ts.entry.longAbbr !== undefined && ts.originalAbbr
|
|
105
|
+
if (ts.entry.longAbbr !== undefined && ts.originalAbbr !== undefined &&
|
|
106
|
+
(ts.originalAbbr.startsWith(ts.entry.longAbbr) ||
|
|
107
|
+
// The shorter long-family spellings ("Am", the alias of "Amd"
|
|
108
|
+
// the owner ruled renders canonical) are prefixes of the long
|
|
109
|
+
// abbr; the short family ("AMD") matches neither direction.
|
|
110
|
+
ts.entry.longAbbr.startsWith(ts.originalAbbr))) {
|
|
106
111
|
return true;
|
|
112
|
+
}
|
|
107
113
|
if (ts.entry.longAbbr !== undefined && ts.originalAbbr?.includes("Directives"))
|
|
108
114
|
return true;
|
|
109
115
|
return false;
|
|
@@ -32,7 +32,7 @@ export const ISO_TYPED_STAGES = [
|
|
|
32
32
|
code: "prf_amd", stageCode: "prf", typeCode: "amd", abbr: ["PRF Amd"], harmonized: ["50.00"]
|
|
33
33
|
}),
|
|
34
34
|
TS("amd", {
|
|
35
|
-
code: "published", stageCode: "published", typeCode: "amd", abbr: ["Amd", "AMD", "Amd."], shortAbbr: "AMD", longAbbr: "Amd", harmonized: ["60.00", "60.60"]
|
|
35
|
+
code: "published", stageCode: "published", typeCode: "amd", abbr: ["Amd", "AMD", "Amd.", "Am"], shortAbbr: "AMD", longAbbr: "Amd", harmonized: ["60.00", "60.60"]
|
|
36
36
|
}),
|
|
37
37
|
TS("cor", {
|
|
38
38
|
code: "pwi_cor", stageCode: "proposal", typeCode: "cor", abbr: ["PWI Cor"], harmonized: ["00.00", "00.20", "00.60", "00.92", "00.93", "00.98", "00.99"]
|
|
@@ -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
|
}
|
|
@@ -709,8 +714,24 @@ function nistClass(spec) {
|
|
|
709
714
|
return `${this.publisher ?? "NIST"} ${this.date_year ?? ""}-${this.date_month ?? ""}-${this.date_day ?? ""} ${this.dated_seq ?? ""}`;
|
|
710
715
|
}
|
|
711
716
|
if (spec.style === "fips") {
|
|
712
|
-
|
|
713
|
-
|
|
717
|
+
// The official published face is "FIPS PUB <number>": FIPS is
|
|
718
|
+
// government-published and "PUB" (Federal Information Processing
|
|
719
|
+
// Standards PUBlication) is part of the official designation
|
|
720
|
+
// (owner ruling 2026-11-12). A spelled NIST publisher renders the
|
|
721
|
+
// official face; the historical NBS-prefixed rows keep
|
|
722
|
+
// "NBS FIPS <number>", and the bare publisher-less spelling keeps
|
|
723
|
+
// its short "FIPS <number>" face. The lead reads
|
|
724
|
+
// shortRenderPublisher() (the printed-publisher view), so a
|
|
725
|
+
// series-default publisher filled without being spelled (#704's
|
|
726
|
+
// ruby model) can never flip the bare face; the tail rides the
|
|
727
|
+
// lead.
|
|
728
|
+
const pub = this.shortRenderPublisher();
|
|
729
|
+
const series = this.seriesCode() ?? "";
|
|
730
|
+
let result = pub === "NIST"
|
|
731
|
+
? "FIPS PUB"
|
|
732
|
+
: pub !== undefined && pub !== ""
|
|
733
|
+
? `${pub} ${series}`
|
|
734
|
+
: series;
|
|
714
735
|
let numberPart = this.number ?? "";
|
|
715
736
|
const fy = /^(\d{1,3})-(\d{4})$/.exec(numberPart);
|
|
716
737
|
if (fy !== null) {
|
|
@@ -803,7 +824,17 @@ export class NistSupplementIdentifier extends NistIdentifier {
|
|
|
803
824
|
}
|
|
804
825
|
}
|
|
805
826
|
const TYPE_SPECS = [
|
|
806
|
-
{
|
|
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
|
+
},
|
|
807
838
|
{ kind: "federal-information-processing-standards", seriesCode: "FIPS", defaultPublisher: "", style: "fips" },
|
|
808
839
|
{ kind: "interagency-report", seriesCode: "IR", forceShort: true },
|
|
809
840
|
{ kind: "handbook", seriesCode: "HB" },
|
|
@@ -137,6 +137,17 @@ export function preprocessNist(input) {
|
|
|
137
137
|
cleaned = cleaned.replace(/^(NBS|NIST)(IR|FIPS|GCR|HB|MONO|MP|NCSTAR|NSRDS)/i, "$1 $2");
|
|
138
138
|
cleaned = cleaned.replace(/\b(ir|sp|tn|hb|fips|ams|vts)\b/i, (m) => m.toUpperCase());
|
|
139
139
|
cleaned = cleaned.replace(/\bLC\b(?!IRC)/g, "LCIRC");
|
|
140
|
+
// normalize_fips_pub_alias: the FIPS series' official printed face is
|
|
141
|
+
// "FIPS PUB <number>" — FIPS is government-published and "PUB" (Federal
|
|
142
|
+
// Information Processing Standards PUBlication) is part of the official
|
|
143
|
+
// designation — and the RENDERER emits that face directly (owner ruling
|
|
144
|
+
// 2026-11-12, mirroring the gem). The grammar reads the
|
|
145
|
+
// publisher-bearing spelling only through this fold (pubid#697): the
|
|
146
|
+
// printed spellings — "FIPS PUB 205" and the publisher-prefixed
|
|
147
|
+
// "NIST FIPS PUB 205" (pubid#702) — fold onto the one model "NIST FIPS
|
|
148
|
+
// <number>" the grammar already builds (same hash, same URN, same MR
|
|
149
|
+
// string). Anchored at the head; bare "FIPS" is untouched.
|
|
150
|
+
cleaned = cleaned.replace(/^(?:NIST )?FIPS PUB\b/i, "NIST FIPS");
|
|
140
151
|
// normalize_lcirc_supplement_contexts
|
|
141
152
|
cleaned = cleaned.replace(/\bNBS LCIRC\b(?=.*\b(?:supp?|sup\+|r\d+\/)\d)/, "NBS.LCIRC");
|
|
142
153
|
cleaned = cleaned.replace(/\bNBS\.LCIRC\.(\d+r\d+\/\d{4})/, "NBS LCIRC $1");
|
|
@@ -20,11 +20,17 @@ function buildRules() {
|
|
|
20
20
|
rule("edition_part", () => str("第").then(digits.then(str("."), digits).as("edition"), str("版")));
|
|
21
21
|
rule("edition_latin", () => digits.then(str("."), digits).as("edition"));
|
|
22
22
|
rule("edition", () => space.then(rules["edition_part"].or(rules["edition_latin"])));
|
|
23
|
+
// MLIT's volume label after the edition: 本編 (main volume) or
|
|
24
|
+
// 本編+付録 (main volume with appendix). ASCII or full-width (U+3000)
|
|
25
|
+
// space; ASCII "+" or full-width "+" (U+FF0B), which the builder
|
|
26
|
+
// normalizes to "+".
|
|
27
|
+
rule("volume_sep", () => str(" ").or(str(" ")));
|
|
28
|
+
rule("volume", () => rules["volume_sep"].then(str("本編").then(str("+").or(str("+")).then(str("付録")).maybe()).as("volume")));
|
|
23
29
|
rule("annex_supplement", () => space.then(str("Annex")).then(space, match("[A-Z]").as("annex_letter")));
|
|
24
30
|
rule("handbook", () => str("PLATEAU")
|
|
25
31
|
.then(space, rules["doc_type"], space, rules["number"])
|
|
26
32
|
.then(rules["annex"].maybe())
|
|
27
|
-
.then(rules["edition"].maybe()));
|
|
33
|
+
.then(rules["edition"].then(rules["volume"].maybe()).maybe()));
|
|
28
34
|
rule("identifier", () => rules["handbook"]
|
|
29
35
|
.then(rules["annex_supplement"])
|
|
30
36
|
.as("base")
|
|
@@ -42,14 +48,21 @@ function plateauClass(kind) {
|
|
|
42
48
|
number: { type: "integer" },
|
|
43
49
|
annex: { type: "integer" },
|
|
44
50
|
edition: { type: "string" },
|
|
51
|
+
// The volume label MLIT prints after the edition: "本編" (the main
|
|
52
|
+
// volume alone) or "本編+付録" (main volume and appendix, one
|
|
53
|
+
// PDF). A nil volume means the publication has no volume label:
|
|
54
|
+
// "#00 第5.0版" does not subsume "#00 第5.0版 本編+付録".
|
|
55
|
+
volume: { type: "string" },
|
|
45
56
|
});
|
|
46
|
-
static mappings = keyValue({ wire: "number", to: "number" }, { wire: "edition", to: "edition" }, { wire: "annex", to: "annex" });
|
|
57
|
+
static mappings = keyValue({ wire: "number", to: "number" }, { wire: "edition", to: "edition" }, { wire: "annex", to: "annex" }, { wire: "volume", to: "volume" });
|
|
47
58
|
render() {
|
|
48
59
|
let result = `PLATEAU ${isHandbook ? "Handbook" : "Technical Report"} #${pad2(this.number)}`;
|
|
49
60
|
if (this.annex !== undefined)
|
|
50
61
|
result += `-${this.annex}`;
|
|
51
62
|
if (isHandbook && this.edition !== undefined)
|
|
52
63
|
result += ` 第${this.edition}版`;
|
|
64
|
+
if (this.volume !== undefined)
|
|
65
|
+
result += ` ${this.volume}`;
|
|
53
66
|
return result;
|
|
54
67
|
}
|
|
55
68
|
}
|
|
@@ -91,6 +104,12 @@ export function plateauGrammarImplementation() {
|
|
|
91
104
|
if (data["edition"] !== undefined && data["edition"] !== null && kind === "handbook") {
|
|
92
105
|
attrs["edition"] = String(data["edition"]);
|
|
93
106
|
}
|
|
107
|
+
// The grammar reads a volume label only after an edition, on the
|
|
108
|
+
// Handbook; the builder normalizes the ASCII "+" to the
|
|
109
|
+
// full-width "+" (MLIT prints full-width).
|
|
110
|
+
if (data["volume"] !== undefined && data["volume"] !== null && kind === "handbook") {
|
|
111
|
+
attrs["volume"] = String(data["volume"]).replaceAll("+", "+");
|
|
112
|
+
}
|
|
94
113
|
return new KIND_CLASSES[kind](attrs);
|
|
95
114
|
},
|
|
96
115
|
};
|
|
@@ -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
|
+
});
|
|
@@ -15,6 +15,9 @@ export const ihoSchema = define("iho", (s) => {
|
|
|
15
15
|
s.atom("part", "part");
|
|
16
16
|
s.atom("part_edition", "parted");
|
|
17
17
|
s.atom("part_year", "party");
|
|
18
|
+
s.atom("spec", "spec");
|
|
19
|
+
s.atom("spec_sub", "specsub");
|
|
20
|
+
s.atom("spec_variant", "specvar");
|
|
18
21
|
s.atom("annex", "annex");
|
|
19
22
|
s.atom("annex_edition", "anned");
|
|
20
23
|
s.atom("annex_year", "annyear");
|
|
@@ -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,
|
|
@@ -10,6 +10,7 @@ export const plateauSchema = define("plateau", (s) => {
|
|
|
10
10
|
s.atom("publisher", "pub");
|
|
11
11
|
s.atom("edition", "ed");
|
|
12
12
|
s.atom("annex", "annex", "int");
|
|
13
|
+
s.atom("volume", "vol");
|
|
13
14
|
s.type("pubid:plateau:annex", "annex", {
|
|
14
15
|
core: [],
|
|
15
16
|
atoms: [["letter", "letter"]],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pubid/pubid",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.39",
|
|
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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"bindings":null,"version":"0.1.0","grammar":"PubidEtsiPfs","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Str":{"pattern":"ETSI "}},{"Entity":{"atom":18}},{"Str":{"pattern":"I-ETS"}},{"Str":{"pattern":"TCRTR"}},{"Str":{"pattern":"GTS"}},{"Str":{"pattern":"ETR"}},{"Str":{"pattern":"ETS"}},{"Str":{"pattern":"TBR"}},{"Str":{"pattern":"NET"}},{"Str":{"pattern":"EN"}},{"Str":{"pattern":"ES"}},{"Str":{"pattern":"EG"}},{"Str":{"pattern":"TS"}},{"Str":{"pattern":"GR"}},{"Str":{"pattern":"GS"}},{"Str":{"pattern":"SR"}},{"Str":{"pattern":"TR"}},{"Alternative":{"atoms":[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]}},{"Named":{"name":"type","atom":17}},{"Str":{"pattern":" "}},{"Entity":{"atom":54}},{"Str":{"pattern":"GSM"}},{"Str":{"pattern":" "}},{"Entity":{"atom":24}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":23,"min":1,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"."}},{"Entity":{"atom":24}},{"Repetition":{"atom":27,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[21,22,25,26,28]}},{"Entity":{"atom":24}},{"Repetition":{"atom":30,"min":1,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"."}},{"Entity":{"atom":24}},{"Repetition":{"atom":33,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[31,32,34]}},{"Entity":{"atom":40}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Alternative":{"atoms":[37,38,39]}},{"Repetition":{"atom":36,"min":1,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"-"}},{"Entity":{"atom":40}},{"Repetition":{"atom":43,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[42,44]}},{"Repetition":{"atom":45,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":" "}},{"Entity":{"atom":24}},{"Repetition":{"atom":48,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[41,46,47,49]}},{"Entity":{"atom":24}},{"Repetition":{"atom":51,"min":1,"max":null,"tag":"Repetition"}},{"Alternative":{"atoms":[29,35,50,52]}},{"Named":{"name":"number","atom":53}},{"Sequence":{"atoms":[0,1,19,20]}},{"Str":{"pattern":"ETSI "}},{"Entity":{"atom":18}},{"Str":{"pattern":" "}},{"Entity":{"atom":54}},{"Str":{"pattern":" "}},{"Entity":{"atom":64}},{"Entity":{"atom":24}},{"Repetition":{"atom":62,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"minor","atom":63}},{"Sequence":{"atoms":[60,61]}},{"Repetition":{"atom":65,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":73}},{"Str":{"pattern":"-"}},{"Entity":{"atom":40}},{"Repetition":{"atom":69,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[68,70]}},{"Repetition":{"atom":71,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"parts","atom":72}},{"Repetition":{"atom":67,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":83}},{"Str":{"pattern":"/A"}},{"Str":{"pattern":"/C"}},{"Alternative":{"atoms":[76,77]}},{"Entity":{"atom":24}},{"Repetition":{"atom":79,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[78,80]}},{"Repetition":{"atom":81,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"supplements","atom":82}},{"Repetition":{"atom":75,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":" V"}},{"Entity":{"atom":92}},{"Entity":{"atom":90}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Re":{"pattern":"[.]"}},{"Alternative":{"atoms":[88,89]}},{"Repetition":{"atom":87,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"version","atom":91}},{"Sequence":{"atoms":[85,86]}},{"Str":{"pattern":" ed."}},{"Entity":{"atom":98}},{"Entity":{"atom":24}},{"Repetition":{"atom":96,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"edition","atom":97}},{"Sequence":{"atoms":[94,95]}},{"Alternative":{"atoms":[93,99]}},{"Repetition":{"atom":100,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":" ("}},{"Entity":{"atom":106}},{"Entity":{"atom":24}},{"Repetition":{"atom":104,"min":4,"max":4,"tag":"Repetition"}},{"Named":{"name":"year","atom":105}},{"Str":{"pattern":"-"}},{"Entity":{"atom":111}},{"Entity":{"atom":24}},{"Repetition":{"atom":109,"min":2,"max":2,"tag":"Repetition"}},{"Named":{"name":"month","atom":110}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[102,103,107,108,112]}},{"Repetition":{"atom":113,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[56,57,58,59,66,74,84,101,114]}},{"Alternative":{"atoms":[55,115]}}],"root":116},"bindings":[{"capture":"type","path":"type","type":"string","card":null,"preprocess":null},{"capture":"number","path":"number","type":"string","card":null,"preprocess":null},{"capture":"minor","path":"minor","type":"string","card":null,"preprocess":null},{"capture":"parts","path":"parts","type":"string","card":null,"preprocess":null},{"capture":"supplements","path":"supplements","type":"string","card":null,"preprocess":null},{"capture":"version","path":"version","type":"string","card":null,"preprocess":null},{"capture":"edition","path":"edition","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}]}},"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":"ETSI EG 200 053 V1.5.1 (2004-06)","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI EN 300 175","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI EN 300 175-2","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI EN 300 019-1-0 V2.1.2 (2003-09)","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI TS 103 702","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI EG 201 880 V1.2.1","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI GTS GSM 02.01 V5.5.0 (1999-08)","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI GR NFV-EVE 008 V3.1.1 (2017-12)","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI I-ETS 300 003 ed.1 (1991-08)","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI ETR 108/A1 ed.1 (1995-08)","expect":{}},{"entry":"identifier","kind":"accept","input":"ETSI ETS 300 092-1/A1/C1 ed.1 (1994-04)","expect":{}},{"entry":"identifier","kind":"reject","input":"nonsense","expect":{}},{"entry":"identifier","kind":"reject","input":"ETSI","expect":{}},{"entry":"identifier","kind":"reject","input":"ETSI EN","expect":{}},{"entry":"identifier","kind":"reject","input":"ETSI XX 100","expect":{}},{"entry":"identifier","kind":"reject","input":"ETSI EN 300 175 V","expect":{}},{"entry":"identifier","kind":"reject","input":"ETSI EN 300 175 V1.2.x","expect":{}},{"entry":"identifier","kind":"reject","input":"ETSI EN 300 175 (","expect":{}},{"entry":"identifier","kind":"reject","input":"ETSI EN 300 175 (2004-6)","expect":{}},{"entry":"identifier","kind":"example","input":"ETSI EG 200 053 V1.5.1 (2004-06)","expect":{"type":"EG","number":"200 053","version":"1.5.1","year":"2004","month":"06"}},{"entry":"identifier","kind":"example","input":"ETSI EN 300 175","expect":{"type":"EN","number":"300 175"}},{"entry":"identifier","kind":"example","input":"ETSI EN 300 175-2","expect":{"type":"EN","number":"300 175","parts":"-2"}},{"entry":"identifier","kind":"example","input":"ETSI EN 300 019-1-0 V2.1.2 (2003-09)","expect":{"type":"EN","number":"300 019","parts":"-1-0","version":"2.1.2","year":"2003","month":"09"}},{"entry":"identifier","kind":"example","input":"ETSI TS 103 702","expect":{"type":"TS","number":"103 702"}},{"entry":"identifier","kind":"example","input":"ETSI EG 201 880 V1.2.1","expect":{"type":"EG","number":"201 880","version":"1.2.1"}},{"entry":"identifier","kind":"example","input":"ETSI GTS GSM 02.01 V5.5.0 (1999-08)","expect":{"type":"GTS","number":"GSM 02.01","version":"5.5.0","year":"1999","month":"08"}},{"entry":"identifier","kind":"example","input":"ETSI GR NFV-EVE 008 V3.1.1 (2017-12)","expect":{"type":"GR","number":"NFV-EVE 008","version":"3.1.1","year":"2017","month":"12"}},{"entry":"identifier","kind":"example","input":"ETSI I-ETS 300 003 ed.1 (1991-08)","expect":{"type":"I-ETS","number":"300 003","edition":"1","year":"1991","month":"08"}},{"entry":"identifier","kind":"example","input":"ETSI ETR 108/A1 ed.1 (1995-08)","expect":{"type":"ETR","number":"108","supplements":"/A1","edition":"1","year":"1995","month":"08"}},{"entry":"identifier","kind":"example","input":"ETSI ETS 300 092-1/A1/C1 ed.1 (1994-04)","expect":{"type":"ETS","number":"300 092","parts":"-1","supplements":"/A1/C1","edition":"1","year":"1994","month":"04"}}],"docs":{},"source":"# PFS-generated grammar — DO NOT EDIT BY HAND.\n# Source: definitions/etsi.pfs (pfs:1) sha256:9343088bf087b55ea790057e6be0bbebe2272407ee81f035b52e5f9a4d5c7b76\n# Compiler: pubid/grammar/pfs 0.1.0\n# Flavor key: etsi_pfs (grammar PubidEtsiPfs)\n# Regenerate: ruby scripts/pfs compile definitions/etsi.pfs --as etsi_pfs\n\ngrammar PubidEtsiPfs version \"0.1.0\" edition 2 {\n\n # Grammar fragments: named lexical terms declared under `grammar:`.\n digit = %x30-39\n alnum_char = %x41-5A / %x61-7A / %x30-39\n version_char = %x30-39 / %x2E\n\n # Fields: one capture rule per declared field; the whole pattern\n # is the capture.\n etsi_type = (\"I-ETS\" / \"TCRTR\" / \"GTS\" / \"ETR\" / \"ETS\" / \"TBR\" / \"NET\" / \"EN\" / \"ES\" / \"EG\" / \"TS\" / \"GR\" / \"GS\" / \"SR\" / \"TR\") as type\n etsi_number = ((\"GSM\" \" \" 1*digit \".\" 1*digit) / (1*digit \".\" 1*digit) / (1*alnum_char [(\"-\" 1*alnum_char)] \" \" 1*digit) / (1*digit)) as number\n etsi_minor = (1*digit) as minor\n etsi_parts = (1*(\"-\" 1*alnum_char)) as parts\n etsi_supplements = (1*((\"/A\" / \"/C\") 1*digit)) as supplements\n etsi_version = (1*version_char) as version\n etsi_edition = (1*digit) as edition\n etsi_year = (4digit) as year\n etsi_month = (2digit) as month\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 \"ETSI \" etsi_type \" \" etsi_number\n / \"ETSI \" etsi_type \" \" etsi_number [\" \" etsi_minor] [etsi_parts] [etsi_supplements] [( \" V\" etsi_version / \" ed.\" etsi_edition )] [\" (\" etsi_year \"-\" etsi_month \")\"]\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 type -> type (string)\n number -> number (string)\n minor -> minor (string)\n parts -> parts (string)\n supplements -> supplements (string)\n version -> version (string)\n edition -> edition (string)\n year -> year (string)\n month -> month (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 \"ETSI EG 200 053 V1.5.1 (2004-06)\"\n accept \"ETSI EN 300 175\"\n accept \"ETSI EN 300 175-2\"\n accept \"ETSI EN 300 019-1-0 V2.1.2 (2003-09)\"\n accept \"ETSI TS 103 702\"\n accept \"ETSI EG 201 880 V1.2.1\"\n accept \"ETSI GTS GSM 02.01 V5.5.0 (1999-08)\"\n accept \"ETSI GR NFV-EVE 008 V3.1.1 (2017-12)\"\n accept \"ETSI I-ETS 300 003 ed.1 (1991-08)\"\n accept \"ETSI ETR 108/A1 ed.1 (1995-08)\"\n accept \"ETSI ETS 300 092-1/A1/C1 ed.1 (1994-04)\"\n reject \"nonsense\"\n reject \"ETSI\"\n reject \"ETSI EN\"\n reject \"ETSI XX 100\"\n reject \"ETSI EN 300 175 V\"\n reject \"ETSI EN 300 175 V1.2.x\"\n reject \"ETSI EN 300 175 (\"\n reject \"ETSI EN 300 175 (2004-6)\"\n example \"ETSI EG 200 053 V1.5.1 (2004-06)\" { type: \"EG\" number: \"200 053\" version: \"1.5.1\" year: \"2004\" month: \"06\" }\n example \"ETSI EN 300 175\" { type: \"EN\" number: \"300 175\" }\n example \"ETSI EN 300 175-2\" { type: \"EN\" number: \"300 175\" parts: \"-2\" }\n example \"ETSI EN 300 019-1-0 V2.1.2 (2003-09)\" { type: \"EN\" number: \"300 019\" parts: \"-1-0\" version: \"2.1.2\" year: \"2003\" month: \"09\" }\n example \"ETSI TS 103 702\" { type: \"TS\" number: \"103 702\" }\n example \"ETSI EG 201 880 V1.2.1\" { type: \"EG\" number: \"201 880\" version: \"1.2.1\" }\n example \"ETSI GTS GSM 02.01 V5.5.0 (1999-08)\" { type: \"GTS\" number: \"GSM 02.01\" version: \"5.5.0\" year: \"1999\" month: \"08\" }\n example \"ETSI GR NFV-EVE 008 V3.1.1 (2017-12)\" { type: \"GR\" number: \"NFV-EVE 008\" version: \"3.1.1\" year: \"2017\" month: \"12\" }\n example \"ETSI I-ETS 300 003 ed.1 (1991-08)\" { type: \"I-ETS\" number: \"300 003\" edition: \"1\" year: \"1991\" month: \"08\" }\n example \"ETSI ETR 108/A1 ed.1 (1995-08)\" { type: \"ETR\" number: \"108\" supplements: \"/A1\" edition: \"1\" year: \"1995\" month: \"08\" }\n example \"ETSI ETS 300 092-1/A1/C1 ed.1 (1994-04)\" { type: \"ETS\" number: \"300 092\" parts: \"-1\" supplements: \"/A1/C1\" edition: \"1\" year: \"1994\" month: \"04\" }\n }\n}\n","source_hash":"f5e47bb403d9bff4737d8a200f08c71f8029df12f96c56e9774b722908bfa853","unicode_tables":"onigmo (Ruby 3.4.8)","compiler_version":"1.3.126","edition":2,"semantics_hash":"sha256:204a90b72aa2ea5fc2249622bd61c052b4ba5d1ebf732a2c2b57669c8de24393","checksum":"sha256:d861e040f36868dcef43c6547c5791979d4832d1ec1ca6bc310bdad82ea0e930"}
|