@grafema/cli 0.1.1-alpha
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 +190 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +36 -0
- package/dist/commands/analyze.d.ts +6 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +209 -0
- package/dist/commands/check.d.ts +10 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +295 -0
- package/dist/commands/coverage.d.ts +11 -0
- package/dist/commands/coverage.d.ts.map +1 -0
- package/dist/commands/coverage.js +96 -0
- package/dist/commands/explore.d.ts +6 -0
- package/dist/commands/explore.d.ts.map +1 -0
- package/dist/commands/explore.js +633 -0
- package/dist/commands/get.d.ts +10 -0
- package/dist/commands/get.d.ts.map +1 -0
- package/dist/commands/get.js +189 -0
- package/dist/commands/impact.d.ts +10 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +313 -0
- package/dist/commands/init.d.ts +6 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +94 -0
- package/dist/commands/overview.d.ts +6 -0
- package/dist/commands/overview.d.ts.map +1 -0
- package/dist/commands/overview.js +91 -0
- package/dist/commands/query.d.ts +13 -0
- package/dist/commands/query.d.ts.map +1 -0
- package/dist/commands/query.js +340 -0
- package/dist/commands/server.d.ts +11 -0
- package/dist/commands/server.d.ts.map +1 -0
- package/dist/commands/server.js +300 -0
- package/dist/commands/stats.d.ts +6 -0
- package/dist/commands/stats.d.ts.map +1 -0
- package/dist/commands/stats.js +52 -0
- package/dist/commands/trace.d.ts +10 -0
- package/dist/commands/trace.d.ts.map +1 -0
- package/dist/commands/trace.js +270 -0
- package/dist/utils/codePreview.d.ts +28 -0
- package/dist/utils/codePreview.d.ts.map +1 -0
- package/dist/utils/codePreview.js +51 -0
- package/dist/utils/errorFormatter.d.ts +24 -0
- package/dist/utils/errorFormatter.d.ts.map +1 -0
- package/dist/utils/errorFormatter.js +32 -0
- package/dist/utils/formatNode.d.ts +53 -0
- package/dist/utils/formatNode.d.ts.map +1 -0
- package/dist/utils/formatNode.js +49 -0
- package/package.json +54 -0
- package/src/cli.ts +41 -0
- package/src/commands/analyze.ts +271 -0
- package/src/commands/check.ts +379 -0
- package/src/commands/coverage.ts +108 -0
- package/src/commands/explore.tsx +1056 -0
- package/src/commands/get.ts +265 -0
- package/src/commands/impact.ts +400 -0
- package/src/commands/init.ts +112 -0
- package/src/commands/overview.ts +108 -0
- package/src/commands/query.ts +425 -0
- package/src/commands/server.ts +335 -0
- package/src/commands/stats.ts +58 -0
- package/src/commands/trace.ts +341 -0
- package/src/utils/codePreview.ts +77 -0
- package/src/utils/errorFormatter.ts +35 -0
- package/src/utils/formatNode.ts +88 -0
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check command - Check invariants/guarantees
|
|
3
|
+
*
|
|
4
|
+
* Supports two modes:
|
|
5
|
+
* 1. Rule-based: Check YAML-defined guarantees (default)
|
|
6
|
+
* 2. Built-in validators: --guarantee=<name> (e.g., --guarantee=node-creation)
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
import { resolve, join } from 'path';
|
|
10
|
+
import { existsSync } from 'fs';
|
|
11
|
+
import { RFDBServerBackend, GuaranteeManager, NodeCreationValidator, GraphFreshnessChecker, IncrementalReanalyzer } from '@grafema/core';
|
|
12
|
+
import { exitWithError } from '../utils/errorFormatter.js';
|
|
13
|
+
// Available built-in validators
|
|
14
|
+
const BUILT_IN_VALIDATORS = {
|
|
15
|
+
'node-creation': {
|
|
16
|
+
name: 'NodeCreationValidator',
|
|
17
|
+
description: 'Validates that all nodes are created through NodeFactory'
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
export const checkCommand = new Command('check')
|
|
21
|
+
.description('Check invariants/guarantees')
|
|
22
|
+
.argument('[rule]', 'Specific rule ID to check (or "all" for all rules)')
|
|
23
|
+
.option('-p, --project <path>', 'Project path', '.')
|
|
24
|
+
.option('-f, --file <path>', 'Path to guarantees YAML file')
|
|
25
|
+
.option('-g, --guarantee <name>', 'Run a built-in guarantee validator (e.g., node-creation)')
|
|
26
|
+
.option('-j, --json', 'Output results as JSON')
|
|
27
|
+
.option('-q, --quiet', 'Only output failures')
|
|
28
|
+
.option('--list-guarantees', 'List available built-in guarantees')
|
|
29
|
+
.option('--skip-reanalysis', 'Skip automatic reanalysis of stale modules')
|
|
30
|
+
.option('--fail-on-stale', 'Exit with error if stale modules found (CI mode)')
|
|
31
|
+
.action(async (rule, options) => {
|
|
32
|
+
// List available guarantees
|
|
33
|
+
if (options.listGuarantees) {
|
|
34
|
+
console.log('Available built-in guarantees:');
|
|
35
|
+
console.log('');
|
|
36
|
+
for (const [key, info] of Object.entries(BUILT_IN_VALIDATORS)) {
|
|
37
|
+
console.log(` ${key}`);
|
|
38
|
+
console.log(` ${info.description}`);
|
|
39
|
+
console.log('');
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Run built-in guarantee validator
|
|
44
|
+
if (options.guarantee) {
|
|
45
|
+
const validatorInfo = BUILT_IN_VALIDATORS[options.guarantee];
|
|
46
|
+
if (!validatorInfo) {
|
|
47
|
+
const available = Object.keys(BUILT_IN_VALIDATORS).join(', ');
|
|
48
|
+
exitWithError(`Unknown guarantee: ${options.guarantee}`, [
|
|
49
|
+
`Available: ${available}`
|
|
50
|
+
]);
|
|
51
|
+
}
|
|
52
|
+
await runBuiltInValidator(options.guarantee, options.project, {
|
|
53
|
+
json: options.json,
|
|
54
|
+
quiet: options.quiet,
|
|
55
|
+
skipReanalysis: options.skipReanalysis,
|
|
56
|
+
failOnStale: options.failOnStale
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const projectPath = resolve(options.project);
|
|
61
|
+
const grafemaDir = join(projectPath, '.grafema');
|
|
62
|
+
const dbPath = join(grafemaDir, 'graph.rfdb');
|
|
63
|
+
if (!existsSync(dbPath)) {
|
|
64
|
+
exitWithError('No graph database found', ['Run: grafema analyze']);
|
|
65
|
+
}
|
|
66
|
+
const backend = new RFDBServerBackend({ dbPath });
|
|
67
|
+
await backend.connect();
|
|
68
|
+
// Check graph freshness
|
|
69
|
+
const freshnessChecker = new GraphFreshnessChecker();
|
|
70
|
+
const freshness = await freshnessChecker.checkFreshness(backend);
|
|
71
|
+
if (!freshness.isFresh) {
|
|
72
|
+
if (options.failOnStale) {
|
|
73
|
+
console.error(`✗ Graph is stale: ${freshness.staleCount} module(s) changed`);
|
|
74
|
+
for (const stale of freshness.staleModules.slice(0, 5)) {
|
|
75
|
+
console.error(` ${stale.file} (${stale.reason})`);
|
|
76
|
+
}
|
|
77
|
+
if (freshness.staleModules.length > 5) {
|
|
78
|
+
console.error(` ... and ${freshness.staleModules.length - 5} more`);
|
|
79
|
+
}
|
|
80
|
+
console.error('');
|
|
81
|
+
console.error('→ Run: grafema analyze');
|
|
82
|
+
await backend.close();
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
if (!options.skipReanalysis) {
|
|
86
|
+
console.log(`Reanalyzing ${freshness.staleCount} stale module(s)...`);
|
|
87
|
+
const reanalyzer = new IncrementalReanalyzer(backend, projectPath);
|
|
88
|
+
const result = await reanalyzer.reanalyze(freshness.staleModules);
|
|
89
|
+
console.log(`Reanalyzed ${result.modulesReanalyzed} module(s) in ${result.durationMs}ms`);
|
|
90
|
+
console.log('');
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
console.warn(`Warning: ${freshness.staleCount} stale module(s) detected. Use --skip-reanalysis to suppress.`);
|
|
94
|
+
for (const stale of freshness.staleModules.slice(0, 5)) {
|
|
95
|
+
console.warn(` - ${stale.file} (${stale.reason})`);
|
|
96
|
+
}
|
|
97
|
+
if (freshness.staleModules.length > 5) {
|
|
98
|
+
console.warn(` ... and ${freshness.staleModules.length - 5} more`);
|
|
99
|
+
}
|
|
100
|
+
console.log('');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
else if (!options.quiet) {
|
|
104
|
+
console.log('Graph is fresh');
|
|
105
|
+
console.log('');
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
const guaranteeGraph = backend;
|
|
109
|
+
const manager = new GuaranteeManager(guaranteeGraph, projectPath);
|
|
110
|
+
// Load guarantees from file if specified
|
|
111
|
+
const guaranteesFile = options.file || join(grafemaDir, 'guarantees.yaml');
|
|
112
|
+
if (existsSync(guaranteesFile)) {
|
|
113
|
+
await manager.import(guaranteesFile);
|
|
114
|
+
}
|
|
115
|
+
// Get all guarantees
|
|
116
|
+
const guarantees = await manager.list();
|
|
117
|
+
if (guarantees.length === 0) {
|
|
118
|
+
console.log('No guarantees found.');
|
|
119
|
+
console.log('');
|
|
120
|
+
console.log('Create guarantees in .grafema/guarantees.yaml or use --file option.');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// Filter to specific rule if requested
|
|
124
|
+
const toCheck = rule && rule !== 'all'
|
|
125
|
+
? guarantees.filter((g) => g.id === rule || g.name === rule)
|
|
126
|
+
: guarantees;
|
|
127
|
+
if (toCheck.length === 0 && rule) {
|
|
128
|
+
const available = guarantees.map((g) => g.id).join(', ');
|
|
129
|
+
exitWithError(`Guarantee not found: ${rule}`, [
|
|
130
|
+
`Available: ${available}`
|
|
131
|
+
]);
|
|
132
|
+
}
|
|
133
|
+
// Check all matching guarantees
|
|
134
|
+
const results = await manager.checkAll();
|
|
135
|
+
// Filter results to only requested rules
|
|
136
|
+
const filteredResults = rule && rule !== 'all'
|
|
137
|
+
? {
|
|
138
|
+
...results,
|
|
139
|
+
results: results.results.filter((r) => toCheck.some((g) => g.id === r.guaranteeId)),
|
|
140
|
+
}
|
|
141
|
+
: results;
|
|
142
|
+
if (options.json) {
|
|
143
|
+
console.log(JSON.stringify(filteredResults, null, 2));
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
if (!options.quiet) {
|
|
147
|
+
console.log(`Checking ${filteredResults.results.length} guarantee(s)...`);
|
|
148
|
+
console.log('');
|
|
149
|
+
}
|
|
150
|
+
for (const result of filteredResults.results) {
|
|
151
|
+
if (options.quiet && result.passed)
|
|
152
|
+
continue;
|
|
153
|
+
const status = result.passed ? '✓' : '✗';
|
|
154
|
+
const color = result.passed ? '\x1b[32m' : '\x1b[31m';
|
|
155
|
+
const reset = '\x1b[0m';
|
|
156
|
+
console.log(`${color}${status}${reset} ${result.guaranteeId}: ${result.name}`);
|
|
157
|
+
if (!result.passed && result.violations.length > 0) {
|
|
158
|
+
console.log(` Violations (${result.violationCount}):`);
|
|
159
|
+
for (const v of result.violations.slice(0, 10)) {
|
|
160
|
+
// Prefer nodeId (semantic ID) for queryability
|
|
161
|
+
const identifier = v.nodeId || (v.file ? `${v.file}${v.line ? `:${v.line}` : ''}` : '(unknown)');
|
|
162
|
+
console.log(` - ${identifier}`);
|
|
163
|
+
if (v.name || v.type) {
|
|
164
|
+
console.log(` ${v.name || ''} (${v.type || 'unknown'})`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (result.violations.length > 10) {
|
|
168
|
+
console.log(` ... and ${result.violations.length - 10} more`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (result.error) {
|
|
172
|
+
console.log(` Error: ${result.error}`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
console.log('');
|
|
176
|
+
console.log(`Summary: ${filteredResults.passed}/${filteredResults.total} passed`);
|
|
177
|
+
if (filteredResults.failed > 0) {
|
|
178
|
+
process.exit(1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
await backend.close();
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
/**
|
|
187
|
+
* Run a built-in validator
|
|
188
|
+
*/
|
|
189
|
+
async function runBuiltInValidator(guaranteeName, projectPath, options) {
|
|
190
|
+
const resolvedPath = resolve(projectPath);
|
|
191
|
+
const grafemaDir = join(resolvedPath, '.grafema');
|
|
192
|
+
const dbPath = join(grafemaDir, 'graph.rfdb');
|
|
193
|
+
if (!existsSync(dbPath)) {
|
|
194
|
+
exitWithError('No graph database found', ['Run: grafema analyze']);
|
|
195
|
+
}
|
|
196
|
+
const backend = new RFDBServerBackend({ dbPath });
|
|
197
|
+
await backend.connect();
|
|
198
|
+
// Check graph freshness
|
|
199
|
+
const freshnessChecker = new GraphFreshnessChecker();
|
|
200
|
+
const freshness = await freshnessChecker.checkFreshness(backend);
|
|
201
|
+
if (!freshness.isFresh) {
|
|
202
|
+
if (options.failOnStale) {
|
|
203
|
+
console.error(`✗ Graph is stale: ${freshness.staleCount} module(s) changed`);
|
|
204
|
+
for (const stale of freshness.staleModules.slice(0, 5)) {
|
|
205
|
+
console.error(` ${stale.file} (${stale.reason})`);
|
|
206
|
+
}
|
|
207
|
+
if (freshness.staleModules.length > 5) {
|
|
208
|
+
console.error(` ... and ${freshness.staleModules.length - 5} more`);
|
|
209
|
+
}
|
|
210
|
+
console.error('');
|
|
211
|
+
console.error('→ Run: grafema analyze');
|
|
212
|
+
await backend.close();
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
if (!options.skipReanalysis) {
|
|
216
|
+
console.log(`Reanalyzing ${freshness.staleCount} stale module(s)...`);
|
|
217
|
+
const reanalyzer = new IncrementalReanalyzer(backend, resolvedPath);
|
|
218
|
+
const result = await reanalyzer.reanalyze(freshness.staleModules);
|
|
219
|
+
console.log(`Reanalyzed ${result.modulesReanalyzed} module(s) in ${result.durationMs}ms`);
|
|
220
|
+
console.log('');
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
console.warn(`Warning: ${freshness.staleCount} stale module(s) detected. Use --skip-reanalysis to suppress.`);
|
|
224
|
+
for (const stale of freshness.staleModules.slice(0, 5)) {
|
|
225
|
+
console.warn(` - ${stale.file} (${stale.reason})`);
|
|
226
|
+
}
|
|
227
|
+
if (freshness.staleModules.length > 5) {
|
|
228
|
+
console.warn(` ... and ${freshness.staleModules.length - 5} more`);
|
|
229
|
+
}
|
|
230
|
+
console.log('');
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
else if (!options.quiet) {
|
|
234
|
+
console.log('Graph is fresh');
|
|
235
|
+
console.log('');
|
|
236
|
+
}
|
|
237
|
+
try {
|
|
238
|
+
let validator;
|
|
239
|
+
let validatorName;
|
|
240
|
+
switch (guaranteeName) {
|
|
241
|
+
case 'node-creation':
|
|
242
|
+
validator = new NodeCreationValidator();
|
|
243
|
+
validatorName = 'NodeCreationValidator';
|
|
244
|
+
break;
|
|
245
|
+
default:
|
|
246
|
+
exitWithError(`Unknown guarantee: ${guaranteeName}`, [
|
|
247
|
+
'Use --list-guarantees to see available options'
|
|
248
|
+
]);
|
|
249
|
+
}
|
|
250
|
+
if (!options.quiet) {
|
|
251
|
+
console.log(`Running ${validatorName}...`);
|
|
252
|
+
console.log('');
|
|
253
|
+
}
|
|
254
|
+
const result = await validator.execute({
|
|
255
|
+
graph: backend,
|
|
256
|
+
projectPath: resolvedPath
|
|
257
|
+
});
|
|
258
|
+
const metadata = result.metadata;
|
|
259
|
+
if (options.json) {
|
|
260
|
+
console.log(JSON.stringify({
|
|
261
|
+
guarantee: guaranteeName,
|
|
262
|
+
passed: (metadata.summary?.totalViolations ?? 0) === 0,
|
|
263
|
+
...metadata
|
|
264
|
+
}, null, 2));
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
const violations = metadata.summary?.totalViolations ?? 0;
|
|
268
|
+
const issues = metadata.issues ?? [];
|
|
269
|
+
if (violations === 0) {
|
|
270
|
+
console.log('\x1b[32m✓\x1b[0m All checks passed');
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
console.log(`\x1b[31m✗\x1b[0m Found ${violations} violation(s):`);
|
|
274
|
+
console.log('');
|
|
275
|
+
for (const issue of issues.slice(0, 10)) {
|
|
276
|
+
const location = issue.file ? `${issue.file}${issue.line ? `:${issue.line}` : ''}` : '';
|
|
277
|
+
console.log(` \x1b[31m•\x1b[0m [${issue.type}] ${issue.message}`);
|
|
278
|
+
if (issue.suggestion && !options.quiet) {
|
|
279
|
+
console.log(` Suggestion: ${issue.suggestion}`);
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (issues.length > 10) {
|
|
283
|
+
console.log(` ... and ${issues.length - 10} more violations`);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
console.log('');
|
|
287
|
+
if (violations > 0) {
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
finally {
|
|
293
|
+
await backend.close();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage command - Show analysis coverage statistics
|
|
3
|
+
*
|
|
4
|
+
* Shows what percentage of the codebase has been analyzed:
|
|
5
|
+
* - Analyzed: Files in the graph as MODULE nodes
|
|
6
|
+
* - Unsupported: Files with extensions that no indexer handles
|
|
7
|
+
* - Unreachable: Files with supported extensions but not imported from entrypoints
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
export declare const coverageCommand: Command;
|
|
11
|
+
//# sourceMappingURL=coverage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage.d.ts","sourceRoot":"","sources":["../../src/commands/coverage.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,eAAO,MAAM,eAAe,SA6BxB,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Coverage command - Show analysis coverage statistics
|
|
3
|
+
*
|
|
4
|
+
* Shows what percentage of the codebase has been analyzed:
|
|
5
|
+
* - Analyzed: Files in the graph as MODULE nodes
|
|
6
|
+
* - Unsupported: Files with extensions that no indexer handles
|
|
7
|
+
* - Unreachable: Files with supported extensions but not imported from entrypoints
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import { resolve, join } from 'path';
|
|
11
|
+
import { existsSync } from 'fs';
|
|
12
|
+
import { RFDBServerBackend, CoverageAnalyzer } from '@grafema/core';
|
|
13
|
+
import { exitWithError } from '../utils/errorFormatter.js';
|
|
14
|
+
export const coverageCommand = new Command('coverage')
|
|
15
|
+
.description('Show analysis coverage statistics')
|
|
16
|
+
.option('-p, --project <path>', 'Project path', '.')
|
|
17
|
+
.option('-j, --json', 'Output as JSON')
|
|
18
|
+
.option('-v, --verbose', 'Show detailed file lists')
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
const projectPath = resolve(options.project);
|
|
21
|
+
const grafemaDir = join(projectPath, '.grafema');
|
|
22
|
+
const dbPath = join(grafemaDir, 'graph.rfdb');
|
|
23
|
+
if (!existsSync(dbPath)) {
|
|
24
|
+
exitWithError('No graph database found', ['Run: grafema analyze']);
|
|
25
|
+
}
|
|
26
|
+
const backend = new RFDBServerBackend({ dbPath });
|
|
27
|
+
await backend.connect();
|
|
28
|
+
try {
|
|
29
|
+
const analyzer = new CoverageAnalyzer(backend, projectPath);
|
|
30
|
+
const result = await analyzer.analyze();
|
|
31
|
+
if (options.json) {
|
|
32
|
+
console.log(JSON.stringify(result, null, 2));
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
printCoverageReport(result, options.verbose ?? false);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
await backend.close();
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* Print human-readable coverage report
|
|
44
|
+
*/
|
|
45
|
+
function printCoverageReport(result, verbose) {
|
|
46
|
+
console.log('');
|
|
47
|
+
console.log('Analysis Coverage');
|
|
48
|
+
console.log('=================');
|
|
49
|
+
console.log('');
|
|
50
|
+
// Summary
|
|
51
|
+
console.log(`Project: ${result.projectPath}`);
|
|
52
|
+
console.log('');
|
|
53
|
+
// Main statistics
|
|
54
|
+
console.log('File breakdown:');
|
|
55
|
+
console.log(` Total files: ${result.total}`);
|
|
56
|
+
console.log(` Analyzed: ${result.analyzed.count} (${result.percentages.analyzed}%) - in graph`);
|
|
57
|
+
console.log(` Unsupported: ${result.unsupported.count} (${result.percentages.unsupported}%) - no indexer available`);
|
|
58
|
+
console.log(` Unreachable: ${result.unreachable.count} (${result.percentages.unreachable}%) - not imported from entrypoints`);
|
|
59
|
+
// Unsupported files breakdown
|
|
60
|
+
if (result.unsupported.count > 0) {
|
|
61
|
+
console.log('');
|
|
62
|
+
console.log('Unsupported files by extension:');
|
|
63
|
+
const sortedExtensions = Object.entries(result.unsupported.byExtension)
|
|
64
|
+
.sort((a, b) => b[1].length - a[1].length);
|
|
65
|
+
for (const [ext, files] of sortedExtensions) {
|
|
66
|
+
console.log(` ${ext}: ${files.length} files`);
|
|
67
|
+
if (verbose) {
|
|
68
|
+
for (const file of files.slice(0, 10)) {
|
|
69
|
+
console.log(` - ${file}`);
|
|
70
|
+
}
|
|
71
|
+
if (files.length > 10) {
|
|
72
|
+
console.log(` ... and ${files.length - 10} more`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Unreachable files breakdown
|
|
78
|
+
if (result.unreachable.count > 0) {
|
|
79
|
+
console.log('');
|
|
80
|
+
console.log('Unreachable source files:');
|
|
81
|
+
const sortedExtensions = Object.entries(result.unreachable.byExtension)
|
|
82
|
+
.sort((a, b) => b[1].length - a[1].length);
|
|
83
|
+
for (const [ext, files] of sortedExtensions) {
|
|
84
|
+
console.log(` ${ext}: ${files.length} files - not imported from entrypoints`);
|
|
85
|
+
if (verbose) {
|
|
86
|
+
for (const file of files.slice(0, 10)) {
|
|
87
|
+
console.log(` - ${file}`);
|
|
88
|
+
}
|
|
89
|
+
if (files.length > 10) {
|
|
90
|
+
console.log(` ... and ${files.length - 10} more`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
console.log('');
|
|
96
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explore.d.ts","sourceRoot":"","sources":["../../src/commands/explore.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA2/BpC,eAAO,MAAM,cAAc,SAgCvB,CAAC"}
|