project-runner 0.1.2 → 0.2.0
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 +1 -0
- package/dist/index.js +193 -103
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -17,6 +17,13 @@ var colors = {
|
|
|
17
17
|
white: "\x1B[37m",
|
|
18
18
|
gray: "\x1B[90m"
|
|
19
19
|
};
|
|
20
|
+
var CliError = class extends Error {
|
|
21
|
+
constructor(message, exitCode = 1) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.exitCode = exitCode;
|
|
24
|
+
this.name = "CliError";
|
|
25
|
+
}
|
|
26
|
+
};
|
|
20
27
|
var isVerbose = false;
|
|
21
28
|
function setVerbose(verbose) {
|
|
22
29
|
isVerbose = verbose;
|
|
@@ -74,6 +81,34 @@ async function execute(cmd, options = {}) {
|
|
|
74
81
|
});
|
|
75
82
|
});
|
|
76
83
|
}
|
|
84
|
+
async function executeCapture(cmd, options = {}) {
|
|
85
|
+
const { cwd = process.cwd(), env } = options;
|
|
86
|
+
return new Promise((resolve2, reject) => {
|
|
87
|
+
const isWindows = process.platform === "win32";
|
|
88
|
+
const command = cmd[0] || "";
|
|
89
|
+
const args = cmd.slice(1);
|
|
90
|
+
const proc = spawn(command, args, {
|
|
91
|
+
cwd,
|
|
92
|
+
env: { ...process.env, ...env },
|
|
93
|
+
shell: isWindows,
|
|
94
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
95
|
+
});
|
|
96
|
+
let stdout = "";
|
|
97
|
+
let stderr = "";
|
|
98
|
+
proc.stdout.on("data", (data) => {
|
|
99
|
+
stdout += data.toString();
|
|
100
|
+
});
|
|
101
|
+
proc.stderr.on("data", (data) => {
|
|
102
|
+
stderr += data.toString();
|
|
103
|
+
});
|
|
104
|
+
proc.on("close", (code) => {
|
|
105
|
+
resolve2({ stdout, stderr, exitCode: code ?? 0 });
|
|
106
|
+
});
|
|
107
|
+
proc.on("error", (err) => {
|
|
108
|
+
reject(err);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
77
112
|
function setupSignalHandlers() {
|
|
78
113
|
process.on("SIGINT", () => {
|
|
79
114
|
if (currentProcess) {
|
|
@@ -90,12 +125,32 @@ function setupSignalHandlers() {
|
|
|
90
125
|
}
|
|
91
126
|
|
|
92
127
|
// src/analyzer/index.ts
|
|
93
|
-
import { readFile
|
|
94
|
-
import { join as
|
|
128
|
+
import { readFile } from "fs/promises";
|
|
129
|
+
import { join as join3 } from "path";
|
|
95
130
|
|
|
96
131
|
// src/analyzer/package-manager.ts
|
|
97
|
-
import { readFile, stat } from "fs/promises";
|
|
98
132
|
import { join } from "path";
|
|
133
|
+
|
|
134
|
+
// src/utils/fs.ts
|
|
135
|
+
import { stat } from "fs/promises";
|
|
136
|
+
async function fileExists(path) {
|
|
137
|
+
try {
|
|
138
|
+
const stats = await stat(path);
|
|
139
|
+
return stats.isFile();
|
|
140
|
+
} catch {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function directoryExists(path) {
|
|
145
|
+
try {
|
|
146
|
+
const stats = await stat(path);
|
|
147
|
+
return stats.isDirectory();
|
|
148
|
+
} catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// src/analyzer/package-manager.ts
|
|
99
154
|
var LOCKFILE_MAP = {
|
|
100
155
|
"bun.lockb": "bun",
|
|
101
156
|
"bun.lock": "bun",
|
|
@@ -103,9 +158,7 @@ var LOCKFILE_MAP = {
|
|
|
103
158
|
"yarn.lock": "yarn",
|
|
104
159
|
"package-lock.json": "npm"
|
|
105
160
|
};
|
|
106
|
-
async function detectPackageManager(projectDir) {
|
|
107
|
-
const packageJsonPath = join(projectDir, "package.json");
|
|
108
|
-
const packageJson = await readPackageJson(packageJsonPath);
|
|
161
|
+
async function detectPackageManager(projectDir, packageJson) {
|
|
109
162
|
if (!packageJson) {
|
|
110
163
|
return { name: "npm", source: "default" };
|
|
111
164
|
}
|
|
@@ -164,46 +217,17 @@ function getInstallCommand(pm) {
|
|
|
164
217
|
return ["npm", "install"];
|
|
165
218
|
}
|
|
166
219
|
}
|
|
167
|
-
async function fileExists(path) {
|
|
168
|
-
try {
|
|
169
|
-
const stats = await stat(path);
|
|
170
|
-
return stats.isFile();
|
|
171
|
-
} catch {
|
|
172
|
-
return false;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
async function readPackageJson(path) {
|
|
176
|
-
try {
|
|
177
|
-
const content = await readFile(path, "utf-8");
|
|
178
|
-
return JSON.parse(content);
|
|
179
|
-
} catch {
|
|
180
|
-
}
|
|
181
|
-
return null;
|
|
182
|
-
}
|
|
183
220
|
|
|
184
221
|
// src/analyzer/scripts.ts
|
|
185
|
-
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
186
|
-
import { join as join2 } from "path";
|
|
187
222
|
var DEV_PATTERNS = ["dev", "serve", "start:dev", "develop", "watch"];
|
|
188
223
|
var TEST_PATTERNS = ["test", "test:unit", "test:all", "spec"];
|
|
189
224
|
var BUILD_PATTERNS = ["build", "compile", "bundle", "dist"];
|
|
190
|
-
var START_PATTERNS = ["start", "
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return stats.isFile();
|
|
195
|
-
} catch {
|
|
196
|
-
return false;
|
|
225
|
+
var START_PATTERNS = ["start", "preview", "production"];
|
|
226
|
+
function analyzeScripts(packageJson) {
|
|
227
|
+
if (!packageJson) {
|
|
228
|
+
return null;
|
|
197
229
|
}
|
|
198
|
-
}
|
|
199
|
-
async function analyzeScripts(projectDir) {
|
|
200
|
-
const packageJsonPath = join2(projectDir, "package.json");
|
|
201
230
|
try {
|
|
202
|
-
if (!await fileExists2(packageJsonPath)) {
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
const content = await readFile2(packageJsonPath, "utf-8");
|
|
206
|
-
const packageJson = JSON.parse(content);
|
|
207
231
|
const scripts = packageJson.scripts || {};
|
|
208
232
|
const detected = {
|
|
209
233
|
dev: findMatchingScript(scripts, DEV_PATTERNS),
|
|
@@ -242,8 +266,8 @@ function findMatchingScript(scripts, patterns) {
|
|
|
242
266
|
}
|
|
243
267
|
|
|
244
268
|
// src/analyzer/dependencies.ts
|
|
245
|
-
import { stat as
|
|
246
|
-
import { join as
|
|
269
|
+
import { stat as stat2 } from "fs/promises";
|
|
270
|
+
import { join as join2 } from "path";
|
|
247
271
|
var LOCKFILES = [
|
|
248
272
|
"bun.lockb",
|
|
249
273
|
"bun.lock",
|
|
@@ -252,7 +276,7 @@ var LOCKFILES = [
|
|
|
252
276
|
"package-lock.json"
|
|
253
277
|
];
|
|
254
278
|
async function checkDependencyStatus(projectDir) {
|
|
255
|
-
const nodeModulesPath =
|
|
279
|
+
const nodeModulesPath = join2(projectDir, "node_modules");
|
|
256
280
|
const nodeModulesExists = await directoryExists(nodeModulesPath);
|
|
257
281
|
if (!nodeModulesExists) {
|
|
258
282
|
return {
|
|
@@ -261,11 +285,11 @@ async function checkDependencyStatus(projectDir) {
|
|
|
261
285
|
reason: "node_modules \u4E0D\u5B58\u5728"
|
|
262
286
|
};
|
|
263
287
|
}
|
|
288
|
+
const nodeModulesMtime = await getModifiedTime(nodeModulesPath);
|
|
264
289
|
const lockfilePath = await findLockfile(projectDir);
|
|
265
290
|
if (lockfilePath) {
|
|
266
291
|
const lockfileMtime = await getModifiedTime(lockfilePath);
|
|
267
|
-
|
|
268
|
-
if (lockfileMtime && nodeModulesMtime2 && lockfileMtime > nodeModulesMtime2) {
|
|
292
|
+
if (lockfileMtime && nodeModulesMtime && lockfileMtime > nodeModulesMtime) {
|
|
269
293
|
return {
|
|
270
294
|
hasNodeModules: true,
|
|
271
295
|
needsInstall: true,
|
|
@@ -273,9 +297,8 @@ async function checkDependencyStatus(projectDir) {
|
|
|
273
297
|
};
|
|
274
298
|
}
|
|
275
299
|
}
|
|
276
|
-
const packageJsonPath =
|
|
300
|
+
const packageJsonPath = join2(projectDir, "package.json");
|
|
277
301
|
const packageJsonMtime = await getModifiedTime(packageJsonPath);
|
|
278
|
-
const nodeModulesMtime = await getModifiedTime(nodeModulesPath);
|
|
279
302
|
if (packageJsonMtime && nodeModulesMtime && packageJsonMtime > nodeModulesMtime) {
|
|
280
303
|
return {
|
|
281
304
|
hasNodeModules: true,
|
|
@@ -290,8 +313,8 @@ async function checkDependencyStatus(projectDir) {
|
|
|
290
313
|
}
|
|
291
314
|
async function findLockfile(projectDir) {
|
|
292
315
|
for (const lockfile of LOCKFILES) {
|
|
293
|
-
const lockfilePath =
|
|
294
|
-
if (await
|
|
316
|
+
const lockfilePath = join2(projectDir, lockfile);
|
|
317
|
+
if (await fileExists(lockfilePath)) {
|
|
295
318
|
return lockfilePath;
|
|
296
319
|
}
|
|
297
320
|
}
|
|
@@ -299,41 +322,17 @@ async function findLockfile(projectDir) {
|
|
|
299
322
|
}
|
|
300
323
|
async function getModifiedTime(path) {
|
|
301
324
|
try {
|
|
302
|
-
const stats = await
|
|
325
|
+
const stats = await stat2(path);
|
|
303
326
|
return stats.mtimeMs;
|
|
304
327
|
} catch {
|
|
305
328
|
return null;
|
|
306
329
|
}
|
|
307
330
|
}
|
|
308
|
-
async function directoryExists(path) {
|
|
309
|
-
try {
|
|
310
|
-
const stats = await stat3(path);
|
|
311
|
-
return stats.isDirectory();
|
|
312
|
-
} catch {
|
|
313
|
-
return false;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
async function fileExists3(path) {
|
|
317
|
-
try {
|
|
318
|
-
const stats = await stat3(path);
|
|
319
|
-
return stats.isFile();
|
|
320
|
-
} catch {
|
|
321
|
-
return false;
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
331
|
|
|
325
332
|
// src/analyzer/index.ts
|
|
326
|
-
async function fileExists4(path) {
|
|
327
|
-
try {
|
|
328
|
-
const stats = await stat4(path);
|
|
329
|
-
return stats.isFile();
|
|
330
|
-
} catch {
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
333
|
async function analyzeProject(projectDir) {
|
|
335
|
-
const packageJsonPath =
|
|
336
|
-
const hasPackageJson = await
|
|
334
|
+
const packageJsonPath = join3(projectDir, "package.json");
|
|
335
|
+
const hasPackageJson = await fileExists(packageJsonPath);
|
|
337
336
|
if (!hasPackageJson) {
|
|
338
337
|
return {
|
|
339
338
|
type: "unknown",
|
|
@@ -344,15 +343,15 @@ async function analyzeProject(projectDir) {
|
|
|
344
343
|
}
|
|
345
344
|
let packageJson = {};
|
|
346
345
|
try {
|
|
347
|
-
const content = await
|
|
346
|
+
const content = await readFile(packageJsonPath, "utf-8");
|
|
348
347
|
packageJson = JSON.parse(content);
|
|
349
348
|
} catch {
|
|
350
349
|
}
|
|
351
|
-
const [packageManager,
|
|
352
|
-
detectPackageManager(projectDir),
|
|
353
|
-
analyzeScripts(projectDir),
|
|
350
|
+
const [packageManager, dependencies] = await Promise.all([
|
|
351
|
+
detectPackageManager(projectDir, packageJson),
|
|
354
352
|
checkDependencyStatus(projectDir)
|
|
355
353
|
]);
|
|
354
|
+
const scripts = analyzeScripts(packageJson);
|
|
356
355
|
return {
|
|
357
356
|
type: "nodejs",
|
|
358
357
|
packageManager,
|
|
@@ -364,28 +363,115 @@ async function analyzeProject(projectDir) {
|
|
|
364
363
|
};
|
|
365
364
|
}
|
|
366
365
|
|
|
366
|
+
// src/utils/pm-availability.ts
|
|
367
|
+
import { createInterface } from "node:readline/promises";
|
|
368
|
+
var availabilityCache = /* @__PURE__ */ new Map();
|
|
369
|
+
async function isPmAvailable(pm) {
|
|
370
|
+
if (availabilityCache.has(pm)) {
|
|
371
|
+
return availabilityCache.get(pm);
|
|
372
|
+
}
|
|
373
|
+
try {
|
|
374
|
+
const result = await executeCapture([pm, "--version"]);
|
|
375
|
+
const available = result.exitCode === 0 && result.stdout.trim().length > 0;
|
|
376
|
+
availabilityCache.set(pm, available);
|
|
377
|
+
return available;
|
|
378
|
+
} catch {
|
|
379
|
+
availabilityCache.set(pm, false);
|
|
380
|
+
return false;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
async function ensurePmAvailable(pm) {
|
|
384
|
+
if (pm === "npm") {
|
|
385
|
+
return pm;
|
|
386
|
+
}
|
|
387
|
+
const available = await isPmAvailable(pm);
|
|
388
|
+
if (available) {
|
|
389
|
+
return pm;
|
|
390
|
+
}
|
|
391
|
+
warn(`\u5305\u7BA1\u7406\u5668 ${pm} \u672A\u5B89\u88C5`);
|
|
392
|
+
if (!process.stdin.isTTY) {
|
|
393
|
+
warn("\u975E\u4EA4\u4E92\u73AF\u5883\uFF0C\u81EA\u52A8\u56DE\u9000\u5230 npm");
|
|
394
|
+
return "npm";
|
|
395
|
+
}
|
|
396
|
+
return await promptPmResolution(pm);
|
|
397
|
+
}
|
|
398
|
+
async function promptPmResolution(pm) {
|
|
399
|
+
console.log();
|
|
400
|
+
console.log(` \u68C0\u6D4B\u5230\u9879\u76EE\u4F7F\u7528 ${colors.cyan}${pm}${colors.reset}\uFF0C\u4F46\u7CFB\u7EDF\u672A\u5B89\u88C5\u3002`);
|
|
401
|
+
console.log();
|
|
402
|
+
console.log(` ${colors.bold}\u8BF7\u9009\u62E9\u64CD\u4F5C:${colors.reset}`);
|
|
403
|
+
console.log(` ${colors.cyan}1${colors.reset}) \u81EA\u52A8\u5B89\u88C5 ${pm} ${colors.dim}(npm install -g ${pm})${colors.reset}`);
|
|
404
|
+
console.log(` ${colors.cyan}2${colors.reset}) \u4F7F\u7528 npm \u4EE3\u66FF`);
|
|
405
|
+
console.log(` ${colors.cyan}3${colors.reset}) \u9000\u51FA\uFF0C\u624B\u52A8\u5904\u7406`);
|
|
406
|
+
console.log();
|
|
407
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
408
|
+
try {
|
|
409
|
+
const answer = await rl.question(` \u8BF7\u8F93\u5165\u9009\u9879 ${colors.dim}[1/2/3]${colors.reset}: `);
|
|
410
|
+
const choice = answer.trim();
|
|
411
|
+
switch (choice) {
|
|
412
|
+
case "1":
|
|
413
|
+
return await autoInstallPm(pm);
|
|
414
|
+
case "2":
|
|
415
|
+
warn(`\u4F7F\u7528 npm \u4EE3\u66FF ${pm}`);
|
|
416
|
+
return "npm";
|
|
417
|
+
case "3":
|
|
418
|
+
default:
|
|
419
|
+
throw new CliError(`\u8BF7\u5148\u5B89\u88C5 ${pm}: npm install -g ${pm}`);
|
|
420
|
+
}
|
|
421
|
+
} finally {
|
|
422
|
+
rl.close();
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
async function autoInstallPm(pm) {
|
|
426
|
+
info(`\u6B63\u5728\u5B89\u88C5 ${pm}...`);
|
|
427
|
+
console.log();
|
|
428
|
+
try {
|
|
429
|
+
const result = await executeCapture(["npm", "install", "-g", pm]);
|
|
430
|
+
if (result.exitCode !== 0) {
|
|
431
|
+
error(`\u5B89\u88C5 ${pm} \u5931\u8D25`);
|
|
432
|
+
if (result.stderr.trim()) {
|
|
433
|
+
console.error(result.stderr.trim());
|
|
434
|
+
}
|
|
435
|
+
throw new CliError(`\u65E0\u6CD5\u81EA\u52A8\u5B89\u88C5 ${pm}\uFF0C\u8BF7\u624B\u52A8\u8FD0\u884C: npm install -g ${pm}`);
|
|
436
|
+
}
|
|
437
|
+
} catch (err) {
|
|
438
|
+
if (err instanceof CliError)
|
|
439
|
+
throw err;
|
|
440
|
+
throw new CliError(`\u5B89\u88C5 ${pm} \u65F6\u51FA\u9519\uFF0C\u8BF7\u624B\u52A8\u8FD0\u884C: npm install -g ${pm}`);
|
|
441
|
+
}
|
|
442
|
+
availabilityCache.delete(pm);
|
|
443
|
+
const nowAvailable = await isPmAvailable(pm);
|
|
444
|
+
if (!nowAvailable) {
|
|
445
|
+
throw new CliError(`${pm} \u5DF2\u5B89\u88C5\u4F46\u65E0\u6CD5\u6267\u884C\u3002\u8BF7\u68C0\u67E5 PATH \u6216\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u540E\u91CD\u8BD5\u3002`);
|
|
446
|
+
}
|
|
447
|
+
success(`${pm} \u5B89\u88C5\u5B8C\u6210`);
|
|
448
|
+
console.log();
|
|
449
|
+
return pm;
|
|
450
|
+
}
|
|
451
|
+
|
|
367
452
|
// src/cli/run.ts
|
|
368
453
|
async function runCommand(projectDir, options = {}) {
|
|
369
454
|
const { noInstall = false, forceInstall = false, scriptType = "dev" } = options;
|
|
370
455
|
log("\u6B63\u5728\u5206\u6790\u9879\u76EE...");
|
|
371
456
|
const project = await analyzeProject(projectDir);
|
|
372
457
|
if (project.type === "unknown") {
|
|
373
|
-
|
|
374
|
-
process.exit(1);
|
|
458
|
+
throw new CliError("\u672A\u68C0\u6D4B\u5230\u9879\u76EE\u7C7B\u578B\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u5305\u542B package.json");
|
|
375
459
|
}
|
|
376
460
|
log(`\u9879\u76EE\u7C7B\u578B: ${project.type}`);
|
|
377
461
|
log(`\u5305\u7BA1\u7406\u5668: ${project.packageManager.name} (from ${project.packageManager.source})`);
|
|
378
462
|
if (!project.scripts) {
|
|
379
|
-
|
|
380
|
-
process.exit(1);
|
|
463
|
+
throw new CliError("\u65E0\u6CD5\u8BFB\u53D6 package.json \u7684 scripts");
|
|
381
464
|
}
|
|
382
465
|
const scriptName = findScript(project, scriptType);
|
|
383
466
|
if (!scriptName) {
|
|
384
|
-
error(`\u672A\u627E\u5230 ${scriptType} \u76F8\u5173\u7684\u811A\u672C`);
|
|
385
467
|
showAvailableScripts(project);
|
|
386
|
-
|
|
468
|
+
throw new CliError(`\u672A\u627E\u5230 ${scriptType} \u76F8\u5173\u7684\u811A\u672C`);
|
|
387
469
|
}
|
|
388
470
|
log(`\u5C06\u6267\u884C\u811A\u672C: ${scriptName}`);
|
|
471
|
+
const resolvedPm = await ensurePmAvailable(project.packageManager.name);
|
|
472
|
+
if (resolvedPm !== project.packageManager.name) {
|
|
473
|
+
log(`\u4F7F\u7528 ${resolvedPm} \u4EE3\u66FF ${project.packageManager.name}`);
|
|
474
|
+
}
|
|
389
475
|
const shouldInstall = !noInstall && (forceInstall || project.dependencies.needsInstall);
|
|
390
476
|
if (shouldInstall) {
|
|
391
477
|
if (forceInstall) {
|
|
@@ -394,21 +480,20 @@ async function runCommand(projectDir, options = {}) {
|
|
|
394
480
|
log(`\u4F9D\u8D56\u72B6\u6001: ${project.dependencies.reason || "\u9700\u8981\u5B89\u88C5"}`);
|
|
395
481
|
}
|
|
396
482
|
newline();
|
|
397
|
-
const installCmd = getInstallCommand(
|
|
483
|
+
const installCmd = getInstallCommand(resolvedPm);
|
|
398
484
|
const installExitCode = await execute(installCmd, { cwd: projectDir });
|
|
399
485
|
if (installExitCode !== 0) {
|
|
400
|
-
|
|
401
|
-
process.exit(installExitCode);
|
|
486
|
+
throw new CliError("\u4F9D\u8D56\u5B89\u88C5\u5931\u8D25", installExitCode);
|
|
402
487
|
}
|
|
403
488
|
success("\u4F9D\u8D56\u5B89\u88C5\u5B8C\u6210");
|
|
404
489
|
newline();
|
|
405
490
|
} else if (!noInstall) {
|
|
406
491
|
log("\u4F9D\u8D56\u72B6\u6001: \u5DF2\u662F\u6700\u65B0");
|
|
407
492
|
}
|
|
408
|
-
const runCmd = getRunCommand(
|
|
493
|
+
const runCmd = getRunCommand(resolvedPm, scriptName);
|
|
409
494
|
const exitCode = await execute(runCmd, { cwd: projectDir });
|
|
410
495
|
if (exitCode !== 0) {
|
|
411
|
-
|
|
496
|
+
throw new CliError("\u811A\u672C\u6267\u884C\u5931\u8D25", exitCode);
|
|
412
497
|
}
|
|
413
498
|
}
|
|
414
499
|
function findScript(project, scriptType) {
|
|
@@ -437,7 +522,7 @@ function showAvailableScripts(project) {
|
|
|
437
522
|
console.log(` - ${name}`);
|
|
438
523
|
}
|
|
439
524
|
console.log();
|
|
440
|
-
info("\u4F7F\u7528
|
|
525
|
+
info("\u4F7F\u7528 pr <script> \u8FD0\u884C\u4EFB\u610F\u811A\u672C");
|
|
441
526
|
}
|
|
442
527
|
|
|
443
528
|
// src/cli/info.ts
|
|
@@ -467,7 +552,9 @@ async function infoCommand(projectDir) {
|
|
|
467
552
|
pmInfo += `@${pm.version}`;
|
|
468
553
|
}
|
|
469
554
|
pmInfo += ` ${colors.dim}(${pm.source})${colors.reset}`;
|
|
470
|
-
|
|
555
|
+
const pmAvailable = await isPmAvailable(pm.name);
|
|
556
|
+
const pmStatus = pmAvailable ? `${colors.green}\u5DF2\u5B89\u88C5${colors.reset}` : `${colors.red}\u672A\u5B89\u88C5${colors.reset}`;
|
|
557
|
+
console.log(`${colors.bold}\u5305\u7BA1\u7406\u5668:${colors.reset} ${pmInfo} [${pmStatus}]`);
|
|
471
558
|
const deps = project.dependencies;
|
|
472
559
|
const depsStatus = deps.needsInstall ? `${colors.yellow}\u9700\u8981\u5B89\u88C5${colors.reset} (${deps.reason})` : `${colors.green}\u5DF2\u5C31\u7EEA${colors.reset}`;
|
|
473
560
|
console.log(`${colors.bold}\u4F9D\u8D56\u72B6\u6001:${colors.reset} ${depsStatus}`);
|
|
@@ -505,26 +592,23 @@ async function infoCommand(projectDir) {
|
|
|
505
592
|
async function scriptCommand(projectDir, scriptName) {
|
|
506
593
|
const project = await analyzeProject(projectDir);
|
|
507
594
|
if (project.type === "unknown") {
|
|
508
|
-
|
|
509
|
-
process.exit(1);
|
|
595
|
+
throw new CliError("\u672A\u68C0\u6D4B\u5230\u9879\u76EE\u7C7B\u578B\u3002\u8BF7\u786E\u4FDD\u5F53\u524D\u76EE\u5F55\u5305\u542B package.json");
|
|
510
596
|
}
|
|
511
597
|
if (!project.scripts) {
|
|
512
|
-
|
|
513
|
-
process.exit(1);
|
|
598
|
+
throw new CliError("\u65E0\u6CD5\u8BFB\u53D6 package.json \u7684 scripts");
|
|
514
599
|
}
|
|
515
600
|
const scripts = project.scripts.scripts;
|
|
516
601
|
if (!(scriptName in scripts)) {
|
|
517
|
-
error(`\u811A\u672C "${scriptName}" \u4E0D\u5B58\u5728`);
|
|
518
|
-
console.log();
|
|
519
602
|
showAvailableScripts2(scripts);
|
|
520
|
-
|
|
603
|
+
throw new CliError(`\u811A\u672C "${scriptName}" \u4E0D\u5B58\u5728`);
|
|
521
604
|
}
|
|
522
605
|
log(`\u5305\u7BA1\u7406\u5668: ${project.packageManager.name}`);
|
|
523
606
|
log(`\u6267\u884C\u811A\u672C: ${scriptName}`);
|
|
524
|
-
const
|
|
607
|
+
const resolvedPm = await ensurePmAvailable(project.packageManager.name);
|
|
608
|
+
const runCmd = getRunCommand(resolvedPm, scriptName);
|
|
525
609
|
const exitCode = await execute(runCmd, { cwd: projectDir });
|
|
526
610
|
if (exitCode !== 0) {
|
|
527
|
-
|
|
611
|
+
throw new CliError("\u811A\u672C\u6267\u884C\u5931\u8D25", exitCode);
|
|
528
612
|
}
|
|
529
613
|
}
|
|
530
614
|
function showAvailableScripts2(scripts) {
|
|
@@ -540,7 +624,7 @@ function showAvailableScripts2(scripts) {
|
|
|
540
624
|
}
|
|
541
625
|
|
|
542
626
|
// src/index.ts
|
|
543
|
-
var VERSION = "0.
|
|
627
|
+
var VERSION = true ? "0.2.0" : "0.0.0-dev";
|
|
544
628
|
function parseArgs(args) {
|
|
545
629
|
const options = {
|
|
546
630
|
verbose: false,
|
|
@@ -571,6 +655,8 @@ function parseArgs(args) {
|
|
|
571
655
|
} else {
|
|
572
656
|
remainingArgs.push(arg);
|
|
573
657
|
}
|
|
658
|
+
} else {
|
|
659
|
+
warn(`\u672A\u77E5\u9009\u9879: ${arg}`);
|
|
574
660
|
}
|
|
575
661
|
i++;
|
|
576
662
|
}
|
|
@@ -643,6 +729,10 @@ async function main() {
|
|
|
643
729
|
}
|
|
644
730
|
}
|
|
645
731
|
main().catch((err) => {
|
|
646
|
-
|
|
732
|
+
if (err instanceof CliError) {
|
|
733
|
+
error(err.message);
|
|
734
|
+
process.exit(err.exitCode);
|
|
735
|
+
}
|
|
736
|
+
error(err.message || "\u672A\u77E5\u9519\u8BEF");
|
|
647
737
|
process.exit(1);
|
|
648
738
|
});
|