keepset 0.25.0 → 0.26.0
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/dist/{bundled-Dkvod55t.js → bundled-V1EJ0k9e.js} +210 -11
- package/dist/{categories-zC2eMs6y.d.ts → categories-HeWbVPhc.d.ts} +33 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/node/fetch-dataset.d.ts +1 -1
- package/dist/node/fetch-dataset.js +256 -50
- package/dist-cli/keepset.mjs +1 -1
- package/package.json +1 -1
- package/schemas/entry.schema.json +1 -1
- package/schemas/manifest.schema.json +1 -1
|
@@ -529,6 +529,10 @@ const ParserSchema = z.discriminatedUnion("format", [
|
|
|
529
529
|
format: z.literal("toptw"),
|
|
530
530
|
encoding: EncodingSchema
|
|
531
531
|
}).strict(),
|
|
532
|
+
z.object({
|
|
533
|
+
format: z.literal("tsplib"),
|
|
534
|
+
encoding: EncodingSchema
|
|
535
|
+
}).strict(),
|
|
532
536
|
z.object({
|
|
533
537
|
format: z.literal("csv-table"),
|
|
534
538
|
encoding: EncodingSchema,
|
|
@@ -988,7 +992,7 @@ var catalogue_default = {
|
|
|
988
992
|
"id": "keepset",
|
|
989
993
|
"name": "keepset",
|
|
990
994
|
"description": "The keepset catalogue: datasets with machine-readable recipes that fetch each one and normalise it into its category's target shape.",
|
|
991
|
-
"version": "1.
|
|
995
|
+
"version": "1.14.0",
|
|
992
996
|
"repository": "https://github.com/Mearman/keepset",
|
|
993
997
|
"namespaceAliases": {
|
|
994
998
|
"networkrepository": ["nr"],
|
|
@@ -56309,20 +56313,119 @@ var catalogue_default = {
|
|
|
56309
56313
|
"territory",
|
|
56310
56314
|
"travelTime"
|
|
56311
56315
|
],
|
|
56312
|
-
"category": "or/v1",
|
|
56316
|
+
"category": "or-set/v1",
|
|
56313
56317
|
"sources": [{
|
|
56314
56318
|
"url": "http://www.vrp-rep.org/datasets/download/angelelli-et-al-2014.zip",
|
|
56315
56319
|
"retrieved": "2026-10-19",
|
|
56316
56320
|
"status": "live"
|
|
56321
|
+
}, {
|
|
56322
|
+
"url": "https://www.vrp-rep.org/datasets/download/angelelli-et-al-2014.zip",
|
|
56323
|
+
"retrieved": "2026-10-19",
|
|
56324
|
+
"status": "live"
|
|
56317
56325
|
}],
|
|
56318
56326
|
"licence": { "kind": "unrecorded" },
|
|
56319
56327
|
"citations": [],
|
|
56320
56328
|
"recipe": {
|
|
56321
|
-
"status": "
|
|
56322
|
-
"
|
|
56329
|
+
"status": "fetchable",
|
|
56330
|
+
"source": 1,
|
|
56331
|
+
"archive": {
|
|
56332
|
+
"kind": "zip",
|
|
56333
|
+
"members": { "extensions": [".cop"] }
|
|
56334
|
+
},
|
|
56335
|
+
"parser": {
|
|
56336
|
+
"format": "tsplib",
|
|
56337
|
+
"encoding": "utf-8"
|
|
56338
|
+
}
|
|
56323
56339
|
},
|
|
56324
|
-
"crosswalk": {
|
|
56325
|
-
|
|
56340
|
+
"crosswalk": {
|
|
56341
|
+
"source": "tsplib",
|
|
56342
|
+
"target": "or-set/v1",
|
|
56343
|
+
"rules": [
|
|
56344
|
+
{
|
|
56345
|
+
"op": "move",
|
|
56346
|
+
"from": "meta",
|
|
56347
|
+
"to": "meta"
|
|
56348
|
+
},
|
|
56349
|
+
{
|
|
56350
|
+
"op": "move",
|
|
56351
|
+
"from": "members[].id",
|
|
56352
|
+
"to": "instances[].id"
|
|
56353
|
+
},
|
|
56354
|
+
{
|
|
56355
|
+
"op": "move",
|
|
56356
|
+
"from": "members[].meta.name",
|
|
56357
|
+
"to": "instances[].meta.name"
|
|
56358
|
+
},
|
|
56359
|
+
{
|
|
56360
|
+
"op": "move",
|
|
56361
|
+
"from": "members[].meta.type",
|
|
56362
|
+
"to": "instances[].meta.type"
|
|
56363
|
+
},
|
|
56364
|
+
{
|
|
56365
|
+
"op": "move",
|
|
56366
|
+
"from": "members[].meta.budget",
|
|
56367
|
+
"to": "instances[].meta.budget"
|
|
56368
|
+
},
|
|
56369
|
+
{
|
|
56370
|
+
"op": "move",
|
|
56371
|
+
"from": "members[].meta.edgeWeightType",
|
|
56372
|
+
"to": "instances[].meta.edgeWeightType"
|
|
56373
|
+
},
|
|
56374
|
+
{
|
|
56375
|
+
"op": "move",
|
|
56376
|
+
"from": "members[].meta.setPrizes",
|
|
56377
|
+
"to": "instances[].meta.setPrizes"
|
|
56378
|
+
},
|
|
56379
|
+
{
|
|
56380
|
+
"op": "move",
|
|
56381
|
+
"from": "members[].nodes[].id",
|
|
56382
|
+
"to": "instances[].nodes[].id"
|
|
56383
|
+
},
|
|
56384
|
+
{
|
|
56385
|
+
"op": "move",
|
|
56386
|
+
"from": "members[].nodes[].lat",
|
|
56387
|
+
"to": "instances[].nodes[].lat"
|
|
56388
|
+
},
|
|
56389
|
+
{
|
|
56390
|
+
"op": "move",
|
|
56391
|
+
"from": "members[].nodes[].lon",
|
|
56392
|
+
"to": "instances[].nodes[].lon"
|
|
56393
|
+
},
|
|
56394
|
+
{
|
|
56395
|
+
"op": "move",
|
|
56396
|
+
"from": "members[].nodes[].x",
|
|
56397
|
+
"to": "instances[].nodes[].x"
|
|
56398
|
+
},
|
|
56399
|
+
{
|
|
56400
|
+
"op": "move",
|
|
56401
|
+
"from": "members[].nodes[].y",
|
|
56402
|
+
"to": "instances[].nodes[].y"
|
|
56403
|
+
},
|
|
56404
|
+
{
|
|
56405
|
+
"op": "move",
|
|
56406
|
+
"from": "members[].nodes[].clusters",
|
|
56407
|
+
"to": "instances[].nodes[].clusters"
|
|
56408
|
+
}
|
|
56409
|
+
],
|
|
56410
|
+
"oneWay": [
|
|
56411
|
+
{
|
|
56412
|
+
"op": "drop",
|
|
56413
|
+
"from": "members[].meta.totalPrize",
|
|
56414
|
+
"direction": "encode"
|
|
56415
|
+
},
|
|
56416
|
+
{
|
|
56417
|
+
"op": "drop",
|
|
56418
|
+
"from": "members[].nodes[].prize",
|
|
56419
|
+
"direction": "encode"
|
|
56420
|
+
},
|
|
56421
|
+
{
|
|
56422
|
+
"op": "drop",
|
|
56423
|
+
"from": "members[].nodes[].probability",
|
|
56424
|
+
"direction": "encode"
|
|
56425
|
+
}
|
|
56426
|
+
]
|
|
56427
|
+
},
|
|
56428
|
+
"expectedCounts": { "instances": 924 },
|
|
56326
56429
|
"properties": { "surveyId": "or-4" }
|
|
56327
56430
|
},
|
|
56328
56431
|
{
|
|
@@ -56365,20 +56468,116 @@ var catalogue_default = {
|
|
|
56365
56468
|
"location",
|
|
56366
56469
|
"travelTime"
|
|
56367
56470
|
],
|
|
56368
|
-
"category": "or/v1",
|
|
56471
|
+
"category": "or-set/v1",
|
|
56369
56472
|
"sources": [{
|
|
56370
56473
|
"url": "http://www.vrp-rep.org/datasets/download/angelelli-et-al-2017.zip",
|
|
56371
56474
|
"retrieved": "2026-10-19",
|
|
56372
56475
|
"status": "live"
|
|
56476
|
+
}, {
|
|
56477
|
+
"url": "https://www.vrp-rep.org/datasets/download/angelelli-et-al-2017.zip",
|
|
56478
|
+
"retrieved": "2026-10-19",
|
|
56479
|
+
"status": "live"
|
|
56373
56480
|
}],
|
|
56374
56481
|
"licence": { "kind": "unrecorded" },
|
|
56375
56482
|
"citations": [],
|
|
56376
56483
|
"recipe": {
|
|
56377
|
-
"status": "
|
|
56378
|
-
"
|
|
56484
|
+
"status": "fetchable",
|
|
56485
|
+
"source": 1,
|
|
56486
|
+
"archive": {
|
|
56487
|
+
"kind": "zip",
|
|
56488
|
+
"members": { "extensions": [".pop"] }
|
|
56489
|
+
},
|
|
56490
|
+
"parser": {
|
|
56491
|
+
"format": "tsplib",
|
|
56492
|
+
"encoding": "utf-8"
|
|
56493
|
+
}
|
|
56379
56494
|
},
|
|
56380
|
-
"crosswalk": {
|
|
56381
|
-
|
|
56495
|
+
"crosswalk": {
|
|
56496
|
+
"source": "tsplib",
|
|
56497
|
+
"target": "or-set/v1",
|
|
56498
|
+
"rules": [
|
|
56499
|
+
{
|
|
56500
|
+
"op": "move",
|
|
56501
|
+
"from": "meta",
|
|
56502
|
+
"to": "meta"
|
|
56503
|
+
},
|
|
56504
|
+
{
|
|
56505
|
+
"op": "move",
|
|
56506
|
+
"from": "members[].id",
|
|
56507
|
+
"to": "instances[].id"
|
|
56508
|
+
},
|
|
56509
|
+
{
|
|
56510
|
+
"op": "move",
|
|
56511
|
+
"from": "members[].meta.name",
|
|
56512
|
+
"to": "instances[].meta.name"
|
|
56513
|
+
},
|
|
56514
|
+
{
|
|
56515
|
+
"op": "move",
|
|
56516
|
+
"from": "members[].meta.type",
|
|
56517
|
+
"to": "instances[].meta.type"
|
|
56518
|
+
},
|
|
56519
|
+
{
|
|
56520
|
+
"op": "move",
|
|
56521
|
+
"from": "members[].meta.budget",
|
|
56522
|
+
"to": "instances[].meta.budget"
|
|
56523
|
+
},
|
|
56524
|
+
{
|
|
56525
|
+
"op": "move",
|
|
56526
|
+
"from": "members[].meta.edgeWeightType",
|
|
56527
|
+
"to": "instances[].meta.edgeWeightType"
|
|
56528
|
+
},
|
|
56529
|
+
{
|
|
56530
|
+
"op": "move",
|
|
56531
|
+
"from": "members[].meta.totalPrize",
|
|
56532
|
+
"to": "instances[].meta.totalPrize"
|
|
56533
|
+
},
|
|
56534
|
+
{
|
|
56535
|
+
"op": "move",
|
|
56536
|
+
"from": "members[].nodes[].id",
|
|
56537
|
+
"to": "instances[].nodes[].id"
|
|
56538
|
+
},
|
|
56539
|
+
{
|
|
56540
|
+
"op": "move",
|
|
56541
|
+
"from": "members[].nodes[].lat",
|
|
56542
|
+
"to": "instances[].nodes[].lat"
|
|
56543
|
+
},
|
|
56544
|
+
{
|
|
56545
|
+
"op": "move",
|
|
56546
|
+
"from": "members[].nodes[].lon",
|
|
56547
|
+
"to": "instances[].nodes[].lon"
|
|
56548
|
+
},
|
|
56549
|
+
{
|
|
56550
|
+
"op": "move",
|
|
56551
|
+
"from": "members[].nodes[].prize",
|
|
56552
|
+
"to": "instances[].nodes[].prize"
|
|
56553
|
+
},
|
|
56554
|
+
{
|
|
56555
|
+
"op": "move",
|
|
56556
|
+
"from": "members[].nodes[].probability",
|
|
56557
|
+
"to": "instances[].nodes[].prizeProbability"
|
|
56558
|
+
},
|
|
56559
|
+
{
|
|
56560
|
+
"op": "move",
|
|
56561
|
+
"from": "members[].nodes[].x",
|
|
56562
|
+
"to": "instances[].nodes[].x"
|
|
56563
|
+
},
|
|
56564
|
+
{
|
|
56565
|
+
"op": "move",
|
|
56566
|
+
"from": "members[].nodes[].y",
|
|
56567
|
+
"to": "instances[].nodes[].y"
|
|
56568
|
+
}
|
|
56569
|
+
],
|
|
56570
|
+
"oneWay": [{
|
|
56571
|
+
"op": "drop",
|
|
56572
|
+
"from": "members[].meta.setPrizes",
|
|
56573
|
+
"direction": "encode"
|
|
56574
|
+
}, {
|
|
56575
|
+
"op": "drop",
|
|
56576
|
+
"from": "members[].nodes[].clusters",
|
|
56577
|
+
"direction": "encode"
|
|
56578
|
+
}]
|
|
56579
|
+
},
|
|
56580
|
+
"expectedCounts": { "instances": 264 },
|
|
56382
56581
|
"properties": { "surveyId": "or-3" }
|
|
56383
56582
|
},
|
|
56384
56583
|
{
|
|
@@ -158,6 +158,12 @@ declare const ParserSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
158
158
|
"utf-8": "utf-8";
|
|
159
159
|
latin1: "latin1";
|
|
160
160
|
}>;
|
|
161
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
162
|
+
format: z.ZodLiteral<"tsplib">;
|
|
163
|
+
encoding: z.ZodEnum<{
|
|
164
|
+
"utf-8": "utf-8";
|
|
165
|
+
latin1: "latin1";
|
|
166
|
+
}>;
|
|
161
167
|
}, z.core.$strict>, z.ZodObject<{
|
|
162
168
|
format: z.ZodLiteral<"csv-table">;
|
|
163
169
|
encoding: z.ZodEnum<{
|
|
@@ -289,6 +295,12 @@ declare const RecipeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
289
295
|
"utf-8": "utf-8";
|
|
290
296
|
latin1: "latin1";
|
|
291
297
|
}>;
|
|
298
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
299
|
+
format: z.ZodLiteral<"tsplib">;
|
|
300
|
+
encoding: z.ZodEnum<{
|
|
301
|
+
"utf-8": "utf-8";
|
|
302
|
+
latin1: "latin1";
|
|
303
|
+
}>;
|
|
292
304
|
}, z.core.$strict>, z.ZodObject<{
|
|
293
305
|
format: z.ZodLiteral<"csv-table">;
|
|
294
306
|
encoding: z.ZodEnum<{
|
|
@@ -475,6 +487,12 @@ declare const EntrySchema: z.ZodObject<{
|
|
|
475
487
|
"utf-8": "utf-8";
|
|
476
488
|
latin1: "latin1";
|
|
477
489
|
}>;
|
|
490
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
491
|
+
format: z.ZodLiteral<"tsplib">;
|
|
492
|
+
encoding: z.ZodEnum<{
|
|
493
|
+
"utf-8": "utf-8";
|
|
494
|
+
latin1: "latin1";
|
|
495
|
+
}>;
|
|
478
496
|
}, z.core.$strict>, z.ZodObject<{
|
|
479
497
|
format: z.ZodLiteral<"csv-table">;
|
|
480
498
|
encoding: z.ZodEnum<{
|
|
@@ -619,6 +637,9 @@ declare const EntrySchema: z.ZodObject<{
|
|
|
619
637
|
} | {
|
|
620
638
|
format: "toptw";
|
|
621
639
|
encoding: "utf-8" | "latin1";
|
|
640
|
+
} | {
|
|
641
|
+
format: "tsplib";
|
|
642
|
+
encoding: "utf-8" | "latin1";
|
|
622
643
|
};
|
|
623
644
|
paging?: {
|
|
624
645
|
kind: "arcgis-query";
|
|
@@ -880,6 +901,12 @@ declare const CatalogueIndexSchema: z.ZodObject<{
|
|
|
880
901
|
"utf-8": "utf-8";
|
|
881
902
|
latin1: "latin1";
|
|
882
903
|
}>;
|
|
904
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
905
|
+
format: z.ZodLiteral<"tsplib">;
|
|
906
|
+
encoding: z.ZodEnum<{
|
|
907
|
+
"utf-8": "utf-8";
|
|
908
|
+
latin1: "latin1";
|
|
909
|
+
}>;
|
|
883
910
|
}, z.core.$strict>, z.ZodObject<{
|
|
884
911
|
format: z.ZodLiteral<"csv-table">;
|
|
885
912
|
encoding: z.ZodEnum<{
|
|
@@ -1024,6 +1051,9 @@ declare const CatalogueIndexSchema: z.ZodObject<{
|
|
|
1024
1051
|
} | {
|
|
1025
1052
|
format: "toptw";
|
|
1026
1053
|
encoding: "utf-8" | "latin1";
|
|
1054
|
+
} | {
|
|
1055
|
+
format: "tsplib";
|
|
1056
|
+
encoding: "utf-8" | "latin1";
|
|
1027
1057
|
};
|
|
1028
1058
|
paging?: {
|
|
1029
1059
|
kind: "arcgis-query";
|
|
@@ -1171,6 +1201,9 @@ declare const CatalogueIndexSchema: z.ZodObject<{
|
|
|
1171
1201
|
} | {
|
|
1172
1202
|
format: "toptw";
|
|
1173
1203
|
encoding: "utf-8" | "latin1";
|
|
1204
|
+
} | {
|
|
1205
|
+
format: "tsplib";
|
|
1206
|
+
encoding: "utf-8" | "latin1";
|
|
1174
1207
|
};
|
|
1175
1208
|
paging?: {
|
|
1176
1209
|
kind: "arcgis-query";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as Parser, A as LineageSchema, B as Citation, C as CatalogueIndex, D as NamespaceNode, E as DatasetQuery, F as AliasSchema, G as Entry, H as ColumnNameSchema, I as Archive, J as IdSchema, K as EntrySchema, L as ArchiveMember, M as ManifestSchema, N as SemVerSchema, O as createCatalogue, P as parseManifest, Q as NamespaceSchema, R as ArchiveMemberSchema, S as Catalogue, T as Dataset, U as CrosswalkReference, V as CitationSchema, W as CrosswalkReferenceSchema, X as LicenceSchema, Y as Licence, Z as Namespace, _ as GraphEdgeSchema, a as CategoryTargets, at as Snapshot, b as GraphV1, c as getCategory, ct as SourceSchema, d as listCategories, dt as waybackUrl, et as ParserSchema, f as OrNode, g as GraphEdge, h as OrV1Schema, i as CategoryTarget, it as RelativePathSchema, j as Manifest, k as Lineage, l as getTarget, lt as WaybackTimestampSchema, m as OrV1, n as CategoryId, nt as Recipe, o as CountedKey, ot as SnapshotSchema, p as OrNodeSchema, q as HttpUrlSchema, r as CategoryIdSchema, rt as RecipeSchema, s as countTarget, st as Source, t as Category, tt as RESERVED_META_KEYS, u as kindOf, ut as parseEntry, v as GraphNode, w as CatalogueIndexSchema, x as GraphV1Schema, y as GraphNodeSchema, z as ArchiveSchema } from "./categories-
|
|
1
|
+
import { $ as Parser, A as LineageSchema, B as Citation, C as CatalogueIndex, D as NamespaceNode, E as DatasetQuery, F as AliasSchema, G as Entry, H as ColumnNameSchema, I as Archive, J as IdSchema, K as EntrySchema, L as ArchiveMember, M as ManifestSchema, N as SemVerSchema, O as createCatalogue, P as parseManifest, Q as NamespaceSchema, R as ArchiveMemberSchema, S as Catalogue, T as Dataset, U as CrosswalkReference, V as CitationSchema, W as CrosswalkReferenceSchema, X as LicenceSchema, Y as Licence, Z as Namespace, _ as GraphEdgeSchema, a as CategoryTargets, at as Snapshot, b as GraphV1, c as getCategory, ct as SourceSchema, d as listCategories, dt as waybackUrl, et as ParserSchema, f as OrNode, g as GraphEdge, h as OrV1Schema, i as CategoryTarget, it as RelativePathSchema, j as Manifest, k as Lineage, l as getTarget, lt as WaybackTimestampSchema, m as OrV1, n as CategoryId, nt as Recipe, o as CountedKey, ot as SnapshotSchema, p as OrNodeSchema, q as HttpUrlSchema, r as CategoryIdSchema, rt as RecipeSchema, s as countTarget, st as Source, t as Category, tt as RESERVED_META_KEYS, u as kindOf, ut as parseEntry, v as GraphNode, w as CatalogueIndexSchema, x as GraphV1Schema, y as GraphNodeSchema, z as ArchiveSchema } from "./categories-HeWbVPhc.js";
|
|
2
2
|
import { Crosswalk } from "twindex";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
//#region src/errors.d.ts
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as NativeParseError, A as toIssues, B as kindOf, C as RESERVED_META_KEYS, D as SourceSchema, E as SnapshotSchema, G as GraphNodeSchema, H as OrNodeSchema, I as CategoryIdSchema, J as ArchiveError, K as GraphV1Schema, L as countTarget, M as NAME_SEPARATOR, N as groupsOf, O as WaybackTimestampSchema, P as namesOf, Q as KeepsetError, R as getCategory, S as ParserSchema, T as RelativePathSchema, U as OrV1Schema, V as listCategories, W as GraphEdgeSchema, X as DatasetAmbiguousError, Y as CatalogueSyntaxError, Z as DatasetNotFoundError, _ as EntrySchema, a as CatalogueIndexSchema, b as LicenceSchema, c as ManifestSchema, d as AliasSchema, et as RecipeError, f as ArchiveMemberSchema, g as CrosswalkReferenceSchema, h as ColumnNameSchema, i as listNamespaces, j as waybackUrl, k as parseEntry, l as SemVerSchema, m as CitationSchema, n as getManifest, o as createCatalogue, p as ArchiveSchema, q as JsonScalarSchema, r as listDatasets, s as LineageSchema, t as getDataset, tt as UnknownCategoryError, u as parseManifest, v as HttpUrlSchema, w as RecipeSchema, x as NamespaceSchema, y as IdSchema, z as getTarget } from "./bundled-
|
|
1
|
+
import { $ as NativeParseError, A as toIssues, B as kindOf, C as RESERVED_META_KEYS, D as SourceSchema, E as SnapshotSchema, G as GraphNodeSchema, H as OrNodeSchema, I as CategoryIdSchema, J as ArchiveError, K as GraphV1Schema, L as countTarget, M as NAME_SEPARATOR, N as groupsOf, O as WaybackTimestampSchema, P as namesOf, Q as KeepsetError, R as getCategory, S as ParserSchema, T as RelativePathSchema, U as OrV1Schema, V as listCategories, W as GraphEdgeSchema, X as DatasetAmbiguousError, Y as CatalogueSyntaxError, Z as DatasetNotFoundError, _ as EntrySchema, a as CatalogueIndexSchema, b as LicenceSchema, c as ManifestSchema, d as AliasSchema, et as RecipeError, f as ArchiveMemberSchema, g as CrosswalkReferenceSchema, h as ColumnNameSchema, i as listNamespaces, j as waybackUrl, k as parseEntry, l as SemVerSchema, m as CitationSchema, n as getManifest, o as createCatalogue, p as ArchiveSchema, q as JsonScalarSchema, r as listDatasets, s as LineageSchema, t as getDataset, tt as UnknownCategoryError, u as parseManifest, v as HttpUrlSchema, w as RecipeSchema, x as NamespaceSchema, y as IdSchema, z as getTarget } from "./bundled-V1EJ0k9e.js";
|
|
2
2
|
import { validateCrosswalk } from "twindex";
|
|
3
3
|
//#region src/serialise.ts
|
|
4
4
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { G as Entry, T as Dataset, at as Snapshot, i as CategoryTarget, st as Source } from "../categories-
|
|
1
|
+
import { G as Entry, T as Dataset, at as Snapshot, i as CategoryTarget, st as Source } from "../categories-HeWbVPhc.js";
|
|
2
2
|
//#region src/node/fetch-dataset.d.ts
|
|
3
3
|
/** The network port a recipe downloads through: `downloadRaw` by default, which returns the bytes exactly as served, or a stand-in under test. */
|
|
4
4
|
export type FetchPort = (url: string, init: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as NativeParseError, F as getOwn, J as ArchiveError, L as countTarget, Q as KeepsetError, et as RecipeError, t as getDataset, z as getTarget } from "../bundled-
|
|
1
|
+
import { $ as NativeParseError, F as getOwn, J as ArchiveError, L as countTarget, Q as KeepsetError, et as RecipeError, t as getDataset, z as getTarget } from "../bundled-V1EJ0k9e.js";
|
|
2
2
|
import { RoundTripMismatchError, assertRoundTrip, encode } from "twindex";
|
|
3
3
|
import { z } from "zod";
|
|
4
4
|
import { createHash } from "node:crypto";
|
|
@@ -104,7 +104,7 @@ function parseEdgeList(text, options) {
|
|
|
104
104
|
//#endregion
|
|
105
105
|
//#region src/parsers/gml.ts
|
|
106
106
|
const KEY = /[A-Za-z_][A-Za-z0-9_]*/y;
|
|
107
|
-
const NUMBER$
|
|
107
|
+
const NUMBER$4 = /[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?/y;
|
|
108
108
|
/**
|
|
109
109
|
* Matches a sticky pattern at a position.
|
|
110
110
|
* @param pattern - A sticky regular expression.
|
|
@@ -155,7 +155,7 @@ function tokenise(text) {
|
|
|
155
155
|
position = end + 1;
|
|
156
156
|
} else {
|
|
157
157
|
const key = matchAt(KEY, text, position);
|
|
158
|
-
const number = key === void 0 ? matchAt(NUMBER$
|
|
158
|
+
const number = key === void 0 ? matchAt(NUMBER$4, text, position) : void 0;
|
|
159
159
|
const match = key ?? number;
|
|
160
160
|
if (match === void 0) throw new NativeParseError("gml", line, `unexpected character ${JSON.stringify(char)}`);
|
|
161
161
|
tokens.push({
|
|
@@ -833,9 +833,9 @@ function parsePajek(text) {
|
|
|
833
833
|
}
|
|
834
834
|
//#endregion
|
|
835
835
|
//#region src/parsers/solomon.ts
|
|
836
|
-
const FORMAT$
|
|
836
|
+
const FORMAT$3 = "solomon";
|
|
837
837
|
/** A line of integers or decimals separated by any run of spaces and tabs, as the files write rows (Solomon's with padded spaces, the Tenerife set with tabs). */
|
|
838
|
-
const NUMBER$
|
|
838
|
+
const NUMBER$3 = /^-?\d+(?:\.\d+)?$/;
|
|
839
839
|
/**
|
|
840
840
|
* Reads a token as a finite number.
|
|
841
841
|
* @param token - The token.
|
|
@@ -844,8 +844,8 @@ const NUMBER$2 = /^-?\d+(?:\.\d+)?$/;
|
|
|
844
844
|
* @returns The number.
|
|
845
845
|
* @throws NativeParseError when the token is not a decimal number.
|
|
846
846
|
*/
|
|
847
|
-
function numberOf$
|
|
848
|
-
if (!NUMBER$
|
|
847
|
+
function numberOf$2(token, line, what) {
|
|
848
|
+
if (!NUMBER$3.test(token)) throw new NativeParseError(FORMAT$3, line, `expected ${what}, found ${JSON.stringify(token)}`);
|
|
849
849
|
return Number(token);
|
|
850
850
|
}
|
|
851
851
|
/**
|
|
@@ -858,7 +858,7 @@ function parseSolomon(text) {
|
|
|
858
858
|
const all = lines(text);
|
|
859
859
|
const present = (index) => (all[index] ?? "").trim();
|
|
860
860
|
const name = present(0);
|
|
861
|
-
if (name === "") throw new NativeParseError(FORMAT$
|
|
861
|
+
if (name === "") throw new NativeParseError(FORMAT$3, 1, "expected the instance name on the first line");
|
|
862
862
|
const meta = { name };
|
|
863
863
|
const nodes = [];
|
|
864
864
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -874,7 +874,7 @@ function parseSolomon(text) {
|
|
|
874
874
|
awaitingHeader = true;
|
|
875
875
|
continue;
|
|
876
876
|
}
|
|
877
|
-
if (section === "preamble") throw new NativeParseError(FORMAT$
|
|
877
|
+
if (section === "preamble") throw new NativeParseError(FORMAT$3, line, `expected VEHICLE or CUSTOMER, found ${JSON.stringify(trimmed)}`);
|
|
878
878
|
if (awaitingHeader) {
|
|
879
879
|
awaitingHeader = false;
|
|
880
880
|
continue;
|
|
@@ -882,29 +882,29 @@ function parseSolomon(text) {
|
|
|
882
882
|
const tokens = trimmed.split(/\s+/);
|
|
883
883
|
if (section === "vehicle") {
|
|
884
884
|
const [vehicles, capacity, ...extra] = tokens;
|
|
885
|
-
if (vehicles === void 0 || capacity === void 0 || extra.length > 0) throw new NativeParseError(FORMAT$
|
|
886
|
-
meta.vehicles = numberOf$
|
|
887
|
-
meta.capacity = numberOf$
|
|
885
|
+
if (vehicles === void 0 || capacity === void 0 || extra.length > 0) throw new NativeParseError(FORMAT$3, line, `expected the vehicle count and capacity, found ${JSON.stringify(trimmed)}`);
|
|
886
|
+
meta.vehicles = numberOf$2(vehicles, line, "the vehicle count");
|
|
887
|
+
meta.capacity = numberOf$2(capacity, line, "the vehicle capacity");
|
|
888
888
|
continue;
|
|
889
889
|
}
|
|
890
890
|
const [id, x, y, demand, ready, due, service, ...extra] = tokens;
|
|
891
|
-
if (id === void 0 || x === void 0 || y === void 0 || demand === void 0 || ready === void 0 || due === void 0 || service === void 0 || extra.length > 0) throw new NativeParseError(FORMAT$
|
|
892
|
-
if (!/^\d+$/.test(id)) throw new NativeParseError(FORMAT$
|
|
893
|
-
if (seen.has(id)) throw new NativeParseError(FORMAT$
|
|
891
|
+
if (id === void 0 || x === void 0 || y === void 0 || demand === void 0 || ready === void 0 || due === void 0 || service === void 0 || extra.length > 0) throw new NativeParseError(FORMAT$3, line, `expected seven numbers (id, x, y, demand, ready, due, service), found ${JSON.stringify(trimmed)}`);
|
|
892
|
+
if (!/^\d+$/.test(id)) throw new NativeParseError(FORMAT$3, line, `expected a whole number node id, found ${JSON.stringify(id)}`);
|
|
893
|
+
if (seen.has(id)) throw new NativeParseError(FORMAT$3, line, `node ${id} appears twice`);
|
|
894
894
|
seen.add(id);
|
|
895
895
|
nodes.push({
|
|
896
896
|
id,
|
|
897
|
-
x: numberOf$
|
|
898
|
-
y: numberOf$
|
|
899
|
-
demand: numberOf$
|
|
900
|
-
ready: numberOf$
|
|
901
|
-
due: numberOf$
|
|
902
|
-
service: numberOf$
|
|
897
|
+
x: numberOf$2(x, line, "x"),
|
|
898
|
+
y: numberOf$2(y, line, "y"),
|
|
899
|
+
demand: numberOf$2(demand, line, "the demand"),
|
|
900
|
+
ready: numberOf$2(ready, line, "the ready time"),
|
|
901
|
+
due: numberOf$2(due, line, "the due date"),
|
|
902
|
+
service: numberOf$2(service, line, "the service time")
|
|
903
903
|
});
|
|
904
904
|
}
|
|
905
|
-
if (section !== "customer") throw new NativeParseError(FORMAT$
|
|
906
|
-
if (nodes.length === 0) throw new NativeParseError(FORMAT$
|
|
907
|
-
if (meta.vehicles === void 0 || meta.capacity === void 0) throw new NativeParseError(FORMAT$
|
|
905
|
+
if (section !== "customer") throw new NativeParseError(FORMAT$3, all.length, "expected a CUSTOMER section");
|
|
906
|
+
if (nodes.length === 0) throw new NativeParseError(FORMAT$3, all.length, "the CUSTOMER section has no rows");
|
|
907
|
+
if (meta.vehicles === void 0 || meta.capacity === void 0) throw new NativeParseError(FORMAT$3, all.length, "expected a VEHICLE section with the vehicle count and capacity");
|
|
908
908
|
return {
|
|
909
909
|
meta: {
|
|
910
910
|
name: meta.name,
|
|
@@ -916,10 +916,10 @@ function parseSolomon(text) {
|
|
|
916
916
|
}
|
|
917
917
|
//#endregion
|
|
918
918
|
//#region src/parsers/top.ts
|
|
919
|
-
const FORMAT$
|
|
919
|
+
const FORMAT$2 = "top";
|
|
920
920
|
/** The header lines before the first point: `n`, `m` and `tmax`. */
|
|
921
921
|
const HEADER_LINES = 3;
|
|
922
|
-
const NUMBER$
|
|
922
|
+
const NUMBER$2 = /^-?\d+(?:\.\d+)?$/;
|
|
923
923
|
/**
|
|
924
924
|
* Reads the value of a header line `<key> <number>`.
|
|
925
925
|
* @param text - The line.
|
|
@@ -930,7 +930,7 @@ const NUMBER$1 = /^-?\d+(?:\.\d+)?$/;
|
|
|
930
930
|
*/
|
|
931
931
|
function headerOf(text, key, line) {
|
|
932
932
|
const [name, value, ...extra] = (text ?? "").trim().split(/\s+/);
|
|
933
|
-
if (name !== key || value === void 0 || extra.length > 0 || !NUMBER$
|
|
933
|
+
if (name !== key || value === void 0 || extra.length > 0 || !NUMBER$2.test(value)) throw new NativeParseError(FORMAT$2, line, `expected "${key} <number>", found ${JSON.stringify((text ?? "").trim())}`);
|
|
934
934
|
return Number(value);
|
|
935
935
|
}
|
|
936
936
|
/**
|
|
@@ -949,11 +949,11 @@ function parseTop(text) {
|
|
|
949
949
|
const points = headerOf(first?.text, "n", first?.line ?? 1);
|
|
950
950
|
const paths = headerOf(second?.text, "m", second?.line ?? 2);
|
|
951
951
|
const budget = headerOf(third?.text, "tmax", third?.line ?? HEADER_LINES);
|
|
952
|
-
if (!Number.isInteger(points) || points < 2) throw new NativeParseError(FORMAT$
|
|
953
|
-
if (rows.length !== points) throw new NativeParseError(FORMAT$
|
|
952
|
+
if (!Number.isInteger(points) || points < 2) throw new NativeParseError(FORMAT$2, first?.line ?? 1, `expected at least a start and an end point, found n ${String(points)}`);
|
|
953
|
+
if (rows.length !== points) throw new NativeParseError(FORMAT$2, all[all.length - 1]?.line ?? 1, `the header gives ${String(points)} points, found ${String(rows.length)} rows`);
|
|
954
954
|
const nodes = rows.map((row, index) => {
|
|
955
955
|
const [x, y, score, ...extra] = row.text.split(/\s+/);
|
|
956
|
-
if (x === void 0 || y === void 0 || score === void 0 || extra.length > 0 || !NUMBER$
|
|
956
|
+
if (x === void 0 || y === void 0 || score === void 0 || extra.length > 0 || !NUMBER$2.test(x) || !NUMBER$2.test(y) || !NUMBER$2.test(score)) throw new NativeParseError(FORMAT$2, row.line, `expected three numbers (x, y, score), found ${JSON.stringify(row.text)}`);
|
|
957
957
|
return {
|
|
958
958
|
id: String(index),
|
|
959
959
|
x: Number(x),
|
|
@@ -973,7 +973,7 @@ function parseTop(text) {
|
|
|
973
973
|
}
|
|
974
974
|
//#endregion
|
|
975
975
|
//#region src/parsers/toptw.ts
|
|
976
|
-
const FORMAT = "toptw";
|
|
976
|
+
const FORMAT$1 = "toptw";
|
|
977
977
|
/** How many numbers the first header line holds (k, paths, customers, t) and the second (D, capacity). */
|
|
978
978
|
const FIRST_HEADER_NUMBERS = 4;
|
|
979
979
|
const SECOND_HEADER_NUMBERS = 2;
|
|
@@ -981,7 +981,7 @@ const SECOND_HEADER_NUMBERS = 2;
|
|
|
981
981
|
const LIST_LENGTH_AT = 6;
|
|
982
982
|
const LIST_STARTS_AT = 7;
|
|
983
983
|
const ROW_NUMBERS_BESIDE_LIST = 9;
|
|
984
|
-
const NUMBER = /^-?\d+(?:\.\d+)?$/;
|
|
984
|
+
const NUMBER$1 = /^-?\d+(?:\.\d+)?$/;
|
|
985
985
|
/**
|
|
986
986
|
* Reads a token as a finite number.
|
|
987
987
|
* @param token - The token.
|
|
@@ -990,8 +990,8 @@ const NUMBER = /^-?\d+(?:\.\d+)?$/;
|
|
|
990
990
|
* @returns The number.
|
|
991
991
|
* @throws NativeParseError when the token is not a decimal number.
|
|
992
992
|
*/
|
|
993
|
-
function numberOf(token, line, what) {
|
|
994
|
-
if (token === void 0 || !NUMBER.test(token)) throw new NativeParseError(FORMAT, line, `expected ${what}, found ${JSON.stringify(token)}`);
|
|
993
|
+
function numberOf$1(token, line, what) {
|
|
994
|
+
if (token === void 0 || !NUMBER$1.test(token)) throw new NativeParseError(FORMAT$1, line, `expected ${what}, found ${JSON.stringify(token)}`);
|
|
995
995
|
return Number(token);
|
|
996
996
|
}
|
|
997
997
|
/**
|
|
@@ -1005,8 +1005,8 @@ function numberOf(token, line, what) {
|
|
|
1005
1005
|
*/
|
|
1006
1006
|
function numbersOf(text, count, line, what) {
|
|
1007
1007
|
const tokens = text.trim().split(/\s+/);
|
|
1008
|
-
if (tokens.length !== count) throw new NativeParseError(FORMAT, line, `expected ${what}, found ${JSON.stringify(text.trim())}`);
|
|
1009
|
-
return tokens.map((token) => numberOf(token, line, what));
|
|
1008
|
+
if (tokens.length !== count) throw new NativeParseError(FORMAT$1, line, `expected ${what}, found ${JSON.stringify(text.trim())}`);
|
|
1009
|
+
return tokens.map((token) => numberOf$1(token, line, what));
|
|
1010
1010
|
}
|
|
1011
1011
|
/**
|
|
1012
1012
|
* Parses a team orienteering problem with time windows instance (TOPTW, in the layout of Righini and Salani, as the KU Leuven pages describe it). The first line holds four numbers, of which the second is the number of paths and the third the number of customers, the second line two, of which the second is the vehicle capacity, and then one row per node, the depot first: its id, position, service duration, profit, an unused number, the length of a list of unused numbers, that list, and the opening and closing of its time window. Columns are separated by any run of spaces, and blank or whitespace only lines are skipped. The row count must be the customer count plus one, which catches a truncated file. The time quantities are in the unit of the source's coordinate grid, which the format does not name.
|
|
@@ -1020,30 +1020,30 @@ function parseToptw(text) {
|
|
|
1020
1020
|
text: raw.trim()
|
|
1021
1021
|
})).filter((entry) => entry.text !== "");
|
|
1022
1022
|
const [first, second, ...rows] = all;
|
|
1023
|
-
if (first === void 0 || second === void 0) throw new NativeParseError(FORMAT, 1, "expected the two header lines");
|
|
1023
|
+
if (first === void 0 || second === void 0) throw new NativeParseError(FORMAT$1, 1, "expected the two header lines");
|
|
1024
1024
|
const [, paths, customers] = numbersOf(first.text, FIRST_HEADER_NUMBERS, first.line, "four numbers (k, paths, customers, t)");
|
|
1025
1025
|
const [, capacity] = numbersOf(second.text, SECOND_HEADER_NUMBERS, second.line, "two numbers (D, capacity)");
|
|
1026
|
-
if (paths === void 0 || customers === void 0 || capacity === void 0) throw new NativeParseError(FORMAT, first.line, "the header lacks a number");
|
|
1026
|
+
if (paths === void 0 || customers === void 0 || capacity === void 0) throw new NativeParseError(FORMAT$1, first.line, "the header lacks a number");
|
|
1027
1027
|
const seen = /* @__PURE__ */ new Set();
|
|
1028
1028
|
const nodes = rows.map((row) => {
|
|
1029
1029
|
const tokens = row.text.split(/\s+/);
|
|
1030
|
-
const listLength = numberOf(tokens[LIST_LENGTH_AT], row.line, "the length of the list after the unused number");
|
|
1031
|
-
if (!Number.isInteger(listLength) || listLength < 0 || tokens.length !== ROW_NUMBERS_BESIDE_LIST + listLength) throw new NativeParseError(FORMAT, row.line, `expected ${String(ROW_NUMBERS_BESIDE_LIST + listLength)} numbers for a list of ${String(listLength)}, found ${String(tokens.length)}`);
|
|
1030
|
+
const listLength = numberOf$1(tokens[LIST_LENGTH_AT], row.line, "the length of the list after the unused number");
|
|
1031
|
+
if (!Number.isInteger(listLength) || listLength < 0 || tokens.length !== ROW_NUMBERS_BESIDE_LIST + listLength) throw new NativeParseError(FORMAT$1, row.line, `expected ${String(ROW_NUMBERS_BESIDE_LIST + listLength)} numbers for a list of ${String(listLength)}, found ${String(tokens.length)}`);
|
|
1032
1032
|
const [id] = tokens;
|
|
1033
|
-
if (id === void 0 || !/^\d+$/.test(id)) throw new NativeParseError(FORMAT, row.line, `expected a whole number node id, found ${JSON.stringify(id)}`);
|
|
1034
|
-
if (seen.has(id)) throw new NativeParseError(FORMAT, row.line, `node ${id} appears twice`);
|
|
1033
|
+
if (id === void 0 || !/^\d+$/.test(id)) throw new NativeParseError(FORMAT$1, row.line, `expected a whole number node id, found ${JSON.stringify(id)}`);
|
|
1034
|
+
if (seen.has(id)) throw new NativeParseError(FORMAT$1, row.line, `node ${id} appears twice`);
|
|
1035
1035
|
seen.add(id);
|
|
1036
1036
|
return {
|
|
1037
1037
|
id,
|
|
1038
|
-
x: numberOf(tokens[1], row.line, "x"),
|
|
1039
|
-
y: numberOf(tokens[2], row.line, "y"),
|
|
1040
|
-
service: numberOf(tokens[3], row.line, "the service duration"),
|
|
1041
|
-
profit: numberOf(tokens[4], row.line, "the profit"),
|
|
1042
|
-
open: numberOf(tokens[LIST_STARTS_AT + listLength], row.line, "the opening of the window"),
|
|
1043
|
-
close: numberOf(tokens[8 + listLength], row.line, "the closing of the window")
|
|
1038
|
+
x: numberOf$1(tokens[1], row.line, "x"),
|
|
1039
|
+
y: numberOf$1(tokens[2], row.line, "y"),
|
|
1040
|
+
service: numberOf$1(tokens[3], row.line, "the service duration"),
|
|
1041
|
+
profit: numberOf$1(tokens[4], row.line, "the profit"),
|
|
1042
|
+
open: numberOf$1(tokens[LIST_STARTS_AT + listLength], row.line, "the opening of the window"),
|
|
1043
|
+
close: numberOf$1(tokens[8 + listLength], row.line, "the closing of the window")
|
|
1044
1044
|
};
|
|
1045
1045
|
});
|
|
1046
|
-
if (nodes.length !== customers + 1) throw new NativeParseError(FORMAT, all.length === 0 ? 1 : all[all.length - 1]?.line ?? 1, `the header gives ${String(customers)} customers, so expected ${String(customers + 1)} rows with the depot, found ${String(nodes.length)}`);
|
|
1046
|
+
if (nodes.length !== customers + 1) throw new NativeParseError(FORMAT$1, all.length === 0 ? 1 : all[all.length - 1]?.line ?? 1, `the header gives ${String(customers)} customers, so expected ${String(customers + 1)} rows with the depot, found ${String(nodes.length)}`);
|
|
1047
1047
|
return {
|
|
1048
1048
|
meta: {
|
|
1049
1049
|
paths,
|
|
@@ -1054,6 +1054,206 @@ function parseToptw(text) {
|
|
|
1054
1054
|
};
|
|
1055
1055
|
}
|
|
1056
1056
|
//#endregion
|
|
1057
|
+
//#region src/parsers/tsplib.ts
|
|
1058
|
+
const FORMAT = "tsplib";
|
|
1059
|
+
/** The instance types the parser reads: the probabilistic and the clustered orienteering problem. */
|
|
1060
|
+
const TYPES = /* @__PURE__ */ new Set(["POP", "COP"]);
|
|
1061
|
+
/** The edge weight types a coordinate section is read under: planar ones keep their coordinates as `x` and `y`, `GEO` converts them to degrees, and `EXPLICIT` has no coordinates. */
|
|
1062
|
+
const PLANAR = /* @__PURE__ */ new Set([
|
|
1063
|
+
"EUC_2D",
|
|
1064
|
+
"CEIL_2D",
|
|
1065
|
+
"ATT"
|
|
1066
|
+
]);
|
|
1067
|
+
const NUMBER = /^-?\d+(?:\.\d+)?$/;
|
|
1068
|
+
const WHOLE = /^\d+$/;
|
|
1069
|
+
const HEADER$1 = /^([A-Z][A-Z_]*)\s*:\s*(.*)$/;
|
|
1070
|
+
const SECTION = /^[A-Z][A-Z_]*$/;
|
|
1071
|
+
/** Minutes in a degree, which a `DDD.MM` coordinate counts in. */
|
|
1072
|
+
const MINUTES_PER_DEGREE = 60;
|
|
1073
|
+
/** `DDD.MM` has two digits of minutes, so the fraction is read in hundredths. */
|
|
1074
|
+
const MINUTE_SCALE = 100;
|
|
1075
|
+
/** How far a coordinate's hundredths may lie from a whole number of minutes: float error in the text's value, not a third digit. */
|
|
1076
|
+
const MINUTE_TOLERANCE = 1e-6;
|
|
1077
|
+
/**
|
|
1078
|
+
* Converts a TSPLIB `GEO` coordinate to decimal degrees. The value is `DDD.MM`, degrees then minutes in one number (`48.23` is 48 degrees 23 minutes), so the fraction is minutes out of a hundred, not a decimal fraction of a degree. The degrees are truncated, which is what makes the conversion agree with the optimal tour lengths the instances record where the specification's `nint` would round minutes of 50 or more up to the next degree.
|
|
1079
|
+
* @param value - The coordinate as the file writes it.
|
|
1080
|
+
* @param line - The 1-based line, for the error.
|
|
1081
|
+
* @returns Decimal degrees, signed like the input.
|
|
1082
|
+
* @throws NativeParseError when the minutes are not a whole number below sixty.
|
|
1083
|
+
*/
|
|
1084
|
+
function degrees(value, line) {
|
|
1085
|
+
const magnitude = Math.abs(value);
|
|
1086
|
+
const whole = Math.trunc(magnitude);
|
|
1087
|
+
const hundredths = (magnitude - whole) * MINUTE_SCALE;
|
|
1088
|
+
const minutes = Math.round(hundredths);
|
|
1089
|
+
if (Math.abs(hundredths - minutes) > MINUTE_TOLERANCE || minutes >= MINUTES_PER_DEGREE) throw new NativeParseError(FORMAT, line, `expected a DDD.MM coordinate with whole minutes below 60, found ${String(value)}`);
|
|
1090
|
+
return Math.sign(value) * (whole + minutes / MINUTES_PER_DEGREE);
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Reads a token as a finite number.
|
|
1094
|
+
* @param token - The token.
|
|
1095
|
+
* @param line - The 1-based line, for the error.
|
|
1096
|
+
* @param what - What the token should be, for the error.
|
|
1097
|
+
* @returns The number.
|
|
1098
|
+
* @throws NativeParseError when the token is not a decimal number.
|
|
1099
|
+
*/
|
|
1100
|
+
function numberOf(token, line, what) {
|
|
1101
|
+
if (token === void 0 || !NUMBER.test(token)) throw new NativeParseError(FORMAT, line, `expected ${what}, found ${JSON.stringify(token)}`);
|
|
1102
|
+
return Number(token);
|
|
1103
|
+
}
|
|
1104
|
+
/**
|
|
1105
|
+
* Reads a token as a whole number.
|
|
1106
|
+
* @param token - The token.
|
|
1107
|
+
* @param line - The 1-based line, for the error.
|
|
1108
|
+
* @param what - What the token should be, for the error.
|
|
1109
|
+
* @returns The number.
|
|
1110
|
+
* @throws NativeParseError when the token is not a whole number.
|
|
1111
|
+
*/
|
|
1112
|
+
function wholeOf(token, line, what) {
|
|
1113
|
+
if (token === void 0 || !WHOLE.test(token)) throw new NativeParseError(FORMAT, line, `expected ${what}, found ${JSON.stringify(token)}`);
|
|
1114
|
+
return Number(token);
|
|
1115
|
+
}
|
|
1116
|
+
/**
|
|
1117
|
+
* Reads the header, the coordinate section, the prize and probability section and the set section of a file, skipping every other section.
|
|
1118
|
+
* @param text - The file text.
|
|
1119
|
+
* @returns What it holds.
|
|
1120
|
+
* @throws NativeParseError naming the line for a repeated key, a malformed row, a repeated node or set id, or a row outside any section.
|
|
1121
|
+
*/
|
|
1122
|
+
function collect(text) {
|
|
1123
|
+
const collected = {
|
|
1124
|
+
header: /* @__PURE__ */ new Map(),
|
|
1125
|
+
coords: /* @__PURE__ */ new Map(),
|
|
1126
|
+
prizes: /* @__PURE__ */ new Map(),
|
|
1127
|
+
sets: []
|
|
1128
|
+
};
|
|
1129
|
+
let section;
|
|
1130
|
+
for (const [index, raw] of lines(text).entries()) {
|
|
1131
|
+
const line = index + 1;
|
|
1132
|
+
const trimmed = raw.trim();
|
|
1133
|
+
if (trimmed === "" || trimmed === "EOF") continue;
|
|
1134
|
+
const keyed = HEADER$1.exec(trimmed);
|
|
1135
|
+
const key = keyed?.[1];
|
|
1136
|
+
if (key === "CONSTRAINING_SET_SECTION") {
|
|
1137
|
+
section = "sets";
|
|
1138
|
+
continue;
|
|
1139
|
+
}
|
|
1140
|
+
if (keyed !== null && key !== void 0) {
|
|
1141
|
+
if (collected.header.has(key)) throw new NativeParseError(FORMAT, line, `${key} appears twice`);
|
|
1142
|
+
collected.header.set(key, (keyed[2] ?? "").trim());
|
|
1143
|
+
section = void 0;
|
|
1144
|
+
continue;
|
|
1145
|
+
}
|
|
1146
|
+
if (SECTION.test(trimmed)) {
|
|
1147
|
+
section = trimmed === "NODE_COORD_SECTION" ? "coords" : trimmed === "NODE_PRIZE_PROBABILITY_SECTION" ? "prizes" : "skipped";
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
const tokens = trimmed.split(/\s+/);
|
|
1151
|
+
if (section === "coords") {
|
|
1152
|
+
const [id, x, y, ...extra] = tokens;
|
|
1153
|
+
if (extra.length > 0) throw new NativeParseError(FORMAT, line, `expected "id x y", found ${JSON.stringify(trimmed)}`);
|
|
1154
|
+
const node = wholeOf(id, line, "a node id");
|
|
1155
|
+
if (collected.coords.has(node)) throw new NativeParseError(FORMAT, line, `node ${String(node)} has two coordinate rows`);
|
|
1156
|
+
collected.coords.set(node, {
|
|
1157
|
+
x: numberOf(x, line, "x"),
|
|
1158
|
+
y: numberOf(y, line, "y"),
|
|
1159
|
+
line
|
|
1160
|
+
});
|
|
1161
|
+
} else if (section === "prizes") {
|
|
1162
|
+
const [id, prize, probability, ...extra] = tokens;
|
|
1163
|
+
if (extra.length > 0) throw new NativeParseError(FORMAT, line, `expected "id prize probability", found ${JSON.stringify(trimmed)}`);
|
|
1164
|
+
const node = wholeOf(id, line, "a node id");
|
|
1165
|
+
if (collected.prizes.has(node)) throw new NativeParseError(FORMAT, line, `node ${String(node)} has two prize rows`);
|
|
1166
|
+
collected.prizes.set(node, {
|
|
1167
|
+
prize: numberOf(prize, line, "the prize"),
|
|
1168
|
+
probability: numberOf(probability, line, "the probability")
|
|
1169
|
+
});
|
|
1170
|
+
} else if (section === "sets") {
|
|
1171
|
+
const [id, prize, ...members] = tokens;
|
|
1172
|
+
const setId = wholeOf(id, line, "a set id");
|
|
1173
|
+
if (collected.sets.some((set) => set.id === setId)) throw new NativeParseError(FORMAT, line, `set ${String(setId)} appears twice`);
|
|
1174
|
+
collected.sets.push({
|
|
1175
|
+
id: setId,
|
|
1176
|
+
prize: numberOf(prize, line, "the set prize"),
|
|
1177
|
+
members: members.map((member) => wholeOf(member, line, "a node id in a set"))
|
|
1178
|
+
});
|
|
1179
|
+
} else if (section === void 0) throw new NativeParseError(FORMAT, line, `expected a KEY : value line or a section, found ${JSON.stringify(trimmed)}`);
|
|
1180
|
+
}
|
|
1181
|
+
return collected;
|
|
1182
|
+
}
|
|
1183
|
+
/**
|
|
1184
|
+
* Reads a header value that must be there.
|
|
1185
|
+
* @param header - The header.
|
|
1186
|
+
* @param key - The key.
|
|
1187
|
+
* @returns Its text.
|
|
1188
|
+
* @throws NativeParseError when the file has no such key.
|
|
1189
|
+
*/
|
|
1190
|
+
function required(header, key) {
|
|
1191
|
+
const value = header.get(key);
|
|
1192
|
+
if (value === void 0) throw new NativeParseError(FORMAT, 1, `expected a ${key} line`);
|
|
1193
|
+
return value;
|
|
1194
|
+
}
|
|
1195
|
+
/**
|
|
1196
|
+
* Parses a TSPLIB style orienteering instance of type `POP` (probabilistic orienteering, Angelelli and others) or `COP` (clustered orienteering), in the layout TSPLIB95 (Reinelt) defines: `KEY : value` header lines and bare keyword sections. The nodes are 1 to `DIMENSION`. The planar weight types keep their coordinates as `x` and `y` and `GEO` converts them to `lat` and `lon`; an `EXPLICIT` file has no coordinates, so its nodes have only the prize data. A `POP` file's `NODE_PRIZE_PROBABILITY_SECTION` gives each node its prize and probability. A `COP` file has no prize on a node: its prizes belong to sets of nodes that may overlap, so each node lists the sets it is in under `clusters` and the sets' prizes are the `setPrizes` metadata, and nothing is divided among the members. The weight matrix is not read, as or/v1 has no arcs.
|
|
1197
|
+
* @param text - The file text.
|
|
1198
|
+
* @returns The instance: its header values as `meta` and its nodes in id order.
|
|
1199
|
+
* @throws NativeParseError naming the line for an unsupported type or weight type, a missing key or section, a node id outside 1 to `DIMENSION` or missing from a section that must cover every node, or a set that names a node outside that range.
|
|
1200
|
+
*/
|
|
1201
|
+
function parseTsplib(text) {
|
|
1202
|
+
const { header, coords, prizes, sets } = collect(text);
|
|
1203
|
+
const type = required(header, "TYPE");
|
|
1204
|
+
if (!TYPES.has(type)) throw new NativeParseError(FORMAT, 1, `expected TYPE POP or COP, found ${JSON.stringify(type)}`);
|
|
1205
|
+
const weightType = required(header, "EDGE_WEIGHT_TYPE");
|
|
1206
|
+
const geographic = weightType === "GEO";
|
|
1207
|
+
if (!geographic && !PLANAR.has(weightType) && weightType !== "EXPLICIT") throw new NativeParseError(FORMAT, 1, `expected EDGE_WEIGHT_TYPE EUC_2D, CEIL_2D, ATT, GEO or EXPLICIT, found ${JSON.stringify(weightType)}`);
|
|
1208
|
+
const dimension = wholeOf(required(header, "DIMENSION"), 1, "DIMENSION");
|
|
1209
|
+
const budget = numberOf(required(header, "TMAX"), 1, "TMAX");
|
|
1210
|
+
if (weightType === "EXPLICIT" ? coords.size > 0 : coords.size !== dimension) throw new NativeParseError(FORMAT, 1, weightType === "EXPLICIT" ? "an EXPLICIT file has no NODE_COORD_SECTION" : `expected ${String(dimension)} coordinate rows, found ${String(coords.size)}`);
|
|
1211
|
+
const inRange = (id) => id >= 1 && id <= dimension;
|
|
1212
|
+
for (const id of [
|
|
1213
|
+
...coords.keys(),
|
|
1214
|
+
...prizes.keys(),
|
|
1215
|
+
...sets.flatMap((set) => set.members)
|
|
1216
|
+
]) if (!inRange(id)) throw new NativeParseError(FORMAT, 1, `node ${String(id)} is outside 1 to ${String(dimension)}`);
|
|
1217
|
+
if (type === "POP" && prizes.size !== dimension) throw new NativeParseError(FORMAT, 1, `expected ${String(dimension)} prize rows, found ${String(prizes.size)}`);
|
|
1218
|
+
if (type === "COP") {
|
|
1219
|
+
const declared = wholeOf(required(header, "SETS"), 1, "SETS");
|
|
1220
|
+
if (sets.length !== declared) throw new NativeParseError(FORMAT, 1, `expected ${String(declared)} sets, found ${String(sets.length)}`);
|
|
1221
|
+
}
|
|
1222
|
+
const clustersOf = (node) => {
|
|
1223
|
+
const ids = sets.filter((set) => set.members.includes(node)).map((set) => String(set.id));
|
|
1224
|
+
return ids.length === 0 ? null : ids.join(",");
|
|
1225
|
+
};
|
|
1226
|
+
const nodes = Array.from({ length: dimension }, (_, index) => {
|
|
1227
|
+
const id = index + 1;
|
|
1228
|
+
const position = coords.get(id);
|
|
1229
|
+
const prize = prizes.get(id);
|
|
1230
|
+
const lat = geographic && position !== void 0 ? degrees(position.x, position.line) : null;
|
|
1231
|
+
const lon = geographic && position !== void 0 ? degrees(position.y, position.line) : null;
|
|
1232
|
+
return {
|
|
1233
|
+
id: String(id),
|
|
1234
|
+
x: geographic ? null : position?.x ?? null,
|
|
1235
|
+
y: geographic ? null : position?.y ?? null,
|
|
1236
|
+
lat,
|
|
1237
|
+
lon,
|
|
1238
|
+
prize: prize?.prize ?? null,
|
|
1239
|
+
probability: prize?.probability ?? null,
|
|
1240
|
+
clusters: clustersOf(id)
|
|
1241
|
+
};
|
|
1242
|
+
});
|
|
1243
|
+
const total = header.get("TPRIZE");
|
|
1244
|
+
return {
|
|
1245
|
+
meta: {
|
|
1246
|
+
name: header.get("NAME") ?? null,
|
|
1247
|
+
type,
|
|
1248
|
+
budget,
|
|
1249
|
+
edgeWeightType: weightType,
|
|
1250
|
+
totalPrize: total === void 0 ? null : numberOf(total, 1, "TPRIZE"),
|
|
1251
|
+
setPrizes: type === "COP" ? sets.map((set) => `${String(set.id)}:${String(set.prize)}`).join(",") : null
|
|
1252
|
+
},
|
|
1253
|
+
nodes
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
//#endregion
|
|
1057
1257
|
//#region src/parsers/parse-native.ts
|
|
1058
1258
|
/** Bytes converted per String.fromCharCode call: spreading a whole file would exceed the engine's argument-count limit, and this many stays well inside every engine's. */
|
|
1059
1259
|
const LATIN1_CHUNK = 32768;
|
|
@@ -1112,6 +1312,7 @@ function parseNative(bytes, parser) {
|
|
|
1112
1312
|
if (parser.format === "solomon") return parseSolomon(text);
|
|
1113
1313
|
if (parser.format === "top") return parseTop(text);
|
|
1114
1314
|
if (parser.format === "toptw") return parseToptw(text);
|
|
1315
|
+
if (parser.format === "tsplib") return parseTsplib(text);
|
|
1115
1316
|
return parsePajek(text);
|
|
1116
1317
|
}
|
|
1117
1318
|
/** The ustar header layout (POSIX.1-1988, pax(1) "ustar Interchange Format"): each field's byte offset and length. */
|
|
@@ -1648,6 +1849,8 @@ const REDIRECTS = new Set(Object.values({
|
|
|
1648
1849
|
}));
|
|
1649
1850
|
/** What the downloader says it is, so a server operator can tell where the traffic comes from. */
|
|
1650
1851
|
const USER_AGENT = "keepset (+https://github.com/Mearman/keepset)";
|
|
1852
|
+
/** What the downloader accepts: anything, as the file is the recipe's to read. Node's HTTP client sends no `Accept` header of its own, and a server that content-negotiates a download (the VRP-REP host answers 406 to a request without one) refuses it; every other HTTP client sends this, and RFC 9110 reads an absent header as the same. */
|
|
1853
|
+
const ACCEPT = "*/*";
|
|
1651
1854
|
/** The failure of a connection that sent nothing for the stall time. */
|
|
1652
1855
|
var StalledError = class extends KeepsetError {};
|
|
1653
1856
|
/**
|
|
@@ -1672,7 +1875,10 @@ async function get(url, signal, stall) {
|
|
|
1672
1875
|
let answered;
|
|
1673
1876
|
const request = send(url, {
|
|
1674
1877
|
method: "GET",
|
|
1675
|
-
headers: {
|
|
1878
|
+
headers: {
|
|
1879
|
+
accept: ACCEPT,
|
|
1880
|
+
"user-agent": USER_AGENT
|
|
1881
|
+
},
|
|
1676
1882
|
...signal === void 0 ? {} : { signal }
|
|
1677
1883
|
}, (response) => {
|
|
1678
1884
|
answered = response;
|
package/dist-cli/keepset.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { KeepsetError, NAME_SEPARATOR, countTarget, getDataset, listDatasets, li
|
|
|
4
4
|
import { fetchDataset, roundTripDataset } from "keepset/node";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
6
6
|
//#region package.json
|
|
7
|
-
var version = "0.
|
|
7
|
+
var version = "0.26.0";
|
|
8
8
|
const usage = `Usage: keepset <command> [options]
|
|
9
9
|
|
|
10
10
|
Commands:
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$defs":{"Crosswalk":{"$ref":"https://cdn.jsdelivr.net/npm/twindex@0.1.4/schemas/twindex.schema.json"},"Entry":{"additionalProperties":false,"properties":{"aliases":{"items":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*(?:\\/[A-Za-z0-9][A-Za-z0-9._-]*)*$","type":"string"},"minItems":1,"type":"array"},"category":{"enum":["graph/v1","or/v1","or-set/v1"],"type":"string"},"citations":{"items":{"additionalProperties":false,"properties":{"doi":{"pattern":"^10\\.\\d{4,9}\\/\\S+$","type":"string"},"text":{"minLength":1,"type":"string"},"url":{"format":"uri","type":"string"}},"required":["text"],"type":"object"},"type":"array"},"crosswalk":{"anyOf":[{"$ref":"#/$defs/Crosswalk"},{"additionalProperties":false,"properties":{"file":{"type":"string"}},"required":["file"],"type":"object"}]},"description":{"minLength":1,"type":"string"},"domain":{"minLength":1,"type":"string"},"expectedCounts":{"additionalProperties":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"propertyNames":{"pattern":"^[A-Za-z][A-Za-z0-9]*$","type":"string"},"type":"object"},"id":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"licence":{"oneOf":[{"additionalProperties":false,"properties":{"id":{"pattern":"^[A-Za-z0-9][A-Za-z0-9.+-]*$","type":"string"},"kind":{"const":"spdx","type":"string"}},"required":["kind","id"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"custom","type":"string"},"name":{"minLength":1,"type":"string"},"url":{"format":"uri","type":"string"}},"required":["kind","name","url"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"unrecorded","type":"string"}},"required":["kind"],"type":"object"}]},"name":{"minLength":1,"type":"string"},"namespace":{"items":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"minItems":1,"type":"array"},"properties":{"additionalProperties":{"type":["string","number","boolean","null"]},"propertyNames":{"pattern":"^[A-Za-z][A-Za-z0-9]*$","type":"string"},"type":"object"},"recipe":{"oneOf":[{"additionalProperties":false,"properties":{"archive":{"anyOf":[{"additionalProperties":false,"properties":{"kind":{"const":"none","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"gzip","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"enum":["zip","tar","tar.gz"],"type":"string"},"member":{"anyOf":[{"additionalProperties":false,"properties":{"path":{"type":"string"}},"required":["path"],"type":"object"},{"additionalProperties":false,"properties":{"extensions":{"items":{"pattern":"^\\.[A-Za-z0-9][A-Za-z0-9.]*$","type":"string"},"minItems":1,"type":"array"}},"required":["extensions"],"type":"object"}]}},"required":["kind","member"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"enum":["zip","tar","tar.gz"],"type":"string"},"members":{"anyOf":[{"additionalProperties":false,"properties":{"path":{"type":"string"}},"required":["path"],"type":"object"},{"additionalProperties":false,"properties":{"extensions":{"items":{"pattern":"^\\.[A-Za-z0-9][A-Za-z0-9.]*$","type":"string"},"minItems":1,"type":"array"}},"required":["extensions"],"type":"object"}]}},"required":["kind","members"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"xlsx","type":"string"},"sheet":{"minLength":1,"type":"string"}},"required":["kind","sheet"],"type":"object"}]},"paging":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"arcgis-query","type":"string"},"orderBy":{"pattern":"^[A-Za-z_][A-Za-z0-9_]*$","type":"string"}},"required":["kind","orderBy"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"socrata-resource","type":"string"},"pageSize":{"maximum":9007199254740991,"minimum":1,"type":"integer"}},"required":["kind","pageSize"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"ckan-datastore","type":"string"},"pageSize":{"maximum":9007199254740991,"minimum":1,"type":"integer"}},"required":["kind","pageSize"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"openfema","type":"string"},"pageSize":{"maximum":9007199254740991,"minimum":1,"type":"integer"}},"required":["kind","pageSize"],"type":"object"}]},"parser":{"oneOf":[{"additionalProperties":false,"properties":{"commentPrefixes":{"items":{"minLength":1,"type":"string"},"type":"array"},"delimiter":{"enum":["detect","whitespace","tab","comma","space"],"type":"string"},"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"edge-list","type":"string"},"skipLines":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"sourceColumn":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"targetColumn":{"maximum":9007199254740991,"minimum":0,"type":"integer"}},"required":["format","encoding","delimiter","skipLines","commentPrefixes","sourceColumn","targetColumn"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"matrix-market","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"gml","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"pajek","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"solomon","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"top","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"toptw","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"columns":{"items":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"type":"array"},"delimiter":{"enum":["comma","tab","semicolon"],"type":"string"},"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"csv-table","type":"string"},"idColumn":{"anyOf":[{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},{"type":"null"}]},"nullValues":{"items":{"minLength":1,"type":"string"},"type":"array"},"numericColumns":{"items":{"additionalProperties":false,"properties":{"column":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"factor":{"exclusiveMinimum":0,"type":"number"}},"required":["column","factor"],"type":"object"},"type":"array"},"skipLines":{"maximum":9007199254740991,"minimum":0,"type":"integer"}},"required":["format","encoding","delimiter","skipLines","idColumn","numericColumns"],"type":"object"},{"additionalProperties":false,"properties":{"columns":{"items":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"minItems":1,"type":"array"},"dateColumns":{"items":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"type":"array"},"encoding":{"const":"utf-8","type":"string"},"format":{"const":"geojson","type":"string"},"idColumn":{"anyOf":[{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},{"type":"null"}]},"numericColumns":{"items":{"additionalProperties":false,"properties":{"column":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"factor":{"exclusiveMinimum":0,"type":"number"}},"required":["column","factor"],"type":"object"},"type":"array"}},"required":["format","encoding","idColumn","numericColumns","dateColumns","columns"],"type":"object"}]},"source":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"status":{"const":"fetchable","type":"string"}},"required":["status","source","archive","parser"],"type":"object"},{"additionalProperties":false,"properties":{"reason":{"minLength":1,"type":"string"},"status":{"const":"not-fetchable","type":"string"}},"required":["status","reason"],"type":"object"}]},"sources":{"items":{"additionalProperties":false,"properties":{"retrieved":{"format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","type":"string"},"snapshot":{"additionalProperties":false,"properties":{"timestamp":{"pattern":"^\\d{8}(?:\\d{6})?$","type":"string"},"url":{"format":"uri","type":"string"}},"required":["url","timestamp"],"type":"object"},"status":{"enum":["live","dead"],"type":"string"},"url":{"format":"uri","type":"string"}},"required":["url","retrieved","status"],"type":"object"},"minItems":1,"type":"array"},"tags":{"items":{"minLength":1,"type":"string"},"type":"array"}},"required":["id","name","tags","category","sources","licence","citations","recipe","crosswalk","expectedCounts","properties"],"type":"object"}},"$id":"https://cdn.jsdelivr.net/npm/keepset@0.
|
|
1
|
+
{"$defs":{"Crosswalk":{"$ref":"https://cdn.jsdelivr.net/npm/twindex@0.1.4/schemas/twindex.schema.json"},"Entry":{"additionalProperties":false,"properties":{"aliases":{"items":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*(?:\\/[A-Za-z0-9][A-Za-z0-9._-]*)*$","type":"string"},"minItems":1,"type":"array"},"category":{"enum":["graph/v1","or/v1","or-set/v1"],"type":"string"},"citations":{"items":{"additionalProperties":false,"properties":{"doi":{"pattern":"^10\\.\\d{4,9}\\/\\S+$","type":"string"},"text":{"minLength":1,"type":"string"},"url":{"format":"uri","type":"string"}},"required":["text"],"type":"object"},"type":"array"},"crosswalk":{"anyOf":[{"$ref":"#/$defs/Crosswalk"},{"additionalProperties":false,"properties":{"file":{"type":"string"}},"required":["file"],"type":"object"}]},"description":{"minLength":1,"type":"string"},"domain":{"minLength":1,"type":"string"},"expectedCounts":{"additionalProperties":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"propertyNames":{"pattern":"^[A-Za-z][A-Za-z0-9]*$","type":"string"},"type":"object"},"id":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"licence":{"oneOf":[{"additionalProperties":false,"properties":{"id":{"pattern":"^[A-Za-z0-9][A-Za-z0-9.+-]*$","type":"string"},"kind":{"const":"spdx","type":"string"}},"required":["kind","id"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"custom","type":"string"},"name":{"minLength":1,"type":"string"},"url":{"format":"uri","type":"string"}},"required":["kind","name","url"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"unrecorded","type":"string"}},"required":["kind"],"type":"object"}]},"name":{"minLength":1,"type":"string"},"namespace":{"items":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"minItems":1,"type":"array"},"properties":{"additionalProperties":{"type":["string","number","boolean","null"]},"propertyNames":{"pattern":"^[A-Za-z][A-Za-z0-9]*$","type":"string"},"type":"object"},"recipe":{"oneOf":[{"additionalProperties":false,"properties":{"archive":{"anyOf":[{"additionalProperties":false,"properties":{"kind":{"const":"none","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"gzip","type":"string"}},"required":["kind"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"enum":["zip","tar","tar.gz"],"type":"string"},"member":{"anyOf":[{"additionalProperties":false,"properties":{"path":{"type":"string"}},"required":["path"],"type":"object"},{"additionalProperties":false,"properties":{"extensions":{"items":{"pattern":"^\\.[A-Za-z0-9][A-Za-z0-9.]*$","type":"string"},"minItems":1,"type":"array"}},"required":["extensions"],"type":"object"}]}},"required":["kind","member"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"enum":["zip","tar","tar.gz"],"type":"string"},"members":{"anyOf":[{"additionalProperties":false,"properties":{"path":{"type":"string"}},"required":["path"],"type":"object"},{"additionalProperties":false,"properties":{"extensions":{"items":{"pattern":"^\\.[A-Za-z0-9][A-Za-z0-9.]*$","type":"string"},"minItems":1,"type":"array"}},"required":["extensions"],"type":"object"}]}},"required":["kind","members"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"xlsx","type":"string"},"sheet":{"minLength":1,"type":"string"}},"required":["kind","sheet"],"type":"object"}]},"paging":{"oneOf":[{"additionalProperties":false,"properties":{"kind":{"const":"arcgis-query","type":"string"},"orderBy":{"pattern":"^[A-Za-z_][A-Za-z0-9_]*$","type":"string"}},"required":["kind","orderBy"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"socrata-resource","type":"string"},"pageSize":{"maximum":9007199254740991,"minimum":1,"type":"integer"}},"required":["kind","pageSize"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"ckan-datastore","type":"string"},"pageSize":{"maximum":9007199254740991,"minimum":1,"type":"integer"}},"required":["kind","pageSize"],"type":"object"},{"additionalProperties":false,"properties":{"kind":{"const":"openfema","type":"string"},"pageSize":{"maximum":9007199254740991,"minimum":1,"type":"integer"}},"required":["kind","pageSize"],"type":"object"}]},"parser":{"oneOf":[{"additionalProperties":false,"properties":{"commentPrefixes":{"items":{"minLength":1,"type":"string"},"type":"array"},"delimiter":{"enum":["detect","whitespace","tab","comma","space"],"type":"string"},"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"edge-list","type":"string"},"skipLines":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"sourceColumn":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"targetColumn":{"maximum":9007199254740991,"minimum":0,"type":"integer"}},"required":["format","encoding","delimiter","skipLines","commentPrefixes","sourceColumn","targetColumn"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"matrix-market","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"gml","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"pajek","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"solomon","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"top","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"toptw","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"tsplib","type":"string"}},"required":["format","encoding"],"type":"object"},{"additionalProperties":false,"properties":{"columns":{"items":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"type":"array"},"delimiter":{"enum":["comma","tab","semicolon"],"type":"string"},"encoding":{"enum":["utf-8","latin1"],"type":"string"},"format":{"const":"csv-table","type":"string"},"idColumn":{"anyOf":[{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},{"type":"null"}]},"nullValues":{"items":{"minLength":1,"type":"string"},"type":"array"},"numericColumns":{"items":{"additionalProperties":false,"properties":{"column":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"factor":{"exclusiveMinimum":0,"type":"number"}},"required":["column","factor"],"type":"object"},"type":"array"},"skipLines":{"maximum":9007199254740991,"minimum":0,"type":"integer"}},"required":["format","encoding","delimiter","skipLines","idColumn","numericColumns"],"type":"object"},{"additionalProperties":false,"properties":{"columns":{"items":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"minItems":1,"type":"array"},"dateColumns":{"items":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"type":"array"},"encoding":{"const":"utf-8","type":"string"},"format":{"const":"geojson","type":"string"},"idColumn":{"anyOf":[{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},{"type":"null"}]},"numericColumns":{"items":{"additionalProperties":false,"properties":{"column":{"pattern":"^[A-Za-z](?:[A-Za-z0-9_]*[A-Za-z0-9])?$","type":"string"},"factor":{"exclusiveMinimum":0,"type":"number"}},"required":["column","factor"],"type":"object"},"type":"array"}},"required":["format","encoding","idColumn","numericColumns","dateColumns","columns"],"type":"object"}]},"source":{"maximum":9007199254740991,"minimum":0,"type":"integer"},"status":{"const":"fetchable","type":"string"}},"required":["status","source","archive","parser"],"type":"object"},{"additionalProperties":false,"properties":{"reason":{"minLength":1,"type":"string"},"status":{"const":"not-fetchable","type":"string"}},"required":["status","reason"],"type":"object"}]},"sources":{"items":{"additionalProperties":false,"properties":{"retrieved":{"format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","type":"string"},"snapshot":{"additionalProperties":false,"properties":{"timestamp":{"pattern":"^\\d{8}(?:\\d{6})?$","type":"string"},"url":{"format":"uri","type":"string"}},"required":["url","timestamp"],"type":"object"},"status":{"enum":["live","dead"],"type":"string"},"url":{"format":"uri","type":"string"}},"required":["url","retrieved","status"],"type":"object"},"minItems":1,"type":"array"},"tags":{"items":{"minLength":1,"type":"string"},"type":"array"}},"required":["id","name","tags","category","sources","licence","citations","recipe","crosswalk","expectedCounts","properties"],"type":"object"}},"$id":"https://cdn.jsdelivr.net/npm/keepset@0.26.0/schemas/entry.schema.json","$ref":"#/$defs/Entry","$schema":"https://json-schema.org/draft/2020-12/schema"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$defs":{"Manifest":{"additionalProperties":false,"properties":{"description":{"minLength":1,"type":"string"},"id":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"lineage":{"additionalProperties":false,"properties":{"catalogue":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"repository":{"format":"uri","type":"string"},"version":{"pattern":"^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$","type":"string"}},"required":["catalogue","version","repository"],"type":"object"},"name":{"minLength":1,"type":"string"},"namespaceAliases":{"additionalProperties":{"items":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"minItems":1,"type":"array"},"propertyNames":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"type":"object"},"repository":{"format":"uri","type":"string"},"version":{"pattern":"^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$","type":"string"}},"required":["id","name","description","version","repository"],"type":"object"}},"$id":"https://cdn.jsdelivr.net/npm/keepset@0.
|
|
1
|
+
{"$defs":{"Manifest":{"additionalProperties":false,"properties":{"description":{"minLength":1,"type":"string"},"id":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"lineage":{"additionalProperties":false,"properties":{"catalogue":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"repository":{"format":"uri","type":"string"},"version":{"pattern":"^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$","type":"string"}},"required":["catalogue","version","repository"],"type":"object"},"name":{"minLength":1,"type":"string"},"namespaceAliases":{"additionalProperties":{"items":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"minItems":1,"type":"array"},"propertyNames":{"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]*$","type":"string"},"type":"object"},"repository":{"format":"uri","type":"string"},"version":{"pattern":"^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$","type":"string"}},"required":["id","name","description","version","repository"],"type":"object"}},"$id":"https://cdn.jsdelivr.net/npm/keepset@0.26.0/schemas/manifest.schema.json","$ref":"#/$defs/Manifest","$schema":"https://json-schema.org/draft/2020-12/schema"}
|