@hawkeyexl/manni 1.0.1 → 1.1.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/{chunk-IRHWILCO.js → chunk-7SE7XDCL.js} +2964 -382
- package/dist/chunk-7SE7XDCL.js.map +1 -0
- package/dist/{chunk-FL75S2L4.js → chunk-WP2BP3ZX.js} +103 -5
- package/dist/chunk-WP2BP3ZX.js.map +1 -0
- package/dist/cli.js +2 -2
- package/dist/docmeta.js +2 -2
- package/dist/index.d.ts +719 -7
- package/dist/index.js +77 -1
- package/package.json +1 -1
- package/dist/chunk-FL75S2L4.js.map +0 -1
- package/dist/chunk-IRHWILCO.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Buffer } from 'node:buffer';
|
|
2
2
|
import { InferenceProvider } from '@hawkeyexl/inference';
|
|
3
|
+
import { DatabaseSync } from 'node:sqlite';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* The error every tool under the umbrella throws for an operational failure.
|
|
@@ -300,6 +301,175 @@ declare function selectCollections(collections: readonly CollectionConfig[], nam
|
|
|
300
301
|
*/
|
|
301
302
|
declare function isMember(collection: CollectionConfig, relPath: string): boolean;
|
|
302
303
|
|
|
304
|
+
/**
|
|
305
|
+
* The derived metadata channel: values computed from git history, CODEOWNERS
|
|
306
|
+
* and the review record on GitHub or GitLab rather than written by hand.
|
|
307
|
+
*
|
|
308
|
+
* A derived value never merges into what the schema sees. `manni meta derive`
|
|
309
|
+
* stamps the managed fields (`derive.fields` in the config) into the
|
|
310
|
+
* document, and `validate` reports a managed field whose asserted value
|
|
311
|
+
* differs from the derived one as a finding. This module holds the shared
|
|
312
|
+
* vocabulary — which fields can be derived, from which sources — and the two
|
|
313
|
+
* pure steps every source feeds: comparing an asserted value with a derived
|
|
314
|
+
* one, and turning the stale comparisons into findings.
|
|
315
|
+
*/
|
|
316
|
+
|
|
317
|
+
/** The six built-in fields, in the order messages list them. */
|
|
318
|
+
declare const DERIVABLE_FIELDS: readonly ["created", "last-updated", "authors", "owner", "reviewed-by", "last-reviewed"];
|
|
319
|
+
type BuiltinDerivableField = (typeof DERIVABLE_FIELDS)[number];
|
|
320
|
+
/**
|
|
321
|
+
* A managed field name: one of the six built-ins, or a key with an entry in
|
|
322
|
+
* `derive.commands`. The config parser guarantees one or the other.
|
|
323
|
+
*/
|
|
324
|
+
type DerivableField = string;
|
|
325
|
+
declare function isBuiltinField(x: string): x is BuiltinDerivableField;
|
|
326
|
+
/** Every source `derive.sources` may name; absent means all five. */
|
|
327
|
+
declare const DERIVE_SOURCES: readonly ["git", "codeowners", "github", "gitlab", "command"];
|
|
328
|
+
type DeriveSource = (typeof DERIVE_SOURCES)[number];
|
|
329
|
+
/**
|
|
330
|
+
* One configured command, as `derive.commands` reads after parsing: the argv
|
|
331
|
+
* to run, the program first, and how long to wait for it.
|
|
332
|
+
*/
|
|
333
|
+
interface DeriveCommand {
|
|
334
|
+
run: readonly string[];
|
|
335
|
+
timeoutMs: number;
|
|
336
|
+
}
|
|
337
|
+
declare function isDeriveSource(x: string): x is DeriveSource;
|
|
338
|
+
/**
|
|
339
|
+
* One fact a source produced, with where it came from. `evidence` is the
|
|
340
|
+
* short human-readable trail a finding quotes — a commit, a CODEOWNERS line,
|
|
341
|
+
* a pull request — so the reader can check the claim without re-running.
|
|
342
|
+
*/
|
|
343
|
+
interface DerivedValue {
|
|
344
|
+
value: unknown;
|
|
345
|
+
source: DeriveSource;
|
|
346
|
+
evidence: string;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Everything derived for one document. A `null` field means a source was
|
|
350
|
+
* consulted and had no fact to offer (a file with no commits yet, a path no
|
|
351
|
+
* CODEOWNERS rule matches); an absent field means no source answered for it.
|
|
352
|
+
*/
|
|
353
|
+
interface DerivedRecord {
|
|
354
|
+
file: string;
|
|
355
|
+
fields: Record<DerivableField, DerivedValue | null>;
|
|
356
|
+
}
|
|
357
|
+
/** Whether a source can answer at all; `reason` names the fix when not. */
|
|
358
|
+
interface SourceStatus {
|
|
359
|
+
available: boolean;
|
|
360
|
+
reason?: string;
|
|
361
|
+
}
|
|
362
|
+
/** Which host the origin remote points at, and what to call the project there. */
|
|
363
|
+
interface RemoteIdentity {
|
|
364
|
+
kind: "github" | "gitlab";
|
|
365
|
+
host: string;
|
|
366
|
+
/** `owner/repo` on GitHub; the full namespace path on GitLab. */
|
|
367
|
+
project: string;
|
|
368
|
+
}
|
|
369
|
+
/** One `APPROVED` review, the latest per reviewer. */
|
|
370
|
+
interface Approval {
|
|
371
|
+
login: string;
|
|
372
|
+
/** ISO-8601. */
|
|
373
|
+
submittedAt: string;
|
|
374
|
+
}
|
|
375
|
+
/** The merged PR/MR that carried a commit. Immutable once merged, so cacheable. */
|
|
376
|
+
interface MergedChange {
|
|
377
|
+
/** The PR number or MR iid. */
|
|
378
|
+
id: number;
|
|
379
|
+
/** ISO-8601. */
|
|
380
|
+
mergedAt: string;
|
|
381
|
+
/** Approvals only, deduplicated by login; the built-in clients order them oldest first. */
|
|
382
|
+
approvals: Approval[];
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* The review half of the derive context: the merged change behind a commit and
|
|
386
|
+
* who approved it. Reached through `gh` / `glab`, never an HTTP client — see
|
|
387
|
+
* `reviews.ts`.
|
|
388
|
+
*/
|
|
389
|
+
interface ReviewClient {
|
|
390
|
+
detect(): Promise<RemoteIdentity | null>;
|
|
391
|
+
/** Binary on PATH and authenticated for the host; `reason` names the fix. */
|
|
392
|
+
status(): Promise<SourceStatus>;
|
|
393
|
+
/** The merged PR/MR that contains the commit, or null (open, none, or unknown). */
|
|
394
|
+
mergedChangeFor(sha: string): Promise<MergedChange | null>;
|
|
395
|
+
}
|
|
396
|
+
/** One document as the sources see it. */
|
|
397
|
+
interface DeriveInput {
|
|
398
|
+
label: string;
|
|
399
|
+
absPath: string;
|
|
400
|
+
content: string;
|
|
401
|
+
extracted: ExtractedMetadata;
|
|
402
|
+
}
|
|
403
|
+
/** What a derive run holds constant across every document it visits. */
|
|
404
|
+
interface DeriveContext {
|
|
405
|
+
/** The run's working directory, the fallback when no config directory applies. */
|
|
406
|
+
cwd: string;
|
|
407
|
+
/** Directory the input labels are relative to, as `resolveRunConfig` settled it. */
|
|
408
|
+
base: string;
|
|
409
|
+
configDir?: string;
|
|
410
|
+
sources: readonly DeriveSource[];
|
|
411
|
+
fields: readonly DerivableField[];
|
|
412
|
+
/** CODEOWNERS path, when the config names one; resolved from `configDir`. */
|
|
413
|
+
codeowners?: string;
|
|
414
|
+
/** The `command` source's table, by the field each command derives; absent means none configured. */
|
|
415
|
+
commands?: Readonly<Record<string, DeriveCommand>>;
|
|
416
|
+
cache: boolean;
|
|
417
|
+
now: () => Date;
|
|
418
|
+
/** The review client for every repository in the run; the built-in `gh` / `glab` clients when absent. */
|
|
419
|
+
reviews?: ReviewClient;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* How an asserted value stands against the derived one.
|
|
423
|
+
*
|
|
424
|
+
* - `current` — they agree.
|
|
425
|
+
* - `stale` — the document says one thing and a source says another.
|
|
426
|
+
* - `unset` — the document says nothing and a source has a value.
|
|
427
|
+
* - `unknown` — no source could answer, so nothing is claimed either way.
|
|
428
|
+
*/
|
|
429
|
+
type DerivedStatus = "current" | "stale" | "unset" | "unknown";
|
|
430
|
+
interface DerivedField {
|
|
431
|
+
field: DerivableField;
|
|
432
|
+
/** What the document carries; absent when it carries nothing. */
|
|
433
|
+
asserted?: unknown;
|
|
434
|
+
/**
|
|
435
|
+
* What the sources say. `null` when they could not answer, which is exactly
|
|
436
|
+
* when `status` is `unknown`.
|
|
437
|
+
*/
|
|
438
|
+
derived: unknown;
|
|
439
|
+
source?: DeriveSource;
|
|
440
|
+
evidence?: string;
|
|
441
|
+
status: DerivedStatus;
|
|
442
|
+
/** Whether `derive` wrote the value into the document. */
|
|
443
|
+
written: boolean;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* The `schema` ref a stale-field finding carries, and so its baseline and
|
|
447
|
+
* rule identity: `derived:stale/derived`. Shaped like `check:<name>` and
|
|
448
|
+
* `external:owned` so `classifyRef` passes it through as a built-in id rather
|
|
449
|
+
* than resolving it as a cwd-relative file path, and reserved in the registry
|
|
450
|
+
* for the same reason those are.
|
|
451
|
+
*/
|
|
452
|
+
declare const DERIVED_STALE_SCHEMA = "derived:stale";
|
|
453
|
+
/** The `keyword` every derived finding carries: no Ajv keyword produced it. */
|
|
454
|
+
declare const DERIVED_KEYWORD = "derived";
|
|
455
|
+
/**
|
|
456
|
+
* Compare what a document asserts with what a source derived.
|
|
457
|
+
*
|
|
458
|
+
* Pure. Lists compare as sets — order-insensitive, members deep-equal — so a
|
|
459
|
+
* reordered `authors:` is not a stale one. A missing or `null` derived value
|
|
460
|
+
* means the sources could not answer, which is `unknown` rather than a
|
|
461
|
+
* verdict either way. `written` is always false here; only `derive` writes.
|
|
462
|
+
*/
|
|
463
|
+
declare function compareDerived(field: DerivableField, asserted: unknown, derived: DerivedValue | null | undefined): DerivedField;
|
|
464
|
+
/**
|
|
465
|
+
* The findings `validate` files for a document's managed fields: one per
|
|
466
|
+
* field that is `stale` or `unset`. Current and unknown fields file nothing.
|
|
467
|
+
*
|
|
468
|
+
* `lineFor` is the document's own pointer lookup, so a finding lands on the
|
|
469
|
+
* line the asserted key sits on; an unset field has no line.
|
|
470
|
+
*/
|
|
471
|
+
declare function staleFindings(fields: readonly DerivedField[], lineFor: (pointer: string) => number | undefined): FieldError[];
|
|
472
|
+
|
|
303
473
|
interface SchemaOverride {
|
|
304
474
|
/**
|
|
305
475
|
* The glob, or globs, this override governs. A file matches when **any** of
|
|
@@ -403,6 +573,41 @@ interface CheckConfig {
|
|
|
403
573
|
/** One SQL statement whose rows follow the finding column convention. */
|
|
404
574
|
query: string;
|
|
405
575
|
}
|
|
576
|
+
/**
|
|
577
|
+
* One `derive.commands` entry: a program to run for a field's value, as the
|
|
578
|
+
* config spells it. `run` is the argv, the program first; `timeout` is in
|
|
579
|
+
* seconds. The derive context carries the parsed form, `DeriveCommand`.
|
|
580
|
+
*/
|
|
581
|
+
interface DeriveCommandConfig {
|
|
582
|
+
run: string[];
|
|
583
|
+
timeout?: number;
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* The derived channel: managed fields `manni meta derive` stamps from git
|
|
587
|
+
* history, CODEOWNERS, the review record on GitHub or GitLab, or a configured
|
|
588
|
+
* command, and `validate` checks for drift.
|
|
589
|
+
*/
|
|
590
|
+
interface DeriveConfig {
|
|
591
|
+
/**
|
|
592
|
+
* The managed fields. Each is one of `DERIVABLE_FIELDS` or a key of
|
|
593
|
+
* `commands`, never `$schema`, and never a key a manifest owns: a value
|
|
594
|
+
* with two authorities has none.
|
|
595
|
+
*/
|
|
596
|
+
fields: DerivableField[];
|
|
597
|
+
/** Which sources to consult; absent means all of `DERIVE_SOURCES`. */
|
|
598
|
+
sources?: DeriveSource[];
|
|
599
|
+
/**
|
|
600
|
+
* CODEOWNERS path, relative to the config file's directory, when it is not
|
|
601
|
+
* in one of the places the codeowners source looks by itself. Checked for
|
|
602
|
+
* existence at run time, not here.
|
|
603
|
+
*/
|
|
604
|
+
codeowners?: string;
|
|
605
|
+
/**
|
|
606
|
+
* The `command` source's table, by the field each command derives. A key
|
|
607
|
+
* is never a built-in field, `$schema`, or a key a manifest owns.
|
|
608
|
+
*/
|
|
609
|
+
commands?: Record<string, DeriveCommandConfig>;
|
|
610
|
+
}
|
|
406
611
|
/** Defaults for the `fill` command; every key is overridable by a CLI flag. */
|
|
407
612
|
interface FillConfig {
|
|
408
613
|
provider?: string;
|
|
@@ -435,6 +640,11 @@ interface DocmetaConfig {
|
|
|
435
640
|
* run's file set is the config-resolved corpus. See `CheckConfig`.
|
|
436
641
|
*/
|
|
437
642
|
checks?: CheckConfig[];
|
|
643
|
+
/**
|
|
644
|
+
* The managed fields `derive` stamps and `validate` checks for drift. See
|
|
645
|
+
* `DeriveConfig`.
|
|
646
|
+
*/
|
|
647
|
+
derive?: DeriveConfig;
|
|
438
648
|
/**
|
|
439
649
|
* Element paths to lift in addition to each format's convention. See
|
|
440
650
|
* `parseElementPath` for the syntax.
|
|
@@ -702,12 +912,27 @@ interface ValidateOptions {
|
|
|
702
912
|
* in charge, which itself defaults to off.
|
|
703
913
|
*/
|
|
704
914
|
offline?: boolean;
|
|
915
|
+
/**
|
|
916
|
+
* `--no-cache` (false): ask GitHub or GitLab again rather than reading the
|
|
917
|
+
* review cache. It reaches the comparison and any check reading the
|
|
918
|
+
* `derived` table; absent leaves the cache on.
|
|
919
|
+
*/
|
|
920
|
+
cache?: boolean;
|
|
705
921
|
/**
|
|
706
922
|
* `--no-checks` (false): skip the config's named corpus checks for this
|
|
707
923
|
* run. Absent leaves them on — they still only run when the resolved file
|
|
708
924
|
* set is the config-resolved corpus (proposal 0026).
|
|
709
925
|
*/
|
|
710
926
|
checks?: boolean;
|
|
927
|
+
/**
|
|
928
|
+
* `--no-derive` (false): skip comparing each managed field (`derive.fields`
|
|
929
|
+
* in the config, proposal 0040) with what the evidence says. Absent leaves
|
|
930
|
+
* the comparison on whenever `derive:` is configured — on scoped runs too,
|
|
931
|
+
* since it is per file rather than a corpus rule.
|
|
932
|
+
*/
|
|
933
|
+
derive?: boolean;
|
|
934
|
+
/** The clock an uncommitted body change is dated by. Test seam; default `new Date()`. */
|
|
935
|
+
now?: () => Date;
|
|
711
936
|
}
|
|
712
937
|
interface ValidateRun {
|
|
713
938
|
results: ValidationResult[];
|
|
@@ -767,11 +992,60 @@ interface GetOptions {
|
|
|
767
992
|
* `--offline` uniformly without knowing which subcommand needs it.
|
|
768
993
|
*/
|
|
769
994
|
offline?: boolean;
|
|
995
|
+
/**
|
|
996
|
+
* `--no-cache` (false): ask GitHub or GitLab again rather than reading the
|
|
997
|
+
* review cache. Only `--derived` consults it, and only for `reviewed-by`
|
|
998
|
+
* and `last-reviewed`; absent leaves the cache on.
|
|
999
|
+
*/
|
|
1000
|
+
cache?: boolean;
|
|
1001
|
+
/**
|
|
1002
|
+
* Whether to resolve each requested field against the evidence — git
|
|
1003
|
+
* history, CODEOWNERS, the review record, a configured command (proposals
|
|
1004
|
+
* 0040, 0042). **On unless explicitly `false`** (proposal 0043): a read
|
|
1005
|
+
* says what the value is and where it came from, and `--no-derived` is the
|
|
1006
|
+
* way back to what the document alone stores.
|
|
1007
|
+
*
|
|
1008
|
+
* Only the requested fields a source can state are derived, so a field no
|
|
1009
|
+
* source claims consults nothing and spawns nothing. Stdin is included in
|
|
1010
|
+
* the run and simply derives nothing: a piped document has no path, so no
|
|
1011
|
+
* source can speak for it, and that is an answer rather than an error.
|
|
1012
|
+
*/
|
|
1013
|
+
derived?: boolean;
|
|
1014
|
+
/** The clock an uncommitted body change is dated by. Test seam; default `new Date()`. */
|
|
1015
|
+
now?: () => Date;
|
|
770
1016
|
}
|
|
771
1017
|
interface GetFileResult {
|
|
772
1018
|
file: string;
|
|
773
1019
|
present: boolean;
|
|
774
1020
|
values: Record<string, unknown>;
|
|
1021
|
+
/**
|
|
1022
|
+
* The evidence per requested field. A derivable field is always a key
|
|
1023
|
+
* here: a `DerivedValue` when a source answered, `null` when every
|
|
1024
|
+
* consulted source had nothing to say (a file with no commits, a path no
|
|
1025
|
+
* CODEOWNERS rule matches). A requested field that is **not** derivable is
|
|
1026
|
+
* absent from the record. Absent altogether under `--no-derived`, when no
|
|
1027
|
+
* requested field is derivable, and on a file that did not parse.
|
|
1028
|
+
*/
|
|
1029
|
+
derived?: Record<string, DerivedValue | null>;
|
|
1030
|
+
/**
|
|
1031
|
+
* The effective value per requested field (proposal 0043): the document's
|
|
1032
|
+
* when it **carries the key**, the derived one otherwise, and absent when
|
|
1033
|
+
* neither side has it. Presence is `Object.hasOwn`, not truthiness, so a
|
|
1034
|
+
* document writing `owner: null` has asserted a value and no derived one
|
|
1035
|
+
* replaces it — the same rule the `resolved` SQL view implements.
|
|
1036
|
+
*
|
|
1037
|
+
* Shaped exactly like `values`: one entry per requested field, `undefined`
|
|
1038
|
+
* where nothing resolved, which JSON drops. Absent under `--no-derived`,
|
|
1039
|
+
* and on a file that did not parse.
|
|
1040
|
+
*/
|
|
1041
|
+
resolved?: Record<string, unknown>;
|
|
1042
|
+
/**
|
|
1043
|
+
* Which side answered, for the fields that resolved to something. A field
|
|
1044
|
+
* neither the document nor any source has is absent, which is how a reader
|
|
1045
|
+
* tells "unset" from "unset, but derivable". Absent under `--no-derived`,
|
|
1046
|
+
* and on a file that did not parse.
|
|
1047
|
+
*/
|
|
1048
|
+
origin?: Record<string, "asserted" | "derived">;
|
|
775
1049
|
/**
|
|
776
1050
|
* Why this file yielded no values, when it yielded none for a reason.
|
|
777
1051
|
*
|
|
@@ -833,6 +1107,12 @@ interface QueryOptions {
|
|
|
833
1107
|
* suppress.
|
|
834
1108
|
*/
|
|
835
1109
|
offline?: boolean;
|
|
1110
|
+
/**
|
|
1111
|
+
* `--no-cache` (false): ask GitHub or GitLab again rather than reading the
|
|
1112
|
+
* review cache. Only a statement naming the `derived` table consults it,
|
|
1113
|
+
* and only for `reviewed-by` and `last-reviewed`; absent leaves it on.
|
|
1114
|
+
*/
|
|
1115
|
+
cache?: boolean;
|
|
836
1116
|
/**
|
|
837
1117
|
* `--dry-run`: preview the statement's per-file changes — the diff it
|
|
838
1118
|
* would make, files untouched. Without it a mutating statement applies,
|
|
@@ -861,6 +1141,8 @@ interface QueryOptions {
|
|
|
861
1141
|
* applied — a flag that would silently mean nothing must refuse.
|
|
862
1142
|
*/
|
|
863
1143
|
schemas?: string[];
|
|
1144
|
+
/** The clock an uncommitted body change is dated by. Test seam; default `new Date()`. */
|
|
1145
|
+
now?: () => Date;
|
|
864
1146
|
}
|
|
865
1147
|
/**
|
|
866
1148
|
* One thing a statement changed, in file-space terms. Cell-level kinds carry
|
|
@@ -1150,7 +1432,12 @@ type SkipReason =
|
|
|
1150
1432
|
/** Writing it would leave the document failing its own schema. */
|
|
1151
1433
|
| "schema-mismatch"
|
|
1152
1434
|
/** The model declined to propose a value. */
|
|
1153
|
-
| "no-proposal"
|
|
1435
|
+
| "no-proposal"
|
|
1436
|
+
/**
|
|
1437
|
+
* The field is managed by `derive` (`derive.fields` in the config), so it
|
|
1438
|
+
* was never sent for inference: only `manni meta derive` writes it.
|
|
1439
|
+
*/
|
|
1440
|
+
| "managed";
|
|
1154
1441
|
interface FilledField {
|
|
1155
1442
|
/** JSON Pointer, e.g. "/title" — the same form `validate` reports. */
|
|
1156
1443
|
field: string;
|
|
@@ -1261,6 +1548,91 @@ interface FillOptions {
|
|
|
1261
1548
|
|
|
1262
1549
|
declare function runFill(opts: FillOptions): Promise<FillRun>;
|
|
1263
1550
|
|
|
1551
|
+
interface DeriveOptions {
|
|
1552
|
+
inputs: string[];
|
|
1553
|
+
/**
|
|
1554
|
+
* `--collection <name>`, repeatable: stamp only the named configured
|
|
1555
|
+
* collections instead of every declared one (proposal 0041). Cannot be
|
|
1556
|
+
* combined with paths.
|
|
1557
|
+
*/
|
|
1558
|
+
collections?: string[];
|
|
1559
|
+
/** `--fields`: the managed fields to stamp this run; config `derive.fields` otherwise. */
|
|
1560
|
+
fields?: string[];
|
|
1561
|
+
/** `--sources`: the sources to consult; config `derive.sources`, else all four. */
|
|
1562
|
+
sources?: string[];
|
|
1563
|
+
/** `--dry-run`: report what would change and write nothing. */
|
|
1564
|
+
dryRun?: boolean;
|
|
1565
|
+
/** `--check`: implies `dryRun`; stale and unset fields are findings. */
|
|
1566
|
+
check?: boolean;
|
|
1567
|
+
/** Use the on-disk GitHub or GitLab review cache. Default true. */
|
|
1568
|
+
cache?: boolean;
|
|
1569
|
+
/** `--as` format override (extractor name). */
|
|
1570
|
+
as?: string;
|
|
1571
|
+
exts?: string[];
|
|
1572
|
+
exclude?: string[];
|
|
1573
|
+
configPath?: string;
|
|
1574
|
+
/** `--no-config`: skip config discovery and use the built-in defaults. */
|
|
1575
|
+
noConfig?: boolean;
|
|
1576
|
+
cwd?: string;
|
|
1577
|
+
/** Permit an input set that resolves to zero files (see `assertNonEmpty`). */
|
|
1578
|
+
allowEmpty?: boolean;
|
|
1579
|
+
/**
|
|
1580
|
+
* `--no-gitignore` (false). Absent leaves config `respectGitignore:` in
|
|
1581
|
+
* charge, which itself defaults to on.
|
|
1582
|
+
*/
|
|
1583
|
+
respectGitignore?: boolean;
|
|
1584
|
+
/** Diagnostics for the user; the CLI writes these to stderr. */
|
|
1585
|
+
onNotice?: (message: string) => void;
|
|
1586
|
+
/** Called once when a config governs the run, so the CLI can report it. */
|
|
1587
|
+
onConfigLoaded?: (info: ConfigNotice) => void;
|
|
1588
|
+
/** The clock an uncommitted body change is dated by. Test seam; default `new Date()`. */
|
|
1589
|
+
now?: () => Date;
|
|
1590
|
+
/** The review client, for every repository in the run. Test seam; default `gh` / `glab`. */
|
|
1591
|
+
reviews?: ReviewClient;
|
|
1592
|
+
}
|
|
1593
|
+
interface DeriveFileResult {
|
|
1594
|
+
file: string;
|
|
1595
|
+
/** Extractor/format used; `unknown` when none matched the file. */
|
|
1596
|
+
format: string;
|
|
1597
|
+
/** One entry per requested field, in the requested order. Empty on `error`. */
|
|
1598
|
+
fields: DerivedField[];
|
|
1599
|
+
/**
|
|
1600
|
+
* Whether writing the stale and unset fields changed the document, or
|
|
1601
|
+
* would have but for `dryRun`. Computed from the writer's output, so a
|
|
1602
|
+
* patch the format serializes to the same bytes is not a change.
|
|
1603
|
+
*/
|
|
1604
|
+
changed: boolean;
|
|
1605
|
+
/** Why the file could not be derived or written; the run goes on without it. */
|
|
1606
|
+
error?: string;
|
|
1607
|
+
/**
|
|
1608
|
+
* Under `check`, the findings for this file: one per stale or unset field,
|
|
1609
|
+
* at the field's line, plus one for an `error`. Absent otherwise.
|
|
1610
|
+
*/
|
|
1611
|
+
findings?: FieldError[];
|
|
1612
|
+
}
|
|
1613
|
+
interface DeriveSummary {
|
|
1614
|
+
files: number;
|
|
1615
|
+
/** Files whose document changed, or would have under `dryRun`. */
|
|
1616
|
+
changed: number;
|
|
1617
|
+
/** Fields whose write reached the disk: always 0 under `dryRun` and `check`. */
|
|
1618
|
+
written: number;
|
|
1619
|
+
stale: number;
|
|
1620
|
+
unset: number;
|
|
1621
|
+
unknown: number;
|
|
1622
|
+
errors: number;
|
|
1623
|
+
}
|
|
1624
|
+
interface DeriveRun {
|
|
1625
|
+
results: DeriveFileResult[];
|
|
1626
|
+
summary: DeriveSummary;
|
|
1627
|
+
dryRun: boolean;
|
|
1628
|
+
check: boolean;
|
|
1629
|
+
/** One status per source the run consulted; a source nobody asked for is absent. */
|
|
1630
|
+
sources: Partial<Record<DeriveSource, SourceStatus>>;
|
|
1631
|
+
/** Where the run stood, for the SARIF reporter under `check`. See `ValidateRun.frame`. */
|
|
1632
|
+
frame: FingerprintContext;
|
|
1633
|
+
}
|
|
1634
|
+
declare function runDerive(opts: DeriveOptions): Promise<DeriveRun>;
|
|
1635
|
+
|
|
1264
1636
|
/**
|
|
1265
1637
|
* The `schema` ref a collision finding carries, and so its baseline and rule
|
|
1266
1638
|
* identity: `external:owned/external`. Shaped like `check:<name>` so
|
|
@@ -1659,6 +2031,330 @@ interface ExternalMetadataFetchOptions {
|
|
|
1659
2031
|
/** Fetch one remote manifest. Resolves to its text; throws `DocmetaError`. */
|
|
1660
2032
|
declare function fetchExternalMetadata(url: string, opts?: ExternalMetadataFetchOptions): Promise<string>;
|
|
1661
2033
|
|
|
2034
|
+
/** Which sources can state each built-in field, in precedence order. */
|
|
2035
|
+
declare const FIELD_SOURCES: Readonly<Record<BuiltinDerivableField, readonly DeriveSource[]>>;
|
|
2036
|
+
interface DeriveResult {
|
|
2037
|
+
/** Keyed by `DeriveInput.label`; every input has a record. */
|
|
2038
|
+
records: Map<string, DerivedRecord>;
|
|
2039
|
+
/**
|
|
2040
|
+
* One status per source the run consulted. A source nobody asked for is
|
|
2041
|
+
* absent, and so is whichever of `github` and `gitlab` the origin remote does
|
|
2042
|
+
* not point at. Absent means not applicable here, never unavailable.
|
|
2043
|
+
*/
|
|
2044
|
+
sources: Partial<Record<DeriveSource, SourceStatus>>;
|
|
2045
|
+
}
|
|
2046
|
+
/**
|
|
2047
|
+
* Which sources can state a field, in precedence order: the built-in table
|
|
2048
|
+
* for one of the six, `command` for a key of `commands`, nothing otherwise.
|
|
2049
|
+
* A built-in never reaches the command arm, whatever the table says.
|
|
2050
|
+
*/
|
|
2051
|
+
declare function sourcesFor(field: DerivableField, commands?: Readonly<Record<string, DeriveCommand>>): readonly DeriveSource[];
|
|
2052
|
+
/** The sources a run consults: requested, and able to state a requested field. */
|
|
2053
|
+
declare function consultedSources(fields: readonly DerivableField[], sources: readonly DeriveSource[], commands?: Readonly<Record<string, DeriveCommand>>): DeriveSource[];
|
|
2054
|
+
/**
|
|
2055
|
+
* Throw the exit-2 error for the first consulted source that could not
|
|
2056
|
+
* answer. `hint` is the command's own way out, appended after a semicolon.
|
|
2057
|
+
*/
|
|
2058
|
+
declare function assertSourcesAvailable(sources: Partial<Record<DeriveSource, SourceStatus>>, hint?: string): void;
|
|
2059
|
+
declare function deriveMetadata(inputs: readonly DeriveInput[], ctx: DeriveContext): Promise<DeriveResult>;
|
|
2060
|
+
|
|
2061
|
+
/** How a client reaches the binary; tests point `bin` at node and a fake script. */
|
|
2062
|
+
interface SpawnOptions {
|
|
2063
|
+
/** Defaults to `gh` / `glab`, resolved on PATH. */
|
|
2064
|
+
bin?: string;
|
|
2065
|
+
/** Arguments placed before the command's own, such as a script for `node`. */
|
|
2066
|
+
prefixArgs?: string[];
|
|
2067
|
+
cwd: string;
|
|
2068
|
+
/** Kill the child after this long. Default 30 s. */
|
|
2069
|
+
timeoutMs?: number;
|
|
2070
|
+
}
|
|
2071
|
+
interface Run {
|
|
2072
|
+
/** Exit code; `null` when a signal ended the child. */
|
|
2073
|
+
code: number | null;
|
|
2074
|
+
stdout: string;
|
|
2075
|
+
stderr: string;
|
|
2076
|
+
timedOut: boolean;
|
|
2077
|
+
/** A stream passed `MAX_OUTPUT_BYTES` and the child was killed. */
|
|
2078
|
+
tooLarge: boolean;
|
|
2079
|
+
}
|
|
2080
|
+
/** The binary could not be started at all: nothing on PATH by that name. */
|
|
2081
|
+
declare class BinMissing extends Error {
|
|
2082
|
+
}
|
|
2083
|
+
/** One child, stdout collected, stderr drained and kept for the message. */
|
|
2084
|
+
declare function run(bin: string, args: string[], opts: SpawnOptions): Promise<Run>;
|
|
2085
|
+
|
|
2086
|
+
/**
|
|
2087
|
+
* The `command` source: a field derived by running whatever `derive.commands`
|
|
2088
|
+
* names for it. The value is the program's stdout — JSON when it parses as
|
|
2089
|
+
* JSON, the trimmed text otherwise, `null` when there is none.
|
|
2090
|
+
*
|
|
2091
|
+
* A command is spawned once per run, and its value copied into every
|
|
2092
|
+
* document's record, unless its argv carries `{path}`, in which case it is
|
|
2093
|
+
* spawned once per document with the document's label in place. The argv is
|
|
2094
|
+
* never handed to a shell: what the config lists is what runs.
|
|
2095
|
+
*
|
|
2096
|
+
* The first failure ends the source for the whole run, with nothing further
|
|
2097
|
+
* spawned: a program that is not on PATH, a timeout, a non-zero exit. A
|
|
2098
|
+
* half-derived field would read as "the command said nothing" for the
|
|
2099
|
+
* documents it never reached, which is the false green the whole channel
|
|
2100
|
+
* refuses. Availability is reported, never thrown, as the other sources do.
|
|
2101
|
+
*/
|
|
2102
|
+
|
|
2103
|
+
/** The argv token a per-file command carries where the document's label goes. */
|
|
2104
|
+
declare const PATH_PLACEHOLDER = "{path}";
|
|
2105
|
+
interface CommandSourceOptions {
|
|
2106
|
+
/** Where the commands run: the config directory, else the run cwd. */
|
|
2107
|
+
cwd: string;
|
|
2108
|
+
/** Test seam: `bin` and `prefixArgs` replace the configured program. */
|
|
2109
|
+
spawn?: Partial<SpawnOptions>;
|
|
2110
|
+
}
|
|
2111
|
+
interface CommandSourceResult {
|
|
2112
|
+
status: SourceStatus;
|
|
2113
|
+
/** By label; every input present when available, keyed by field within. */
|
|
2114
|
+
records: Map<string, Record<string, DerivedValue | null>>;
|
|
2115
|
+
}
|
|
2116
|
+
/** Whether any argv element carries `{path}`, so the command runs once per document. */
|
|
2117
|
+
declare function isPerFile(command: DeriveCommand): boolean;
|
|
2118
|
+
/** The argv with every `{path}` replaced by the label, forward slashes as the run spells it. */
|
|
2119
|
+
declare function argvFor(command: DeriveCommand, label: string): string[];
|
|
2120
|
+
/**
|
|
2121
|
+
* What a command's stdout means: nothing when blank, the parsed value when it
|
|
2122
|
+
* is *structured* JSON, the trimmed text otherwise. A date or a version string
|
|
2123
|
+
* stays a string; a list or an object arrives as one.
|
|
2124
|
+
*
|
|
2125
|
+
* Only `{`, `[` and `"` open a parse, and that boundary is the whole point.
|
|
2126
|
+
* A bare scalar is text a person wrote, and reading it as JSON silently
|
|
2127
|
+
* rewrites it: `1.10` becomes the number `1.1`, so a command reporting
|
|
2128
|
+
* version 1.10 stamps 1.1 into the document. A field wants the characters
|
|
2129
|
+
* the command printed. The structured forms are the reason a parse exists at
|
|
2130
|
+
* all — `verified-against` takes an object, and a list of anchors is a list —
|
|
2131
|
+
* and neither of those can be confused with prose.
|
|
2132
|
+
*/
|
|
2133
|
+
declare function valueOf(stdout: string): unknown;
|
|
2134
|
+
declare function deriveFromCommands(inputs: readonly DeriveInput[], commands: Readonly<Record<string, DeriveCommand>>, opts: CommandSourceOptions): Promise<CommandSourceResult>;
|
|
2135
|
+
|
|
2136
|
+
/**
|
|
2137
|
+
* The host and project an origin URL names, for the three spellings git
|
|
2138
|
+
* writes: `git@host:owner/repo.git`, `https://[user@]host/owner/repo[.git]`,
|
|
2139
|
+
* `ssh://git@host[:port]/owner/repo`. The project keeps every path segment,
|
|
2140
|
+
* because a GitLab namespace can nest (`group/sub/repo`). Anything else —
|
|
2141
|
+
* a local path, a bare host — is `null`. A local path is recognised before
|
|
2142
|
+
* the scp form is tried, because git reads `C:/mirrors/repo.git` as a
|
|
2143
|
+
* directory on drive C and the scp regex would read it as host `C`.
|
|
2144
|
+
*/
|
|
2145
|
+
declare function parseOriginUrl(url: string): {
|
|
2146
|
+
host: string;
|
|
2147
|
+
project: string;
|
|
2148
|
+
} | null;
|
|
2149
|
+
/**
|
|
2150
|
+
* Which platform a host is, and so which CLI reaches it. A host whose name
|
|
2151
|
+
* says `github` (github.com, github.example.com) is GitHub; one that says
|
|
2152
|
+
* `gitlab` is GitLab. A host that says neither, such as `git.example.com`,
|
|
2153
|
+
* is decided by the config: when exactly one of the `github` and `gitlab`
|
|
2154
|
+
* sources is requested, that is the platform the operator named. Otherwise
|
|
2155
|
+
* the answer is null, and the caller reports it as a source that cannot
|
|
2156
|
+
* answer. Nothing is ever assumed: the `github` source applies to GitHub
|
|
2157
|
+
* and the `gitlab` source to GitLab, and neither stands in for the other.
|
|
2158
|
+
*/
|
|
2159
|
+
declare function identityFromOrigin(host: string, project: string, requested?: readonly RemoteIdentity["kind"][]): RemoteIdentity | null;
|
|
2160
|
+
/**
|
|
2161
|
+
* The base for both CLIs: the same spawn, the same failure ladder, the same
|
|
2162
|
+
* status vocabulary. Subclasses supply the binary name and the lookups.
|
|
2163
|
+
*/
|
|
2164
|
+
declare abstract class CliClient implements ReviewClient {
|
|
2165
|
+
protected readonly identity: RemoteIdentity | null;
|
|
2166
|
+
protected readonly spawnOpts: SpawnOptions;
|
|
2167
|
+
protected abstract readonly tool: "gh" | "glab";
|
|
2168
|
+
constructor(identity: RemoteIdentity | null, spawnOpts: SpawnOptions);
|
|
2169
|
+
detect(): Promise<RemoteIdentity | null>;
|
|
2170
|
+
status(): Promise<SourceStatus>;
|
|
2171
|
+
mergedChangeFor(sha: string): Promise<MergedChange | null>;
|
|
2172
|
+
protected abstract lookup(identity: RemoteIdentity, sha: string): Promise<MergedChange | null>;
|
|
2173
|
+
protected get bin(): string;
|
|
2174
|
+
protected run(args: string[]): Promise<Run>;
|
|
2175
|
+
private timeout;
|
|
2176
|
+
/**
|
|
2177
|
+
* Run a call whose stdout is JSON. A not-found answer is `null`; any other
|
|
2178
|
+
* failure throws, naming the command the user can re-run by hand. The
|
|
2179
|
+
* message quotes the tool's own name rather than `bin`, which under test
|
|
2180
|
+
* is `node`.
|
|
2181
|
+
*/
|
|
2182
|
+
protected json(args: string[]): Promise<unknown>;
|
|
2183
|
+
}
|
|
2184
|
+
/**
|
|
2185
|
+
* GitHub through `gh`. Every call carries `--hostname` (or `-R host/project`)
|
|
2186
|
+
* so a GHES origin is reached even when `gh`'s default host is github.com.
|
|
2187
|
+
*
|
|
2188
|
+
* - `gh api --hostname <host> repos/<project>/commits/<sha>/pulls`
|
|
2189
|
+
* - if empty: `gh pr list --search <sha> --state merged --json number,mergedAt -R <host>/<project>`
|
|
2190
|
+
* (a squash-merged commit's original sha is only findable through search,
|
|
2191
|
+
* and a commit that came in through another repository is `[]` here, which
|
|
2192
|
+
* is a legitimate non-error)
|
|
2193
|
+
* - `gh api --hostname <host> repos/<project>/pulls/<n>` only when the list
|
|
2194
|
+
* item does not say whether it merged
|
|
2195
|
+
* - `gh api --hostname <host> repos/<project>/pulls/<n>/reviews?per_page=100`
|
|
2196
|
+
*/
|
|
2197
|
+
declare class GitHubClient extends CliClient {
|
|
2198
|
+
protected readonly tool = "gh";
|
|
2199
|
+
protected lookup(identity: RemoteIdentity, sha: string): Promise<MergedChange | null>;
|
|
2200
|
+
}
|
|
2201
|
+
/**
|
|
2202
|
+
* GitLab through `glab`. `:fullpath` is substituted by glab from the current
|
|
2203
|
+
* repository, which is why the client runs from the checkout.
|
|
2204
|
+
*
|
|
2205
|
+
* - `glab api --hostname <host> projects/:fullpath/repository/commits/<sha>/merge_requests`
|
|
2206
|
+
* - `glab api --hostname <host> projects/:fullpath/merge_requests/<iid>/approvals`
|
|
2207
|
+
*
|
|
2208
|
+
* GitLab records who approved but not when, so every approval is stamped
|
|
2209
|
+
* with the MR's `merged_at`; `deriveFromReviews` says so in the evidence.
|
|
2210
|
+
*/
|
|
2211
|
+
declare class GitLabClient extends CliClient {
|
|
2212
|
+
protected readonly tool = "glab";
|
|
2213
|
+
protected lookup(identity: RemoteIdentity, sha: string): Promise<MergedChange | null>;
|
|
2214
|
+
}
|
|
2215
|
+
/**
|
|
2216
|
+
* The client for the repository at `root`: origin read with
|
|
2217
|
+
* `git remote get-url origin`, the CLI chosen by `identityFromOrigin`, the
|
|
2218
|
+
* result wrapped in the on-disk cache. No origin (or no git) yields a client
|
|
2219
|
+
* whose `status()` says so; nothing throws here, because "no host" is a
|
|
2220
|
+
* source being unavailable, and that is reported where sources are reported.
|
|
2221
|
+
*
|
|
2222
|
+
* The CLI is spawned in `root`, not in the caller's `cwd`: `glab` fills in
|
|
2223
|
+
* `:fullpath` from the repository it runs in, and `gh` detects the
|
|
2224
|
+
* repository the same way, so the child must run from the checkout this
|
|
2225
|
+
* client answers for. `spawn.cwd` is the test seam that overrides that.
|
|
2226
|
+
*/
|
|
2227
|
+
declare function createReviewClient(root: string, opts: {
|
|
2228
|
+
cwd: string;
|
|
2229
|
+
cache: boolean;
|
|
2230
|
+
cacheDir: string;
|
|
2231
|
+
spawn?: Partial<SpawnOptions>;
|
|
2232
|
+
/** The review sources the run requested; decides a host that names neither platform. */
|
|
2233
|
+
requested?: readonly RemoteIdentity["kind"][];
|
|
2234
|
+
}): Promise<ReviewClient>;
|
|
2235
|
+
interface ReviewSourceInput {
|
|
2236
|
+
label: string;
|
|
2237
|
+
/** The newest body-changing commit; `null` for a working-tree document. */
|
|
2238
|
+
sha: string | null;
|
|
2239
|
+
}
|
|
2240
|
+
interface ReviewFacts {
|
|
2241
|
+
"reviewed-by": DerivedValue | null;
|
|
2242
|
+
"last-reviewed": DerivedValue | null;
|
|
2243
|
+
}
|
|
2244
|
+
interface ReviewSourceResult {
|
|
2245
|
+
status: SourceStatus;
|
|
2246
|
+
/** By label. Empty when the source is unavailable. */
|
|
2247
|
+
records: Map<string, ReviewFacts>;
|
|
2248
|
+
}
|
|
2249
|
+
/**
|
|
2250
|
+
* `reviewed-by` is every approver of the merged change, in approval order,
|
|
2251
|
+
* and every fact names the source of the host it came from, `github` or `gitlab`;
|
|
2252
|
+
* `last-reviewed` is the UTC date of the latest approval. A document with no
|
|
2253
|
+
* commit, no merged change, or a change nobody approved derives `null` for
|
|
2254
|
+
* both. One host lookup per distinct sha, however many documents share it.
|
|
2255
|
+
*
|
|
2256
|
+
* An unavailable client is reported and never called: `status.reason` names
|
|
2257
|
+
* the fix, and the caller decides whether that fails the run.
|
|
2258
|
+
*/
|
|
2259
|
+
declare function deriveFromReviews(inputs: readonly ReviewSourceInput[], client: ReviewClient): Promise<ReviewSourceResult>;
|
|
2260
|
+
|
|
2261
|
+
/**
|
|
2262
|
+
* The `derived` table (proposal 0040): what the evidence says each derivable
|
|
2263
|
+
* field should be, one row per file, as a read-only SQL view beside `docs`.
|
|
2264
|
+
*
|
|
2265
|
+
* `query` builds it when a statement names it, and a corpus check that names
|
|
2266
|
+
* it gets the same view — this module is what keeps the two from drifting.
|
|
2267
|
+
* It is a view over a backing table rather than a table, so that SQLite's own
|
|
2268
|
+
* `cannot modify derived because it is a view` refuses a write before any
|
|
2269
|
+
* effect gate has to: the value it holds is not stored anywhere, and the only
|
|
2270
|
+
* way to change it is to change the evidence. Both objects are transient: a
|
|
2271
|
+
* `--db` export drops them before the handle closes, so a frozen derived
|
|
2272
|
+
* value never outlives the run that computed it.
|
|
2273
|
+
*
|
|
2274
|
+
* The columns are the run's: the six built-in fields, then one per key of
|
|
2275
|
+
* `derive.commands` (proposal 0042), so a command-derived field is read
|
|
2276
|
+
* exactly as a built-in one is.
|
|
2277
|
+
*/
|
|
2278
|
+
|
|
2279
|
+
/** The third table: the effective value per field, over `docs` and the rows. */
|
|
2280
|
+
declare const RESOLVED_VIEW = "resolved";
|
|
2281
|
+
/**
|
|
2282
|
+
* Every column `resolved` carries, in order: `_path`, the `docs` data columns,
|
|
2283
|
+
* then any derivable field `docs` does not already have, then `_origin` and
|
|
2284
|
+
* `_sources`. A docs column that is also a derivable field appears once, in
|
|
2285
|
+
* the position `docs` gives it, so the field list only ever adds.
|
|
2286
|
+
*
|
|
2287
|
+
* The system columns are skipped: `_path` is already first, and `_format`,
|
|
2288
|
+
* `_present` and `_data` are facts about the document rather than values a
|
|
2289
|
+
* source could state. A frontmatter key spelled `_origin` or `_sources` is
|
|
2290
|
+
* skipped for the same reason a reserved one is — the column is taken.
|
|
2291
|
+
*/
|
|
2292
|
+
declare function resolvedColumns(docsColumns: readonly string[], commands?: Readonly<Record<string, DeriveCommand>>): string[];
|
|
2293
|
+
/**
|
|
2294
|
+
* Does the statement name the `resolved` table? The twin of `mentionsDerived`,
|
|
2295
|
+
* with the same shape and the same reason: `resolved` where a table goes, so
|
|
2296
|
+
* that a column alias or the word inside `unresolved` does not build a view —
|
|
2297
|
+
* and, more to the point, does not spawn git behind it.
|
|
2298
|
+
*/
|
|
2299
|
+
declare function mentionsResolved(sql: string): boolean;
|
|
2300
|
+
/**
|
|
2301
|
+
* Create the `resolved` view: one row per `docs` row, holding the effective
|
|
2302
|
+
* value of every field — what the document asserts when it carries the key,
|
|
2303
|
+
* what the evidence derived otherwise — plus `_origin` saying which of the two
|
|
2304
|
+
* answered, and the derived row's `_sources` unchanged. Call after
|
|
2305
|
+
* `createDocsTable` and `createDerivedView`.
|
|
2306
|
+
*
|
|
2307
|
+
* **Presence is decided by `_data`, never by NULL.** A docs column is NULL
|
|
2308
|
+
* both when the key is absent and when the document writes `key: null`, and
|
|
2309
|
+
* those are opposite answers: an explicit null is an assertion, and the
|
|
2310
|
+
* derived value must not overwrite it. So each field asks
|
|
2311
|
+
* `json_type(_data, '$."field"') IS NOT NULL`, which is true for a JSON null
|
|
2312
|
+
* and false for an absent key.
|
|
2313
|
+
*
|
|
2314
|
+
* `_origin` is `json_patch('{}', json_object(…))` over a CASE per field that
|
|
2315
|
+
* yields `'asserted'`, `'derived'`, or NULL. `json_object` alone would keep
|
|
2316
|
+
* the NULL members — a field neither side has would read as present with a
|
|
2317
|
+
* null origin — and RFC 7396 merge-patch, which `json_patch` implements, is
|
|
2318
|
+
* exactly the "a null member deletes the key" rule that drops them. One patch
|
|
2319
|
+
* call does the whole object, so the shape stays flat however many fields the
|
|
2320
|
+
* run carries.
|
|
2321
|
+
*
|
|
2322
|
+
* The join is a LEFT JOIN, so a file the derive run has no row for keeps its
|
|
2323
|
+
* asserted values with an all-`asserted` `_origin` and a NULL `_sources`.
|
|
2324
|
+
*
|
|
2325
|
+
* Read-only by construction: SQLite refuses a write to a view with no
|
|
2326
|
+
* INSTEAD OF trigger, and there is none. The effective value is not stored
|
|
2327
|
+
* anywhere, so the only way to change it is to change the document or the
|
|
2328
|
+
* evidence.
|
|
2329
|
+
*
|
|
2330
|
+
* Call it after `createDocsTable` and `createDerivedView`. SQLite accepts a
|
|
2331
|
+
* view over a table that does not exist yet and fails only at the first read,
|
|
2332
|
+
* as `no such table: main._derived_rows`, far from the call that got the
|
|
2333
|
+
* order wrong.
|
|
2334
|
+
*/
|
|
2335
|
+
declare function createResolvedView(db: DatabaseSync, docsColumns: readonly string[], commands?: Readonly<Record<string, DeriveCommand>>): void;
|
|
2336
|
+
|
|
2337
|
+
/** Where the GitHub or GitLab review cache lives, relative to the project root. `.manni/` is gitignored. */
|
|
2338
|
+
declare const REVIEW_CACHE_DIR = ".manni/meta/review-cache";
|
|
2339
|
+
/** The only entry format this version understands. */
|
|
2340
|
+
declare const REVIEW_CACHE_VERSION = 1;
|
|
2341
|
+
/** The GitHub or GitLab review cache: one immutable merged change per `host/project/sha`. */
|
|
2342
|
+
declare class ReviewCache {
|
|
2343
|
+
private readonly dir;
|
|
2344
|
+
private readonly enabled;
|
|
2345
|
+
constructor(dir: string, enabled: boolean);
|
|
2346
|
+
entryPath(key: string): string;
|
|
2347
|
+
/** The cached change, or `undefined` for a miss. Never `null`: nulls are not stored. */
|
|
2348
|
+
get(key: string): MergedChange | undefined;
|
|
2349
|
+
set(key: string, value: MergedChange): void;
|
|
2350
|
+
}
|
|
2351
|
+
/**
|
|
2352
|
+
* `client` with `mergedChangeFor` read through the cache. Only a merged
|
|
2353
|
+
* answer is stored. With no identity there is no key, and every call goes
|
|
2354
|
+
* straight through — which, for a client with no origin, is a `null`.
|
|
2355
|
+
*/
|
|
2356
|
+
declare function cachedClient(client: ReviewClient, cache: ReviewCache, identity: RemoteIdentity | null): ReviewClient;
|
|
2357
|
+
|
|
1662
2358
|
/**
|
|
1663
2359
|
* Where the cache lives, relative to the project root.
|
|
1664
2360
|
*
|
|
@@ -1873,6 +2569,17 @@ interface FillReportOptions {
|
|
|
1873
2569
|
declare function renderFillGithub(run: FillRun): string;
|
|
1874
2570
|
declare function renderFill(format: FillReportFormat, run: FillRun, opts?: FillReportOptions): string;
|
|
1875
2571
|
|
|
2572
|
+
/**
|
|
2573
|
+
* Every value `derive -f` accepts: the same five as `validate`, because a
|
|
2574
|
+
* `--check` run renders through validate's reporters. Stated as its own list
|
|
2575
|
+
* so the two can grow apart without either edit reaching the other.
|
|
2576
|
+
*/
|
|
2577
|
+
declare const DERIVE_FORMATS: readonly ["pretty", "json", "github", "sarif", "junit"];
|
|
2578
|
+
type DeriveReportFormat = (typeof DERIVE_FORMATS)[number];
|
|
2579
|
+
declare function isDeriveFormat(value: string): value is DeriveReportFormat;
|
|
2580
|
+
type DeriveReportOptions = ReportOptions;
|
|
2581
|
+
declare function renderDerive(run: DeriveRun, format: DeriveReportFormat, opts?: DeriveReportOptions): string;
|
|
2582
|
+
|
|
1876
2583
|
/**
|
|
1877
2584
|
* Reporter for `get`.
|
|
1878
2585
|
*
|
|
@@ -1896,12 +2603,17 @@ interface GetReportOptions {
|
|
|
1896
2603
|
/** `(unset)` for a missing field; JSON for anything that is not a string. */
|
|
1897
2604
|
declare function stringifyValue(value: unknown): string;
|
|
1898
2605
|
/**
|
|
1899
|
-
* One `<file>: <field>=<value>` line per requested field per file.
|
|
2606
|
+
* One `<file>: <field>=<value>` line per requested field per file. The value
|
|
2607
|
+
* is the **resolved** one where the run derived (proposal 0043), followed by
|
|
2608
|
+
* the annotation saying which side answered; under `--no-derived` it is what
|
|
2609
|
+
* the document stores, with no annotation at all.
|
|
1900
2610
|
*
|
|
1901
|
-
* `quiet` hides a file only when **every** requested field is unset
|
|
1902
|
-
*
|
|
1903
|
-
*
|
|
1904
|
-
*
|
|
2611
|
+
* `quiet` hides a file only when **every** requested field is unset, judged
|
|
2612
|
+
* after resolving — so a page whose only `owner` comes from CODEOWNERS is
|
|
2613
|
+
* shown, where before the flag hid it. A file where one field resolved and
|
|
2614
|
+
* another did not is still printed, `(unset)` included: the flag hides files,
|
|
2615
|
+
* never values, so `--quiet` can never be the reason a value the user asked
|
|
2616
|
+
* for went missing.
|
|
1905
2617
|
*/
|
|
1906
2618
|
declare function renderGet(results: GetFileResult[], fields: string[], opts?: GetReportOptions): string;
|
|
1907
2619
|
|
|
@@ -2006,4 +2718,4 @@ declare function extractorForExtension(ext: string): MetadataExtractor | undefin
|
|
|
2006
2718
|
/** Extensions handled by implemented extractors (used for directory walks). */
|
|
2007
2719
|
declare function supportedExtensions(): string[];
|
|
2008
2720
|
|
|
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 };
|
|
2721
|
+
export { type ApplyOptions, type Approval, type BaselineSummary, BinMissing, type BuiltinDerivableField, COMMON_FORMATS, type CheckConfig, type CollectionConfig, type CommandSourceOptions, type CommandSourceResult, type CommonFormat, type ConfigNotice, DEFAULT_SCHEMAS, DEFAULT_TTL_HOURS, DEFAULT_VENDOR_DIR, DERIVABLE_FIELDS, DERIVED_KEYWORD, DERIVED_STALE_SCHEMA, DERIVE_FORMATS, DERIVE_SOURCES, type DerivableField, type DeriveCommand, type DeriveCommandConfig, type DeriveConfig, type DeriveContext, type DeriveFileResult, type DeriveInput, type DeriveOptions, type DeriveReportFormat, type DeriveReportOptions, type DeriveResult, type DeriveRun, type DeriveSource, type DeriveSummary, type DerivedField, type DerivedRecord, type DerivedStatus, type DerivedValue, 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, FIELD_SOURCES, 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, GitHubClient, GitLabClient, INTEGRITY_SHAPE, type JunitOptions, type LoadExternalMetadataOptions, type LoadSchemaOptions, type LoadedConfig, type MergedChange, type MergedMetadata, type MetadataExtractor, type MetadataPatch, PATH_JOIN, PATH_PLACEHOLDER, QUERY_FORMATS, type QueryChange, type QueryFormat, type QueryOptions, type QueryReportOptions, type QueryRun, REPORT_FORMATS, RESOLVED_VIEW, REVIEW_CACHE_DIR, REVIEW_CACHE_VERSION, type ReadOptions, type RemoteIdentity, type ReportFormat, type ReportOptions, ReviewCache, type ReviewClient, type ReviewFacts, type ReviewSourceInput, type ReviewSourceResult, type Run, 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 SourceStatus, type SpawnOptions, type ValidateOptions, type ValidateRun, type ValidationResult, Validator, type VendorOptions, type VendorResult, applyFrontmatter, argvFor, assertSourcesAvailable, cachedClient, classifyRef, collectSchemaPins, compareDerived, consultedSources, createResolvedView, createReviewClient, deriveFromCommands, deriveFromReviews, deriveMetadata, externalMetadataJoin, externalMetadataPointer, externalMetadataUrlProblem, extractFrontmatter, extractorForExtension, fetchExternalMetadata, fetchSchemaBytes, frontmatterInnerText, getSchemasInfo, identityFromOrigin, integrityOf, isBuiltinField, isCommonFormat, isDeriveFormat, isDeriveSource, isFillFormat, isIntegrity, isMember, isPerFile, isQueryFormat, isReportFormat, listBuiltins, loadConfig, loadExternalMetadata, loadSchema, locateFrontmatter, memberOf, mentionsResolved, mergeExternalMetadata, orphanEntries, orphanError, orphanJoins, parseCollections, parseConfig, parseOriginUrl, rebaseConfigSchemaRefs, render, renderDerive, renderFill, renderFillGithub, renderGet, renderJunit, renderQuery, renderQueryCsv, renderSarif, resolveRunConfig, resolveSchemaSet, resolvedColumns, run, runDerive, runFill, runGet, runQuery, runValidate, runVendorSchema, schemaCacheDir, schemaEntryRef, schemaLoadOptions, selectCollections, sourcesFor, staleFindings, stringifyValue, supportedExtensions, valueOf, vendorFileName, writeFileAtomic };
|