@ttsc/evidence 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +279 -0
- package/lib/index.d.ts +65 -0
- package/lib/index.js +87 -0
- package/lib/internal/loadPrismaModels.d.ts +1 -0
- package/lib/internal/loadPrismaModels.js +197 -0
- package/lib/internal/loadSwaggerOperations.d.ts +1 -0
- package/lib/internal/loadSwaggerOperations.js +156 -0
- package/lib/internal/normalizeSwaggerDocument.d.ts +1 -0
- package/lib/internal/normalizeSwaggerDocument.js +7 -0
- package/lib/structures/ITtscEvidenceDocumentedConfig.d.ts +32 -0
- package/lib/structures/ITtscEvidenceDocumentedConfig.js +2 -0
- package/lib/structures/ITtscEvidenceGraphClaim.d.ts +14 -0
- package/lib/structures/ITtscEvidenceGraphClaim.js +2 -0
- package/lib/structures/ITtscEvidenceGraphClaimBase.d.ts +102 -0
- package/lib/structures/ITtscEvidenceGraphClaimBase.js +2 -0
- package/lib/structures/ITtscEvidenceGraphConfig.d.ts +19 -0
- package/lib/structures/ITtscEvidenceGraphConfig.js +2 -0
- package/lib/structures/ITtscEvidenceGraphMarkdownClaim.d.ts +40 -0
- package/lib/structures/ITtscEvidenceGraphMarkdownClaim.js +2 -0
- package/lib/structures/ITtscEvidenceGraphMarkdownReference.d.ts +76 -0
- package/lib/structures/ITtscEvidenceGraphMarkdownReference.js +2 -0
- package/lib/structures/ITtscEvidenceGraphPrismaClaim.d.ts +65 -0
- package/lib/structures/ITtscEvidenceGraphPrismaClaim.js +2 -0
- package/lib/structures/ITtscEvidenceGraphPrismaReference.d.ts +75 -0
- package/lib/structures/ITtscEvidenceGraphPrismaReference.js +2 -0
- package/lib/structures/ITtscEvidenceGraphReference.d.ts +14 -0
- package/lib/structures/ITtscEvidenceGraphReference.js +2 -0
- package/lib/structures/ITtscEvidenceGraphReferenceBase.d.ts +73 -0
- package/lib/structures/ITtscEvidenceGraphReferenceBase.js +2 -0
- package/lib/structures/ITtscEvidenceGraphSwaggerReference.d.ts +39 -0
- package/lib/structures/ITtscEvidenceGraphSwaggerReference.js +2 -0
- package/lib/structures/ITtscEvidenceGraphTypeScriptClaim.d.ts +54 -0
- package/lib/structures/ITtscEvidenceGraphTypeScriptClaim.js +2 -0
- package/lib/structures/ITtscEvidenceGraphTypeScriptReference.d.ts +83 -0
- package/lib/structures/ITtscEvidenceGraphTypeScriptReference.js +2 -0
- package/lib/structures/index.d.ts +13 -0
- package/lib/structures/index.js +29 -0
- package/lib/typings/ITtscLintContributorRules.d.ts +34 -0
- package/lib/typings/ITtscLintContributorRules.js +2 -0
- package/lib/typings/ITtscLintRuleOptionsMap.d.ts +20 -0
- package/lib/typings/ITtscLintRuleOptionsMap.js +2 -0
- package/lib/typings/TtscEvidenceGraphMarkdownSymbol.d.ts +32 -0
- package/lib/typings/TtscEvidenceGraphMarkdownSymbol.js +2 -0
- package/lib/typings/TtscEvidenceGraphPrismaSymbol.d.ts +38 -0
- package/lib/typings/TtscEvidenceGraphPrismaSymbol.js +2 -0
- package/lib/typings/TtscEvidenceGraphTypeScriptSymbol.d.ts +64 -0
- package/lib/typings/TtscEvidenceGraphTypeScriptSymbol.js +2 -0
- package/lib/typings/index.d.ts +5 -0
- package/lib/typings/index.js +21 -0
- package/native/base.go +298 -0
- package/native/config.go +798 -0
- package/native/declaration.go +240 -0
- package/native/documented.go +353 -0
- package/native/exports.go +484 -0
- package/native/glob.go +207 -0
- package/native/graph.go +1409 -0
- package/native/health.go +45 -0
- package/native/hints.go +261 -0
- package/native/imports.go +373 -0
- package/native/inputs.go +125 -0
- package/native/loader.go +424 -0
- package/native/markdown.go +423 -0
- package/native/model.go +296 -0
- package/native/prisma.go +719 -0
- package/native/prisma_cache.go +213 -0
- package/native/prisma_locator.go +417 -0
- package/native/singular.go +369 -0
- package/native/swagger.go +331 -0
- package/native/swagger_cache.go +274 -0
- package/native/todo.go +138 -0
- package/native/typescript.go +1199 -0
- package/native/typescript_cache.go +96 -0
- package/package.json +64 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.loadSwaggerOperations = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const yaml_1 = require("yaml");
|
|
11
|
+
const normalizeSwaggerDocument_1 = require("./normalizeSwaggerDocument");
|
|
12
|
+
const MAX_DOCUMENT_BYTES = 16 * 1024 * 1024;
|
|
13
|
+
const REMOTE_TIMEOUT_MILLISECONDS = 30_000;
|
|
14
|
+
const METHODS = [
|
|
15
|
+
"get",
|
|
16
|
+
"post",
|
|
17
|
+
"put",
|
|
18
|
+
"delete",
|
|
19
|
+
"options",
|
|
20
|
+
"head",
|
|
21
|
+
"patch",
|
|
22
|
+
"trace",
|
|
23
|
+
"query",
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Loads and normalizes every configured Swagger source for the native rule.
|
|
27
|
+
*
|
|
28
|
+
* The native contributor is Go, while the version converter is JavaScript. This
|
|
29
|
+
* function is the narrow process boundary between them: it accepts only source
|
|
30
|
+
* locations and returns only operation identities.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
const loadSwaggerOperations = async (request) => {
|
|
35
|
+
const loaded = await Promise.all(request.sources.map(async (source) => {
|
|
36
|
+
let digest = "";
|
|
37
|
+
try {
|
|
38
|
+
const read = await readSource(request.root, source);
|
|
39
|
+
digest = read.digest;
|
|
40
|
+
const input = (0, yaml_1.parse)(read.text);
|
|
41
|
+
const document = (0, normalizeSwaggerDocument_1.normalizeSwaggerDocument)(input);
|
|
42
|
+
return {
|
|
43
|
+
source,
|
|
44
|
+
operations: operationsOf(document),
|
|
45
|
+
digest,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
catch (error) {
|
|
49
|
+
return {
|
|
50
|
+
source,
|
|
51
|
+
message: errorMessage(error),
|
|
52
|
+
digest,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}));
|
|
56
|
+
return {
|
|
57
|
+
documents: loaded.filter(isInventory),
|
|
58
|
+
problems: loaded.filter(isProblem),
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
exports.loadSwaggerOperations = loadSwaggerOperations;
|
|
62
|
+
const readSource = async (root, source) => {
|
|
63
|
+
if (source.startsWith("http://") || source.startsWith("https://"))
|
|
64
|
+
return { text: await readRemoteSource(source), digest: "" };
|
|
65
|
+
if (source.includes("://"))
|
|
66
|
+
throw new Error("only http: and https: URLs are supported");
|
|
67
|
+
// A local document may sit anywhere on the filesystem, including above the
|
|
68
|
+
// project or on an absolute path. The native decoder is what validates the
|
|
69
|
+
// spelling; this side only has to resolve it the same way, which
|
|
70
|
+
// `path.resolve` already does for both forms.
|
|
71
|
+
const location = node_path_1.default.resolve(root, source);
|
|
72
|
+
const stat = await promises_1.default.stat(location);
|
|
73
|
+
if (!stat.isFile())
|
|
74
|
+
throw new Error("the local Swagger source is not a file");
|
|
75
|
+
if (stat.size > MAX_DOCUMENT_BYTES)
|
|
76
|
+
throw new Error(`the Swagger document exceeds the ${MAX_DOCUMENT_BYTES} byte limit`);
|
|
77
|
+
// Hashed before decoding, over the bytes as they were read. The native side
|
|
78
|
+
// hashes the file's bytes too, so the two agree by construction; hashing the
|
|
79
|
+
// decoded string instead would agree only for inputs where the round trip
|
|
80
|
+
// happens to be exact.
|
|
81
|
+
const content = await promises_1.default.readFile(location);
|
|
82
|
+
return {
|
|
83
|
+
text: decodeUtf8(content),
|
|
84
|
+
digest: (0, node_crypto_1.createHash)("sha256").update(content).digest("hex"),
|
|
85
|
+
};
|
|
86
|
+
};
|
|
87
|
+
const readRemoteSource = async (source) => {
|
|
88
|
+
const response = await fetch(source, {
|
|
89
|
+
signal: AbortSignal.timeout(REMOTE_TIMEOUT_MILLISECONDS),
|
|
90
|
+
});
|
|
91
|
+
if (!response.ok)
|
|
92
|
+
throw new Error(`HTTP ${response.status} ${response.statusText || "response"}`);
|
|
93
|
+
if (response.body === null)
|
|
94
|
+
return "";
|
|
95
|
+
const reader = response.body.getReader();
|
|
96
|
+
const chunks = [];
|
|
97
|
+
let length = 0;
|
|
98
|
+
while (true) {
|
|
99
|
+
const next = await reader.read();
|
|
100
|
+
if (next.done)
|
|
101
|
+
break;
|
|
102
|
+
length += next.value.byteLength;
|
|
103
|
+
if (length > MAX_DOCUMENT_BYTES) {
|
|
104
|
+
await reader.cancel();
|
|
105
|
+
throw new Error(`the Swagger document exceeds the ${MAX_DOCUMENT_BYTES} byte limit`);
|
|
106
|
+
}
|
|
107
|
+
chunks.push(next.value);
|
|
108
|
+
}
|
|
109
|
+
const content = new Uint8Array(length);
|
|
110
|
+
let offset = 0;
|
|
111
|
+
for (const chunk of chunks) {
|
|
112
|
+
content.set(chunk, offset);
|
|
113
|
+
offset += chunk.byteLength;
|
|
114
|
+
}
|
|
115
|
+
return decodeUtf8(content);
|
|
116
|
+
};
|
|
117
|
+
const decodeUtf8 = (content) => new TextDecoder("utf-8", { fatal: true }).decode(content);
|
|
118
|
+
const operationsOf = (document) => {
|
|
119
|
+
const operations = [];
|
|
120
|
+
for (const [operationPath, item] of Object.entries(document.paths ?? {})) {
|
|
121
|
+
for (const method of METHODS) {
|
|
122
|
+
const operation = item[method];
|
|
123
|
+
if (operation !== undefined)
|
|
124
|
+
operations.push(operationOf(method, operationPath));
|
|
125
|
+
}
|
|
126
|
+
for (const method of Object.keys(item.additionalOperations ?? {}))
|
|
127
|
+
operations.push(operationOf(method, operationPath));
|
|
128
|
+
}
|
|
129
|
+
operations.sort((left, right) => {
|
|
130
|
+
const leftTarget = `${left.method}:${left.path}`;
|
|
131
|
+
const rightTarget = `${right.method}:${right.path}`;
|
|
132
|
+
return leftTarget.localeCompare(rightTarget);
|
|
133
|
+
});
|
|
134
|
+
for (let index = 1; index < operations.length; index++) {
|
|
135
|
+
const previous = operations[index - 1];
|
|
136
|
+
const current = operations[index];
|
|
137
|
+
if (`${previous.method}:${previous.path}` ===
|
|
138
|
+
`${current.method}:${current.path}`)
|
|
139
|
+
throw new Error(`OpenAPI operation '${current.method} ${current.path}' is declared more than once`);
|
|
140
|
+
}
|
|
141
|
+
return operations;
|
|
142
|
+
};
|
|
143
|
+
const operationOf = (method, operationPath) => {
|
|
144
|
+
if (!operationPath.startsWith("/"))
|
|
145
|
+
throw new Error(`OpenAPI path '${operationPath}' must start with '/' to form an operation target`);
|
|
146
|
+
if (/^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/u.test(method) === false ||
|
|
147
|
+
method.includes(":"))
|
|
148
|
+
throw new Error(`OpenAPI method '${method}' cannot form a '<METHOD>:<path>' target`);
|
|
149
|
+
return {
|
|
150
|
+
method: method.toUpperCase(),
|
|
151
|
+
path: operationPath,
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
const isInventory = (value) => "operations" in value;
|
|
155
|
+
const isProblem = (value) => "message" in value;
|
|
156
|
+
const errorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeSwaggerDocument = void 0;
|
|
4
|
+
const utils_1 = require("@typia/utils");
|
|
5
|
+
/** @internal */
|
|
6
|
+
const normalizeSwaggerDocument = (input) => utils_1.OpenApiConverter.upgradeDocument(input);
|
|
7
|
+
exports.normalizeSwaggerDocument = normalizeSwaggerDocument;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { TtscEvidenceGraphTypeScriptSymbol } from "../typings/TtscEvidenceGraphTypeScriptSymbol";
|
|
2
|
+
/**
|
|
3
|
+
* Options of the `evidence/documented` rule.
|
|
4
|
+
*
|
|
5
|
+
* The rule requires a JSDoc block on every selected export, because a JSDoc
|
|
6
|
+
* block is the only place an `@evidence` tag is ever read from. A symbol
|
|
7
|
+
* without one cannot cite anything: the citation has no location to live in,
|
|
8
|
+
* and the graph's obligation silently shifts onto whichever sibling does have a
|
|
9
|
+
* block.
|
|
10
|
+
*
|
|
11
|
+
* Presence is the whole check. The rule never judges what the prose says, how
|
|
12
|
+
* long it is, or whether it is sincere — a rule that tried would only teach
|
|
13
|
+
* authors to write filler that satisfies it.
|
|
14
|
+
*/
|
|
15
|
+
export interface ITtscEvidenceDocumentedConfig {
|
|
16
|
+
/**
|
|
17
|
+
* Symbol kind or kinds that must carry a JSDoc block.
|
|
18
|
+
*
|
|
19
|
+
* Omit this property to select every kind a claim can use as a declaration
|
|
20
|
+
* host. That default is deliberate: the population which must be able to hold
|
|
21
|
+
* a tag is exactly the population a claim can select as a host, so a narrower
|
|
22
|
+
* default would leave some potential host unable to cite while the rule
|
|
23
|
+
* reported success.
|
|
24
|
+
*
|
|
25
|
+
* A single value selects one kind; a non-empty array selects the union. The
|
|
26
|
+
* exact declaration forms behind each kind are documented by
|
|
27
|
+
* {@link TtscEvidenceGraphTypeScriptSymbol}.
|
|
28
|
+
*
|
|
29
|
+
* @default ["type", "function", "property"]
|
|
30
|
+
*/
|
|
31
|
+
symbol?: TtscEvidenceGraphTypeScriptSymbol | TtscEvidenceGraphTypeScriptSymbol[];
|
|
32
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ITtscEvidenceGraphMarkdownClaim } from "./ITtscEvidenceGraphMarkdownClaim";
|
|
2
|
+
import type { ITtscEvidenceGraphPrismaClaim } from "./ITtscEvidenceGraphPrismaClaim";
|
|
3
|
+
import type { ITtscEvidenceGraphTypeScriptClaim } from "./ITtscEvidenceGraphTypeScriptClaim";
|
|
4
|
+
/**
|
|
5
|
+
* One population of artifacts asserting that it implements, verifies, or
|
|
6
|
+
* documents its referenced evidence.
|
|
7
|
+
*
|
|
8
|
+
* A claim owns the outgoing side of every evidence edge it declares: its files
|
|
9
|
+
* host the `@evidence` citations, and each referenced evidence population must
|
|
10
|
+
* be acknowledged completely. Separate claims remain separate obligations,
|
|
11
|
+
* preventing two teams' partial use of the same evidence from being reported as
|
|
12
|
+
* one complete use.
|
|
13
|
+
*/
|
|
14
|
+
export type ITtscEvidenceGraphClaim = ITtscEvidenceGraphMarkdownClaim | ITtscEvidenceGraphPrismaClaim | ITtscEvidenceGraphTypeScriptClaim;
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import type { ITtscEvidenceGraphReference } from "./ITtscEvidenceGraphReference";
|
|
2
|
+
/**
|
|
3
|
+
* What every claim declares: which artifact kind makes the claim, where its
|
|
4
|
+
* population lives, and which evidence it must cite completely.
|
|
5
|
+
*
|
|
6
|
+
* A claim owns the outgoing side of every evidence edge it declares. The
|
|
7
|
+
* properties here are the ones that mean the same thing in Markdown, Prisma,
|
|
8
|
+
* and TypeScript; only the symbol selector differs, because its eligible host
|
|
9
|
+
* kinds are a property of the language rather than of the claim.
|
|
10
|
+
*
|
|
11
|
+
* Swagger is deliberately absent. An API operation grounds a claim but cannot
|
|
12
|
+
* host `@evidence`, so it extends {@link ITtscEvidenceGraphReferenceBase}
|
|
13
|
+
* instead and never this one.
|
|
14
|
+
*/
|
|
15
|
+
export interface ITtscEvidenceGraphClaimBase<Type extends string> {
|
|
16
|
+
/** Identifies the artifact kind making this claim. */
|
|
17
|
+
type: Type;
|
|
18
|
+
/**
|
|
19
|
+
* Optional human-readable label shown with diagnostics for this claim. It
|
|
20
|
+
* does not identify evidence nodes or establish relationships between
|
|
21
|
+
* configuration entries.
|
|
22
|
+
*/
|
|
23
|
+
name?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Excludes this claim from graph loading and evaluation.
|
|
26
|
+
*
|
|
27
|
+
* The configuration shape is still validated, but this claim contributes no
|
|
28
|
+
* populations, references, coverage obligations, completion hints, or watched
|
|
29
|
+
* inputs. Omit this property or set it to `false` to enable the claim.
|
|
30
|
+
*
|
|
31
|
+
* @default false
|
|
32
|
+
*/
|
|
33
|
+
disabled?: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Directory this claim's {@link files} patterns resolve against.
|
|
36
|
+
*
|
|
37
|
+
* Omit this property to resolve against the active `ttsc` project root, which
|
|
38
|
+
* is where every population resolved before this property existed.
|
|
39
|
+
*
|
|
40
|
+
* The value names one directory, never a glob. It may sit inside the project,
|
|
41
|
+
* above it (`../../docs`), or on an absolute path. A drive-relative Windows
|
|
42
|
+
* path such as `C:docs` is refused, because it resolves against whatever
|
|
43
|
+
* directory that drive currently sits on rather than against a stable base.
|
|
44
|
+
*
|
|
45
|
+
* Diagnostics name the resolved base, and the resolved patterns are published
|
|
46
|
+
* to the `ttsc` host as watched inputs.
|
|
47
|
+
*/
|
|
48
|
+
root?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Glob patterns for the files that must cite the referenced evidence,
|
|
51
|
+
* resolved against {@link root} or against the project root when none is
|
|
52
|
+
* declared.
|
|
53
|
+
*
|
|
54
|
+
* These are globs, not regular expressions. `*` matches within one path
|
|
55
|
+
* segment, `**` crosses any number of path segments, and `?` matches one
|
|
56
|
+
* character. Both `/` and `\` are accepted as separators, while path identity
|
|
57
|
+
* remains case-sensitive on every operating system.
|
|
58
|
+
*
|
|
59
|
+
* Patterns are evaluated from left to right. A pattern prefixed with `!`
|
|
60
|
+
* removes its matches; a later positive pattern can include them again. The
|
|
61
|
+
* array must contain at least one positive pattern.
|
|
62
|
+
*
|
|
63
|
+
* A bare directory such as `src` or `src/` does not include its children;
|
|
64
|
+
* write `src/**` when the whole subtree belongs to this claim.
|
|
65
|
+
*/
|
|
66
|
+
files: string[];
|
|
67
|
+
/**
|
|
68
|
+
* Glob patterns for the files that may host this claim's `@evidenceExclude`
|
|
69
|
+
* declarations.
|
|
70
|
+
*
|
|
71
|
+
* Omit this property to accept an exclusion wherever it is otherwise
|
|
72
|
+
* eligible, which is how every claim behaved before this property existed.
|
|
73
|
+
*
|
|
74
|
+
* Declare it to gather them. An exclusion is the one acknowledgement that
|
|
75
|
+
* reports an obligation discharged without anything being built, so reading
|
|
76
|
+
* every exclusion a claim owns is a review that has to happen; scattered
|
|
77
|
+
* through the population it means reading the population, and named here it
|
|
78
|
+
* means opening these files. An exclusion selected from any other file is
|
|
79
|
+
* reported where it sits, naming these patterns, and discharges nothing, so
|
|
80
|
+
* its target still owes positive `@evidence`.
|
|
81
|
+
*
|
|
82
|
+
* The patterns narrow and never widen. They use the grammar and the root
|
|
83
|
+
* {@link files} uses, and a carrier must already be selected by {@link files}
|
|
84
|
+
* to host anything.
|
|
85
|
+
*
|
|
86
|
+
* This is independent of `noEvidenceExclude`, which decides whether one
|
|
87
|
+
* reference accepts an exclusion at all. A claim whose every reference
|
|
88
|
+
* refuses them gains nothing here.
|
|
89
|
+
*/
|
|
90
|
+
evidenceExcludeCarriers?: string[];
|
|
91
|
+
/**
|
|
92
|
+
* One evidence population or independently complete evidence populations that
|
|
93
|
+
* this claim must cite.
|
|
94
|
+
*
|
|
95
|
+
* A single reference requires this claim's files to acknowledge every
|
|
96
|
+
* evidence unit it materializes. An array creates a separate 100% obligation
|
|
97
|
+
* for every element: acknowledgements toward one reference never count toward
|
|
98
|
+
* another, and partially covered references cannot be pooled. The array must
|
|
99
|
+
* not be empty.
|
|
100
|
+
*/
|
|
101
|
+
reference: ITtscEvidenceGraphReference | ITtscEvidenceGraphReference[];
|
|
102
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ITtscEvidenceGraphClaim } from "./ITtscEvidenceGraphClaim";
|
|
2
|
+
/**
|
|
3
|
+
* The root declaration of a project's evidence graph.
|
|
4
|
+
*
|
|
5
|
+
* An evidence graph makes grounds for code and documentation explicit: one side
|
|
6
|
+
* claims to implement, verify, or document something, and the other side is the
|
|
7
|
+
* evidence it must cite with a reason. The configuration defines those
|
|
8
|
+
* boundaries without hardcoding a repository's folder layout or its notion of
|
|
9
|
+
* proof.
|
|
10
|
+
*/
|
|
11
|
+
export interface ITtscEvidenceGraphConfig {
|
|
12
|
+
/**
|
|
13
|
+
* Claim populations whose files must cite their referenced evidence. Each
|
|
14
|
+
* claim owns its reference obligations; coverage is never pooled across
|
|
15
|
+
* claims. Provide at least one claim; an empty array is invalid because it
|
|
16
|
+
* would enable the rule without establishing any evidence obligation.
|
|
17
|
+
*/
|
|
18
|
+
claims: ITtscEvidenceGraphClaim[];
|
|
19
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { TtscEvidenceGraphMarkdownSymbol } from "../typings/TtscEvidenceGraphMarkdownSymbol";
|
|
2
|
+
import type { ITtscEvidenceGraphClaimBase } from "./ITtscEvidenceGraphClaimBase";
|
|
3
|
+
/**
|
|
4
|
+
* A population of Markdown documents claiming its referenced evidence.
|
|
5
|
+
*
|
|
6
|
+
* Markdown uses HTML comments as invisible but reviewable declaration hosts.
|
|
7
|
+
* Both `@evidence <target> <reason>` and `@evidenceExclude <target> <reason>`
|
|
8
|
+
* require a target and a non-empty explanation.
|
|
9
|
+
*
|
|
10
|
+
* An exclusion still has to appear in a selected claim file and on a selected
|
|
11
|
+
* host kind. Its particular host is not part of the acknowledgement identity,
|
|
12
|
+
* so moving it between eligible sections cannot change the target scope this
|
|
13
|
+
* claim excludes. The target scope, not the declaration's host position,
|
|
14
|
+
* determines which selected descendants are acknowledged.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* <!-- @evidence docs/orders.md#create-order This section adopts the creation contract. -->
|
|
18
|
+
*/
|
|
19
|
+
export interface ITtscEvidenceGraphMarkdownClaim extends ITtscEvidenceGraphClaimBase<"markdown"> {
|
|
20
|
+
/**
|
|
21
|
+
* Glob patterns for the Markdown files that must cite the referenced
|
|
22
|
+
* evidence. Every matching regular file is parsed as Markdown regardless of
|
|
23
|
+
* extension, so exclude non-Markdown assets rather than relying on a suffix.
|
|
24
|
+
*/
|
|
25
|
+
files: string[];
|
|
26
|
+
/**
|
|
27
|
+
* Markdown node kind or kinds eligible to host this claim's declarations.
|
|
28
|
+
*
|
|
29
|
+
* Omit this property to select documents and H1 through H4 sections. A single
|
|
30
|
+
* value selects one kind; a non-empty array selects the union of its kinds.
|
|
31
|
+
*
|
|
32
|
+
* A `"file"` declaration appears before the document's first ATX heading. A
|
|
33
|
+
* heading declaration belongs to the nearest preceding ATX heading, whose
|
|
34
|
+
* exact level must be selected. This makes an H3 declaration distinct from
|
|
35
|
+
* its enclosing H2 section.
|
|
36
|
+
*
|
|
37
|
+
* @default ["file", "h1", "h2", "h3", "h4"]
|
|
38
|
+
*/
|
|
39
|
+
symbol?: TtscEvidenceGraphMarkdownSymbol | TtscEvidenceGraphMarkdownSymbol[];
|
|
40
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { TtscEvidenceGraphMarkdownSymbol } from "../typings/TtscEvidenceGraphMarkdownSymbol";
|
|
2
|
+
import type { ITtscEvidenceGraphReferenceBase } from "./ITtscEvidenceGraphReferenceBase";
|
|
3
|
+
/**
|
|
4
|
+
* A population of documentary evidence that the owning claim must cite.
|
|
5
|
+
*
|
|
6
|
+
* A document is useful as evidence only when a reviewer can identify the scope
|
|
7
|
+
* that supports a claim. This reference makes the obligation levels explicit
|
|
8
|
+
* while allowing one file or heading target to acknowledge its selected
|
|
9
|
+
* descendants. Citations remain anchored in the outline, so an editorial change
|
|
10
|
+
* cannot silently preserve a claim whose grounds disappeared.
|
|
11
|
+
*/
|
|
12
|
+
export interface ITtscEvidenceGraphMarkdownReference extends ITtscEvidenceGraphReferenceBase<"markdown"> {
|
|
13
|
+
/**
|
|
14
|
+
* Directory this population's {@link files} patterns resolve against, and the
|
|
15
|
+
* base its evidence targets are addressed from.
|
|
16
|
+
*
|
|
17
|
+
* Omit this property to resolve against the active `ttsc` project root, which
|
|
18
|
+
* is where every population resolved before this property existed.
|
|
19
|
+
*
|
|
20
|
+
* The value names one directory, never a glob. It may sit inside the project
|
|
21
|
+
* (`docs`), above it (`../../docs`), or on an absolute path
|
|
22
|
+
* (`/srv/contracts`, `C:/contracts`). A drive-relative Windows path such as
|
|
23
|
+
* `C:docs` is refused, because it resolves against whatever directory that
|
|
24
|
+
* drive currently sits on rather than against a stable base.
|
|
25
|
+
*
|
|
26
|
+
* Moving the root moves the addresses with it. With `root: "../../docs"` and
|
|
27
|
+
* `files: ["requirements/**"]`, a section is cited as
|
|
28
|
+
* `requirements/pricing.md#discounts` rather than through this project's
|
|
29
|
+
* distance from the documents — which is what lets two packages sharing one
|
|
30
|
+
* requirements set write the same citation, and why a shared population
|
|
31
|
+
* declares its root once instead of spelling `..` inside every pattern.
|
|
32
|
+
*
|
|
33
|
+
* Diagnostics name the resolved base, and the resolved patterns are published
|
|
34
|
+
* to the `ttsc` host as watched inputs, so editing a document above the
|
|
35
|
+
* project still invalidates the graph.
|
|
36
|
+
*/
|
|
37
|
+
root?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Glob patterns for Markdown documents in this evidence population, resolved
|
|
40
|
+
* against {@link root} or against the project root when none is declared.
|
|
41
|
+
* Every matching regular file is parsed as Markdown regardless of extension,
|
|
42
|
+
* so exclude images and other non-Markdown assets from the patterns.
|
|
43
|
+
*
|
|
44
|
+
* These are globs, not regular expressions. `*` matches within one path
|
|
45
|
+
* segment, `**` crosses any number of path segments, and `?` matches one
|
|
46
|
+
* character. Both `/` and `\` are accepted as separators, while path identity
|
|
47
|
+
* remains case-sensitive on every operating system.
|
|
48
|
+
*
|
|
49
|
+
* Patterns are evaluated from left to right. A pattern prefixed with `!`
|
|
50
|
+
* removes its matches; a later positive pattern can include them again. The
|
|
51
|
+
* array must contain at least one positive pattern.
|
|
52
|
+
*
|
|
53
|
+
* For example, `docs/*.md` selects Markdown files directly under `docs`,
|
|
54
|
+
* while `specs/v?.md` selects names such as `v1.md` but not `v10.md`.
|
|
55
|
+
*
|
|
56
|
+
* A bare directory such as `docs` or `docs/` does not include its children;
|
|
57
|
+
* write `docs/**` when the whole subtree belongs to this reference.
|
|
58
|
+
*/
|
|
59
|
+
files: string[];
|
|
60
|
+
/**
|
|
61
|
+
* Markdown node kind or kinds eligible to become evidence units.
|
|
62
|
+
*
|
|
63
|
+
* Omit this property to select documents and H1 through H4 sections. A single
|
|
64
|
+
* value selects one obligation kind; a non-empty array selects the union.
|
|
65
|
+
* Selected units remain independent obligations until an ancestor target
|
|
66
|
+
* acknowledges their shared scope. Ancestors of selected units are
|
|
67
|
+
* addressable even when their own kind is omitted from this selector.
|
|
68
|
+
*
|
|
69
|
+
* File units use the path inside {@link root} as their target. Heading units
|
|
70
|
+
* use `<path>#<anchor>` as documented by
|
|
71
|
+
* {@link TtscEvidenceGraphMarkdownSymbol}.
|
|
72
|
+
*
|
|
73
|
+
* @default ["file", "h1", "h2", "h3", "h4"]
|
|
74
|
+
*/
|
|
75
|
+
symbol?: TtscEvidenceGraphMarkdownSymbol | TtscEvidenceGraphMarkdownSymbol[];
|
|
76
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import type { TtscEvidenceGraphPrismaSymbol } from "../typings/TtscEvidenceGraphPrismaSymbol";
|
|
2
|
+
import type { ITtscEvidenceGraphClaimBase } from "./ITtscEvidenceGraphClaimBase";
|
|
3
|
+
/**
|
|
4
|
+
* A Prisma schema claiming its referenced evidence.
|
|
5
|
+
*
|
|
6
|
+
* A schema is authored, not generated, so it can carry its own citations. This
|
|
7
|
+
* is what turns "this table exists" into "this table exists because of that
|
|
8
|
+
* requirement", and it is the direction a data model most needs: a column
|
|
9
|
+
* nobody asked for is invisible until someone reads the whole schema against
|
|
10
|
+
* the whole specification.
|
|
11
|
+
*
|
|
12
|
+
* Ownership declarations live in `///` documentation comments immediately above
|
|
13
|
+
* their model or field. Both `@evidence <target> <reason>` and
|
|
14
|
+
* `@evidenceExclude <target> <reason>` require a target and a non-empty
|
|
15
|
+
* explanation.
|
|
16
|
+
*
|
|
17
|
+
* A triple-slash comment and a block comment both host a citation, because
|
|
18
|
+
* Prisma documents a declaration with either and both reach the generated
|
|
19
|
+
* client types. A double-slash line comment is discarded by Prisma itself and
|
|
20
|
+
* hosts nothing — a citation written in one is reported rather than ignored,
|
|
21
|
+
* because a tag that silently does nothing is the exact failure this rule
|
|
22
|
+
* exists to remove.
|
|
23
|
+
*
|
|
24
|
+
* A comment documents the declaration that immediately follows it, which is
|
|
25
|
+
* Prisma's own rule. A blank line before a top-level block detaches the comment
|
|
26
|
+
* entirely, and a comment above a block attribute or a closing brace documents
|
|
27
|
+
* nothing; a citation in any of those positions is reported.
|
|
28
|
+
*
|
|
29
|
+
* A matching claim file has one exclusion-only exception: an unattached
|
|
30
|
+
* top-level `/// @evidenceExclude` run is a file-level carrier. This supports a
|
|
31
|
+
* lint-only `.schema` ledger outside Prisma generation. `@evidence` in the same
|
|
32
|
+
* position remains invalid.
|
|
33
|
+
*
|
|
34
|
+
* ```prisma
|
|
35
|
+
* /// @evidence docs/requirements.md#pricing Sale price derives from this section.
|
|
36
|
+
* model Sale {
|
|
37
|
+
* /// @evidence docs/requirements.md#coupons The stacking limit is stored here.
|
|
38
|
+
* coupon_limit Int
|
|
39
|
+
* }
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export interface ITtscEvidenceGraphPrismaClaim extends ITtscEvidenceGraphClaimBase<"prisma"> {
|
|
43
|
+
/**
|
|
44
|
+
* Glob patterns for the Prisma schema files that must cite the referenced
|
|
45
|
+
* evidence. Every matching regular file is parsed as part of one schema
|
|
46
|
+
* regardless of extension, which is what lets a lint-only `.schema` ledger
|
|
47
|
+
* join the population Prisma generation never reads.
|
|
48
|
+
*/
|
|
49
|
+
files: string[];
|
|
50
|
+
/**
|
|
51
|
+
* Prisma node kind or kinds eligible to host this claim's ownership evidence.
|
|
52
|
+
*
|
|
53
|
+
* Omit this property to select models, columns, and relations. A single value
|
|
54
|
+
* selects one kind; a non-empty array selects the union of its kinds.
|
|
55
|
+
*
|
|
56
|
+
* The default is the widest one, because on the claiming side a selector
|
|
57
|
+
* narrows where ownership evidence may sit rather than what must be covered.
|
|
58
|
+
* Narrow it to `"model"` when only tables owe an answer and a column-level
|
|
59
|
+
* citation should be reported as out of scope. A file-level exclusion carrier
|
|
60
|
+
* is eligible independently of this selector.
|
|
61
|
+
*
|
|
62
|
+
* @default ["model", "column", "relation"]
|
|
63
|
+
*/
|
|
64
|
+
symbol?: TtscEvidenceGraphPrismaSymbol | TtscEvidenceGraphPrismaSymbol[];
|
|
65
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import type { TtscEvidenceGraphPrismaSymbol } from "../typings/TtscEvidenceGraphPrismaSymbol";
|
|
2
|
+
import type { ITtscEvidenceGraphReferenceBase } from "./ITtscEvidenceGraphReferenceBase";
|
|
3
|
+
/**
|
|
4
|
+
* A population of Prisma schema declarations that the owning claim must cite.
|
|
5
|
+
*
|
|
6
|
+
* A data model is a set of decisions about what the product stores, and this
|
|
7
|
+
* reference makes each of them something a claim has to answer for. A provider
|
|
8
|
+
* cites the model it persists, a DTO cites the column it exposes, and a table
|
|
9
|
+
* nothing cites becomes a build failure rather than a discovery made later.
|
|
10
|
+
*
|
|
11
|
+
* Every matched file is parsed together as one schema, because a Prisma schema
|
|
12
|
+
* folder is a single namespace whose files reference each other. The parse is
|
|
13
|
+
* Prisma's own, so a schema it rejects is reported as a parse failure rather
|
|
14
|
+
* than as an empty population.
|
|
15
|
+
*/
|
|
16
|
+
export interface ITtscEvidenceGraphPrismaReference extends ITtscEvidenceGraphReferenceBase<"prisma"> {
|
|
17
|
+
/**
|
|
18
|
+
* Directory this population's {@link files} patterns resolve against.
|
|
19
|
+
*
|
|
20
|
+
* Omit this property to resolve against the active `ttsc` project root, which
|
|
21
|
+
* is where every population resolved before this property existed.
|
|
22
|
+
*
|
|
23
|
+
* The value names one directory, never a glob. It may sit inside the project
|
|
24
|
+
* (`prisma`), above it (`../../prisma`), or on an absolute path
|
|
25
|
+
* (`/srv/schema`, `C:/schema`). A drive-relative Windows path such as
|
|
26
|
+
* `C:prisma` is refused, because it resolves against whatever directory that
|
|
27
|
+
* drive currently sits on rather than against a stable base.
|
|
28
|
+
*
|
|
29
|
+
* A Prisma target carries no path, so a declared root changes which files
|
|
30
|
+
* belong to the schema set and where a diagnostic points, never how a model
|
|
31
|
+
* is cited. Diagnostics name the resolved base, and the resolved patterns are
|
|
32
|
+
* published to the `ttsc` host as watched inputs.
|
|
33
|
+
*/
|
|
34
|
+
root?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Glob patterns for the Prisma schema files in this evidence population,
|
|
37
|
+
* resolved against {@link root} or against the project root when none is
|
|
38
|
+
* declared. Every matching regular file is parsed as part of one schema
|
|
39
|
+
* regardless of extension.
|
|
40
|
+
*
|
|
41
|
+
* These are globs, not regular expressions. `*` matches within one path
|
|
42
|
+
* segment, `**` crosses any number of path segments, and `?` matches one
|
|
43
|
+
* character. Both `/` and `\` are accepted as separators, while path identity
|
|
44
|
+
* remains case-sensitive on every operating system.
|
|
45
|
+
*
|
|
46
|
+
* Patterns are evaluated from left to right. A pattern prefixed with `!`
|
|
47
|
+
* removes its matches; a later positive pattern can include them again. The
|
|
48
|
+
* array must contain at least one positive pattern.
|
|
49
|
+
*
|
|
50
|
+
* A bare directory such as `prisma` or `prisma/` does not include its
|
|
51
|
+
* children; write `prisma/schema/**` when the whole folder belongs to this
|
|
52
|
+
* reference.
|
|
53
|
+
*/
|
|
54
|
+
files: string[];
|
|
55
|
+
/**
|
|
56
|
+
* Prisma node kind or kinds eligible to become evidence units.
|
|
57
|
+
*
|
|
58
|
+
* Omit this property to select models alone. A single value selects one
|
|
59
|
+
* obligation kind; a non-empty array selects the union.
|
|
60
|
+
*
|
|
61
|
+
* The default is deliberately the coarsest one. Selecting every column puts
|
|
62
|
+
* `id`, `created_at`, and every relation back-reference into the denominator,
|
|
63
|
+
* which is a large obligation to discharge honestly and an easy one to
|
|
64
|
+
* discharge with filler. Select `"column"` or `"relation"` when a claim
|
|
65
|
+
* really does owe an answer per member, and use `@evidenceExclude` for the
|
|
66
|
+
* members it deliberately does not use.
|
|
67
|
+
*
|
|
68
|
+
* A model remains addressable as an aggregate scope even when only its
|
|
69
|
+
* members are selected, so one citation on the model can discharge all of
|
|
70
|
+
* them.
|
|
71
|
+
*
|
|
72
|
+
* @default ["model"]
|
|
73
|
+
*/
|
|
74
|
+
symbol?: TtscEvidenceGraphPrismaSymbol | TtscEvidenceGraphPrismaSymbol[];
|
|
75
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ITtscEvidenceGraphMarkdownReference } from "./ITtscEvidenceGraphMarkdownReference";
|
|
2
|
+
import type { ITtscEvidenceGraphPrismaReference } from "./ITtscEvidenceGraphPrismaReference";
|
|
3
|
+
import type { ITtscEvidenceGraphSwaggerReference } from "./ITtscEvidenceGraphSwaggerReference";
|
|
4
|
+
import type { ITtscEvidenceGraphTypeScriptReference } from "./ITtscEvidenceGraphTypeScriptReference";
|
|
5
|
+
/**
|
|
6
|
+
* One population of evidence units that a claim must cite completely.
|
|
7
|
+
*
|
|
8
|
+
* A reference selects what counts as evidence: Markdown documents and heading
|
|
9
|
+
* sections, Swagger or OpenAPI operations, or selected exported TypeScript
|
|
10
|
+
* symbols. Every unit it materializes must be acknowledged by the owning claim,
|
|
11
|
+
* so a reference is the denominator of one coverage obligation, never a pooled
|
|
12
|
+
* global set.
|
|
13
|
+
*/
|
|
14
|
+
export type ITtscEvidenceGraphReference = ITtscEvidenceGraphMarkdownReference | ITtscEvidenceGraphPrismaReference | ITtscEvidenceGraphSwaggerReference | ITtscEvidenceGraphTypeScriptReference;
|