@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.
- package/README.md +25 -5
- package/dist/{check-7PYMMMZK.js → check-XDGAGYOE.js} +2 -2
- package/dist/{chunk-OJGTPK6N.js → chunk-4VHPGJVU.js} +1674 -11
- package/dist/{chunk-QDVUNUTK.js → chunk-BVXGN3AC.js} +36 -2
- package/dist/{install-UTFQ545S.js → chunk-OAAGGK2H.js} +139 -137
- package/dist/{chunk-VJ254HJY.js → chunk-WKYUK64P.js} +110 -16
- package/dist/cli.js +17 -6
- package/dist/install-APYIRHSN.js +258 -0
- package/dist/install-nextjs-C3LEKJLY.js +353 -0
- package/dist/{installed-G2RXXXZ6.js → installed-IKSARZIK.js} +1 -1
- package/dist/{list-NW6ENYK6.js → list-IJK225B3.js} +1 -1
- package/dist/{remove-QDF5BA6U.js → remove-IIT34Y3T.js} +1 -1
- package/package.json +1 -1
|
@@ -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
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-VJ254HJY.js";
|
|
2
|
+
getPluginsByCategory
|
|
3
|
+
} from "./chunk-4VHPGJVU.js";
|
|
5
4
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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(
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|