@hawkeyexl/manni 0.2.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -174,6 +174,16 @@ interface FieldError {
174
174
  line?: number;
175
175
  /** 1-based column, when known. */
176
176
  col?: number;
177
+ /**
178
+ * The file `line` and `col` refer to, when it is not the result's own file.
179
+ *
180
+ * Set only for a value a manifest supplied (proposal 0037), spelled
181
+ * the way the run spells file labels. Absent means the document itself,
182
+ * which is every violation that existed before external metadata. The finding's
183
+ * subject file stays `ValidationResult.file`: that is its baseline identity
184
+ * and its SARIF location, and this names where the *value* was written.
185
+ */
186
+ file?: string;
177
187
  }
178
188
  /** Validation outcome for a single file. */
179
189
  interface ValidationResult {
@@ -247,6 +257,49 @@ interface FingerprintContext {
247
257
  runBase?: string;
248
258
  }
249
259
 
260
+ /** One external-metadata manifest (proposals 0037, 0038, 0039) joined to a collection. */
261
+ interface ExternalMetadataConfig {
262
+ file: string;
263
+ keys: string[];
264
+ tokenEnv?: string;
265
+ join?: string;
266
+ }
267
+ /** One named document set, as declared under the top-level `collections:` key. */
268
+ interface CollectionConfig {
269
+ name: string;
270
+ paths: string[];
271
+ exclude: string[];
272
+ externalMetadata: ExternalMetadataConfig[];
273
+ /** Where the collection is published; `manni a11y check` seeds from it. */
274
+ url?: string;
275
+ }
276
+ /**
277
+ * Whether a URL may name an external-metadata manifest: `https://` anywhere,
278
+ * or `http://` on a loopback host only, where plaintext leaks nothing.
279
+ * Userinfo is refused because the URL is printed in every diagnostic and a
280
+ * secret in it would print too. Returns the reason it may not, or `null`.
281
+ */
282
+ declare function externalMetadataUrlProblem(url: string): string | null;
283
+ /**
284
+ * Parse the top-level `collections:` value. Errors are built with `toError`,
285
+ * so each tool reports a bad family file in its own error class.
286
+ */
287
+ declare function parseCollections(raw: unknown, source: string, toError: (message: string) => Error): CollectionConfig[];
288
+ /**
289
+ * The collections a run covers: every one when `names` is undefined, else the
290
+ * named ones in **declaration** order, however they were named on the command
291
+ * line. Repeats collapse; an unknown name is an error, because a typo that
292
+ * silently narrowed the run to nothing would read as a clean pass.
293
+ */
294
+ declare function selectCollections(collections: readonly CollectionConfig[], names: readonly string[] | undefined, source: string, toError: (message: string) => Error): CollectionConfig[];
295
+ /**
296
+ * Is this file a member of the collection? `relPath` is posix and already
297
+ * relative to the config file's directory, so this is arithmetic on a string:
298
+ * no `stat`, nothing that can fail, and nothing that costs per file. A path
299
+ * that climbed out of the config directory, and stdin, are members of nothing.
300
+ */
301
+ declare function isMember(collection: CollectionConfig, relPath: string): boolean;
302
+
250
303
  interface SchemaOverride {
251
304
  /**
252
305
  * The glob, or globs, this override governs. A file matches when **any** of
@@ -258,20 +311,23 @@ interface SchemaOverride {
258
311
  * caller may hand `runValidate` a config object it built itself, and that
259
312
  * caller's bare string must keep working. Read it through `overrideGlobs`
260
313
  * rather than directly — that is the one place the two shapes collapse.
314
+ *
315
+ * Optional since proposal 0041: an entry carries **exactly one** of `files`
316
+ * or `collection`.
261
317
  */
262
- files: string | string[];
318
+ files?: string | string[];
263
319
  schemas: string[];
264
320
  /**
265
- * Optional collection name (proposal 0027): the override group becomes a
266
- * SQL view of that name over the `docs` projection, holding exactly the
267
- * files this override won schema resolution for. Any string is legal —
268
- * view names are quoted identifiers — except the refusals `parseConfig`
269
- * makes: a duplicate, `docs` (the table every query already reads), a
270
- * blank name, and a name starting `sqlite_` (SQLite reserves the prefix).
271
- * A `name:` also requires `schemas:`, because a schema-less override never
272
- * wins resolution and its view would be empty by construction.
321
+ * The collection this override governs (proposal 0041), in place of globs of
322
+ * its own: it matches the members of the named collection, which are decided
323
+ * once, at the top level of the family file, for every tool. Must name a
324
+ * collection `collections:` defines — checked by `loadConfig`, which is the
325
+ * first place both halves of the file are known.
326
+ *
327
+ * This is what `overrides[].name` was for under 0027, inverted: a collection
328
+ * is the thing that has a name, and an override points at it.
273
329
  */
274
- name?: string;
330
+ collection?: string;
275
331
  /**
276
332
  * Extra element paths for files matching `files`. Unlike `schemas`, which the
277
333
  * first matching override *replaces* because a schema set is a complete
@@ -368,8 +424,6 @@ interface SchemaCacheConfig {
368
424
  ttlHours?: number;
369
425
  }
370
426
  interface DocmetaConfig {
371
- paths?: string[];
372
- exclude?: string[];
373
427
  /**
374
428
  * The default schema set. Each entry is either a reference string or a
375
429
  * `{ ref, source?, integrity? }` mapping — see `SchemaEntry`.
@@ -430,17 +484,28 @@ interface LoadedConfig {
430
484
  /** Absolute path to the file the config was read from. */
431
485
  path: string;
432
486
  /**
433
- * Directory holding that file. Relative paths written *in* the config —
434
- * `paths:`, `exclude:`, local-file schema refs — are meaningful relative to
487
+ * Directory holding that file. Relative paths written *in* the config — a
488
+ * collection's `paths:`, local-file schema refs — are meaningful relative to
435
489
  * this, not to the directory the command happened to be invoked from.
436
490
  */
437
491
  dir: string;
492
+ /**
493
+ * The file as the user would name it, which is how every config message
494
+ * spells it. Threaded from `ConfigFile.source` so `selectCollections` can
495
+ * name the file a `--collection` failed to find a collection in.
496
+ */
497
+ source: string;
438
498
  /**
439
499
  * The family-file key the config was read from under (`"meta"`), when it
440
500
  * was. Absent for a pre-family file, whose top level is the config. A
441
501
  * command that writes the file back (`schemas vendor`) needs to know.
442
502
  */
443
503
  section?: string;
504
+ /**
505
+ * Every collection the family file declares (proposal 0041), in declaration
506
+ * order. `[]` for a legacy per-tool file, which carries no family-wide keys.
507
+ */
508
+ collections: CollectionConfig[];
444
509
  }
445
510
 
446
511
  /**
@@ -497,24 +562,37 @@ interface RunConfigOptions {
497
562
  configPath?: string;
498
563
  /** `--no-config`: skip discovery and run on the built-in defaults. */
499
564
  noConfig?: boolean;
500
- /** Positional inputs; empty means fall back to the config's `paths:`. */
565
+ /**
566
+ * Positional inputs; empty means fall back to the configured collections'
567
+ * `paths:` (proposal 0041).
568
+ */
501
569
  inputs: string[];
570
+ /**
571
+ * `--collection <name>`, repeatable: the collections this run covers. Empty
572
+ * or absent means every declared collection — the same thing, because
573
+ * commander's repeatable collector hands a caller `[]` when the flag was
574
+ * never passed (see `selectCollections`).
575
+ */
576
+ collections?: string[];
502
577
  onConfigLoaded?: (info: ConfigNotice) => void;
503
578
  }
