@configjs/cli 1.1.3 → 1.1.5

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.
@@ -1,283 +1,135 @@
1
1
  import {
2
2
  CompatibilityValidator,
3
- compatibilityRules
4
- } from "./chunk-VJ254HJY.js";
3
+ allCompatibilityRules
4
+ } from "./chunk-D37FHAGO.js";
5
5
  import {
6
6
  BackupManager,
7
7
  ConfigWriter,
8
8
  getPluginsByCategory,
9
9
  pluginRegistry
10
- } from "./chunk-OJGTPK6N.js";
10
+ } from "./chunk-V75HW2AM.js";
11
11
  import {
12
- DetectionError,
13
- PluginTracker,
14
- detectContext
15
- } from "./chunk-ZSDLWQSS.js";
12
+ PluginTracker
13
+ } from "./chunk-TVZWTKJU.js";
14
+ import {
15
+ installPackages
16
+ } from "./chunk-MQV3WNMH.js";
16
17
  import {
17
- checkPathExists,
18
- installPackages,
19
18
  logger
20
- } from "./chunk-QRFLHLFE.js";
21
- import "./chunk-QGM4M3NI.js";
22
-
23
- // src/cli/prompts/language.ts
24
- import inquirer from "inquirer";
19
+ } from "./chunk-HM2JWJOO.js";
20
+ import {
21
+ getTranslations
22
+ } from "./chunk-3V72QFFY.js";
25
23
 
