@configjs/cli 1.1.4 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,308 +0,0 @@
1
- import {
2
- logger
3
- } from "./chunk-QRFLHLFE.js";
4
-
5
- // src/core/validator.ts
6
- var CompatibilityValidator = class {
7
- /**
8
- * @param rules - Règles de compatibilité à appliquer
9
- */
10
- constructor(rules) {
11
- this.rules = rules;
12
- }
13
- /**
14
- * Valide la compatibilité d'un ensemble de plugins
15
- *
16
- * @param plugins - Liste des plugins à valider
17
- * @param ctx - Contexte du projet (optionnel, pour règles spécifiques framework)
18
- * @returns Résultat de la validation avec erreurs, warnings et suggestions
19
- *
20
- * @example
21
- * ```typescript
22
- * const result = validator.validate([plugin1, plugin2, plugin3], ctx)
23
- * if (!result.valid) {
24
- * // Gérer les erreurs
25
- * }
26
- * ```
27
- */
28
- validate(plugins, ctx) {
29
- logger.debug(`Validating ${plugins.length} plugin(s)`);
30
- const pluginNames = new Set(plugins.map((p) => p.name));
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
- );
39
- const conflictErrors = [];
40
- const conflictWarnings = [];
41
- for (const conflict of allConflicts) {
42
- const rule = applicableRules.find(
43
- (r) => r.type === "CONFLICT" && r.plugins?.every((p) => conflict.plugins?.includes(p))
44
- );
45
- if (rule?.severity === "error") {
46
- conflictErrors.push(conflict);
47
- } else {
48
- conflictWarnings.push(conflict);
49
- }
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
- }
64
- const errors = [
65
- ...this.checkExclusivity(plugins, pluginNames, applicableRules),
66
- ...conflictErrors,
67
- ...this.checkDependencies(plugins, pluginNames, applicableRules),
68
- ...frameworkErrors
69
- ];
70
- const warnings = [...conflictWarnings, ...frameworkWarnings];
71
- const suggestions = this.checkRecommendations(
72
- plugins,
73
- pluginNames,
74
- applicableRules
75
- );
76
- const valid = errors.length === 0;
77
- logger.debug(`Validation result: ${valid ? "valid" : "invalid"}`, {
78
- errors: errors.length,
79
- warnings: warnings.length,
80
- suggestions: suggestions.length
81
- });
82
- return {
83
- valid,
84
- errors,
85
- warnings,
86
- suggestions
87
- };
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
- }
122
- /**
123
- * Vérifie les règles d'exclusivité (EXCLUSIVE)
124
- *
125
- * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
126
- * @param pluginNames - Set des noms de plugins pour lookup rapide
127
- * @param rules - Règles applicables
128
- * @returns Liste des erreurs d'exclusivité
129
- *
130
- * @internal
131
- */
132
- checkExclusivity(_plugins, pluginNames, rules = this.rules) {
133
- const errors = [];
134
- for (const rule of rules) {
135
- if (rule.type !== "EXCLUSIVE" || !rule.plugins) {
136
- continue;
137
- }
138
- const selectedExclusivePlugins = rule.plugins.filter(
139
- (pluginName) => pluginNames.has(pluginName)
140
- );
141
- if (selectedExclusivePlugins.length > 1) {
142
- errors.push({
143
- type: "EXCLUSIVE",
144
- plugins: selectedExclusivePlugins,
145
- message: rule.reason,
146
- canOverride: rule.allowOverride ?? false
147
- });
148
- }
149
- }
150
- return errors;
151
- }
152
- /**
153
- * Vérifie les conflits entre plugins (CONFLICT)
154
- *
155
- * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
156
- * @param pluginNames - Set des noms de plugins pour lookup rapide
157
- * @param rules - Règles applicables
158
- * @returns Liste des warnings/erreurs de conflit
159
- *
160
- * @internal
161
- */
162
- checkConflicts(_plugins, pluginNames, rules = this.rules) {
163
- const conflicts = [];
164
- for (const rule of rules) {
165
- if (rule.framework) {
166
- continue;
167
- }
168
- if (rule.type !== "CONFLICT" || !rule.plugins) {
169
- continue;
170
- }
171
- const conflictingPlugins = rule.plugins.filter(
172
- (pluginName) => pluginNames.has(pluginName)
173
- );
174
- if (conflictingPlugins.length > 1) {
175
- conflicts.push({
176
- type: "CONFLICT",
177
- plugins: conflictingPlugins,
178
- message: rule.reason,
179
- canOverride: rule.allowOverride ?? true
180
- });
181
- }
182
- }
183
- return conflicts;
184
- }
185
- /**
186
- * Vérifie les dépendances requises (REQUIRES)
187
- *
188
- * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
189
- * @param pluginNames - Set des noms de plugins pour lookup rapide
190
- * @param rules - Règles applicables
191
- * @returns Liste des erreurs de dépendances manquantes
192
- *
193
- * @internal
194
- */
195
- checkDependencies(_plugins, pluginNames, rules = this.rules) {
196
- const errors = [];
197
- for (const rule of rules) {
198
- if (rule.type !== "REQUIRES" || !rule.plugin || !rule.requires) {
199
- continue;
200
- }
201
- if (!pluginNames.has(rule.plugin)) {
202
- continue;
203
- }
204
- const missingDependencies = rule.requires.filter(
205
- (dep) => !pluginNames.has(dep)
206
- );
207
- if (missingDependencies.length > 0) {
208
- errors.push({
209
- type: "REQUIRES",
210
- plugin: rule.plugin,
211
- required: missingDependencies.join(", "),
212
- message: `${rule.plugin} requires: ${missingDependencies.join(", ")}. ${rule.reason}`,
213
- canOverride: rule.allowOverride ?? false
214
- });
215
- }
216
- }
217
- return errors;
218
- }
219
- /**
220
- * Vérifie les recommandations (RECOMMENDS)
221
- *
222
- * @param _plugins - Liste des plugins (non utilisée, conservée pour cohérence)
223
- * @param pluginNames - Set des noms de plugins pour lookup rapide
224
- * @param rules - Règles applicables
225
- * @returns Liste des suggestions de plugins recommandés
226
- *
227
- * @internal
228
- */
229
- checkRecommendations(_plugins, pluginNames, rules = this.rules) {
230
- const suggestions = [];
231
- for (const rule of rules) {
232
- if (rule.type !== "RECOMMENDS" || !rule.plugin || !rule.recommends) {
233
- continue;
234
- }
235
- if (!pluginNames.has(rule.plugin)) {
236
- continue;
237
- }
238
- const missingRecommendations = rule.recommends.filter(
239
- (rec) => !pluginNames.has(rec)
240
- );
241
- if (missingRecommendations.length > 0) {
242
- suggestions.push(
243
- `${rule.plugin} recommends: ${missingRecommendations.join(", ")}. ${rule.reason}`
244
- );
245
- }
246
- }
247
- return suggestions;
248
- }
249
- };
250
- var compatibilityRules = [
251
- // Exclusivités - State Management
252
- {
253
- type: "EXCLUSIVE",
254
- plugins: ["@reduxjs/toolkit", "zustand", "jotai"],
255
- reason: "Une seule solution de state management est recommand\xE9e",
256
- severity: "error",
257
- allowOverride: false
258
- },
259
- // Conflits - CSS Frameworks
260
- {
261
- type: "CONFLICT",
262
- plugins: ["tailwindcss", "bootstrap"],
263
- reason: "Approches CSS potentiellement conflictuelles",
264
- severity: "warning",
265
- allowOverride: true
266
- },
267
- // Recommandations - React Router
268
- {
269
- type: "RECOMMENDS",
270
- plugin: "react-router-dom",
271
- recommends: ["@types/react-router-dom"],
272
- reason: "Types TypeScript recommand\xE9s pour une meilleure exp\xE9rience de d\xE9veloppement",
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"
302
- }
303
- ];
304
-
305
- export {
306
- CompatibilityValidator,
307
- compatibilityRules
308
- };
@@ -1,258 +0,0 @@
1
- import {
2
- Installer,
3
- SpinnerManager,
4
- displayInstallationReport,
5
- getTranslations,
6
- promptConfirmation,
7
- promptLanguage,
8
- promptPluginSelection
9
- } from "./chunk-OAAGGK2H.js";
10
- import {
11
- CompatibilityValidator,
12
- compatibilityRules
13
- } from "./chunk-WKYUK64P.js";
14
- import {
15
- BackupManager,
16
- ConfigWriter,
17
- pluginRegistry
18
- } from "./chunk-4VHPGJVU.js";
19
- import {
20
- DetectionError,
21
- detectContext
22
- } from "./chunk-BVXGN3AC.js";
23
- import {
24
- checkPathExists,
25
- logger
26
- } from "./chunk-QRFLHLFE.js";
27
- import "./chunk-QGM4M3NI.js";
28
-
29
- // src/cli/prompts/vite-setup.ts
30
- import inquirer from "inquirer";
31
- async function promptViteSetup(language) {
32
- const t = getTranslations(language);
33
- const answers = await inquirer.prompt([
34
- {
35
- type: "confirm",
36
- name: "shouldCreate",
37
- message: t.vite.proposeSetup,
38
- default: true
39
- },
40
- {
41
- type: "input",
42
- name: "projectName",
43
- message: t.vite.projectName,
44
- default: t.vite.projectNamePlaceholder,
45
- when: (answers2) => answers2.shouldCreate === true,
46
- validate: (input) => {
47
- if (!input || input.trim().length === 0) {
48
- return t.vite.validation.empty;
49
- }
50
- if (!/^[a-z0-9-_]+$/i.test(input)) {
51
- return t.vite.validation.invalid;
52
- }
53
- return true;
54
- }
55
- },
56
- {
57
- type: "list",
58
- name: "template",
59
- message: t.vite.template,
60
- choices: t.vite.templateOptions,
61
- when: (answers2) => answers2.shouldCreate === true
62
- }
63
- ]);
64
- if (!answers.shouldCreate) {
65
- return null;
66
- }
67
- return {
68
- projectName: answers.projectName.trim(),
69
- template: answers.template
70
- };
71
- }
72
-
73
- // src/cli/utils/vite-installer.ts
74
- import { resolve } from "path";
75
- import { execa } from "execa";
76
- async function createViteProject(options, currentDir, language) {
77
- const t = getTranslations(language);
78
- const { projectName, template } = options;
79
- const projectPath = resolve(currentDir, projectName);
80
- if (await checkPathExists(projectPath)) {
81
- throw new Error(t.vite.folderExists(projectName));
82
- }
83
- logger.info(t.vite.creating);
84
- try {
85
- const result = await execa(
86
- "npm",
87
- ["create", "vite@latest", projectName, "--", "--template", template],
88
- {
89
- cwd: currentDir,
90
- stdio: "inherit",
91
- env: {
92
- ...process.env,
93
- // Désactiver les prompts interactifs de Vite
94
- npm_config_yes: "true"
95
- }
96
- }
97
- );
98
- if (result.exitCode !== 0) {
99
- throw new Error(`${t.vite.error}: exit code ${result.exitCode}`);
100
- }
101
- logger.success(t.vite.success);
102
- logger.info(t.vite.changingDirectory);
103
- return projectPath;
104
- } catch (error) {
105
- const errorMessage = error instanceof Error ? error.message : String(error);
106
- logger.error(`${t.vite.error}: ${errorMessage}`);
107
- throw error;
108
- }
109
- }
110
-
111
- // src/cli/commands/install.ts
112
- import pc from "picocolors";
113
- async function installReact(options) {
114
- try {
115
- const language = await promptLanguage();
116
- const t = getTranslations(language);
117
- console.log();
118
- console.log(pc.bold(pc.cyan(`\u{1F50D} ${t.detection.detecting}`)));
119
- let projectRoot = process.cwd();
120
- let ctx;
121
- try {
122
- ctx = await detectContext(projectRoot);
123
- } catch (error) {
124
- if (error instanceof DetectionError) {
125
- console.log();
126
- console.log(pc.yellow(t.vite.noReactDetected));
127
- console.log();
128
- const viteOptions = await promptViteSetup(language);
129
- if (!viteOptions) {
130
- console.log();
131
- console.log(pc.gray(t.common.cancel));
132
- return;
133
- }
134
- const newProjectPath = await createViteProject(
135
- viteOptions,
136
- projectRoot,
137
- language
138
- );
139
- process.chdir(newProjectPath);
140
- projectRoot = newProjectPath;
141
- console.log();
142
- ctx = await detectContext(projectRoot);
143
- } else {
144
- throw error;
145
- }
146
- }
147
- console.log(
148
- pc.green(` \u2713 ${t.detection.framework}: `) + pc.bold(`${ctx.framework} ${pc.gray(ctx.frameworkVersion)}`)
149
- );
150
- console.log(
151
- pc.green(` \u2713 ${t.detection.typescript}: `) + pc.bold(ctx.typescript ? "Oui" : "Non")
152
- );
153
- if (ctx.bundler) {
154
- console.log(
155
- pc.green(` \u2713 ${t.detection.bundler}: `) + pc.bold(`${ctx.bundler} ${pc.gray(ctx.bundlerVersion || "")}`)
156
- );
157
- }
158
- console.log(
159
- pc.green(` \u2713 ${t.detection.packageManager}: `) + pc.bold(ctx.packageManager)
160
- );
161
- console.log();
162
- let selectedPlugins = [];
163
- if (options.yes) {
164
- logger.info("Using default recommendations (--yes mode)");
165
- } else {
166
- selectedPlugins = await promptPluginSelection(
167
- ctx,
168
- pluginRegistry,
169
- language
170
- );
171
- }
172
- if (selectedPlugins.length === 0) {
173
- console.log();
174
- console.log(pc.yellow(`\u26A0\uFE0F ${t.common.selected(0)}`));
175
- console.log(pc.gray("Exiting..."));
176
- return;
177
- }
178
- console.log();
179
- console.log(
180
- pc.bold(pc.green(`\u2713 ${t.common.selected(selectedPlugins.length)}`))
181
- );
182
- console.log();
183
- if (!options.yes && !options.silent) {
184
- const confirmed = await promptConfirmation(selectedPlugins, language);
185
- if (!confirmed) {
186
- console.log(t.common.cancel);
187
- return;
188
- }
189
- }
190
- if (options.dryRun) {
191
- console.log();
192
- console.log(pc.bold(pc.yellow("\u2501".repeat(60))));
193
- console.log(pc.bold(pc.yellow("\u{1F50D} MODE DRY-RUN (simulation uniquement)")));
194
- console.log(pc.bold(pc.yellow("\u2501".repeat(60))));
195
- console.log();
196
- console.log(pc.bold(pc.cyan("\u{1F4E6} Packages \xE0 installer :")));
197
- for (const plugin of selectedPlugins) {
198
- console.log(
199
- pc.blue(` \u2022 ${plugin.displayName}`) + pc.gray(
200
- ` (${plugin.name}${plugin.version ? `@${plugin.version}` : ""})`
201
- )
202
- );
203
- }
204
- console.log();
205
- console.log(pc.bold(pc.cyan("\u{1F4DD} Fichiers qui seraient cr\xE9\xE9s/modifi\xE9s :")));
206
- for (const plugin of selectedPlugins) {
207
- console.log(pc.gray(` \u2022 ${plugin.displayName} configuration`));
208
- }
209
- console.log();
210
- console.log(
211
- pc.yellow("\u26A0\uFE0F Aucune modification n'a \xE9t\xE9 effectu\xE9e (dry-run)")
212
- );
213
- console.log(
214
- pc.cyan("\u{1F4A1} Ex\xE9cutez sans --dry-run pour appliquer les changements")
215
- );
216
- console.log();
217
- return;
218
- }
219
- const backupManager = new BackupManager();
220
- const configWriter = new ConfigWriter(backupManager);
221
- const validator = new CompatibilityValidator(compatibilityRules);
222
- const installer = new Installer(ctx, validator, configWriter, backupManager);
223
- if (options.install === false) {
224
- console.log();
225
- console.log(pc.yellow("\u2699\uFE0F Mode configuration uniquement (--no-install)"));
226
- console.log(pc.gray("Les packages ne seront PAS install\xE9s"));
227
- console.log();
228
- }
229
- const spinner = new SpinnerManager();
230
- spinner.start(t.installation.installing);
231
- try {
232
- const result = await installer.install(selectedPlugins, {
233
- skipPackageInstall: options.install === false
234
- });
235
- spinner.succeed(t.installation.success);
236
- if (result.success) {
237
- displayInstallationReport(result, selectedPlugins, language);
238
- } else {
239
- console.error(`
240
- ${t.installation.error}`);
241
- process.exit(1);
242
- }
243
- } catch (error) {
244
- spinner.fail(t.installation.error);
245
- throw error;
246
- }
247
- } catch (error) {
248
- logger.error("Installation failed:", error);
249
- if (error instanceof Error) {
250
- console.error(`
251
- \u274C ${error.message}`);
252
- }
253
- process.exit(1);
254
- }
255
- }
256
- export {
257
- installReact
258
- };