504
579
  interface RunConfig {
505
580
  /** The config, with its local file schema refs already rebased. */
506
581
  config: DocmetaConfig | null;
507
- /** What to resolve: the positional inputs, or the config's `paths:`. */
582
+ /**
583
+ * What to resolve: the positional inputs, or the selected collections'
584
+ * `paths:`, concatenated in declaration order.
585
+ */
508
586
  inputs: string[];
509
587
  /**
510
588
  * Directory those inputs — and so every resolved file path, and every file
511
589
  * read — are relative to.
512
590
  *
513
- * A run uses *either* positional paths *or* config `paths:`, never both, so
514
- * there is exactly one base per run and no ambiguity about which it is.
515
- * Positional paths are typed by a person standing in a shell, so they stay
516
- * relative to the working directory; `paths:` globs were written next to the
517
- * config, so they resolve from there.
591
+ * A run uses *either* positional paths *or* the collections' `paths:`, never
592
+ * both, so there is exactly one base per run and no ambiguity about which it
593
+ * is. Positional paths are typed by a person standing in a shell, so they
594
+ * stay relative to the working directory; a collection's globs were written
595
+ * next to the config, so they resolve from there.
518
596
  */
519
597
  base: string;
520
598
  /**
@@ -535,6 +613,40 @@ interface RunConfig {
535
613
  * assumed filename names the wrong file in every one of those setups.
536
614
  */
537
615
  configPath?: string;
616
+ /**
617
+ * The key the tool's config sits under in that file — `meta` for a family
618
+ * file, `undefined` for a legacy per-tool file whose whole document is the
619
+ * section.
620
+ *
621
+ * Anything that *rewrites* the config by hand has to know: `schemas:` is at
622
+ * the top level of a legacy file and one level down in a family file, so a
623
+ * rewriter that assumes the top level silently finds nothing in the shape
624
+ * proposal 0033 made the default. `query`'s DDL repointing did exactly that
625
+ * until the 0041 fixtures stopped being legacy files and made it visible.
626
+ */
627
+ configSection?: string;
628
+ /**
629
+ * The collections this run covers (proposal 0041): every declared one, or
630
+ * the ones `--collection` named. `[]` when no config governs the run.
631
+ *
632
+ * Selected even when the inputs are positional, because membership is what
633
+ * external metadata attaches to (rule 4) and a file the operator typed is
634
+ * still a member of whatever collections contain it.
635
+ */
636
+ collections: CollectionConfig[];
637
+ /**
638
+ * Every collection the config declares, in declaration order — the same list
639
+ * `collections` narrows. `query` needs both: membership and manifests follow
640
+ * the *selected* set, while every *declared* collection is a SQL view (0041
641
+ * rule 11), so a statement naming one the run did not select still answers.
642
+ */
643
+ declaredCollections: CollectionConfig[];
644
+ /**
645
+ * Whether `inputs` came from the collections rather than the command line.
646
+ * The corpus invariant every scoped check reads: a positional path means the
647
+ * operator chose part of the corpus.
648
+ */
649
+ fromCollections: boolean;
538
650
  }
