@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 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
- See [Next.js Documentation](./DOCUMENTATION/NEXTJS.md) for complete guide.
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
- compatibilityRules
4
- } from "./chunk-WKYUK64P.js";
3
+ allCompatibilityRules
4
+ } from "./chunk-3NRMV3WL.js";
5
5
  import {
6
6
  pluginRegistry
7
- } from "./chunk-4VHPGJVU.js";
7
+ } from "./chunk-V75HW2AM.js";
8
+ import "./chunk-MQV3WNMH.js";
8
9
  import {
9
10
  logger
10
- } from "./chunk-QRFLHLFE.js";
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(compatibilityRules);
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
+ };