kibi-cli 0.12.4 → 0.12.5
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/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +12 -16
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +6 -0
- package/dist/public/symbol-granularity.d.ts +23 -0
- package/dist/public/symbol-granularity.d.ts.map +1 -0
- package/dist/public/symbol-granularity.js +68 -0
- package/dist/schemas/entity.schema.json +11 -0
- package/dist/traceability/symbol-extract.d.ts +3 -1
- package/dist/traceability/symbol-extract.d.ts.map +1 -1
- package/dist/traceability/symbol-extract.js +2 -0
- package/package.json +6 -2
- package/src/public/schemas/entity.ts +6 -0
- package/src/public/symbol-granularity.ts +125 -0
- package/src/schemas/entity.schema.json +11 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAiFA,OAAO,EAGL,KAAK,SAAS,EAEf,MAAM,2BAA2B,CAAC;AAEnC,YAAY,EAAE,SAAS,EAAE,CAAC;AAI1B,MAAM,WAAW,YAAY;IAC3B,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AA2bD,wBAAsB,YAAY,CAChC,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CA0V/B"}
|
package/dist/commands/check.js
CHANGED
|
@@ -22,6 +22,7 @@ import { extractFromManifest, extractFromManifestString, } from "../extractors/m
|
|
|
22
22
|
import { extractFromMarkdownString, } from "../extractors/markdown.js";
|
|
23
23
|
import { PrologProcess } from "../prolog.js";
|
|
24
24
|
import { escapeAtom, parseTriples, parseViolationRows, } from "../prolog/codec.js";
|
|
25
|
+
import { getBehavioralSymbolNames, getNonBehavioralSymbolNames, isAllowedGranularityReason, isTraceabilityRelationshipType, } from "../public/symbol-granularity.js";
|
|
25
26
|
import { KIBI_NO_IMPACT_DECLARATION, KIBI_SYMBOLS_MANIFEST_PATH, } from "../traceability/evidence-model.js";
|
|
26
27
|
import { getStagedFiles } from "../traceability/git-staged.js";
|
|
27
28
|
import { validateStagedMarkdown } from "../traceability/markdown-validate.js";
|
|
@@ -133,23 +134,11 @@ function buildManifestLookup(stagedFiles) {
|
|
|
133
134
|
stagedAuthoredSymbolResults,
|
|
134
135
|
};
|
|
135
136
|
}
|
|
136
|
-
const GRANULARITY_RELATIONSHIP_TYPES = new Set([
|
|
137
|
-
"implements",
|
|
138
|
-
"covered_by",
|
|
139
|
-
"executable_for",
|
|
140
|
-
]);
|
|
141
|
-
const ALLOWED_GRANULARITY_REASONS = new Set([
|
|
142
|
-
"config-artifact",
|
|
143
|
-
"module-level-behavior",
|
|
144
|
-
"extractor-miss",
|
|
145
|
-
"legacy-link",
|
|
146
|
-
]);
|
|
147
137
|
function hasTraceabilityRelationship(result) {
|
|
148
|
-
return result.relationships.some((relationship) =>
|
|
138
|
+
return result.relationships.some((relationship) => isTraceabilityRelationshipType(relationship.type));
|
|
149
139
|
}
|
|
150
140
|
function hasValidGranularityReason(result) {
|
|
151
|
-
|
|
152
|
-
return typeof reason === "string" && ALLOWED_GRANULARITY_REASONS.has(reason);
|
|
141
|
+
return isAllowedGranularityReason(result.entity.granularity_reason);
|
|
153
142
|
}
|
|
154
143
|
function createSymbolGranularityDiagnostics(options) {
|
|
155
144
|
const diagnostics = [];
|
|
@@ -168,13 +157,20 @@ function createSymbolGranularityDiagnostics(options) {
|
|
|
168
157
|
].sort();
|
|
169
158
|
if (granularNames.includes(result.entity.title))
|
|
170
159
|
continue;
|
|
160
|
+
const behavioralNames = getBehavioralSymbolNames(granularSymbols);
|
|
161
|
+
if (behavioralNames.length === 0)
|
|
162
|
+
continue;
|
|
163
|
+
const nonBehavioralNames = getNonBehavioralSymbolNames(granularSymbols);
|
|
164
|
+
const ignoredSymbolsSuggestion = nonBehavioralNames.length > 0
|
|
165
|
+
? ` Non-behavioral symbols ignored for this decision: ${nonBehavioralNames.join(", ")}.`
|
|
166
|
+
: "";
|
|
171
167
|
diagnostics.push({
|
|
172
168
|
id: "symbol_granularity_violation",
|
|
173
169
|
severity: "error",
|
|
174
170
|
files: [result.entity.source, result.sourceFile],
|
|
175
171
|
docs: ["docs/symbol-traceability-taxonomy.md"],
|
|
176
|
-
message: `Symbol ${result.entity.id} links ${result.sourceFile} coarsely while granular symbols are available: ${
|
|
177
|
-
suggestion:
|
|
172
|
+
message: `Symbol ${result.entity.id} links ${result.sourceFile} coarsely while granular symbols are available (behavioral only): ${behavioralNames.join(", ")}`,
|
|
173
|
+
suggestion: `Move ownership/coverage/test relationships to the narrow behavioral symbol, add a manifest behavioral anchor, or add granularity_reason with config-artifact, module-level-behavior, extractor-miss, or legacy-link when the coarse symbol is intentional.${ignoredSymbolsSuggestion}`,
|
|
178
174
|
});
|
|
179
175
|
}
|
|
180
176
|
return diagnostics;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"entity.d.ts","sourceRoot":"","sources":["../../../src/public/schemas/entity.ts"],"names":[],"mappings":"AAiFA,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CA+JzC,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
You should have received a copy of the GNU Affero General Public License
|
|
16
16
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
17
|
*/
|
|
18
|
+
// Typed fact field enums per proposal
|
|
19
|
+
import { SYMBOL_ROLES } from "../symbol-granularity.js";
|
|
18
20
|
const factConditionals = JSON.parse(`[
|
|
19
21
|
{
|
|
20
22
|
"if": {
|
|
@@ -113,6 +115,10 @@ const entitySchema = {
|
|
|
113
115
|
"legacy-link",
|
|
114
116
|
],
|
|
115
117
|
},
|
|
118
|
+
symbol_role: {
|
|
119
|
+
type: "string",
|
|
120
|
+
enum: [...SYMBOL_ROLES],
|
|
121
|
+
},
|
|
116
122
|
type: {
|
|
117
123
|
type: "string",
|
|
118
124
|
enum: [
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare const SYMBOL_ROLES: readonly ["behavioral", "structural", "type-shape", "config", "module", "unknown"];
|
|
2
|
+
export type SymbolRole = (typeof SYMBOL_ROLES)[number];
|
|
3
|
+
export declare const TRACEABILITY_RELATIONSHIP_TYPES: readonly ["implements", "covered_by", "executable_for"];
|
|
4
|
+
export type TraceabilityRelationshipType = (typeof TRACEABILITY_RELATIONSHIP_TYPES)[number];
|
|
5
|
+
export declare const ALLOWED_GRANULARITY_REASONS: readonly ["config-artifact", "module-level-behavior", "extractor-miss", "legacy-link"];
|
|
6
|
+
export type GranularityReason = (typeof ALLOWED_GRANULARITY_REASONS)[number];
|
|
7
|
+
export type SymbolKind = "function" | "class" | "method" | "interface" | "type" | "variable" | "enum" | "unknown";
|
|
8
|
+
export type SourceSymbolKind = SymbolKind;
|
|
9
|
+
export interface GranularSymbolCandidate {
|
|
10
|
+
name: string;
|
|
11
|
+
kind?: SymbolKind;
|
|
12
|
+
role?: SymbolRole;
|
|
13
|
+
}
|
|
14
|
+
export declare function inferSymbolRole(kind: SymbolKind): SymbolRole;
|
|
15
|
+
export declare const inferSymbolRoleFromKind: typeof inferSymbolRole;
|
|
16
|
+
export declare function isSymbolRole(value: unknown): value is SymbolRole;
|
|
17
|
+
export declare function isTraceabilityRelationshipType(value: unknown): value is TraceabilityRelationshipType;
|
|
18
|
+
export declare function isAllowedGranularityReason(value: unknown): value is GranularityReason;
|
|
19
|
+
export declare function getSymbolRole(candidate: GranularSymbolCandidate): SymbolRole;
|
|
20
|
+
export declare function isBehavioralSymbol(candidate: GranularSymbolCandidate): boolean;
|
|
21
|
+
export declare function getBehavioralSymbolNames(candidates: GranularSymbolCandidate[]): string[];
|
|
22
|
+
export declare function getNonBehavioralSymbolNames(candidates: GranularSymbolCandidate[]): string[];
|
|
23
|
+
//# sourceMappingURL=symbol-granularity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"symbol-granularity.d.ts","sourceRoot":"","sources":["../../src/public/symbol-granularity.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,oFAOf,CAAC;AAEX,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,eAAO,MAAM,+BAA+B,yDAIlC,CAAC;AAEX,MAAM,MAAM,4BAA4B,GACtC,CAAC,OAAO,+BAA+B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnD,eAAO,MAAM,2BAA2B,wFAK9B,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7E,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,OAAO,GACP,QAAQ,GACR,WAAW,GACX,MAAM,GACN,UAAU,GACV,MAAM,GACN,SAAS,CAAC;AAEd,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC;AAE1C,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AASD,wBAAgB,eAAe,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAc5D;AAED,eAAO,MAAM,uBAAuB,wBAAkB,CAAC;AAEvD,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAIhE;AAED,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,4BAA4B,CAIvC;AAED,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,iBAAiB,CAE5B;AAED,wBAAgB,aAAa,CAAC,SAAS,EAAE,uBAAuB,GAAG,UAAU,CAI5E;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,uBAAuB,GACjC,OAAO,CAET;AAED,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,uBAAuB,EAAE,GACpC,MAAM,EAAE,CAMV;AAED,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,uBAAuB,EAAE,GACpC,MAAM,EAAE,CAQV"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export const SYMBOL_ROLES = [
|
|
2
|
+
"behavioral",
|
|
3
|
+
"structural",
|
|
4
|
+
"type-shape",
|
|
5
|
+
"config",
|
|
6
|
+
"module",
|
|
7
|
+
"unknown",
|
|
8
|
+
];
|
|
9
|
+
export const TRACEABILITY_RELATIONSHIP_TYPES = [
|
|
10
|
+
"implements",
|
|
11
|
+
"covered_by",
|
|
12
|
+
"executable_for",
|
|
13
|
+
];
|
|
14
|
+
export const ALLOWED_GRANULARITY_REASONS = [
|
|
15
|
+
"config-artifact",
|
|
16
|
+
"module-level-behavior",
|
|
17
|
+
"extractor-miss",
|
|
18
|
+
"legacy-link",
|
|
19
|
+
];
|
|
20
|
+
const traceabilityRelationshipTypeSet = new Set(TRACEABILITY_RELATIONSHIP_TYPES);
|
|
21
|
+
const allowedGranularityReasonSet = new Set(ALLOWED_GRANULARITY_REASONS);
|
|
22
|
+
export function inferSymbolRole(kind) {
|
|
23
|
+
switch (kind) {
|
|
24
|
+
case "function":
|
|
25
|
+
case "class":
|
|
26
|
+
case "method":
|
|
27
|
+
return "behavioral";
|
|
28
|
+
case "interface":
|
|
29
|
+
case "type":
|
|
30
|
+
case "enum":
|
|
31
|
+
return "type-shape";
|
|
32
|
+
case "variable":
|
|
33
|
+
case "unknown":
|
|
34
|
+
return "unknown";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export const inferSymbolRoleFromKind = inferSymbolRole;
|
|
38
|
+
export function isSymbolRole(value) {
|
|
39
|
+
return (typeof value === "string" && SYMBOL_ROLES.some((role) => role === value));
|
|
40
|
+
}
|
|
41
|
+
export function isTraceabilityRelationshipType(value) {
|
|
42
|
+
return (typeof value === "string" && traceabilityRelationshipTypeSet.has(value));
|
|
43
|
+
}
|
|
44
|
+
export function isAllowedGranularityReason(value) {
|
|
45
|
+
return typeof value === "string" && allowedGranularityReasonSet.has(value);
|
|
46
|
+
}
|
|
47
|
+
export function getSymbolRole(candidate) {
|
|
48
|
+
if (candidate.role)
|
|
49
|
+
return candidate.role;
|
|
50
|
+
if (candidate.kind)
|
|
51
|
+
return inferSymbolRole(candidate.kind);
|
|
52
|
+
return "unknown";
|
|
53
|
+
}
|
|
54
|
+
export function isBehavioralSymbol(candidate) {
|
|
55
|
+
return getSymbolRole(candidate) === "behavioral";
|
|
56
|
+
}
|
|
57
|
+
export function getBehavioralSymbolNames(candidates) {
|
|
58
|
+
return [
|
|
59
|
+
...new Set(candidates.filter(isBehavioralSymbol).map((candidate) => candidate.name)),
|
|
60
|
+
].sort();
|
|
61
|
+
}
|
|
62
|
+
export function getNonBehavioralSymbolNames(candidates) {
|
|
63
|
+
return [
|
|
64
|
+
...new Set(candidates
|
|
65
|
+
.filter((candidate) => !isBehavioralSymbol(candidate))
|
|
66
|
+
.map((candidate) => candidate.name)),
|
|
67
|
+
].sort();
|
|
68
|
+
}
|
|
@@ -48,6 +48,17 @@
|
|
|
48
48
|
"legacy-link"
|
|
49
49
|
]
|
|
50
50
|
},
|
|
51
|
+
"symbol_role": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"enum": [
|
|
54
|
+
"behavioral",
|
|
55
|
+
"structural",
|
|
56
|
+
"type-shape",
|
|
57
|
+
"config",
|
|
58
|
+
"module",
|
|
59
|
+
"unknown"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
51
62
|
"verification_scope": {
|
|
52
63
|
"type": "string",
|
|
53
64
|
"enum": ["unit", "integration", "end_to_end"]
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SymbolKind, type SymbolRole } from "../public/symbol-granularity.js";
|
|
1
2
|
import type { HunkRange, StagedFile } from "./git-staged.js";
|
|
2
3
|
type TraceabilityRelationship = {
|
|
3
4
|
type: string;
|
|
@@ -6,7 +7,8 @@ type TraceabilityRelationship = {
|
|
|
6
7
|
export interface ExtractedSymbol {
|
|
7
8
|
id: string;
|
|
8
9
|
name: string;
|
|
9
|
-
kind:
|
|
10
|
+
kind: SymbolKind;
|
|
11
|
+
role: SymbolRole;
|
|
10
12
|
location: {
|
|
11
13
|
file: string;
|
|
12
14
|
startLine: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"symbol-extract.d.ts","sourceRoot":"","sources":["../../src/traceability/symbol-extract.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7D,KAAK,wBAAwB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAU7D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,
|
|
1
|
+
{"version":3,"file":"symbol-extract.d.ts","sourceRoot":"","sources":["../../src/traceability/symbol-extract.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,KAAK,UAAU,EACf,KAAK,UAAU,EAEhB,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7D,KAAK,wBAAwB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;AAU7D,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,UAAU,EAAE,SAAS,EAAE,CAAC;IACxB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAC5C;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,wBAAwB,EAAE,CAAC;CAC5C;AAED,MAAM,MAAM,cAAc,GAAG,GAAG,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;AAE9D,wBAAgB,+BAA+B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAG5E;AAmOD,wBAAgB,4BAA4B,CAE1C,UAAU,EAAE,UAAU,EACtB,cAAc,CAAC,EAAE,cAAc,GAC9B,eAAe,EAAE,CAyOnB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { Project, ScriptKind } from "ts-morph";
|
|
3
3
|
import { readManifestWithCoordinateOverlay } from "../extractors/manifest.js";
|
|
4
|
+
import { inferSymbolRole, } from "../public/symbol-granularity.js";
|
|
4
5
|
const TRACEABILITY_RELATIONSHIP_TYPES = new Set([
|
|
5
6
|
"implements",
|
|
6
7
|
"covered_by",
|
|
@@ -109,6 +110,7 @@ function buildSymbolResult(stagedFile, name, kind, span, inlineReqLinks, manifes
|
|
|
109
110
|
id,
|
|
110
111
|
name,
|
|
111
112
|
kind,
|
|
113
|
+
role: inferSymbolRole(kind),
|
|
112
114
|
location: {
|
|
113
115
|
file: stagedFile.path,
|
|
114
116
|
startLine: span.startLine,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kibi-cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Kibi CLI for knowledge base management",
|
|
6
6
|
"engines": {
|
|
@@ -69,6 +69,10 @@
|
|
|
69
69
|
"types": "./dist/public/check-types.d.ts",
|
|
70
70
|
"default": "./dist/public/check-types.js"
|
|
71
71
|
},
|
|
72
|
+
"./public/symbol-granularity": {
|
|
73
|
+
"types": "./dist/public/symbol-granularity.d.ts",
|
|
74
|
+
"default": "./dist/public/symbol-granularity.js"
|
|
75
|
+
},
|
|
72
76
|
"./schema-version": {
|
|
73
77
|
"types": "./dist/public/schema-version.d.ts",
|
|
74
78
|
"default": "./dist/public/schema-version.js"
|
|
@@ -95,7 +99,7 @@
|
|
|
95
99
|
"fast-glob": "^3.2.12",
|
|
96
100
|
"gray-matter": "^4.0.3",
|
|
97
101
|
"js-yaml": "^4.1.0",
|
|
98
|
-
"kibi-core": "^0.6.
|
|
102
|
+
"kibi-core": "^0.6.1",
|
|
99
103
|
"ts-morph": "^23.0.0",
|
|
100
104
|
"ignore": "^5.3.0"
|
|
101
105
|
},
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
// Typed fact field enums per proposal
|
|
20
|
+
import { SYMBOL_ROLES, type SymbolRole } from "../symbol-granularity.js";
|
|
21
|
+
|
|
20
22
|
type FactKind =
|
|
21
23
|
| "subject"
|
|
22
24
|
| "property_value"
|
|
@@ -127,6 +129,10 @@ const entitySchema: Record<string, unknown> = {
|
|
|
127
129
|
"legacy-link",
|
|
128
130
|
],
|
|
129
131
|
},
|
|
132
|
+
symbol_role: {
|
|
133
|
+
type: "string",
|
|
134
|
+
enum: [...SYMBOL_ROLES] satisfies SymbolRole[],
|
|
135
|
+
},
|
|
130
136
|
type: {
|
|
131
137
|
type: "string",
|
|
132
138
|
enum: [
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
export const SYMBOL_ROLES = [
|
|
2
|
+
"behavioral",
|
|
3
|
+
"structural",
|
|
4
|
+
"type-shape",
|
|
5
|
+
"config",
|
|
6
|
+
"module",
|
|
7
|
+
"unknown",
|
|
8
|
+
] as const;
|
|
9
|
+
|
|
10
|
+
export type SymbolRole = (typeof SYMBOL_ROLES)[number];
|
|
11
|
+
|
|
12
|
+
export const TRACEABILITY_RELATIONSHIP_TYPES = [
|
|
13
|
+
"implements",
|
|
14
|
+
"covered_by",
|
|
15
|
+
"executable_for",
|
|
16
|
+
] as const;
|
|
17
|
+
|
|
18
|
+
export type TraceabilityRelationshipType =
|
|
19
|
+
(typeof TRACEABILITY_RELATIONSHIP_TYPES)[number];
|
|
20
|
+
|
|
21
|
+
export const ALLOWED_GRANULARITY_REASONS = [
|
|
22
|
+
"config-artifact",
|
|
23
|
+
"module-level-behavior",
|
|
24
|
+
"extractor-miss",
|
|
25
|
+
"legacy-link",
|
|
26
|
+
] as const;
|
|
27
|
+
|
|
28
|
+
export type GranularityReason = (typeof ALLOWED_GRANULARITY_REASONS)[number];
|
|
29
|
+
|
|
30
|
+
export type SymbolKind =
|
|
31
|
+
| "function"
|
|
32
|
+
| "class"
|
|
33
|
+
| "method"
|
|
34
|
+
| "interface"
|
|
35
|
+
| "type"
|
|
36
|
+
| "variable"
|
|
37
|
+
| "enum"
|
|
38
|
+
| "unknown";
|
|
39
|
+
|
|
40
|
+
export type SourceSymbolKind = SymbolKind;
|
|
41
|
+
|
|
42
|
+
export interface GranularSymbolCandidate {
|
|
43
|
+
name: string;
|
|
44
|
+
kind?: SymbolKind;
|
|
45
|
+
role?: SymbolRole;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const traceabilityRelationshipTypeSet: ReadonlySet<string> = new Set(
|
|
49
|
+
TRACEABILITY_RELATIONSHIP_TYPES,
|
|
50
|
+
);
|
|
51
|
+
const allowedGranularityReasonSet: ReadonlySet<string> = new Set(
|
|
52
|
+
ALLOWED_GRANULARITY_REASONS,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
export function inferSymbolRole(kind: SymbolKind): SymbolRole {
|
|
56
|
+
switch (kind) {
|
|
57
|
+
case "function":
|
|
58
|
+
case "class":
|
|
59
|
+
case "method":
|
|
60
|
+
return "behavioral";
|
|
61
|
+
case "interface":
|
|
62
|
+
case "type":
|
|
63
|
+
case "enum":
|
|
64
|
+
return "type-shape";
|
|
65
|
+
case "variable":
|
|
66
|
+
case "unknown":
|
|
67
|
+
return "unknown";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const inferSymbolRoleFromKind = inferSymbolRole;
|
|
72
|
+
|
|
73
|
+
export function isSymbolRole(value: unknown): value is SymbolRole {
|
|
74
|
+
return (
|
|
75
|
+
typeof value === "string" && SYMBOL_ROLES.some((role) => role === value)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function isTraceabilityRelationshipType(
|
|
80
|
+
value: unknown,
|
|
81
|
+
): value is TraceabilityRelationshipType {
|
|
82
|
+
return (
|
|
83
|
+
typeof value === "string" && traceabilityRelationshipTypeSet.has(value)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function isAllowedGranularityReason(
|
|
88
|
+
value: unknown,
|
|
89
|
+
): value is GranularityReason {
|
|
90
|
+
return typeof value === "string" && allowedGranularityReasonSet.has(value);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getSymbolRole(candidate: GranularSymbolCandidate): SymbolRole {
|
|
94
|
+
if (candidate.role) return candidate.role;
|
|
95
|
+
if (candidate.kind) return inferSymbolRole(candidate.kind);
|
|
96
|
+
return "unknown";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function isBehavioralSymbol(
|
|
100
|
+
candidate: GranularSymbolCandidate,
|
|
101
|
+
): boolean {
|
|
102
|
+
return getSymbolRole(candidate) === "behavioral";
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function getBehavioralSymbolNames(
|
|
106
|
+
candidates: GranularSymbolCandidate[],
|
|
107
|
+
): string[] {
|
|
108
|
+
return [
|
|
109
|
+
...new Set(
|
|
110
|
+
candidates.filter(isBehavioralSymbol).map((candidate) => candidate.name),
|
|
111
|
+
),
|
|
112
|
+
].sort();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function getNonBehavioralSymbolNames(
|
|
116
|
+
candidates: GranularSymbolCandidate[],
|
|
117
|
+
): string[] {
|
|
118
|
+
return [
|
|
119
|
+
...new Set(
|
|
120
|
+
candidates
|
|
121
|
+
.filter((candidate) => !isBehavioralSymbol(candidate))
|
|
122
|
+
.map((candidate) => candidate.name),
|
|
123
|
+
),
|
|
124
|
+
].sort();
|
|
125
|
+
}
|
|
@@ -48,6 +48,17 @@
|
|
|
48
48
|
"legacy-link"
|
|
49
49
|
]
|
|
50
50
|
},
|
|
51
|
+
"symbol_role": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"enum": [
|
|
54
|
+
"behavioral",
|
|
55
|
+
"structural",
|
|
56
|
+
"type-shape",
|
|
57
|
+
"config",
|
|
58
|
+
"module",
|
|
59
|
+
"unknown"
|
|
60
|
+
]
|
|
61
|
+
},
|
|
51
62
|
"verification_scope": {
|
|
52
63
|
"type": "string",
|
|
53
64
|
"enum": ["unit", "integration", "end_to_end"]
|