keepset 0.28.0 → 0.29.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.
@@ -4,6 +4,8 @@ import { z } from "zod";
4
4
  /** A stable identifier: an entry id, a catalogue id. It starts with a letter or digit, so no id can be `__proto__` or any other name that begins with an underscore. Entry ids stay the same across forks, which is what lets two catalogues be compared entry by entry. */
5
5
  declare const IdSchema: z.ZodString;
6
6
  /** A key of an entry's `properties` or `expectedCounts` record: an identifier that starts with a letter, so it can never be `__proto__` or another name Object.prototype reacts to on assignment. */
7
+ /** A subject: the field of study a dataset is relevant to, as a lowercase slug of words joined by hyphens, such as `operations-research`. It is separate from the entry's domain (its topic), its tags (the node fields it carries) and its namespace (the source it comes from), and it is the value a search filters by. */
8
+ declare const SubjectSchema: z.ZodString;
7
9
  /** An alias: an id, or a path of ids joined by `/` such as `foo/graphs/bar`. A bare id is a name inside the entry's own namespace; a path is a name of its own, in the group its leading segments name. The segment pattern repeats the one in `IdSchema` so that each part of a path is an id. */
8
10
  declare const AliasSchema: z.ZodString;
9
11
  /** The path a dataset sits under in a collection, outermost segment first, such as `["suitesparse", "gset"]`. Each segment is an id, so a segment can never contain the `/` that joins a namespace to a name. */
@@ -401,7 +403,7 @@ type CrosswalkReference = z.infer<typeof CrosswalkReferenceSchema>;
401
403
  /** The meta keys a fetched result takes from the entry's own descriptor, which its `properties` therefore may not also set. */
402
404
  declare const RESERVED_META_KEYS: readonly ["id", "name"];
403
405
  /**
404
- * One catalogue entry: the descriptor (id, optional namespace and aliases, name, description, domain, tags), the category whose target the entry resolves to, where the bytes come from, the licence and citations, the recipe, the crosswalk, the counts a fetched result is expected to have and the dataset's recorded properties. The kind of data is the category's (`kindOf(category)`), never a second field that could disagree with it.
406
+ * One catalogue entry: the descriptor (id, optional namespace and aliases, name, description, domain, subjects, tags), the category whose target the entry resolves to, where the bytes come from, the licence and citations, the recipe, the crosswalk, the counts a fetched result is expected to have and the dataset's recorded properties. The kind of data is the category's (`kindOf(category)`), never a second field that could disagree with it.
405
407
  */
