docstodev 1.0.3 → 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/dist/ai/analyzer.d.ts +3 -0
- package/dist/ai/analyzer.d.ts.map +1 -0
- package/dist/ai/analyzer.js +45 -0
- package/dist/ai/analyzer.js.map +1 -0
- package/dist/analyzers/languageAnalyzer.d.ts +20 -0
- package/dist/analyzers/languageAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/languageAnalyzer.js +513 -0
- package/dist/analyzers/languageAnalyzer.js.map +1 -0
- package/dist/cache/cacheManager.d.ts +38 -0
- package/dist/cache/cacheManager.d.ts.map +1 -0
- package/dist/cache/cacheManager.js +141 -0
- package/dist/cache/cacheManager.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +316 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/generateSummary.d.ts +18 -0
- package/dist/commands/generateSummary.d.ts.map +1 -0
- package/dist/commands/generateSummary.js +116 -0
- package/dist/commands/generateSummary.js.map +1 -0
- package/dist/commands/run.d.ts +5 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +326 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/exporters/html.d.ts +6 -0
- package/dist/exporters/html.d.ts.map +1 -0
- package/dist/exporters/html.js +596 -0
- package/dist/exporters/html.js.map +1 -0
- package/docs/docs-to-dev.md +240 -0
- package/docs/report.html +633 -0
- package/docs/report.pdf +0 -0
- package/docs/summary.md +16 -0
- package/package.json +1 -1
- package/src/ai/analyzer.ts +258 -19
- package/src/commands/run.ts +149 -83
- package/src/exporters/html.ts +302 -48
package/src/ai/analyzer.ts
CHANGED
|
@@ -1,28 +1,66 @@
|
|
|
1
1
|
// Emplacement absolu : M:\workspace\extensions\docstodev\src\ai\analyzer.ts
|
|
2
2
|
|
|
3
|
-
import "dotenv/config";
|
|
3
|
+
import "dotenv/config";
|
|
4
4
|
|
|
5
|
-
export
|
|
5
|
+
export interface AIAnalysisOptions {
|
|
6
|
+
language?: "fr" | "en";
|
|
7
|
+
includeDesignSystem?: boolean;
|
|
8
|
+
includeRisks?: boolean;
|
|
9
|
+
includeRecommendations?: boolean;
|
|
10
|
+
detailLevel?: "brief" | "detailed" | "comprehensive";
|
|
11
|
+
focusAreas?: ("architecture" | "security" | "performance" | "maintainability")[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface AIAnalysisResult {
|
|
15
|
+
summary: string;
|
|
16
|
+
projectGoal?: string;
|
|
17
|
+
designSystem?: {
|
|
18
|
+
primaryColors: string[];
|
|
19
|
+
typography?: string;
|
|
20
|
+
componentPatterns?: string[];
|
|
21
|
+
};
|
|
22
|
+
risks?: Array<{ level: "low" | "medium" | "high"; description: string }>;
|
|
23
|
+
recommendations?: string[];
|
|
24
|
+
rawAnalysis: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function askAI(
|
|
28
|
+
technicalContext: string,
|
|
29
|
+
options: AIAnalysisOptions = {}
|
|
30
|
+
): Promise<string> {
|
|
31
|
+
const result = await askAIDetailed(technicalContext, options);
|
|
32
|
+
return result.rawAnalysis;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export async function askAIDetailed(
|
|
36
|
+
technicalContext: string,
|
|
37
|
+
options: AIAnalysisOptions = {}
|
|
38
|
+
): Promise<AIAnalysisResult> {
|
|
39
|
+
const {
|
|
40
|
+
language = "fr",
|
|
41
|
+
includeDesignSystem = true,
|
|
42
|
+
includeRisks = true,
|
|
43
|
+
includeRecommendations = true,
|
|
44
|
+
detailLevel = "detailed",
|
|
45
|
+
focusAreas = ["architecture", "maintainability"]
|
|
46
|
+
} = options;
|
|
6
47
|
|
|
7
|
-
// clé par défaut gratuite
|
|
8
48
|
const GROQ_API_KEY = process.env.GROQ_API_KEY || "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";
|
|
9
49
|
|
|
10
50
|
if (!GROQ_API_KEY) {
|
|
11
|
-
return
|
|
51
|
+
return {
|
|
52
|
+
summary: "⚠️ Erreur : Clé API Groq manquante",
|
|
53
|
+
rawAnalysis: "⚠️ Erreur : Clé API Groq manquante dans le fichier .env"
|
|
54
|
+
};
|
|
12
55
|
}
|
|
13
56
|
|
|
14
|
-
const systemPrompt =
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- Soyez pro, mais gardez votre touche amicale et votre pointe d'humour du Congo-Brazzaville.
|
|
22
|
-
- mentionnez les imports, technique ( "il y a une fonction X"), expliquez le BUT du fichier.
|
|
23
|
-
- selon le nombre d'occurance précisez les couleurs qui reviennen souvent eu suggérez un design systèm , pallette de couleur.
|
|
24
|
-
- donnez une très bref description du but de l'ensemble du projet.
|
|
25
|
-
`;
|
|
57
|
+
const systemPrompt = buildSystemPrompt(language, {
|
|
58
|
+
includeDesignSystem,
|
|
59
|
+
includeRisks,
|
|
60
|
+
includeRecommendations,
|
|
61
|
+
detailLevel,
|
|
62
|
+
focusAreas
|
|
63
|
+
});
|
|
26
64
|
|
|
27
65
|
try {
|
|
28
66
|
const resp = await fetch("https://api.groq.com/openai/v1/chat/completions", {
|
|
@@ -35,16 +73,217 @@ Instructions :
|
|
|
35
73
|
model: "llama-3.3-70b-versatile",
|
|
36
74
|
messages: [
|
|
37
75
|
{ role: "system", content: systemPrompt },
|
|
38
|
-
{
|
|
76
|
+
{
|
|
77
|
+
role: "user",
|
|
78
|
+
content: language === "fr"
|
|
79
|
+
? `Voici les données techniques du projet :\n\n${technicalContext}`
|
|
80
|
+
: `Here is the technical project data:\n\n${technicalContext}`
|
|
81
|
+
}
|
|
39
82
|
],
|
|
40
83
|
temperature: 0.7,
|
|
84
|
+
max_tokens: detailLevel === "comprehensive" ? 4096 : detailLevel === "detailed" ? 2048 : 1024
|
|
41
85
|
}),
|
|
42
86
|
});
|
|
43
87
|
|
|
44
88
|
const data = await resp.json();
|
|
45
|
-
|
|
89
|
+
const rawAnalysis = data.choices?.[0]?.message?.content ||
|
|
90
|
+
(language === "fr" ? "Désolé, je n'ai pas pu analyser ce fichier." : "Sorry, I couldn't analyze this file.");
|
|
91
|
+
|
|
92
|
+
return parseAIResponse(rawAnalysis, options);
|
|
46
93
|
} catch (error) {
|
|
47
94
|
console.error("Erreur IA:", error);
|
|
48
|
-
return
|
|
95
|
+
return {
|
|
96
|
+
summary: language === "fr"
|
|
97
|
+
? "Erreur lors de la connexion à l'intelligence artificielle."
|
|
98
|
+
: "Error connecting to artificial intelligence.",
|
|
99
|
+
rawAnalysis: language === "fr"
|
|
100
|
+
? "Erreur lors de la connexion à l'intelligence artificielle."
|
|
101
|
+
: "Error connecting to artificial intelligence."
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function buildSystemPrompt(
|
|
107
|
+
language: "fr" | "en",
|
|
108
|
+
options: {
|
|
109
|
+
includeDesignSystem: boolean;
|
|
110
|
+
includeRisks: boolean;
|
|
111
|
+
includeRecommendations: boolean;
|
|
112
|
+
detailLevel: string;
|
|
113
|
+
focusAreas: string[];
|
|
114
|
+
}
|
|
115
|
+
): string {
|
|
116
|
+
const { includeDesignSystem, includeRisks, includeRecommendations, detailLevel, focusAreas } = options;
|
|
117
|
+
|
|
118
|
+
if (language === "fr") {
|
|
119
|
+
return `
|
|
120
|
+
Vous êtes **MakazouIA**, l'assistant IA de **DocsToDev**, créé par **Chadrack Massamba (EsporDev)**.
|
|
121
|
+
Votre mission : Transformer des données techniques brutes en documentation métier claire et structurée.
|
|
122
|
+
|
|
123
|
+
## 📋 Instructions Générales
|
|
124
|
+
- Analysez les fichiers fournis et identifiez leur rôle métier précis.
|
|
125
|
+
- Rédigez des descriptions concises mais complètes (${detailLevel === "brief" ? "1 phrase" : detailLevel === "detailed" ? "2-3 phrases" : "paragraphe complet"}).
|
|
126
|
+
- Gardez un ton professionnel avec une touche amicale et une pointe d'humour du Congo-Brazzaville.
|
|
127
|
+
- Mentionnez les imports importants et expliquez le BUT métier de chaque fichier, pas seulement la technique.
|
|
128
|
+
|
|
129
|
+
## 🎯 Structure de Réponse Requise
|
|
130
|
+
|
|
131
|
+
### 1. **But du Projet** (Section prioritaire)
|
|
132
|
+
Rédigez UN paragraphe clair expliquant :
|
|
133
|
+
- L'objectif principal du projet
|
|
134
|
+
- Les problèmes qu'il résout
|
|
135
|
+
- Le public cible ou cas d'usage
|
|
136
|
+
|
|
137
|
+
${includeDesignSystem ? `
|
|
138
|
+
### 2. **Design System Détecté**
|
|
139
|
+
Analysez le code pour identifier :
|
|
140
|
+
- **Palette de couleurs** : Couleurs primaires/secondaires utilisées (avec codes hex si possibles)
|
|
141
|
+
- **Typographie** : Polices détectées
|
|
142
|
+
- **Patterns de composants** : Patterns UI récurrents (cards, modals, forms, etc.)
|
|
143
|
+
` : ""}
|
|
144
|
+
|
|
145
|
+
${includeRisks ? `
|
|
146
|
+
### 3. **⚠️ Risques Identifiés**
|
|
147
|
+
Listez les risques potentiels classés par niveau :
|
|
148
|
+
- 🔴 **Critique** : Problèmes majeurs (sécurité, architecture)
|
|
149
|
+
- 🟡 **Moyen** : Points d'attention (dette technique, performance)
|
|
150
|
+
- 🟢 **Faible** : Améliorations mineures
|
|
151
|
+
|
|
152
|
+
Focus sur : ${focusAreas.join(", ")}
|
|
153
|
+
` : ""}
|
|
154
|
+
|
|
155
|
+
${includeRecommendations ? `
|
|
156
|
+
### 4. **💡 Recommandations**
|
|
157
|
+
Proposez 3-5 actions concrètes pour améliorer le projet :
|
|
158
|
+
- Refactoring suggéré
|
|
159
|
+
- Optimisations possibles
|
|
160
|
+
- Bonnes pratiques à adopter
|
|
161
|
+
` : ""}
|
|
162
|
+
|
|
163
|
+
### 5. **Analyse Détaillée des Fichiers**
|
|
164
|
+
Pour chaque fichier majeur, expliquez :
|
|
165
|
+
- Son rôle métier principal
|
|
166
|
+
- Ses dépendances clés
|
|
167
|
+
- Son importance dans l'architecture globale
|
|
168
|
+
|
|
169
|
+
## ⚡ Ton et Style
|
|
170
|
+
- Soyez technique mais accessible
|
|
171
|
+
- Utilisez des émojis judicieusement (📂 🔧 ⚠️ 💡)
|
|
172
|
+
- Pas de jargon inutile, privilégiez la clarté
|
|
173
|
+
`;
|
|
174
|
+
} else {
|
|
175
|
+
return `
|
|
176
|
+
You are **MakazouIA**, the AI assistant of **DocsToDev**, created by **Chadrack Massamba (EsporDev)**.
|
|
177
|
+
Your mission: Transform raw technical data into clear business documentation.
|
|
178
|
+
|
|
179
|
+
## 📋 General Instructions
|
|
180
|
+
- Analyze provided files and identify their precise business role.
|
|
181
|
+
- Write concise yet complete descriptions (${detailLevel === "brief" ? "1 sentence" : detailLevel === "detailed" ? "2-3 sentences" : "full paragraph"}).
|
|
182
|
+
- Keep a professional tone with a friendly touch and a hint of Congo-Brazzaville humor.
|
|
183
|
+
- Mention important imports and explain the business PURPOSE of each file, not just the technical aspect.
|
|
184
|
+
|
|
185
|
+
## 🎯 Required Response Structure
|
|
186
|
+
|
|
187
|
+
### 1. **Project Goal** (Priority section)
|
|
188
|
+
Write ONE clear paragraph explaining:
|
|
189
|
+
- The main project objective
|
|
190
|
+
- Problems it solves
|
|
191
|
+
- Target audience or use cases
|
|
192
|
+
|
|
193
|
+
${includeDesignSystem ? `
|
|
194
|
+
### 2. **Detected Design System**
|
|
195
|
+
Analyze code to identify:
|
|
196
|
+
- **Color palette**: Primary/secondary colors used (with hex codes if possible)
|
|
197
|
+
- **Typography**: Detected fonts
|
|
198
|
+
- **Component patterns**: Recurring UI patterns (cards, modals, forms, etc.)
|
|
199
|
+
` : ""}
|
|
200
|
+
|
|
201
|
+
${includeRisks ? `
|
|
202
|
+
### 3. **⚠️ Identified Risks**
|
|
203
|
+
List potential risks classified by level:
|
|
204
|
+
- 🔴 **Critical**: Major issues (security, architecture)
|
|
205
|
+
- 🟡 **Medium**: Points of attention (technical debt, performance)
|
|
206
|
+
- 🟢 **Low**: Minor improvements
|
|
207
|
+
|
|
208
|
+
Focus on: ${focusAreas.join(", ")}
|
|
209
|
+
` : ""}
|
|
210
|
+
|
|
211
|
+
${includeRecommendations ? `
|
|
212
|
+
### 4. **💡 Recommendations**
|
|
213
|
+
Propose 3-5 concrete actions to improve the project:
|
|
214
|
+
- Suggested refactoring
|
|
215
|
+
- Possible optimizations
|
|
216
|
+
- Best practices to adopt
|
|
217
|
+
` : ""}
|
|
218
|
+
|
|
219
|
+
### 5. **Detailed File Analysis**
|
|
220
|
+
For each major file, explain:
|
|
221
|
+
- Its main business role
|
|
222
|
+
- Key dependencies
|
|
223
|
+
- Its importance in the overall architecture
|
|
224
|
+
|
|
225
|
+
## ⚡ Tone and Style
|
|
226
|
+
- Be technical but accessible
|
|
227
|
+
- Use emojis judiciously (📂 🔧 ⚠️ 💡)
|
|
228
|
+
- No unnecessary jargon, prioritize clarity
|
|
229
|
+
`;
|
|
49
230
|
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function parseAIResponse(rawAnalysis: string, options: AIAnalysisOptions): AIAnalysisResult {
|
|
234
|
+
const result: AIAnalysisResult = {
|
|
235
|
+
summary: "",
|
|
236
|
+
rawAnalysis
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
// Extraire le but du projet
|
|
240
|
+
const goalMatch = rawAnalysis.match(/(?:But du Projet|Project Goal)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
|
|
241
|
+
if (goalMatch) {
|
|
242
|
+
result.projectGoal = goalMatch[1]?.trim() || "";
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Extraire le design system
|
|
246
|
+
if (options.includeDesignSystem) {
|
|
247
|
+
const designMatch = rawAnalysis.match(/(?:Design System|Palette)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
|
|
248
|
+
if (designMatch) {
|
|
249
|
+
const colors = designMatch[1]?.match(/#[0-9A-Fa-f]{6}/g) || [];
|
|
250
|
+
result.designSystem = {
|
|
251
|
+
primaryColors: colors,
|
|
252
|
+
componentPatterns: []
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// Extraire les risques
|
|
258
|
+
if (options.includeRisks) {
|
|
259
|
+
const risksMatch = rawAnalysis.match(/(?:Risques|Risks)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
|
|
260
|
+
if (risksMatch) {
|
|
261
|
+
result.risks = [];
|
|
262
|
+
const criticalMatches = risksMatch[1]?.match(/🔴[^\n]+/g) || [];
|
|
263
|
+
const mediumMatches = risksMatch[1]?.match(/🟡[^\n]+/g) || [];
|
|
264
|
+
const lowMatches = risksMatch[1]?.match(/🟢[^\n]+/g) || [];
|
|
265
|
+
|
|
266
|
+
criticalMatches.forEach(r => result.risks!.push({ level: "high", description: r.replace(/🔴\s*/, "") }));
|
|
267
|
+
mediumMatches.forEach(r => result.risks!.push({ level: "medium", description: r.replace(/🟡\s*/, "") }));
|
|
268
|
+
lowMatches.forEach(r => result.risks!.push({ level: "low", description: r.replace(/🟢\s*/, "") }));
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Extraire les recommandations
|
|
273
|
+
if (options.includeRecommendations) {
|
|
274
|
+
const recoMatch = rawAnalysis.match(/(?:Recommandations|Recommendations)[:\s]*\n+([\s\S]*?)(?=\n#{2,}|\n\n[A-Z#]|$)/i);
|
|
275
|
+
if (recoMatch && recoMatch[1]) {
|
|
276
|
+
result.recommendations = recoMatch[1]
|
|
277
|
+
.split(/\n[-*•]/)
|
|
278
|
+
.map(r => r.trim())
|
|
279
|
+
.filter(r => r.length > 10);
|
|
280
|
+
} else {
|
|
281
|
+
result.recommendations = [];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Résumé (premiers 200 caractères)
|
|
286
|
+
result.summary = rawAnalysis.substring(0, 200).trim() + "...";
|
|
287
|
+
|
|
288
|
+
return result;
|
|
50
289
|
}
|
package/src/commands/run.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { writeFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import puppeteer, { Browser, Page } from "puppeteer";
|
|
6
6
|
import { exportToHTML } from "../exporters/html.js";
|
|
7
|
-
import {
|
|
7
|
+
import { askAIDetailed, type AIAnalysisOptions } from "../ai/analyzer.js";
|
|
8
8
|
import { getAnalyzer, getSupportedExtensions } from "../analyzers/languageAnalyzer.js";
|
|
9
9
|
import { CacheManager } from "../cache/cacheManager.js";
|
|
10
10
|
|
|
@@ -14,7 +14,6 @@ interface FileAnalysis {
|
|
|
14
14
|
path: string;
|
|
15
15
|
lines: number;
|
|
16
16
|
exports: string[];
|
|
17
|
-
// Ajout de '| undefined' pour supporter les propriétés optionnelles en mode strict
|
|
18
17
|
imports: Array<{ name: string; type: string; usage?: string | undefined }>;
|
|
19
18
|
functions: string[];
|
|
20
19
|
classes: string[];
|
|
@@ -36,7 +35,13 @@ const i18n = {
|
|
|
36
35
|
functions: "Fonctions",
|
|
37
36
|
classes: "Classes",
|
|
38
37
|
types: "Types/Interfaces",
|
|
39
|
-
complexity: "Score de complexité"
|
|
38
|
+
complexity: "Score de complexité",
|
|
39
|
+
projectGoal: "But du Projet",
|
|
40
|
+
designSystem: "Design System Détecté",
|
|
41
|
+
colorPalette: "Palette de couleurs",
|
|
42
|
+
componentPatterns: "Patterns de composants",
|
|
43
|
+
risks: "Risques Identifiés",
|
|
44
|
+
recommendations: "Recommandations"
|
|
40
45
|
},
|
|
41
46
|
en: {
|
|
42
47
|
role: "Role and responsibilities",
|
|
@@ -51,7 +56,13 @@ const i18n = {
|
|
|
51
56
|
functions: "Functions",
|
|
52
57
|
classes: "Classes",
|
|
53
58
|
types: "Types/Interfaces",
|
|
54
|
-
complexity: "Complexity score"
|
|
59
|
+
complexity: "Complexity score",
|
|
60
|
+
projectGoal: "Project Goal",
|
|
61
|
+
designSystem: "Detected Design System",
|
|
62
|
+
colorPalette: "Color Palette",
|
|
63
|
+
componentPatterns: "Component Patterns",
|
|
64
|
+
risks: "Identified Risks",
|
|
65
|
+
recommendations: "Recommendations"
|
|
55
66
|
}
|
|
56
67
|
};
|
|
57
68
|
|
|
@@ -92,43 +103,30 @@ function analyzeFile(file: string, content: string): FileAnalysis {
|
|
|
92
103
|
const lines = content.split(/\r?\n/);
|
|
93
104
|
const analyzer = getAnalyzer(file);
|
|
94
105
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
whileCount * 1.5;
|
|
110
|
-
|
|
111
|
-
return {
|
|
112
|
-
path: file,
|
|
113
|
-
lines: lines.length,
|
|
114
|
-
exports: result.exports,
|
|
115
|
-
imports: result.imports,
|
|
116
|
-
functions: result.functions,
|
|
117
|
-
classes: result.classes,
|
|
118
|
-
types: result.types,
|
|
119
|
-
complexity: Math.round(complexity)
|
|
120
|
-
};
|
|
121
|
-
}
|
|
106
|
+
const result = analyzer.analyzeFile(content);
|
|
107
|
+
|
|
108
|
+
const ifCount = (content.match(/\b(if|elif|else if)\s*\(/g) || []).length;
|
|
109
|
+
const forCount = (content.match(/\b(for|foreach|while)\s*\(/g) || []).length;
|
|
110
|
+
const whileCount = (content.match(/\bwhile\s*\(/g) || []).length;
|
|
111
|
+
|
|
112
|
+
const complexity =
|
|
113
|
+
lines.length * 0.1 +
|
|
114
|
+
result.functions.length * 2 +
|
|
115
|
+
result.classes.length * 3 +
|
|
116
|
+
result.imports.length * 1.5 +
|
|
117
|
+
ifCount * 1 +
|
|
118
|
+
forCount * 1.5 +
|
|
119
|
+
whileCount * 1.5;
|
|
122
120
|
|
|
123
121
|
return {
|
|
124
122
|
path: file,
|
|
125
123
|
lines: lines.length,
|
|
126
|
-
exports:
|
|
127
|
-
imports:
|
|
128
|
-
functions:
|
|
129
|
-
classes:
|
|
130
|
-
types:
|
|
131
|
-
complexity:
|
|
124
|
+
exports: result.exports,
|
|
125
|
+
imports: result.imports,
|
|
126
|
+
functions: result.functions,
|
|
127
|
+
classes: result.classes,
|
|
128
|
+
types: result.types,
|
|
129
|
+
complexity: Math.round(complexity)
|
|
132
130
|
};
|
|
133
131
|
}
|
|
134
132
|
|
|
@@ -140,7 +138,7 @@ function getComplexityLevel(score: number): string {
|
|
|
140
138
|
}
|
|
141
139
|
|
|
142
140
|
function formatAISummary(summary: string): string {
|
|
143
|
-
let formatted = summary.replace(/([a-zA-Z0-9_-]+\.(ts|js|py|java|cs|go|rs|tsx|jsx|mjs|cjs))/g, '`$1`');
|
|
141
|
+
let formatted = summary.replace(/([a-zA-Z0-9_-]+\.(ts|js|py|java|cs|go|rs|tsx|jsx|mjs|cjs|html|css|php|rb|sql))/g, '`$1`');
|
|
144
142
|
formatted = formatted.replace(/([a-zA-Z0-9_-]+\/[a-zA-Z0-9_\/-]+)/g, '`$1`');
|
|
145
143
|
formatted = formatted.replace(/\b([a-z][a-zA-Z0-9]*[A-Z][a-zA-Z0-9]*|[A-Z][a-z][a-zA-Z0-9]*)\b/g, '`$1`');
|
|
146
144
|
formatted = formatted.replace(/\.\s+/g, '.\n\n');
|
|
@@ -150,7 +148,11 @@ function formatAISummary(summary: string): string {
|
|
|
150
148
|
|
|
151
149
|
export async function runCommand(
|
|
152
150
|
language: "fr" | "en" = "fr",
|
|
153
|
-
options: {
|
|
151
|
+
options: {
|
|
152
|
+
incremental?: boolean;
|
|
153
|
+
clearCache?: boolean;
|
|
154
|
+
aiOptions?: AIAnalysisOptions;
|
|
155
|
+
} = {}
|
|
154
156
|
): Promise<number> {
|
|
155
157
|
const t = i18n[language];
|
|
156
158
|
|
|
@@ -167,7 +169,7 @@ export async function runCommand(
|
|
|
167
169
|
console.log(" ✓ Cache vidé\n");
|
|
168
170
|
}
|
|
169
171
|
|
|
170
|
-
console.log("📂 Étape 1/
|
|
172
|
+
console.log("📂 Étape 1/5 : Scan des fichiers du projet...");
|
|
171
173
|
const supportedExts = getSupportedExtensions();
|
|
172
174
|
const files = await globby(["**/*"], {
|
|
173
175
|
gitignore: true,
|
|
@@ -198,9 +200,15 @@ export async function runCommand(
|
|
|
198
200
|
console.log(` ✓ ${modifiedFiles.length} fichiers modifiés, ${cachedCount} en cache\n`);
|
|
199
201
|
}
|
|
200
202
|
|
|
201
|
-
console.log("🔍 Étape 2/
|
|
202
|
-
let aiContext =
|
|
203
|
-
|
|
203
|
+
console.log("🔍 Étape 2/5 : Analyse approfondie des fichiers sources...");
|
|
204
|
+
let aiContext = language === "fr"
|
|
205
|
+
? `Tu es un expert en analyse de code. Analyse ces fichiers et explique leur architecture, leurs responsabilités et comment ils collaborent ensemble. Identifie le rôle de chaque fichier (Page, Component, Service, API, Utility, etc.). Sois précis et technique.\n\n`
|
|
206
|
+
: `You are a code analysis expert. Analyze these files and explain their architecture, responsibilities and how they work together. Identify the role of each file (Page, Component, Service, API, Utility, etc.). Be precise and technical.\n\n`;
|
|
207
|
+
|
|
208
|
+
let detailContent = language === "fr"
|
|
209
|
+
? `## 🔬 Analyse détaillée des composants\n\n`
|
|
210
|
+
: `## 🔬 Detailed Component Analysis\n\n`;
|
|
211
|
+
|
|
204
212
|
let mermaidGraph = "graph LR\n";
|
|
205
213
|
const allDeps = new Map<string, string>();
|
|
206
214
|
const analyses: FileAnalysis[] = [];
|
|
@@ -283,25 +291,83 @@ export async function runCommand(
|
|
|
283
291
|
const totalAnalyzed = processedCount + cachedCount;
|
|
284
292
|
console.log(` ✓ ${totalAnalyzed} fichiers analysés (${processedCount} nouvelles analyses, ${cachedCount} depuis cache)\n`);
|
|
285
293
|
|
|
286
|
-
console.log("🤖 Étape 3/
|
|
287
|
-
|
|
288
|
-
const
|
|
294
|
+
console.log("🤖 Étape 3/5 : Génération de l'analyse intelligente (IA)...");
|
|
295
|
+
|
|
296
|
+
const aiOptions: AIAnalysisOptions = options.aiOptions || {
|
|
297
|
+
language,
|
|
298
|
+
includeDesignSystem: true,
|
|
299
|
+
includeRisks: true,
|
|
300
|
+
includeRecommendations: true,
|
|
301
|
+
detailLevel: "detailed",
|
|
302
|
+
focusAreas: ["architecture", "maintainability", "security"]
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
const aiResult = await askAIDetailed(aiContext, aiOptions);
|
|
306
|
+
const formattedAiSummary = formatAISummary(aiResult.rawAnalysis);
|
|
307
|
+
|
|
289
308
|
console.log(` ✓ Synthèse IA générée\n`);
|
|
290
309
|
|
|
291
|
-
console.log("📝 Étape 4/
|
|
310
|
+
console.log("📝 Étape 4/5 : Construction du rapport Markdown...");
|
|
292
311
|
let finalMD = `# ${t.reportTitle}\n\n`;
|
|
293
|
-
finalMD += `> 📅 ${t.genAt} : ${new Date().toLocaleString("fr-FR", { dateStyle: "full", timeStyle: "short" })}\n`;
|
|
312
|
+
finalMD += `> 📅 ${t.genAt} : ${new Date().toLocaleString(language === "fr" ? "fr-FR" : "en-US", { dateStyle: "full", timeStyle: "short" })}\n`;
|
|
294
313
|
finalMD += `> 📊 ${totalAnalyzed} fichiers analysés • ${allDeps.size} dépendances identifiées\n`;
|
|
295
314
|
if (options.incremental && cachedCount > 0) {
|
|
296
315
|
finalMD += `> ⚡ Mode incrémental : ${cachedCount} fichiers depuis cache\n`;
|
|
297
316
|
}
|
|
298
317
|
finalMD += `\n`;
|
|
318
|
+
|
|
319
|
+
// Section BUT DU PROJET (PRIORITÉ ABSOLUE)
|
|
320
|
+
if (aiResult.projectGoal) {
|
|
321
|
+
finalMD += `## 🎯 ${t.projectGoal}\n\n`;
|
|
322
|
+
finalMD += `${aiResult.projectGoal}\n\n`;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Section DESIGN SYSTEM
|
|
326
|
+
if (aiResult.designSystem && aiOptions.includeDesignSystem) {
|
|
327
|
+
finalMD += `## 🎨 ${t.designSystem}\n\n`;
|
|
328
|
+
if (aiResult.designSystem.primaryColors && aiResult.designSystem.primaryColors.length > 0) {
|
|
329
|
+
finalMD += `**${t.colorPalette}** : ${aiResult.designSystem.primaryColors.join(", ")}\n\n`;
|
|
330
|
+
}
|
|
331
|
+
if (aiResult.designSystem.typography) {
|
|
332
|
+
finalMD += `**Typographie** : ${aiResult.designSystem.typography}\n\n`;
|
|
333
|
+
}
|
|
334
|
+
if (aiResult.designSystem.componentPatterns && aiResult.designSystem.componentPatterns.length > 0) {
|
|
335
|
+
finalMD += `**${t.componentPatterns}** : ${aiResult.designSystem.componentPatterns.join(", ")}\n\n`;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Section RISQUES
|
|
340
|
+
if (aiResult.risks && aiOptions.includeRisks && aiResult.risks.length > 0) {
|
|
341
|
+
finalMD += `## ⚠️ ${t.risks}\n\n`;
|
|
342
|
+
aiResult.risks.forEach(risk => {
|
|
343
|
+
const icon = risk.level === "high" ? "🔴" : risk.level === "medium" ? "🟡" : "🟢";
|
|
344
|
+
const levelText = risk.level === "high" ? "CRITIQUE" : risk.level === "medium" ? "MOYEN" : "FAIBLE";
|
|
345
|
+
finalMD += `${icon} **${levelText}** : ${risk.description}\n\n`;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Section RECOMMANDATIONS
|
|
350
|
+
if (aiResult.recommendations && aiOptions.includeRecommendations && aiResult.recommendations.length > 0) {
|
|
351
|
+
finalMD += `## 💡 ${t.recommendations}\n\n`;
|
|
352
|
+
aiResult.recommendations.forEach(reco => {
|
|
353
|
+
finalMD += `- ${reco}\n`;
|
|
354
|
+
});
|
|
355
|
+
finalMD += `\n`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Analyse IA complète
|
|
299
359
|
finalMD += `## 💡 ${t.aiTitle}\n\n${formattedAiSummary}\n\n`;
|
|
360
|
+
|
|
361
|
+
// Structure du projet
|
|
300
362
|
finalMD += `## 📂 ${t.structure}\n\n`;
|
|
301
363
|
finalMD += "```\n";
|
|
302
364
|
finalMD += renderTree(buildTree(files));
|
|
303
365
|
finalMD += "```\n\n";
|
|
366
|
+
|
|
367
|
+
// Analyse détaillée
|
|
304
368
|
finalMD += detailContent;
|
|
369
|
+
|
|
370
|
+
// Dépendances
|
|
305
371
|
finalMD += `## 📦 ${t.deps}\n\n`;
|
|
306
372
|
finalMD += `| Module | Type | Occurrences |\n`;
|
|
307
373
|
finalMD += `| :--- | :--- | :---: |\n`;
|
|
@@ -322,14 +388,14 @@ export async function runCommand(
|
|
|
322
388
|
writeFileSync(path.join(docsDir, "docs-to-dev.md"), finalMD);
|
|
323
389
|
console.log(` ✓ Rapport Markdown généré : docs/docs-to-dev.md\n`);
|
|
324
390
|
|
|
325
|
-
console.log("🎨 Étape 5/
|
|
391
|
+
console.log("🎨 Étape 5/5 : Export HTML avec graphiques...");
|
|
326
392
|
const fileTreeStructure = buildTree(files);
|
|
327
393
|
exportToHTML(docsDir, finalMD, mermaidGraph, language, fileTreeStructure);
|
|
328
394
|
console.log(` ✓ Rapport HTML généré : docs/report.html\n`);
|
|
329
395
|
|
|
330
|
-
console.log("📄 Étape 6/6 : Génération du PDF...");
|
|
331
|
-
await generatePDF(path.join(docsDir, "report.html"), path.join(docsDir, "report.pdf"));
|
|
332
|
-
console.log(` ✓ PDF exporté : docs/report.pdf\n`);
|
|
396
|
+
// console.log("📄 Étape 6/6 : Génération du PDF...");
|
|
397
|
+
// await generatePDF(path.join(docsDir, "report.html"), path.join(docsDir, "report.pdf"));
|
|
398
|
+
// console.log(` ✓ PDF exporté : docs/report.pdf\n`);
|
|
333
399
|
|
|
334
400
|
console.log("╔══════════════════════════════════════════╗");
|
|
335
401
|
console.log("║ ✨ Analyse terminée avec succès ! ║");
|
|
@@ -355,39 +421,39 @@ export async function runCommand(
|
|
|
355
421
|
return files.length;
|
|
356
422
|
}
|
|
357
423
|
|
|
358
|
-
async function generatePDF(htmlPath: string, outputPath: string): Promise<void> {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
424
|
+
// async function generatePDF(htmlPath: string, outputPath: string): Promise<void> {
|
|
425
|
+
// let browser: Browser | null = null;
|
|
426
|
+
// try {
|
|
427
|
+
// browser = await puppeteer.launch({
|
|
428
|
+
// headless: true,
|
|
429
|
+
// args: ['--no-sandbox', '--disable-setuid-sandbox']
|
|
430
|
+
// });
|
|
431
|
+
// const page: Page = await browser.newPage();
|
|
366
432
|
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
433
|
+
// await page.goto(`file://${path.resolve(htmlPath)}`, {
|
|
434
|
+
// waitUntil: "networkidle0",
|
|
435
|
+
// timeout: 30000
|
|
436
|
+
// });
|
|
371
437
|
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
438
|
+
// await page.waitForFunction(() => {
|
|
439
|
+
// return typeof (window as any).mermaid !== 'undefined';
|
|
440
|
+
// }, { timeout: 5000 }).catch(() => {});
|
|
375
441
|
|
|
376
|
-
|
|
442
|
+
// await new Promise(resolve => setTimeout(resolve, 2000));
|
|
377
443
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
444
|
+
// await page.pdf({
|
|
445
|
+
// path: outputPath,
|
|
446
|
+
// format: 'A4',
|
|
447
|
+
// printBackground: true,
|
|
448
|
+
// margin: { top: '1cm', bottom: '1cm', left: '1cm', right: '1cm' },
|
|
449
|
+
// preferCSSPageSize: true
|
|
450
|
+
// });
|
|
385
451
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
452
|
+
// await browser.close();
|
|
453
|
+
// } catch (e) {
|
|
454
|
+
// console.error(" ⚠️ Erreur lors de la génération du PDF:", e);
|
|
455
|
+
// if (browser) {
|
|
456
|
+
// await browser.close().catch(() => {});
|
|
457
|
+
// }
|
|
458
|
+
// }
|
|
459
|
+
// }
|