@configjs/cli 1.1.3 → 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-ZSDLWQSS.js → chunk-BVXGN3AC.js} +35 -2
- package/dist/{install-7LTMBLVZ.js → chunk-OAAGGK2H.js} +79 -247
- 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-Y76PWTXI.js → installed-IKSARZIK.js} +1 -1
- package/dist/{list-NW6ENYK6.js → list-IJK225B3.js} +1 -1
- package/dist/{remove-7HJKNAEX.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}`, {
|
|
@@ -1,27 +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";
|
|
5
|
+
PluginTracker
|
|
6
|
+
} from "./chunk-BVXGN3AC.js";
|
|
11
7
|
import {
|
|
12
|
-
DetectionError,
|
|
13
|
-
PluginTracker,
|
|
14
|
-
detectContext
|
|
15
|
-
} from "./chunk-ZSDLWQSS.js";
|
|
16
|
-
import {
|
|
17
|
-
checkPathExists,
|
|
18
8
|
installPackages,
|
|
19
9
|
logger
|
|
20
10
|
} from "./chunk-QRFLHLFE.js";
|
|
21
|
-
import "./chunk-QGM4M3NI.js";
|
|
22
|
-
|
|
23
|
-
// src/cli/prompts/language.ts
|
|
24
|
-
import inquirer from "inquirer";
|
|
25
11
|
|
|
26
12
|
// src/cli/i18n/fr.ts
|
|
27
13
|
var fr = {
|
|
@@ -100,6 +86,27 @@ var fr = {
|
|
|
100
86
|
invalid: "Le nom du projet ne peut contenir que des lettres, chiffres, tirets et underscores"
|
|
101
87
|
},
|
|
102
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.`
|
|
103
110
|
}
|
|
104
111
|
};
|
|
105
112
|
|
|
@@ -180,6 +187,27 @@ var en = {
|
|
|
180
187
|
invalid: "Project name can only contain letters, numbers, dashes and underscores"
|
|
181
188
|
},
|
|
182
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.`
|
|
183
211
|
}
|
|
184
212
|
};
|
|
185
213
|
|
|
@@ -260,6 +288,27 @@ var es = {
|
|
|
260
288
|
invalid: "El nombre del proyecto solo puede contener letras, n\xFAmeros, guiones y guiones bajos"
|
|
261
289
|
},
|
|
262
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.`
|
|
263
312
|
}
|
|
264
313
|
};
|
|
265
314
|
|
|
@@ -278,6 +327,7 @@ function getTranslations(lang) {
|
|
|
278
327
|
}
|
|
279
328
|
|
|
280
329
|
// src/cli/prompts/language.ts
|
|
330
|
+
import inquirer from "inquirer";
|
|
281
331
|
async function promptLanguage() {
|
|
282
332
|
const defaultTranslations = getTranslations("en");
|
|
283
333
|
const { language } = await inquirer.prompt([
|
|
@@ -329,6 +379,9 @@ async function promptPluginSelection(ctx, availablePlugins, lang) {
|
|
|
329
379
|
if (!plugin.frameworks.includes(ctx.framework)) {
|
|
330
380
|
continue;
|
|
331
381
|
}
|
|
382
|
+
if (ctx.framework === "nextjs" && plugin.name === "react-router-dom") {
|
|
383
|
+
continue;
|
|
384
|
+
}
|
|
332
385
|
if (plugin.requiresTypeScript === true && !ctx.typescript) {
|
|
333
386
|
continue;
|
|
334
387
|
}
|
|
@@ -409,88 +462,6 @@ ${translations.confirmation.summary}
|
|
|
409
462
|
return confirm;
|
|
410
463
|
}
|
|
411
464
|
|
|
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
465
|
// src/core/installer.ts
|
|
495
466
|
var Installer = class {
|
|
496
467
|
/**
|
|
@@ -581,7 +552,7 @@ var Installer = class {
|
|
|
581
552
|
}
|
|
582
553
|
}
|
|
583
554
|
logger.debug("Validating plugins compatibility...");
|
|
584
|
-
const validationResult = this.validator.validate(notInstalled);
|
|
555
|
+
const validationResult = this.validator.validate(notInstalled, this.ctx);
|
|
585
556
|
if (!validationResult.valid) {
|
|
586
557
|
const errorMessages = validationResult.errors.map((e) => e.message).join("; ");
|
|
587
558
|
throw new Error(
|
|
@@ -1024,151 +995,12 @@ function displayNextSteps(lang) {
|
|
|
1024
995
|
console.log();
|
|
1025
996
|
}
|
|
1026
997
|
|
|
1027
|
-
// src/cli/commands/install.ts
|
|
1028
|
-
import pc2 from "picocolors";
|
|
1029
|
-
async function installReact(options) {
|
|
1030
|
-
try {
|
|
1031
|
-
const language = await promptLanguage();
|
|
1032
|
-
const t = getTranslations(language);
|
|
1033
|
-
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
|
-
}
|
|
1063
|
-
console.log(
|
|
1064
|
-
pc2.green(` \u2713 ${t.detection.framework}: `) + pc2.bold(`${ctx.framework} ${pc2.gray(ctx.frameworkVersion)}`)
|
|
1065
|
-
);
|
|
1066
|
-
console.log(
|
|
1067
|
-
pc2.green(` \u2713 ${t.detection.typescript}: `) + pc2.bold(ctx.typescript ? "Oui" : "Non")
|
|
1068
|
-
);
|
|
1069
|
-
if (ctx.bundler) {
|
|
1070
|
-
console.log(
|
|
1071
|
-
pc2.green(` \u2713 ${t.detection.bundler}: `) + pc2.bold(`${ctx.bundler} ${pc2.gray(ctx.bundlerVersion || "")}`)
|
|
1072
|
-
);
|
|
1073
|
-
}
|
|
1074
|
-
console.log(
|
|
1075
|
-
pc2.green(` \u2713 ${t.detection.packageManager}: `) + pc2.bold(ctx.packageManager)
|
|
1076
|
-
);
|
|
1077
|
-
console.log();
|
|
1078
|
-
let selectedPlugins = [];
|
|
1079
|
-
if (options.yes) {
|
|
1080
|
-
logger.info("Using default recommendations (--yes mode)");
|
|
1081
|
-
} else {
|
|
1082
|
-
selectedPlugins = await promptPluginSelection(
|
|
1083
|
-
ctx,
|
|
1084
|
-
pluginRegistry,
|
|
1085
|
-
language
|
|
1086
|
-
);
|
|
1087
|
-
}
|
|
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;
|
|
1093
|
-
}
|
|
1094
|
-
console.log();
|
|
1095
|
-
console.log(
|
|
1096
|
-
pc2.bold(pc2.green(`\u2713 ${t.common.selected(selectedPlugins.length)}`))
|
|
1097
|
-
);
|
|
1098
|
-
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
|
-
);
|
|
1129
|
-
console.log(
|
|
1130
|
-
pc2.cyan("\u{1F4A1} Ex\xE9cutez sans --dry-run pour appliquer les changements")
|
|
1131
|
-
);
|
|
1132
|
-
console.log();
|
|
1133
|
-
return;
|
|
1134
|
-
}
|
|
1135
|
-
const backupManager = new BackupManager();
|
|
1136
|
-
const configWriter = new ConfigWriter(backupManager);
|
|
1137
|
-
const validator = new CompatibilityValidator(compatibilityRules);
|
|
1138
|
-
const installer = new Installer(ctx, validator, configWriter, backupManager);
|
|
1139
|
-
if (options.install === false) {
|
|
1140
|
-
console.log();
|
|
1141
|
-
console.log(pc2.yellow("\u2699\uFE0F Mode configuration uniquement (--no-install)"));
|
|
1142
|
-
console.log(pc2.gray("Les packages ne seront PAS install\xE9s"));
|
|
1143
|
-
console.log();
|
|
1144
|
-
}
|
|
1145
|
-
const spinner = new SpinnerManager();
|
|
1146
|
-
spinner.start(t.installation.installing);
|
|
1147
|
-
try {
|
|
1148
|
-
const result = await installer.install(selectedPlugins, {
|
|
1149
|
-
skipPackageInstall: options.install === false
|
|
1150
|
-
});
|
|
1151
|
-
spinner.succeed(t.installation.success);
|
|
1152
|
-
if (result.success) {
|
|
1153
|
-
displayInstallationReport(result, selectedPlugins, language);
|
|
1154
|
-
} else {
|
|
1155
|
-
console.error(`
|
|
1156
|
-
${t.installation.error}`);
|
|
1157
|
-
process.exit(1);
|
|
1158
|
-
}
|
|
1159
|
-
} catch (error) {
|
|
1160
|
-
spinner.fail(t.installation.error);
|
|
1161
|
-
throw error;
|
|
1162
|
-
}
|
|
1163
|
-
} catch (error) {
|
|
1164
|
-
logger.error("Installation failed:", error);
|
|
1165
|
-
if (error instanceof Error) {
|
|
1166
|
-
console.error(`
|
|
1167
|
-
\u274C ${error.message}`);
|
|
1168
|
-
}
|
|
1169
|
-
process.exit(1);
|
|
1170
|
-
}
|
|
1171
|
-
}
|
|
1172
998
|
export {
|
|
1173
|
-
|
|
999
|
+
getTranslations,
|
|
1000
|
+
promptLanguage,
|
|
1001
|
+
promptPluginSelection,
|
|
1002
|
+
promptConfirmation,
|
|
1003
|
+
Installer,
|
|
1004
|
+
SpinnerManager,
|
|
1005
|
+
displayInstallationReport
|
|
1174
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
|
|