@enokdev/springdocs-mcp 1.2.7 → 1.4.1
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/README.md +108 -40
- package/build/config.d.ts +9 -0
- package/build/config.d.ts.map +1 -0
- package/build/config.js +32 -0
- package/build/config.js.map +1 -0
- package/build/format.d.ts +6 -0
- package/build/format.d.ts.map +1 -0
- package/build/format.js +23 -0
- package/build/format.js.map +1 -0
- package/build/http-server.d.ts +15 -0
- package/build/http-server.d.ts.map +1 -0
- package/build/http-server.js +131 -0
- package/build/http-server.js.map +1 -0
- package/build/index.js +184 -69
- package/build/index.js.map +1 -1
- package/build/prompts.d.ts +23 -0
- package/build/prompts.d.ts.map +1 -0
- package/build/prompts.js +112 -0
- package/build/prompts.js.map +1 -0
- package/build/resources.d.ts +31 -0
- package/build/resources.d.ts.map +1 -0
- package/build/resources.js +66 -0
- package/build/resources.js.map +1 -0
- package/build/services/advanced-features.d.ts +19 -9
- package/build/services/advanced-features.d.ts.map +1 -1
- package/build/services/advanced-features.js +266 -191
- package/build/services/advanced-features.js.map +1 -1
- package/build/services/boot-wiki.d.ts +25 -0
- package/build/services/boot-wiki.d.ts.map +1 -0
- package/build/services/boot-wiki.js +103 -0
- package/build/services/boot-wiki.js.map +1 -0
- package/build/services/cache.d.ts +18 -3
- package/build/services/cache.d.ts.map +1 -1
- package/build/services/cache.js +84 -3
- package/build/services/cache.js.map +1 -1
- package/build/services/dependency-finder.d.ts +46 -0
- package/build/services/dependency-finder.d.ts.map +1 -0
- package/build/services/dependency-finder.js +181 -0
- package/build/services/dependency-finder.js.map +1 -0
- package/build/services/diagnosis.d.ts +46 -0
- package/build/services/diagnosis.d.ts.map +1 -0
- package/build/services/diagnosis.js +481 -0
- package/build/services/diagnosis.js.map +1 -0
- package/build/services/guides-list.d.ts +16 -0
- package/build/services/guides-list.d.ts.map +1 -0
- package/build/services/guides-list.js +45 -0
- package/build/services/guides-list.js.map +1 -0
- package/build/services/http.d.ts +21 -0
- package/build/services/http.d.ts.map +1 -0
- package/build/services/http.js +168 -0
- package/build/services/http.js.map +1 -0
- package/build/services/initializr.d.ts +41 -0
- package/build/services/initializr.d.ts.map +1 -0
- package/build/services/initializr.js +135 -0
- package/build/services/initializr.js.map +1 -0
- package/build/services/markdown.d.ts +56 -0
- package/build/services/markdown.d.ts.map +1 -0
- package/build/services/markdown.js +146 -0
- package/build/services/markdown.js.map +1 -0
- package/build/services/migration-sources.d.ts +13 -0
- package/build/services/migration-sources.d.ts.map +1 -0
- package/build/services/migration-sources.js +48 -0
- package/build/services/migration-sources.js.map +1 -0
- package/build/services/release-notes.d.ts +23 -0
- package/build/services/release-notes.d.ts.map +1 -0
- package/build/services/release-notes.js +94 -0
- package/build/services/release-notes.js.map +1 -0
- package/build/services/search-index.d.ts +33 -0
- package/build/services/search-index.d.ts.map +1 -0
- package/build/services/search-index.js +147 -0
- package/build/services/search-index.js.map +1 -0
- package/build/services/spring-projects-config.d.ts +98 -0
- package/build/services/spring-projects-config.d.ts.map +1 -0
- package/build/services/spring-projects-config.js +397 -0
- package/build/services/spring-projects-config.js.map +1 -0
- package/build/services/springboot-docs-optimized.d.ts +72 -21
- package/build/services/springboot-docs-optimized.d.ts.map +1 -1
- package/build/services/springboot-docs-optimized.js +354 -208
- package/build/services/springboot-docs-optimized.js.map +1 -1
- package/build/services/url.d.ts +15 -0
- package/build/services/url.d.ts.map +1 -0
- package/build/services/url.js +40 -0
- package/build/services/url.js.map +1 -0
- package/build/tools/index.d.ts +393 -2
- package/build/tools/index.d.ts.map +1 -1
- package/build/tools/index.js +188 -15
- package/build/tools/index.js.map +1 -1
- package/build/validation.d.ts +7 -0
- package/build/validation.d.ts.map +1 -0
- package/build/validation.js +50 -0
- package/build/validation.js.map +1 -0
- package/build/version.d.ts +3 -0
- package/build/version.d.ts.map +1 -0
- package/build/version.js +6 -0
- package/build/version.js.map +1 -0
- package/package.json +9 -7
- package/build/debug.d.ts +0 -3
- package/build/debug.d.ts.map +0 -1
- package/build/debug.js +0 -292
- package/build/debug.js.map +0 -1
- package/build/services/advanced-features-old.d.ts +0 -45
- package/build/services/advanced-features-old.d.ts.map +0 -1
- package/build/services/advanced-features-old.js +0 -792
- package/build/services/advanced-features-old.js.map +0 -1
- package/build/services/springboot-docs-optimized-old.d.ts +0 -55
- package/build/services/springboot-docs-optimized-old.d.ts.map +0 -1
- package/build/services/springboot-docs-optimized-old.js +0 -588
- package/build/services/springboot-docs-optimized-old.js.map +0 -1
- package/build/services/springboot-docs.d.ts +0 -65
- package/build/services/springboot-docs.d.ts.map +0 -1
- package/build/services/springboot-docs.js +0 -708
- package/build/services/springboot-docs.js.map +0 -1
|
@@ -1,708 +0,0 @@
|
|
|
1
|
-
import fetch from 'node-fetch';
|
|
2
|
-
import * as cheerio from 'cheerio';
|
|
3
|
-
import TurndownService from 'turndown';
|
|
4
|
-
/**
|
|
5
|
-
* Service pour accéder et traiter la documentation Spring Boot
|
|
6
|
-
*/
|
|
7
|
-
export class SpringBootDocsService {
|
|
8
|
-
baseUrl = 'https://docs.spring.io';
|
|
9
|
-
springProjectsUrl = 'https://spring.io/projects';
|
|
10
|
-
springGuideUrl = 'https://spring.io/guides';
|
|
11
|
-
springBootVersion = '3.5.5'; // Version par défaut
|
|
12
|
-
turndownService;
|
|
13
|
-
constructor() {
|
|
14
|
-
this.turndownService = new TurndownService({
|
|
15
|
-
headingStyle: 'atx',
|
|
16
|
-
codeBlockStyle: 'fenced',
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Recherche dans tous les projets Spring
|
|
21
|
-
*/
|
|
22
|
-
async searchSpringProjects(query, limit = 10) {
|
|
23
|
-
try {
|
|
24
|
-
const response = await fetch(this.springProjectsUrl);
|
|
25
|
-
if (!response.ok) {
|
|
26
|
-
throw new Error('Impossible d\'accéder à la page des projets Spring');
|
|
27
|
-
}
|
|
28
|
-
const html = await response.text();
|
|
29
|
-
const $ = cheerio.load(html);
|
|
30
|
-
const projects = [];
|
|
31
|
-
// Extraire les projets depuis la page
|
|
32
|
-
$('.project-list .project, .project-item, .card').each((index, element) => {
|
|
33
|
-
const $project = $(element);
|
|
34
|
-
const title = $project.find('h2, h3, .title, .project-title').first().text().trim();
|
|
35
|
-
const description = $project.find('p, .description, .summary').first().text().trim();
|
|
36
|
-
const link = $project.find('a').first().attr('href');
|
|
37
|
-
if (title && (title.toLowerCase().includes(query.toLowerCase()) ||
|
|
38
|
-
description.toLowerCase().includes(query.toLowerCase()))) {
|
|
39
|
-
projects.push({
|
|
40
|
-
type: 'spring-project',
|
|
41
|
-
title: title,
|
|
42
|
-
description: description,
|
|
43
|
-
url: link?.startsWith('http') ? link : `https://spring.io${link}`,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
// Si peu de résultats, ajouter des projets populaires
|
|
48
|
-
if (projects.length < 3) {
|
|
49
|
-
const popularProjects = this.getPopularSpringProjects()
|
|
50
|
-
.filter(project => project.title.toLowerCase().includes(query.toLowerCase()) ||
|
|
51
|
-
project.description.toLowerCase().includes(query.toLowerCase()) ||
|
|
52
|
-
project.keywords.some((k) => k.toLowerCase().includes(query.toLowerCase())));
|
|
53
|
-
projects.push(...popularProjects);
|
|
54
|
-
}
|
|
55
|
-
return projects.slice(0, limit);
|
|
56
|
-
}
|
|
57
|
-
catch (error) {
|
|
58
|
-
console.error('Erreur lors de la recherche des projets Spring:', error);
|
|
59
|
-
// Fallback sur les projets populaires
|
|
60
|
-
return this.getPopularSpringProjects()
|
|
61
|
-
.filter(project => project.title.toLowerCase().includes(query.toLowerCase()) ||
|
|
62
|
-
project.description.toLowerCase().includes(query.toLowerCase()))
|
|
63
|
-
.slice(0, limit);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Récupère les détails d'un projet Spring spécifique
|
|
68
|
-
*/
|
|
69
|
-
async getSpringProject(projectName) {
|
|
70
|
-
try {
|
|
71
|
-
const url = `${this.springProjectsUrl}/${projectName}`;
|
|
72
|
-
const response = await fetch(url);
|
|
73
|
-
if (!response.ok) {
|
|
74
|
-
throw new Error(`Projet non trouvé: ${projectName}`);
|
|
75
|
-
}
|
|
76
|
-
const html = await response.text();
|
|
77
|
-
const $ = cheerio.load(html);
|
|
78
|
-
// Extrait le contenu principal du projet
|
|
79
|
-
const content = $('.project-overview, .content, main, .project-details').first();
|
|
80
|
-
if (content.length === 0) {
|
|
81
|
-
throw new Error('Contenu du projet non trouvé');
|
|
82
|
-
}
|
|
83
|
-
// Nettoie et convertit en Markdown
|
|
84
|
-
this.cleanHtml($, content);
|
|
85
|
-
const markdown = this.turndownService.turndown(content.html() || '');
|
|
86
|
-
// Ajouter des informations supplémentaires
|
|
87
|
-
const version = $('.version, .current-version').first().text().trim();
|
|
88
|
-
const status = $('.status, .project-status').first().text().trim();
|
|
89
|
-
let result = `# Projet Spring: ${projectName}\n\n`;
|
|
90
|
-
if (version)
|
|
91
|
-
result += `**Version actuelle:** ${version}\n\n`;
|
|
92
|
-
if (status)
|
|
93
|
-
result += `**Statut:** ${status}\n\n`;
|
|
94
|
-
result += markdown;
|
|
95
|
-
return result;
|
|
96
|
-
}
|
|
97
|
-
catch (error) {
|
|
98
|
-
console.error(`Erreur lors de la récupération du projet ${projectName}:`, error);
|
|
99
|
-
throw new Error(`Impossible de récupérer le projet: ${projectName}`);
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Récupère tous les guides Spring disponibles
|
|
104
|
-
*/
|
|
105
|
-
async getAllSpringGuides(category, limit = 20) {
|
|
106
|
-
try {
|
|
107
|
-
const response = await fetch(this.springGuideUrl);
|
|
108
|
-
if (!response.ok) {
|
|
109
|
-
throw new Error('Impossible d\'accéder à la page des guides Spring');
|
|
110
|
-
}
|
|
111
|
-
const html = await response.text();
|
|
112
|
-
const $ = cheerio.load(html);
|
|
113
|
-
const guides = [];
|
|
114
|
-
// Extraire les guides depuis la page
|
|
115
|
-
$('.guide-list .guide, .guide-item, .card').each((index, element) => {
|
|
116
|
-
const $guide = $(element);
|
|
117
|
-
const title = $guide.find('h2, h3, .title, .guide-title').first().text().trim();
|
|
118
|
-
const description = $guide.find('p, .description, .summary').first().text().trim();
|
|
119
|
-
const link = $guide.find('a').first().attr('href');
|
|
120
|
-
const guideCategory = $guide.find('.category, .tag').first().text().trim();
|
|
121
|
-
if (title && (!category || guideCategory.toLowerCase().includes(category.toLowerCase()))) {
|
|
122
|
-
guides.push({
|
|
123
|
-
type: 'spring-guide',
|
|
124
|
-
title: title,
|
|
125
|
-
description: description,
|
|
126
|
-
category: guideCategory,
|
|
127
|
-
url: link?.startsWith('http') ? link : `https://spring.io${link}`,
|
|
128
|
-
id: link?.split('/').pop()?.replace('.html', '') || title.toLowerCase().replace(/\s+/g, '-'),
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
// Si peu de résultats, ajouter des guides populaires
|
|
133
|
-
if (guides.length < 5) {
|
|
134
|
-
const popularGuides = this.getPopularSpringGuides();
|
|
135
|
-
guides.push(...popularGuides);
|
|
136
|
-
}
|
|
137
|
-
return guides.slice(0, limit);
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
console.error('Erreur lors de la récupération des guides Spring:', error);
|
|
141
|
-
// Fallback sur les guides populaires
|
|
142
|
-
return this.getPopularSpringGuides().slice(0, limit);
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Liste des projets Spring populaires
|
|
147
|
-
*/
|
|
148
|
-
getPopularSpringProjects() {
|
|
149
|
-
return [
|
|
150
|
-
{
|
|
151
|
-
type: 'spring-project',
|
|
152
|
-
title: 'Spring Boot',
|
|
153
|
-
description: 'Créez des applications Spring de qualité production facilement',
|
|
154
|
-
url: 'https://spring.io/projects/spring-boot',
|
|
155
|
-
keywords: ['boot', 'microservices', 'web', 'standalone'],
|
|
156
|
-
},
|
|
157
|
-
{
|
|
158
|
-
type: 'spring-project',
|
|
159
|
-
title: 'Spring Framework',
|
|
160
|
-
description: 'Le framework Java le plus populaire pour créer des applications d\'entreprise',
|
|
161
|
-
url: 'https://spring.io/projects/spring-framework',
|
|
162
|
-
keywords: ['framework', 'core', 'mvc', 'ioc', 'dependency injection'],
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
type: 'spring-project',
|
|
166
|
-
title: 'Spring Data',
|
|
167
|
-
description: 'Fournit un modèle de programmation familier pour l\'accès aux données',
|
|
168
|
-
url: 'https://spring.io/projects/spring-data',
|
|
169
|
-
keywords: ['data', 'jpa', 'mongodb', 'redis', 'repository'],
|
|
170
|
-
},
|
|
171
|
-
{
|
|
172
|
-
type: 'spring-project',
|
|
173
|
-
title: 'Spring Security',
|
|
174
|
-
description: 'Framework de sécurité puissant et hautement personnalisable',
|
|
175
|
-
url: 'https://spring.io/projects/spring-security',
|
|
176
|
-
keywords: ['security', 'authentication', 'authorization', 'oauth'],
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
type: 'spring-project',
|
|
180
|
-
title: 'Spring Cloud',
|
|
181
|
-
description: 'Outils pour développer rapidement des patterns de systèmes distribués',
|
|
182
|
-
url: 'https://spring.io/projects/spring-cloud',
|
|
183
|
-
keywords: ['cloud', 'microservices', 'distributed', 'netflix'],
|
|
184
|
-
},
|
|
185
|
-
{
|
|
186
|
-
type: 'spring-project',
|
|
187
|
-
title: 'Spring Integration',
|
|
188
|
-
description: 'Implémentation des Enterprise Integration Patterns',
|
|
189
|
-
url: 'https://spring.io/projects/spring-integration',
|
|
190
|
-
keywords: ['integration', 'messaging', 'endpoints', 'channels'],
|
|
191
|
-
},
|
|
192
|
-
{
|
|
193
|
-
type: 'spring-project',
|
|
194
|
-
title: 'Spring Batch',
|
|
195
|
-
description: 'Framework pour le traitement batch robuste',
|
|
196
|
-
url: 'https://spring.io/projects/spring-batch',
|
|
197
|
-
keywords: ['batch', 'processing', 'jobs', 'steps'],
|
|
198
|
-
},
|
|
199
|
-
{
|
|
200
|
-
type: 'spring-project',
|
|
201
|
-
title: 'Spring WebFlux',
|
|
202
|
-
description: 'Framework web réactif pour Spring',
|
|
203
|
-
url: 'https://spring.io/projects/spring-framework',
|
|
204
|
-
keywords: ['reactive', 'webflux', 'non-blocking', 'async'],
|
|
205
|
-
},
|
|
206
|
-
];
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Liste des guides Spring populaires
|
|
210
|
-
*/
|
|
211
|
-
getPopularSpringGuides() {
|
|
212
|
-
return [
|
|
213
|
-
{
|
|
214
|
-
type: 'spring-guide',
|
|
215
|
-
title: 'Building a RESTful Web Service',
|
|
216
|
-
description: 'Apprendre à créer un service web RESTful avec Spring Boot',
|
|
217
|
-
category: 'Web',
|
|
218
|
-
url: 'https://spring.io/guides/gs/rest-service/',
|
|
219
|
-
id: 'gs-rest-service',
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
type: 'spring-guide',
|
|
223
|
-
title: 'Building an Application with Spring Boot',
|
|
224
|
-
description: 'Apprendre à construire une application avec une configuration minimale',
|
|
225
|
-
category: 'Getting Started',
|
|
226
|
-
url: 'https://spring.io/guides/gs/spring-boot/',
|
|
227
|
-
id: 'gs-spring-boot',
|
|
228
|
-
},
|
|
229
|
-
{
|
|
230
|
-
type: 'spring-guide',
|
|
231
|
-
title: 'Accessing Data with JPA',
|
|
232
|
-
description: 'Apprendre à travailler avec la persistance de données JPA',
|
|
233
|
-
category: 'Data',
|
|
234
|
-
url: 'https://spring.io/guides/gs/accessing-data-jpa/',
|
|
235
|
-
id: 'gs-accessing-data-jpa',
|
|
236
|
-
},
|
|
237
|
-
{
|
|
238
|
-
type: 'spring-guide',
|
|
239
|
-
title: 'Securing a Web Application',
|
|
240
|
-
description: 'Apprendre à protéger votre application web avec Spring Security',
|
|
241
|
-
category: 'Security',
|
|
242
|
-
url: 'https://spring.io/guides/gs/securing-web/',
|
|
243
|
-
id: 'gs-securing-web',
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
type: 'spring-guide',
|
|
247
|
-
title: 'Building a RESTful Web Service with Spring Boot Actuator',
|
|
248
|
-
description: 'Apprendre à créer un service prêt pour la production',
|
|
249
|
-
category: 'Production',
|
|
250
|
-
url: 'https://spring.io/guides/gs/actuator-service/',
|
|
251
|
-
id: 'gs-actuator-service',
|
|
252
|
-
},
|
|
253
|
-
{
|
|
254
|
-
type: 'spring-guide',
|
|
255
|
-
title: 'Testing the Web Layer',
|
|
256
|
-
description: 'Apprendre à tester les applications Spring Boot',
|
|
257
|
-
category: 'Testing',
|
|
258
|
-
url: 'https://spring.io/guides/gs/testing-web/',
|
|
259
|
-
id: 'gs-testing-web',
|
|
260
|
-
},
|
|
261
|
-
{
|
|
262
|
-
type: 'spring-guide',
|
|
263
|
-
title: 'Building a Reactive RESTful Web Service',
|
|
264
|
-
description: 'Créer des services web réactifs avec Spring WebFlux',
|
|
265
|
-
category: 'Reactive',
|
|
266
|
-
url: 'https://spring.io/guides/gs/reactive-rest-service/',
|
|
267
|
-
id: 'gs-reactive-rest-service',
|
|
268
|
-
},
|
|
269
|
-
{
|
|
270
|
-
type: 'spring-guide',
|
|
271
|
-
title: 'Consuming a RESTful Web Service',
|
|
272
|
-
description: 'Apprendre à récupérer des données depuis un endpoint REST',
|
|
273
|
-
category: 'Web',
|
|
274
|
-
url: 'https://spring.io/guides/gs/consuming-rest/',
|
|
275
|
-
id: 'gs-consuming-rest',
|
|
276
|
-
},
|
|
277
|
-
];
|
|
278
|
-
}
|
|
279
|
-
async searchDocumentation(query, docType = 'all', limit = 10) {
|
|
280
|
-
const results = [];
|
|
281
|
-
try {
|
|
282
|
-
// Recherche dans les guides
|
|
283
|
-
if (docType === 'all' || docType === 'guides') {
|
|
284
|
-
const guideResults = await this.searchGuides(query, Math.ceil(limit / 3));
|
|
285
|
-
results.push(...guideResults);
|
|
286
|
-
}
|
|
287
|
-
// Recherche dans la documentation de référence
|
|
288
|
-
if (docType === 'all' || docType === 'reference') {
|
|
289
|
-
const refResults = await this.searchReference(query, Math.ceil(limit / 3));
|
|
290
|
-
results.push(...refResults);
|
|
291
|
-
}
|
|
292
|
-
// Recherche dans l'API documentation
|
|
293
|
-
if (docType === 'all' || docType === 'api') {
|
|
294
|
-
const apiResults = await this.searchAPI(query, Math.ceil(limit / 3));
|
|
295
|
-
results.push(...apiResults);
|
|
296
|
-
}
|
|
297
|
-
return results.slice(0, limit);
|
|
298
|
-
}
|
|
299
|
-
catch (error) {
|
|
300
|
-
console.error('Erreur lors de la recherche dans la documentation:', error);
|
|
301
|
-
throw new Error('Impossible de rechercher dans la documentation Spring Boot');
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
/**
|
|
305
|
-
* Récupère un guide Spring Boot spécifique
|
|
306
|
-
*/
|
|
307
|
-
async getGuide(guideId) {
|
|
308
|
-
console.log(`Récupération du guide: ${guideId}`);
|
|
309
|
-
// Fonction helper pour fetch avec timeout
|
|
310
|
-
const fetchWithTimeout = async (url, timeout = 10000) => {
|
|
311
|
-
const controller = new AbortController();
|
|
312
|
-
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
313
|
-
try {
|
|
314
|
-
const response = await fetch(url, {
|
|
315
|
-
signal: controller.signal,
|
|
316
|
-
headers: {
|
|
317
|
-
'User-Agent': 'Spring-Docs-MCP/1.0',
|
|
318
|
-
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
|
|
319
|
-
}
|
|
320
|
-
});
|
|
321
|
-
clearTimeout(timeoutId);
|
|
322
|
-
return response;
|
|
323
|
-
}
|
|
324
|
-
catch (error) {
|
|
325
|
-
clearTimeout(timeoutId);
|
|
326
|
-
throw error;
|
|
327
|
-
}
|
|
328
|
-
};
|
|
329
|
-
try {
|
|
330
|
-
let content = '';
|
|
331
|
-
let sourceUrl = '';
|
|
332
|
-
// 1. Essayer d'abord spring.io/guides
|
|
333
|
-
try {
|
|
334
|
-
console.log(`Tentative 1: spring.io/guides/${guideId}/`);
|
|
335
|
-
const url1 = `https://spring.io/guides/${guideId}/`;
|
|
336
|
-
const response1 = await fetchWithTimeout(url1);
|
|
337
|
-
if (response1.ok) {
|
|
338
|
-
content = await response1.text();
|
|
339
|
-
sourceUrl = url1;
|
|
340
|
-
console.log(`✅ Succès avec spring.io (${content.length} chars)`);
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
console.log(`❌ spring.io failed: ${response1.status}`);
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
catch (error) {
|
|
347
|
-
console.log(`❌ spring.io error:`, error instanceof Error ? error.message : 'Unknown error');
|
|
348
|
-
}
|
|
349
|
-
// 2. Si échec, essayer GitHub raw
|
|
350
|
-
if (!content) {
|
|
351
|
-
try {
|
|
352
|
-
console.log(`Tentative 2: GitHub raw/${guideId}/main/README.adoc`);
|
|
353
|
-
const url2 = `https://raw.githubusercontent.com/spring-guides/${guideId}/main/README.adoc`;
|
|
354
|
-
const response2 = await fetchWithTimeout(url2);
|
|
355
|
-
if (response2.ok) {
|
|
356
|
-
content = await response2.text();
|
|
357
|
-
sourceUrl = url2;
|
|
358
|
-
console.log(`✅ Succès avec GitHub raw (${content.length} chars)`);
|
|
359
|
-
}
|
|
360
|
-
else {
|
|
361
|
-
console.log(`❌ GitHub raw failed: ${response2.status}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
catch (error) {
|
|
365
|
-
console.log(`❌ GitHub raw error:`, error instanceof Error ? error.message : 'Unknown error');
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
// 3. Si échec, essayer GitHub blob
|
|
369
|
-
if (!content) {
|
|
370
|
-
try {
|
|
371
|
-
console.log(`Tentative 3: GitHub blob/${guideId}/blob/main/README.adoc`);
|
|
372
|
-
const url3 = `https://github.com/spring-guides/${guideId}/blob/main/README.adoc`;
|
|
373
|
-
const response3 = await fetchWithTimeout(url3);
|
|
374
|
-
if (response3.ok) {
|
|
375
|
-
content = await response3.text();
|
|
376
|
-
sourceUrl = url3;
|
|
377
|
-
console.log(`✅ Succès avec GitHub blob (${content.length} chars)`);
|
|
378
|
-
}
|
|
379
|
-
else {
|
|
380
|
-
console.log(`❌ GitHub blob failed: ${response3.status}`);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
catch (error) {
|
|
384
|
-
console.log(`❌ GitHub blob error:`, error instanceof Error ? error.message : 'Unknown error');
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
if (!content) {
|
|
388
|
-
return `# Guide Spring: ${guideId}
|
|
389
|
-
|
|
390
|
-
❌ **Guide non trouvé**
|
|
391
|
-
|
|
392
|
-
Le guide "${guideId}" n'a pas pu être récupéré depuis aucune source.
|
|
393
|
-
|
|
394
|
-
## 📚 Guides populaires disponibles:
|
|
395
|
-
- \`gs-rest-service\` - Building a RESTful Web Service
|
|
396
|
-
- \`gs-spring-boot\` - Building an Application with Spring Boot
|
|
397
|
-
- \`gs-accessing-data-jpa\` - Accessing Data with JPA
|
|
398
|
-
- \`gs-securing-web\` - Securing a Web Application
|
|
399
|
-
- \`gs-actuator-service\` - Building a RESTful Web Service with Spring Boot Actuator
|
|
400
|
-
- \`gs-testing-web\` - Testing the Web Layer
|
|
401
|
-
|
|
402
|
-
## 🔧 Outils alternatifs:
|
|
403
|
-
1. \`get_all_spring_guides\` - Voir tous les guides disponibles
|
|
404
|
-
2. \`search_spring_docs\` - Rechercher dans la documentation
|
|
405
|
-
|
|
406
|
-
## 💡 Format d'identifiant:
|
|
407
|
-
L'identifiant doit être au format: \`gs-nom-du-guide\``;
|
|
408
|
-
}
|
|
409
|
-
// Traitement du contenu selon le type
|
|
410
|
-
if (content.includes('<html') || content.includes('<!DOCTYPE')) {
|
|
411
|
-
// C'est du HTML (spring.io)
|
|
412
|
-
console.log('Processing HTML content...');
|
|
413
|
-
const $ = cheerio.load(content);
|
|
414
|
-
// Chercher le contenu principal avec différents sélecteurs
|
|
415
|
-
let mainContent = $('.guide-content, .content, main, .container .row .col-md-8, .markdown-body, article').first();
|
|
416
|
-
if (mainContent.length === 0) {
|
|
417
|
-
// Fallback: chercher le titre et le contenu
|
|
418
|
-
const title = $('h1, .guide-title').first().text().trim();
|
|
419
|
-
const bodyContent = $('.guide-body, .guide-content, .content').first();
|
|
420
|
-
if (bodyContent.length > 0) {
|
|
421
|
-
mainContent = bodyContent;
|
|
422
|
-
}
|
|
423
|
-
else {
|
|
424
|
-
mainContent = $('body');
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
if (mainContent.length > 0) {
|
|
428
|
-
// Nettoyer le HTML
|
|
429
|
-
this.cleanHtml($, mainContent);
|
|
430
|
-
const markdown = this.turndownService.turndown(mainContent.html() || '');
|
|
431
|
-
return `# Guide Spring: ${guideId}
|
|
432
|
-
|
|
433
|
-
*Source: ${sourceUrl}*
|
|
434
|
-
|
|
435
|
-
${markdown}`;
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
// Si c'est de l'AsciiDoc ou du texte brut
|
|
439
|
-
if (content.includes('=') || content.includes(':toc:') || content.includes('== ') || content.includes('=== ')) {
|
|
440
|
-
console.log('Processing AsciiDoc content...');
|
|
441
|
-
// Traitement spécial pour AsciiDoc
|
|
442
|
-
let processedContent = content;
|
|
443
|
-
// Convertir les titres AsciiDoc en Markdown
|
|
444
|
-
processedContent = processedContent
|
|
445
|
-
.replace(/^= (.+)$/gm, '# $1')
|
|
446
|
-
.replace(/^== (.+)$/gm, '## $1')
|
|
447
|
-
.replace(/^=== (.+)$/gm, '### $1')
|
|
448
|
-
.replace(/^==== (.+)$/gm, '#### $1')
|
|
449
|
-
.replace(/^\[source,(\w+)\]$/gm, '')
|
|
450
|
-
.replace(/^----$/gm, '```')
|
|
451
|
-
.replace(/^\+\+\+\+$/gm, '```');
|
|
452
|
-
return `# Guide Spring: ${guideId}
|
|
453
|
-
|
|
454
|
-
*Source: ${sourceUrl}*
|
|
455
|
-
|
|
456
|
-
${processedContent}`;
|
|
457
|
-
}
|
|
458
|
-
// Contenu par défaut (texte brut)
|
|
459
|
-
console.log('Processing plain text content...');
|
|
460
|
-
return `# Guide Spring: ${guideId}
|
|
461
|
-
|
|
462
|
-
*Source: ${sourceUrl}*
|
|
463
|
-
|
|
464
|
-
\`\`\`
|
|
465
|
-
${content}
|
|
466
|
-
\`\`\``;
|
|
467
|
-
}
|
|
468
|
-
catch (error) {
|
|
469
|
-
console.error(`Erreur lors de la récupération du guide ${guideId}:`, error);
|
|
470
|
-
return `# Guide Spring: ${guideId}
|
|
471
|
-
|
|
472
|
-
❌ **Erreur lors de la récupération du guide**
|
|
473
|
-
|
|
474
|
-
Le guide "${guideId}" n'a pas pu être récupéré.
|
|
475
|
-
|
|
476
|
-
## 🔧 Solutions possibles:
|
|
477
|
-
1. Vérifiez l'identifiant du guide (format: \`gs-nom-du-guide\`)
|
|
478
|
-
2. Utilisez \`get_all_spring_guides\` pour voir tous les guides disponibles
|
|
479
|
-
3. Utilisez \`search_spring_docs\` pour rechercher dans la documentation
|
|
480
|
-
|
|
481
|
-
## 📚 Guides populaires:
|
|
482
|
-
- \`gs-rest-service\` - Creating a RESTful Web Service
|
|
483
|
-
- \`gs-spring-boot\` - Building an Application with Spring Boot
|
|
484
|
-
- \`gs-accessing-data-jpa\` - Accessing Data with JPA
|
|
485
|
-
- \`gs-securing-web\` - Securing a Web Application
|
|
486
|
-
|
|
487
|
-
**Erreur technique:** ${error instanceof Error ? error.message : 'Erreur inconnue'}`;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
/**
|
|
491
|
-
* Récupère une section de la documentation de référence
|
|
492
|
-
*/
|
|
493
|
-
async getReference(section, subsection) {
|
|
494
|
-
try {
|
|
495
|
-
let url = `${this.baseUrl}/spring-boot/docs/${this.springBootVersion}/reference/html/`;
|
|
496
|
-
if (subsection) {
|
|
497
|
-
url += `${section}.html#${subsection}`;
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
url += `${section}.html`;
|
|
501
|
-
}
|
|
502
|
-
const response = await fetch(url);
|
|
503
|
-
if (!response.ok) {
|
|
504
|
-
throw new Error(`Section de référence non trouvée: ${section}`);
|
|
505
|
-
}
|
|
506
|
-
const html = await response.text();
|
|
507
|
-
const $ = cheerio.load(html);
|
|
508
|
-
// Extrait le contenu principal
|
|
509
|
-
const content = $('.content, .section, main').first();
|
|
510
|
-
if (content.length === 0) {
|
|
511
|
-
throw new Error('Contenu de la section non trouvé');
|
|
512
|
-
}
|
|
513
|
-
this.cleanHtml($, content);
|
|
514
|
-
const markdown = this.turndownService.turndown(content.html() || '');
|
|
515
|
-
return `# Spring Boot Reference: ${section}\n\n${markdown}`;
|
|
516
|
-
}
|
|
517
|
-
catch (error) {
|
|
518
|
-
console.error(`Erreur lors de la récupération de la référence ${section}:`, error);
|
|
519
|
-
throw new Error(`Impossible de récupérer la section de référence: ${section}`);
|
|
520
|
-
}
|
|
521
|
-
}
|
|
522
|
-
/**
|
|
523
|
-
* Recherche des concepts Spring Boot
|
|
524
|
-
*/
|
|
525
|
-
async searchConcepts(concept, category) {
|
|
526
|
-
try {
|
|
527
|
-
const concepts = this.getSpringBootConcepts();
|
|
528
|
-
const results = {};
|
|
529
|
-
for (const [cat, conceptList] of Object.entries(concepts)) {
|
|
530
|
-
if (category && cat !== category)
|
|
531
|
-
continue;
|
|
532
|
-
const matches = conceptList.filter((c) => c.name.toLowerCase().includes(concept.toLowerCase()) ||
|
|
533
|
-
c.description.toLowerCase().includes(concept.toLowerCase()) ||
|
|
534
|
-
c.keywords.some((k) => k.toLowerCase().includes(concept.toLowerCase())));
|
|
535
|
-
if (matches.length > 0) {
|
|
536
|
-
results[cat] = matches;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
return results;
|
|
540
|
-
}
|
|
541
|
-
catch (error) {
|
|
542
|
-
console.error('Erreur lors de la recherche de concepts:', error);
|
|
543
|
-
throw new Error('Impossible de rechercher les concepts Spring Boot');
|
|
544
|
-
}
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Recherche dans les guides Spring Boot
|
|
548
|
-
*/
|
|
549
|
-
async searchGuides(query, limit) {
|
|
550
|
-
// Liste des guides populaires Spring Boot
|
|
551
|
-
const guides = [
|
|
552
|
-
{ id: 'gs-rest-service', title: 'Building a RESTful Web Service', description: 'Learn how to create a RESTful web service with Spring Boot' },
|
|
553
|
-
{ id: 'gs-spring-boot', title: 'Building an Application with Spring Boot', description: 'Learn how to build an application with minimal configuration' },
|
|
554
|
-
{ id: 'gs-accessing-data-jpa', title: 'Accessing Data with JPA', description: 'Learn how to work with JPA data persistence' },
|
|
555
|
-
{ id: 'gs-securing-web', title: 'Securing a Web Application', description: 'Learn how to protect your web application with Spring Security' },
|
|
556
|
-
{ id: 'gs-consuming-rest', title: 'Consuming a RESTful Web Service', description: 'Learn how to retrieve data from a REST endpoint' },
|
|
557
|
-
{ id: 'gs-testing-web', title: 'Testing the Web Layer', description: 'Learn how to test Spring Boot applications' },
|
|
558
|
-
{ id: 'gs-actuator-service', title: 'Building a RESTful Web Service with Spring Boot Actuator', description: 'Learn how to create a production-ready service' },
|
|
559
|
-
];
|
|
560
|
-
return guides
|
|
561
|
-
.filter(guide => guide.title.toLowerCase().includes(query.toLowerCase()) ||
|
|
562
|
-
guide.description.toLowerCase().includes(query.toLowerCase()))
|
|
563
|
-
.slice(0, limit)
|
|
564
|
-
.map(guide => ({
|
|
565
|
-
type: 'guide',
|
|
566
|
-
title: guide.title,
|
|
567
|
-
url: `${this.baseUrl}/guides/${guide.id}/`,
|
|
568
|
-
description: guide.description,
|
|
569
|
-
id: guide.id,
|
|
570
|
-
}));
|
|
571
|
-
}
|
|
572
|
-
/**
|
|
573
|
-
* Recherche dans la documentation de référence
|
|
574
|
-
*/
|
|
575
|
-
async searchReference(query, limit) {
|
|
576
|
-
const sections = [
|
|
577
|
-
{ name: 'web', title: 'Web Applications', description: 'Building web applications with Spring Boot' },
|
|
578
|
-
{ name: 'data', title: 'Data Access', description: 'Working with databases and data sources' },
|
|
579
|
-
{ name: 'security', title: 'Security', description: 'Securing Spring Boot applications' },
|
|
580
|
-
{ name: 'actuator', title: 'Production-ready Features', description: 'Monitoring and managing applications' },
|
|
581
|
-
{ name: 'testing', title: 'Testing', description: 'Testing Spring Boot applications' },
|
|
582
|
-
{ name: 'configuration', title: 'Configuration', description: 'Configuring Spring Boot applications' },
|
|
583
|
-
];
|
|
584
|
-
return sections
|
|
585
|
-
.filter(section => section.title.toLowerCase().includes(query.toLowerCase()) ||
|
|
586
|
-
section.description.toLowerCase().includes(query.toLowerCase()))
|
|
587
|
-
.slice(0, limit)
|
|
588
|
-
.map(section => ({
|
|
589
|
-
type: 'reference',
|
|
590
|
-
title: section.title,
|
|
591
|
-
url: `${this.baseUrl}/spring-boot/docs/${this.springBootVersion}/reference/html/${section.name}.html`,
|
|
592
|
-
description: section.description,
|
|
593
|
-
section: section.name,
|
|
594
|
-
}));
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* Recherche dans la documentation de l'API
|
|
598
|
-
*/
|
|
599
|
-
async searchAPI(query, limit) {
|
|
600
|
-
const apiSections = [
|
|
601
|
-
{ name: 'Configuration Properties', description: 'Spring Boot configuration properties reference' },
|
|
602
|
-
{ name: 'Auto-configuration Classes', description: 'List of auto-configuration classes' },
|
|
603
|
-
{ name: 'Starter Dependencies', description: 'Available Spring Boot starters' },
|
|
604
|
-
{ name: 'Test Utilities', description: 'Testing utilities and annotations' },
|
|
605
|
-
];
|
|
606
|
-
return apiSections
|
|
607
|
-
.filter(section => section.name.toLowerCase().includes(query.toLowerCase()) ||
|
|
608
|
-
section.description.toLowerCase().includes(query.toLowerCase()))
|
|
609
|
-
.slice(0, limit)
|
|
610
|
-
.map(section => ({
|
|
611
|
-
type: 'api',
|
|
612
|
-
title: section.name,
|
|
613
|
-
url: `${this.baseUrl}/spring-boot/docs/${this.springBootVersion}/api/`,
|
|
614
|
-
description: section.description,
|
|
615
|
-
}));
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Nettoie le HTML pour une meilleure conversion en Markdown
|
|
619
|
-
*/
|
|
620
|
-
cleanHtml($, content) {
|
|
621
|
-
// Supprime les éléments indésirables
|
|
622
|
-
content.find('script, style, nav, .sidebar, .toc, .feedback').remove();
|
|
623
|
-
// Nettoie les classes CSS
|
|
624
|
-
content.find('*').each((index, element) => {
|
|
625
|
-
$(element).removeAttr('class').removeAttr('style').removeAttr('id');
|
|
626
|
-
});
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Base de connaissances des concepts Spring Boot
|
|
630
|
-
*/
|
|
631
|
-
getSpringBootConcepts() {
|
|
632
|
-
return {
|
|
633
|
-
core: [
|
|
634
|
-
{
|
|
635
|
-
name: 'Auto-configuration',
|
|
636
|
-
description: 'Mécanisme qui configure automatiquement Spring Boot basé sur les dépendances présentes',
|
|
637
|
-
keywords: ['auto-configuration', '@EnableAutoConfiguration', 'conditional'],
|
|
638
|
-
examples: ['@SpringBootApplication', '@Conditional', 'spring.factories'],
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
name: 'Profiles',
|
|
642
|
-
description: 'Permet de séparer les parties de la configuration d\'application pour différents environnements',
|
|
643
|
-
keywords: ['profiles', '@Profile', 'application.properties'],
|
|
644
|
-
examples: ['application-dev.properties', '@Profile("prod")', 'spring.profiles.active'],
|
|
645
|
-
},
|
|
646
|
-
{
|
|
647
|
-
name: 'Properties',
|
|
648
|
-
description: 'Système de configuration externalisée de Spring Boot',
|
|
649
|
-
keywords: ['properties', '@ConfigurationProperties', '@Value'],
|
|
650
|
-
examples: ['application.yml', '@ConfigurationProperties', 'Environment'],
|
|
651
|
-
},
|
|
652
|
-
],
|
|
653
|
-
web: [
|
|
654
|
-
{
|
|
655
|
-
name: 'Spring MVC',
|
|
656
|
-
description: 'Framework web intégré pour construire des applications web et des API REST',
|
|
657
|
-
keywords: ['mvc', '@Controller', '@RestController', 'web'],
|
|
658
|
-
examples: ['@GetMapping', '@PostMapping', '@RequestMapping'],
|
|
659
|
-
},
|
|
660
|
-
{
|
|
661
|
-
name: 'Embedded Server',
|
|
662
|
-
description: 'Serveur web intégré (Tomcat, Jetty, Undertow) pour déployer des applications standalone',
|
|
663
|
-
keywords: ['embedded', 'tomcat', 'jetty', 'server'],
|
|
664
|
-
examples: ['server.port', 'TomcatServletWebServerFactory'],
|
|
665
|
-
},
|
|
666
|
-
],
|
|
667
|
-
data: [
|
|
668
|
-
{
|
|
669
|
-
name: 'Spring Data JPA',
|
|
670
|
-
description: 'Simplifie l\'accès aux données avec JPA/Hibernate',
|
|
671
|
-
keywords: ['jpa', 'hibernate', '@Entity', '@Repository'],
|
|
672
|
-
examples: ['JpaRepository', '@Query', '@Transactional'],
|
|
673
|
-
},
|
|
674
|
-
{
|
|
675
|
-
name: 'Database Migration',
|
|
676
|
-
description: 'Gestion des évolutions de schéma de base de données',
|
|
677
|
-
keywords: ['flyway', 'liquibase', 'migration', 'schema'],
|
|
678
|
-
examples: ['db/migration', 'V1__Initial_schema.sql'],
|
|
679
|
-
},
|
|
680
|
-
],
|
|
681
|
-
security: [
|
|
682
|
-
{
|
|
683
|
-
name: 'Spring Security',
|
|
684
|
-
description: 'Framework de sécurité pour l\'authentification et l\'autorisation',
|
|
685
|
-
keywords: ['security', 'authentication', 'authorization', '@Secured'],
|
|
686
|
-
examples: ['SecurityConfig', '@PreAuthorize', 'HttpSecurity'],
|
|
687
|
-
},
|
|
688
|
-
],
|
|
689
|
-
testing: [
|
|
690
|
-
{
|
|
691
|
-
name: 'Test Slices',
|
|
692
|
-
description: 'Tests d\'intégration focalisés sur des couches spécifiques',
|
|
693
|
-
keywords: ['test', '@WebMvcTest', '@DataJpaTest', 'slice'],
|
|
694
|
-
examples: ['@SpringBootTest', '@TestConfiguration', 'TestRestTemplate'],
|
|
695
|
-
},
|
|
696
|
-
],
|
|
697
|
-
production: [
|
|
698
|
-
{
|
|
699
|
-
name: 'Actuator',
|
|
700
|
-
description: 'Fonctionnalités de monitoring et gestion pour les applications en production',
|
|
701
|
-
keywords: ['actuator', 'monitoring', 'health', 'metrics'],
|
|
702
|
-
examples: ['/actuator/health', '/actuator/metrics', 'HealthIndicator'],
|
|
703
|
-
},
|
|
704
|
-
],
|
|
705
|
-
};
|
|
706
|
-
}
|
|
707
|
-
}
|
|
708
|
-
//# sourceMappingURL=springboot-docs.js.map
|