@vyuhlabs/dxkit 1.6.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -0
- package/README.md +3 -3
- package/dist/agents/extract.d.ts +25 -0
- package/dist/agents/extract.d.ts.map +1 -0
- package/dist/agents/extract.js +186 -0
- package/dist/agents/extract.js.map +1 -0
- package/dist/agents/schemas.d.ts +106 -0
- package/dist/agents/schemas.d.ts.map +1 -0
- package/dist/agents/schemas.js +86 -0
- package/dist/agents/schemas.js.map +1 -0
- package/dist/agents/session.d.ts +28 -0
- package/dist/agents/session.d.ts.map +1 -0
- package/dist/agents/session.js +223 -0
- package/dist/agents/session.js.map +1 -0
- package/dist/analyzers/developer/detailed.js +1 -1
- package/dist/analyzers/developer/detailed.js.map +1 -1
- package/dist/analyzers/dispatcher.d.ts +36 -0
- package/dist/analyzers/dispatcher.d.ts.map +1 -0
- package/dist/analyzers/dispatcher.js +62 -0
- package/dist/analyzers/dispatcher.js.map +1 -0
- package/dist/analyzers/docs/shallow.d.ts +3 -2
- package/dist/analyzers/docs/shallow.d.ts.map +1 -1
- package/dist/analyzers/docs/shallow.js +2 -2
- package/dist/analyzers/docs/shallow.js.map +1 -1
- package/dist/analyzers/dx/shallow.d.ts +3 -2
- package/dist/analyzers/dx/shallow.d.ts.map +1 -1
- package/dist/analyzers/dx/shallow.js +2 -2
- package/dist/analyzers/dx/shallow.js.map +1 -1
- package/dist/analyzers/health/actions.d.ts +3 -3
- package/dist/analyzers/health/actions.d.ts.map +1 -1
- package/dist/analyzers/health/actions.js +99 -52
- package/dist/analyzers/health/actions.js.map +1 -1
- package/dist/analyzers/health/detailed.d.ts.map +1 -1
- package/dist/analyzers/health/detailed.js +6 -2
- package/dist/analyzers/health/detailed.js.map +1 -1
- package/dist/analyzers/health.d.ts +0 -2
- package/dist/analyzers/health.d.ts.map +1 -1
- package/dist/analyzers/health.js +123 -72
- package/dist/analyzers/health.js.map +1 -1
- package/dist/analyzers/maintainability/shallow.d.ts +3 -2
- package/dist/analyzers/maintainability/shallow.d.ts.map +1 -1
- package/dist/analyzers/maintainability/shallow.js +2 -2
- package/dist/analyzers/maintainability/shallow.js.map +1 -1
- package/dist/analyzers/quality/detailed.js +1 -1
- package/dist/analyzers/quality/detailed.js.map +1 -1
- package/dist/analyzers/quality/gather.d.ts +33 -4
- package/dist/analyzers/quality/gather.d.ts.map +1 -1
- package/dist/analyzers/quality/gather.js +81 -93
- package/dist/analyzers/quality/gather.js.map +1 -1
- package/dist/analyzers/quality/index.js +4 -4
- package/dist/analyzers/quality/index.js.map +1 -1
- package/dist/analyzers/quality/shallow.d.ts +3 -2
- package/dist/analyzers/quality/shallow.d.ts.map +1 -1
- package/dist/analyzers/quality/shallow.js +2 -2
- package/dist/analyzers/quality/shallow.js.map +1 -1
- package/dist/analyzers/scoring.d.ts +26 -9
- package/dist/analyzers/scoring.d.ts.map +1 -1
- package/dist/analyzers/scoring.js +83 -71
- package/dist/analyzers/scoring.js.map +1 -1
- package/dist/analyzers/security/detailed.js +1 -1
- package/dist/analyzers/security/detailed.js.map +1 -1
- package/dist/analyzers/security/gather.d.ts +28 -5
- package/dist/analyzers/security/gather.d.ts.map +1 -1
- package/dist/analyzers/security/gather.js +87 -135
- package/dist/analyzers/security/gather.js.map +1 -1
- package/dist/analyzers/security/index.d.ts +1 -1
- package/dist/analyzers/security/index.d.ts.map +1 -1
- package/dist/analyzers/security/index.js +16 -11
- package/dist/analyzers/security/index.js.map +1 -1
- package/dist/analyzers/security/report.d.ts +6 -0
- package/dist/analyzers/security/report.d.ts.map +1 -0
- package/dist/analyzers/security/report.js +118 -0
- package/dist/analyzers/security/report.js.map +1 -0
- package/dist/analyzers/security/shallow.d.ts +3 -2
- package/dist/analyzers/security/shallow.d.ts.map +1 -1
- package/dist/analyzers/security/shallow.js +2 -2
- package/dist/analyzers/security/shallow.js.map +1 -1
- package/dist/analyzers/tests/detailed.js +1 -1
- package/dist/analyzers/tests/detailed.js.map +1 -1
- package/dist/analyzers/tests/import-graph.d.ts +8 -22
- package/dist/analyzers/tests/import-graph.d.ts.map +1 -1
- package/dist/analyzers/tests/import-graph.js +22 -189
- package/dist/analyzers/tests/import-graph.js.map +1 -1
- package/dist/analyzers/tests/index.d.ts +1 -1
- package/dist/analyzers/tests/index.d.ts.map +1 -1
- package/dist/analyzers/tests/index.js +3 -3
- package/dist/analyzers/tests/index.js.map +1 -1
- package/dist/analyzers/tests/shallow.d.ts +3 -2
- package/dist/analyzers/tests/shallow.d.ts.map +1 -1
- package/dist/analyzers/tests/shallow.js +2 -2
- package/dist/analyzers/tests/shallow.js.map +1 -1
- package/dist/analyzers/tools/coverage.d.ts +21 -11
- package/dist/analyzers/tools/coverage.d.ts.map +1 -1
- package/dist/analyzers/tools/coverage.js +32 -44
- package/dist/analyzers/tools/coverage.js.map +1 -1
- package/dist/analyzers/tools/dotnet.d.ts +8 -0
- package/dist/analyzers/tools/dotnet.d.ts.map +1 -0
- package/dist/analyzers/tools/dotnet.js +81 -0
- package/dist/analyzers/tools/dotnet.js.map +1 -0
- package/dist/analyzers/tools/gather-cache.d.ts +16 -0
- package/dist/analyzers/tools/gather-cache.d.ts.map +1 -0
- package/dist/analyzers/tools/gather-cache.js +126 -0
- package/dist/analyzers/tools/gather-cache.js.map +1 -0
- package/dist/analyzers/tools/generic.d.ts.map +1 -1
- package/dist/analyzers/tools/generic.js +6 -28
- package/dist/analyzers/tools/generic.js.map +1 -1
- package/dist/analyzers/tools/gitleaks.d.ts +28 -5
- package/dist/analyzers/tools/gitleaks.d.ts.map +1 -1
- package/dist/analyzers/tools/gitleaks.js +91 -37
- package/dist/analyzers/tools/gitleaks.js.map +1 -1
- package/dist/analyzers/tools/go.d.ts +8 -0
- package/dist/analyzers/tools/go.d.ts.map +1 -0
- package/dist/analyzers/tools/go.js +84 -0
- package/dist/analyzers/tools/go.js.map +1 -0
- package/dist/analyzers/tools/graphify.d.ts +31 -3
- package/dist/analyzers/tools/graphify.d.ts.map +1 -1
- package/dist/analyzers/tools/graphify.js +78 -36
- package/dist/analyzers/tools/graphify.js.map +1 -1
- package/dist/analyzers/tools/grep-secrets.d.ts +6 -0
- package/dist/analyzers/tools/grep-secrets.d.ts.map +1 -0
- package/dist/analyzers/tools/grep-secrets.js +124 -0
- package/dist/analyzers/tools/grep-secrets.js.map +1 -0
- package/dist/analyzers/tools/jscpd.d.ts +40 -0
- package/dist/analyzers/tools/jscpd.d.ts.map +1 -0
- package/dist/analyzers/tools/jscpd.js +96 -0
- package/dist/analyzers/tools/jscpd.js.map +1 -0
- package/dist/analyzers/tools/node.d.ts +8 -0
- package/dist/analyzers/tools/node.d.ts.map +1 -0
- package/dist/analyzers/tools/node.js +160 -0
- package/dist/analyzers/tools/node.js.map +1 -0
- package/dist/analyzers/tools/package-json.d.ts +6 -0
- package/dist/analyzers/tools/package-json.d.ts.map +1 -0
- package/dist/analyzers/tools/package-json.js +67 -0
- package/dist/analyzers/tools/package-json.js.map +1 -0
- package/dist/analyzers/tools/parallel.d.ts +22 -5
- package/dist/analyzers/tools/parallel.d.ts.map +1 -1
- package/dist/analyzers/tools/parallel.js +26 -185
- package/dist/analyzers/tools/parallel.js.map +1 -1
- package/dist/analyzers/tools/paths.d.ts +21 -0
- package/dist/analyzers/tools/paths.d.ts.map +1 -0
- package/dist/analyzers/tools/paths.js +62 -0
- package/dist/analyzers/tools/paths.js.map +1 -0
- package/dist/analyzers/tools/python.d.ts +8 -0
- package/dist/analyzers/tools/python.d.ts.map +1 -0
- package/dist/analyzers/tools/python.js +81 -0
- package/dist/analyzers/tools/python.js.map +1 -0
- package/dist/analyzers/tools/rust.d.ts +8 -0
- package/dist/analyzers/tools/rust.d.ts.map +1 -0
- package/dist/analyzers/tools/rust.js +86 -0
- package/dist/analyzers/tools/rust.js.map +1 -0
- package/dist/analyzers/tools/semgrep.d.ts +39 -0
- package/dist/analyzers/tools/semgrep.d.ts.map +1 -0
- package/dist/analyzers/tools/semgrep.js +129 -0
- package/dist/analyzers/tools/semgrep.js.map +1 -0
- package/dist/analyzers/tools/tool-registry.d.ts +0 -41
- package/dist/analyzers/tools/tool-registry.d.ts.map +1 -1
- package/dist/analyzers/tools/tool-registry.js +0 -87
- package/dist/analyzers/tools/tool-registry.js.map +1 -1
- package/dist/analyzers/types.d.ts +42 -30
- package/dist/analyzers/types.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/cli.js.map +1 -1
- package/dist/constants.d.ts +1 -3
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +55 -14
- package/dist/constants.js.map +1 -1
- package/dist/languages/capabilities/descriptors.d.ts +74 -0
- package/dist/languages/capabilities/descriptors.d.ts.map +1 -0
- package/dist/languages/capabilities/descriptors.js +250 -0
- package/dist/languages/capabilities/descriptors.js.map +1 -0
- package/dist/languages/capabilities/global.d.ts +43 -0
- package/dist/languages/capabilities/global.d.ts.map +1 -0
- package/dist/languages/capabilities/global.js +48 -0
- package/dist/languages/capabilities/global.js.map +1 -0
- package/dist/languages/capabilities/index.d.ts +31 -0
- package/dist/languages/capabilities/index.d.ts.map +1 -0
- package/dist/languages/capabilities/index.js +56 -0
- package/dist/languages/capabilities/index.js.map +1 -0
- package/dist/languages/capabilities/provider.d.ts +16 -0
- package/dist/languages/capabilities/provider.d.ts.map +1 -0
- package/dist/languages/capabilities/provider.js +12 -0
- package/dist/languages/capabilities/provider.js.map +1 -0
- package/dist/languages/capabilities/types.d.ts +226 -0
- package/dist/languages/capabilities/types.d.ts.map +1 -0
- package/dist/languages/capabilities/types.js +23 -0
- package/dist/languages/capabilities/types.js.map +1 -0
- package/dist/languages/csharp.d.ts +8 -0
- package/dist/languages/csharp.d.ts.map +1 -1
- package/dist/languages/csharp.js +203 -103
- package/dist/languages/csharp.js.map +1 -1
- package/dist/languages/go.d.ts +13 -7
- package/dist/languages/go.d.ts.map +1 -1
- package/dist/languages/go.js +277 -183
- package/dist/languages/go.js.map +1 -1
- package/dist/languages/python.d.ts +14 -0
- package/dist/languages/python.d.ts.map +1 -1
- package/dist/languages/python.js +276 -169
- package/dist/languages/python.js.map +1 -1
- package/dist/languages/rust.d.ts +8 -0
- package/dist/languages/rust.d.ts.map +1 -1
- package/dist/languages/rust.js +218 -131
- package/dist/languages/rust.js.map +1 -1
- package/dist/languages/types.d.ts +16 -15
- package/dist/languages/types.d.ts.map +1 -1
- package/dist/languages/typescript.d.ts +12 -11
- package/dist/languages/typescript.d.ts.map +1 -1
- package/dist/languages/typescript.js +256 -161
- package/dist/languages/typescript.js.map +1 -1
- package/package.json +1 -1
- package/templates/.ai/templates/session-checkpoint-template.md +97 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capability result envelopes.
|
|
3
|
+
*
|
|
4
|
+
* Phase 10e introduces a capabilities model: language packs (and global
|
|
5
|
+
* gatherers) expose typed *capabilities* that the dispatcher collects,
|
|
6
|
+
* runs, and aggregates. Each capability returns a strongly-typed envelope
|
|
7
|
+
* that extends `CapabilityEnvelope` so every result carries:
|
|
8
|
+
*
|
|
9
|
+
* - `schemaVersion`: pinned literal so downstream consumers can detect
|
|
10
|
+
* wire-format changes without inspecting fields.
|
|
11
|
+
* - `tool`: which underlying tool produced this result. Required for
|
|
12
|
+
* attribution in reports and for the `toolsUsed` aggregation.
|
|
13
|
+
*
|
|
14
|
+
* `ImportsResult` landed in Phase 10e.B.4 — a pack pre-computes the full
|
|
15
|
+
* per-pack import graph (extracted specifiers + resolved edges) for every
|
|
16
|
+
* source file matching its `sourceExtensions`, and the dispatcher unions
|
|
17
|
+
* the per-pack graphs so `buildReachable` can BFS over the unified edge
|
|
18
|
+
* map. Global-gatherer envelopes (`SecretsResult`, `CodePatternsResult`,
|
|
19
|
+
* ...) land in Phase 10e.B.6+.
|
|
20
|
+
*/
|
|
21
|
+
import type { Coverage } from '../../analyzers/tools/coverage';
|
|
22
|
+
/** Four-tier severity counts, the project-wide convention. */
|
|
23
|
+
export interface SeverityCounts {
|
|
24
|
+
critical: number;
|
|
25
|
+
high: number;
|
|
26
|
+
medium: number;
|
|
27
|
+
low: number;
|
|
28
|
+
}
|
|
29
|
+
/** Common shape every capability envelope carries. */
|
|
30
|
+
export interface CapabilityEnvelope {
|
|
31
|
+
/** Pinned literal — bump when the shape changes incompatibly. */
|
|
32
|
+
readonly schemaVersion: 1;
|
|
33
|
+
/** Underlying tool name (e.g. 'pip-audit', 'eslint', 'govulncheck'). */
|
|
34
|
+
readonly tool: string;
|
|
35
|
+
}
|
|
36
|
+
/** Per-finding detail for dep-vuln reports that need more than counts. */
|
|
37
|
+
export interface DepVulnFinding {
|
|
38
|
+
id: string;
|
|
39
|
+
package: string;
|
|
40
|
+
installedVersion?: string;
|
|
41
|
+
fixedVersion?: string;
|
|
42
|
+
severity: keyof SeverityCounts;
|
|
43
|
+
source: 'osv.dev' | 'tool-default' | 'tool-reported';
|
|
44
|
+
}
|
|
45
|
+
/** Dependency vulnerabilities, the depVulns capability. */
|
|
46
|
+
export interface DepVulnResult extends CapabilityEnvelope {
|
|
47
|
+
/** Severity-tier counts. Always populated; zeros allowed. */
|
|
48
|
+
counts: SeverityCounts;
|
|
49
|
+
/** Source of severity classification, when enrichment is involved. */
|
|
50
|
+
enrichment: 'osv.dev' | null;
|
|
51
|
+
/** Optional per-finding detail. Deep-mode reports populate this. */
|
|
52
|
+
findings?: DepVulnFinding[];
|
|
53
|
+
}
|
|
54
|
+
/** Lint output, the lint capability. Tier counts collapse to errors/warnings in legacy fields. */
|
|
55
|
+
export interface LintResult extends CapabilityEnvelope {
|
|
56
|
+
counts: SeverityCounts;
|
|
57
|
+
}
|
|
58
|
+
/** Coverage data, the coverage capability. Wraps the existing Coverage type. */
|
|
59
|
+
export interface CoverageResult extends CapabilityEnvelope {
|
|
60
|
+
coverage: Coverage;
|
|
61
|
+
}
|
|
62
|
+
/** Detected test runner, the testFramework capability. */
|
|
63
|
+
export interface TestFrameworkResult extends CapabilityEnvelope {
|
|
64
|
+
/** Lower-case framework id: 'vitest', 'jest', 'pytest', 'go-test', 'cargo-test', 'dotnet-test'. */
|
|
65
|
+
name: string;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Pre-computed import graph for one language pack, the imports capability.
|
|
69
|
+
*
|
|
70
|
+
* Every key in `extracted` and `edges` is a project-relative source file
|
|
71
|
+
* path matching one of `sourceExtensions`. Keys are disjoint across packs
|
|
72
|
+
* (a pack only owns files whose extension it declares), so the descriptor
|
|
73
|
+
* aggregates by plain union.
|
|
74
|
+
*
|
|
75
|
+
* `extracted` carries the raw specifiers captured from each file (e.g.
|
|
76
|
+
* `'./foo'`, `'lodash'`, `'../bar/baz'`). `edges` carries only the
|
|
77
|
+
* specifiers the pack could resolve to an in-project file; external
|
|
78
|
+
* packages and unresolvable specifiers are dropped. `buildReachable`
|
|
79
|
+
* consumes `edges`; future analyses (unused-imports, dead-code) can
|
|
80
|
+
* consume `extracted` without re-parsing source.
|
|
81
|
+
*
|
|
82
|
+
* Packs whose language has no file-based import resolution (Rust uses
|
|
83
|
+
* `mod`/crate paths, C# uses namespaces) still emit a result: `extracted`
|
|
84
|
+
* is populated for completeness and `edges` is empty. The union of an
|
|
85
|
+
* empty edges map is a no-op.
|
|
86
|
+
*/
|
|
87
|
+
export interface ImportsResult extends CapabilityEnvelope {
|
|
88
|
+
readonly sourceExtensions: ReadonlyArray<string>;
|
|
89
|
+
readonly extracted: ReadonlyMap<string, ReadonlyArray<string>>;
|
|
90
|
+
readonly edges: ReadonlyMap<string, ReadonlySet<string>>;
|
|
91
|
+
}
|
|
92
|
+
/** Per-finding detail for the secrets capability. */
|
|
93
|
+
export interface SecretFinding {
|
|
94
|
+
file: string;
|
|
95
|
+
line: number;
|
|
96
|
+
rule: string;
|
|
97
|
+
severity: keyof SeverityCounts;
|
|
98
|
+
/** Human-readable description from the scanner (e.g. gitleaks' `Description` field). */
|
|
99
|
+
title?: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Hardcoded-secret findings, the secrets capability. Produced by global
|
|
103
|
+
* scanners (gitleaks today, trufflehog-compatible in the future) that
|
|
104
|
+
* run once per repo rather than per language pack. `suppressedCount`
|
|
105
|
+
* is the count of findings the repo's `.dxkit-suppressions.json`
|
|
106
|
+
* acknowledged and dropped — reported separately so the UI can
|
|
107
|
+
* distinguish "zero findings" from "zero visible findings after
|
|
108
|
+
* suppression."
|
|
109
|
+
*/
|
|
110
|
+
export interface SecretsResult extends CapabilityEnvelope {
|
|
111
|
+
findings: ReadonlyArray<SecretFinding>;
|
|
112
|
+
suppressedCount: number;
|
|
113
|
+
}
|
|
114
|
+
/** Per-finding detail for the codePatterns capability. */
|
|
115
|
+
export interface CodePatternFinding {
|
|
116
|
+
file: string;
|
|
117
|
+
line: number;
|
|
118
|
+
rule: string;
|
|
119
|
+
severity: keyof SeverityCounts;
|
|
120
|
+
/** Human-readable summary from the scanner (first line of semgrep's `message`). */
|
|
121
|
+
title: string;
|
|
122
|
+
/** CWE identifier when the scanner supplies one (e.g. `CWE-79`). Empty otherwise. */
|
|
123
|
+
cwe: string;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Code-pattern findings, the codePatterns capability. Produced by static
|
|
127
|
+
* analysis scanners (semgrep today) that consume rulesets per active
|
|
128
|
+
* language pack (`LanguageSupport.semgrepRulesets`). Running once per
|
|
129
|
+
* repo rather than per pack: the scanner takes a union of rulesets and
|
|
130
|
+
* emits findings attributed by file path.
|
|
131
|
+
*
|
|
132
|
+
* `suppressedCount` mirrors `SecretsResult` — the count dropped by
|
|
133
|
+
* `.dxkit-suppressions.json` so the UI can report "zero visible after
|
|
134
|
+
* suppression" separately from "zero real findings."
|
|
135
|
+
*/
|
|
136
|
+
export interface CodePatternsResult extends CapabilityEnvelope {
|
|
137
|
+
findings: ReadonlyArray<CodePatternFinding>;
|
|
138
|
+
suppressedCount: number;
|
|
139
|
+
}
|
|
140
|
+
/** One side of a duplicate block reported by a clone detector. */
|
|
141
|
+
export interface DuplicationCloneSide {
|
|
142
|
+
file: string;
|
|
143
|
+
startLine: number;
|
|
144
|
+
endLine: number;
|
|
145
|
+
}
|
|
146
|
+
/** A single clone pair (two locations with matching content). */
|
|
147
|
+
export interface DuplicationClone {
|
|
148
|
+
lines: number;
|
|
149
|
+
tokens: number;
|
|
150
|
+
a: DuplicationCloneSide;
|
|
151
|
+
b: DuplicationCloneSide;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Duplication metrics, the duplication capability. Produced by clone
|
|
155
|
+
* detectors (jscpd today) that tokenize every source file and emit
|
|
156
|
+
* pair-wise matches above configured thresholds. `topClones` is
|
|
157
|
+
* bounded (the detector sorts + truncates) so the envelope is safe
|
|
158
|
+
* to keep in reports.
|
|
159
|
+
*/
|
|
160
|
+
export interface DuplicationResult extends CapabilityEnvelope {
|
|
161
|
+
totalLines: number;
|
|
162
|
+
duplicatedLines: number;
|
|
163
|
+
/** Rounded to 2 decimal places. */
|
|
164
|
+
percentage: number;
|
|
165
|
+
/** Total clone pairs found (may exceed topClones.length after truncation). */
|
|
166
|
+
cloneCount: number;
|
|
167
|
+
/** Largest clone pairs first; typically capped at ~15. */
|
|
168
|
+
topClones: ReadonlyArray<DuplicationClone>;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Structural metrics, the structural capability. Produced by AST
|
|
172
|
+
* graph-builders (graphify today) that walk every source file via
|
|
173
|
+
* tree-sitter, build a call-graph, detect communities, and derive
|
|
174
|
+
* cohesion / dead-import / orphan signals.
|
|
175
|
+
*
|
|
176
|
+
* Every field is a repo-level scalar produced by one graph pass —
|
|
177
|
+
* summing them across providers would double-count the same real
|
|
178
|
+
* functions/modules, so the descriptor aggregate is last-wins
|
|
179
|
+
* (matches COVERAGE's strategy for the same reason).
|
|
180
|
+
*/
|
|
181
|
+
export interface StructuralResult extends CapabilityEnvelope {
|
|
182
|
+
functionCount: number;
|
|
183
|
+
classCount: number;
|
|
184
|
+
maxFunctionsInFile: number;
|
|
185
|
+
maxFunctionsFilePath: string;
|
|
186
|
+
godNodeCount: number;
|
|
187
|
+
communityCount: number;
|
|
188
|
+
/** Mean cohesion score across communities, 0-1 range, 3 decimal places. */
|
|
189
|
+
avgCohesion: number;
|
|
190
|
+
orphanModuleCount: number;
|
|
191
|
+
deadImportCount: number;
|
|
192
|
+
/** Share of source files with zero AST nodes — proxy for "mostly-commented" files. */
|
|
193
|
+
commentedCodeRatio: number;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Internal outcome shape used by language packs' `gatherDepVulnsResult`
|
|
197
|
+
* helpers. The pack's `capabilities.depVulns` provider unwraps the
|
|
198
|
+
* envelope (returning null for every non-success kind) so the dispatcher
|
|
199
|
+
* surface stays `T | null`; keeping the richer outcome here lets the
|
|
200
|
+
* pack's own code distinguish e.g. "tool missing" from "tool ran but
|
|
201
|
+
* produced no output" if a future caller needs that detail.
|
|
202
|
+
*/
|
|
203
|
+
export type DepVulnGatherOutcome = {
|
|
204
|
+
kind: 'success';
|
|
205
|
+
envelope: DepVulnResult;
|
|
206
|
+
} | {
|
|
207
|
+
kind: 'tool-missing';
|
|
208
|
+
} | {
|
|
209
|
+
kind: 'parse-error';
|
|
210
|
+
} | {
|
|
211
|
+
kind: 'no-output';
|
|
212
|
+
};
|
|
213
|
+
/**
|
|
214
|
+
* Internal outcome shape for the lint capability. Simpler than depVulns:
|
|
215
|
+
* either the linter ran and we have tier counts, or it didn't and we
|
|
216
|
+
* have a reason. The pack's `capabilities.lint` provider unwraps
|
|
217
|
+
* `success` into the envelope and returns null otherwise.
|
|
218
|
+
*/
|
|
219
|
+
export type LintGatherOutcome = {
|
|
220
|
+
kind: 'success';
|
|
221
|
+
envelope: LintResult;
|
|
222
|
+
} | {
|
|
223
|
+
kind: 'unavailable';
|
|
224
|
+
reason: string;
|
|
225
|
+
};
|
|
226
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/languages/capabilities/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE/D,8DAA8D;AAC9D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;CACb;AAED,sDAAsD;AACtD,MAAM,WAAW,kBAAkB;IACjC,iEAAiE;IACjE,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,0EAA0E;AAC1E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,cAAc,CAAC;IAC/B,MAAM,EAAE,SAAS,GAAG,cAAc,GAAG,eAAe,CAAC;CACtD;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAc,SAAQ,kBAAkB;IACvD,6DAA6D;IAC7D,MAAM,EAAE,cAAc,CAAC;IACvB,sEAAsE;IACtE,UAAU,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,oEAAoE;IACpE,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED,kGAAkG;AAClG,MAAM,WAAW,UAAW,SAAQ,kBAAkB;IACpD,MAAM,EAAE,cAAc,CAAC;CACxB;AAED,gFAAgF;AAChF,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,0DAA0D;AAC1D,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,mGAAmG;IACnG,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,aAAc,SAAQ,kBAAkB;IACvD,QAAQ,CAAC,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACjD,QAAQ,CAAC,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/D,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;CAC1D;AAED,qDAAqD;AACrD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,cAAc,CAAC;IAC/B,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAc,SAAQ,kBAAkB;IACvD,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACvC,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,0DAA0D;AAC1D,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,cAAc,CAAC;IAC/B,mFAAmF;IACnF,KAAK,EAAE,MAAM,CAAC;IACd,qFAAqF;IACrF,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAmB,SAAQ,kBAAkB;IAC5D,QAAQ,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAC;IAC5C,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,kEAAkE;AAClE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,EAAE,oBAAoB,CAAC;IACxB,CAAC,EAAE,oBAAoB,CAAC;CACzB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,iBAAkB,SAAQ,kBAAkB;IAC3D,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAC;IACnB,0DAA0D;IAC1D,SAAS,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAC;CAC5C;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,gBAAiB,SAAQ,kBAAkB;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAC5B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,aAAa,CAAA;CAAE,GAC5C;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GACzB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,EAAE,UAAU,CAAA;CAAE,GACzC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Capability result envelopes.
|
|
4
|
+
*
|
|
5
|
+
* Phase 10e introduces a capabilities model: language packs (and global
|
|
6
|
+
* gatherers) expose typed *capabilities* that the dispatcher collects,
|
|
7
|
+
* runs, and aggregates. Each capability returns a strongly-typed envelope
|
|
8
|
+
* that extends `CapabilityEnvelope` so every result carries:
|
|
9
|
+
*
|
|
10
|
+
* - `schemaVersion`: pinned literal so downstream consumers can detect
|
|
11
|
+
* wire-format changes without inspecting fields.
|
|
12
|
+
* - `tool`: which underlying tool produced this result. Required for
|
|
13
|
+
* attribution in reports and for the `toolsUsed` aggregation.
|
|
14
|
+
*
|
|
15
|
+
* `ImportsResult` landed in Phase 10e.B.4 — a pack pre-computes the full
|
|
16
|
+
* per-pack import graph (extracted specifiers + resolved edges) for every
|
|
17
|
+
* source file matching its `sourceExtensions`, and the dispatcher unions
|
|
18
|
+
* the per-pack graphs so `buildReachable` can BFS over the unified edge
|
|
19
|
+
* map. Global-gatherer envelopes (`SecretsResult`, `CodePatternsResult`,
|
|
20
|
+
* ...) land in Phase 10e.B.6+.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/languages/capabilities/types.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { Coverage } from '../analyzers/tools/coverage';
|
|
2
2
|
import type { LanguageSupport } from './types';
|
|
3
3
|
export declare function parseCoberturaXml(raw: string, sourceFile: string, cwd: string): Coverage | null;
|
|
4
|
+
/**
|
|
5
|
+
* Capture C# `using` directives from source text, including
|
|
6
|
+
* `using static Foo`, aliased (`using X = Foo.Bar`), and plain forms.
|
|
7
|
+
* C# has no deterministic file-level resolver (namespaces aren't files),
|
|
8
|
+
* so this is the only raw helper the imports capability needs. Exported
|
|
9
|
+
* for unit tests.
|
|
10
|
+
*/
|
|
11
|
+
export declare function extractCsharpImportsRaw(content: string): string[];
|
|
4
12
|
export declare const csharp: LanguageSupport;
|
|
5
13
|
//# sourceMappingURL=csharp.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csharp.d.ts","sourceRoot":"","sources":["../../src/languages/csharp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"csharp.d.ts","sourceRoot":"","sources":["../../src/languages/csharp.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAgB,MAAM,6BAA6B,CAAC;AAc1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAwD/C,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAoC/F;AA+HD;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAQjE;AAqED,eAAO,MAAM,MAAM,EAAE,eAqCpB,CAAC"}
|
package/dist/languages/csharp.js
CHANGED
|
@@ -35,8 +35,10 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.csharp = void 0;
|
|
37
37
|
exports.parseCoberturaXml = parseCoberturaXml;
|
|
38
|
+
exports.extractCsharpImportsRaw = extractCsharpImportsRaw;
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
39
40
|
const path = __importStar(require("path"));
|
|
41
|
+
const exclusions_1 = require("../analyzers/tools/exclusions");
|
|
40
42
|
const runner_1 = require("../analyzers/tools/runner");
|
|
41
43
|
const tool_registry_1 = require("../analyzers/tools/tool-registry");
|
|
42
44
|
function dirHasMatching(dir, regex) {
|
|
@@ -133,6 +135,201 @@ function parseCoberturaXml(raw, sourceFile, cwd) {
|
|
|
133
135
|
const rel = path.relative(cwd, path.resolve(cwd, sourceFile)).split(path.sep).join('/');
|
|
134
136
|
return { source: 'cobertura', sourceFile: rel || sourceFile, linePercent, files };
|
|
135
137
|
}
|
|
138
|
+
/**
|
|
139
|
+
* Single source of truth for the csharp pack's dep-vuln gathering.
|
|
140
|
+
* Consumed by `csharpDepVulnsProvider` (capability dispatcher). Runs
|
|
141
|
+
* independently of `dotnet-format` availability — historical bug where
|
|
142
|
+
* projects with `dotnet` but no `dotnet-format` saw zero vuln data.
|
|
143
|
+
*/
|
|
144
|
+
async function gatherCsharpDepVulnsResult(cwd) {
|
|
145
|
+
const vulnRaw = (0, runner_1.run)('dotnet list package --vulnerable --format json 2>/dev/null', cwd, 120000);
|
|
146
|
+
if (!vulnRaw)
|
|
147
|
+
return { kind: 'no-output' };
|
|
148
|
+
try {
|
|
149
|
+
const data = JSON.parse(vulnRaw);
|
|
150
|
+
let critical = 0;
|
|
151
|
+
let high = 0;
|
|
152
|
+
let medium = 0;
|
|
153
|
+
let low = 0;
|
|
154
|
+
for (const proj of data.projects || []) {
|
|
155
|
+
for (const fw of proj.frameworks || []) {
|
|
156
|
+
for (const pkg of fw.topLevelPackages || []) {
|
|
157
|
+
for (const adv of pkg.advisories || []) {
|
|
158
|
+
const sev = adv.severity?.toLowerCase();
|
|
159
|
+
if (sev === 'critical')
|
|
160
|
+
critical++;
|
|
161
|
+
else if (sev === 'high')
|
|
162
|
+
high++;
|
|
163
|
+
else if (sev === 'moderate' || sev === 'medium')
|
|
164
|
+
medium++;
|
|
165
|
+
else
|
|
166
|
+
low++;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (critical + high + medium + low === 0)
|
|
172
|
+
return { kind: 'no-output' };
|
|
173
|
+
const envelope = {
|
|
174
|
+
schemaVersion: 1,
|
|
175
|
+
tool: 'dotnet-vulnerable',
|
|
176
|
+
enrichment: null,
|
|
177
|
+
counts: { critical, high, medium, low },
|
|
178
|
+
};
|
|
179
|
+
return { kind: 'success', envelope };
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return { kind: 'parse-error' };
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
const csharpDepVulnsProvider = {
|
|
186
|
+
source: 'csharp',
|
|
187
|
+
async gather(cwd) {
|
|
188
|
+
const outcome = await gatherCsharpDepVulnsResult(cwd);
|
|
189
|
+
return outcome.kind === 'success' ? outcome.envelope : null;
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Single source of truth for the csharp pack's lint gathering.
|
|
194
|
+
* Consumed by `csharpLintProvider` (capability dispatcher).
|
|
195
|
+
*
|
|
196
|
+
* dotnet-format is a formatter, not a tiered linter — it emits binary
|
|
197
|
+
* pass/fail per file. Violations are formatting issues (indentation,
|
|
198
|
+
* spacing), not correctness. This helper reports them at `low` tier so
|
|
199
|
+
* they don't inflate the Quality/Slop score.
|
|
200
|
+
*/
|
|
201
|
+
function gatherCsharpLintResult(cwd) {
|
|
202
|
+
const dotnet = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS['dotnet-format'], cwd);
|
|
203
|
+
if (!dotnet.available) {
|
|
204
|
+
return { kind: 'unavailable', reason: 'not installed' };
|
|
205
|
+
}
|
|
206
|
+
const exitCode = (0, runner_1.runExitCode)('dotnet format --verify-no-changes 2>/dev/null', cwd, 120000);
|
|
207
|
+
let violations = 0;
|
|
208
|
+
if (exitCode !== 0) {
|
|
209
|
+
const raw = (0, runner_1.run)('dotnet format --verify-no-changes 2>&1', cwd, 120000);
|
|
210
|
+
violations = raw ? raw.split('\n').filter((l) => l.includes('Formatted')).length : 1;
|
|
211
|
+
}
|
|
212
|
+
const envelope = {
|
|
213
|
+
schemaVersion: 1,
|
|
214
|
+
tool: 'dotnet-format',
|
|
215
|
+
counts: { critical: 0, high: 0, medium: 0, low: violations },
|
|
216
|
+
};
|
|
217
|
+
return { kind: 'success', envelope };
|
|
218
|
+
}
|
|
219
|
+
const csharpLintProvider = {
|
|
220
|
+
source: 'csharp',
|
|
221
|
+
async gather(cwd) {
|
|
222
|
+
const outcome = gatherCsharpLintResult(cwd);
|
|
223
|
+
return outcome.kind === 'success' ? outcome.envelope : null;
|
|
224
|
+
},
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Single source of truth for the csharp pack's coverage gathering.
|
|
228
|
+
* Locates the Cobertura artifact across known layouts (explicit `coverage/`
|
|
229
|
+
* dir or `dotnet test --collect`'s TestResults/<guid>/ subtree). Consumed
|
|
230
|
+
* by `csharpCoverageProvider` (capability dispatcher).
|
|
231
|
+
*/
|
|
232
|
+
function gatherCsharpCoverageResult(cwd) {
|
|
233
|
+
const artifact = findCoberturaArtifact(cwd);
|
|
234
|
+
if (!artifact)
|
|
235
|
+
return null;
|
|
236
|
+
let raw;
|
|
237
|
+
try {
|
|
238
|
+
raw = fs.readFileSync(artifact, 'utf-8');
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
return null;
|
|
242
|
+
}
|
|
243
|
+
const rel = path.relative(cwd, artifact).split(path.sep).join('/');
|
|
244
|
+
const coverage = parseCoberturaXml(raw, rel, cwd);
|
|
245
|
+
if (!coverage)
|
|
246
|
+
return null;
|
|
247
|
+
return { schemaVersion: 1, tool: `coverage:${coverage.source}`, coverage };
|
|
248
|
+
}
|
|
249
|
+
const csharpCoverageProvider = {
|
|
250
|
+
source: 'csharp',
|
|
251
|
+
async gather(cwd) {
|
|
252
|
+
return gatherCsharpCoverageResult(cwd);
|
|
253
|
+
},
|
|
254
|
+
};
|
|
255
|
+
/**
|
|
256
|
+
* Capture C# `using` directives from source text, including
|
|
257
|
+
* `using static Foo`, aliased (`using X = Foo.Bar`), and plain forms.
|
|
258
|
+
* C# has no deterministic file-level resolver (namespaces aren't files),
|
|
259
|
+
* so this is the only raw helper the imports capability needs. Exported
|
|
260
|
+
* for unit tests.
|
|
261
|
+
*/
|
|
262
|
+
function extractCsharpImportsRaw(content) {
|
|
263
|
+
const out = [];
|
|
264
|
+
const re = /^\s*using\s+(?:static\s+)?(?:[A-Za-z_]\w*\s*=\s*)?([A-Za-z_][\w.]*)\s*;/gm;
|
|
265
|
+
let m;
|
|
266
|
+
while ((m = re.exec(content)) !== null) {
|
|
267
|
+
out.push(m[1]);
|
|
268
|
+
}
|
|
269
|
+
return out;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Enumerate .cs source files and capture the pack's per-file imports.
|
|
273
|
+
* C# has no `resolveImport` (namespaces don't map to file paths
|
|
274
|
+
* deterministically), so `edges` is always empty.
|
|
275
|
+
*/
|
|
276
|
+
function gatherCsharpImportsResult(cwd) {
|
|
277
|
+
const excludes = (0, exclusions_1.getFindExcludeFlags)(cwd);
|
|
278
|
+
const raw = (0, runner_1.run)(`find . -type f -name "*.cs" ${excludes} 2>/dev/null`, cwd);
|
|
279
|
+
if (!raw)
|
|
280
|
+
return null;
|
|
281
|
+
const extracted = new Map();
|
|
282
|
+
for (const line of raw.split('\n')) {
|
|
283
|
+
const p = line.trim();
|
|
284
|
+
if (!p)
|
|
285
|
+
continue;
|
|
286
|
+
const rel = p.replace(/^\.\//, '');
|
|
287
|
+
let content;
|
|
288
|
+
try {
|
|
289
|
+
content = fs.readFileSync(path.join(cwd, rel), 'utf-8');
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
extracted.set(rel, extractCsharpImportsRaw(content));
|
|
295
|
+
}
|
|
296
|
+
if (extracted.size === 0)
|
|
297
|
+
return null;
|
|
298
|
+
return {
|
|
299
|
+
schemaVersion: 1,
|
|
300
|
+
tool: 'csharp-imports',
|
|
301
|
+
sourceExtensions: ['.cs'],
|
|
302
|
+
extracted,
|
|
303
|
+
edges: new Map(),
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
const csharpImportsProvider = {
|
|
307
|
+
source: 'csharp',
|
|
308
|
+
async gather(cwd) {
|
|
309
|
+
return gatherCsharpImportsResult(cwd);
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
/**
|
|
313
|
+
* Detect C# test projects by the runner package referenced in the
|
|
314
|
+
* project's `.csproj` file — xunit, NUnit, and MSTest cover the
|
|
315
|
+
* dominant majority of .NET test projects. A repo without any
|
|
316
|
+
* `.csproj` referencing these returns null.
|
|
317
|
+
*/
|
|
318
|
+
function gatherCsharpTestFrameworkResult(cwd) {
|
|
319
|
+
const hasCsproj = (0, runner_1.fileExists)(cwd, '*.csproj') || !!findMatchingRecursive(cwd, /\.csproj$/, 3);
|
|
320
|
+
if (!hasCsproj)
|
|
321
|
+
return null;
|
|
322
|
+
const csproj = (0, runner_1.run)("find . -name '*.csproj' -exec grep -l 'xunit\\|nunit\\|MSTest' {} \\; 2>/dev/null | head -1", cwd);
|
|
323
|
+
if (!csproj)
|
|
324
|
+
return null;
|
|
325
|
+
return { schemaVersion: 1, tool: 'csharp', name: 'dotnet-test' };
|
|
326
|
+
}
|
|
327
|
+
const csharpTestFrameworkProvider = {
|
|
328
|
+
source: 'csharp',
|
|
329
|
+
async gather(cwd) {
|
|
330
|
+
return gatherCsharpTestFrameworkResult(cwd);
|
|
331
|
+
},
|
|
332
|
+
};
|
|
136
333
|
exports.csharp = {
|
|
137
334
|
id: 'csharp',
|
|
138
335
|
displayName: 'C#',
|
|
@@ -147,35 +344,13 @@ exports.csharp = {
|
|
|
147
344
|
tools: ['dotnet-format'],
|
|
148
345
|
// p/csharp semgrep ruleset is sparse — skip until it matures.
|
|
149
346
|
semgrepRulesets: [],
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
raw = fs.readFileSync(artifact, 'utf-8');
|
|
157
|
-
}
|
|
158
|
-
catch {
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
const rel = path.relative(cwd, artifact).split(path.sep).join('/');
|
|
162
|
-
return parseCoberturaXml(raw, rel, cwd);
|
|
347
|
+
capabilities: {
|
|
348
|
+
depVulns: csharpDepVulnsProvider,
|
|
349
|
+
lint: csharpLintProvider,
|
|
350
|
+
coverage: csharpCoverageProvider,
|
|
351
|
+
imports: csharpImportsProvider,
|
|
352
|
+
testFramework: csharpTestFrameworkProvider,
|
|
163
353
|
},
|
|
164
|
-
extractImports(content) {
|
|
165
|
-
// `using System;`, `using System.IO;`, `using static System.Math;`,
|
|
166
|
-
// `using Alias = Foo.Bar;`. Captures the fully-qualified namespace.
|
|
167
|
-
const out = [];
|
|
168
|
-
const re = /^\s*using\s+(?:static\s+)?(?:[A-Za-z_]\w*\s*=\s*)?([A-Za-z_][\w.]*)\s*;/gm;
|
|
169
|
-
let m;
|
|
170
|
-
while ((m = re.exec(content)) !== null) {
|
|
171
|
-
out.push(m[1]);
|
|
172
|
-
}
|
|
173
|
-
return out;
|
|
174
|
-
},
|
|
175
|
-
// resolveImport intentionally omitted: C# namespaces don't map to file
|
|
176
|
-
// paths deterministically — one namespace can span many files, one file
|
|
177
|
-
// can declare many namespaces. Internal edges are best inferred via the
|
|
178
|
-
// project assembly graph, which is out of scope here.
|
|
179
354
|
// mapLintSeverity intentionally omitted: dotnet-format is a formatter,
|
|
180
355
|
// not a tiered linter. It emits binary pass/fail per file and doesn't
|
|
181
356
|
// expose per-rule codes that could be categorized into
|
|
@@ -186,80 +361,5 @@ exports.csharp = {
|
|
|
186
361
|
// mapping each to a tier. That's deferred until a C# test project
|
|
187
362
|
// is available to validate the integration; see architecture-redesign
|
|
188
363
|
// plan for the capability-based approach this will live in.
|
|
189
|
-
async gatherMetrics(cwd) {
|
|
190
|
-
const metrics = {
|
|
191
|
-
toolsUsed: [],
|
|
192
|
-
toolsUnavailable: [],
|
|
193
|
-
};
|
|
194
|
-
const dotnet = (0, tool_registry_1.findTool)(tool_registry_1.TOOL_DEFS['dotnet-format'], cwd);
|
|
195
|
-
if (dotnet.available) {
|
|
196
|
-
const exitCode = (0, runner_1.runExitCode)('dotnet format --verify-no-changes 2>/dev/null', cwd, 120000);
|
|
197
|
-
if (exitCode === 0) {
|
|
198
|
-
metrics.lintErrors = 0;
|
|
199
|
-
metrics.lintWarnings = 0;
|
|
200
|
-
}
|
|
201
|
-
else {
|
|
202
|
-
const raw = (0, runner_1.run)('dotnet format --verify-no-changes 2>&1', cwd, 120000);
|
|
203
|
-
const violations = raw ? raw.split('\n').filter((l) => l.includes('Formatted')).length : 1;
|
|
204
|
-
// dotnet-format findings are formatting violations (indentation,
|
|
205
|
-
// spacing) — style issues, not correctness errors. Report them as
|
|
206
|
-
// warnings so they don't inflate the "lint errors" count that
|
|
207
|
-
// drives Quality/Slop scoring. A future upgrade to parse
|
|
208
|
-
// `dotnet build` diagnostics can populate lintErrors properly.
|
|
209
|
-
metrics.lintErrors = 0;
|
|
210
|
-
metrics.lintWarnings = violations;
|
|
211
|
-
}
|
|
212
|
-
metrics.lintTool = 'dotnet-format';
|
|
213
|
-
metrics.toolsUsed.push('dotnet-format');
|
|
214
|
-
const vulnRaw = (0, runner_1.run)('dotnet list package --vulnerable --format json 2>/dev/null', cwd, 120000);
|
|
215
|
-
if (vulnRaw) {
|
|
216
|
-
try {
|
|
217
|
-
const data = JSON.parse(vulnRaw);
|
|
218
|
-
let critical = 0;
|
|
219
|
-
let high = 0;
|
|
220
|
-
let medium = 0;
|
|
221
|
-
let low = 0;
|
|
222
|
-
for (const proj of data.projects || []) {
|
|
223
|
-
for (const fw of proj.frameworks || []) {
|
|
224
|
-
for (const pkg of fw.topLevelPackages || []) {
|
|
225
|
-
for (const adv of pkg.advisories || []) {
|
|
226
|
-
const sev = adv.severity?.toLowerCase();
|
|
227
|
-
if (sev === 'critical')
|
|
228
|
-
critical++;
|
|
229
|
-
else if (sev === 'high')
|
|
230
|
-
high++;
|
|
231
|
-
else if (sev === 'moderate' || sev === 'medium')
|
|
232
|
-
medium++;
|
|
233
|
-
else
|
|
234
|
-
low++;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
if (critical + high + medium + low > 0) {
|
|
240
|
-
metrics.depVulnCritical = critical;
|
|
241
|
-
metrics.depVulnHigh = high;
|
|
242
|
-
metrics.depVulnMedium = medium;
|
|
243
|
-
metrics.depVulnLow = low;
|
|
244
|
-
metrics.depAuditTool = 'dotnet-vulnerable';
|
|
245
|
-
metrics.toolsUsed.push('dotnet-vulnerable');
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
catch {
|
|
249
|
-
metrics.toolsUnavailable.push('dotnet-vulnerable (parse error)');
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
else {
|
|
254
|
-
metrics.toolsUnavailable.push('dotnet-format');
|
|
255
|
-
}
|
|
256
|
-
if ((0, runner_1.fileExists)(cwd, '*.csproj') || findMatchingRecursive(cwd, /\.csproj$/, 3)) {
|
|
257
|
-
const csproj = (0, runner_1.run)("find . -name '*.csproj' -exec grep -l 'xunit\\|nunit\\|MSTest' {} \\; 2>/dev/null | head -1", cwd);
|
|
258
|
-
if (csproj) {
|
|
259
|
-
metrics.testFramework = 'dotnet-test';
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return metrics;
|
|
263
|
-
},
|
|
264
364
|
};
|
|
265
365
|
//# sourceMappingURL=csharp.js.map
|