keepset 0.24.0 → 0.25.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.
@@ -521,6 +521,14 @@ const ParserSchema = z.discriminatedUnion("format", [
521
521
  format: z.literal("solomon"),
522
522
  encoding: EncodingSchema
523
523
  }).strict(),
524
+ z.object({
525
+ format: z.literal("top"),
526
+ encoding: EncodingSchema
527
+ }).strict(),
528
+ z.object({
529
+ format: z.literal("toptw"),
530
+ encoding: EncodingSchema
531
+ }).strict(),
524
532
  z.object({
525
533
  format: z.literal("csv-table"),
526
534
  encoding: EncodingSchema,
@@ -980,7 +988,7 @@ var catalogue_default = {
980
988
  "id": "keepset",
981
989
  "name": "keepset",
982
990
  "description": "The keepset catalogue: datasets with machine-readable recipes that fetch each one and normalise it into its category's target shape.",
983
- "version": "1.12.0",
991
+ "version": "1.13.0",
984
992
  "repository": "https://github.com/Mearman/keepset",
985
993
  "namespaceAliases": {
986
994
  "networkrepository": ["nr"],
@@ -8635,7 +8643,7 @@ var catalogue_default = {
8635
8643
  "location",
8636
8644
  "travelTime"
8637
8645
  ],
8638
- "category": "or/v1",
8646
+ "category": "or-set/v1",
8639
8647
  "sources": [{
8640
8648
  "url": "https://www.mech.kuleuven.be/en/mim/op",
8641
8649
  "retrieved": "2026-10-19",
@@ -8648,11 +8656,75 @@ var catalogue_default = {
8648
8656
  "licence": { "kind": "unrecorded" },
8649
8657
  "citations": [],
8650
8658
  "recipe": {
8651
- "status": "not-fetchable",
8652
- "reason": "The download is a collection of 60 text instance files of one 100 node point set under different budgets (planar coordinates and a prize, with no time quantities), and a collection is more than one or/v1 document, so no recipe reads it."
8659
+ "status": "fetchable",
8660
+ "source": 1,
8661
+ "archive": {
8662
+ "kind": "zip",
8663
+ "members": { "extensions": [".txt"] }
8664
+ },
8665
+ "parser": {
8666
+ "format": "top",
8667
+ "encoding": "utf-8"
8668
+ }
8653
8669
  },
8654
- "crosswalk": { "file": "crosswalks/or-v1/nodes.json" },
8655
- "expectedCounts": {},
8670
+ "crosswalk": {
8671
+ "source": "top",
8672
+ "target": "or-set/v1",
8673
+ "rules": [
8674
+ {
8675
+ "op": "move",
8676
+ "from": "meta",
8677
+ "to": "meta"
8678
+ },
8679
+ {
8680
+ "op": "move",
8681
+ "from": "members[].id",
8682
+ "to": "instances[].id"
8683
+ },
8684
+ {
8685
+ "op": "move",
8686
+ "from": "members[].meta.points",
8687
+ "to": "instances[].meta.points"
8688
+ },
8689
+ {
8690
+ "op": "move",
8691
+ "from": "members[].meta.paths",
8692
+ "to": "instances[].meta.paths"
8693
+ },
8694
+ {
8695
+ "op": "move",
8696
+ "from": "members[].meta.budget",
8697
+ "to": "instances[].meta.budget"
8698
+ },
8699
+ {
8700
+ "op": "move",
8701
+ "from": "members[].nodes[].id",
8702
+ "to": "instances[].nodes[].id"
8703
+ },
8704
+ {
8705
+ "op": "move",
8706
+ "from": "members[].nodes[].score",
8707
+ "to": "instances[].nodes[].prize"
8708
+ },
8709
+ {
8710
+ "op": "move",
8711
+ "from": "members[].nodes[].x",
8712
+ "to": "instances[].nodes[].x"
8713
+ },
8714
+ {
8715
+ "op": "move",
8716
+ "from": "members[].nodes[].y",
8717
+ "to": "instances[].nodes[].y"
8718
+ },
8719
+ {
8720
+ "op": "move",
8721
+ "from": "members[].nodes[].role",
8722
+ "to": "instances[].nodes[].role"
8723
+ }
8724
+ ],
8725
+ "oneWay": []
8726
+ },
8727
+ "expectedCounts": { "instances": 60 },
8656
8728
  "properties": { "surveyId": "or-0" }
8657
8729
  },
8658
8730
  {
@@ -8669,7 +8741,7 @@ var catalogue_default = {
8669
8741
  "duration",
8670
8742
  "travelTime"
8671
8743
  ],
8672
- "category": "or/v1",
8744
+ "category": "or-set/v1",
8673
8745
  "sources": [{
8674
8746
  "url": "https://www.mech.kuleuven.be/en/mim/op",
8675
8747
  "retrieved": "2026-10-19",
@@ -8682,12 +8754,89 @@ var catalogue_default = {
8682
8754
  "licence": { "kind": "unrecorded" },
8683
8755
  "citations": [],
8684
8756
  "recipe": {
8685
- "status": "not-fetchable",
8686
- "reason": "The download is a collection of Solomon style time window instance files (planar coordinates, service durations, prizes and windows in abstract units, not seconds), and a collection is more than one or/v1 document, so no recipe reads it."
8757
+ "status": "fetchable",
8758
+ "source": 1,
8759
+ "archive": {
8760
+ "kind": "zip",
8761
+ "members": { "extensions": [".txt"] }
8762
+ },
8763
+ "parser": {
8764
+ "format": "toptw",
8765
+ "encoding": "utf-8"
8766
+ }
8687
8767
  },
8688
- "crosswalk": { "file": "crosswalks/or-v1/nodes.json" },
8689
- "expectedCounts": {},
8690
- "properties": { "surveyId": "or-1" }
8768
+ "crosswalk": {
8769
+ "source": "toptw",
8770
+ "target": "or-set/v1",
8771
+ "rules": [
8772
+ {
8773
+ "op": "move",
8774
+ "from": "meta",
8775
+ "to": "meta"
8776
+ },
8777
+ {
8778
+ "op": "move",
8779
+ "from": "members[].id",
8780
+ "to": "instances[].id"
8781
+ },
8782
+ {
8783
+ "op": "move",
8784
+ "from": "members[].meta.paths",
8785
+ "to": "instances[].meta.paths"
8786
+ },
8787
+ {
8788
+ "op": "move",
8789
+ "from": "members[].meta.customers",
8790
+ "to": "instances[].meta.customers"
8791
+ },
8792
+ {
8793
+ "op": "move",
8794
+ "from": "members[].meta.capacity",
8795
+ "to": "instances[].meta.capacity"
8796
+ },
8797
+ {
8798
+ "op": "move",
8799
+ "from": "members[].nodes[].id",
8800
+ "to": "instances[].nodes[].id"
8801
+ },
8802
+ {
8803
+ "op": "move",
8804
+ "from": "members[].nodes[].close",
8805
+ "to": "instances[].nodes[].deadline"
8806
+ },
8807
+ {
8808
+ "op": "move",
8809
+ "from": "members[].nodes[].profit",
8810
+ "to": "instances[].nodes[].prize"
8811
+ },
8812
+ {
8813
+ "op": "move",
8814
+ "from": "members[].nodes[].x",
8815
+ "to": "instances[].nodes[].x"
8816
+ },
8817
+ {
8818
+ "op": "move",
8819
+ "from": "members[].nodes[].y",
8820
+ "to": "instances[].nodes[].y"
8821
+ },
8822
+ {
8823
+ "op": "move",
8824
+ "from": "members[].nodes[].service",
8825
+ "to": "instances[].nodes[].service"
8826
+ },
8827
+ {
8828
+ "op": "move",
8829
+ "from": "members[].nodes[].open",
8830
+ "to": "instances[].nodes[].open"
8831
+ }
8832
+ ],
8833
+ "oneWay": []
8834
+ },
8835
+ "expectedCounts": { "instances": 29 },
8836
+ "properties": {
8837
+ "surveyId": "or-1",
8838
+ "timeUnit": "abstract units"
8839
+ }
8691
8840
  },
8692
8841
  {
8693
8842
  "id": "lastfm-hgb",
@@ -146,6 +146,18 @@ declare const ParserSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
146
146
  "utf-8": "utf-8";
147
147
  latin1: "latin1";
148
148
  }>;
149
+ }, z.core.$strict>, z.ZodObject<{
150
+ format: z.ZodLiteral<"top">;
151
+ encoding: z.ZodEnum<{
152
+ "utf-8": "utf-8";
153
+ latin1: "latin1";
154
+ }>;
155
+ }, z.core.$strict>, z.ZodObject<{
156
+ format: z.ZodLiteral<"toptw">;
157
+ encoding: z.ZodEnum<{
158
+ "utf-8": "utf-8";
159
+ latin1: "latin1";
160
+ }>;
149
161
  }, z.core.$strict>, z.ZodObject<{
150
162
  format: z.ZodLiteral<"csv-table">;
151
163
  encoding: z.ZodEnum<{
@@ -265,6 +277,18 @@ declare const RecipeSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
265
277
  "utf-8": "utf-8";
266
278
  latin1: "latin1";
267
279
  }>;
280
+ }, z.core.$strict>, z.ZodObject<{
281
+ format: z.ZodLiteral<"top">;
282
+ encoding: z.ZodEnum<{
283
+ "utf-8": "utf-8";
284
+ latin1: "latin1";
285
+ }>;
286
+ }, z.core.$strict>, z.ZodObject<{
287
+ format: z.ZodLiteral<"toptw">;
288
+ encoding: z.ZodEnum<{
289
+ "utf-8": "utf-8";
290
+ latin1: "latin1";
291
+ }>;
268
292
  }, z.core.$strict>, z.ZodObject<{
269
293
  format: z.ZodLiteral<"csv-table">;
270
294
  encoding: z.ZodEnum<{
@@ -439,6 +463,18 @@ declare const EntrySchema: z.ZodObject<{
439
463
  "utf-8": "utf-8";
440
464
  latin1: "latin1";
441
465
  }>;
466
+ }, z.core.$strict>, z.ZodObject<{
467
+ format: z.ZodLiteral<"top">;
468
+ encoding: z.ZodEnum<{
469
+ "utf-8": "utf-8";
470
+ latin1: "latin1";
471
+ }>;
472
+ }, z.core.$strict>, z.ZodObject<{
473
+ format: z.ZodLiteral<"toptw">;
474
+ encoding: z.ZodEnum<{
475
+ "utf-8": "utf-8";
476
+ latin1: "latin1";
477
+ }>;
442
478
  }, z.core.$strict>, z.ZodObject<{
443
479
  format: z.ZodLiteral<"csv-table">;
444
480
  encoding: z.ZodEnum<{
@@ -514,19 +550,19 @@ declare const EntrySchema: z.ZodObject<{
514
550
  status: "fetchable";
515
551
  source: number;
516
552
  archive: {
517
- kind: "none";
518
- } | {
519
- kind: "gzip";
520
- } | {
521
553
  kind: "zip" | "tar" | "tar.gz";
522
- member: {
554
+ members: {
523
555
  path: string;
524
556
  } | {
525
557
  extensions: string[];
526
558
  };
559
+ } | {
560
+ kind: "none";
561
+ } | {
562
+ kind: "gzip";
527
563
  } | {
528
564
  kind: "zip" | "tar" | "tar.gz";
529
- members: {
565
+ member: {
530
566
  path: string;
531
567
  } | {
532
568
  extensions: string[];
@@ -577,6 +613,12 @@ declare const EntrySchema: z.ZodObject<{
577
613
  } | {
578
614
  format: "solomon";
579
615
  encoding: "utf-8" | "latin1";
616
+ } | {
617
+ format: "top";
618
+ encoding: "utf-8" | "latin1";
619
+ } | {
620
+ format: "toptw";
621
+ encoding: "utf-8" | "latin1";
580
622
  };
581
623
  paging?: {
582
624
  kind: "arcgis-query";
@@ -826,6 +868,18 @@ declare const CatalogueIndexSchema: z.ZodObject<{
826
868
  "utf-8": "utf-8";
827
869
  latin1: "latin1";
828
870
  }>;
871
+ }, z.core.$strict>, z.ZodObject<{
872
+ format: z.ZodLiteral<"top">;
873
+ encoding: z.ZodEnum<{
874
+ "utf-8": "utf-8";
875
+ latin1: "latin1";
876
+ }>;
877
+ }, z.core.$strict>, z.ZodObject<{
878
+ format: z.ZodLiteral<"toptw">;
879
+ encoding: z.ZodEnum<{
880
+ "utf-8": "utf-8";
881
+ latin1: "latin1";
882
+ }>;
829
883
  }, z.core.$strict>, z.ZodObject<{
830
884
  format: z.ZodLiteral<"csv-table">;
831
885
  encoding: z.ZodEnum<{
@@ -901,19 +955,19 @@ declare const CatalogueIndexSchema: z.ZodObject<{
901
955
  status: "fetchable";
902
956
  source: number;
903
957
  archive: {
904
- kind: "none";
905
- } | {
906
- kind: "gzip";
907
- } | {
908
958
  kind: "zip" | "tar" | "tar.gz";
909
- member: {
959
+ members: {
910
960
  path: string;
911
961
  } | {
912
962
  extensions: string[];
913
963
  };
964
+ } | {
965
+ kind: "none";
966
+ } | {
967
+ kind: "gzip";
914
968
  } | {
915
969
  kind: "zip" | "tar" | "tar.gz";
916
- members: {
970
+ member: {
917
971
  path: string;
918
972
  } | {
919
973
  extensions: string[];
@@ -964,6 +1018,12 @@ declare const CatalogueIndexSchema: z.ZodObject<{
964
1018
  } | {
965
1019
  format: "solomon";
966
1020
  encoding: "utf-8" | "latin1";
1021
+ } | {
1022
+ format: "top";
1023
+ encoding: "utf-8" | "latin1";
1024
+ } | {
1025
+ format: "toptw";
1026
+ encoding: "utf-8" | "latin1";
967
1027
  };
968
1028
  paging?: {
969
1029
  kind: "arcgis-query";
@@ -1042,19 +1102,19 @@ declare const CatalogueIndexSchema: z.ZodObject<{
1042
1102
  status: "fetchable";
1043
1103
  source: number;
1044
1104
  archive: {
1045
- kind: "none";
1046
- } | {
1047
- kind: "gzip";
1048
- } | {
1049
1105
  kind: "zip" | "tar" | "tar.gz";
1050
- member: {
1106
+ members: {
1051
1107
  path: string;
1052
1108
  } | {
1053
1109
  extensions: string[];
1054
1110
  };
1111
+ } | {
1112
+ kind: "none";
1113
+ } | {
1114
+ kind: "gzip";
1055
1115
  } | {
1056
1116
  kind: "zip" | "tar" | "tar.gz";
1057
- members: {
1117
+ member: {
1058
1118
  path: string;
1059
1119
  } | {
1060
1120
  extensions: string[];
@@ -1105,6 +1165,12 @@ declare const CatalogueIndexSchema: z.ZodObject<{
1105
1165
  } | {
1106
1166
  format: "solomon";
1107
1167
  encoding: "utf-8" | "latin1";
1168
+ } | {
1169
+ format: "top";
1170
+ encoding: "utf-8" | "latin1";
1171
+ } | {
1172
+ format: "toptw";
1173
+ encoding: "utf-8" | "latin1";
1108
1174
  };
1109
1175
  paging?: {
1110
1176
  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-BfqmrAvf.js";
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-zC2eMs6y.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-BWINQKLQ.js";
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-Dkvod55t.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-BfqmrAvf.js";
1
+ import { G as Entry, T as Dataset, at as Snapshot, i as CategoryTarget, st as Source } from "../categories-zC2eMs6y.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-BWINQKLQ.js";
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-Dkvod55t.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$1 = /[+-]?(?:\d+\.?\d*|\.\d+)(?:[Ee][+-]?\d+)?/y;
107
+ const NUMBER$3 = /[+-]?(?:\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$1, text, position) : void 0;
158
+ const number = key === void 0 ? matchAt(NUMBER$3, 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 = "solomon";
836
+ const FORMAT$2 = "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 = /^-?\d+(?:\.\d+)?$/;
838
+ const NUMBER$2 = /^-?\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 = /^-?\d+(?:\.\d+)?$/;
844
844
  * @returns The number.
845
845
  * @throws NativeParseError when the token is not a decimal number.
846
846
  */
847
- function numberOf(token, line, what) {
848
- if (!NUMBER.test(token)) throw new NativeParseError(FORMAT, line, `expected ${what}, found ${JSON.stringify(token)}`);
847
+ function numberOf$1(token, line, what) {
848
+ if (!NUMBER$2.test(token)) throw new NativeParseError(FORMAT$2, 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, 1, "expected the instance name on the first line");
861
+ if (name === "") throw new NativeParseError(FORMAT$2, 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, line, `expected VEHICLE or CUSTOMER, found ${JSON.stringify(trimmed)}`);
877
+ if (section === "preamble") throw new NativeParseError(FORMAT$2, 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, line, `expected the vehicle count and capacity, found ${JSON.stringify(trimmed)}`);
886
- meta.vehicles = numberOf(vehicles, line, "the vehicle count");
887
- meta.capacity = numberOf(capacity, line, "the vehicle capacity");
885
+ if (vehicles === void 0 || capacity === void 0 || extra.length > 0) throw new NativeParseError(FORMAT$2, line, `expected the vehicle count and capacity, found ${JSON.stringify(trimmed)}`);
886
+ meta.vehicles = numberOf$1(vehicles, line, "the vehicle count");
887
+ meta.capacity = numberOf$1(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, line, `expected seven numbers (id, x, y, demand, ready, due, service), found ${JSON.stringify(trimmed)}`);
892
- if (!/^\d+$/.test(id)) throw new NativeParseError(FORMAT, line, `expected a whole number node id, found ${JSON.stringify(id)}`);
893
- if (seen.has(id)) throw new NativeParseError(FORMAT, line, `node ${id} appears twice`);
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$2, line, `expected seven numbers (id, x, y, demand, ready, due, service), found ${JSON.stringify(trimmed)}`);
892
+ if (!/^\d+$/.test(id)) throw new NativeParseError(FORMAT$2, line, `expected a whole number node id, found ${JSON.stringify(id)}`);
893
+ if (seen.has(id)) throw new NativeParseError(FORMAT$2, line, `node ${id} appears twice`);
894
894
  seen.add(id);
895
895
  nodes.push({
896
896
  id,
897
- x: numberOf(x, line, "x"),
898
- y: numberOf(y, line, "y"),
899
- demand: numberOf(demand, line, "the demand"),
900
- ready: numberOf(ready, line, "the ready time"),
901
- due: numberOf(due, line, "the due date"),
902
- service: numberOf(service, line, "the service time")
897
+ x: numberOf$1(x, line, "x"),
898
+ y: numberOf$1(y, line, "y"),
899
+ demand: numberOf$1(demand, line, "the demand"),
900
+ ready: numberOf$1(ready, line, "the ready time"),
901
+ due: numberOf$1(due, line, "the due date"),
902
+ service: numberOf$1(service, line, "the service time")
903
903
  });
904
904
  }
905
- if (section !== "customer") throw new NativeParseError(FORMAT, all.length, "expected a CUSTOMER section");
906
- if (nodes.length === 0) throw new NativeParseError(FORMAT, all.length, "the CUSTOMER section has no rows");
907
- if (meta.vehicles === void 0 || meta.capacity === void 0) throw new NativeParseError(FORMAT, all.length, "expected a VEHICLE section with the vehicle count and capacity");
905
+ if (section !== "customer") throw new NativeParseError(FORMAT$2, all.length, "expected a CUSTOMER section");
906
+ if (nodes.length === 0) throw new NativeParseError(FORMAT$2, all.length, "the CUSTOMER section has no rows");
907
+ if (meta.vehicles === void 0 || meta.capacity === void 0) throw new NativeParseError(FORMAT$2, all.length, "expected a VEHICLE section with the vehicle count and capacity");
908
908
  return {
909
909
  meta: {
910
910
  name: meta.name,
@@ -915,6 +915,145 @@ function parseSolomon(text) {
915
915
  };
916
916
  }
917
917
  //#endregion
918
+ //#region src/parsers/top.ts
919
+ const FORMAT$1 = "top";
920
+ /** The header lines before the first point: `n`, `m` and `tmax`. */
921
+ const HEADER_LINES = 3;
922
+ const NUMBER$1 = /^-?\d+(?:\.\d+)?$/;
923
+ /**
924
+ * Reads the value of a header line `<key> <number>`.
925
+ * @param text - The line.
926
+ * @param key - The key it must start with.
927
+ * @param line - The 1-based line, for the error.
928
+ * @returns The number.
929
+ * @throws NativeParseError when the line is not the key and one number.
930
+ */
931
+ function headerOf(text, key, line) {
932
+ const [name, value, ...extra] = (text ?? "").trim().split(/\s+/);
933
+ if (name !== key || value === void 0 || extra.length > 0 || !NUMBER$1.test(value)) throw new NativeParseError(FORMAT$1, line, `expected "${key} <number>", found ${JSON.stringify((text ?? "").trim())}`);
934
+ return Number(value);
935
+ }
936
+ /**
937
+ * Parses a team orienteering problem instance (Chao, Golden and Wasil, as the KU Leuven pages describe it): `n <points>`, `m <paths>` and `tmax <budget>` on three lines, then one row of position and score for each point. The first point is where the paths start and the last is where they end, and the rest are to visit; the file has no ids, so a point's id is its zero-based row number. Columns are separated by any run of spaces or tabs, and blank or whitespace only lines are skipped. The positions and the budget are in the same planar unit, which the format does not name.
938
+ * @param text - The file text.
939
+ * @returns The instance: its point count, path count and per-path budget as `meta`, and its nodes in file order.
940
+ * @throws NativeParseError naming the line for a missing or misordered header line, a row that is not three numbers, or a row count that is not the point count.
941
+ */
942
+ function parseTop(text) {
943
+ const all = lines(text).map((raw, index) => ({
944
+ line: index + 1,
945
+ text: raw.trim()
946
+ })).filter((entry) => entry.text !== "");
947
+ const [first, second, third] = all;
948
+ const rows = all.slice(HEADER_LINES);
949
+ const points = headerOf(first?.text, "n", first?.line ?? 1);
950
+ const paths = headerOf(second?.text, "m", second?.line ?? 2);
951
+ const budget = headerOf(third?.text, "tmax", third?.line ?? HEADER_LINES);
952
+ if (!Number.isInteger(points) || points < 2) throw new NativeParseError(FORMAT$1, 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$1, all[all.length - 1]?.line ?? 1, `the header gives ${String(points)} points, found ${String(rows.length)} rows`);
954
+ const nodes = rows.map((row, index) => {
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$1.test(x) || !NUMBER$1.test(y) || !NUMBER$1.test(score)) throw new NativeParseError(FORMAT$1, row.line, `expected three numbers (x, y, score), found ${JSON.stringify(row.text)}`);
957
+ return {
958
+ id: String(index),
959
+ x: Number(x),
960
+ y: Number(y),
961
+ score: Number(score),
962
+ role: index === 0 ? "start" : index === points - 1 ? "end" : "visit"
963
+ };
964
+ });
965
+ return {
966
+ meta: {
967
+ points,
968
+ paths,
969
+ budget
970
+ },
971
+ nodes
972
+ };
973
+ }
974
+ //#endregion
975
+ //#region src/parsers/toptw.ts
976
+ const FORMAT = "toptw";
977
+ /** How many numbers the first header line holds (k, paths, customers, t) and the second (D, capacity). */
978
+ const FIRST_HEADER_NUMBERS = 4;
979
+ const SECOND_HEADER_NUMBERS = 2;
980
+ /** Where a node row's fields sit: the length of the unused list is the seventh token, the list follows, and the window's opening and closing come after it. A row without a list is the first token to the window's closing, so it holds this many numbers plus the list's length. */
981
+ const LIST_LENGTH_AT = 6;
982
+ const LIST_STARTS_AT = 7;
983
+ const ROW_NUMBERS_BESIDE_LIST = 9;
984
+ const NUMBER = /^-?\d+(?:\.\d+)?$/;
985
+ /**
986
+ * Reads a token as a finite number.
987
+ * @param token - The token.
988
+ * @param line - The 1-based line, for the error.
989
+ * @param what - What the token should be, for the error.
990
+ * @returns The number.
991
+ * @throws NativeParseError when the token is not a decimal number.
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)}`);
995
+ return Number(token);
996
+ }
997
+ /**
998
+ * Reads a line of a given number of numbers.
999
+ * @param text - The line.
1000
+ * @param count - How many numbers it holds.
1001
+ * @param line - The 1-based line, for the error.
1002
+ * @param what - What the line should be, for the error.
1003
+ * @returns The numbers.
1004
+ * @throws NativeParseError when the line does not hold exactly that many numbers.
1005
+ */
1006
+ function numbersOf(text, count, line, what) {
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));
1010
+ }
1011
+ /**
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.
1013
+ * @param text - The file text.
1014
+ * @returns The instance: its path count, customer count and capacity as `meta`, and its nodes in file order.
1015
+ * @throws NativeParseError naming the line for a header or row that is not made of the numbers the format has, a row whose length does not match its list, a repeated node id, or a row count that is not the customer count plus one.
1016
+ */
1017
+ function parseToptw(text) {
1018
+ const all = lines(text).map((raw, index) => ({
1019
+ line: index + 1,
1020
+ text: raw.trim()
1021
+ })).filter((entry) => entry.text !== "");
1022
+ const [first, second, ...rows] = all;
1023
+ if (first === void 0 || second === void 0) throw new NativeParseError(FORMAT, 1, "expected the two header lines");
1024
+ const [, paths, customers] = numbersOf(first.text, FIRST_HEADER_NUMBERS, first.line, "four numbers (k, paths, customers, t)");
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");
1027
+ const seen = /* @__PURE__ */ new Set();
1028
+ const nodes = rows.map((row) => {
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)}`);
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`);
1035
+ seen.add(id);
1036
+ return {
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")
1044
+ };
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)}`);
1047
+ return {
1048
+ meta: {
1049
+ paths,
1050
+ customers,
1051
+ capacity
1052
+ },
1053
+ nodes
1054
+ };
1055
+ }
1056
+ //#endregion
918
1057
  //#region src/parsers/parse-native.ts
919
1058
  /** 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. */
920
1059
  const LATIN1_CHUNK = 32768;
@@ -971,6 +1110,8 @@ function parseNative(bytes, parser) {
971
1110
  if (parser.format === "matrix-market") return parseMatrixMarket(text);
972
1111
  if (parser.format === "gml") return parseGml(text);
973
1112
  if (parser.format === "solomon") return parseSolomon(text);
1113
+ if (parser.format === "top") return parseTop(text);
1114
+ if (parser.format === "toptw") return parseToptw(text);
974
1115
  return parsePajek(text);
975
1116
  }
976
1117
  /** The ustar header layout (POSIX.1-1988, pax(1) "ustar Interchange Format"): each field's byte offset and length. */
@@ -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.24.0";
7
+ var version = "0.25.0";
8
8
  const usage = `Usage: keepset <command> [options]
9
9
 
10
10
  Commands:
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "keepset",
3
3
  "description": "Library, CLI and statically generated catalogue for dataset fetch-and-normalise recipes",
4
- "version": "0.24.0",
4
+ "version": "0.25.0",
5
5
  "bin": {
6
6
  "keepset": "./dist-cli/keepset.mjs"
7
7
  },
@@ -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":{"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.24.0/schemas/entry.schema.json","$ref":"#/$defs/Entry","$schema":"https://json-schema.org/draft/2020-12/schema"}
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.25.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.24.0/schemas/manifest.schema.json","$ref":"#/$defs/Manifest","$schema":"https://json-schema.org/draft/2020-12/schema"}
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.25.0/schemas/manifest.schema.json","$ref":"#/$defs/Manifest","$schema":"https://json-schema.org/draft/2020-12/schema"}