@configjs/cli 1.1.4 → 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.
- package/README.fr.md +1 -1
- package/README.md +16 -2
- package/dist/{check-XDGAGYOE.js → check-AJCBQBFD.js} +6 -5
- package/dist/chunk-3V72QFFY.js +383 -0
- package/dist/{chunk-OAAGGK2H.js → chunk-CNAEKUBH.js} +361 -317
- package/dist/chunk-D37FHAGO.js +569 -0
- package/dist/chunk-HM2JWJOO.js +418 -0
- package/dist/chunk-MQV3WNMH.js +114 -0
- package/dist/{chunk-BVXGN3AC.js → chunk-TVZWTKJU.js} +316 -224
- package/dist/{chunk-4VHPGJVU.js → chunk-V75HW2AM.js} +8557 -6661
- package/dist/cli.js +23 -9
- package/dist/{installed-IKSARZIK.js → installed-WA6I2IFD.js} +4 -3
- package/dist/{list-IJK225B3.js → list-Y7I5NUWT.js} +3 -2
- package/dist/nextjs-command-AUVNEBHG.js +59 -0
- package/dist/nextjs-installer-RWBGWW23.js +80 -0
- package/dist/nextjs-setup-7LWMEC5I.js +100 -0
- package/dist/react-command-DTIKCCPO.js +59 -0
- package/dist/{remove-IIT34Y3T.js → remove-JBICRDXX.js} +4 -3
- package/dist/vite-installer-XIJFJ4CN.js +49 -0
- package/dist/vite-setup-3U22LJFG.js +51 -0
- package/dist/vue-command-R4XETTRT.js +73 -0
- package/dist/vue-installer-SFROF4N3.js +74 -0
- package/dist/vue-setup-X65P3CZX.js +91 -0
- package/package.json +5 -2
- package/dist/chunk-QRFLHLFE.js +0 -300
- package/dist/chunk-WKYUK64P.js +0 -308
- package/dist/install-APYIRHSN.js +0 -258
- package/dist/install-nextjs-C3LEKJLY.js +0 -353
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
// src/utils/logger.ts
|
|
2
|
+
import pc from "picocolors";
|
|
3
|
+
var Logger = class {
|
|
4
|
+
level = 1 /* INFO */;
|
|
5
|
+
setLevel(level) {
|
|
6
|
+
this.level = level;
|
|
7
|
+
}
|
|
8
|
+
debug(message, ...args) {
|
|
9
|
+
if (this.level <= 0 /* DEBUG */) {
|
|
10
|
+
console.log(pc.gray(`[DEBUG] ${message}`), ...args);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
info(message, ...args) {
|
|
14
|
+
if (this.level <= 1 /* INFO */) {
|
|
15
|
+
console.log(pc.cyan(`\u2139 ${message}`), ...args);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
success(message, ...args) {
|
|
19
|
+
if (this.level <= 1 /* INFO */) {
|
|
20
|
+
console.log(pc.green(`\u2713 ${message}`), ...args);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
warn(message, ...args) {
|
|
24
|
+
if (this.level <= 2 /* WARN */) {
|
|
25
|
+
console.warn(pc.yellow(`\u26A0\uFE0F ${message}`), ...args);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
error(message, ...args) {
|
|
29
|
+
if (this.level <= 3 /* ERROR */) {
|
|
30
|
+
console.error(pc.red(`\u2716 ${message}`), ...args);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
header(message) {
|
|
34
|
+
if (this.level <= 1 /* INFO */) {
|
|
35
|
+
console.log();
|
|
36
|
+
console.log(pc.bold(pc.magenta(`\u25C6 ${message}`)));
|
|
37
|
+
console.log();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
section(title) {
|
|
41
|
+
if (this.level <= 1 /* INFO */) {
|
|
42
|
+
console.log();
|
|
43
|
+
console.log(pc.bold(pc.cyan(`\u25B8 ${title}`)));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
item(message, color = "gray") {
|
|
47
|
+
if (this.level <= 1 /* INFO */) {
|
|
48
|
+
const colorFn = pc[color];
|
|
49
|
+
console.log(colorFn(` \u2022 ${message}`));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
dim(message) {
|
|
53
|
+
if (this.level <= 1 /* INFO */) {
|
|
54
|
+
console.log(pc.gray(` ${message}`));
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
step(message) {
|
|
58
|
+
if (this.level <= 1 /* INFO */) {
|
|
59
|
+
console.log(pc.cyan(`
|
|
60
|
+
\u2192 ${message}`));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
box(title, content) {
|
|
64
|
+
if (this.level <= 1 /* INFO */) {
|
|
65
|
+
const maxLength = Math.max(
|
|
66
|
+
title.length,
|
|
67
|
+
...content.map((line) => line.length)
|
|
68
|
+
);
|
|
69
|
+
const border = "\u2500".repeat(maxLength + 4);
|
|
70
|
+
console.log(pc.cyan(`\u250C${border}\u2510`));
|
|
71
|
+
console.log(pc.cyan(`\u2502 ${title.padEnd(maxLength)} \u2502`));
|
|
72
|
+
console.log(pc.cyan(`\u251C${border}\u2524`));
|
|
73
|
+
content.forEach((line) => {
|
|
74
|
+
console.log(pc.cyan(`\u2502 ${line.padEnd(maxLength)} \u2502`));
|
|
75
|
+
});
|
|
76
|
+
console.log(pc.cyan(`\u2514${border}\u2518`));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
var logger = new Logger();
|
|
81
|
+
|
|
82
|
+
// src/utils/fs-helpers.ts
|
|
83
|
+
import { resolve as resolve2, dirname as dirname2, extname } from "path";
|
|
84
|
+
|
|
85
|
+
// src/core/fs-adapter.ts
|
|
86
|
+
import fs from "fs-extra";
|
|
87
|
+
import { resolve, dirname } from "path";
|
|
88
|
+
var FileSystemAdapter = class {
|
|
89
|
+
/**
|
|
90
|
+
* @param fsImpl - Implémentation du filesystem (memfs) ou undefined pour fs-extra
|
|
91
|
+
*/
|
|
92
|
+
constructor(fsImpl) {
|
|
93
|
+
this.fsImpl = fsImpl;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Obtient l'implémentation du filesystem
|
|
97
|
+
*/
|
|
98
|
+
getFs() {
|
|
99
|
+
return this.fsImpl || fs;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Normalise un chemin (résout les chemins relatifs)
|
|
103
|
+
*/
|
|
104
|
+
normalizePath(path) {
|
|
105
|
+
return resolve(path);
|
|
106
|
+
}
|
|
107
|
+
// ===== Async Operations =====
|
|
108
|
+
async readFile(path, encoding = "utf-8") {
|
|
109
|
+
const fullPath = this.normalizePath(path);
|
|
110
|
+
const implementation = this.getFs();
|
|
111
|
+
if (this.fsImpl) {
|
|
112
|
+
const content = await implementation.promises.readFile(fullPath, encoding);
|
|
113
|
+
if (typeof content === "string") {
|
|
114
|
+
return content;
|
|
115
|
+
}
|
|
116
|
+
const buffer = content;
|
|
117
|
+
return buffer.toString(encoding);
|
|
118
|
+
} else {
|
|
119
|
+
const content = await fs.readFile(fullPath, encoding);
|
|
120
|
+
if (typeof content === "string") {
|
|
121
|
+
return content;
|
|
122
|
+
}
|
|
123
|
+
const buffer = content;
|
|
124
|
+
return buffer.toString(encoding);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
async writeFile(path, content, encoding = "utf-8") {
|
|
128
|
+
const fullPath = this.normalizePath(path);
|
|
129
|
+
const implementation = this.getFs();
|
|
130
|
+
const parentDir = dirname(fullPath);
|
|
131
|
+
await this.mkdir(parentDir, { recursive: true });
|
|
132
|
+
if (this.fsImpl) {
|
|
133
|
+
await implementation.promises.writeFile(fullPath, content, encoding);
|
|
134
|
+
} else {
|
|
135
|
+
await fs.writeFile(fullPath, content, encoding);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
async mkdir(path, _options) {
|
|
139
|
+
const fullPath = this.normalizePath(path);
|
|
140
|
+
const implementation = this.getFs();
|
|
141
|
+
if (this.fsImpl) {
|
|
142
|
+
await implementation.promises.mkdir(fullPath, { recursive: true });
|
|
143
|
+
} else {
|
|
144
|
+
await fs.ensureDir(fullPath);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async readdir(path) {
|
|
148
|
+
const fullPath = this.normalizePath(path);
|
|
149
|
+
if (this.fsImpl) {
|
|
150
|
+
const entries = this.fsImpl.readdirSync(fullPath);
|
|
151
|
+
return Promise.resolve(entries.map((entry) => String(entry)));
|
|
152
|
+
} else {
|
|
153
|
+
return await fs.readdir(fullPath);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
async stat(path) {
|
|
157
|
+
const fullPath = this.normalizePath(path);
|
|
158
|
+
const implementation = this.getFs();
|
|
159
|
+
if (this.fsImpl) {
|
|
160
|
+
const stats = await implementation.promises.stat(fullPath);
|
|
161
|
+
return {
|
|
162
|
+
isFile: () => stats.isFile(),
|
|
163
|
+
isDirectory: () => stats.isDirectory(),
|
|
164
|
+
mtime: stats.mtime
|
|
165
|
+
};
|
|
166
|
+
} else {
|
|
167
|
+
const stats = await fs.stat(fullPath);
|
|
168
|
+
return {
|
|
169
|
+
isFile: () => stats.isFile(),
|
|
170
|
+
isDirectory: () => stats.isDirectory(),
|
|
171
|
+
mtime: stats.mtime
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
async pathExists(path) {
|
|
176
|
+
const fullPath = this.normalizePath(path);
|
|
177
|
+
const implementation = this.getFs();
|
|
178
|
+
if (this.fsImpl) {
|
|
179
|
+
try {
|
|
180
|
+
await implementation.promises.access(fullPath);
|
|
181
|
+
return true;
|
|
182
|
+
} catch {
|
|
183
|
+
return false;
|
|
184
|
+
}
|
|
185
|
+
} else {
|
|
186
|
+
return await fs.pathExists(fullPath);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async readJson(path) {
|
|
190
|
+
const fullPath = this.normalizePath(path);
|
|
191
|
+
if (this.fsImpl) {
|
|
192
|
+
const content = await this.readFile(fullPath);
|
|
193
|
+
return JSON.parse(content);
|
|
194
|
+
} else {
|
|
195
|
+
return await fs.readJson(fullPath);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async writeJson(path, data, options) {
|
|
199
|
+
const fullPath = this.normalizePath(path);
|
|
200
|
+
const parentDir = dirname(fullPath);
|
|
201
|
+
await this.mkdir(parentDir, { recursive: true });
|
|
202
|
+
if (this.fsImpl) {
|
|
203
|
+
const content = JSON.stringify(data, null, options?.spaces ?? 2);
|
|
204
|
+
await this.writeFile(fullPath, content);
|
|
205
|
+
} else {
|
|
206
|
+
await fs.writeJson(fullPath, data, {
|
|
207
|
+
spaces: options?.spaces ?? 2,
|
|
208
|
+
EOL: options?.EOL ?? "\n"
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async copyFile(src, dest) {
|
|
213
|
+
const srcPath = this.normalizePath(src);
|
|
214
|
+
const destPath = this.normalizePath(dest);
|
|
215
|
+
const destDir = dirname(destPath);
|
|
216
|
+
await this.mkdir(destDir, { recursive: true });
|
|
217
|
+
if (this.fsImpl) {
|
|
218
|
+
const content = await this.readFile(srcPath);
|
|
219
|
+
await this.writeFile(destPath, content);
|
|
220
|
+
} else {
|
|
221
|
+
await fs.copyFile(srcPath, destPath);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
async remove(path) {
|
|
225
|
+
const fullPath = this.normalizePath(path);
|
|
226
|
+
const implementation = this.getFs();
|
|
227
|
+
if (this.fsImpl) {
|
|
228
|
+
try {
|
|
229
|
+
const stats = await this.stat(fullPath);
|
|
230
|
+
if (stats.isDirectory()) {
|
|
231
|
+
await implementation.promises.rm(fullPath, { recursive: true });
|
|
232
|
+
} else {
|
|
233
|
+
await implementation.promises.unlink(fullPath);
|
|
234
|
+
}
|
|
235
|
+
} catch {
|
|
236
|
+
}
|
|
237
|
+
} else {
|
|
238
|
+
await fs.remove(fullPath);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
// ===== Sync Operations (pour compatibilité) =====
|
|
242
|
+
readFileSync(path, encoding = "utf-8") {
|
|
243
|
+
const fullPath = this.normalizePath(path);
|
|
244
|
+
const implementation = this.getFs();
|
|
245
|
+
if (this.fsImpl) {
|
|
246
|
+
const content = implementation.readFileSync(fullPath, encoding);
|
|
247
|
+
if (typeof content === "string") {
|
|
248
|
+
return content;
|
|
249
|
+
}
|
|
250
|
+
const buffer = content;
|
|
251
|
+
return buffer.toString(encoding);
|
|
252
|
+
} else {
|
|
253
|
+
const content = fs.readFileSync(fullPath, encoding);
|
|
254
|
+
if (typeof content === "string") {
|
|
255
|
+
return content;
|
|
256
|
+
}
|
|
257
|
+
const buffer = content;
|
|
258
|
+
return buffer.toString(encoding);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
writeFileSync(path, content) {
|
|
262
|
+
const fullPath = this.normalizePath(path);
|
|
263
|
+
const implementation = this.getFs();
|
|
264
|
+
const parentDir = dirname(fullPath);
|
|
265
|
+
if (!this.existsSync(parentDir)) {
|
|
266
|
+
this.mkdirSync(parentDir, { recursive: true });
|
|
267
|
+
}
|
|
268
|
+
if (this.fsImpl) {
|
|
269
|
+
implementation.writeFileSync(fullPath, content);
|
|
270
|
+
} else {
|
|
271
|
+
fs.writeFileSync(fullPath, content);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
existsSync(path) {
|
|
275
|
+
const fullPath = this.normalizePath(path);
|
|
276
|
+
const implementation = this.getFs();
|
|
277
|
+
if (this.fsImpl) {
|
|
278
|
+
try {
|
|
279
|
+
implementation.statSync(fullPath);
|
|
280
|
+
return true;
|
|
281
|
+
} catch {
|
|
282
|
+
return false;
|
|
283
|
+
}
|
|
284
|
+
} else {
|
|
285
|
+
return fs.existsSync(fullPath);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
mkdirSync(path, _options) {
|
|
289
|
+
const fullPath = this.normalizePath(path);
|
|
290
|
+
const implementation = this.getFs();
|
|
291
|
+
if (this.fsImpl) {
|
|
292
|
+
implementation.mkdirSync(fullPath, { recursive: true });
|
|
293
|
+
} else {
|
|
294
|
+
fs.ensureDirSync(fullPath);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
function createDefaultFsAdapter() {
|
|
299
|
+
return new FileSystemAdapter();
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
// src/utils/fs-helpers.ts
|
|
303
|
+
function normalizePath(path) {
|
|
304
|
+
return path.replace(/\\/g, "/");
|
|
305
|
+
}
|
|
306
|
+
async function readPackageJson(root, fsAdapter) {
|
|
307
|
+
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
308
|
+
const packageJsonPath = resolve2(root, "package.json");
|
|
309
|
+
if (!await adapter.pathExists(packageJsonPath)) {
|
|
310
|
+
throw new Error(`package.json not found at ${packageJsonPath}`);
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
const pkg = await adapter.readJson(packageJsonPath);
|
|
314
|
+
logger.debug(`Read package.json from ${packageJsonPath}`);
|
|
315
|
+
return pkg;
|
|
316
|
+
} catch (error) {
|
|
317
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
318
|
+
throw new Error(
|
|
319
|
+
`Failed to read package.json: ${errorMessage}. File may be invalid JSON.`
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
async function writePackageJson(root, pkg, fsAdapter) {
|
|
324
|
+
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
325
|
+
const packageJsonPath = resolve2(root, "package.json");
|
|
326
|
+
try {
|
|
327
|
+
await adapter.writeJson(packageJsonPath, pkg, {
|
|
328
|
+
spaces: 2,
|
|
329
|
+
EOL: "\n"
|
|
330
|
+
});
|
|
331
|
+
logger.debug(`Wrote package.json to ${packageJsonPath}`);
|
|
332
|
+
} catch (error) {
|
|
333
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
334
|
+
throw new Error(`Failed to write package.json: ${errorMessage}`);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async function readTsConfig(root, fsAdapter) {
|
|
338
|
+
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
339
|
+
const possiblePaths = [
|
|
340
|
+
resolve2(root, "tsconfig.json"),
|
|
341
|
+
resolve2(root, "tsconfig.app.json"),
|
|
342
|
+
resolve2(root, "tsconfig.node.json")
|
|
343
|
+
];
|
|
344
|
+
for (const tsconfigPath of possiblePaths) {
|
|
345
|
+
if (await adapter.pathExists(tsconfigPath)) {
|
|
346
|
+
try {
|
|
347
|
+
const config = await adapter.readJson(tsconfigPath);
|
|
348
|
+
logger.debug(`Read tsconfig.json from ${tsconfigPath}`);
|
|
349
|
+
return config;
|
|
350
|
+
} catch (error) {
|
|
351
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
352
|
+
logger.warn(
|
|
353
|
+
`Failed to parse tsconfig.json at ${tsconfigPath}: ${errorMessage}`
|
|
354
|
+
);
|
|
355
|
+
return null;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
logger.debug("No tsconfig.json found");
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
async function checkPathExists(path, fsAdapter) {
|
|
363
|
+
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
364
|
+
const fullPath = resolve2(path);
|
|
365
|
+
return adapter.pathExists(fullPath);
|
|
366
|
+
}
|
|
367
|
+
async function ensureDirectory(path, fsAdapter) {
|
|
368
|
+
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
369
|
+
const fullPath = resolve2(path);
|
|
370
|
+
try {
|
|
371
|
+
await adapter.mkdir(fullPath, { recursive: true });
|
|
372
|
+
logger.debug(`Ensured directory exists: ${fullPath}`);
|
|
373
|
+
} catch (error) {
|
|
374
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
375
|
+
throw new Error(`Failed to create directory ${fullPath}: ${errorMessage}`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
async function readFileContent(filePath, encoding = "utf-8", fsAdapter) {
|
|
379
|
+
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
380
|
+
const fullPath = resolve2(filePath);
|
|
381
|
+
if (!await adapter.pathExists(fullPath)) {
|
|
382
|
+
throw new Error(`File not found: ${fullPath}`);
|
|
383
|
+
}
|
|
384
|
+
try {
|
|
385
|
+
const content = await adapter.readFile(fullPath, encoding || "utf-8");
|
|
386
|
+
logger.debug(`Read file: ${fullPath}`);
|
|
387
|
+
return content;
|
|
388
|
+
} catch (error) {
|
|
389
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
390
|
+
throw new Error(`Failed to read file ${fullPath}: ${errorMessage}`);
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
async function writeFileContent(filePath, content, encoding = "utf-8", fsAdapter) {
|
|
394
|
+
const adapter = fsAdapter || createDefaultFsAdapter();
|
|
395
|
+
const fullPath = resolve2(filePath);
|
|
396
|
+
const parentDir = dirname2(fullPath);
|
|
397
|
+
await ensureDirectory(parentDir, adapter);
|
|
398
|
+
try {
|
|
399
|
+
await adapter.writeFile(fullPath, content, encoding);
|
|
400
|
+
logger.debug(`Wrote file: ${fullPath}`);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
403
|
+
throw new Error(`Failed to write file ${fullPath}: ${errorMessage}`);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
export {
|
|
408
|
+
logger,
|
|
409
|
+
createDefaultFsAdapter,
|
|
410
|
+
normalizePath,
|
|
411
|
+
readPackageJson,
|
|
412
|
+
writePackageJson,
|
|
413
|
+
readTsConfig,
|
|
414
|
+
checkPathExists,
|
|
415
|
+
ensureDirectory,
|
|
416
|
+
readFileContent,
|
|
417
|
+
writeFileContent
|
|
418
|
+
};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
logger
|
|
3
|
+
} from "./chunk-HM2JWJOO.js";
|
|
4
|
+
|
|
5
|
+
// src/utils/package-manager.ts
|
|
6
|
+
import { execa } from "execa";
|
|
7
|
+
import fs from "fs-extra";
|
|
8
|
+
import { resolve, join } from "path";
|
|
9
|
+
async function detectPackageManager(projectRoot) {
|
|
10
|
+
const root = resolve(projectRoot);
|
|
11
|
+
const lockfiles = [
|
|
12
|
+
{ file: "pnpm-lock.yaml", manager: "pnpm" },
|
|
13
|
+
{ file: "yarn.lock", manager: "yarn" },
|
|
14
|
+
{ file: "package-lock.json", manager: "npm" },
|
|
15
|
+
{ file: "bun.lockb", manager: "bun" }
|
|
16
|
+
];
|
|
17
|
+
for (const { file, manager } of lockfiles) {
|
|
18
|
+
const lockfilePath = join(root, file);
|
|
19
|
+
if (await fs.pathExists(lockfilePath)) {
|
|
20
|
+
logger.debug(`Detected package manager: ${manager} (found ${file})`);
|
|
21
|
+
return manager;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
logger.debug("No lockfile found, defaulting to npm");
|
|
25
|
+
return "npm";
|
|
26
|
+
}
|
|
27
|
+
async function installPackages(packages, options) {
|
|
28
|
+
if (packages.length === 0) {
|
|
29
|
+
logger.warn("No packages to install");
|
|
30
|
+
return { success: true, packages: [] };
|
|
31
|
+
}
|
|
32
|
+
const {
|
|
33
|
+
packageManager,
|
|
34
|
+
projectRoot,
|
|
35
|
+
dev = false,
|
|
36
|
+
exact = false,
|
|
37
|
+
silent = false
|
|
38
|
+
} = options;
|
|
39
|
+
logger.info(
|
|
40
|
+
`Installing ${packages.length} package(s) with ${packageManager}...`
|
|
41
|
+
);
|
|
42
|
+
try {
|
|
43
|
+
const command = getInstallCommand(packageManager, packages, { dev, exact });
|
|
44
|
+
const cwd = resolve(projectRoot);
|
|
45
|
+
logger.debug(`Executing: ${command.join(" ")} in ${cwd}`);
|
|
46
|
+
const [cmd, ...args] = command;
|
|
47
|
+
if (!cmd) {
|
|
48
|
+
throw new Error("Command is empty");
|
|
49
|
+
}
|
|
50
|
+
const result = await execa(cmd, args, {
|
|
51
|
+
cwd,
|
|
52
|
+
stdio: silent ? "pipe" : "inherit",
|
|
53
|
+
env: {
|
|
54
|
+
...process.env,
|
|
55
|
+
// Désactiver les prompts interactifs
|
|
56
|
+
npm_config_yes: "true",
|
|
57
|
+
YARN_ENABLE_IMMUTABLE_INSTALLS: "false"
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
if (result.exitCode !== 0) {
|
|
61
|
+
throw new Error(`Installation failed with exit code ${result.exitCode}`);
|
|
62
|
+
}
|
|
63
|
+
logger.success(`Successfully installed ${packages.length} package(s)`);
|
|
64
|
+
return {
|
|
65
|
+
success: true,
|
|
66
|
+
packages
|
|
67
|
+
};
|
|
68
|
+
} catch (error) {
|
|
69
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
70
|
+
logger.error(`Failed to install packages: ${errorMessage}`);
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
packages,
|
|
74
|
+
error: errorMessage
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function getInstallCommand(packageManager, packages, options) {
|
|
79
|
+
const { dev, exact } = options;
|
|
80
|
+
switch (packageManager) {
|
|
81
|
+
case "pnpm":
|
|
82
|
+
return [
|
|
83
|
+
"pnpm",
|
|
84
|
+
"add",
|
|
85
|
+
...dev ? ["-D"] : [],
|
|
86
|
+
...exact ? ["--save-exact"] : [],
|
|
87
|
+
...packages
|
|
88
|
+
];
|
|
89
|
+
case "yarn":
|
|
90
|
+
return [
|
|
91
|
+
"yarn",
|
|
92
|
+
"add",
|
|
93
|
+
...dev ? ["--dev"] : [],
|
|
94
|
+
...exact ? ["--exact"] : [],
|
|
95
|
+
...packages
|
|
96
|
+
];
|
|
97
|
+
case "bun":
|
|
98
|
+
return ["bun", "add", ...dev ? ["--dev"] : [], ...packages];
|
|
99
|
+
case "npm":
|
|
100
|
+
default:
|
|
101
|
+
return [
|
|
102
|
+
"npm",
|
|
103
|
+
"install",
|
|
104
|
+
...dev ? ["--save-dev"] : [],
|
|
105
|
+
...exact ? ["--save-exact"] : [],
|
|
106
|
+
...packages
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
detectPackageManager,
|
|
113
|
+
installPackages
|
|
114
|
+
};
|