@sema-agent/wiki-gate 0.0.0-stage → 7.67.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/LICENSE +107 -0
- package/README.md +95 -2
- package/dist/acceptance.d.ts +45 -0
- package/dist/acceptance.js +79 -0
- package/dist/check.d.ts +57 -0
- package/dist/check.js +378 -0
- package/dist/corrections.d.ts +29 -0
- package/dist/corrections.js +44 -0
- package/dist/coverage.d.ts +91 -0
- package/dist/coverage.js +151 -0
- package/dist/generators.d.ts +12 -0
- package/dist/generators.js +45 -0
- package/dist/genre.d.ts +46 -0
- package/dist/genre.js +15 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.js +12 -0
- package/dist/knobs.d.ts +19 -0
- package/dist/knobs.js +58 -0
- package/dist/page.d.ts +128 -0
- package/dist/page.js +175 -0
- package/dist/run.d.ts +81 -0
- package/dist/run.js +231 -0
- package/dist/source.d.ts +82 -0
- package/dist/source.js +193 -0
- package/dist/tree.d.ts +234 -0
- package/dist/tree.js +240 -0
- package/dist/versions.d.ts +64 -0
- package/dist/versions.js +53 -0
- package/package.json +36 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Business Source License 1.1
|
|
2
|
+
|
|
3
|
+
Parameters
|
|
4
|
+
|
|
5
|
+
Licensor: clay (github.com/clayboby)
|
|
6
|
+
Licensed Work: @sema-agent/core (sema-core) and the satellite packages
|
|
7
|
+
published from this repository (currently
|
|
8
|
+
@sema-agent/mods-kernel, @sema-agent/primitives,
|
|
9
|
+
@sema-agent/core-stores-sql and @sema-agent/wiki-gate)
|
|
10
|
+
(formerly published as @sema-ai/core)
|
|
11
|
+
The Licensed Work is (c) 2026 clay.
|
|
12
|
+
Additional Use Grant: You may make production use of the Licensed Work for
|
|
13
|
+
personal, educational, research, or other
|
|
14
|
+
non-commercial purposes. Commercial production use
|
|
15
|
+
requires a commercial license from the Licensor.
|
|
16
|
+
Change Date: 2030-07-13
|
|
17
|
+
Change License: Apache License, Version 2.0
|
|
18
|
+
|
|
19
|
+
For information about alternative licensing arrangements for the Licensed
|
|
20
|
+
Work, please contact the Licensor.
|
|
21
|
+
|
|
22
|
+
Notice
|
|
23
|
+
|
|
24
|
+
The Business Source License (this document, or the "License") is not an Open
|
|
25
|
+
Source license. However, the Licensed Work will eventually be made available
|
|
26
|
+
under an Open Source License, as stated in this License.
|
|
27
|
+
|
|
28
|
+
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
|
|
29
|
+
"Business Source License" is a trademark of MariaDB Corporation Ab.
|
|
30
|
+
|
|
31
|
+
-----------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
Terms
|
|
34
|
+
|
|
35
|
+
The Licensor hereby grants you the right to copy, modify, create derivative
|
|
36
|
+
works, redistribute, and make non-production use of the Licensed Work. The
|
|
37
|
+
Licensor may make an Additional Use Grant, above, permitting limited
|
|
38
|
+
production use.
|
|
39
|
+
|
|
40
|
+
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
41
|
+
available distribution of a specific version of the Licensed Work under this
|
|
42
|
+
License, whichever comes first, the Licensor hereby grants you rights under
|
|
43
|
+
the terms of the Change License, and the rights granted in the paragraph
|
|
44
|
+
above terminate.
|
|
45
|
+
|
|
46
|
+
If your use of the Licensed Work does not comply with the requirements
|
|
47
|
+
currently in effect as described in this License, you must purchase a
|
|
48
|
+
commercial license from the Licensor, its affiliated entities, or authorized
|
|
49
|
+
resellers, or you must refrain from using the Licensed Work.
|
|
50
|
+
|
|
51
|
+
All copies of the original and modified Licensed Work, and derivative works
|
|
52
|
+
of the Licensed Work, are subject to this License. This License applies
|
|
53
|
+
separately for each version of the Licensed Work and the Change Date may vary
|
|
54
|
+
for each version of the Licensed Work released by Licensor.
|
|
55
|
+
|
|
56
|
+
You must conspicuously display this License on each original or modified copy
|
|
57
|
+
of the Licensed Work. If you receive the Licensed Work in original or
|
|
58
|
+
modified form from a third party, the terms and conditions set forth in this
|
|
59
|
+
License apply to your use of that work.
|
|
60
|
+
|
|
61
|
+
Any use of the Licensed Work in violation of this License will automatically
|
|
62
|
+
terminate your rights under this License for the current and all other
|
|
63
|
+
versions of the Licensed Work.
|
|
64
|
+
|
|
65
|
+
This License does not grant you any right in any trademark or logo of
|
|
66
|
+
Licensor or its affiliates (provided that you may use a trademark or logo of
|
|
67
|
+
Licensor as expressly required by this License).
|
|
68
|
+
|
|
69
|
+
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
|
|
70
|
+
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
|
|
71
|
+
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
|
|
72
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
|
|
73
|
+
TITLE.
|
|
74
|
+
|
|
75
|
+
MariaDB hereby grants you permission to use this License's text to license
|
|
76
|
+
your works, and to refer to it using the trademark "Business Source License",
|
|
77
|
+
as long as you comply with the Covenants of Licensor below.
|
|
78
|
+
|
|
79
|
+
Covenants of Licensor
|
|
80
|
+
|
|
81
|
+
In consideration of the right to use this License's text and the "Business
|
|
82
|
+
Source License" name and trademark, Licensor covenants to MariaDB, and to all
|
|
83
|
+
other recipients of the licensed work to be provided by Licensor:
|
|
84
|
+
|
|
85
|
+
1. To specify as the Change License the GPL Version 2.0 or any later version,
|
|
86
|
+
or a license that is compatible with GPL Version 2.0 or a later version,
|
|
87
|
+
where "compatible" means that software provided under the Change License can
|
|
88
|
+
be included in a program with software provided under GPL Version 2.0 or a
|
|
89
|
+
later version. Licensor may specify additional Change Licenses without
|
|
90
|
+
limitation.
|
|
91
|
+
|
|
92
|
+
2. To either: (a) specify an additional grant of rights to use that does not
|
|
93
|
+
impose any additional restriction on the right granted in this License, as
|
|
94
|
+
the Additional Use Grant; or (b) insert the text "None".
|
|
95
|
+
|
|
96
|
+
3. To specify a Change Date.
|
|
97
|
+
|
|
98
|
+
4. Not to modify this License in any other way.
|
|
99
|
+
|
|
100
|
+
-----------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
Third-party notices
|
|
103
|
+
|
|
104
|
+
Versions of this package up to and including 1.277.1 were published under the
|
|
105
|
+
MIT License; those published copies remain governed by the license they were
|
|
106
|
+
distributed under. This package incorporates design and (where noted) prompt
|
|
107
|
+
content adapted from MIT-licensed projects — see NOTICE.md for attributions.
|
package/README.md
CHANGED
|
@@ -1,3 +1,96 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @sema-agent/wiki-gate
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The sema wiki gates: one reader module with three gate entries — anchors, freshness, coverage — and the stamp tool,
|
|
4
|
+
over the repository a configuration object names. A wiki page carries sentences marked with their evidence level and
|
|
5
|
+
the refs they rest on; the gates answer whether every claim is marked, whether every ref still resolves to what was
|
|
6
|
+
stamped, and whether every source the repository requires (for the wiki genre, also the shipped feature rows) is on
|
|
7
|
+
some page.
|
|
8
|
+
|
|
9
|
+
## One rule set
|
|
10
|
+
|
|
11
|
+
The gate holds every page directory it is pointed at — `docs/wiki` and `docs/manual` alike — to one rule set: the
|
|
12
|
+
genre, and with it the directory, is chosen by the entry's configuration object, never by a page's own header, and the
|
|
13
|
+
package opens no second interface for another genre. The genre is a word of the package's frozen genre table, `GENRES`
|
|
14
|
+
(`wiki` → `docs/wiki`, `manual` → `docs/manual`); a row names its directory, its readers, the evidence levels it admits
|
|
15
|
+
and the coverage it requires of its own. The wiki is read by embedders, deployers and callers, admits `G`, `P`, `V` and
|
|
16
|
+
`I`, and requires the shipped feature rows; the manual is read by users, scripters and admins, admits `G`, `U`, `P` and
|
|
17
|
+
`I`, and requires nothing of its own. A `U` sentence cites one `crit:<repo>@<X.Y.Z>:<cell>` key, and it is evidence only
|
|
18
|
+
while the acceptance index judges that cell `pass` and no later cell supersedes or retires it. A word the table does not
|
|
19
|
+
hold is every entry's refusal (exit 2), by name — there is no default genre and no directory member to name instead.
|
|
20
|
+
|
|
21
|
+
The rules — page shape, markers, refs, digests, severities, corrections, the stamp — are the package's and read the same
|
|
22
|
+
in every repository. A repository hands in its own readers (its export surface, its closed-set and contract-sentence
|
|
23
|
+
registries, its configuration catalog, its literal tables, its internal work-item name form, its test reader when its
|
|
24
|
+
tests are not vitest, its acceptance index and its criteria as it publishes them) and its own generators. A ref whose
|
|
25
|
+
kind needs a reader the repository does not configure is an anchors finding that says so. A source the repository names
|
|
26
|
+
among its `required` or `reported` sources comes with its reader: one named without a reader is every entry's refusal
|
|
27
|
+
(exit 2), and the coverage verdict line names each required source with its coverage. The page index (`page-index`),
|
|
28
|
+
the genre table (`genre-table`) and the table of knob fields (`knob-fields`) are the package's own generators, held by
|
|
29
|
+
every repository; a repository generator spelled like any of them is every entry's refusal.
|
|
30
|
+
|
|
31
|
+
A generator whose region is a table of configuration knobs names the fields its columns render with `rowFields`, out of
|
|
32
|
+
`KNOB_FIELDS`. The anchors gate then holds the region to that table: an unknown field, a field named twice, a missing
|
|
33
|
+
required field (`name`, `readPoints`) and a header row of another width are findings, and so is a knob row whose
|
|
34
|
+
`readPoints` cell holds no `path:line` coordinate. The gate reads the shape of a coordinate, never whether the file
|
|
35
|
+
and the line exist, and it judges a generator only by what the generator declares: a table rendered without a
|
|
36
|
+
`rowFields` declaration is not read as a table of knobs. The package scans no source for read points; the generator of
|
|
37
|
+
the repository that owns the catalog computes them.
|
|
38
|
+
|
|
39
|
+
## Install
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
npm install --save-dev @sema-agent/wiki-gate
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
ES modules only (`"type": "module"`), Node >= 20.18.1. One entry, `.`; there are no deep paths. Its one dependency is
|
|
46
|
+
`typescript` at an exact version: the digests a stamp writes are read through that compiler's printer, so another
|
|
47
|
+
version could read the same declaration to another digest.
|
|
48
|
+
|
|
49
|
+
## Use
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import { wikiAnchors, wikiFreshness, wikiCoverage, runWikiGate } from "@sema-agent/wiki-gate";
|
|
53
|
+
|
|
54
|
+
const config = {
|
|
55
|
+
root: "/path/to/repo", // every path is relative to it
|
|
56
|
+
genre: "wiki", // its row of GENRES names the page directory ("manual" = docs/manual, the same rules)
|
|
57
|
+
redFrom: { wiki: "7.69.0" }, // per genre: below it a finding warns, from it on a finding fails
|
|
58
|
+
readers: { /* snapshot, closedSets, contracts, catalog, tableValues, workItemName, pin, acceptanceIndex, criterionText */ },
|
|
59
|
+
generators: (read) => ({ /* name → { render: (...args) => ({ text, refs }), covers?, rowFields? } */ }),
|
|
60
|
+
required: { /* source name → its reader; one named without a reader cannot be judged */ },
|
|
61
|
+
reported: { /* source name → its reader; counted, never failed */ },
|
|
62
|
+
// optional: identity, releaseDistance, bans, preflight
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const r = wikiAnchors(config, { strict: true });
|
|
66
|
+
// r.exit: 0 = no failure (warnings counted), 1 = at least one failure, 2 = cannot judge (r.couldNotJudge says why)
|
|
67
|
+
// r.line: the verdict line every run speaks — a gate that judged nothing never looks like a green one
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`runWikiGate(config, { argv })` is the command line over the same entries and the stamp:
|
|
71
|
+
`anchors|freshness [--strict] [<page.md> …]`, `coverage [--strict] [--comms <dir>] [--report]`, `stamp <page.md> …`; each
|
|
72
|
+
also takes `--test <dir>` (the acceptance checkout) and `--corrections <dir>` (the correction-record checkout).
|
|
73
|
+
`--report` prints the coverage report as a table (source, cited, size, cited %). An option a command does not take is
|
|
74
|
+
refused by name (exit 2).
|
|
75
|
+
|
|
76
|
+
`citedByPages(tree, pages)` is the one reading of "what the pages cite" (feature rows on `feats:`, and for each source the
|
|
77
|
+
ids cited through a ref of its kind or covered by a generated region); the coverage gate counts from it, and a
|
|
78
|
+
repository's release tooling can ask it whether a name a release moved is on a page.
|
|
79
|
+
|
|
80
|
+
A finding is a warning while the repository's own `package.json` version is below its `redFrom` version for the page's
|
|
81
|
+
genre and a failure from that version on; `strict` takes the version out. A severity a finding carries of its own holds
|
|
82
|
+
under every reading: a `crit:` cell that is not a passing, current one, and an open correction, fail under every
|
|
83
|
+
reading; an old `V` run, or an old `U` cell, is a warning.
|
|
84
|
+
|
|
85
|
+
## Version
|
|
86
|
+
|
|
87
|
+
`@sema-agent/wiki-gate@X.Y.Z` is cut with `@sema-agent/core@X.Y.Z`: the same version number, built from the same
|
|
88
|
+
commit. A package version moves with every core release whether or not the gates changed. It does not take core.
|
|
89
|
+
|
|
90
|
+
## Source and package
|
|
91
|
+
|
|
92
|
+
In the sema-core repository the gates run through that repository's own binding, which loads this package's source
|
|
93
|
+
(tsx's `tsImport`) with the repository's readers, so a gate run needs no build. The package published from the same
|
|
94
|
+
source is its `tsc` output, and the two do not differ: the package's frozen export surface
|
|
95
|
+
(`test/export-surface.snapshot.json`), and the tarball test that imports the three entries from a packed tarball and
|
|
96
|
+
judges the same sample pages green and broken pages red, are the proof.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** The verdicts an acceptance cell may carry. Only `pass` vouches for a sentence. */
|
|
2
|
+
export declare const ACCEPTANCE_STATES: readonly string[];
|
|
3
|
+
/** Where an acceptance-index checkout holds its index. */
|
|
4
|
+
export declare const ACCEPTANCE_INDEX_FILE = "criteria-index/INDEX.json";
|
|
5
|
+
/** An acceptance cell's immutable key read: the repository word, the release, and the cell id within that release. */
|
|
6
|
+
export interface CritKey {
|
|
7
|
+
readonly repo: string;
|
|
8
|
+
readonly version: string;
|
|
9
|
+
readonly cell: string;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* `<repo>@<X.Y.Z>:<cell>`: `core@7.66.0:G6`, `core@7.66.0:G6.a`, `cli@1.0.161:G-EN1`. Undefined for anything else.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseCritKey(key: string): CritKey | undefined;
|
|
15
|
+
/** One cell as the index judges it now: its verdict, the digest of the text it judged, and the cells it supersedes or retires. */
|
|
16
|
+
export interface AcceptanceCell {
|
|
17
|
+
readonly key: string;
|
|
18
|
+
readonly state: string;
|
|
19
|
+
readonly textSha: string;
|
|
20
|
+
readonly supersedes: readonly string[];
|
|
21
|
+
readonly retires: readonly string[];
|
|
22
|
+
}
|
|
23
|
+
/** An index read at one commit: every key's current cell, and which later cell supersedes or retires a key. */
|
|
24
|
+
export interface AcceptanceIndex {
|
|
25
|
+
readonly commit: string;
|
|
26
|
+
readonly cells: ReadonlyMap<string, AcceptanceCell>;
|
|
27
|
+
readonly supersededBy: ReadonlyMap<string, string>;
|
|
28
|
+
readonly retiredBy: ReadonlyMap<string, string>;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The index text read: a JSON array of rows, each `{ key, state, textSha, supersedes?, retires? }` (other members are
|
|
32
|
+
* the owner's and are not read). The index only grows: a key written again is judged by its last row. A row that does
|
|
33
|
+
* not read this way makes the whole index unreadable — a gate never judges a cell from half an index.
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseAcceptanceIndex(text: string, commit: string): AcceptanceIndex;
|
|
36
|
+
/** How an index is read from a checkout named on the command line: undefined when none is named or the file is not there. */
|
|
37
|
+
export type AcceptanceIndexReader = (testRoot: string | undefined) => AcceptanceIndex | undefined;
|
|
38
|
+
/** The reader over `<checkout>/criteria-index/INDEX.json`, at the commit `commitOf` reads for the checkout. */
|
|
39
|
+
export declare function acceptanceIndexAt({ commitOf }: {
|
|
40
|
+
readonly commitOf: (dir: string) => string;
|
|
41
|
+
}): AcceptanceIndexReader;
|
|
42
|
+
/** Why a cell is no evidence, or undefined when it vouches (`pass`, not superseded, not retired). */
|
|
43
|
+
export declare function cellRefusal(index: AcceptanceIndex, key: string): string | undefined;
|
|
44
|
+
/** Whether a key's version is one this repository's tree has reached. */
|
|
45
|
+
export declare function keyReached(key: CritKey, version: string): boolean;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { compareVersions, parseVersion } from "./versions.js";
|
|
4
|
+
export const ACCEPTANCE_STATES = Object.freeze(["pass", "fail", "obs", "info", "not_constructed", "exempt"]);
|
|
5
|
+
export const ACCEPTANCE_INDEX_FILE = "criteria-index/INDEX.json";
|
|
6
|
+
const CRIT_KEY = /^([a-z][a-z0-9-]*)@(\d+\.\d+\.\d+):(G(?:\d+|-[A-Za-z0-9][A-Za-z0-9-]*)(?:\.[A-Za-z0-9]+)*)$/;
|
|
7
|
+
export function parseCritKey(key) {
|
|
8
|
+
const m = CRIT_KEY.exec(key);
|
|
9
|
+
return m && parseVersion(m[2]) ? { repo: m[1], version: m[2], cell: m[3] } : undefined;
|
|
10
|
+
}
|
|
11
|
+
export function parseAcceptanceIndex(text, commit) {
|
|
12
|
+
let rows;
|
|
13
|
+
try {
|
|
14
|
+
rows = JSON.parse(text);
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
throw new Error(`the acceptance index is not JSON: ${e.message}`);
|
|
18
|
+
}
|
|
19
|
+
if (!Array.isArray(rows))
|
|
20
|
+
throw new Error("the acceptance index is not an array of rows");
|
|
21
|
+
const keys = (v, at) => {
|
|
22
|
+
if (v === undefined)
|
|
23
|
+
return [];
|
|
24
|
+
if (!Array.isArray(v) || v.some((k) => typeof k !== "string" || parseCritKey(k) === undefined))
|
|
25
|
+
throw new Error(`${at} is not an array of acceptance keys`);
|
|
26
|
+
return v;
|
|
27
|
+
};
|
|
28
|
+
const cells = new Map();
|
|
29
|
+
const supersededBy = new Map();
|
|
30
|
+
const retiredBy = new Map();
|
|
31
|
+
rows.forEach((row, i) => {
|
|
32
|
+
const at = `acceptance index row ${i + 1}`;
|
|
33
|
+
if (row === null || typeof row !== "object" || Array.isArray(row))
|
|
34
|
+
throw new Error(`${at} is not an object`);
|
|
35
|
+
const r = row;
|
|
36
|
+
if (typeof r.key !== "string" || parseCritKey(r.key) === undefined)
|
|
37
|
+
throw new Error(`${at}: key ${JSON.stringify(r.key)} is not <repo>@<X.Y.Z>:<cell>`);
|
|
38
|
+
if (typeof r.state !== "string" || !ACCEPTANCE_STATES.includes(r.state))
|
|
39
|
+
throw new Error(`${at}: state ${JSON.stringify(r.state)} is not one of ${ACCEPTANCE_STATES.join(", ")}`);
|
|
40
|
+
if (typeof r.textSha !== "string" || r.textSha.length === 0)
|
|
41
|
+
throw new Error(`${at}: textSha is not a non-empty string`);
|
|
42
|
+
const cell = { key: r.key, state: r.state, textSha: r.textSha, supersedes: keys(r.supersedes, `${at}: supersedes`), retires: keys(r.retires, `${at}: retires`) };
|
|
43
|
+
cells.set(cell.key, cell);
|
|
44
|
+
});
|
|
45
|
+
for (const cell of cells.values()) {
|
|
46
|
+
for (const k of cell.supersedes)
|
|
47
|
+
supersededBy.set(k, cell.key);
|
|
48
|
+
for (const k of cell.retires)
|
|
49
|
+
retiredBy.set(k, cell.key);
|
|
50
|
+
}
|
|
51
|
+
return { commit, cells, supersededBy, retiredBy };
|
|
52
|
+
}
|
|
53
|
+
export function acceptanceIndexAt({ commitOf }) {
|
|
54
|
+
return (testRoot) => {
|
|
55
|
+
if (testRoot === undefined)
|
|
56
|
+
return undefined;
|
|
57
|
+
const file = join(testRoot, ACCEPTANCE_INDEX_FILE);
|
|
58
|
+
if (!existsSync(file))
|
|
59
|
+
return undefined;
|
|
60
|
+
return parseAcceptanceIndex(readFileSync(file, "utf8"), commitOf(testRoot));
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function cellRefusal(index, key) {
|
|
64
|
+
const cell = index.cells.get(key);
|
|
65
|
+
if (cell === undefined)
|
|
66
|
+
return `the acceptance index (at ${index.commit}) holds no cell ${key}`;
|
|
67
|
+
if (cell.state !== "pass")
|
|
68
|
+
return `the acceptance index (at ${index.commit}) judges ${key} \`${cell.state}\`; only \`pass\` vouches for a sentence`;
|
|
69
|
+
const by = index.supersededBy.get(key);
|
|
70
|
+
if (by !== undefined)
|
|
71
|
+
return `${key} is superseded by ${by}`;
|
|
72
|
+
const retired = index.retiredBy.get(key);
|
|
73
|
+
if (retired !== undefined)
|
|
74
|
+
return `${key} is retired by ${retired}`;
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
export function keyReached(key, version) {
|
|
78
|
+
return compareVersions(key.version, version) <= 0;
|
|
79
|
+
}
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { type Generated, type Generator, type WikiTree } from "./tree.js";
|
|
2
|
+
import { type Severity } from "./versions.js";
|
|
3
|
+
export declare const PAGE_KINDS: readonly string[];
|
|
4
|
+
/** The repositories that own pages; a page-id is prefixed by one of them, or by a genre's own word for a page about the genre. */
|
|
5
|
+
export declare const OWNER_REPOS: readonly string[];
|
|
6
|
+
/** A frontmatter key and whether it may repeat. A key not in this table is a finding (a typo is not a new key). */
|
|
7
|
+
export declare const FRONTMATTER_KEYS: Readonly<Record<string, "one" | "many">>;
|
|
8
|
+
/** The gate a finding belongs to, the page and file line it points at, its sentence, and a severity of its own. */
|
|
9
|
+
export interface Finding {
|
|
10
|
+
readonly gate: "anchors" | "freshness" | "coverage";
|
|
11
|
+
readonly page: string;
|
|
12
|
+
readonly line: number;
|
|
13
|
+
readonly message: string;
|
|
14
|
+
readonly fixed?: Severity;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* What page text, marker text and generated text never carry: identifiers of the repositories' internal record. A test
|
|
18
|
+
* file path inside a `pin:` ref is a coordinate and is exempt (it is removed before these run). The work-item name form
|
|
19
|
+
* is the internal record's own reading of one, its flags kept (a global or sticky flag is dropped: each line is matched
|
|
20
|
+
* on its own); a repository that configures none has no such row. A repository's own forms (`extra`) follow the shared ones.
|
|
21
|
+
*/
|
|
22
|
+
export declare function publicnessBans(workItemName?: RegExp, extra?: ReadonlyArray<readonly [string, RegExp]>): ReadonlyArray<readonly [string, RegExp]>;
|
|
23
|
+
/** A generator by name; a name the generators object only inherits (`constructor`) is no generator. */
|
|
24
|
+
export declare const generatorOf: (tree: Pick<WikiTree, "generators">, name: string) => Generator | undefined;
|
|
25
|
+
/** A region's generation, or why it cannot be had: a generator's answer that is not `{ text, refs }` is unreadable. */
|
|
26
|
+
export declare function generate(gen: Generator, args: readonly string[]): Generated;
|
|
27
|
+
/** The findings of one page, the digests the stamp writes, the coordinates of its refs, and its marker levels. */
|
|
28
|
+
export interface PageCheck {
|
|
29
|
+
readonly findings: Finding[];
|
|
30
|
+
readonly digests: Record<string, string>;
|
|
31
|
+
readonly coords: Record<string, string>;
|
|
32
|
+
readonly levels: Record<string, number>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Check one page. Findings carry the gate that owns them (`anchors` | `freshness`), a file line and a sentence.
|
|
36
|
+
* `stamp: true` is the stamp tool's reading: the stamped digests are not compared (they are about to be rewritten).
|
|
37
|
+
*/
|
|
38
|
+
export declare function checkPage(tree: WikiTree, rel: string, text: string, { stamp }?: {
|
|
39
|
+
stamp?: boolean;
|
|
40
|
+
}): PageCheck;
|
|
41
|
+
/**
|
|
42
|
+
* The page with every generated region rewritten from a fresh generation — the regions `claimBlocks` reads, so an
|
|
43
|
+
* example inside inline code or a code fence is never rewritten; a region whose generator fails is left as it is.
|
|
44
|
+
*/
|
|
45
|
+
export declare function regenerate(tree: WikiTree, text: string): string;
|
|
46
|
+
/**
|
|
47
|
+
* The stamp: regenerate every region, then rewrite `verified:` and every `anchor:` line from the tree. Refuses (returns
|
|
48
|
+
* the anchors findings, no text) while the page has any — a stamp vouches for a page that resolves, never for one that does not.
|
|
49
|
+
*/
|
|
50
|
+
export declare function stampPage(tree: WikiTree, rel: string, text: string, { commit }: {
|
|
51
|
+
commit: string;
|
|
52
|
+
}): {
|
|
53
|
+
text: string;
|
|
54
|
+
anchors: number;
|
|
55
|
+
} | {
|
|
56
|
+
refused: Finding[];
|
|
57
|
+
};
|