project-runner 0.2.0 → 0.3.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 +24 -0
- package/dist/index.js +335 -36
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -106,9 +106,33 @@ pr info
|
|
|
106
106
|
| `-d, --dir <path>` | 指定项目目录(默认:当前目录)|
|
|
107
107
|
| `-i, --install` | 强制执行依赖安装 |
|
|
108
108
|
| `--no-install` | 跳过依赖安装步骤 |
|
|
109
|
+
| `-e, --entry <name>` | 指定 MPA 入口(也可用 `PR_ENTRY`) |
|
|
109
110
|
| `-h, --help` | 显示帮助信息 |
|
|
110
111
|
| `-V, --version` | 显示版本号 |
|
|
111
112
|
|
|
113
|
+
## MPA 项目支持
|
|
114
|
+
|
|
115
|
+
`pr run` 会自动检测是否存在 `dev:<entry>` 形式的多入口脚本。
|
|
116
|
+
|
|
117
|
+
- 在交互终端中:自动弹出入口列表并让你选择。
|
|
118
|
+
- 在 CI / 非交互环境中:按优先级选择入口
|
|
119
|
+
1. `--entry <name>`
|
|
120
|
+
2. `PR_ENTRY=<name>`
|
|
121
|
+
3. `.pr.local.json` 中的 `defaultEntry`
|
|
122
|
+
4. 若仍无法确定则报错并提示可选入口
|
|
123
|
+
|
|
124
|
+
本地配置文件(推荐):
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"entries": ["main", "formengine", "design", "approve"],
|
|
129
|
+
"defaultEntry": "main"
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- 文件名固定:`.pr.local.json`
|
|
134
|
+
- 当该文件存在时,`pr` 会自动确保 `.gitignore` 包含 `.pr.local.json`
|
|
135
|
+
|
|
112
136
|
## 示例输出
|
|
113
137
|
|
|
114
138
|
### `pr info`
|
package/dist/index.js
CHANGED
|
@@ -124,9 +124,12 @@ function setupSignalHandlers() {
|
|
|
124
124
|
});
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// src/cli/run.ts
|
|
128
|
+
import { createInterface as createInterface2 } from "node:readline/promises";
|
|
129
|
+
|
|
127
130
|
// src/analyzer/index.ts
|
|
128
|
-
import { readFile } from "fs/promises";
|
|
129
|
-
import { join as
|
|
131
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
132
|
+
import { join as join4 } from "path";
|
|
130
133
|
|
|
131
134
|
// src/analyzer/package-manager.ts
|
|
132
135
|
import { join } from "path";
|
|
@@ -223,7 +226,8 @@ var DEV_PATTERNS = ["dev", "serve", "start:dev", "develop", "watch"];
|
|
|
223
226
|
var TEST_PATTERNS = ["test", "test:unit", "test:all", "spec"];
|
|
224
227
|
var BUILD_PATTERNS = ["build", "compile", "bundle", "dist"];
|
|
225
228
|
var START_PATTERNS = ["start", "preview", "production"];
|
|
226
|
-
|
|
229
|
+
var STANDARD_TYPES = ["dev", "test", "build", "start"];
|
|
230
|
+
function analyzeScripts(packageJson, localConfig) {
|
|
227
231
|
if (!packageJson) {
|
|
228
232
|
return null;
|
|
229
233
|
}
|
|
@@ -235,11 +239,81 @@ function analyzeScripts(packageJson) {
|
|
|
235
239
|
build: findMatchingScript(scripts, BUILD_PATTERNS),
|
|
236
240
|
start: findMatchingScript(scripts, START_PATTERNS)
|
|
237
241
|
};
|
|
238
|
-
|
|
242
|
+
const mpa = analyzeMpa(packageJson, scripts, localConfig);
|
|
243
|
+
return { scripts, detected, mpa };
|
|
239
244
|
} catch {
|
|
240
245
|
return null;
|
|
241
246
|
}
|
|
242
247
|
}
|
|
248
|
+
function analyzeMpa(packageJson, scripts, localConfig) {
|
|
249
|
+
const configuredEntriesFromLocal = normalizeEntryList(localConfig?.entries);
|
|
250
|
+
const configuredEntriesFromPackage = normalizeEntryList(packageJson?.pr?.entries);
|
|
251
|
+
const configuredEntries = configuredEntriesFromLocal.length > 0 ? configuredEntriesFromLocal : configuredEntriesFromPackage;
|
|
252
|
+
const scriptEntries = collectEntriesByPrefix(scripts, "dev");
|
|
253
|
+
let entries = configuredEntries.length > 0 ? configuredEntries : scriptEntries;
|
|
254
|
+
let source = "scripts";
|
|
255
|
+
if (configuredEntriesFromLocal.length > 0) {
|
|
256
|
+
source = "local-config";
|
|
257
|
+
} else if (configuredEntriesFromPackage.length > 0) {
|
|
258
|
+
source = "package-json";
|
|
259
|
+
}
|
|
260
|
+
const defaultEntry = normalizeEntryName(localConfig?.defaultEntry ?? packageJson?.pr?.defaultEntry);
|
|
261
|
+
if (defaultEntry && !entries.includes(defaultEntry) && scripts[`dev:${defaultEntry}`]) {
|
|
262
|
+
entries = [...entries, defaultEntry];
|
|
263
|
+
}
|
|
264
|
+
entries = dedupe(entries);
|
|
265
|
+
if (entries.length === 0) {
|
|
266
|
+
source = "none";
|
|
267
|
+
}
|
|
268
|
+
const scriptsByType = {};
|
|
269
|
+
for (const type of STANDARD_TYPES) {
|
|
270
|
+
const mapping = {};
|
|
271
|
+
for (const entry of entries) {
|
|
272
|
+
const scriptName = `${type}:${entry}`;
|
|
273
|
+
if (scripts[scriptName]) {
|
|
274
|
+
mapping[entry] = scriptName;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (Object.keys(mapping).length > 0) {
|
|
278
|
+
scriptsByType[type] = mapping;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
isMpa: entries.length > 0,
|
|
283
|
+
entries,
|
|
284
|
+
defaultEntry: defaultEntry && entries.includes(defaultEntry) ? defaultEntry : void 0,
|
|
285
|
+
source,
|
|
286
|
+
scriptsByType
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function normalizeEntryList(value) {
|
|
290
|
+
if (!Array.isArray(value)) {
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
return dedupe(value.map(normalizeEntryName).filter((item) => Boolean(item)));
|
|
294
|
+
}
|
|
295
|
+
function normalizeEntryName(value) {
|
|
296
|
+
if (typeof value !== "string") {
|
|
297
|
+
return void 0;
|
|
298
|
+
}
|
|
299
|
+
const trimmed = value.trim();
|
|
300
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
301
|
+
}
|
|
302
|
+
function collectEntriesByPrefix(scripts, prefix) {
|
|
303
|
+
const prefixWithColon = `${prefix}:`;
|
|
304
|
+
const entries = [];
|
|
305
|
+
for (const name of Object.keys(scripts)) {
|
|
306
|
+
if (!name.startsWith(prefixWithColon)) {
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
const entry = name.slice(prefixWithColon.length).trim();
|
|
310
|
+
if (!entry) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
entries.push(entry);
|
|
314
|
+
}
|
|
315
|
+
return dedupe(entries);
|
|
316
|
+
}
|
|
243
317
|
function findMatchingScript(scripts, patterns) {
|
|
244
318
|
const scriptNames = Object.keys(scripts);
|
|
245
319
|
for (const pattern of patterns) {
|
|
@@ -252,8 +326,12 @@ function findMatchingScript(scripts, patterns) {
|
|
|
252
326
|
if (!name.toLowerCase().includes(pattern.toLowerCase())) {
|
|
253
327
|
return false;
|
|
254
328
|
}
|
|
255
|
-
const scriptContent = scripts[name]
|
|
256
|
-
if (scriptContent
|
|
329
|
+
const scriptContent = scripts[name];
|
|
330
|
+
if (!scriptContent) {
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
const content = scriptContent.toLowerCase();
|
|
334
|
+
if (content.includes("npm i") || content.includes("npm install") || content.includes("yarn install") || content.includes("pnpm install") || content.includes("bun install")) {
|
|
257
335
|
return false;
|
|
258
336
|
}
|
|
259
337
|
return true;
|
|
@@ -264,6 +342,9 @@ function findMatchingScript(scripts, patterns) {
|
|
|
264
342
|
}
|
|
265
343
|
return void 0;
|
|
266
344
|
}
|
|
345
|
+
function dedupe(items) {
|
|
346
|
+
return [...new Set(items)];
|
|
347
|
+
}
|
|
267
348
|
|
|
268
349
|
// src/analyzer/dependencies.ts
|
|
269
350
|
import { stat as stat2 } from "fs/promises";
|
|
@@ -329,34 +410,84 @@ async function getModifiedTime(path) {
|
|
|
329
410
|
}
|
|
330
411
|
}
|
|
331
412
|
|
|
413
|
+
// src/analyzer/local-config.ts
|
|
414
|
+
import { appendFile, readFile, writeFile } from "fs/promises";
|
|
415
|
+
import { join as join3 } from "path";
|
|
416
|
+
var LOCAL_CONFIG_FILENAME = ".pr.local.json";
|
|
417
|
+
async function loadPrLocalConfig(projectDir) {
|
|
418
|
+
const configPath = join3(projectDir, LOCAL_CONFIG_FILENAME);
|
|
419
|
+
if (!await fileExists(configPath)) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
let parsed;
|
|
423
|
+
try {
|
|
424
|
+
const content = await readFile(configPath, "utf-8");
|
|
425
|
+
parsed = JSON.parse(content.replace(/^\uFEFF/, ""));
|
|
426
|
+
} catch {
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
await ensureLocalConfigGitignored(projectDir);
|
|
430
|
+
if (!parsed || typeof parsed !== "object") {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
const config = {};
|
|
434
|
+
if (Array.isArray(parsed.entries)) {
|
|
435
|
+
config.entries = parsed.entries.filter((item) => typeof item === "string").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
436
|
+
}
|
|
437
|
+
if (typeof parsed.defaultEntry === "string" && parsed.defaultEntry.trim()) {
|
|
438
|
+
config.defaultEntry = parsed.defaultEntry.trim();
|
|
439
|
+
}
|
|
440
|
+
return config;
|
|
441
|
+
}
|
|
442
|
+
async function ensureLocalConfigGitignored(projectDir) {
|
|
443
|
+
const gitignorePath = join3(projectDir, ".gitignore");
|
|
444
|
+
const ignoreEntry = LOCAL_CONFIG_FILENAME;
|
|
445
|
+
if (!await fileExists(gitignorePath)) {
|
|
446
|
+
await writeFile(gitignorePath, `${ignoreEntry}
|
|
447
|
+
`, "utf-8");
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
const content = await readFile(gitignorePath, "utf-8");
|
|
451
|
+
const lines = content.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
452
|
+
if (lines.includes(ignoreEntry) || lines.includes(`/${ignoreEntry}`)) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
const suffix = content.endsWith("\n") || content.length === 0 ? "" : "\n";
|
|
456
|
+
await appendFile(gitignorePath, `${suffix}${ignoreEntry}
|
|
457
|
+
`, "utf-8");
|
|
458
|
+
}
|
|
459
|
+
|
|
332
460
|
// src/analyzer/index.ts
|
|
333
461
|
async function analyzeProject(projectDir) {
|
|
334
|
-
const packageJsonPath =
|
|
462
|
+
const packageJsonPath = join4(projectDir, "package.json");
|
|
335
463
|
const hasPackageJson = await fileExists(packageJsonPath);
|
|
336
464
|
if (!hasPackageJson) {
|
|
337
465
|
return {
|
|
338
466
|
type: "unknown",
|
|
339
467
|
packageManager: { name: "npm", source: "default" },
|
|
340
468
|
scripts: null,
|
|
341
|
-
dependencies: { hasNodeModules: false, needsInstall: false }
|
|
469
|
+
dependencies: { hasNodeModules: false, needsInstall: false },
|
|
470
|
+
localConfig: null
|
|
342
471
|
};
|
|
343
472
|
}
|
|
344
473
|
let packageJson = {};
|
|
345
474
|
try {
|
|
346
|
-
const content = await
|
|
347
|
-
packageJson = JSON.parse(content);
|
|
475
|
+
const content = await readFile2(packageJsonPath, "utf-8");
|
|
476
|
+
packageJson = JSON.parse(content.replace(/^\uFEFF/, ""));
|
|
348
477
|
} catch {
|
|
349
478
|
}
|
|
350
|
-
const [packageManager, dependencies] = await Promise.all([
|
|
479
|
+
const [packageManager, dependencies, localConfig] = await Promise.all([
|
|
351
480
|
detectPackageManager(projectDir, packageJson),
|
|
352
|
-
checkDependencyStatus(projectDir)
|
|
481
|
+
checkDependencyStatus(projectDir),
|
|
482
|
+
loadPrLocalConfig(projectDir)
|
|
353
483
|
]);
|
|
354
|
-
const scripts = analyzeScripts(packageJson);
|
|
484
|
+
const scripts = analyzeScripts(packageJson, localConfig);
|
|
355
485
|
return {
|
|
356
486
|
type: "nodejs",
|
|
357
487
|
packageManager,
|
|
358
488
|
scripts,
|
|
359
489
|
dependencies,
|
|
490
|
+
localConfig,
|
|
360
491
|
name: packageJson.name,
|
|
361
492
|
version: packageJson.version,
|
|
362
493
|
description: packageJson.description
|
|
@@ -451,7 +582,7 @@ async function autoInstallPm(pm) {
|
|
|
451
582
|
|
|
452
583
|
// src/cli/run.ts
|
|
453
584
|
async function runCommand(projectDir, options = {}) {
|
|
454
|
-
const { noInstall = false, forceInstall = false, scriptType = "dev" } = options;
|
|
585
|
+
const { noInstall = false, forceInstall = false, scriptType = "dev", entry } = options;
|
|
455
586
|
log("\u6B63\u5728\u5206\u6790\u9879\u76EE...");
|
|
456
587
|
const project = await analyzeProject(projectDir);
|
|
457
588
|
if (project.type === "unknown") {
|
|
@@ -462,10 +593,14 @@ async function runCommand(projectDir, options = {}) {
|
|
|
462
593
|
if (!project.scripts) {
|
|
463
594
|
throw new CliError("\u65E0\u6CD5\u8BFB\u53D6 package.json \u7684 scripts");
|
|
464
595
|
}
|
|
465
|
-
const
|
|
596
|
+
const resolvedEntry = await resolveEntry(project, scriptType, entry);
|
|
597
|
+
const scriptName = findScript(project, scriptType, resolvedEntry);
|
|
466
598
|
if (!scriptName) {
|
|
467
|
-
showAvailableScripts(project);
|
|
468
|
-
throw new CliError(`\u672A\u627E\u5230 ${scriptType} \u76F8\u5173\u7684\u811A\u672C`);
|
|
599
|
+
showAvailableScripts(project, scriptType, resolvedEntry);
|
|
600
|
+
throw new CliError(`\u672A\u627E\u5230 ${scriptType}${resolvedEntry ? `:${resolvedEntry}` : ""} \u76F8\u5173\u7684\u811A\u672C`);
|
|
601
|
+
}
|
|
602
|
+
if (resolvedEntry) {
|
|
603
|
+
log(`\u5165\u53E3: ${resolvedEntry}`);
|
|
469
604
|
}
|
|
470
605
|
log(`\u5C06\u6267\u884C\u811A\u672C: ${scriptName}`);
|
|
471
606
|
const resolvedPm = await ensurePmAvailable(project.packageManager.name);
|
|
@@ -496,10 +631,16 @@ async function runCommand(projectDir, options = {}) {
|
|
|
496
631
|
throw new CliError("\u811A\u672C\u6267\u884C\u5931\u8D25", exitCode);
|
|
497
632
|
}
|
|
498
633
|
}
|
|
499
|
-
function findScript(project, scriptType) {
|
|
634
|
+
function findScript(project, scriptType, entry) {
|
|
500
635
|
const scripts = project.scripts;
|
|
501
636
|
if (!scripts)
|
|
502
637
|
return void 0;
|
|
638
|
+
if (entry) {
|
|
639
|
+
const entryScript = `${scriptType}:${entry}`;
|
|
640
|
+
if (scripts.scripts[entryScript]) {
|
|
641
|
+
return entryScript;
|
|
642
|
+
}
|
|
643
|
+
}
|
|
503
644
|
const detected = scripts.detected[scriptType];
|
|
504
645
|
if (detected) {
|
|
505
646
|
return detected;
|
|
@@ -509,9 +650,115 @@ function findScript(project, scriptType) {
|
|
|
509
650
|
}
|
|
510
651
|
return void 0;
|
|
511
652
|
}
|
|
512
|
-
function
|
|
653
|
+
async function resolveEntry(project, scriptType, entry) {
|
|
654
|
+
if (!project.scripts) {
|
|
655
|
+
return entry;
|
|
656
|
+
}
|
|
657
|
+
if (entry) {
|
|
658
|
+
validateEntry(project, scriptType, entry);
|
|
659
|
+
return entry;
|
|
660
|
+
}
|
|
661
|
+
if (scriptType !== "dev") {
|
|
662
|
+
return void 0;
|
|
663
|
+
}
|
|
664
|
+
const { mpa } = project.scripts;
|
|
665
|
+
if (!mpa.isMpa || mpa.entries.length === 0) {
|
|
666
|
+
return void 0;
|
|
667
|
+
}
|
|
668
|
+
if (mpa.entries.length === 1) {
|
|
669
|
+
const onlyEntry = mpa.entries[0];
|
|
670
|
+
if (onlyEntry) {
|
|
671
|
+
return onlyEntry;
|
|
672
|
+
}
|
|
673
|
+
return void 0;
|
|
674
|
+
}
|
|
675
|
+
const envEntry = process.env.PR_ENTRY?.trim();
|
|
676
|
+
if (envEntry) {
|
|
677
|
+
validateEntry(project, scriptType, envEntry);
|
|
678
|
+
return envEntry;
|
|
679
|
+
}
|
|
680
|
+
const defaultEntry = mpa.defaultEntry && hasEntryScript(project, scriptType, mpa.defaultEntry) ? mpa.defaultEntry : void 0;
|
|
681
|
+
if (!process.stdin.isTTY) {
|
|
682
|
+
if (defaultEntry) {
|
|
683
|
+
return defaultEntry;
|
|
684
|
+
}
|
|
685
|
+
throw new CliError(
|
|
686
|
+
`\u68C0\u6D4B\u5230 MPA \u5165\u53E3: ${mpa.entries.join(", ")}\u3002\u975E\u4EA4\u4E92\u73AF\u5883\u8BF7\u4F7F\u7528 --entry <name> \u6216\u8BBE\u7F6E PR_ENTRY\u3002`
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
return promptSelectEntry(project, scriptType, defaultEntry);
|
|
690
|
+
}
|
|
691
|
+
function validateEntry(project, scriptType, entry) {
|
|
692
|
+
if (!hasEntryScript(project, scriptType, entry)) {
|
|
693
|
+
const available = getAvailableEntriesByType(project, scriptType);
|
|
694
|
+
if (available.length > 0) {
|
|
695
|
+
throw new CliError(`\u5165\u53E3 "${entry}" \u4E0D\u5B58\u5728\u3002\u53EF\u9009\u5165\u53E3: ${available.join(", ")}`);
|
|
696
|
+
}
|
|
697
|
+
throw new CliError(`\u5165\u53E3 "${entry}" \u4E0D\u5B58\u5728\uFF0C\u4E14\u672A\u627E\u5230 ${scriptType}:<entry> \u811A\u672C`);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
function hasEntryScript(project, scriptType, entry) {
|
|
701
|
+
const scripts = project.scripts;
|
|
702
|
+
if (!scripts)
|
|
703
|
+
return false;
|
|
704
|
+
return Boolean(scripts.scripts[`${scriptType}:${entry}`]);
|
|
705
|
+
}
|
|
706
|
+
function getAvailableEntriesByType(project, scriptType) {
|
|
707
|
+
const scripts = project.scripts;
|
|
708
|
+
if (!scripts)
|
|
709
|
+
return [];
|
|
710
|
+
const mapping = scripts.mpa.scriptsByType[scriptType];
|
|
711
|
+
if (!mapping)
|
|
712
|
+
return [];
|
|
713
|
+
return Object.keys(mapping);
|
|
714
|
+
}
|
|
715
|
+
async function promptSelectEntry(project, scriptType, defaultEntry) {
|
|
716
|
+
const entries = getAvailableEntriesByType(project, scriptType);
|
|
717
|
+
if (entries.length === 0) {
|
|
718
|
+
throw new CliError(`\u672A\u627E\u5230 ${scriptType}:<entry> \u811A\u672C\uFF0C\u65E0\u6CD5\u9009\u62E9 MPA \u5165\u53E3`);
|
|
719
|
+
}
|
|
720
|
+
const defaultResolved = defaultEntry && entries.includes(defaultEntry) ? defaultEntry : entries[0];
|
|
721
|
+
if (!defaultResolved) {
|
|
722
|
+
throw new CliError("\u672A\u627E\u5230\u53EF\u7528\u5165\u53E3\uFF0C\u65E0\u6CD5\u7EE7\u7EED\u6267\u884C");
|
|
723
|
+
}
|
|
724
|
+
info("\u68C0\u6D4B\u5230 MPA \u9879\u76EE\uFF0C\u8BF7\u9009\u62E9\u542F\u52A8\u5165\u53E3\uFF1A");
|
|
725
|
+
entries.forEach((item, index) => {
|
|
726
|
+
const marker = item === defaultResolved ? " (\u9ED8\u8BA4)" : "";
|
|
727
|
+
console.log(` ${index + 1}) ${item}${marker}`);
|
|
728
|
+
});
|
|
729
|
+
console.log();
|
|
730
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
731
|
+
try {
|
|
732
|
+
const answer = await rl.question(`\u8BF7\u8F93\u5165\u5E8F\u53F7 [1-${entries.length}]\uFF0C\u56DE\u8F66\u9ED8\u8BA4 ${defaultResolved}: `);
|
|
733
|
+
const trimmed = answer.trim();
|
|
734
|
+
if (!trimmed) {
|
|
735
|
+
return defaultResolved;
|
|
736
|
+
}
|
|
737
|
+
const number = Number(trimmed);
|
|
738
|
+
if (Number.isInteger(number) && number >= 1 && number <= entries.length) {
|
|
739
|
+
const selectedByNumber = entries[number - 1];
|
|
740
|
+
if (selectedByNumber) {
|
|
741
|
+
return selectedByNumber;
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (entries.includes(trimmed)) {
|
|
745
|
+
return trimmed;
|
|
746
|
+
}
|
|
747
|
+
} finally {
|
|
748
|
+
rl.close();
|
|
749
|
+
}
|
|
750
|
+
throw new CliError("\u65E0\u6548\u7684\u5165\u53E3\u9009\u62E9\uFF0C\u8BF7\u91CD\u65B0\u8FD0\u884C\u5E76\u8F93\u5165\u6B63\u786E\u5E8F\u53F7");
|
|
751
|
+
}
|
|
752
|
+
function showAvailableScripts(project, scriptType, entry) {
|
|
513
753
|
if (!project.scripts)
|
|
514
754
|
return;
|
|
755
|
+
if (entry) {
|
|
756
|
+
const availableEntries = getAvailableEntriesByType(project, scriptType);
|
|
757
|
+
if (availableEntries.length > 0) {
|
|
758
|
+
info(`\u53EF\u9009 ${scriptType} \u5165\u53E3: ${availableEntries.join(", ")}`);
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
515
762
|
const scriptNames = Object.keys(project.scripts.scripts);
|
|
516
763
|
if (scriptNames.length === 0) {
|
|
517
764
|
warn("package.json \u4E2D\u6CA1\u6709\u5B9A\u4E49\u4EFB\u4F55 scripts");
|
|
@@ -529,8 +776,8 @@ function showAvailableScripts(project) {
|
|
|
529
776
|
async function infoCommand(projectDir) {
|
|
530
777
|
const project = await analyzeProject(projectDir);
|
|
531
778
|
if (project.type === "unknown") {
|
|
532
|
-
console.log(`${colors.red}\
|
|
533
|
-
console.log(" \u8BF7\u786E\
|
|
779
|
+
console.log(`${colors.red}\xD7${colors.reset} \u672A\u68C0\u6D4B\u5230\u9879\u76EE\u7C7B\u578B`);
|
|
780
|
+
console.log(" \u8BF7\u786E\u8BA4\u5F53\u524D\u76EE\u5F55\u5305\u542B package.json");
|
|
534
781
|
return;
|
|
535
782
|
}
|
|
536
783
|
console.log();
|
|
@@ -558,6 +805,22 @@ async function infoCommand(projectDir) {
|
|
|
558
805
|
const deps = project.dependencies;
|
|
559
806
|
const depsStatus = deps.needsInstall ? `${colors.yellow}\u9700\u8981\u5B89\u88C5${colors.reset} (${deps.reason})` : `${colors.green}\u5DF2\u5C31\u7EEA${colors.reset}`;
|
|
560
807
|
console.log(`${colors.bold}\u4F9D\u8D56\u72B6\u6001:${colors.reset} ${depsStatus}`);
|
|
808
|
+
if (project.scripts) {
|
|
809
|
+
const { mpa } = project.scripts;
|
|
810
|
+
if (mpa.isMpa) {
|
|
811
|
+
const sourceLabel = mpa.source === "local-config" ? ".pr.local.json" : mpa.source === "package-json" ? "package.json#pr" : "scripts";
|
|
812
|
+
console.log(`${colors.bold}MPA \u6A21\u5F0F:${colors.reset} \u662F ${colors.dim}(${sourceLabel})${colors.reset}`);
|
|
813
|
+
console.log(`${colors.bold}\u53EF\u9009\u5165\u53E3:${colors.reset} ${mpa.entries.join(", ")}`);
|
|
814
|
+
if (mpa.defaultEntry) {
|
|
815
|
+
console.log(`${colors.bold}\u9ED8\u8BA4\u5165\u53E3:${colors.reset} ${mpa.defaultEntry}`);
|
|
816
|
+
}
|
|
817
|
+
if (project.localConfig) {
|
|
818
|
+
console.log(`${colors.bold}\u672C\u5730\u914D\u7F6E:${colors.reset} .pr.local.json ${colors.dim}(\u81EA\u52A8\u52A0\u5165 .gitignore)${colors.reset}`);
|
|
819
|
+
}
|
|
820
|
+
} else {
|
|
821
|
+
console.log(`${colors.bold}MPA \u6A21\u5F0F:${colors.reset} \u5426`);
|
|
822
|
+
}
|
|
823
|
+
}
|
|
561
824
|
console.log();
|
|
562
825
|
if (project.scripts) {
|
|
563
826
|
const { scripts, detected } = project.scripts;
|
|
@@ -580,7 +843,10 @@ async function infoCommand(projectDir) {
|
|
|
580
843
|
console.log(`${colors.bold}\u6240\u6709\u811A\u672C:${colors.reset}`);
|
|
581
844
|
for (const name of allScripts) {
|
|
582
845
|
const cmd = scripts[name];
|
|
583
|
-
|
|
846
|
+
if (!cmd) {
|
|
847
|
+
continue;
|
|
848
|
+
}
|
|
849
|
+
const displayCmd = cmd.length > 60 ? cmd.slice(0, 60) + "..." : cmd;
|
|
584
850
|
console.log(` ${colors.cyan}${name}${colors.reset} ${colors.dim}\u2192 ${displayCmd}${colors.reset}`);
|
|
585
851
|
}
|
|
586
852
|
}
|
|
@@ -624,7 +890,7 @@ function showAvailableScripts2(scripts) {
|
|
|
624
890
|
}
|
|
625
891
|
|
|
626
892
|
// src/index.ts
|
|
627
|
-
var VERSION = true ? "0.
|
|
893
|
+
var VERSION = true ? "0.3.0" : "0.0.0-dev";
|
|
628
894
|
function parseArgs(args) {
|
|
629
895
|
const options = {
|
|
630
896
|
verbose: false,
|
|
@@ -637,14 +903,30 @@ function parseArgs(args) {
|
|
|
637
903
|
let i = 0;
|
|
638
904
|
while (i < args.length) {
|
|
639
905
|
const arg = args[i];
|
|
906
|
+
if (!arg) {
|
|
907
|
+
i++;
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
640
910
|
if (arg === "-v" || arg === "--verbose") {
|
|
641
911
|
options.verbose = true;
|
|
642
912
|
} else if (arg === "-d" || arg === "--dir") {
|
|
643
|
-
|
|
913
|
+
const dirArg = args[i + 1];
|
|
914
|
+
if (!dirArg || dirArg.startsWith("-")) {
|
|
915
|
+
throw new CliError("--dir \u9700\u8981\u4E00\u4E2A\u76EE\u5F55\u53C2\u6570");
|
|
916
|
+
}
|
|
917
|
+
options.dir = resolve(dirArg);
|
|
918
|
+
i++;
|
|
644
919
|
} else if (arg === "--no-install") {
|
|
645
920
|
options.noInstall = true;
|
|
646
921
|
} else if (arg === "-i" || arg === "--install") {
|
|
647
922
|
options.install = true;
|
|
923
|
+
} else if (arg === "-e" || arg === "--entry") {
|
|
924
|
+
const entryArg = args[i + 1];
|
|
925
|
+
if (!entryArg || entryArg.startsWith("-")) {
|
|
926
|
+
throw new CliError("--entry \u9700\u8981\u4E00\u4E2A\u5165\u53E3\u540D\u53C2\u6570");
|
|
927
|
+
}
|
|
928
|
+
options.entry = entryArg.trim();
|
|
929
|
+
i++;
|
|
648
930
|
} else if (arg === "-h" || arg === "--help") {
|
|
649
931
|
command = "help";
|
|
650
932
|
} else if (arg === "-V" || arg === "--version") {
|
|
@@ -669,7 +951,7 @@ ${"\x1B[36m"}pr${"\x1B[0m"} v${VERSION} - \u96F6\u914D\u7F6E\u667A\u80FD\u9879\u
|
|
|
669
951
|
${"\x1B[1m"}\u7528\u6CD5:${"\x1B[0m"} pr <command> [options]
|
|
670
952
|
|
|
671
953
|
${"\x1B[1m"}\u547D\u4EE4:${"\x1B[0m"}
|
|
672
|
-
run \u5B8C\u6574\u6D41\u7A0B\uFF1A\u68C0\u6D4B
|
|
954
|
+
run \u5B8C\u6574\u6D41\u7A0B\uFF1A\u68C0\u6D4B -> install -> \u542F\u52A8\u5F00\u53D1\u811A\u672C
|
|
673
955
|
test \u8FD0\u884C\u6D4B\u8BD5
|
|
674
956
|
build \u6784\u5EFA\u9879\u76EE
|
|
675
957
|
start \u751F\u4EA7\u6A21\u5F0F\u542F\u52A8
|
|
@@ -681,16 +963,16 @@ ${"\x1B[1m"}\u9009\u9879:${"\x1B[0m"}
|
|
|
681
963
|
-d, --dir <path> \u6307\u5B9A\u9879\u76EE\u76EE\u5F55 (\u9ED8\u8BA4: \u5F53\u524D\u76EE\u5F55)
|
|
682
964
|
-i, --install \u5F3A\u5236\u6267\u884C\u4F9D\u8D56\u5B89\u88C5
|
|
683
965
|
--no-install \u8DF3\u8FC7\u4F9D\u8D56\u5B89\u88C5\u6B65\u9AA4
|
|
966
|
+
-e, --entry \u6307\u5B9A MPA \u5165\u53E3 (\u4E5F\u53EF\u7528\u73AF\u5883\u53D8\u91CF PR_ENTRY)
|
|
684
967
|
-h, --help \u663E\u793A\u5E2E\u52A9\u4FE1\u606F
|
|
685
968
|
-V, --version \u663E\u793A\u7248\u672C\u53F7
|
|
686
969
|
|
|
687
970
|
${"\x1B[1m"}\u793A\u4F8B:${"\x1B[0m"}
|
|
688
|
-
pr run
|
|
689
|
-
pr run
|
|
690
|
-
pr run
|
|
691
|
-
pr
|
|
692
|
-
pr
|
|
693
|
-
pr info \u67E5\u770B\u9879\u76EE\u4FE1\u606F
|
|
971
|
+
pr run
|
|
972
|
+
pr run --entry main
|
|
973
|
+
PR_ENTRY=formengine pr run
|
|
974
|
+
pr build --entry approve
|
|
975
|
+
pr info
|
|
694
976
|
`);
|
|
695
977
|
}
|
|
696
978
|
function showVersion() {
|
|
@@ -698,7 +980,7 @@ function showVersion() {
|
|
|
698
980
|
}
|
|
699
981
|
async function main() {
|
|
700
982
|
setupSignalHandlers();
|
|
701
|
-
const { command, options
|
|
983
|
+
const { command, options } = parseArgs(process.argv.slice(2));
|
|
702
984
|
setVerbose(options.verbose);
|
|
703
985
|
switch (command) {
|
|
704
986
|
case "":
|
|
@@ -709,16 +991,33 @@ async function main() {
|
|
|
709
991
|
showVersion();
|
|
710
992
|
break;
|
|
711
993
|
case "run":
|
|
712
|
-
await runCommand(options.dir, {
|
|
994
|
+
await runCommand(options.dir, {
|
|
995
|
+
noInstall: options.noInstall,
|
|
996
|
+
forceInstall: options.install,
|
|
997
|
+
scriptType: "dev",
|
|
998
|
+
entry: options.entry
|
|
999
|
+
});
|
|
713
1000
|
break;
|
|
714
1001
|
case "test":
|
|
715
|
-
await runCommand(options.dir, {
|
|
1002
|
+
await runCommand(options.dir, {
|
|
1003
|
+
noInstall: true,
|
|
1004
|
+
scriptType: "test",
|
|
1005
|
+
entry: options.entry
|
|
1006
|
+
});
|
|
716
1007
|
break;
|
|
717
1008
|
case "build":
|
|
718
|
-
await runCommand(options.dir, {
|
|
1009
|
+
await runCommand(options.dir, {
|
|
1010
|
+
noInstall: true,
|
|
1011
|
+
scriptType: "build",
|
|
1012
|
+
entry: options.entry
|
|
1013
|
+
});
|
|
719
1014
|
break;
|
|
720
1015
|
case "start":
|
|
721
|
-
await runCommand(options.dir, {
|
|
1016
|
+
await runCommand(options.dir, {
|
|
1017
|
+
noInstall: true,
|
|
1018
|
+
scriptType: "start",
|
|
1019
|
+
entry: options.entry
|
|
1020
|
+
});
|
|
722
1021
|
break;
|
|
723
1022
|
case "info":
|
|
724
1023
|
await infoCommand(options.dir);
|