@configjs/cli 1.1.2 → 1.1.4

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.
@@ -24,6 +24,12 @@ function detectFramework(pkg) {
24
24
  ...pkg["dependencies"] || {},
25
25
  ...pkg["devDependencies"] || {}
26
26
  };
27
+ if (deps["next"]) {
28
+ return {
29
+ framework: "nextjs",
30
+ version: deps["next"].replace(/[\^~]/, "")
31
+ };
32
+ }
27
33
  if (deps["react"]) {
28
34
  return {
29
35
  framework: "react",
@@ -43,7 +49,7 @@ function detectFramework(pkg) {
43
49
  };
44
50
  }
45
51
  throw new DetectionError(
46
- "No supported framework detected. Supported frameworks: React, Vue, Svelte",
52
+ "No supported framework detected. Supported frameworks: Next.js, React, Vue, Svelte",
47
53
  { dependencies: Object.keys(deps) }
48
54
  );
49
55
  }
@@ -52,6 +58,15 @@ async function detectBundler(projectRoot, pkg) {
52
58
  ...pkg["dependencies"] || {},
53
59
  ...pkg["devDependencies"] || {}
54
60
  };
61
+ if (deps["next"]) {
62
+ const nextConfigExists = await checkPathExists(join(projectRoot, "next.config.js")) || await checkPathExists(join(projectRoot, "next.config.ts")) || await checkPathExists(join(projectRoot, "next.config.mjs")) || await checkPathExists(join(projectRoot, "next.config.cjs"));
63
+ if (nextConfigExists) {
64
+ return {
65
+ bundler: "nextjs",
66
+ version: deps["next"].replace(/[\^~]/, "")
67
+ };
68
+ }
69
+ }
55
70
  if (deps["vite"]) {
56
71
  const viteConfigExists = await checkPathExists(join(projectRoot, "vite.config.js")) || await checkPathExists(join(projectRoot, "vite.config.ts")) || await checkPathExists(join(projectRoot, "vite.config.mjs")) || await checkPathExists(join(projectRoot, "vite.config.cjs"));
57
72
  if (viteConfigExists) {
@@ -132,6 +147,21 @@ async function detectPublicDir(projectRoot) {
132
147
  }
133
148
  return "public";
134
149
  }
150
+ async function detectNextjsRouter(projectRoot, srcDir) {
151
+ const appDirInSrc = join(projectRoot, srcDir, "app");
152
+ const pagesDirInSrc = join(projectRoot, srcDir, "pages");
153
+ const appDirAtRoot = join(projectRoot, "app");
154
+ const pagesDirAtRoot = join(projectRoot, "pages");
155
+ const appDirExists = await checkPathExists(appDirInSrc) || await checkPathExists(appDirAtRoot);
156
+ const pagesDirExists = await checkPathExists(pagesDirInSrc) || await checkPathExists(pagesDirAtRoot);
157
+ if (appDirExists) {
158
+ return "app";
159
+ }
160
+ if (pagesDirExists) {
161
+ return "pages";
162
+ }
163
+ return void 0;
164
+ }
135
165
  async function detectGit(projectRoot) {
136
166
  const gitDir = join(projectRoot, ".git");
137
167
  const hasGit = await checkPathExists(gitDir);
@@ -197,6 +227,7 @@ async function detectContext(projectRoot) {
197
227
  detectGit(fullPath)
198
228
  ]);
199
229
  const lockfile = await detectLockfile(fullPath, packageManager);
230
+ const nextjsRouter = frameworkInfo.framework === "nextjs" ? await detectNextjsRouter(fullPath, srcDir) : void 0;
200
231
  const dependencies = pkg["dependencies"] || {};
201
232
  const devDependencies = pkg["devDependencies"] || {};
202
233
  const context = {
@@ -224,7 +255,9 @@ async function detectContext(projectRoot) {
224
255
  devDependencies,
225
256
  // Git
226
257
  hasGit: gitInfo.hasGit,
227
- gitHooksPath: gitInfo.gitHooksPath
258
+ gitHooksPath: gitInfo.gitHooksPath,
259
+ // Next.js specific
260
+ nextjsRouter
228
261
  };
229
262
  detectionCache.set(fullPath, context);
230
263
  logger.debug(`Context detected successfully for ${fullPath}`, {
@@ -412,6 +445,7 @@ var PluginTracker = class {
412
445
  };
413
446
 
414
447
  export {
448
+ DetectionError,
415
449
  detectContext,
416
450
  PluginTracker
417
451
  };
@@ -1,25 +1,13 @@
1
1
  import {
2
- CompatibilityValidator,
3
- compatibilityRules
4
- } from "./chunk-VJ254HJY.js";
2
+ getPluginsByCategory
3
+ } from "./chunk-4VHPGJVU.js";
5
4
  import {
6
- BackupManager,
7
- ConfigWriter,
8
- getPluginsByCategory,
9
- pluginRegistry
10
- } from "./chunk-OJGTPK6N.js";
11
- import {
12
- PluginTracker,
13
- detectContext
14
- } from "./chunk-QDVUNUTK.js";
5
+ PluginTracker
6
+ } from "./chunk-BVXGN3AC.js";
15
7
  import {
16
8
  installPackages,
17
9
  logger
18
10
  } from "./chunk-QRFLHLFE.js";
19
- import "./chunk-QGM4M3NI.js";
20
-
21
- // src/cli/prompts/language.ts
22
- import inquirer from "inquirer";
23
11
 
24
12
  // src/cli/i18n/fr.ts
25
13
  var fr = {
@@ -78,6 +66,47 @@ var fr = {
78
66
  installationFailed: "\xC9chec de l'installation",
79
67
  validationFailed: "\xC9chec de la validation",
80
68
  incompatiblePlugins: (plugins) => `Plugins incompatibles d\xE9tect\xE9s : ${plugins.join(", ")}`
69
+ },
70
+ vite: {
71
+ noReactDetected: "\u26A0\uFE0F Aucun projet React d\xE9tect\xE9 dans le r\xE9pertoire actuel.",
72
+ proposeSetup: "Souhaitez-vous cr\xE9er un nouveau projet React avec Vite ?",
73
+ projectName: "Nom du projet",
74
+ projectNamePlaceholder: "mon-projet-react",
75
+ template: "Template",
76
+ templateOptions: [
77
+ { value: "react", name: "React (JavaScript)" },
78
+ { value: "react-ts", name: "React (TypeScript)" }
79
+ ],
80
+ creating: "Cr\xE9ation du projet React avec Vite...",
81
+ success: "\u2705 Projet cr\xE9\xE9 avec succ\xE8s !",
82
+ error: "\u274C Erreur lors de la cr\xE9ation du projet",
83
+ changingDirectory: "Changement vers le r\xE9pertoire du projet...",
84
+ validation: {
85
+ empty: "Le nom du projet ne peut pas \xEAtre vide",
86
+ invalid: "Le nom du projet ne peut contenir que des lettres, chiffres, tirets et underscores"
87
+ },
88
+ folderExists: (name) => `Le dossier "${name}" existe d\xE9j\xE0. Veuillez choisir un autre nom.`
89
+ },
90
+ nextjs: {
91
+ noNextjsDetected: "\u26A0\uFE0F Aucun projet Next.js d\xE9tect\xE9 dans le r\xE9pertoire actuel.",
92
+ proposeSetup: "Souhaitez-vous cr\xE9er un nouveau projet Next.js ?",
93
+ projectName: "Nom du projet",
94
+ projectNamePlaceholder: "mon-projet-nextjs",
95
+ typescript: "Utiliser TypeScript ?",
96
+ eslint: "Utiliser ESLint ?",
97
+ tailwind: "Utiliser TailwindCSS ?",
98
+ srcDir: "Utiliser le dossier src/ ?",
99
+ appRouter: "Utiliser App Router (recommand\xE9) ?",
100
+ importAlias: "Alias d'import (ex: @/*)",
101
+ creating: "Cr\xE9ation du projet Next.js...",
102
+ success: "\u2705 Projet cr\xE9\xE9 avec succ\xE8s !",
103
+ error: "\u274C Erreur lors de la cr\xE9ation du projet",
104
+ changingDirectory: "Changement vers le r\xE9pertoire du projet...",
105
+ validation: {
106
+ empty: "Le nom du projet ne peut pas \xEAtre vide",
107
+ invalid: "Le nom du projet ne peut contenir que des lettres, chiffres, tirets et underscores"
108
+ },
109
+ folderExists: (name) => `Le dossier "${name}" existe d\xE9j\xE0. Veuillez choisir un autre nom.`
81
110
  }
82
111
  };
83
112
 
@@ -138,6 +167,47 @@ var en = {
138
167
  installationFailed: "Installation failed",
139
168
  validationFailed: "Validation failed",
140
169
  incompatiblePlugins: (plugins) => `Incompatible plugins detected: ${plugins.join(", ")}`
170
+ },
171
+ vite: {
172
+ noReactDetected: "\u26A0\uFE0F No React project detected in the current directory.",
173
+ proposeSetup: "Would you like to create a new React project with Vite?",
174
+ projectName: "Project name",
175
+ projectNamePlaceholder: "my-react-project",
176
+ template: "Template",
177
+ templateOptions: [
178
+ { value: "react", name: "React (JavaScript)" },
179
+ { value: "react-ts", name: "React (TypeScript)" }
180
+ ],
181
+ creating: "Creating React project with Vite...",
182
+ success: "\u2705 Project created successfully!",
183
+ error: "\u274C Error creating project",
184
+ changingDirectory: "Changing to project directory...",
185
+ validation: {
186
+ empty: "Project name cannot be empty",
187
+ invalid: "Project name can only contain letters, numbers, dashes and underscores"
188
+ },
189
+ folderExists: (name) => `Folder "${name}" already exists. Please choose another name.`
190
+ },
191
+ nextjs: {
192
+ noNextjsDetected: "\u26A0\uFE0F No Next.js project detected in the current directory.",
193
+ proposeSetup: "Would you like to create a new Next.js project?",
194
+ projectName: "Project name",
195
+ projectNamePlaceholder: "my-nextjs-project",
196
+ typescript: "Use TypeScript?",
197
+ eslint: "Use ESLint?",
198
+ tailwind: "Use TailwindCSS?",
199
+ srcDir: "Use src/ directory?",
200
+ appRouter: "Use App Router (recommended)?",
201
+ importAlias: "Import alias (e.g. @/*)",
202
+ creating: "Creating Next.js project...",
203
+ success: "\u2705 Project created successfully!",
204
+ error: "\u274C Error creating project",
205
+ changingDirectory: "Changing to project directory...",
206
+ validation: {
207
+ empty: "Project name cannot be empty",
208
+ invalid: "Project name can only contain letters, numbers, dashes and underscores"
209
+ },
210
+ folderExists: (name) => `Folder "${name}" already exists. Please choose another name.`
141
211
  }
142
212
  };
143
213
 
@@ -198,6 +268,47 @@ var es = {
198
268
  installationFailed: "Fallo en la instalaci\xF3n",
199
269
  validationFailed: "Fallo en la validaci\xF3n",
200
270
  incompatiblePlugins: (plugins) => `Plugins incompatibles detectados: ${plugins.join(", ")}`
271
+ },
272
+ vite: {
273
+ noReactDetected: "\u26A0\uFE0F No se detect\xF3 ning\xFAn proyecto React en el directorio actual.",
274
+ proposeSetup: "\xBFDesea crear un nuevo proyecto React con Vite?",
275
+ projectName: "Nombre del proyecto",
276
+ projectNamePlaceholder: "mi-proyecto-react",
277
+ template: "Plantilla",
278
+ templateOptions: [
279
+ { value: "react", name: "React (JavaScript)" },
280
+ { value: "react-ts", name: "React (TypeScript)" }
281
+ ],
282
+ creating: "Creando proyecto React con Vite...",
283
+ success: "\u2705 \xA1Proyecto creado con \xE9xito!",
284
+ error: "\u274C Error al crear el proyecto",
285
+ changingDirectory: "Cambiando al directorio del proyecto...",
286
+ validation: {
287
+ empty: "El nombre del proyecto no puede estar vac\xEDo",
288
+ invalid: "El nombre del proyecto solo puede contener letras, n\xFAmeros, guiones y guiones bajos"
289
+ },
290
+ folderExists: (name) => `La carpeta "${name}" ya existe. Por favor, elija otro nombre.`
291
+ },
292
+ nextjs: {
293
+ noNextjsDetected: "\u26A0\uFE0F No se detect\xF3 ning\xFAn proyecto Next.js en el directorio actual.",
294
+ proposeSetup: "\xBFDesea crear un nuevo proyecto Next.js?",
295
+ projectName: "Nombre del proyecto",
296
+ projectNamePlaceholder: "mi-proyecto-nextjs",
297
+ typescript: "\xBFUsar TypeScript?",
298
+ eslint: "\xBFUsar ESLint?",
299
+ tailwind: "\xBFUsar TailwindCSS?",
300
+ srcDir: "\xBFUsar directorio src/?",
301
+ appRouter: "\xBFUsar App Router (recomendado)?",
302
+ importAlias: "Alias de importaci\xF3n (ej: @/*)",
303
+ creating: "Creando proyecto Next.js...",
304
+ success: "\u2705 \xA1Proyecto creado con \xE9xito!",
305
+ error: "\u274C Error al crear el proyecto",
306
+ changingDirectory: "Cambiando al directorio del proyecto...",
307
+ validation: {
308
+ empty: "El nombre del proyecto no puede estar vac\xEDo",
309
+ invalid: "El nombre del proyecto solo puede contener letras, n\xFAmeros, guiones y guiones bajos"
310
+ },
311
+ folderExists: (name) => `La carpeta "${name}" ya existe. Por favor, elija otro nombre.`
201
312
  }
202
313
  };
