docstodev 1.0.0 → 1.0.2

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/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. Gestion de la Langue ---
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
- const rl = readline.createInterface({ input, output });
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: { start: "🚀 Démarrage de l'analyse approfondie...", success: "✨ Documentation générée avec succès dans /docs !" },
45
- en: { start: "🚀 Starting deep analysis...", success: "✨ Documentation successfully generated in /docs!" }
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${messages.start} [${lang.toUpperCase()}]\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
- // --- 3. Exécution du Moteur (runCommand) ---
52
- // Analyse statique + MakazouIA + Export HTML
53
- const fileCount = await runCommand(lang);
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
- console.log(`\n${messages.success}`);
59
- console.log(`📂 Dossier : ${process.cwd()}${path.sep}docs\n`);
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
- const errorMsg = lang === "fr"
63
- ? "Une erreur est survenue lors de l'analyse :"
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);