@configjs/cli 1.1.4 → 1.1.6
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.fr.md +1 -1
- package/README.md +16 -2
- package/dist/{check-XDGAGYOE.js → check-AJ4GD66M.js} +6 -5
- package/dist/chunk-3NRMV3WL.js +569 -0
- package/dist/chunk-HM2JWJOO.js +418 -0
- package/dist/{chunk-OAAGGK2H.js → chunk-JTTIDBSN.js} +361 -317
- package/dist/chunk-MQV3WNMH.js +114 -0
- package/dist/chunk-QBMH2K7B.js +386 -0
- package/dist/{chunk-BVXGN3AC.js → chunk-TVZWTKJU.js} +316 -224
- package/dist/{chunk-4VHPGJVU.js → chunk-V75HW2AM.js} +8557 -6661
- package/dist/cli.js +23 -9
- package/dist/{installed-IKSARZIK.js → installed-WA6I2IFD.js} +4 -3
- package/dist/{list-IJK225B3.js → list-Y7I5NUWT.js} +3 -2
- package/dist/nextjs-command-4G7N6VPP.js +59 -0
- package/dist/nextjs-installer-5C3VBCZE.js +80 -0
- package/dist/nextjs-setup-YYXNONJ6.js +100 -0
- package/dist/react-command-C47QFAJ5.js +59 -0
- package/dist/{remove-IIT34Y3T.js → remove-JBICRDXX.js} +4 -3
- package/dist/vite-installer-OPE53M3C.js +49 -0
- package/dist/vite-setup-B5TXMX72.js +51 -0
- package/dist/vue-command-6I7JVUI2.js +73 -0
- package/dist/vue-installer-2VSYMM6R.js +74 -0
- package/dist/vue-setup-WY57VJB3.js +91 -0
- package/package.json +5 -2
- package/dist/chunk-QRFLHLFE.js +0 -300
- package/dist/chunk-WKYUK64P.js +0 -308
- package/dist/install-APYIRHSN.js +0 -258
- package/dist/install-nextjs-C3LEKJLY.js +0 -353
package/README.fr.md
CHANGED
|
@@ -359,7 +359,7 @@ Les contributions sont les bienvenues ! Consultez [CONTRIBUTING.md](./docs/CONTR
|
|
|
359
359
|
|
|
360
360
|
### Développer un Plugin
|
|
361
361
|
|
|
362
|
-
Voir [PLUGIN_DEVELOPMENT.md](./docs/PLUGIN_DEVELOPMENT.md) pour créer vos propres plugins.
|
|
362
|
+
Voir [PLUGIN_DEVELOPMENT.md](./docs/PLUGIN_DEVELOPMENT.md) pour créer vos propres plugins (documentation de développement).
|
|
363
363
|
|
|
364
364
|
### Configuration de Développement
|
|
365
365
|
|
package/README.md
CHANGED
|
@@ -61,6 +61,12 @@ cd your-nextjs-project
|
|
|
61
61
|
npx @configjs/cli nextjs
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
### For Vue.js Projects
|
|
65
|
+
```bash
|
|
66
|
+
cd your-vue-project
|
|
67
|
+
npx @configjs/cli vue
|
|
68
|
+
```
|
|
69
|
+
|
|
64
70
|
That's it! ConfigJS will:
|
|
65
71
|
1. 🔍 **Detect** your environment (React/Next.js version, TypeScript, bundler)
|
|
66
72
|
2. 🎯 **Guide** you through library selection by category
|
|
@@ -298,7 +304,15 @@ ConfigJS fully supports Next.js projects with automatic detection of:
|
|
|
298
304
|
- Next.js-specific plugins (Image Optimization, Font Optimization, Middleware, API Routes)
|
|
299
305
|
- Compatible libraries adapted for Next.js (TailwindCSS, Shadcn/ui, React Hot Toast)
|
|
300
306
|
|
|
301
|
-
|
|
307
|
+
### Vue.js Support
|
|
308
|
+
|
|
309
|
+
ConfigJS fully supports Vue.js 3 projects with automatic detection of:
|
|
310
|
+
- **Composition API** vs **Options API**
|
|
311
|
+
- Vue.js-specific plugins (Vue Router, Pinia, VueUse, Vuetify)
|
|
312
|
+
- Compatible libraries adapted for Vue.js (TailwindCSS, Axios, ESLint Vue)
|
|
313
|
+
- Automatic project creation with Vite
|
|
314
|
+
|
|
315
|
+
See [Next.js Documentation](./DOCUMENTATION/NEXTJS.md) and [Vue.js Documentation](./DOCUMENTATION/VUE.md) for complete guides.
|
|
302
316
|
|
|
303
317
|
### CLI Options
|
|
304
318
|
|
|
@@ -379,7 +393,7 @@ Contributions are welcome! Check out [CONTRIBUTING.md](./docs/CONTRIBUTING.md) f
|
|
|
379
393
|
|
|
380
394
|
### Develop a Plugin
|
|
381
395
|
|
|
382
|
-
See [PLUGIN_DEVELOPMENT.md](./docs/PLUGIN_DEVELOPMENT.md) to create your own plugins.
|
|
396
|
+
See [PLUGIN_DEVELOPMENT.md](./docs/PLUGIN_DEVELOPMENT.md) to create your own plugins (development documentation).
|
|
383
397
|
|
|
384
398
|
### Development Setup
|
|
385
399
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CompatibilityValidator,
|
|
3
|
-
|
|
4
|
-
} from "./chunk-
|
|
3
|
+
allCompatibilityRules
|
|
4
|
+
} from "./chunk-3NRMV3WL.js";
|
|
5
5
|
import {
|
|
6
6
|
pluginRegistry
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-V75HW2AM.js";
|
|
8
|
+
import "./chunk-MQV3WNMH.js";
|
|
8
9
|
import {
|
|
9
10
|
logger
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-HM2JWJOO.js";
|
|
11
12
|
import "./chunk-QGM4M3NI.js";
|
|
12
13
|
|
|
13
14
|
// src/cli/commands/check.ts
|
|
@@ -71,7 +72,7 @@ async function checkCompatibility(options) {
|
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
console.log("\n\u{1F50D} Analyse de compatibilit\xE9...\n");
|
|
74
|
-
const validator = new CompatibilityValidator(
|
|
75
|
+
const validator = new CompatibilityValidator(allCompatibilityRules);
|
|
75
76
|
const validation = validator.validate(
|
|
76
77
|
selectedPlugins
|
|
77
78
|
);
|
|
@@ -0,0 +1,569 @@
|
|
|
1
|
+
import {
|
|
2
|
+
pluginRegistry
|
|
3
|
+
} from "./chunk-V75HW2AM.js";
|
|
4
|
+
import {
|
|
5
|
+
logger
|
|
6
|
+
} from "./chunk-HM2JWJOO.js";
|
|
7
|
+
|
|
8
|
+
// src/core/compatibility-generator.ts
|
|
9
|
+
function generateCompatibilityRules(plugins) {
|
|
10
|
+
logger.debug(
|
|
11
|
+
`Generating compatibility rules from ${plugins.length} plugin(s)`
|
|
12
|
+
);
|
|
13
|
+
const rules = [];
|
|
14
|
+
rules.push(...generateExclusiveRules(plugins));
|
|
15
|
+
rules.push(...generateConflictRules(plugins));
|
|
16
|
+
rules.push(...generateRequiresRules(plugins));
|
|
17
|
+
rules.push(...generateRecommendsRules(plugins));
|
|
18
|
+
logger.debug(`Generated ${rules.length} compatibility rule(s)`);
|
|
19
|
+
return rules;
|
|
20
|
+
}
|
|
21
|
+
function generateExclusiveRules(plugins) {
|
|
22
|
+
const rules = [];
|
|
23
|
+
const pluginsByCategory = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const plugin of plugins) {
|
|
25
|
+
const category = plugin.category;
|
|
26
|
+
if (!pluginsByCategory.has(category)) {
|
|
27
|
+
pluginsByCategory.set(category, []);
|
|
28
|
+
}
|
|
29
|
+
const arr = pluginsByCategory.get(category);
|
|
30
|
+
if (arr) {
|
|
31
|
+
arr.push(plugin);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const [category, categoryPlugins] of pluginsByCategory.entries()) {
|
|
35
|
+
if (categoryPlugins.length < 2) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const exclusiveCategories = [
|
|
39
|
+
"state" /* STATE */,
|
|
40
|
+
// Un seul state management
|
|
41
|
+
"routing" /* ROUTING */,
|
|
42
|
+
// Un seul routing
|
|
43
|
+
"css" /* CSS */
|
|
44
|
+
// Un seul framework CSS (peut être flexible selon le cas)
|
|
45
|
+
];
|
|
46
|
+
if (!exclusiveCategories.includes(category)) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
const pluginNames = categoryPlugins.map((p) => p.name);
|
|
50
|
+
const severity = category === "css" /* CSS */ ? "warning" : "error";
|
|
51
|
+
const allowOverride = category === "css" /* CSS */;
|
|
52
|
+
rules.push({
|
|
53
|
+
type: "EXCLUSIVE",
|
|
54
|
+
plugins: pluginNames,
|
|
55
|
+
reason: getExclusiveReason(category),
|
|
56
|
+
severity,
|
|
57
|
+
allowOverride
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return rules;
|
|
61
|
+
}
|
|
62
|
+
function getExclusiveReason(category) {
|
|
63
|
+
switch (category) {
|
|
64
|
+
case "state" /* STATE */:
|
|
65
|
+
return "Une seule solution de state management est recommand\xE9e";
|
|
66
|
+
case "routing" /* ROUTING */:
|
|
67
|
+
return "Un seul syst\xE8me de routing est recommand\xE9";
|
|
68
|
+
case "css" /* CSS */:
|
|
69
|
+
return "Approches CSS potentiellement conflictuelles";
|
|
70
|
+
default:
|
|
71
|
+
return "Ces plugins sont mutuellement exclusifs";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function generateConflictRules(plugins) {
|
|
75
|
+
const rules = [];
|
|
76
|
+
for (const plugin of plugins) {
|
|
77
|
+
if (!plugin.incompatibleWith || plugin.incompatibleWith.length === 0) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
for (const incompatiblePluginName of plugin.incompatibleWith) {
|
|
81
|
+
const incompatiblePlugin = plugins.find(
|
|
82
|
+
(p) => p.name === incompatiblePluginName
|
|
83
|
+
);
|
|
84
|
+
if (!incompatiblePlugin) {
|
|
85
|
+
logger.debug(
|
|
86
|
+
`Plugin ${plugin.name} declares incompatibleWith ${incompatiblePluginName}, but plugin not found in registry`
|
|
87
|
+
);
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
const commonFrameworks = plugin.frameworks.filter(
|
|
91
|
+
(f) => incompatiblePlugin.frameworks.includes(f)
|
|
92
|
+
);
|
|
93
|
+
const isCssConflict = plugin.category === "css" /* CSS */ && incompatiblePlugin.category === "css" /* CSS */;
|
|
94
|
+
const severity = isCssConflict ? "warning" : "error";
|
|
95
|
+
const allowOverride = isCssConflict;
|
|
96
|
+
if (commonFrameworks.length === 0) {
|
|
97
|
+
rules.push({
|
|
98
|
+
type: "CONFLICT",
|
|
99
|
+
plugins: [plugin.name, incompatiblePluginName],
|
|
100
|
+
reason: `${plugin.displayName} est incompatible avec ${incompatiblePlugin.displayName}`,
|
|
101
|
+
severity,
|
|
102
|
+
allowOverride
|
|
103
|
+
});
|
|
104
|
+
} else {
|
|
105
|
+
for (const framework of commonFrameworks) {
|
|
106
|
+
rules.push({
|
|
107
|
+
type: "CONFLICT",
|
|
108
|
+
plugins: [plugin.name, incompatiblePluginName],
|
|
109
|
+
framework,
|
|
110
|
+
reason: `${plugin.displayName} est incompatible avec ${incompatiblePlugin.displayName} pour ${framework}`,
|
|
111
|
+
severity,
|
|
112
|
+
allowOverride
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return rules;
|
|
119
|
+
}
|
|
120
|
+
function generateRequiresRules(plugins) {
|
|
121
|
+
const rules = [];
|
|
122
|
+
for (const plugin of plugins) {
|
|
123
|
+
if (!plugin.requires || plugin.requires.length === 0) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
for (const framework of plugin.frameworks) {
|
|
127
|
+
rules.push({
|
|
128
|
+
type: "REQUIRES",
|
|
129
|
+
plugin: plugin.name,
|
|
130
|
+
requires: plugin.requires,
|
|
131
|
+
framework,
|
|
132
|
+
reason: `${plugin.displayName} n\xE9cessite les d\xE9pendances suivantes: ${plugin.requires.join(", ")}`,
|
|
133
|
+
severity: "error",
|
|
134
|
+
allowOverride: false
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return rules;
|
|
139
|
+
}
|
|
140
|
+
function generateRecommendsRules(plugins) {
|
|
141
|
+
const rules = [];
|
|
142
|
+
for (const plugin of plugins) {
|
|
143
|
+
if (!plugin.recommends || plugin.recommends.length === 0) {
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
for (const framework of plugin.frameworks) {
|
|
147
|
+
rules.push({
|
|
148
|
+
type: "RECOMMENDS",
|
|
149
|
+
plugin: plugin.name,
|
|
150
|
+
recommends: plugin.recommends,
|
|
151
|
+
framework,
|
|
152
|
+
reason: `${plugin.displayName} recommande d'installer: ${plugin.recommends.join(", ")}`,
|
|
153
|
+
severity: "info"
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return rules;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/core/validator.ts
|
|
161
|
+
var CompatibilityValidator = class {
|
|
162
|
+
/**
|
|
163
|
+
* @param rules - Règles de compatibilité à appliquer
|
|
164
|
+
*/
|
|
165
|
+
constructor(rules) {
|
|
166
|
+
this.rules = rules;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Valide la compatibilité d'un ensemble de plugins
|
|
170
|
+
*
|
|
171
|
+
* @param plugins - Liste des plugins à valider
|
|
172
|
+
* @param ctx - Contexte du projet (optionnel, pour règles spécifiques framework)
|
|
173
|
+
* @returns Résultat de la validation avec erreurs, warnings et suggestions
|
|
174
|
+
*
|
|
175
|
+
* @example
|
|
176
|
+
* ```typescript
|
|
177
|
+
* const result = validator.validate([plugin1, plugin2, plugin3], ctx)
|
|
178
|
+
* if (!result.valid) {
|
|
179
|
+
* // Gérer les erreurs
|
|
180
|
+
* }
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
validate(plugins, ctx) {
|
|
184
|
+
logger.debug(`Validating ${plugins.length} plugin(s)`);
|
|
185
|
+
const pluginNames = new Set(plugins.map((p) => p.name));
|
|
186
|
+
const applicableRules = ctx ? this.rules.filter(
|
|
187
|
+
(rule) => !rule.framework || rule.framework === ctx.framework
|
|
188
|
+
) : this.rules.filter((rule) => !rule.framework);
|
|
189
|
+
const allConflicts = this.checkConflicts(
|
|
190
|
+
plugins,
|
|
191
|
+
pluginNames,
|
|
192
|
+
applicableRules
|
|
193
|
+
);
|
|
194
|
+
const conflictErrors = [];
|
|
195
|
+
const conflictWarnings = [];
|
|
196
|
+
for (const conflict of allConflicts) {
|
|
197
|
+
const rule = applicableRules.find(
|
|
198
|
+
(r) => r.type === "CONFLICT" && r.plugins?.every((p) => conflict.plugins?.includes(p))
|
|
199
|
+
);
|
|
200
|
+
if (rule?.severity === "error") {
|
|
201
|
+
conflictErrors.push(conflict);
|
|
202
|
+
} else {
|
|
203
|
+
conflictWarnings.push(conflict);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const frameworkConflicts = ctx ? this.checkFrameworkConflicts(plugins, pluginNames, ctx, applicableRules) : [];
|
|
207
|
+
const frameworkErrors = [];
|
|
208
|
+
const frameworkWarnings = [];
|
|
209
|
+
for (const conflict of frameworkConflicts) {
|
|
210
|
+
const rule = applicableRules.find(
|
|
211
|
+
(r) => r.type === "CONFLICT" && r.framework === ctx?.framework && r.plugins?.some((p) => conflict.plugins?.includes(p))
|
|
212
|
+
);
|
|
213
|
+
if (rule?.severity === "error") {
|
|
214
|
+
frameworkErrors.push(conflict);
|
|
215
|
+
} else {
|
|
216
|
+
frameworkWarnings.push(conflict);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const exclusivityResults = this.checkExclusivity(
|
|
220
|
+
plugins,
|
|
221
|
+
pluginNames,
|
|
222
|
+
applicableRules
|
|
223
|
+
);
|
|
224
|
+
const exclusivityErrors = [];
|
|
225
|
+
const exclusivityWarnings = [];
|
|
226
|
+
for (const result of exclusivityResults) {
|
|
227
|
+
const rule = applicableRules.find(
|
|
228
|
+
(r) => r.type === "EXCLUSIVE" && result.plugins?.every((p) => r.plugins?.includes(p))
|
|
229
|
+
);
|
|
230
|
+
if (rule?.severity === "warning") {
|
|
231
|
+
exclusivityWarnings.push(result);
|
|
232
|
+
} else {
|
|
233
|
+
exclusivityErrors.push(result);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
const errors = [
|
|
237
|
+
...exclusivityErrors,
|
|
238
|
+
...conflictErrors,
|
|
239
|
+
...this.checkDependencies(plugins, pluginNames, applicableRules, ctx),
|
|
240
|
+
...frameworkErrors
|
|
241
|
+
];
|
|
242
|
+
const warnings = [
|
|
243
|
+
...exclusivityWarnings,
|
|
244
|
+
...conflictWarnings,
|
|
245
|
+
...frameworkWarnings
|
|
246
|
+
];
|
|
247
|
+
const suggestions = this.checkRecommendations(
|
|
248
|
+
plugins,
|
|
249
|
+
pluginNames,
|
|
250
|
+
applicableRules
|
|
251
|
+
);
|
|
252
|
+
const valid = errors.length === 0;
|
|
253
|
+
logger.debug(`Validation result: ${valid ? "valid" : "invalid"}`, {
|
|
254
|
+
errors: errors.length,
|
|
255
|
+
warnings: warnings.length,
|
|
256
|
+
suggestions: suggestions.length
|
|
257
|
+
});
|
|
258
|
+
return {
|
|
259
|
+
valid,
|
|
260
|
+
errors,
|
|
261
|
+
warnings,
|
|
262
|
+
suggestions
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Vérifie les conflits avec le framework
|
|
267
|
+
*
|
|
268
|
+
* @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
|
|
269
|
+
* @param pluginNames - Set des noms de plugins pour lookup rapide
|
|
270
|
+
* @param ctx - Contexte du projet
|
|
271
|
+
* @param rules - Règles applicables
|
|
272
|
+
* @returns Liste des erreurs/warnings de conflit framework
|
|
273
|
+
*
|
|
274
|
+
* @internal
|
|
275
|
+
*/
|
|
276
|
+
checkFrameworkConflicts(_plugins, pluginNames, ctx, rules) {
|
|
277
|
+
const conflicts = [];
|
|
278
|
+
for (const rule of rules) {
|
|
279
|
+
if (rule.type !== "CONFLICT" || !rule.framework || rule.framework !== ctx.framework) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
if (rule.plugins && rule.plugins.length > 0) {
|
|
283
|
+
const conflictingPlugins = rule.plugins.filter(
|
|
284
|
+
(pluginName) => pluginNames.has(pluginName)
|
|
285
|
+
);
|
|
286
|
+
const isFrameworkIncompatible = rule.plugins.length === 1;
|
|
287
|
+
const shouldReportConflict = isFrameworkIncompatible ? conflictingPlugins.length > 0 : conflictingPlugins.length > 1;
|
|
288
|
+
if (shouldReportConflict) {
|
|
289
|
+
conflicts.push({
|
|
290
|
+
type: "CONFLICT",
|
|
291
|
+
plugins: conflictingPlugins,
|
|
292
|
+
message: rule.reason,
|
|
293
|
+
canOverride: rule.allowOverride ?? true
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return conflicts;
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Vérifie les règles d'exclusivité (EXCLUSIVE)
|
|
302
|
+
*
|
|
303
|
+
* @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
|
|
304
|
+
* @param pluginNames - Set des noms de plugins pour lookup rapide
|
|
305
|
+
* @param rules - Règles applicables
|
|
306
|
+
* @returns Liste des erreurs d'exclusivité
|
|
307
|
+
*
|
|
308
|
+
* @internal
|
|
309
|
+
*/
|
|
310
|
+
checkExclusivity(_plugins, pluginNames, rules = this.rules) {
|
|
311
|
+
const errors = [];
|
|
312
|
+
for (const rule of rules) {
|
|
313
|
+
if (rule.type !== "EXCLUSIVE" || !rule.plugins) {
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
316
|
+
const selectedExclusivePlugins = rule.plugins.filter(
|
|
317
|
+
(pluginName) => pluginNames.has(pluginName)
|
|
318
|
+
);
|
|
319
|
+
if (selectedExclusivePlugins.length > 1) {
|
|
320
|
+
errors.push({
|
|
321
|
+
type: "EXCLUSIVE",
|
|
322
|
+
plugins: selectedExclusivePlugins,
|
|
323
|
+
message: rule.reason,
|
|
324
|
+
canOverride: rule.allowOverride ?? false
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
return errors;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* Vérifie les conflits entre plugins (CONFLICT)
|
|
332
|
+
*
|
|
333
|
+
* @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
|
|
334
|
+
* @param pluginNames - Set des noms de plugins pour lookup rapide
|
|
335
|
+
* @param rules - Règles applicables
|
|
336
|
+
* @returns Liste des warnings/erreurs de conflit
|
|
337
|
+
*
|
|
338
|
+
* @internal
|
|
339
|
+
*/
|
|
340
|
+
checkConflicts(_plugins, pluginNames, rules = this.rules) {
|
|
341
|
+
const conflicts = [];
|
|
342
|
+
for (const rule of rules) {
|
|
343
|
+
if (rule.framework) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (rule.type !== "CONFLICT" || !rule.plugins) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const conflictingPlugins = rule.plugins.filter(
|
|
350
|
+
(pluginName) => pluginNames.has(pluginName)
|
|
351
|
+
);
|
|
352
|
+
if (conflictingPlugins.length > 1) {
|
|
353
|
+
conflicts.push({
|
|
354
|
+
type: "CONFLICT",
|
|
355
|
+
plugins: conflictingPlugins,
|
|
356
|
+
message: rule.reason,
|
|
357
|
+
canOverride: rule.allowOverride ?? true
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return conflicts;
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Vérifie les dépendances requises (REQUIRES)
|
|
365
|
+
*
|
|
366
|
+
* @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
|
|
367
|
+
* @param pluginNames - Set des noms de plugins pour lookup rapide
|
|
368
|
+
* @param rules - Règles applicables
|
|
369
|
+
* @param ctx - Contexte du projet (optionnel)
|
|
370
|
+
* @returns Liste des erreurs de dépendances manquantes
|
|
371
|
+
*
|
|
372
|
+
* @internal
|
|
373
|
+
*/
|
|
374
|
+
checkDependencies(_plugins, pluginNames, rules = this.rules, ctx) {
|
|
375
|
+
const errors = [];
|
|
376
|
+
for (const rule of rules) {
|
|
377
|
+
if (rule.type !== "REQUIRES" || !rule.plugin || !rule.requires) {
|
|
378
|
+
continue;
|
|
379
|
+
}
|
|
380
|
+
if (!pluginNames.has(rule.plugin)) {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
const missingDependencies = [];
|
|
384
|
+
for (const dep of rule.requires) {
|
|
385
|
+
const pluginName = dep.split("@")[0];
|
|
386
|
+
if (!pluginName) {
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
if (dep.includes("@") && ctx) {
|
|
390
|
+
const allDeps = { ...ctx.dependencies, ...ctx.devDependencies };
|
|
391
|
+
if (!allDeps[pluginName]) {
|
|
392
|
+
missingDependencies.push(dep);
|
|
393
|
+
}
|
|
394
|
+
} else {
|
|
395
|
+
if (!pluginNames.has(pluginName)) {
|
|
396
|
+
missingDependencies.push(dep);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
if (missingDependencies.length > 0) {
|
|
401
|
+
errors.push({
|
|
402
|
+
type: "REQUIRES",
|
|
403
|
+
plugin: rule.plugin,
|
|
404
|
+
required: missingDependencies.join(", "),
|
|
405
|
+
message: `${rule.plugin} requires: ${missingDependencies.join(", ")}. ${rule.reason}`,
|
|
406
|
+
canOverride: rule.allowOverride ?? false
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
return errors;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Vérifie les recommandations (RECOMMENDS)
|
|
414
|
+
*
|
|
415
|
+
* @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
|
|
416
|
+
* @param pluginNames - Set des noms de plugins pour lookup rapide
|
|
417
|
+
* @param rules - Règles applicables
|
|
418
|
+
* @returns Liste des suggestions de plugins recommandés
|
|
419
|
+
*
|
|
420
|
+
* @internal
|
|
421
|
+
*/
|
|
422
|
+
checkRecommendations(_plugins, pluginNames, rules = this.rules) {
|
|
423
|
+
const suggestions = [];
|
|
424
|
+
for (const rule of rules) {
|
|
425
|
+
if (rule.type !== "RECOMMENDS" || !rule.plugin || !rule.recommends) {
|
|
426
|
+
continue;
|
|
427
|
+
}
|
|
428
|
+
if (!pluginNames.has(rule.plugin)) {
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
const missingRecommendations = rule.recommends.filter(
|
|
432
|
+
(rec) => !pluginNames.has(rec)
|
|
433
|
+
);
|
|
434
|
+
if (missingRecommendations.length > 0) {
|
|
435
|
+
suggestions.push(
|
|
436
|
+
`${rule.plugin} recommends: ${missingRecommendations.join(", ")}. ${rule.reason}`
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return suggestions;
|
|
441
|
+
}
|
|
442
|
+
};
|
|
443
|
+
var compatibilityRules = generateCompatibilityRules(pluginRegistry);
|
|
444
|
+
var additionalCompatibilityRules = [
|
|
445
|
+
// ====================================================================
|
|
446
|
+
// Règles spécifiques Next.js
|
|
447
|
+
// ====================================================================
|
|
448
|
+
// React Router incompatible avec Next.js (routing intégré)
|
|
449
|
+
{
|
|
450
|
+
type: "CONFLICT",
|
|
451
|
+
plugins: ["react-router-dom"],
|
|
452
|
+
framework: "nextjs",
|
|
453
|
+
reason: "React Router est incompatible avec Next.js. Next.js a son propre syst\xE8me de routing int\xE9gr\xE9.",
|
|
454
|
+
severity: "error",
|
|
455
|
+
allowOverride: false
|
|
456
|
+
},
|
|
457
|
+
// Framer Motion peut causer des problèmes SSR avec Next.js
|
|
458
|
+
{
|
|
459
|
+
type: "CONFLICT",
|
|
460
|
+
plugins: ["framer-motion"],
|
|
461
|
+
framework: "nextjs",
|
|
462
|
+
reason: "Framer Motion peut causer des probl\xE8mes avec le Server-Side Rendering (SSR) de Next.js. Utilisez des alternatives compatibles SSR ou configurez correctement le dynamic import.",
|
|
463
|
+
severity: "warning",
|
|
464
|
+
allowOverride: true
|
|
465
|
+
},
|
|
466
|
+
// Shadcn/ui nécessite une configuration spéciale pour Next.js
|
|
467
|
+
{
|
|
468
|
+
type: "RECOMMENDS",
|
|
469
|
+
plugin: "shadcn-ui",
|
|
470
|
+
recommends: ["shadcn-ui-nextjs"],
|
|
471
|
+
framework: "nextjs",
|
|
472
|
+
reason: "Pour Next.js, utilisez la variante shadcn-ui-nextjs qui est optimis\xE9e pour React Server Components.",
|
|
473
|
+
severity: "info"
|
|
474
|
+
},
|
|
475
|
+
// ====================================================================
|
|
476
|
+
// Règles spécifiques Vue.js
|
|
477
|
+
// ====================================================================
|
|
478
|
+
// React Router incompatible avec Vue.js (utiliser Vue Router)
|
|
479
|
+
{
|
|
480
|
+
type: "CONFLICT",
|
|
481
|
+
plugins: ["react-router-dom"],
|
|
482
|
+
framework: "vue",
|
|
483
|
+
reason: "React Router est incompatible avec Vue.js. Utilisez Vue Router (vue-router) pour Vue.js.",
|
|
484
|
+
severity: "error",
|
|
485
|
+
allowOverride: false
|
|
486
|
+
},
|
|
487
|
+
// State management React incompatible avec Vue.js
|
|
488
|
+
{
|
|
489
|
+
type: "CONFLICT",
|
|
490
|
+
plugins: ["zustand", "@reduxjs/toolkit", "jotai"],
|
|
491
|
+
framework: "vue",
|
|
492
|
+
reason: "Zustand, Redux Toolkit et Jotai sont sp\xE9cifiques \xE0 React. Pour Vue.js, utilisez Pinia (state management officiel).",
|
|
493
|
+
severity: "error",
|
|
494
|
+
allowOverride: false
|
|
495
|
+
},
|
|
496
|
+
// Shadcn/ui incompatible avec Vue.js (spécifique React)
|
|
497
|
+
{
|
|
498
|
+
type: "CONFLICT",
|
|
499
|
+
plugins: ["shadcn-ui"],
|
|
500
|
+
framework: "vue",
|
|
501
|
+
reason: "Shadcn/ui est sp\xE9cifique \xE0 React. Pour Vue.js, utilisez Vuetify ou Quasar (frameworks UI Vue.js).",
|
|
502
|
+
severity: "error",
|
|
503
|
+
allowOverride: false
|
|
504
|
+
},
|
|
505
|
+
// Pinia nécessite Vue 3
|
|
506
|
+
{
|
|
507
|
+
type: "REQUIRES",
|
|
508
|
+
plugin: "pinia",
|
|
509
|
+
requires: ["vue@^3.0.0"],
|
|
510
|
+
framework: "vue",
|
|
511
|
+
reason: "Pinia n\xE9cessite Vue 3. Vue 2 n'est plus support\xE9.",
|
|
512
|
+
severity: "error",
|
|
513
|
+
allowOverride: false
|
|
514
|
+
},
|
|
515
|
+
// Vue Router version doit correspondre à Vue version
|
|
516
|
+
{
|
|
517
|
+
type: "CONFLICT",
|
|
518
|
+
plugins: ["vue-router"],
|
|
519
|
+
framework: "vue",
|
|
520
|
+
reason: "Assurez-vous que la version de Vue Router correspond \xE0 la version de Vue.js (Vue Router 4 pour Vue 3).",
|
|
521
|
+
severity: "warning",
|
|
522
|
+
allowOverride: true
|
|
523
|
+
}
|
|
524
|
+
];
|
|
525
|
+
function normalizeArray(values) {
|
|
526
|
+
if (!values || values.length === 0) {
|
|
527
|
+
return [];
|
|
528
|
+
}
|
|
529
|
+
return [...values].sort();
|
|
530
|
+
}
|
|
531
|
+
function buildRuleKey(rule) {
|
|
532
|
+
const plugins = normalizeArray(rule.plugins).join("|");
|
|
533
|
+
const requires = normalizeArray(rule.requires).join("|");
|
|
534
|
+
const recommends = normalizeArray(rule.recommends).join("|");
|
|
535
|
+
return [
|
|
536
|
+
rule.type,
|
|
537
|
+
rule.framework ?? "*",
|
|
538
|
+
rule.plugin ?? "",
|
|
539
|
+
plugins,
|
|
540
|
+
requires,
|
|
541
|
+
recommends,
|
|
542
|
+
rule.severity,
|
|
543
|
+
String(rule.allowOverride ?? false),
|
|
544
|
+
String(rule.autoInstall ?? false),
|
|
545
|
+
String(rule.prompt ?? false)
|
|
546
|
+
].join("::");
|
|
547
|
+
}
|
|
548
|
+
function deduplicateCompatibilityRules(rules) {
|
|
549
|
+
const seen = /* @__PURE__ */ new Set();
|
|
550
|
+
const deduplicated = [];
|
|
551
|
+
for (const rule of rules) {
|
|
552
|
+
const key = buildRuleKey(rule);
|
|
553
|
+
if (seen.has(key)) {
|
|
554
|
+
continue;
|
|
555
|
+
}
|
|
556
|
+
seen.add(key);
|
|
557
|
+
deduplicated.push(rule);
|
|
558
|
+
}
|
|
559
|
+
return deduplicated;
|
|
560
|
+
}
|
|
561
|
+
var allCompatibilityRules = deduplicateCompatibilityRules([
|
|
562
|
+
...compatibilityRules,
|
|
563
|
+
...additionalCompatibilityRules
|
|
564
|
+
]);
|
|
565
|
+
|
|
566
|
+
export {
|
|
567
|
+
CompatibilityValidator,
|
|
568
|
+
allCompatibilityRules
|
|
569
|
+
};
|