406
408
  declare const EntrySchema: z.ZodObject<{
407
409
  id: z.ZodString;
@@ -410,11 +412,11 @@ declare const EntrySchema: z.ZodObject<{
410
412
  name: z.ZodString;
411
413
  description: z.ZodOptional<z.ZodString>;
412
414
  domain: z.ZodOptional<z.ZodString>;
415
+ subjects: z.ZodOptional<z.ZodArray<z.ZodString>>;
413
416
  tags: z.ZodArray<z.ZodString>;
414
417
  category: z.ZodEnum<{
415
418
  "graph/v1": "graph/v1";
416
419
  "or/v1": "or/v1";
417
- "or-set/v1": "or-set/v1";
418
420
  }>;
419
421
  sources: z.ZodArray<z.ZodObject<{
420
422
  url: z.ZodURL;
@@ -610,7 +612,7 @@ declare const EntrySchema: z.ZodObject<{
610
612
  id: string;
611
613
  name: string;
612
614
  tags: string[];
613
- category: "graph/v1" | "or/v1" | "or-set/v1";
615
+ category: "graph/v1" | "or/v1";
614
616
  sources: {
615
617
  url: string;
616
618
  retrieved: string;
@@ -751,6 +753,7 @@ declare const EntrySchema: z.ZodObject<{
751
753
  aliases?: string[] | undefined;
752
754
  description?: string | undefined;
753
755
  domain?: string | undefined;
756
+ subjects?: string[] | undefined;
754
757
  };
755
758
  };
756
759
  type Entry = z.infer<typeof EntrySchema>;
@@ -853,11 +856,11 @@ declare const CatalogueIndexSchema: z.ZodObject<{
853
856
  name: z.ZodString;
854
857
  description: z.ZodOptional<z.ZodString>;
855
858
  domain: z.ZodOptional<z.ZodString>;
859
+ subjects: z.ZodOptional<z.ZodArray<z.ZodString>>;
856
860
  tags: z.ZodArray<z.ZodString>;
857
861
  category: z.ZodEnum<{
858
862
  "graph/v1": "graph/v1";
859
863
  "or/v1": "or/v1";
860
- "or-set/v1": "or-set/v1";
861
864
  }>;
862
865
  sources: z.ZodArray<z.ZodObject<{
863
866
  url: z.ZodURL;
@@ -1053,7 +1056,7 @@ declare const CatalogueIndexSchema: z.ZodObject<{
1053
1056
  id: string;
1054
1057
  name: string;
1055
1058
  tags: string[];
1056
- category: "graph/v1" | "or/v1" | "or-set/v1";
1059
+ category: "graph/v1" | "or/v1";
1057
1060
  sources: {
1058
1061
  url: string;
1059
1062
  retrieved: string;
@@ -1194,6 +1197,7 @@ declare const CatalogueIndexSchema: z.ZodObject<{
1194
1197
  aliases?: string[] | undefined;
1195
1198
  description?: string | undefined;
1196
1199
  domain?: string | undefined;
1200
+ subjects?: string[] | undefined;
1197
1201
  };
1198
1202
  }>;
1199
1203
  }, z.core.$strict> & {
@@ -1216,7 +1220,7 @@ declare const CatalogueIndexSchema: z.ZodObject<{
1216
1220
  id: string;
1217
1221
  name: string;
1218
1222
  tags: string[];
1219
- category: "graph/v1" | "or/v1" | "or-set/v1";
1223
+ category: "graph/v1" | "or/v1";
1220
1224
  sources: {
1221
1225
  url: string;
1222
1226
  retrieved: string;
@@ -1357,6 +1361,7 @@ declare const CatalogueIndexSchema: z.ZodObject<{
1357
1361
  aliases?: string[] | undefined;
1358
1362
  description?: string | undefined;
1359
1363
  domain?: string | undefined;
1364
+ subjects?: string[] | undefined;
1360
1365
  }[];
1361
1366
  };
1362
1367
  };
@@ -1376,9 +1381,11 @@ interface DatasetQuery {
1376
1381
  readonly category?: string;
1377
1382
  /** The entry's domain, matched exactly. */
1378
1383
  readonly domain?: string;
1384
+ /** A subject slug such as `operations-research`, matched exactly against the entry's subjects. */
1385
+ readonly subject?: string;
1379
1386
  /** A group path such as `suitesparse` or `suitesparse/gset`, in which any segment may be an alias the manifest gives it: matches the entries in that group, in any group beneath it, and the entries a path alias files there. */
1380
1387
  readonly namespace?: string;
1381
- /** Text that must appear, ignoring case, in the entry's id, an alias, one of its groups, name, description, domain or one of its tags. */
1388
+ /** Text that must appear, ignoring case, in the entry's id, an alias, one of its groups, name, description, domain, one of its subjects or one of its tags. */
1382
1389
  readonly text?: string;
1383
1390
  }
1384
1391
  /** One namespace in the tree of groups: its path, its last segment, and how many distinct entries sit in it or in any namespace beneath it. */
@@ -1465,84 +1472,29 @@ declare const GraphV1Schema: z.ZodObject<{
1465
1472
  };
1466
1473
  type GraphV1 = z.infer<typeof GraphV1Schema>;
1467
1474
  //#endregion
1468
- //#region src/targets/or-set-v1.d.ts
1469
- /** One instance of a set: an or/v1 instance, `{ meta, nodes }`, with the id that names it within the set (for a collection read from an archive, the member's path). */
1470
- declare const OrInstanceSchema: z.ZodObject<{
1471
- id: z.ZodString;
1472
- meta: z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, unknown>;
1473
- nodes: z.ZodArray<z.ZodObject<{
1474
- id: z.ZodString;
1475
- lat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1476
- lon: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1477
- x: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1478
- y: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1479
- prize: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1480
- prizeProbability: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1481
- duration: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1482
- travelTime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1483
- skill: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1484
- territory: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1485
- status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1486
- opened: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1487
- closed: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1488
- deadline: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
1489
- }, z.core.$loose>>;
1490
- }, z.core.$strict>;
1491
- type OrInstance = z.infer<typeof OrInstanceSchema>;
1475
+ //#region src/targets/json-scalar.d.ts
1476
+ /** A JSON scalar: the only values a target's metadata may hold, so `meta` stays a flat record any consumer can tabulate. `z.number()` already rejects NaN and the infinities, which JSON cannot carry. */
1477
+ declare const JsonScalarSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
1478
+ type JsonScalar = z.infer<typeof JsonScalarSchema>;
1479
+ //#endregion
1480
+ //#region src/targets/collection.d.ts
1481
+ /** One member of a collection: the id that names it within the set (for a collection read from an archive, the path of the member it came from) beside the fields of the category's own document, which are the instance's `meta`, nodes and so on. */
1482
+ type Instance<Document extends object> = {
1483
+ readonly id: string;
1484
+ } & Document;
1485
+ /** A collection of documents of one category: `{ meta, instances }`, where `meta` is the entry's own metadata and each instance is a document of the category under an id. */
1486
+ interface Collection<Document extends object> {
1487
+ readonly meta: Readonly<Record<string, JsonScalar>>;
1488
+ readonly instances: readonly Instance<Document>[];
1489
+ }
1492
1490
  /**
1493
- * The or-set/v1 normalisation target: `{ meta, instances }`, a collection of operations-research instances such as a benchmark suite, each instance an or/v1 document (`{ meta, nodes }`) under an id of its own. Beyond the shapes it checks that instance ids are unique in the set and node ids unique within each instance. A node id need not be unique across instances, because every instance numbers its own nodes.
1491
+ * The schema of a collection of documents of a category, derived from the category's own document schema, so a category needs nothing of its own to be collected. Beyond each instance being a valid document, the instance ids must be unique in the set; node ids and the like stay unique only within an instance, because every instance numbers its own.
1492
+ * @param document - The category's document schema.
1493
+ * @returns The collection schema, with the attached type guard.
1494
1494
  */
1495
- declare const OrSetV1Schema: z.ZodObject<{
1496
- meta: z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, unknown>;
1497
- instances: z.ZodArray<z.ZodObject<{
1498
- id: z.ZodString;
1499
- meta: z.ZodPreprocess<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>>, unknown>;
1500
- nodes: z.ZodArray<z.ZodObject<{
1501
- id: z.ZodString;
1502
- lat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1503
- lon: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1504
- x: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1505
- y: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1506
- prize: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1507
- prizeProbability: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1508
- duration: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1509
- travelTime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
1510
- skill: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1511
- territory: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1512
- status: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1513
- opened: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1514
- closed: z.ZodOptional<z.ZodNullable<z.ZodString>>;
1515
- deadline: z.ZodOptional<z.ZodNullable<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>>;
1516
- }, z.core.$loose>>;
1517
- }, z.core.$strict>>;
1518
- }, z.core.$strict> & {
1519
- is: (value: unknown) => value is {
1520
- meta: Record<string, string | number | boolean | null>;
1521
- instances: {
1522
- id: string;
1523
- meta: Record<string, string | number | boolean | null>;
1524
- nodes: {
1525
- [x: string]: unknown;
1526
- id: string;
1527
- lat?: number | null | undefined;
1528
- lon?: number | null | undefined;
1529
- x?: number | null | undefined;
1530
- y?: number | null | undefined;
1531
- prize?: number | null | undefined;
1532
- prizeProbability?: number | null | undefined;
1533
- duration?: number | null | undefined;
1534
- travelTime?: number | null | undefined;
1535
- skill?: string | null | undefined;
1536
- territory?: string | null | undefined;
1537
- status?: string | null | undefined;
1538
- opened?: string | null | undefined;
1539
- closed?: string | null | undefined;
1540
- deadline?: string | number | null | undefined;
1541
- }[];
1542
- }[];
1543
- };
1495
+ declare function collectionOf<Document extends object>(document: z.ZodType<Document>): z.ZodType<Collection<Document>> & {
1496
+ is: (value: unknown) => value is Collection<Document>;
1544
1497
  };
1545
- type OrSetV1 = z.infer<typeof OrSetV1Schema>;
1546
1498
  //#endregion
1547
1499
  //#region src/targets/or-v1.d.ts
1548
1500
  /**
@@ -1618,27 +1570,25 @@ type OrV1 = z.infer<typeof OrV1Schema>;
1618
1570
  declare const CategoryIdSchema: z.ZodEnum<{
1619
1571
  "graph/v1": "graph/v1";
1620
1572
  "or/v1": "or/v1";
1621
- "or-set/v1": "or-set/v1";
1622
1573
  }>;
1623
1574
  type CategoryId = z.infer<typeof CategoryIdSchema>;
1624
1575
  /** The normalisation target each category resolves to, keyed by category id. */
1625
1576
  interface CategoryTargets {
1626
1577
  readonly "graph/v1": GraphV1;
1627
1578
  readonly "or/v1": OrV1;
1628
- readonly "or-set/v1": OrSetV1;
1629
1579
  }
1630
1580
  /** The normalised shape of any category: what `fetchDataset` can resolve to. */
1631
1581
  type CategoryTarget = CategoryTargets[CategoryId];
1632
1582
  /** The keys of a target whose values are arrays: the collections an entry's `expectedCounts` may name. */
1633
1583
  type CountedKey<Target> = { readonly [Key in keyof Target]: Target[Key] extends readonly unknown[] ? Key : never; }[keyof Target] & string;
1634
- /** What one fetch of an entry in a category reads: a single document, or a set of documents, one per member of the archive the source unpacks to. */
1635
- type CategoryShape = "document" | "collection";
1636
- /** One category: its id, what it holds, whether an entry is one document or a collection of them, the schema of its normalisation target, and which of the target's arrays an entry may record expected counts for. */
1584
+ /** What a fetch of a collection entry resolves to: the entry's metadata and one instance per archive member, each a document of the entry's category. */
1585
+ type CollectionTarget<Id extends CategoryId = CategoryId> = Id extends CategoryId ? Collection<CategoryTargets[Id]> : never;
1586
+ /** One category: its id, what it holds, the schema of its normalisation target (one document), the schema of a collection of such documents derived from it, and which of the target's arrays an entry may record expected counts for. */
1637
1587
  interface CategoryOf<Id extends CategoryId> {
1638
1588
  readonly id: Id;
1639
1589
  readonly description: string;
1640
- readonly shape: CategoryShape;
1641
1590
  readonly target: z.ZodType<CategoryTargets[Id]>;
1591
+ readonly collection: z.ZodType<Collection<CategoryTargets[Id]>>;
1642
1592
  readonly counted: readonly CountedKey<CategoryTargets[Id]>[];
1643
1593
  }
1644
1594
  /** A category, or with no argument any of them: a union over the ids, so each category keeps its own target and counted keys. */
@@ -1659,6 +1609,13 @@ declare function getCategory(id: string): Category;
1659
1609
  */
1660
1610
  declare function getTarget<Id extends CategoryId>(id: Id): z.ZodType<CategoryTargets[Id]>;
1661
1611
  declare function getTarget(id: string): z.ZodType<CategoryTarget>;
1612
+ /**
1613
+ * Returns the schema of a collection of documents of a category: `{ meta, instances }`, each instance a document of the category under an id, derived from the category's own target schema.
1614
+ * @param id - Any string, as for `getCategory`.
1615
+ * @returns The collection schema.
1616
+ * @throws UnknownCategoryError when no category has that id.
1617
+ */
1618
+ declare function getCollectionTarget(id: string): z.ZodType<CollectionTarget>;
1662
1619
  /**
1663
1620
  * The kind of data a category holds: the part of its id before the version.
1664
1621
  * @param id - A category id.
@@ -1668,11 +1625,18 @@ declare function kindOf(id: CategoryId): string;
1668
1625
  /** @returns Every registered category, in id order. */
1669
1626
  declare function listCategories(): readonly Category[];
1670
1627
  /**
1671
- * Counts the collections an entry may record expected counts for, in a resolved target.
1628
+ * The keys of a resolved target an entry may record expected counts for: a document's own arrays, or for a collection its instances.
1629
+ * @param id - The target's category.
1630
+ * @param collection - Whether the entry's recipe reads a collection.
1631
+ * @returns The countable keys.
1632
+ */
1633
+ declare function countedKeys(id: CategoryId, collection: boolean): readonly string[];
1634
+ /**
1635
+ * Counts the arrays an entry may record expected counts for, in a resolved target.
1672
1636
  * @param id - The target's category.
1673
- * @param target - A resolved target of that category.
1637
+ * @param target - A resolved document of that category, or a collection of them.
1674
1638
  * @returns The length of each counted array, by key.
1675
1639
  */
1676
- declare function countTarget(id: CategoryId, target: CategoryTarget): ReadonlyMap<string, number>;
1640
+ declare function countTarget(id: CategoryId, target: CategoryTarget | CollectionTarget): ReadonlyMap<string, number>;
1677
1641
  //#endregion
1678
- export { Entry as $, Dataset as A, AliasSchema as B, GraphNode as C, Catalogue as D, GraphV1Schema as E, LineageSchema as F, Citation as G, ArchiveMember as H, Manifest as I, CollectionArchiveSchema as J, CitationSchema as K, ManifestSchema as L, NamespaceNode as M, createCatalogue as N, CatalogueIndex as O, Lineage as P, DocumentArchive as Q, SemVerSchema as R, GraphEdgeSchema as S, GraphV1 as T, ArchiveMemberSchema as U, Archive as V, ArchiveSchema as W, CrosswalkReference as X, ColumnNameSchema as Y, CrosswalkReferenceSchema as Z, OrInstance as _, WaybackTimestampSchema as _t, CategoryTarget as a, Namespace as at, OrSetV1Schema as b, countTarget as c, ParserSchema as ct, kindOf as d, RecipeSchema as dt, EntrySchema as et, listCategories as f, RelativePathSchema as ft, OrV1Schema as g, SourceSchema as gt, OrV1 as h, Source as ht, CategoryShape as i, LicenceSchema as it, DatasetQuery as j, CatalogueIndexSchema as k, getCategory as l, RESERVED_META_KEYS as lt, OrNodeSchema as m, SnapshotSchema as mt, CategoryId as n, IdSchema as nt, CategoryTargets as o, NamespaceSchema as ot, OrNode as p, Snapshot as pt, CollectionArchive as q, CategoryIdSchema as r, Licence as rt, CountedKey as s, Parser as st, Category as t, HttpUrlSchema as tt, getTarget as u, Recipe as ut, OrInstanceSchema as v, parseEntry as vt, GraphNodeSchema as w, GraphEdge as x, OrSetV1 as y, waybackUrl as yt, parseManifest as z };
1642
+ export { CrosswalkReference as $, Catalogue as A, ManifestSchema as B, JsonScalarSchema as C, waybackUrl as Ct, GraphNodeSchema as D, GraphNode as E, NamespaceNode as F, ArchiveMember as G, parseManifest as H, createCatalogue as I, Citation as J, ArchiveMemberSchema as K, Lineage as L, CatalogueIndexSchema as M, Dataset as N, GraphV1 as O, DatasetQuery as P, ColumnNameSchema as Q, LineageSchema as R, JsonScalar as S, parseEntry as St, GraphEdgeSchema as T, AliasSchema as U, SemVerSchema as V, Archive as W, CollectionArchive as X, CitationSchema as Y, CollectionArchiveSchema as Z, OrV1 as _, SnapshotSchema as _t, CategoryTargets as a, IdSchema as at, Instance as b, SubjectSchema as bt, countTarget as c, Namespace as ct, getCollectionTarget as d, ParserSchema as dt, CrosswalkReferenceSchema as et, getTarget as f, RESERVED_META_KEYS as ft, OrNodeSchema as g, Snapshot as gt, OrNode as h, RelativePathSchema as ht, CategoryTarget as i, HttpUrlSchema as it, CatalogueIndex as j, GraphV1Schema as k, countedKeys as l, NamespaceSchema as lt, listCategories as m, RecipeSchema as mt, CategoryId as n, Entry as nt, CollectionTarget as o, Licence as ot, kindOf as p, Recipe as pt, ArchiveSchema as q, CategoryIdSchema as r, EntrySchema as rt, CountedKey as s, LicenceSchema as st, Category as t, DocumentArchive as tt, getCategory as u, Parser as ut, OrV1Schema as v, Source as vt, GraphEdge as w, collectionOf as x, WaybackTimestampSchema as xt, Collection as y, SourceSchema as yt, Manifest as z };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,5 @@
1
- import { $ as Entry, A as Dataset, B as AliasSchema, C as GraphNode, D as Catalogue, E as GraphV1Schema, F as LineageSchema, G as Citation, H as ArchiveMember, I as Manifest, J as CollectionArchiveSchema, K as CitationSchema, L as ManifestSchema, M as NamespaceNode, N as createCatalogue, O as CatalogueIndex, P as Lineage, Q as DocumentArchive, R as SemVerSchema, S as GraphEdgeSchema, T as GraphV1, U as ArchiveMemberSchema, V as Archive, W as ArchiveSchema, X as CrosswalkReference, Y as ColumnNameSchema, Z as CrosswalkReferenceSchema, _ as OrInstance, _t as WaybackTimestampSchema, a as CategoryTarget, at as Namespace, b as OrSetV1Schema, c as countTarget, ct as ParserSchema, d as kindOf, dt as RecipeSchema, et as EntrySchema, f as listCategories, ft as RelativePathSchema, g as OrV1Schema, gt as SourceSchema, h as OrV1, ht as Source, i as CategoryShape, it as LicenceSchema, j as DatasetQuery, k as CatalogueIndexSchema, l as getCategory, lt as RESERVED_META_KEYS, m as OrNodeSchema, mt as SnapshotSchema, n as CategoryId, nt as IdSchema, o as CategoryTargets, ot as NamespaceSchema, p as OrNode, pt as Snapshot, q as CollectionArchive, r as CategoryIdSchema, rt as Licence, s as CountedKey, st as Parser, t as Category, tt as HttpUrlSchema, u as getTarget, ut as Recipe, v as OrInstanceSchema, vt as parseEntry, w as GraphNodeSchema, x as GraphEdge, y as OrSetV1, yt as waybackUrl, z as parseManifest } from "./categories-C7q-yLo-.js";
1
+ import { $ as CrosswalkReference, A as Catalogue, B as ManifestSchema, C as JsonScalarSchema, Ct as waybackUrl, D as GraphNodeSchema, E as GraphNode, F as NamespaceNode, G as ArchiveMember, H as parseManifest, I as createCatalogue, J as Citation, K as ArchiveMemberSchema, L as Lineage, M as CatalogueIndexSchema, N as Dataset, O as GraphV1, P as DatasetQuery, Q as ColumnNameSchema, R as LineageSchema, S as JsonScalar, St as parseEntry, T as GraphEdgeSchema, U as AliasSchema, V as SemVerSchema, W as Archive, X as CollectionArchive, Y as CitationSchema, Z as CollectionArchiveSchema, _ as OrV1, _t as SnapshotSchema, a as CategoryTargets, at as IdSchema, b as Instance, bt as SubjectSchema, c as countTarget, ct as Namespace, d as getCollectionTarget, dt as ParserSchema, et as CrosswalkReferenceSchema, f as getTarget, ft as RESERVED_META_KEYS, g as OrNodeSchema, gt as Snapshot, h as OrNode, ht as RelativePathSchema, i as CategoryTarget, it as HttpUrlSchema, j as CatalogueIndex, k as GraphV1Schema, l as countedKeys, lt as NamespaceSchema, m as listCategories, mt as RecipeSchema, n as CategoryId, nt as Entry, o as CollectionTarget, ot as Licence, p as kindOf, pt as Recipe, q as ArchiveSchema, r as CategoryIdSchema, rt as EntrySchema, s as CountedKey, st as LicenceSchema, t as Category, tt as DocumentArchive, u as getCategory, ut as Parser, v as OrV1Schema, vt as Source, w as GraphEdge, x as collectionOf, xt as WaybackTimestampSchema, y as Collection, yt as SourceSchema, z as Manifest } from "./categories-DM2a8Esp.js";
2
2
  import { Crosswalk } from "twindex";
3
- import { z } from "zod";
4
3
  //#region src/errors.d.ts
5
4
  /** The root of this package's error taxonomy: every error keepset throws is a `KeepsetError`, so callers can catch the family with one check. */
6
5
  export declare class KeepsetError extends Error {
@@ -110,11 +109,6 @@ export declare function namesOf(entry: Addressed, segmentAliases?: SegmentAliase
110
109
  */
111
110
  export declare function serialise(doc: Entry | Manifest | Crosswalk): string;
112
111
  //#endregion
113
- //#region src/targets/json-scalar.d.ts
114
- /** A JSON scalar: the only values a target's metadata may hold, so `meta` stays a flat record any consumer can tabulate. `z.number()` already rejects NaN and the infinities, which JSON cannot carry. */
115
- export declare const JsonScalarSchema: z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean, z.ZodNull]>;
116
- type JsonScalar = z.infer<typeof JsonScalarSchema>;
117
- //#endregion
118
112
  //#region src/validate.d.ts
119
113
  /**
120
114
  * Checks a dataset as the catalogue holds it: the entry against the entry schema, and its crosswalk against twindex's structural validation and the entry's category. A catalogue index is checked the same way when it is built, so a bundled dataset is valid unless the package itself is broken; the check is what a contributor runs on an entry they are writing.
@@ -123,4 +117,4 @@ type JsonScalar = z.infer<typeof JsonScalarSchema>;
123
117
  */
124
118
  export declare function validateDataset(dataset: Dataset): SyntaxIssue[];
125
119
  //#endregion
126
- export { AliasSchema, type Archive, type ArchiveMember, ArchiveMemberSchema, ArchiveSchema, type Catalogue, type CatalogueIndex, CatalogueIndexSchema, type Category, type CategoryId, CategoryIdSchema, type CategoryShape, type CategoryTarget, type CategoryTargets, type Citation, CitationSchema, type CollectionArchive, CollectionArchiveSchema, ColumnNameSchema, type CountedKey, type CrosswalkReference, CrosswalkReferenceSchema, type Dataset, type DatasetQuery, type DocumentArchive, type Entry, type EntryNames, EntrySchema, type GraphEdge, GraphEdgeSchema, type GraphNode, GraphNodeSchema, type GraphV1, GraphV1Schema, HttpUrlSchema, IdSchema, type JsonScalar, type Licence, LicenceSchema, type Lineage, LineageSchema, type Manifest, ManifestSchema, type Namespace, type NamespaceNode, NamespaceSchema, type OrInstance, OrInstanceSchema, type OrNode, OrNodeSchema, type OrSetV1, OrSetV1Schema, type OrV1, OrV1Schema, type Parser, ParserSchema, RESERVED_META_KEYS, type Recipe, RecipeSchema, type RecipeStep, RelativePathSchema, type SegmentAliases, SemVerSchema, type Snapshot, SnapshotSchema, type Source, SourceSchema, type SyntaxIssue, WaybackTimestampSchema, countTarget, createCatalogue, getCategory, getTarget, kindOf, listCategories, parseEntry, parseManifest, waybackUrl };
120
+ export { AliasSchema, type Archive, type ArchiveMember, ArchiveMemberSchema, ArchiveSchema, type Catalogue, type CatalogueIndex, CatalogueIndexSchema, type Category, type CategoryId, CategoryIdSchema, type CategoryTarget, type CategoryTargets, type Citation, CitationSchema, type Collection, type CollectionArchive, CollectionArchiveSchema, type CollectionTarget, ColumnNameSchema, type CountedKey, type CrosswalkReference, CrosswalkReferenceSchema, type Dataset, type DatasetQuery, type DocumentArchive, type Entry, type EntryNames, EntrySchema, type GraphEdge, GraphEdgeSchema, type GraphNode, GraphNodeSchema, type GraphV1, GraphV1Schema, HttpUrlSchema, IdSchema, type Instance, type JsonScalar, JsonScalarSchema, type Licence, LicenceSchema, type Lineage, LineageSchema, type Manifest, ManifestSchema, type Namespace, type NamespaceNode, NamespaceSchema, type OrNode, OrNodeSchema, type OrV1, OrV1Schema, type Parser, ParserSchema, RESERVED_META_KEYS, type Recipe, RecipeSchema, type RecipeStep, RelativePathSchema, type SegmentAliases, SemVerSchema, type Snapshot, SnapshotSchema, type Source, SourceSchema, SubjectSchema, type SyntaxIssue, WaybackTimestampSchema, collectionOf, countTarget, countedKeys, createCatalogue, getCategory, getCollectionTarget, getTarget, kindOf, listCategories, parseEntry, parseManifest, waybackUrl };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as DatasetAmbiguousError, A as parseEntry, B as getTarget, C as ParserSchema, D as SnapshotSchema, E as RelativePathSchema, F as namesOf, G as OrNodeSchema, H as listCategories, J as GraphNodeSchema, K as OrV1Schema, L as CategoryIdSchema, M as waybackUrl, N as NAME_SEPARATOR, O as SourceSchema, P as groupsOf, Q as CatalogueSyntaxError, R as countTarget, S as NamespaceSchema, T as RecipeSchema, U as OrInstanceSchema, V as kindOf, W as OrSetV1Schema, X as JsonScalarSchema, Y as GraphV1Schema, Z as ArchiveError, _ as CrosswalkReferenceSchema, a as CatalogueIndexSchema, b as IdSchema, c as ManifestSchema, d as AliasSchema, et as DatasetNotFoundError, f as ArchiveMemberSchema, g as ColumnNameSchema, h as CollectionArchiveSchema, i as listNamespaces, it as UnknownCategoryError, j as toIssues, k as WaybackTimestampSchema, l as SemVerSchema, m as CitationSchema, n as getManifest, nt as NativeParseError, o as createCatalogue, p as ArchiveSchema, q as GraphEdgeSchema, r as listDatasets, rt as RecipeError, s as LineageSchema, t as getDataset, tt as KeepsetError, u as parseManifest, v as EntrySchema, w as RESERVED_META_KEYS, x as LicenceSchema, y as HttpUrlSchema, z as getCategory } from "./bundled-C52vPmf3.js";
1
+ import { $ as ArchiveError, A as WaybackTimestampSchema, B as countedKeys, C as ParserSchema, D as SnapshotSchema, E as RelativePathSchema, F as groupsOf, G as listCategories, H as getCollectionTarget, I as namesOf, J as collectionOf, K as OrNodeSchema, M as toIssues, N as waybackUrl, O as SourceSchema, P as NAME_SEPARATOR, Q as JsonScalarSchema, R as CategoryIdSchema, S as NamespaceSchema, T as RecipeSchema, U as getTarget, V as getCategory, W as kindOf, X as GraphNodeSchema, Y as GraphEdgeSchema, Z as GraphV1Schema, _ as CrosswalkReferenceSchema, a as CatalogueIndexSchema, at as RecipeError, b as IdSchema, c as ManifestSchema, d as AliasSchema, et as CatalogueSyntaxError, f as ArchiveMemberSchema, g as ColumnNameSchema, h as CollectionArchiveSchema, i as listNamespaces, it as NativeParseError, j as parseEntry, k as SubjectSchema, l as SemVerSchema, m as CitationSchema, n as getManifest, nt as DatasetNotFoundError, o as createCatalogue, ot as UnknownCategoryError, p as ArchiveSchema, q as OrV1Schema, r as listDatasets, rt as KeepsetError, s as LineageSchema, t as getDataset, tt as DatasetAmbiguousError, u as parseManifest, v as EntrySchema, w as RESERVED_META_KEYS, x as LicenceSchema, y as HttpUrlSchema, z as countTarget } from "./bundled-4MeSniHX.js";
2
2
  import { validateCrosswalk } from "twindex";
3
3
  //#region src/serialise.ts
4
4
  /**
@@ -57,4 +57,4 @@ function validateDataset(dataset) {
57
57
  return issues;
58
58
  }
59
59
  //#endregion
60
- export { AliasSchema, ArchiveError, ArchiveMemberSchema, ArchiveSchema, CatalogueIndexSchema, CatalogueSyntaxError, CategoryIdSchema, CitationSchema, CollectionArchiveSchema, ColumnNameSchema, CrosswalkReferenceSchema, DatasetAmbiguousError, DatasetNotFoundError, EntrySchema, GraphEdgeSchema, GraphNodeSchema, GraphV1Schema, HttpUrlSchema, IdSchema, JsonScalarSchema, KeepsetError, LicenceSchema, LineageSchema, ManifestSchema, NAME_SEPARATOR, NamespaceSchema, NativeParseError, OrInstanceSchema, OrNodeSchema, OrSetV1Schema, OrV1Schema, ParserSchema, RESERVED_META_KEYS, RecipeError, RecipeSchema, RelativePathSchema, SemVerSchema, SnapshotSchema, SourceSchema, UnknownCategoryError, WaybackTimestampSchema, countTarget, createCatalogue, getCategory, getDataset, getManifest, getTarget, groupsOf, kindOf, listCategories, listDatasets, listNamespaces, namesOf, parseEntry, parseManifest, serialise, validateDataset, waybackUrl };
60
+ export { AliasSchema, ArchiveError, ArchiveMemberSchema, ArchiveSchema, CatalogueIndexSchema, CatalogueSyntaxError, CategoryIdSchema, CitationSchema, CollectionArchiveSchema, ColumnNameSchema, CrosswalkReferenceSchema, DatasetAmbiguousError, DatasetNotFoundError, EntrySchema, GraphEdgeSchema, GraphNodeSchema, GraphV1Schema, HttpUrlSchema, IdSchema, JsonScalarSchema, KeepsetError, LicenceSchema, LineageSchema, ManifestSchema, NAME_SEPARATOR, NamespaceSchema, NativeParseError, OrNodeSchema, OrV1Schema, ParserSchema, RESERVED_META_KEYS, RecipeError, RecipeSchema, RelativePathSchema, SemVerSchema, SnapshotSchema, SourceSchema, SubjectSchema, UnknownCategoryError, WaybackTimestampSchema, collectionOf, countTarget, countedKeys, createCatalogue, getCategory, getCollectionTarget, getDataset, getManifest, getTarget, groupsOf, kindOf, listCategories, listDatasets, listNamespaces, namesOf, parseEntry, parseManifest, serialise, validateDataset, waybackUrl };
@@ -1,4 +1,4 @@
1
- import { $ as Entry, A as Dataset, a as CategoryTarget, ht as Source, pt as Snapshot } from "../categories-C7q-yLo-.js";
1
+ import { N as Dataset, gt as Snapshot, i as CategoryTarget, nt as Entry, o as CollectionTarget, vt as Source } from "../categories-DM2a8Esp.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: {
@@ -29,10 +29,10 @@ export interface Provenance {
29
29
  /** The archive members a collection was read from, in the order they were read. */
30
30
  readonly members?: readonly string[];
31
31
  }
32
- /** A fetched dataset: the resolved category target, the provenance of the bytes it came from, and any warnings, such as a count that differs from the one the entry records. */
32
+ /** A fetched dataset: the resolved category target (one document, or for a recipe that selects archive members a collection of them), the provenance of the bytes it came from, and any warnings, such as a count that differs from the one the entry records. */
33
33
  export interface FetchedDataset {
34
34
  readonly dataset: Dataset;
35
- readonly data: CategoryTarget;
35
+ readonly data: CategoryTarget | CollectionTarget;
36
36
  readonly provenance: Provenance;
37
37
  readonly warnings: readonly string[];
38
38
  }
@@ -1,4 +1,4 @@
1
- import { B as getTarget, I as getOwn, R as countTarget, Z as ArchiveError, nt as NativeParseError, rt as RecipeError, t as getDataset, tt as KeepsetError } from "../bundled-C52vPmf3.js";
1
+ import { $ as ArchiveError, H as getCollectionTarget, L as getOwn, U as getTarget, at as RecipeError, it as NativeParseError, rt as KeepsetError, t as getDataset, z as countTarget } from "../bundled-4MeSniHX.js";
2
2
  import { RoundTripMismatchError, assertRoundTrip, encode } from "twindex";
3
3
  import { z } from "zod";
4
4
  import { createHash } from "node:crypto";
@@ -2858,10 +2858,22 @@ function metaOf(entry) {
2858
2858
  };
2859
2859
  }
2860
2860
  /**
2861
- * Runs a recipe's download, extract and parse steps, and builds the native document the crosswalk receives: the parser's output with `meta` built from the entry.
2861
+ * Puts an instance's id beside the fields of its encoded document. A document that is not an object is left as it is, for the collection schema to refuse.
2862
+ * @param document - The crosswalk's output for one member.
2863
+ * @param id - The member's path.
2864
+ * @returns The instance.
2865
+ */
2866
+ function withId(document, id) {
2867
+ return typeof document === "object" && document !== null && !Array.isArray(document) ? {
2868
+ ...document,
2869
+ id
2870
+ } : document;
2871
+ }
2872
+ /**
2873
+ * Runs a recipe's download, extract and parse steps, and builds the native documents the crosswalk receives.
2862
2874
  * @param dataset - The dataset.
2863
2875
  * @param options - The network port, abort signal and clock.
2864
- * @returns The native document and the provenance of its bytes.
2876
+ * @returns The native documents and the provenance of their bytes.
2865
2877
  */
2866
2878
  async function runToNative(dataset, options) {
2867
2879
  const { entry } = dataset;
@@ -2896,35 +2908,39 @@ async function runToNative(dataset, options) {
2896
2908
  const { archive } = recipe;
2897
2909
  if ("members" in archive) {
2898
2910
  const files = await step(entry.id, "extract", () => unpackMembers(bytes, archive));
2899
- const members = await step(entry.id, "parse", () => files.map((file) => {
2900
- try {
2901
- return {
2902
- id: file.path,
2903
- meta: {},
2904
- ...parseNative(file.bytes, recipe.parser)
2905
- };
2906
- } catch (error) {
2907
- throw new KeepsetError(`member ${file.path}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
2908
- }
2909
- }));
2910
2911
  return {
2911
- native: {
2912
- meta: metaOf(entry),
2913
- members
2914
- },
2912
+ collection: true,
2913
+ documents: await step(entry.id, "parse", () => files.map((file) => {
2914
+ try {
2915
+ const parsed = parseNative(file.bytes, recipe.parser);
2916
+ return {
2917
+ id: file.path,
2918
+ native: {
2919
+ ...parsed,
2920
+ meta: "meta" in parsed ? parsed.meta : {}
2921
+ }
2922
+ };
2923
+ } catch (error) {
2924
+ throw new KeepsetError(`member ${file.path}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
2925
+ }
2926
+ })),
2915
2927
  provenance: provenanceOf({ members: files.map((file) => file.path) })
2916
2928
  };
2917
2929
  }
2918
2930
  const unpacked = await step(entry.id, "extract", () => unpack(bytes, archive));
2919
2931
  const parsed = await step(entry.id, "parse", () => parseNative(unpacked.bytes, recipe.parser));
2920
2932
  return {
2921
- native: {
2922
- ...parsed,
2923
- meta: {
2924
- ..."meta" in parsed ? parsed.meta : {},
2925
- ...metaOf(entry)
2933
+ collection: false,
2934
+ documents: [{
2935
+ id: void 0,
2936
+ native: {
2937
+ ...parsed,
2938
+ meta: {
2939
+ ..."meta" in parsed ? parsed.meta : {},
2940
+ ...metaOf(entry)
2941
+ }
2926
2942
  }
2927
- },
2943
+ }],
2928
2944
  provenance: provenanceOf(unpacked.member === void 0 ? {} : { member: unpacked.member })
2929
2945
  };
2930
2946
  }
@@ -2937,11 +2953,22 @@ async function runToNative(dataset, options) {
2937
2953
  */
2938
2954
  async function fetchEntry(dataset, options = {}) {
2939
2955
  const { entry, crosswalk } = dataset;
2940
- const { native, provenance } = await runToNative(dataset, options);
2941
- const encoded = await step(entry.id, "crosswalk", () => encode(crosswalk, native));
2956
+ const { collection, documents, provenance } = await runToNative(dataset, options);
2957
+ const encoded = await step(entry.id, "crosswalk", () => documents.map(({ id, native }) => {
2958
+ try {
2959
+ return encode(crosswalk, native);
2960
+ } catch (error) {
2961
+ throw new KeepsetError(`${id === void 0 ? "" : `member ${id}: `}${error instanceof Error ? error.message : String(error)}`, { cause: error });
2962
+ }
2963
+ }));
2942
2964
  const data = await step(entry.id, "validate", () => {
2943
- const result = getTarget(entry.category).safeParse(encoded);
2944
- if (!result.success) throw new KeepsetError(`the result is not ${entry.category}: ${result.error.issues.map((issue) => `${issue.path.map(String).join(".") || "(root)"}: ${issue.message}`).join("; ")}`);
2965
+ const [only] = encoded;
2966
+ const whole = collection ? {
2967
+ meta: metaOf(entry),
2968
+ instances: encoded.map((document, index) => withId(document, documents[index]?.id))
2969
+ } : only;
2970
+ const result = (collection ? getCollectionTarget(entry.category) : getTarget(entry.category)).safeParse(whole);
2971
+ if (!result.success) throw new KeepsetError(`the result is not ${collection ? "a collection of " : ""}${entry.category}: ${result.error.issues.map((issue) => `${issue.path.map(String).join(".") || "(root)"}: ${issue.message}`).join("; ")}`);
2945
2972
  return result.data;
2946
2973
  });
2947
2974
  const counts = countTarget(entry.category, data);
@@ -2970,9 +2997,9 @@ async function fetchDataset(id, options = {}) {
2970
2997
  * @throws RecipeError naming the entry and the failing step when the recipe fails before the comparison, or when the crosswalk cannot run.
2971
2998
  */
2972
2999
  async function roundTripEntry(dataset, options = {}) {
2973
- const { native, provenance } = await runToNative(dataset, options);
3000
+ const { documents, provenance } = await runToNative(dataset, options);
2974
3001
  try {
2975
- assertRoundTrip(dataset.crosswalk, [native]);
3002
+ assertRoundTrip(dataset.crosswalk, documents.map(({ native }) => native));
2976
3003
  } catch (error) {
2977
3004
  if (error instanceof RoundTripMismatchError) return {
2978
3005
  holds: false,
@@ -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.28.0";
7
+ var version = "0.29.0";
8
8
  //#endregion
9
9
  //#region cli/run.ts
10
10
  /**
@@ -19,11 +19,11 @@ function selectorText(selector) {
19
19
  const usage = `Usage: keepset <command> [options]
20
20
 
21
21
  Commands:
22
- search [text] [--kind <kind>] [--domain <domain>] [--namespace <path>]
23
- [--category <id>] [--json]
22
+ search [text] [--kind <kind>] [--domain <domain>] [--subject <subject>]
23
+ [--namespace <path>] [--category <id>] [--json]
24
24
  list the datasets whose id, alias, namespace, name,
25
- description, domain or tags contain the text, filtered by
26
- kind, domain, namespace (and every namespace beneath it,
25
+ description, domain, subjects or tags contain the text,
26
+ filtered by kind, domain, subject, namespace (and every namespace beneath it,
27
27
  segment aliases allowed) or category
28
28
  namespaces [path] [--json]
29
29
  list the namespaces directly beneath a path, or the
@@ -61,6 +61,7 @@ function parseCommandLine(args) {
61
61
  options: {
62
62
  kind: { type: "string" },
63
63
  domain: { type: "string" },
64
+ subject: { type: "string" },
64
65
  namespace: { type: "string" },
65
66
  category: { type: "string" },
66
67
  json: { type: "boolean" },
@@ -112,6 +113,7 @@ function formatShow(dataset) {
112
113
  lines.push("", `category: ${entry.category} (kind ${dataset.kind})`, `catalogue: ${dataset.catalogue.id} ${dataset.catalogue.version}`);
113
114
  if (entry.namespace !== void 0) lines.push(`namespace: ${entry.namespace.join(NAME_SEPARATOR)}`);
114
115
  if (entry.aliases !== void 0) lines.push(`aliases: ${entry.aliases.join(", ")}`);
116
+ if (entry.subjects !== void 0) lines.push(`subjects: ${entry.subjects.join(", ")}`);
115
117
  if (entry.domain !== void 0) lines.push(`domain: ${entry.domain}`);
116
118
  if (entry.tags.length > 0) lines.push(`tags: ${entry.tags.join(", ")}`);
117
119
  const { licence } = entry;
@@ -198,6 +200,7 @@ async function run(args, library, io) {
198
200
  ...text === void 0 ? {} : { text },
199
201
  ...values.kind === void 0 ? {} : { kind: values.kind },
200
202
  ...values.domain === void 0 ? {} : { domain: values.domain },
203
+ ...values.subject === void 0 ? {} : { subject: values.subject },
201
204
  ...values.namespace === void 0 ? {} : { namespace: values.namespace },
202
205
  ...values.category === void 0 ? {} : { category: values.category }
203
206
  };
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.28.0",
4
+ "version": "0.29.0",
5
5
  "bin": {
6
6
  "keepset": "./dist-cli/keepset.mjs"
7
7
  },