539
651
  /**
540
652
  * Settle the three things every command core needs from config before it can
@@ -553,6 +665,12 @@ interface ValidateOptions {
553
665
  configPath?: string;
554
666
  /** `--no-config`: skip config discovery and use the built-in defaults. */
555
667
  noConfig?: boolean;
668
+ /**
669
+ * `--collection <name>`, repeatable: run over the named configured
670
+ * collections instead of every declared one (proposal 0041). Cannot be
671
+ * combined with positional paths; `-` is allowed beside it.
672
+ */
673
+ collections?: string[];
556
674
  cwd?: string;
557
675
  /** Content for the `-` (stdin) input, injected by the CLI/tests. */
558
676
  stdinContent?: string;
@@ -619,6 +737,12 @@ interface GetOptions {
619
737
  configPath?: string;
620
738
  /** `--no-config`: skip config discovery and use the built-in defaults. */
621
739
  noConfig?: boolean;
740
+ /**
741
+ * `--collection <name>`, repeatable: run over the named configured
742
+ * collections instead of every declared one (proposal 0041). Cannot be
743
+ * combined with positional paths; `-` is allowed beside it.
744
+ */
745
+ collections?: string[];
622
746
  cwd?: string;
623
747
  /** Content for the `-` (stdin) input, injected by the CLI/tests. */
624
748
  stdinContent?: string;
@@ -681,6 +805,12 @@ interface QueryOptions {
681
805
  configPath?: string;
682
806
  /** `--no-config`: skip config discovery and use the built-in defaults. */
683
807
  noConfig?: boolean;
808
+ /**
809
+ * `--collection <name>`, repeatable: run over the named configured
810
+ * collections instead of every declared one (proposal 0041). Cannot be
811
+ * combined with positional paths; `-` is allowed beside it.
812
+ */
813
+ collections?: string[];
684
814
  cwd?: string;
685
815
  /** Content for the `-` (stdin) input, injected by the CLI/tests. */
686
816
  stdinContent?: string;
@@ -1076,6 +1206,12 @@ interface FillOptions {
1076
1206
  configPath?: string;
1077
1207
  /** `--no-config`: skip config discovery and use the built-in defaults. */
1078
1208
  noConfig?: boolean;
1209
+ /**
1210
+ * `--collection <name>`, repeatable: run over the named configured
1211
+ * collections instead of every declared one (proposal 0041). Cannot be
1212
+ * combined with positional paths; `-` is allowed beside it.
1213
+ */
1214
+ collections?: string[];
1079
1215
  cwd?: string;
1080
1216
  /** Content for the `-` (stdin) input, injected by the CLI/tests. */
1081
1217
  stdinContent?: string;
@@ -1125,6 +1261,179 @@ interface FillOptions {
1125
1261
 
1126
1262
  declare function runFill(opts: FillOptions): Promise<FillRun>;
1127
1263
 
1264
+ /**
1265
+ * The `schema` ref a collision finding carries, and so its baseline and rule
1266
+ * identity: `external:owned/external`. Shaped like `check:<name>` so
1267
+ * `classifyRef` passes it through as a built-in id rather than resolving it
1268
+ * as a cwd-relative file path, and reserved in the registry for the same
1269
+ * reason `check` is.
1270
+ */
1271
+ declare const EXTERNAL_OWNED_SCHEMA = "external:owned";
1272
+ /**
1273
+ * The `schema` ref of a duplicate-join finding (0039): two documents carry
1274
+ * the same value of a join field, so one manifest entry matched both.
1275
+ */
1276
+ declare const EXTERNAL_DUPLICATE_SCHEMA = "external:duplicate";
1277
+ /**
1278
+ * The `keyword` every external-metadata finding carries: no Ajv keyword
1279
+ * produced it.
1280
+ */
1281
+ declare const EXTERNAL_KEYWORD = "external";
1282
+ /** The join that names documents by path, and the default. */
1283
+ declare const PATH_JOIN = "path";
1284
+ /** One value a manifest supplied, and where it was written. */
1285
+ interface ExternalMetadataValue {
1286
+ value: unknown;
1287
+ /** The collection whose manifest supplied it (proposal 0041). */
1288
+ collection: string;
1289
+ /** Manifest path as the run reports it: relative to the run's base, posix — or the URL. */
1290
+ file: string;
1291
+ /** 1-based line of the key in the manifest, when known. */
1292
+ line?: number;
1293
+ }
1294
+ /** One manifest entry, for the orphan checks. */
1295
+ interface ExternalMetadataEntry {
1296
+ /** The collection whose manifest declared it (proposal 0041). */
1297
+ collection: string;
1298
+ /** `path`, or the frontmatter field this entry is keyed by. */
1299
+ join: string;
1300
+ /** Absolute document path, for a path entry. */
1301
+ abs?: string;
1302
+ /** The key exactly as written in the manifest. */
1303
+ spelled: string;
1304
+ /** Manifest path as the run reports it. */
1305
+ file: string;
1306
+ /** 1-based line of the entry in the manifest, when known. */
1307
+ line?: number;
1308
+ }
1309
+ /** Every manifest of a run, loaded once and consulted per document. */
1310
+ interface ExternalMetadataIndex {
1311
+ /**
1312
+ * Owned key -> every collection that owns it, with the manifest that does.
1313
+ *
1314
+ * A list rather than one entry, because two collections may legitimately
1315
+ * each own the same key (0041 rule 5): `guides` and `blog` can both supply
1316
+ * `owner`. Ambiguity only exists for a file that is a member of both, which
1317
+ * is decided per file in `mergeExternalMetadata`.
1318
+ */
1319
+ owners: ReadonlyMap<string, readonly {
1320
+ collection: string;
1321
+ file: string;
1322
+ }[]>;
1323
+ /** Path-joined manifests: absolute document path -> owned key -> value. */
1324
+ byPath: ReadonlyMap<string, ReadonlyMap<string, ExternalMetadataValue>>;
1325
+ /** Field-joined manifests: field -> value -> owned key -> value. */
1326
+ byField: ReadonlyMap<string, ReadonlyMap<string, ReadonlyMap<string, ExternalMetadataValue>>>;
1327
+ /** Every manifest entry, in manifest order. */
1328
+ entries: readonly ExternalMetadataEntry[];
1329
+ }
1330
+ interface LoadExternalMetadataOptions {
1331
+ /** Directory `externalMetadata[].file` and every manifest key resolve from. */
1332
+ configDir: string;
1333
+ /** Directory the run's file labels are relative to; manifests are reported the same way. */
1334
+ base: string;
1335
+ /** `--offline` / `offline:`: a URL manifest is refused rather than fetched (0038). */
1336
+ offline?: boolean;
1337
+ /** Network timeout for a URL manifest; the schema fetch's default otherwise. */
1338
+ timeoutMs?: number;
1339
+ /** For tests: the environment `tokenEnv` is read from. */
1340
+ env?: Record<string, string | undefined>;
1341
+ }
1342
+ /** A place a merged value lives, for a finding that must name it. */
1343
+ interface SourceLocation {
1344
+ file: string;
1345
+ line?: number;
1346
+ col?: number;
1347
+ }
1348
+ /** A key the document carries that a manifest owns. */
1349
+ interface ExternalMetadataCollision {
1350
+ key: string;
1351
+ /** The owning manifest, as the run reports it. */
1352
+ file: string;
1353
+ /** The collection that manifest belongs to (proposal 0041). */
1354
+ collection: string;
1355
+ }
1356
+ /** A field-joined entry a document matched (0039). */
1357
+ interface ExternalMetadataJoin {
1358
+ field: string;
1359
+ value: string;
1360
+ /** The manifest, as the run reports it. */
1361
+ file: string;
1362
+ /** The collection that manifest belongs to (proposal 0041). */
1363
+ collection: string;
1364
+ }
1365
+ /** What `mergeExternalMetadata` hands back. */
1366
+ interface MergedMetadata {
1367
+ /** The document's metadata with every owned key the manifest supplied. */
1368
+ extracted: ExtractedMetadata;
1369
+ /**
1370
+ * Owned keys the document itself also carried, in document order, each
1371
+ * with the manifest that owns it — so the finding names it without a
1372
+ * second lookup, and without a fallback for an index that is not there.
1373
+ */
1374
+ collisions: ExternalMetadataCollision[];
1375
+ /** Field-joined entries this document matched, one per manifest at most. */
1376
+ joins: ExternalMetadataJoin[];
1377
+ /**
1378
+ * Where a merged pointer's value lives. Answers only for a value the
1379
+ * manifest supplied — a bare key or its `/key` pointer, and anything
1380
+ * beneath it — and `undefined` for everything the document owns, which is
1381
+ * what `lineFor` is for.
1382
+ */
1383
+ locate: (pointer: string) => SourceLocation | undefined;
1384
+ }
1385
+ /** The join an external-metadata config asks for: `path` unless it names a field. */
1386
+ declare function externalMetadataJoin(manifest: Pick<ExternalMetadataConfig, "join">): string;
1387
+ /**
1388
+ * Load every manifest of every collection the run covers. Resolves to `null`
1389
+ * when none of them declares one, which is every setup that existed before
1390
+ * this feature.
1391
+ *
1392
+ * Every refusal is a `DocmetaError`: the manifest is a config-supplied input,
1393
+ * and one that is missing or misshapen is the run's problem, not a
1394
+ * document's (0014).
1395
+ */
1396
+ declare function loadExternalMetadata(collections: readonly CollectionConfig[], opts: LoadExternalMetadataOptions): Promise<ExternalMetadataIndex | null>;
1397
+ /**
1398
+ * Merge the external metadata for one document into its extracted metadata.
1399
+ *
1400
+ * `label` is the document as the run spells it, relative to `base`; a path
1401
+ * entry matches on the resolved absolute path, never on the spelling, so a
1402
+ * positional run from a subdirectory finds the same entry a config-corpus
1403
+ * run does. A field entry matches on the document's own value of the join
1404
+ * field, wherever the document lives. Stdin never matches a path entry:
1405
+ * there is no file behind it.
1406
+ *
1407
+ * `memberOf` names the collections this document belongs to, and only their
1408
+ * manifests are consulted (0041 rule 4). It is the caller's `memberOf(...)`
1409
+ * result, computed once per file.
1410
+ *
1411
+ * `present`, `format` and the document's own positions are untouched. A
1412
+ * manifest key is not in the document, so `lineFor` keeps answering
1413
+ * `undefined` for it, and `locate` answers instead.
1414
+ */
1415
+ declare function mergeExternalMetadata(label: string, extracted: ExtractedMetadata, index: ExternalMetadataIndex | null, memberOf: readonly string[], base: string): MergedMetadata;
1416
+ /** The `/key` pointer for an external-metadata finding, RFC 6901 escaped. */
1417
+ declare function externalMetadataPointer(key: string): string;
1418
+ /**
1419
+ * Path entries naming no loaded document.
1420
+ *
1421
+ * `loaded` are the run's file labels, relative to `base`. Checked only when
1422
+ * the run is the config corpus (the same invariant corpus checks use): a
1423
+ * positional path means the operator chose to look at part of the corpus,
1424
+ * and an entry for the rest is expected, not orphaned.
1425
+ */
1426
+ declare function orphanEntries(index: ExternalMetadataIndex | null, loaded: readonly string[], base: string, collections?: readonly string[]): ExternalMetadataEntry[];
1427
+ /**
1428
+ * Field entries no loaded document matched (0039). `matched` is field -> the
1429
+ * values documents in the run carried, which the caller collects from each
1430
+ * document's `joins` — so this runs after the per-file loop, under the same
1431
+ * corpus invariant as `orphanEntries`.
1432
+ */
1433
+ declare function orphanJoins(index: ExternalMetadataIndex | null, matched: ReadonlyMap<string, ReadonlySet<string>>, collections?: readonly string[]): ExternalMetadataEntry[];
1434
+ /** The operational error an orphan check raises, naming the first entry. */
1435
+ declare function orphanError(orphans: readonly ExternalMetadataEntry[]): DocmetaError;
1436
+
1128
1437
  declare class Validator {
1129
1438
  private readonly schemaOptions;
1130
1439
  /**
@@ -1170,7 +1479,13 @@ declare class Validator {
1170
1479
  * Callers with an extractor that supplies no column pass nothing and get the
1171
1480
  * previous behavior exactly.
1172
1481
  */
1173
- validate(data: Record<string, unknown>, refs: string[], lineFor: (pointer: string) => number | undefined, colFor?: (pointer: string) => number | undefined): Promise<FieldError[]>;
1482
+ validate(data: Record<string, unknown>, refs: string[], lineFor: (pointer: string) => number | undefined, colFor?: (pointer: string) => number | undefined,
1483
+ /**
1484
+ * Where a merged value lives when it is not in the document (proposal
1485
+ * 0037): a manifest's file and line. Consulted before `lineFor`,
1486
+ * and additive in the way `colFor` was.
1487
+ */
1488
+ locate?: (pointer: string) => SourceLocation | undefined): Promise<FieldError[]>;
1174
1489
  }
1175
1490
 
1176
1491
  /**
@@ -1187,7 +1502,7 @@ declare const DEFAULT_SCHEMAS: readonly string[];
1187
1502
  * The ref *string* is what `resolveSchemaSet` returns and therefore what every
1188
1503
  * report names, what every baseline fingerprint is taken over, and what keys
1189
1504
  * `Validator`'s compile cache. Widening those to carry a mapping would have
1190
- * changed all three; the `{source, integrity}` sidecar travels separately, in
1505
+ * changed all three; the `{source, integrity}` pair travels separately, in
1191
1506
  * the pin map below.
1192
1507
  */
1193
1508
  declare function schemaEntryRef(entry: SchemaEntry): string;
@@ -1257,9 +1572,63 @@ interface ResolveParams {
1257
1572
  * failure mode this key exists to remove.
1258
1573
  */
1259
1574
  onNotice?: (message: string) => void;
1575
+ /**
1576
+ * The collections this file belongs to (proposal 0041), from `memberOf`.
1577
+ *
1578
+ * What an `overrides[].collection` entry is matched against, in place of the
1579
+ * glob match a `files:` entry gets. Absent means the caller decided
1580
+ * membership does not apply — a library caller with no config file, or a
1581
+ * command that has not resolved it — and a `collection:` override then
1582
+ * matches nothing, rather than everything.
1583
+ */
1584
+ memberOf?: readonly string[];
1260
1585
  }
1586
+
1261
1587
  declare function resolveSchemaSet(params: ResolveParams): string[];
1262
1588
 
1589
+ /**
1590
+ * Collection views, and the membership adapter that decides what a collection
1591
+ * contains.
1592
+ *
1593
+ * `memberOf` is proposal 0041's rule 10: which collections a file belongs to,
1594
+ * as path arithmetic against the config file's directory. It is what external
1595
+ * metadata attaches to, what an `overrides[].collection` resolves through, and
1596
+ * — since 0041 rule 7 — what a SQL view holds.
1597
+ *
1598
+ * One meaning of "collection", everywhere. 0027 built each view from the files
1599
+ * an override *won schema resolution for*, so views were disjoint, only a
1600
+ * collection an override pointed at had a view at all, and a file whose own
1601
+ * `$schema` outranked the override was announced as not being in it. 0041
1602
+ * makes a view the set the config says it is: every declared collection is a
1603
+ * view, two views may overlap, and `FROM authors` reads as "the files the
1604
+ * authors collection selects".
1605
+ *
1606
+ * That restores 0021's founding rule, which 0027 had to bend: a plain read
1607
+ * resolves no schemas. Nothing in this module resolves anything, so there is
1608
+ * no trust refusal to demote a file over, no per-file walk to pay for, and no
1609
+ * notice to print. Resolution still honours `overrides[].collection` — it
1610
+ * matches through `memberOf` in `resolve-schema.ts`, which is untouched.
1611
+ *
1612
+ * Shared by both projection consumers — `query` and the corpus checks
1613
+ * `validate` runs — so the two cannot drift on what a collection contains.
1614
+ */
1615
+
1616
+ /**
1617
+ * Names of the collections this file belongs to, in declaration order.
1618
+ *
1619
+ * Where the two bases meet. A run labels files relative to `base` — the
1620
+ * working directory for positional paths, the config's directory otherwise —
1621
+ * while membership is decided relative to the config file's directory, because
1622
+ * that is where a collection's globs were written (0004). So the label is
1623
+ * resolved against `base` and then measured from `configDir`.
1624
+ *
1625
+ * Pure path arithmetic (0041 rule 10): no `stat`, nothing that can fail, and
1626
+ * nothing that costs per file. Stdin and anything outside `configDir` are
1627
+ * members of nothing — stdin because there is no file behind it, and `isMember`
1628
+ * refuses a `../` path on its own.
1629
+ */
1630
+ declare function memberOf(collections: readonly CollectionConfig[], configDir: string, base: string, label: string): string[];
1631
+
1263
1632
  /** What a well-formed pin looks like, for error messages. */
1264
1633
  declare const INTEGRITY_SHAPE = "sha256-<64 hex characters>";
1265
1634
  /**
@@ -1273,6 +1642,23 @@ declare function integrityOf(bytes: Uint8Array): string;
1273
1642
  /** Whether `value` is a pin this version can verify. */
1274
1643
  declare function isIntegrity(value: string): boolean;
1275
1644
 
1645
+ /** Default network timeout, matching the schema fetch. */
1646
+ declare const EXTERNAL_METADATA_FETCH_TIMEOUT_MS = 10000;
1647
+ /** Body cap, matching the schema fetch. */
1648
+ declare const EXTERNAL_METADATA_FETCH_MAX_BYTES: number;
1649
+ interface ExternalMetadataFetchOptions {
1650
+ /** Environment variable holding a bearer token. Absent means an anonymous request. */
1651
+ tokenEnv?: string;
1652
+ timeoutMs?: number;
1653
+ maxBytes?: number;
1654
+ /** `--offline` / `offline:`: refuse rather than fetch. */
1655
+ offline?: boolean;
1656
+ /** For tests: the environment to read `tokenEnv` from. Defaults to `process.env`. */
1657
+ env?: Record<string, string | undefined>;
1658
+ }
1659
+ /** Fetch one remote manifest. Resolves to its text; throws `DocmetaError`. */
1660
+ declare function fetchExternalMetadata(url: string, opts?: ExternalMetadataFetchOptions): Promise<string>;
1661
+
1276
1662
  /**
1277
1663
  * Where the cache lives, relative to the project root.
1278
1664
  *
@@ -1620,4 +2006,4 @@ declare function extractorForExtension(ext: string): MetadataExtractor | undefin
1620
2006
  /** Extensions handled by implemented extractors (used for directory walks). */
1621
2007
  declare function supportedExtensions(): string[];
1622
2008
 
1623
- export { type ApplyOptions, type BaselineSummary, COMMON_FORMATS, type CheckConfig, type CommonFormat, type ConfigNotice, DEFAULT_SCHEMAS, DEFAULT_TTL_HOURS, DEFAULT_VENDOR_DIR, type DocmetaConfig, DocmetaError, type DocumentRefTrust, type ExtractOptions, type ExtractedMetadata, FILL_FORMATS, type FetchedSchema, type FieldError, type FillConfig, type FillFileResult, type FillOptions, type FillReportFormat, type FillReportOptions, type FillRun, type FillSummary, type FilledField, type FingerprintContext, type FrontmatterFlavor, type FrontmatterLocation, type GetFileResult, type GetOptions, type GetReportOptions, INTEGRITY_SHAPE, type JunitOptions, type LoadSchemaOptions, type LoadedConfig, type MetadataExtractor, type MetadataPatch, QUERY_FORMATS, type QueryChange, type QueryFormat, type QueryOptions, type QueryReportOptions, type QueryRun, REPORT_FORMATS, type ReadOptions, type ReportFormat, type ReportOptions, type RunConfig, type RunConfigOptions, type RunSummary, SCHEMA_CACHE_DIR, SCHEMA_CACHE_VERSION, type SarifOptions, SchemaCache, type SchemaCacheConfig, type SchemaCacheEntry, type SchemaEntry, type SchemaPin, type SchemaRefEntry, type SchemaTrustConfig, type SkipReason, type ValidateOptions, type ValidateRun, type ValidationResult, Validator, type VendorOptions, type VendorResult, applyFrontmatter, classifyRef, collectSchemaPins, extractFrontmatter, extractorForExtension, fetchSchemaBytes, frontmatterInnerText, getSchemasInfo, integrityOf, isCommonFormat, isFillFormat, isIntegrity, isQueryFormat, isReportFormat, listBuiltins, loadConfig, loadSchema, locateFrontmatter, parseConfig, rebaseConfigSchemaRefs, render, renderFill, renderFillGithub, renderGet, renderJunit, renderQuery, renderQueryCsv, renderSarif, resolveRunConfig, resolveSchemaSet, runFill, runGet, runQuery, runValidate, runVendorSchema, schemaCacheDir, schemaEntryRef, schemaLoadOptions, stringifyValue, supportedExtensions, vendorFileName, writeFileAtomic };
2009
+ export { type ApplyOptions, type BaselineSummary, COMMON_FORMATS, type CheckConfig, type CollectionConfig, type CommonFormat, type ConfigNotice, DEFAULT_SCHEMAS, DEFAULT_TTL_HOURS, DEFAULT_VENDOR_DIR, type DocmetaConfig, DocmetaError, type DocumentRefTrust, EXTERNAL_DUPLICATE_SCHEMA, EXTERNAL_KEYWORD, EXTERNAL_METADATA_FETCH_MAX_BYTES, EXTERNAL_METADATA_FETCH_TIMEOUT_MS, EXTERNAL_OWNED_SCHEMA, type ExternalMetadataCollision, type ExternalMetadataConfig, type ExternalMetadataEntry, type ExternalMetadataFetchOptions, type ExternalMetadataIndex, type ExternalMetadataJoin, type ExternalMetadataValue, type ExtractOptions, type ExtractedMetadata, FILL_FORMATS, type FetchedSchema, type FieldError, type FillConfig, type FillFileResult, type FillOptions, type FillReportFormat, type FillReportOptions, type FillRun, type FillSummary, type FilledField, type FingerprintContext, type FrontmatterFlavor, type FrontmatterLocation, type GetFileResult, type GetOptions, type GetReportOptions, INTEGRITY_SHAPE, type JunitOptions, type LoadExternalMetadataOptions, type LoadSchemaOptions, type LoadedConfig, type MergedMetadata, type MetadataExtractor, type MetadataPatch, PATH_JOIN, QUERY_FORMATS, type QueryChange, type QueryFormat, type QueryOptions, type QueryReportOptions, type QueryRun, REPORT_FORMATS, type ReadOptions, type ReportFormat, type ReportOptions, type RunConfig, type RunConfigOptions, type RunSummary, SCHEMA_CACHE_DIR, SCHEMA_CACHE_VERSION, type SarifOptions, SchemaCache, type SchemaCacheConfig, type SchemaCacheEntry, type SchemaEntry, type SchemaPin, type SchemaRefEntry, type SchemaTrustConfig, type SkipReason, type SourceLocation, type ValidateOptions, type ValidateRun, type ValidationResult, Validator, type VendorOptions, type VendorResult, applyFrontmatter, classifyRef, collectSchemaPins, externalMetadataJoin, externalMetadataPointer, externalMetadataUrlProblem, extractFrontmatter, extractorForExtension, fetchExternalMetadata, fetchSchemaBytes, frontmatterInnerText, getSchemasInfo, integrityOf, isCommonFormat, isFillFormat, isIntegrity, isMember, isQueryFormat, isReportFormat, listBuiltins, loadConfig, loadExternalMetadata, loadSchema, locateFrontmatter, memberOf, mergeExternalMetadata, orphanEntries, orphanError, orphanJoins, parseCollections, parseConfig, rebaseConfigSchemaRefs, render, renderFill, renderFillGithub, renderGet, renderJunit, renderQuery, renderQueryCsv, renderSarif, resolveRunConfig, resolveSchemaSet, runFill, runGet, runQuery, runValidate, runVendorSchema, schemaCacheDir, schemaEntryRef, schemaLoadOptions, selectCollections, stringifyValue, supportedExtensions, vendorFileName, writeFileAtomic };