203
314
 
@@ -216,6 +327,7 @@ function getTranslations(lang) {
216
327
  }
217
328
 
218
329
  // src/cli/prompts/language.ts
330
+ import inquirer from "inquirer";
219
331
  async function promptLanguage() {
220
332
  const defaultTranslations = getTranslations("en");
221
333
  const { language } = await inquirer.prompt([
@@ -267,6 +379,9 @@ async function promptPluginSelection(ctx, availablePlugins, lang) {
267
379
  if (!plugin.frameworks.includes(ctx.framework)) {
268
380
  continue;
269
381
  }
382
+ if (ctx.framework === "nextjs" && plugin.name === "react-router-dom") {
383
+ continue;
384
+ }
270
385
  if (plugin.requiresTypeScript === true && !ctx.typescript) {
271
386
  continue;
272
387
  }
@@ -437,7 +552,7 @@ var Installer = class {
437
552
  }
438
553
  }
439
554
  logger.debug("Validating plugins compatibility...");
440
- const validationResult = this.validator.validate(notInstalled);
555
+ const validationResult = this.validator.validate(notInstalled, this.ctx);
441
556
  if (!validationResult.valid) {
442
557
  const errorMessages = validationResult.errors.map((e) => e.message).join("; ");
443
558
  throw new Error(
@@ -880,125 +995,12 @@ function displayNextSteps(lang) {
880
995
  console.log();
881
996
  }
882
997
 
883
- // src/cli/commands/install.ts
884
- import pc2 from "picocolors";
885
- async function installReact(options) {
886
- try {
887
- const language = await promptLanguage();
888
- const t = getTranslations(language);
889
- console.log();
890
- console.log(pc2.bold(pc2.cyan(`\u{1F50D} ${t.detection.detecting}`)));
891
- const projectRoot = process.cwd();
892
- const ctx = await detectContext(projectRoot);
893
- console.log(
894
- pc2.green(` \u2713 ${t.detection.framework}: `) + pc2.bold(`${ctx.framework} ${pc2.gray(ctx.frameworkVersion)}`)
895
- );
896
- console.log(
897
- pc2.green(` \u2713 ${t.detection.typescript}: `) + pc2.bold(ctx.typescript ? "Oui" : "Non")
898
- );
899
- if (ctx.bundler) {
900
- console.log(
901
- pc2.green(` \u2713 ${t.detection.bundler}: `) + pc2.bold(`${ctx.bundler} ${pc2.gray(ctx.bundlerVersion || "")}`)
902
- );
903
- }
904
- console.log(
905
- pc2.green(` \u2713 ${t.detection.packageManager}: `) + pc2.bold(ctx.packageManager)
906
- );
907
- console.log();
908
- let selectedPlugins = [];
909
- if (options.yes) {
910
- logger.info("Using default recommendations (--yes mode)");
911
- } else {
912
- selectedPlugins = await promptPluginSelection(
913
- ctx,
914
- pluginRegistry,
915
- language
916
- );
917
- }
918
- if (selectedPlugins.length === 0) {
919
- console.log();
920
- console.log(pc2.yellow(`\u26A0\uFE0F ${t.common.selected(0)}`));
921
- console.log(pc2.gray("Exiting..."));
922
- return;
923
- }
924
- console.log();
925
- console.log(
926
- pc2.bold(pc2.green(`\u2713 ${t.common.selected(selectedPlugins.length)}`))
927
- );
928
- console.log();
929
- if (!options.yes && !options.silent) {
930
- const confirmed = await promptConfirmation(selectedPlugins, language);
931
- if (!confirmed) {
932
- console.log(t.common.cancel);
933
- return;
934
- }
935
- }
936
- if (options.dryRun) {
937
- console.log();
938
- console.log(pc2.bold(pc2.yellow("\u2501".repeat(60))));
939
- console.log(pc2.bold(pc2.yellow("\u{1F50D} MODE DRY-RUN (simulation uniquement)")));
940
- console.log(pc2.bold(pc2.yellow("\u2501".repeat(60))));
941
- console.log();
942
- console.log(pc2.bold(pc2.cyan("\u{1F4E6} Packages \xE0 installer :")));
943
- for (const plugin of selectedPlugins) {
944
- console.log(
945
- pc2.blue(` \u2022 ${plugin.displayName}`) + pc2.gray(
946
- ` (${plugin.name}${plugin.version ? `@${plugin.version}` : ""})`
947
- )
948
- );
949
- }
950
- console.log();
951
- console.log(pc2.bold(pc2.cyan("\u{1F4DD} Fichiers qui seraient cr\xE9\xE9s/modifi\xE9s :")));
952
- for (const plugin of selectedPlugins) {
953
- console.log(pc2.gray(` \u2022 ${plugin.displayName} configuration`));
954
- }
955
- console.log();
956
- console.log(
957
- pc2.yellow("\u26A0\uFE0F Aucune modification n'a \xE9t\xE9 effectu\xE9e (dry-run)")
958
- );
959
- console.log(
960
- pc2.cyan("\u{1F4A1} Ex\xE9cutez sans --dry-run pour appliquer les changements")
961
- );
962
- console.log();
963
- return;
964
- }
965
- const backupManager = new BackupManager();
966
- const configWriter = new ConfigWriter(backupManager);
967
- const validator = new CompatibilityValidator(compatibilityRules);
968
- const installer = new Installer(ctx, validator, configWriter, backupManager);
969
- if (options.install === false) {
970
- console.log();
971
- console.log(pc2.yellow("\u2699\uFE0F Mode configuration uniquement (--no-install)"));
972
- console.log(pc2.gray("Les packages ne seront PAS install\xE9s"));
973
- console.log();
974
- }
975
- const spinner = new SpinnerManager();
976
- spinner.start(t.installation.installing);
977
- try {
978
- const result = await installer.install(selectedPlugins, {
979
- skipPackageInstall: options.install === false
980
- });
981
- spinner.succeed(t.installation.success);
982
- if (result.success) {
983
- displayInstallationReport(result, selectedPlugins, language);
984
- } else {
985
- console.error(`
986
- ${t.installation.error}`);
987
- process.exit(1);
988
- }
989
- } catch (error) {
990
- spinner.fail(t.installation.error);
991
- throw error;
992
- }
993
- } catch (error) {
994
- logger.error("Installation failed:", error);
995
- if (error instanceof Error) {
996
- console.error(`
997
- \u274C ${error.message}`);
998
- }
999
- process.exit(1);
1000
- }
1001
- }
1002
998
  export {
1003
- installReact
999
+ getTranslations,
1000
+ promptLanguage,
1001
+ promptPluginSelection,
1002
+ promptConfirmation,
1003
+ Installer,
1004
+ SpinnerManager,
1005
+ displayInstallationReport
1004
1006
  };
@@ -14,24 +14,32 @@ var CompatibilityValidator = class {
14
14
  * Valide la compatibilité d'un ensemble de plugins
15
15
  *
16
16
  * @param plugins - Liste des plugins à valider
17
+ * @param ctx - Contexte du projet (optionnel, pour règles spécifiques framework)
17
18
  * @returns Résultat de la validation avec erreurs, warnings et suggestions
18
19
  *
19
20
  * @example
20
21
  * ```typescript
21
- * const result = validator.validate([plugin1, plugin2, plugin3])
22
+ * const result = validator.validate([plugin1, plugin2, plugin3], ctx)
22
23
  * if (!result.valid) {
23
24
  * // Gérer les erreurs
24
25
  * }
25
26
  * ```
26
27
  */
27
- validate(plugins) {
28
+ validate(plugins, ctx) {
28
29
  logger.debug(`Validating ${plugins.length} plugin(s)`);
29
30
  const pluginNames = new Set(plugins.map((p) => p.name));
30
- const allConflicts = this.checkConflicts(plugins, pluginNames);
31
+ const applicableRules = ctx ? this.rules.filter(
32
+ (rule) => !rule.framework || rule.framework === ctx.framework
33
+ ) : this.rules.filter((rule) => !rule.framework);
34
+ const allConflicts = this.checkConflicts(
35
+ plugins,
36
+ pluginNames,
37
+ applicableRules
38
+ );
31
39
  const conflictErrors = [];
32
40
  const conflictWarnings = [];
33
41
  for (const conflict of allConflicts) {
34
- const rule = this.rules.find(
42
+ const rule = applicableRules.find(
35
43
  (r) => r.type === "CONFLICT" && r.plugins?.every((p) => conflict.plugins?.includes(p))
36
44
  );
37
45
  if (rule?.severity === "error") {
@@ -40,13 +48,31 @@ var CompatibilityValidator = class {
40
48
  conflictWarnings.push(conflict);
41
49
  }
42
50
  }
51
+ const frameworkConflicts = ctx ? this.checkFrameworkConflicts(plugins, pluginNames, ctx, applicableRules) : [];
52
+ const frameworkErrors = [];
53
+ const frameworkWarnings = [];
54
+ for (const conflict of frameworkConflicts) {
55
+ const rule = applicableRules.find(
56
+ (r) => r.type === "CONFLICT" && r.framework === ctx?.framework && r.plugins?.some((p) => conflict.plugins?.includes(p))
57
+ );
58
+ if (rule?.severity === "error") {
59
+ frameworkErrors.push(conflict);
60
+ } else {
61
+ frameworkWarnings.push(conflict);
62
+ }
63
+ }
43
64
  const errors = [
44
- ...this.checkExclusivity(plugins, pluginNames),
65
+ ...this.checkExclusivity(plugins, pluginNames, applicableRules),
45
66
  ...conflictErrors,
46
- ...this.checkDependencies(plugins, pluginNames)
67
+ ...this.checkDependencies(plugins, pluginNames, applicableRules),
68
+ ...frameworkErrors
47
69
  ];
48
- const warnings = conflictWarnings;
49
- const suggestions = this.checkRecommendations(plugins, pluginNames);
70
+ const warnings = [...conflictWarnings, ...frameworkWarnings];
71
+ const suggestions = this.checkRecommendations(
72
+ plugins,
73
+ pluginNames,
74
+ applicableRules
75
+ );
50
76
  const valid = errors.length === 0;
51
77
  logger.debug(`Validation result: ${valid ? "valid" : "invalid"}`, {
52
78
  errors: errors.length,
@@ -60,18 +86,52 @@ var CompatibilityValidator = class {
60
86
  suggestions
61
87
  };
62
88
  }
89
+ /**
90
+ * Vérifie les conflits avec le framework
91
+ *
92
+ * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
93
+ * @param pluginNames - Set des noms de plugins pour lookup rapide
94
+ * @param ctx - Contexte du projet
95
+ * @param rules - Règles applicables
96
+ * @returns Liste des erreurs/warnings de conflit framework
97
+ *
98
+ * @internal
99
+ */
100
+ checkFrameworkConflicts(_plugins, pluginNames, ctx, rules) {
101
+ const conflicts = [];
102
+ for (const rule of rules) {
103
+ if (rule.type !== "CONFLICT" || !rule.framework || rule.framework !== ctx.framework) {
104
+ continue;
105
+ }
106
+ if (rule.plugins && rule.plugins.length > 0) {
107
+ const conflictingPlugins = rule.plugins.filter(
108
+ (pluginName) => pluginNames.has(pluginName)
109
+ );
110
+ if (conflictingPlugins.length > 0) {
111
+ conflicts.push({
112
+ type: "CONFLICT",
113
+ plugins: conflictingPlugins,
114
+ message: rule.reason,
115
+ canOverride: rule.allowOverride ?? true
116
+ });
117
+ }
118
+ }
119
+ }
120
+ return conflicts;
121
+ }
63
122
  /**
64
123
  * Vérifie les règles d'exclusivité (EXCLUSIVE)
65
124
  *
66
125
  * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
67
126
  * @param pluginNames - Set des noms de plugins pour lookup rapide
127
+ * @param rules - Règles applicables
68
128
  * @returns Liste des erreurs d'exclusivité
69
129
  *
70
130
  * @internal
71
131
  */
72
- checkExclusivity(_plugins, pluginNames) {
132
+ checkExclusivity(_plugins, pluginNames, rules = this.rules) {
73
133
  const errors = [];
74
- for (const rule of this.rules) {
134
+ for (const rule of rules) {
75
135
  if (rule.type !== "EXCLUSIVE" || !rule.plugins) {
76
136
  continue;
77
137
  }
@@ -94,13 +154,17 @@ var CompatibilityValidator = class {
94
154
  *
95
155
  * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
96
156
  * @param pluginNames - Set des noms de plugins pour lookup rapide
157
+ * @param rules - Règles applicables
97
158
  * @returns Liste des warnings/erreurs de conflit
98
159
  *
99
160
  * @internal
100
161
  */
101
- checkConflicts(_plugins, pluginNames) {
162
+ checkConflicts(_plugins, pluginNames, rules = this.rules) {
102
163
  const conflicts = [];
103
- for (const rule of this.rules) {
164
+ for (const rule of rules) {
165
+ if (rule.framework) {
166
+ continue;
167
+ }
104
168
  if (rule.type !== "CONFLICT" || !rule.plugins) {
105
169
  continue;
106
170
  }
@@ -123,13 +187,14 @@ var CompatibilityValidator = class {
123
187
  *
124
188
  * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
125
189
  * @param pluginNames - Set des noms de plugins pour lookup rapide
190
+ * @param rules - Règles applicables
126
191
  * @returns Liste des erreurs de dépendances manquantes
127
192
  *
128
193
  * @internal
129
194
  */
130
- checkDependencies(_plugins, pluginNames) {
195
+ checkDependencies(_plugins, pluginNames, rules = this.rules) {
131
196
  const errors = [];
132
- for (const rule of this.rules) {
197
+ for (const rule of rules) {
133
198
  if (rule.type !== "REQUIRES" || !rule.plugin || !rule.requires) {
134
199
  continue;
135
200
  }
@@ -156,13 +221,14 @@ var CompatibilityValidator = class {
156
221
  *
157
222
  * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
158
223
  * @param pluginNames - Set des noms de plugins pour lookup rapide
224
+ * @param rules - Règles applicables
159
225
  * @returns Liste des suggestions de plugins recommandés
160
226
  *
161
227
  * @internal
162
228
  */
163
- checkRecommendations(_plugins, pluginNames) {
229
+ checkRecommendations(_plugins, pluginNames, rules = this.rules) {
164
230
  const suggestions = [];
165
- for (const rule of this.rules) {
231
+ for (const rule of rules) {
166
232
  if (rule.type !== "RECOMMENDS" || !rule.plugin || !rule.recommends) {
167
233
  continue;
168
234
  }
@@ -205,6 +271,34 @@ var compatibilityRules = [
205
271
  recommends: ["@types/react-router-dom"],
206
272
  reason: "Types TypeScript recommand\xE9s pour une meilleure exp\xE9rience de d\xE9veloppement",
207
273
  severity: "info"
274
+ },
275
+ // Règles spécifiques Next.js
276
+ // React Router incompatible avec Next.js
277
+ {
278
+ type: "CONFLICT",
279
+ plugins: ["react-router-dom"],
280
+ framework: "nextjs",
281
+ reason: "React Router est incompatible avec Next.js. Next.js a son propre syst\xE8me de routing int\xE9gr\xE9.",
282
+ severity: "error",
283
+ allowOverride: false
284
+ },
285
+ // Framer Motion peut causer des problèmes SSR avec Next.js
286
+ {
287
+ type: "CONFLICT",
288
+ plugins: ["framer-motion"],
289
+ framework: "nextjs",
290
+ 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.",
291
+ severity: "warning",
292
+ allowOverride: true
293
+ },
294
+ // Shadcn/ui nécessite une configuration spéciale pour Next.js
295
+ {
296
+ type: "RECOMMENDS",
297
+ plugin: "shadcn-ui",
298
+ recommends: ["shadcn-ui-nextjs"],
299
+ framework: "nextjs",
300
+ reason: "Pour Next.js, utilisez la variante shadcn-ui-nextjs qui est optimis\xE9e pour React Server Components.",
301
+ severity: "info"
208
302
  }
209
303
  ];
210
304