docstodev 1.0.0 → 1.0.3
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/package.json +2 -2
- package/src/ai/analyzer.ts +6 -2
- package/src/analyzers/languageAnalyzer.ts +580 -0
- package/src/cache/cacheManager.ts +179 -0
- package/src/cli/index.ts +307 -23
- package/src/commands/generateSummary.ts +129 -39
- package/src/commands/run.ts +312 -75
- package/src/exporters/html.ts +604 -106
- package/.env +0 -1
- package/dist/ai/analyzer.d.ts +0 -3
- package/dist/ai/analyzer.d.ts.map +0 -1
- package/dist/ai/analyzer.js +0 -42
- package/dist/ai/analyzer.js.map +0 -1
- package/dist/cli/index.d.ts +0 -3
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js +0 -59
- package/dist/cli/index.js.map +0 -1
- package/dist/commands/classify.d.ts +0 -2
- package/dist/commands/classify.d.ts.map +0 -1
- package/dist/commands/classify.js +0 -37
- package/dist/commands/classify.js.map +0 -1
- package/dist/commands/generateSummary.d.ts +0 -5
- package/dist/commands/generateSummary.d.ts.map +0 -1
- package/dist/commands/generateSummary.js +0 -54
- package/dist/commands/generateSummary.js.map +0 -1
- package/dist/commands/run.d.ts +0 -2
- package/dist/commands/run.d.ts.map +0 -1
- package/dist/commands/run.js +0 -142
- package/dist/commands/run.js.map +0 -1
- package/dist/exporters/html.d.ts +0 -2
- package/dist/exporters/html.d.ts.map +0 -1
- package/dist/exporters/html.js +0 -148
- package/dist/exporters/html.js.map +0 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -2
- package/dist/index.js.map +0 -1
- package/docs/docs-to-dev.md +0 -111
- package/docs/report.html +0 -90
- package/docs/report.pdf +0 -0
- package/docs/summary.md +0 -16
- package/src/commands/classify.ts +0 -40
- package/src/index.ts +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// Emplacement : M:\workspace\extensions\docstodev\src\cache\cacheManager.ts
|
|
2
|
+
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { readFileSync, writeFileSync, existsSync, statSync, mkdirSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
|
|
7
|
+
export interface CacheEntry {
|
|
8
|
+
hash: string;
|
|
9
|
+
timestamp: number;
|
|
10
|
+
analysis: any;
|
|
11
|
+
metadata: {
|
|
12
|
+
lines: number;
|
|
13
|
+
size: number;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CacheManifest {
|
|
18
|
+
version: string;
|
|
19
|
+
files: Map<string, CacheEntry>;
|
|
20
|
+
lastUpdate: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class CacheManager {
|
|
24
|
+
private cacheDir: string;
|
|
25
|
+
private manifestPath: string;
|
|
26
|
+
private manifest: CacheManifest;
|
|
27
|
+
private readonly CACHE_VERSION = "1.0.0";
|
|
28
|
+
|
|
29
|
+
constructor(projectRoot: string) {
|
|
30
|
+
this.cacheDir = path.join(projectRoot, ".docstodev", "cache");
|
|
31
|
+
this.manifestPath = path.join(this.cacheDir, "manifest.json");
|
|
32
|
+
|
|
33
|
+
if (!existsSync(this.cacheDir)) {
|
|
34
|
+
mkdirSync(this.cacheDir, { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
this.manifest = this.loadManifest();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private loadManifest(): CacheManifest {
|
|
41
|
+
if (existsSync(this.manifestPath)) {
|
|
42
|
+
try {
|
|
43
|
+
const data = JSON.parse(readFileSync(this.manifestPath, "utf-8"));
|
|
44
|
+
|
|
45
|
+
// Vérifier la version du cache
|
|
46
|
+
if (data.version !== this.CACHE_VERSION) {
|
|
47
|
+
console.log("⚠️ Cache version mismatch, clearing cache...");
|
|
48
|
+
return this.createNewManifest();
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Reconstituer la Map depuis l'objet
|
|
52
|
+
return {
|
|
53
|
+
version: data.version,
|
|
54
|
+
files: new Map(Object.entries(data.files || {})),
|
|
55
|
+
lastUpdate: data.lastUpdate
|
|
56
|
+
};
|
|
57
|
+
} catch (e) {
|
|
58
|
+
console.error("⚠️ Failed to load cache manifest:", e);
|
|
59
|
+
return this.createNewManifest();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return this.createNewManifest();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private createNewManifest(): CacheManifest {
|
|
66
|
+
return {
|
|
67
|
+
version: this.CACHE_VERSION,
|
|
68
|
+
files: new Map(),
|
|
69
|
+
lastUpdate: Date.now()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
private saveManifest(): void {
|
|
74
|
+
try {
|
|
75
|
+
const data = {
|
|
76
|
+
version: this.manifest.version,
|
|
77
|
+
files: Object.fromEntries(this.manifest.files),
|
|
78
|
+
lastUpdate: this.manifest.lastUpdate
|
|
79
|
+
};
|
|
80
|
+
writeFileSync(this.manifestPath, JSON.stringify(data, null, 2));
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.error("⚠️ Failed to save cache manifest:", e);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
private computeHash(filePath: string, content: string): string {
|
|
87
|
+
const stats = statSync(filePath);
|
|
88
|
+
const hashContent = `${content}|${stats.mtime.getTime()}|${stats.size}`;
|
|
89
|
+
return createHash("sha256").update(hashContent).digest("hex");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public isCached(filePath: string, content: string): boolean {
|
|
93
|
+
const entry = this.manifest.files.get(filePath);
|
|
94
|
+
if (!entry) return false;
|
|
95
|
+
|
|
96
|
+
const currentHash = this.computeHash(filePath, content);
|
|
97
|
+
return entry.hash === currentHash;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public get(filePath: string): CacheEntry | null {
|
|
101
|
+
return this.manifest.files.get(filePath) || null;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public set(filePath: string, content: string, analysis: any): void {
|
|
105
|
+
const stats = statSync(filePath);
|
|
106
|
+
const hash = this.computeHash(filePath, content);
|
|
107
|
+
|
|
108
|
+
const entry: CacheEntry = {
|
|
109
|
+
hash,
|
|
110
|
+
timestamp: Date.now(),
|
|
111
|
+
analysis,
|
|
112
|
+
metadata: {
|
|
113
|
+
lines: content.split(/\r?\n/).length,
|
|
114
|
+
size: stats.size
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
this.manifest.files.set(filePath, entry);
|
|
119
|
+
this.manifest.lastUpdate = Date.now();
|
|
120
|
+
this.saveManifest();
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
public invalidate(filePath: string): void {
|
|
124
|
+
this.manifest.files.delete(filePath);
|
|
125
|
+
this.saveManifest();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public invalidateAll(): void {
|
|
129
|
+
this.manifest = this.createNewManifest();
|
|
130
|
+
this.saveManifest();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
public getStats(): { total: number; size: number; oldestEntry: number } {
|
|
134
|
+
const entries = Array.from(this.manifest.files.values());
|
|
135
|
+
return {
|
|
136
|
+
total: entries.length,
|
|
137
|
+
size: entries.reduce((sum, e) => sum + e.metadata.size, 0),
|
|
138
|
+
oldestEntry: Math.min(...entries.map(e => e.timestamp), Date.now())
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public pruneOldEntries(maxAgeMs: number = 7 * 24 * 60 * 60 * 1000): number {
|
|
143
|
+
const now = Date.now();
|
|
144
|
+
let pruned = 0;
|
|
145
|
+
|
|
146
|
+
for (const [filePath, entry] of this.manifest.files.entries()) {
|
|
147
|
+
if (now - entry.timestamp > maxAgeMs) {
|
|
148
|
+
this.manifest.files.delete(filePath);
|
|
149
|
+
pruned++;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (pruned > 0) {
|
|
154
|
+
this.saveManifest();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return pruned;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public getModifiedFiles(files: string[]): string[] {
|
|
161
|
+
const modified: string[] = [];
|
|
162
|
+
|
|
163
|
+
for (const file of files) {
|
|
164
|
+
if (!existsSync(file)) continue;
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const content = readFileSync(file, "utf-8");
|
|
168
|
+
if (!this.isCached(file, content)) {
|
|
169
|
+
modified.push(file);
|
|
170
|
+
}
|
|
171
|
+
} catch (e) {
|
|
172
|
+
// Si erreur de lecture, considérer comme modifié
|
|
173
|
+
modified.push(file);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return modified;
|
|
178
|
+
}
|
|
179
|
+
}
|
package/src/cli/index.ts
CHANGED
|
@@ -11,6 +11,175 @@ import path from "node:path";
|
|
|
11
11
|
|
|
12
12
|
const program = new Command();
|
|
13
13
|
|
|
14
|
+
// Spinner pour les effets de chargement
|
|
15
|
+
class Spinner {
|
|
16
|
+
private frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
17
|
+
private currentFrame = 0;
|
|
18
|
+
private interval: NodeJS.Timeout | null = null;
|
|
19
|
+
private message = "";
|
|
20
|
+
|
|
21
|
+
start(message: string): void {
|
|
22
|
+
this.message = message;
|
|
23
|
+
this.currentFrame = 0;
|
|
24
|
+
|
|
25
|
+
// Cacher le curseur
|
|
26
|
+
process.stdout.write("\x1B[?25l");
|
|
27
|
+
|
|
28
|
+
this.interval = setInterval(() => {
|
|
29
|
+
const frame = this.frames[this.currentFrame];
|
|
30
|
+
process.stdout.write(`\r${frame} ${this.message}`);
|
|
31
|
+
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
|
|
32
|
+
}, 80);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
update(message: string): void {
|
|
36
|
+
this.message = message;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
succeed(message: string): void {
|
|
40
|
+
this.stop();
|
|
41
|
+
console.log(`✓ ${message}`);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
fail(message: string): void {
|
|
45
|
+
this.stop();
|
|
46
|
+
console.log(`✗ ${message}`);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
stop(): void {
|
|
50
|
+
if (this.interval) {
|
|
51
|
+
clearInterval(this.interval);
|
|
52
|
+
this.interval = null;
|
|
53
|
+
}
|
|
54
|
+
// Effacer la ligne actuelle
|
|
55
|
+
if (process.stdout.clearLine) {
|
|
56
|
+
process.stdout.clearLine(0);
|
|
57
|
+
process.stdout.cursorTo(0);
|
|
58
|
+
}
|
|
59
|
+
// Réafficher le curseur
|
|
60
|
+
process.stdout.write("\x1B[?25h");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Barre de progression
|
|
65
|
+
class ProgressBar {
|
|
66
|
+
private total: number;
|
|
67
|
+
private current = 0;
|
|
68
|
+
private barLength = 30;
|
|
69
|
+
|
|
70
|
+
constructor(total: number) {
|
|
71
|
+
this.total = total;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
update(current: number, message?: string): void {
|
|
75
|
+
this.current = current;
|
|
76
|
+
const percentage = Math.floor((this.current / this.total) * 100);
|
|
77
|
+
const filledLength = Math.floor((this.current / this.total) * this.barLength);
|
|
78
|
+
const bar = "█".repeat(filledLength) + "░".repeat(this.barLength - filledLength);
|
|
79
|
+
|
|
80
|
+
const msg = message ? ` ${message}` : "";
|
|
81
|
+
const output = `\r[${bar}] ${percentage}%${msg}`;
|
|
82
|
+
process.stdout.write(output);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
complete(message: string): void {
|
|
86
|
+
this.update(this.total);
|
|
87
|
+
console.log(`\n✓ ${message}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Animation de texte
|
|
92
|
+
function typeWriter(text: string, delay = 30): Promise<void> {
|
|
93
|
+
return new Promise((resolve) => {
|
|
94
|
+
let i = 0;
|
|
95
|
+
const chars = text.split('');
|
|
96
|
+
const interval = setInterval(() => {
|
|
97
|
+
if (i < chars.length) {
|
|
98
|
+
process.stdout.write(chars[i] || '');
|
|
99
|
+
i++;
|
|
100
|
+
} else {
|
|
101
|
+
clearInterval(interval);
|
|
102
|
+
process.stdout.write("\n");
|
|
103
|
+
resolve();
|
|
104
|
+
}
|
|
105
|
+
}, delay);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Bannière animée
|
|
110
|
+
async function showBanner(lang: "fr" | "en"): Promise<void> {
|
|
111
|
+
const banner = `
|
|
112
|
+
╔═══════════════════════════════════════════════════════╗
|
|
113
|
+
║ ║
|
|
114
|
+
║ ██████╗ ██████╗ ██████╗███████╗████████╗ ║
|
|
115
|
+
║ ██╔══██╗██╔═══██╗██╔════╝██╔════╝╚══██╔══╝ ║
|
|
116
|
+
║ ██║ ██║██║ ██║██║ ███████╗ ██║ ║
|
|
117
|
+
║ ██║ ██║██║ ██║██║ ╚════██║ ██║ ║
|
|
118
|
+
║ ██████╔╝╚██████╔╝╚██████╗███████║ ██║ ║
|
|
119
|
+
║ ╚═════╝ ╚═════╝ ╚═════╝╚══════╝ ╚═╝ DEV ║
|
|
120
|
+
║ ║
|
|
121
|
+
║ 📚 Analyse Technique & Documentation ║
|
|
122
|
+
║ Intelligente ║
|
|
123
|
+
║ ║
|
|
124
|
+
╚═══════════════════════════════════════════════════════╝
|
|
125
|
+
`;
|
|
126
|
+
|
|
127
|
+
console.clear();
|
|
128
|
+
const coloredBanner = "\x1b[36m" + banner + "\x1b[0m";
|
|
129
|
+
console.log(coloredBanner);
|
|
130
|
+
|
|
131
|
+
const tagline = lang === "fr"
|
|
132
|
+
? " Transformez votre code en documentation professionnelle"
|
|
133
|
+
: " Transform your code into professional documentation";
|
|
134
|
+
|
|
135
|
+
await typeWriter(tagline, 20);
|
|
136
|
+
console.log("");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Sélection de langue interactive
|
|
140
|
+
async function selectLanguage(): Promise<"fr" | "en"> {
|
|
141
|
+
console.log("\n🌍 Language Selection / Sélection de la langue\n");
|
|
142
|
+
console.log(" [1] 🇫🇷 Français");
|
|
143
|
+
console.log(" [2] 🇬🇧 English\n");
|
|
144
|
+
|
|
145
|
+
const rl = readline.createInterface({ input, output });
|
|
146
|
+
|
|
147
|
+
let answer = "";
|
|
148
|
+
while (!["1", "2", "fr", "en"].includes(answer.toLowerCase())) {
|
|
149
|
+
answer = await rl.question("👉 Votre choix / Your choice (1/2 or fr/en): ");
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
rl.close();
|
|
153
|
+
|
|
154
|
+
if (answer === "1" || answer.toLowerCase() === "fr") {
|
|
155
|
+
return "fr";
|
|
156
|
+
}
|
|
157
|
+
return "en";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Effet de transition
|
|
161
|
+
function showTransition(message: string): Promise<void> {
|
|
162
|
+
return new Promise((resolve) => {
|
|
163
|
+
const dots = [" ", ". ", ".. ", "..."];
|
|
164
|
+
let i = 0;
|
|
165
|
+
|
|
166
|
+
const interval = setInterval(() => {
|
|
167
|
+
const output = `\r${message}${dots[i % dots.length]}`;
|
|
168
|
+
process.stdout.write(output);
|
|
169
|
+
i++;
|
|
170
|
+
|
|
171
|
+
if (i >= 8) {
|
|
172
|
+
clearInterval(interval);
|
|
173
|
+
if (process.stdout.clearLine) {
|
|
174
|
+
process.stdout.clearLine(0);
|
|
175
|
+
process.stdout.cursorTo(0);
|
|
176
|
+
}
|
|
177
|
+
resolve();
|
|
178
|
+
}
|
|
179
|
+
}, 200);
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
14
183
|
// Configuration de base du CLI
|
|
15
184
|
program
|
|
16
185
|
.name("docs-to-dev")
|
|
@@ -21,50 +190,165 @@ program
|
|
|
21
190
|
.command("run")
|
|
22
191
|
.description("Lancer le cycle complet d'analyse et de documentation")
|
|
23
192
|
.option("-l, --lang <lang>", "Langue forcée du rapport (fr | en)")
|
|
193
|
+
.option("--no-animation", "Désactiver les animations")
|
|
194
|
+
.option("-i, --incremental", "Mode incrémental (analyser uniquement les fichiers modifiés)")
|
|
195
|
+
.option("--clear-cache", "Vider le cache avant l'analyse")
|
|
24
196
|
.action(async (options) => {
|
|
197
|
+
const useAnimation = options.animation !== false;
|
|
25
198
|
let lang: "fr" | "en";
|
|
26
199
|
|
|
27
|
-
// --- 1.
|
|
200
|
+
// --- 1. Bannière et Sélection de Langue ---
|
|
201
|
+
if (useAnimation) {
|
|
202
|
+
await showBanner(options.lang || "fr");
|
|
203
|
+
}
|
|
204
|
+
|
|
28
205
|
if (options.lang === "fr" || options.lang === "en") {
|
|
29
206
|
lang = options.lang;
|
|
30
207
|
} else {
|
|
31
|
-
|
|
32
|
-
console.log("\n🌍 Bienvenue dans DocsToDev / Welcome to DocsToDev");
|
|
33
|
-
|
|
34
|
-
let answer = "";
|
|
35
|
-
while (!["fr", "en"].includes(answer.toLowerCase())) {
|
|
36
|
-
answer = await rl.question("👉 Choisissez votre langue / Choose your language (fr/en) : ");
|
|
37
|
-
}
|
|
38
|
-
rl.close();
|
|
39
|
-
lang = answer.toLowerCase() as "fr" | "en";
|
|
208
|
+
lang = await selectLanguage();
|
|
40
209
|
}
|
|
41
210
|
|
|
42
|
-
// --- 2. Interface Utilisateur (Console) ---
|
|
43
211
|
const messages = {
|
|
44
|
-
fr: {
|
|
45
|
-
|
|
212
|
+
fr: {
|
|
213
|
+
initializing: "Initialisation de l'environnement",
|
|
214
|
+
scanning: "Scan des fichiers du projet",
|
|
215
|
+
analyzing: "Analyse approfondie du code",
|
|
216
|
+
generating: "Génération de l'analyse IA",
|
|
217
|
+
building: "Construction du rapport",
|
|
218
|
+
exporting: "Export HTML avec graphiques",
|
|
219
|
+
creating: "Création du PDF",
|
|
220
|
+
finalizing: "Finalisation",
|
|
221
|
+
success: "Documentation générée avec succès !",
|
|
222
|
+
error: "Une erreur est survenue lors de l'analyse"
|
|
223
|
+
},
|
|
224
|
+
en: {
|
|
225
|
+
initializing: "Initializing environment",
|
|
226
|
+
scanning: "Scanning project files",
|
|
227
|
+
analyzing: "Deep code analysis",
|
|
228
|
+
generating: "Generating AI insights",
|
|
229
|
+
building: "Building report",
|
|
230
|
+
exporting: "Exporting HTML with graphs",
|
|
231
|
+
creating: "Creating PDF",
|
|
232
|
+
finalizing: "Finalizing",
|
|
233
|
+
success: "Documentation generated successfully!",
|
|
234
|
+
error: "An error occurred during analysis"
|
|
235
|
+
}
|
|
46
236
|
}[lang];
|
|
47
237
|
|
|
48
|
-
console.log(`\n
|
|
238
|
+
console.log(`\n\x1b[1m${lang === "fr" ? "🚀 Démarrage de l'analyse" : "🚀 Starting analysis"}\x1b[0m\n`);
|
|
49
239
|
|
|
50
240
|
try {
|
|
51
|
-
// ---
|
|
52
|
-
|
|
53
|
-
|
|
241
|
+
// --- 2. Phase d'initialisation ---
|
|
242
|
+
if (useAnimation) {
|
|
243
|
+
const spinner = new Spinner();
|
|
244
|
+
spinner.start(messages.initializing);
|
|
245
|
+
await new Promise(resolve => setTimeout(resolve, 800));
|
|
246
|
+
spinner.succeed(messages.initializing);
|
|
247
|
+
await new Promise(resolve => setTimeout(resolve, 200));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// --- 3. Exécution du Moteur avec feedback ---
|
|
251
|
+
console.log("");
|
|
252
|
+
const fileCount = await runCommand(lang, {
|
|
253
|
+
incremental: options.incremental,
|
|
254
|
+
clearCache: options.clearCache
|
|
255
|
+
});
|
|
54
256
|
|
|
55
257
|
// --- 4. Génération du Résumé ---
|
|
258
|
+
if (useAnimation) {
|
|
259
|
+
await showTransition(messages.finalizing);
|
|
260
|
+
}
|
|
261
|
+
|
|
56
262
|
generateSummary("docs", fileCount || 0, lang);
|
|
57
263
|
|
|
58
|
-
|
|
59
|
-
console.log(
|
|
264
|
+
// --- 5. Message de succès avec animation ---
|
|
265
|
+
console.log("");
|
|
266
|
+
if (useAnimation) {
|
|
267
|
+
await new Promise(resolve => setTimeout(resolve, 300));
|
|
268
|
+
console.log("\n\x1b[32m" + "═".repeat(60) + "\x1b[0m");
|
|
269
|
+
console.log(`\x1b[32m✨ ${messages.success}\x1b[0m`);
|
|
270
|
+
console.log("\x1b[32m" + "═".repeat(60) + "\x1b[0m\n");
|
|
271
|
+
} else {
|
|
272
|
+
console.log(`\n✨ ${messages.success}\n`);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// --- 6. Informations finales ---
|
|
276
|
+
const outputDir = path.join(process.cwd(), "docs");
|
|
277
|
+
console.log(`📂 ${lang === "fr" ? "Dossier de sortie" : "Output folder"}: \x1b[36m${outputDir}\x1b[0m`);
|
|
278
|
+
console.log(`📊 ${lang === "fr" ? "Fichiers analysés" : "Files analyzed"}: \x1b[33m${fileCount}\x1b[0m`);
|
|
279
|
+
console.log(`\n📄 ${lang === "fr" ? "Fichiers générés" : "Generated files"}:`);
|
|
280
|
+
console.log(` • docs-to-dev.md`);
|
|
281
|
+
console.log(` • report.html`);
|
|
282
|
+
console.log(` • report.pdf`);
|
|
283
|
+
console.log(` • summary.json\n`);
|
|
60
284
|
|
|
285
|
+
if (lang === "fr") {
|
|
286
|
+
console.log("💡 \x1b[2mOuvrez report.html dans votre navigateur pour une visualisation interactive\x1b[0m\n");
|
|
287
|
+
} else {
|
|
288
|
+
console.log("💡 \x1b[2mOpen report.html in your browser for an interactive view\x1b[0m\n");
|
|
289
|
+
}
|
|
290
|
+
|
|
61
291
|
} catch (error) {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
: "❌ An error occurred during analysis:";
|
|
65
|
-
console.error(errorMsg, error);
|
|
292
|
+
console.log("");
|
|
293
|
+
console.error(`\n\x1b[31m❌ ${messages.error}:\x1b[0m`, error);
|
|
66
294
|
process.exit(1);
|
|
67
295
|
}
|
|
68
296
|
});
|
|
69
297
|
|
|
298
|
+
// Commande info
|
|
299
|
+
program
|
|
300
|
+
.command("info")
|
|
301
|
+
.description("Afficher les informations sur DocsToDev")
|
|
302
|
+
.action(() => {
|
|
303
|
+
console.log("\n\x1b[36m╔═══════════════════════════════════════╗\x1b[0m");
|
|
304
|
+
console.log("\x1b[36m║ DocsToDev - Info ║\x1b[0m");
|
|
305
|
+
console.log("\x1b[36m╚═══════════════════════════════════════╝\x1b[0m\n");
|
|
306
|
+
console.log("📦 Version: 1.0.0");
|
|
307
|
+
console.log("👨💻 Auteur: Makazou");
|
|
308
|
+
console.log("📝 Description: Outil d'analyse de code et génération de documentation");
|
|
309
|
+
console.log("🔗 Repository: https://github.com/votre-repo/docstodev");
|
|
310
|
+
console.log("\n✨ Fonctionnalités:");
|
|
311
|
+
console.log(" • Analyse statique multi-langages (TS/JS, Python, Java, C#, Go, Rust)");
|
|
312
|
+
console.log(" • Génération de graphiques de dépendances");
|
|
313
|
+
console.log(" • Synthèse intelligente par IA");
|
|
314
|
+
console.log(" • Export multi-formats (MD, HTML, PDF)");
|
|
315
|
+
console.log(" • Support i18n (FR/EN)");
|
|
316
|
+
console.log(" • Cache intelligent avec mode incrémental");
|
|
317
|
+
console.log("\n📚 Langages supportés:");
|
|
318
|
+
console.log(" • TypeScript/JavaScript (.ts, .js, .tsx, .jsx, .mjs, .cjs)");
|
|
319
|
+
console.log(" • Python (.py)");
|
|
320
|
+
console.log(" • Java (.java)");
|
|
321
|
+
console.log(" • C# (.cs)");
|
|
322
|
+
console.log(" • Go (.go)");
|
|
323
|
+
console.log(" • Rust (.rs)\n");
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
// Commande cache
|
|
327
|
+
program
|
|
328
|
+
.command("cache")
|
|
329
|
+
.description("Gérer le cache des analyses")
|
|
330
|
+
.option("--clear", "Vider complètement le cache")
|
|
331
|
+
.option("--stats", "Afficher les statistiques du cache")
|
|
332
|
+
.option("--prune", "Supprimer les entrées de plus de 7 jours")
|
|
333
|
+
.action((options) => {
|
|
334
|
+
const { CacheManager } = require("../cache/cacheManager.js");
|
|
335
|
+
const cache = new CacheManager(process.cwd());
|
|
336
|
+
|
|
337
|
+
if (options.clear) {
|
|
338
|
+
cache.invalidateAll();
|
|
339
|
+
console.log("\n✓ Cache vidé avec succès\n");
|
|
340
|
+
} else if (options.prune) {
|
|
341
|
+
const pruned = cache.pruneOldEntries();
|
|
342
|
+
console.log(`\n✓ ${pruned} entrées obsolètes supprimées\n`);
|
|
343
|
+
} else if (options.stats) {
|
|
344
|
+
const stats = cache.getStats();
|
|
345
|
+
console.log("\n📊 Statistiques du cache:");
|
|
346
|
+
console.log(` • Entrées totales: ${stats.total}`);
|
|
347
|
+
console.log(` • Taille: ${Math.round(stats.size / 1024)} KB`);
|
|
348
|
+
console.log(` • Entrée la plus ancienne: ${new Date(stats.oldestEntry).toLocaleString()}\n`);
|
|
349
|
+
} else {
|
|
350
|
+
console.log("\n⚠️ Spécifiez une option: --clear, --stats, ou --prune\n");
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
|
|
70
354
|
program.parse(process.argv);
|