26
- // src/cli/i18n/fr.ts
27
- var fr = {
28
- language: {
29
- select: "Choisissez votre langue",
30
- options: [
31
- { value: "fr", name: "Fran\xE7ais" },
32
- { value: "en", name: "English" },
33
- { value: "es", name: "Espa\xF1ol" }
34
- ]
35
- },
36
- common: {
37
- continue: "Continuer",
38
- cancel: "Annuler",
39
- back: "Retour",
40
- none: "Aucun",
41
- selected: (count) => count === 0 ? "Aucune biblioth\xE8que s\xE9lectionn\xE9e" : count === 1 ? "1 biblioth\xE8que s\xE9lectionn\xE9e" : `${count} biblioth\xE8ques s\xE9lectionn\xE9es`
42
- },
43
- plugins: {
44
- selectCategory: (category) => `S\xE9lectionnez vos biblioth\xE8ques : ${category}`,
45
- selectMultiple: "S\xE9lection multiple",
46
- pressSpace: "Appuyez sur <espace> pour s\xE9lectionner",
47
- pressEnter: "Appuyez sur <entr\xE9e> pour valider",
48
- description: "Description"
49
- },
50
- detection: {
51
- detecting: "\u{1F50D} D\xE9tection du contexte...",
52
- framework: "Framework",
53
- typescript: "TypeScript",
54
- bundler: "Bundler",
55
- packageManager: "Gestionnaire de paquets"
56
- },
57
- confirmation: {
58
- summary: "\u{1F4CB} R\xE9sum\xE9 de l'installation",
59
- packagesToInstall: "\u{1F4E6} Packages \xE0 installer",
60
- filesToCreate: "\u{1F4DD} Fichiers qui seront cr\xE9\xE9s",
61
- filesToModify: "\u{1F4DD} Fichiers qui seront modifi\xE9s",
62
- continueQuestion: "Continuer avec l'installation ?"
63
- },
64
- installation: {
65
- installing: "Installation en cours...",
66
- configuring: "Configuration en cours...",
67
- success: "\u2728 Installation termin\xE9e !",
68
- error: "\u274C Erreur lors de l'installation",
69
- rollback: "\u21BA Rollback en cours..."
70
- },
71
- report: {
72
- title: "\u2728 Installation termin\xE9e !",
73
- packagesInstalled: "\u{1F4E6} Packages install\xE9s",
74
- filesCreated: "\u{1F4DD} Fichiers cr\xE9\xE9s",
75
- filesModified: "\u{1F4DD} Fichiers modifi\xE9s",
76
- nextSteps: "\u{1F680} Prochaines \xE9tapes"
77
- },
78
- errors: {
79
- detectionFailed: "\xC9chec de la d\xE9tection du contexte",
80
- installationFailed: "\xC9chec de l'installation",
81
- validationFailed: "\xC9chec de la validation",
82
- incompatiblePlugins: (plugins) => `Plugins incompatibles d\xE9tect\xE9s : ${plugins.join(", ")}`
83
- },
84
- vite: {
85
- noReactDetected: "\u26A0\uFE0F Aucun projet React d\xE9tect\xE9 dans le r\xE9pertoire actuel.",
86
- proposeSetup: "Souhaitez-vous cr\xE9er un nouveau projet React avec Vite ?",
87
- projectName: "Nom du projet",
88
- projectNamePlaceholder: "mon-projet-react",
89
- template: "Template",
90
- templateOptions: [
91
- { value: "react", name: "React (JavaScript)" },
92
- { value: "react-ts", name: "React (TypeScript)" }
93
- ],
94
- creating: "Cr\xE9ation du projet React avec Vite...",
95
- success: "\u2705 Projet cr\xE9\xE9 avec succ\xE8s !",
96
- error: "\u274C Erreur lors de la cr\xE9ation du projet",
97
- changingDirectory: "Changement vers le r\xE9pertoire du projet...",
98
- validation: {
99
- empty: "Le nom du projet ne peut pas \xEAtre vide",
100
- invalid: "Le nom du projet ne peut contenir que des lettres, chiffres, tirets et underscores"
24
+ // src/core/framework-registry.ts
25
+ var frameworkRegistry = {
26
+ react: {
27
+ id: "react",
28
+ displayName: "React",
29
+ detectPackages: ["react", "react-dom"],
30
+ defaultBundler: "vite",
31
+ createCommand: "npm create vite@latest",
32
+ templates: {
33
+ js: "react",
34
+ ts: "react-ts"
101
35
  },
102
- folderExists: (name) => `Le dossier "${name}" existe d\xE9j\xE0. Veuillez choisir un autre nom.`
103
- }
104
- };
105
-
106
- // src/cli/i18n/en.ts
107
- var en = {
108
- language: {
109
- select: "Choose your language",
110
- options: [
111
- { value: "fr", name: "Fran\xE7ais" },
112
- { value: "en", name: "English" },
113
- { value: "es", name: "Espa\xF1ol" }
114
- ]
115
- },
116
- common: {
117
- continue: "Continue",
118
- cancel: "Cancel",
119
- back: "Back",
120
- none: "None",
121
- selected: (count) => count === 0 ? "No library selected" : count === 1 ? "1 library selected" : `${count} libraries selected`
122
- },
123
- plugins: {
124
- selectCategory: (category) => `Select your libraries: ${category}`,
125
- selectMultiple: "Multiple selection",
126
- pressSpace: "Press <space> to select",
127
- pressEnter: "Press <enter> to confirm",
128
- description: "Description"
129
- },
130
- detection: {
131
- detecting: "\u{1F50D} Detecting context...",
132
- framework: "Framework",
133
- typescript: "TypeScript",
134
- bundler: "Bundler",
135
- packageManager: "Package manager"
136
- },
137
- confirmation: {
138
- summary: "\u{1F4CB} Installation Summary",
139
- packagesToInstall: "\u{1F4E6} Packages to install",
140
- filesToCreate: "\u{1F4DD} Files that will be created",
141
- filesToModify: "\u{1F4DD} Files that will be modified",
142
- continueQuestion: "Continue with installation?"
143
- },
144
- installation: {
145
- installing: "Installing...",
146
- configuring: "Configuring...",
147
- success: "\u2728 Installation completed!",
148
- error: "\u274C Installation error",
149
- rollback: "\u21BA Rolling back..."
150
- },
151
- report: {
152
- title: "\u2728 Installation completed!",
153
- packagesInstalled: "\u{1F4E6} Installed packages",
154
- filesCreated: "\u{1F4DD} Created files",
155
- filesModified: "\u{1F4DD} Modified files",
156
- nextSteps: "\u{1F680} Next steps"
157
- },
158
- errors: {
159
- detectionFailed: "Context detection failed",
160
- installationFailed: "Installation failed",
161
- validationFailed: "Validation failed",
162
- incompatiblePlugins: (plugins) => `Incompatible plugins detected: ${plugins.join(", ")}`
163
- },
164
- vite: {
165
- noReactDetected: "\u26A0\uFE0F No React project detected in the current directory.",
166
- proposeSetup: "Would you like to create a new React project with Vite?",
167
- projectName: "Project name",
168
- projectNamePlaceholder: "my-react-project",
169
- template: "Template",
170
- templateOptions: [
171
- { value: "react", name: "React (JavaScript)" },
172
- { value: "react-ts", name: "React (TypeScript)" }
173
- ],
174
- creating: "Creating React project with Vite...",
175
- success: "\u2705 Project created successfully!",
176
- error: "\u274C Error creating project",
177
- changingDirectory: "Changing to project directory...",
178
- validation: {
179
- empty: "Project name cannot be empty",
180
- invalid: "Project name can only contain letters, numbers, dashes and underscores"
36
+ getSetupPrompt: async (language) => {
37
+ const { promptViteSetup } = await import("./vite-setup-3U22LJFG.js");
38
+ return await promptViteSetup(language);
181
39
  },
182
- folderExists: (name) => `Folder "${name}" already exists. Please choose another name.`
183
- }
184
- };
185
-
186
- // src/cli/i18n/es.ts
187
- var es = {
188
- language: {
189
- select: "Elige tu idioma",
190
- options: [
191
- { value: "fr", name: "Fran\xE7ais" },
192
- { value: "en", name: "English" },
193
- { value: "es", name: "Espa\xF1ol" }
194
- ]
195
- },
196
- common: {
197
- continue: "Continuar",
198
- cancel: "Cancelar",
199
- back: "Volver",
200
- none: "Ninguno",
201
- selected: (count) => count === 0 ? "Ninguna biblioteca seleccionada" : count === 1 ? "1 biblioteca seleccionada" : `${count} bibliotecas seleccionadas`
202
- },
203
- plugins: {
204
- selectCategory: (category) => `Selecciona tus bibliotecas: ${category}`,
205
- selectMultiple: "Selecci\xF3n m\xFAltiple",
206
- pressSpace: "Presiona <espacio> para seleccionar",
207
- pressEnter: "Presiona <entrar> para confirmar",
208
- description: "Descripci\xF3n"
209
- },
210
- detection: {
211
- detecting: "\u{1F50D} Detectando contexto...",
212
- framework: "Framework",
213
- typescript: "TypeScript",
214
- bundler: "Bundler",
215
- packageManager: "Gestor de paquetes"
216
- },
217
- confirmation: {
218
- summary: "\u{1F4CB} Resumen de la instalaci\xF3n",
219
- packagesToInstall: "\u{1F4E6} Paquetes a instalar",
220
- filesToCreate: "\u{1F4DD} Archivos que se crear\xE1n",
221
- filesToModify: "\u{1F4DD} Archivos que se modificar\xE1n",
222
- continueQuestion: "\xBFContinuar con la instalaci\xF3n?"
223
- },
224
- installation: {
225
- installing: "Instalando...",
226
- configuring: "Configurando...",
227
- success: "\u2728 \xA1Instalaci\xF3n completada!",
228
- error: "\u274C Error en la instalaci\xF3n",
229
- rollback: "\u21BA Revirtiendo..."
40
+ createProject: async (options, currentDir, language) => {
41
+ const { createViteProject } = await import("./vite-installer-XIJFJ4CN.js");
42
+ return await createViteProject(
43
+ options,
44
+ currentDir,
45
+ language
46
+ );
47
+ },
48
+ i18nKeys: {
49
+ noFrameworkDetected: "vite.noReactDetected",
50
+ creating: "vite.creating",
51
+ folderExists: (name) => `vite.folderExists(${name})`
52
+ }
230
53
  },
231
- report: {
232
- title: "\u2728 \xA1Instalaci\xF3n completada!",
233
- packagesInstalled: "\u{1F4E6} Paquetes instalados",
234
- filesCreated: "\u{1F4DD} Archivos creados",
235
- filesModified: "\u{1F4DD} Archivos modificados",
236
- nextSteps: "\u{1F680} Pr\xF3ximos pasos"
54
+ nextjs: {
55
+ id: "nextjs",
56
+ displayName: "Next.js",
57
+ detectPackages: ["next"],
58
+ defaultBundler: "nextjs",
59
+ createCommand: "npm create next-app@latest",
60
+ getSetupPrompt: async (language) => {
61
+ const { promptNextjsSetup } = await import("./nextjs-setup-7LWMEC5I.js");
62
+ return await promptNextjsSetup(language);
63
+ },
64
+ createProject: async (options, currentDir, language) => {
65
+ const { createNextjsProject } = await import("./nextjs-installer-RWBGWW23.js");
66
+ return await createNextjsProject(
67
+ options,
68
+ currentDir,
69
+ language
70
+ );
71
+ },
72
+ i18nKeys: {
73
+ noFrameworkDetected: "nextjs.noNextjsDetected",
74
+ creating: "nextjs.creating",
75
+ folderExists: (name) => `nextjs.folderExists(${name})`
76
+ }
237
77
  },
238
- errors: {
239
- detectionFailed: "Fallo en la detecci\xF3n del contexto",
240
- installationFailed: "Fallo en la instalaci\xF3n",
241
- validationFailed: "Fallo en la validaci\xF3n",
242
- incompatiblePlugins: (plugins) => `Plugins incompatibles detectados: ${plugins.join(", ")}`
78
+ vue: {
79
+ id: "vue",
80
+ displayName: "Vue.js",
81
+ detectPackages: ["vue"],
82
+ defaultBundler: "vite",
83
+ createCommand: "npm create vite@latest",
84
+ templates: {
85
+ js: "vue",
86
+ ts: "vue-ts"
87
+ },
88
+ getSetupPrompt: async (language) => {
89
+ const { promptVueSetup } = await import("./vue-setup-X65P3CZX.js");
90
+ return await promptVueSetup(language);
91
+ },
92
+ createProject: async (options, currentDir, language) => {
93
+ const { createVueProject } = await import("./vue-installer-SFROF4N3.js");
94
+ return await createVueProject(
95
+ options,
96
+ currentDir,
97
+ language
98
+ );
99
+ },
100
+ i18nKeys: {
101
+ noFrameworkDetected: "vue.noVueDetected",
102
+ creating: "vue.creating",
103
+ folderExists: (name) => `vue.folderExists(${name})`
104
+ }
243
105
  },
244
- vite: {
245
- noReactDetected: "\u26A0\uFE0F No se detect\xF3 ning\xFAn proyecto React en el directorio actual.",
246
- proposeSetup: "\xBFDesea crear un nuevo proyecto React con Vite?",
247
- projectName: "Nombre del proyecto",
248
- projectNamePlaceholder: "mi-proyecto-react",
249
- template: "Plantilla",
250
- templateOptions: [
251
- { value: "react", name: "React (JavaScript)" },
252
- { value: "react-ts", name: "React (TypeScript)" }
253
- ],
254
- creating: "Creando proyecto React con Vite...",
255
- success: "\u2705 \xA1Proyecto creado con \xE9xito!",
256
- error: "\u274C Error al crear el proyecto",
257
- changingDirectory: "Cambiando al directorio del proyecto...",
258
- validation: {
259
- empty: "El nombre del proyecto no puede estar vac\xEDo",
260
- invalid: "El nombre del proyecto solo puede contener letras, n\xFAmeros, guiones y guiones bajos"
106
+ svelte: {
107
+ id: "svelte",
108
+ displayName: "Svelte",
109
+ detectPackages: ["svelte", "@sveltejs/kit"],
110
+ defaultBundler: "vite",
111
+ createCommand: "npm create svelte@latest",
112
+ getSetupPrompt: async (_language) => {
113
+ return await Promise.resolve(null);
114
+ },
115
+ createProject: async (_options, _currentDir, _language) => {
116
+ return await Promise.reject(
117
+ new Error("Svelte project creation not yet implemented")
118
+ );
261
119
  },
262
- folderExists: (name) => `La carpeta "${name}" ya existe. Por favor, elija otro nombre.`
120
+ i18nKeys: {
121
+ noFrameworkDetected: "svelte.noSvelteDetected",
122
+ creating: "svelte.creating",
123
+ folderExists: (name) => `svelte.folderExists(${name})`
124
+ }
263
125
  }
264
126
  };
265
-
266
- // src/cli/i18n/index.ts
267
- function getTranslations(lang) {
268
- switch (lang) {
269
- case "fr":
270
- return fr;
271
- case "en":
272
- return en;
273
- case "es":
274
- return es;
275
- default:
276
- return en;
277
- }
127
+ function getFrameworkMetadata(framework) {
128
+ return frameworkRegistry[framework];
278
129
  }
279
130
 
280
131
  // src/cli/prompts/language.ts
132
+ import inquirer from "inquirer";
281
133
  async function promptLanguage() {
282
134
  const defaultTranslations = getTranslations("en");
283
135
  const { language } = await inquirer.prompt([
@@ -329,6 +181,18 @@ async function promptPluginSelection(ctx, availablePlugins, lang) {
329
181
  if (!plugin.frameworks.includes(ctx.framework)) {
330
182
  continue;
331
183
  }
184
+ if (ctx.framework === "nextjs" && plugin.name === "react-router-dom") {
185
+ continue;
186
+ }
187
+ if (ctx.framework === "vue" && plugin.name === "react-router-dom") {
188
+ continue;
189
+ }
190
+ if (ctx.framework === "vue" && (plugin.name === "zustand" || plugin.name === "@reduxjs/toolkit" || plugin.name === "jotai")) {
191
+ continue;
192
+ }
193
+ if (ctx.framework === "vue" && plugin.name === "shadcn-ui") {
194
+ continue;
195
+ }
332
196
  if (plugin.requiresTypeScript === true && !ctx.typescript) {
333
197
  continue;
334
198
  }
@@ -409,88 +273,6 @@ ${translations.confirmation.summary}
409
273
  return confirm;
410
274
  }
411
275
 
412
- // src/cli/prompts/vite-setup.ts
413
- import inquirer4 from "inquirer";
414
- async function promptViteSetup(language) {
415
- const t = getTranslations(language);
416
- const answers = await inquirer4.prompt([
417
- {
418
- type: "confirm",
419
- name: "shouldCreate",
420
- message: t.vite.proposeSetup,
421
- default: true
422
- },
423
- {
424
- type: "input",
425
- name: "projectName",
426
- message: t.vite.projectName,
427
- default: t.vite.projectNamePlaceholder,
428
- when: (answers2) => answers2.shouldCreate === true,
429
- validate: (input) => {
430
- if (!input || input.trim().length === 0) {
431
- return t.vite.validation.empty;
432
- }
433
- if (!/^[a-z0-9-_]+$/i.test(input)) {
434
- return t.vite.validation.invalid;
435
- }
436
- return true;
437
- }
438
- },
439
- {
440
- type: "list",
441
- name: "template",
442
- message: t.vite.template,
443
- choices: t.vite.templateOptions,
444
- when: (answers2) => answers2.shouldCreate === true
445
- }
446
- ]);
447
- if (!answers.shouldCreate) {
448
- return null;
449
- }
450
- return {
451
- projectName: answers.projectName.trim(),
452
- template: answers.template
453
- };
454
- }
455
-
456
- // src/cli/utils/vite-installer.ts
457
- import { resolve } from "path";
458
- import { execa } from "execa";
459
- async function createViteProject(options, currentDir, language) {
460
- const t = getTranslations(language);
461
- const { projectName, template } = options;
462
- const projectPath = resolve(currentDir, projectName);
463
- if (await checkPathExists(projectPath)) {
464
- throw new Error(t.vite.folderExists(projectName));
465
- }
466
- logger.info(t.vite.creating);
467
- try {
468
- const result = await execa(
469
- "npm",
470
- ["create", "vite@latest", projectName, "--", "--template", template],
471
- {
472
- cwd: currentDir,
473
- stdio: "inherit",
474
- env: {
475
- ...process.env,
476
- // Désactiver les prompts interactifs de Vite
477
- npm_config_yes: "true"
478
- }
479
- }
480
- );
481
- if (result.exitCode !== 0) {
482
- throw new Error(`${t.vite.error}: exit code ${result.exitCode}`);
483
- }
484
- logger.success(t.vite.success);
485
- logger.info(t.vite.changingDirectory);
486
- return projectPath;
487
- } catch (error) {
488
- const errorMessage = error instanceof Error ? error.message : String(error);
489
- logger.error(`${t.vite.error}: ${errorMessage}`);
490
- throw error;
491
- }
492
- }
493
-
494
276
  // src/core/installer.ts
495
277
  var Installer = class {
496
278
  /**
@@ -498,13 +280,14 @@ var Installer = class {
498
280
  * @param validator - Validateur de compatibilité
499
281
  * @param writer - Writer de configuration
500
282
  * @param backupManager - Gestionnaire de backups
283
+ * @param fs - Système de fichiers optionnel (par défaut: filesystem réel via memfs.useAsNodeFs)
501
284
  */
502
- constructor(ctx, validator, writer, backupManager) {
285
+ constructor(ctx, validator, writer, backupManager, _fs) {
503
286
  this.ctx = ctx;
504
287
  this.validator = validator;
505
288
  this.writer = writer;
506
289
  this.backupManager = backupManager;
507
- this.tracker = new PluginTracker(ctx.projectRoot);
290
+ this.tracker = new PluginTracker(ctx.projectRoot, ctx.fsAdapter);
508
291
  }
509
292
  tracker;
510
293
  /**
@@ -581,7 +364,7 @@ var Installer = class {
581
364
  }
582
365
  }
583
366
  logger.debug("Validating plugins compatibility...");
584
- const validationResult = this.validator.validate(notInstalled);
367
+ const validationResult = this.validator.validate(notInstalled, this.ctx);
585
368
  if (!validationResult.valid) {
586
369
  const errorMessages = validationResult.errors.map((e) => e.message).join("; ");
587
370
  throw new Error(
@@ -1024,42 +807,58 @@ function displayNextSteps(lang) {
1024
807
  console.log();
1025
808
  }
1026
809
 
1027
- // src/cli/commands/install.ts
810
+ // src/cli/commands/base-framework-command.ts
1028
811
  import pc2 from "picocolors";
1029
- async function installReact(options) {
1030
- try {
1031
- const language = await promptLanguage();
1032
- const t = getTranslations(language);
812
+ var BaseFrameworkCommand = class {
813
+ /**
814
+ * Affiche les informations spécifiques du contexte détecté
815
+ *
816
+ * Permet d'afficher des informations spécifiques au framework
817
+ * (ex: Vue version, Next.js router type, etc.)
818
+ *
819
+ * @param _ctx - Contexte du projet
820
+ * @param _t - Traductions
821
+ */
822
+ displayFrameworkSpecificInfo(_ctx, _t) {
823
+ }
824
+ /**
825
+ * Vérifie que le framework détecté correspond au framework attendu
826
+ *
827
+ * @param ctx - Contexte du projet
828
+ * @returns true si le framework correspond
829
+ */
830
+ validateFramework(ctx) {
831
+ return ctx.framework === this.getFramework();
832
+ }
833
+ /**
834
+ * Affiche un message d'avertissement si le framework ne correspond pas
835
+ *
836
+ * @param ctx - Contexte du projet
837
+ * @param _t - Traductions
838
+ */
839
+ displayFrameworkMismatchWarning(ctx, _t) {
840
+ const framework = this.getFramework();
841
+ const metadata = getFrameworkMetadata(framework);
1033
842
  console.log();
1034
- console.log(pc2.bold(pc2.cyan(`\u{1F50D} ${t.detection.detecting}`)));
1035
- let projectRoot = process.cwd();
1036
- let ctx;
1037
- try {
1038
- ctx = await detectContext(projectRoot);
1039
- } catch (error) {
1040
- if (error instanceof DetectionError) {
1041
- console.log();
1042
- console.log(pc2.yellow(t.vite.noReactDetected));
1043
- console.log();
1044
- const viteOptions = await promptViteSetup(language);
1045
- if (!viteOptions) {
1046
- console.log();
1047
- console.log(pc2.gray(t.common.cancel));
1048
- return;
1049
- }
1050
- const newProjectPath = await createViteProject(
1051
- viteOptions,
1052
- projectRoot,
1053
- language
1054
- );
1055
- process.chdir(newProjectPath);
1056
- projectRoot = newProjectPath;
1057
- console.log();
1058
- ctx = await detectContext(projectRoot);
1059
- } else {
1060
- throw error;
1061
- }
1062
- }
843
+ console.log(
844
+ pc2.yellow(
845
+ `\u26A0\uFE0F Framework d\xE9tect\xE9: ${ctx.framework}. Cette commande est destin\xE9e aux projets ${metadata?.displayName || framework}.`
846
+ )
847
+ );
848
+ console.log(
849
+ pc2.gray(
850
+ `Utilisez "npx @configjs/cli ${ctx.framework}" pour les projets ${ctx.framework}.`
851
+ )
852
+ );
853
+ console.log();
854
+ }
855
+ /**
856
+ * Affiche le contexte détecté
857
+ *
858
+ * @param ctx - Contexte du projet
859
+ * @param t - Traductions
860
+ */
861
+ displayDetectedContext(ctx, t) {
1063
862
  console.log(
1064
863
  pc2.green(` \u2713 ${t.detection.framework}: `) + pc2.bold(`${ctx.framework} ${pc2.gray(ctx.frameworkVersion)}`)
1065
864
  );
@@ -1074,67 +873,89 @@ async function installReact(options) {
1074
873
  console.log(
1075
874
  pc2.green(` \u2713 ${t.detection.packageManager}: `) + pc2.bold(ctx.packageManager)
1076
875
  );
876
+ this.displayFrameworkSpecificInfo(ctx, t);
1077
877
  console.log();
1078
- let selectedPlugins = [];
878
+ }
879
+ /**
880
+ * Sélectionne les plugins à installer
881
+ *
882
+ * @param ctx - Contexte du projet
883
+ * @param language - Langue sélectionnée
884
+ * @param options - Options CLI
885
+ * @returns Liste des plugins sélectionnés
886
+ */
887
+ async selectPlugins(ctx, language, options) {
1079
888
  if (options.yes) {
1080
889
  logger.info("Using default recommendations (--yes mode)");
1081
- } else {
1082
- selectedPlugins = await promptPluginSelection(
1083
- ctx,
1084
- pluginRegistry,
1085
- language
1086
- );
890
+ return [];
1087
891
  }
1088
- if (selectedPlugins.length === 0) {
1089
- console.log();
1090
- console.log(pc2.yellow(`\u26A0\uFE0F ${t.common.selected(0)}`));
1091
- console.log(pc2.gray("Exiting..."));
1092
- return;
892
+ return promptPluginSelection(ctx, pluginRegistry, language);
893
+ }
894
+ /**
895
+ * Demande confirmation avant installation
896
+ *
897
+ * @param selectedPlugins - Plugins sélectionnés
898
+ * @param language - Langue sélectionnée
899
+ * @param options - Options CLI
900
+ * @returns true si l'utilisateur confirme
901
+ */
902
+ async confirmInstallation(selectedPlugins, language, options) {
903
+ if (options.yes || options.silent) {
904
+ return true;
905
+ }
906
+ return promptConfirmation(selectedPlugins, language);
907
+ }
908
+ /**
909
+ * Gère le mode dry-run
910
+ *
911
+ * @param selectedPlugins - Plugins sélectionnés
912
+ * @param options - Options CLI
913
+ */
914
+ handleDryRun(selectedPlugins, options) {
915
+ if (!options.dryRun) {
916
+ return false;
1093
917
  }
1094
918
  console.log();
1095
- console.log(
1096
- pc2.bold(pc2.green(`\u2713 ${t.common.selected(selectedPlugins.length)}`))
1097
- );
919
+ console.log(pc2.bold(pc2.yellow("\u2501".repeat(60))));
920
+ console.log(pc2.bold(pc2.yellow("\u{1F50D} MODE DRY-RUN (simulation uniquement)")));
921
+ console.log(pc2.bold(pc2.yellow("\u2501".repeat(60))));
1098
922
  console.log();
1099
- if (!options.yes && !options.silent) {
1100
- const confirmed = await promptConfirmation(selectedPlugins, language);
1101
- if (!confirmed) {
1102
- console.log(t.common.cancel);
1103
- return;
1104
- }
1105
- }
1106
- if (options.dryRun) {
1107
- console.log();
1108
- console.log(pc2.bold(pc2.yellow("\u2501".repeat(60))));
1109
- console.log(pc2.bold(pc2.yellow("\u{1F50D} MODE DRY-RUN (simulation uniquement)")));
1110
- console.log(pc2.bold(pc2.yellow("\u2501".repeat(60))));
1111
- console.log();
1112
- console.log(pc2.bold(pc2.cyan("\u{1F4E6} Packages \xE0 installer :")));
1113
- for (const plugin of selectedPlugins) {
1114
- console.log(
1115
- pc2.blue(` \u2022 ${plugin.displayName}`) + pc2.gray(
1116
- ` (${plugin.name}${plugin.version ? `@${plugin.version}` : ""})`
1117
- )
1118
- );
1119
- }
1120
- console.log();
1121
- console.log(pc2.bold(pc2.cyan("\u{1F4DD} Fichiers qui seraient cr\xE9\xE9s/modifi\xE9s :")));
1122
- for (const plugin of selectedPlugins) {
1123
- console.log(pc2.gray(` \u2022 ${plugin.displayName} configuration`));
1124
- }
1125
- console.log();
1126
- console.log(
1127
- pc2.yellow("\u26A0\uFE0F Aucune modification n'a \xE9t\xE9 effectu\xE9e (dry-run)")
1128
- );
923
+ console.log(pc2.bold(pc2.cyan("\u{1F4E6} Packages \xE0 installer :")));
924
+ for (const plugin of selectedPlugins) {
1129
925
  console.log(
1130
- pc2.cyan("\u{1F4A1} Ex\xE9cutez sans --dry-run pour appliquer les changements")
926
+ pc2.blue(` \u2022 ${plugin.displayName}`) + pc2.gray(
927
+ ` (${plugin.name}${plugin.version ? `@${plugin.version}` : ""})`
928
+ )
1131
929
  );
1132
- console.log();
1133
- return;
1134
930
  }
931
+ console.log();
932
+ console.log(pc2.bold(pc2.cyan("\u{1F4DD} Fichiers qui seraient cr\xE9\xE9s/modifi\xE9s :")));
933
+ for (const plugin of selectedPlugins) {
934
+ console.log(pc2.gray(` \u2022 ${plugin.displayName} configuration`));
935
+ }
936
+ console.log();
937
+ console.log(
938
+ pc2.yellow("\u26A0\uFE0F Aucune modification n'a \xE9t\xE9 effectu\xE9e (dry-run)")
939
+ );
940
+ console.log(
941
+ pc2.cyan("\u{1F4A1} Ex\xE9cutez sans --dry-run pour appliquer les changements")
942
+ );
943
+ console.log();
944
+ return true;
945
+ }
946
+ /**
947
+ * Effectue l'installation des plugins
948
+ *
949
+ * @param ctx - Contexte du projet
950
+ * @param selectedPlugins - Plugins sélectionnés
951
+ * @param language - Langue sélectionnée
952
+ * @param options - Options CLI
953
+ */
954
+ async performInstallation(ctx, selectedPlugins, language, options) {
955
+ const t = getTranslations(language);
1135
956
  const backupManager = new BackupManager();
1136
957
  const configWriter = new ConfigWriter(backupManager);
1137
- const validator = new CompatibilityValidator(compatibilityRules);
958
+ const validator = new CompatibilityValidator(allCompatibilityRules);
1138
959
  const installer = new Installer(ctx, validator, configWriter, backupManager);
1139
960
  if (options.install === false) {
1140
961
  console.log();
@@ -1160,15 +981,70 @@ ${t.installation.error}`);
1160
981
  spinner.fail(t.installation.error);
1161
982
  throw error;
1162
983
  }
1163
- } catch (error) {
1164
- logger.error("Installation failed:", error);
1165
- if (error instanceof Error) {
1166
- console.error(`
1167
- \u274C ${error.message}`);
984
+ }
985
+ /**
986
+ * Méthode principale d'exécution de la commande
987
+ *
988
+ * Cette méthode orchestre toute la logique commune :
989
+ * 1. Sélection de la langue
990
+ * 2. Détection/création du contexte
991
+ * 3. Validation du framework
992
+ * 4. Affichage du contexte
993
+ * 5. Sélection des plugins
994
+ * 6. Confirmation
995
+ * 7. Installation
996
+ *
997
+ * @param options - Options CLI
998
+ */
999
+ async execute(options) {
1000
+ try {
1001
+ const language = await promptLanguage();
1002
+ const t = getTranslations(language);
1003
+ console.log();
1004
+ console.log(pc2.bold(pc2.cyan(`\u{1F50D} ${t.detection.detecting}`)));
1005
+ const projectRoot = process.cwd();
1006
+ const ctx = await this.getOrCreateContext(projectRoot, language);
1007
+ if (!this.validateFramework(ctx)) {
1008
+ this.displayFrameworkMismatchWarning(ctx, t);
1009
+ return;
1010
+ }
1011
+ this.displayDetectedContext(ctx, t);
1012
+ const selectedPlugins = await this.selectPlugins(ctx, language, options);
1013
+ if (selectedPlugins.length === 0) {
1014
+ console.log();
1015
+ console.log(pc2.yellow(`\u26A0\uFE0F ${t.common.selected(0)}`));
1016
+ console.log(pc2.gray("Exiting..."));
1017
+ return;
1018
+ }
1019
+ console.log();
1020
+ console.log(
1021
+ pc2.bold(pc2.green(`\u2713 ${t.common.selected(selectedPlugins.length)}`))
1022
+ );
1023
+ console.log();
1024
+ const confirmed = await this.confirmInstallation(
1025
+ selectedPlugins,
1026
+ language,
1027
+ options
1028
+ );
1029
+ if (!confirmed) {
1030
+ console.log();
1031
+ console.log(pc2.gray(t.common.cancel));
1032
+ return;
1033
+ }
1034
+ if (this.handleDryRun(selectedPlugins, options)) {
1035
+ return;
1036
+ }
1037
+ await this.performInstallation(ctx, selectedPlugins, language, options);
1038
+ } catch (error) {
1039
+ const errorMessage = error instanceof Error ? error.message : String(error);
1040
+ logger.error(`Fatal error: ${errorMessage}`);
1041
+ console.error("Fatal error:", errorMessage);
1042
+ process.exit(1);
1168
1043
  }
1169
- process.exit(1);
1170
1044
  }
1171
- }
1045
+ };
1046
+
1172
1047
  export {
1173
- installReact
1048
+ getFrameworkMetadata,
1049
+ BaseFrameworkCommand
1174
1050
  };