weapp-ide-cli 5.1.1 → 5.1.3
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/dist/{cli-Dv5EAvYh.js → cli-BkQJ3Aww.js} +294 -355
- package/dist/cli.js +2 -2
- package/dist/commands-CSbpftLN.js +628 -0
- package/dist/index.d.ts +100 -41
- package/dist/index.js +3 -3
- package/package.json +4 -3
- package/dist/commands-9F3ycbXU.js +0 -342
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import process, { stdin, stdout } from "node:process";
|
|
1
|
+
import { A as createLocaleConfig, B as operatingSystemName, E as resolveCliPath, F as defaultCustomConfigFilePath, H as logger_default, I as resolvePath, M as readCustomConfig, N as removeCustomConfigKey, O as getConfiguredLocale, V as colors, _ as connectMiniProgram, a as navigateBack, b as i18nText, c as pageStack, d as remote, f as scrollTo, g as tap, i as input, j as overwriteCustomConfig, k as createCustomConfig, l as reLaunch, m as systemInfo, o as navigateTo, p as switchTab, r as currentPage, s as pageData, t as audit, u as redirectTo, x as validateLocaleOption, y as configureLocaleFromArgv, z as isOperatingSystemSupported } from "./commands-CSbpftLN.js";
|
|
3
2
|
import fs from "fs-extra";
|
|
4
|
-
import
|
|
5
|
-
import os from "node:os";
|
|
3
|
+
import process, { stdin, stdout } from "node:process";
|
|
6
4
|
import { createInterface } from "node:readline/promises";
|
|
5
|
+
import { inspect } from "node:util";
|
|
7
6
|
import { emitKeypressEvents } from "node:readline";
|
|
7
|
+
import { cac } from "cac";
|
|
8
8
|
//#region src/cli/automator-argv.ts
|
|
9
9
|
/**
|
|
10
10
|
* @description 解析 automator 命令通用参数与位置参数。
|
|
@@ -182,7 +182,7 @@ async function runScreenshot(argv) {
|
|
|
182
182
|
}
|
|
183
183
|
const options = parseScreenshotArgs(argv);
|
|
184
184
|
const isJsonOutput = argv.includes("--json");
|
|
185
|
-
const { takeScreenshot } = await import("./commands-
|
|
185
|
+
const { takeScreenshot } = await import("./commands-CSbpftLN.js").then((n) => n.n);
|
|
186
186
|
const result = await takeScreenshot(options);
|
|
187
187
|
if (isJsonOutput) {
|
|
188
188
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -192,6 +192,43 @@ async function runScreenshot(argv) {
|
|
|
192
192
|
}
|
|
193
193
|
//#endregion
|
|
194
194
|
//#region src/cli/run-automator.ts
|
|
195
|
+
const COMMON_OPTION_DEFINITIONS = [
|
|
196
|
+
{
|
|
197
|
+
flag: "-p, --project <path>",
|
|
198
|
+
description: {
|
|
199
|
+
zh: "项目路径(默认:当前目录)",
|
|
200
|
+
en: "Project path (default: current directory)"
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
flag: "-t, --timeout <ms>",
|
|
205
|
+
description: {
|
|
206
|
+
zh: "连接超时时间(默认:30000)",
|
|
207
|
+
en: "Connection timeout (default: 30000)"
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
{
|
|
211
|
+
flag: "--json",
|
|
212
|
+
description: {
|
|
213
|
+
zh: "支持时以 JSON 输出",
|
|
214
|
+
en: "Output as JSON when supported"
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
flag: "--lang <lang>",
|
|
219
|
+
description: {
|
|
220
|
+
zh: "语言切换:zh | en(默认:zh)",
|
|
221
|
+
en: "Language: zh | en (default: zh)"
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
flag: "-h, --help",
|
|
226
|
+
description: {
|
|
227
|
+
zh: "显示命令帮助",
|
|
228
|
+
en: "Show command help"
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
];
|
|
195
232
|
const COMMON_ALLOWED_OPTIONS = new Set([
|
|
196
233
|
"-p",
|
|
197
234
|
"--project",
|
|
@@ -202,6 +239,27 @@ const COMMON_ALLOWED_OPTIONS = new Set([
|
|
|
202
239
|
"-h",
|
|
203
240
|
"--help"
|
|
204
241
|
]);
|
|
242
|
+
function createDefinition(input) {
|
|
243
|
+
return {
|
|
244
|
+
description: input.description,
|
|
245
|
+
usage: input.usage,
|
|
246
|
+
options: input.options ?? [],
|
|
247
|
+
allowedOptions: new Set([...COMMON_ALLOWED_OPTIONS, ...input.allowedOptions ?? []]),
|
|
248
|
+
handler: input.handler
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
function requiredPositional(value, errorMessage) {
|
|
252
|
+
if (!value) throw new Error(errorMessage);
|
|
253
|
+
return value;
|
|
254
|
+
}
|
|
255
|
+
function validateUnsupportedOptions(command, argv, allowedOptions) {
|
|
256
|
+
for (const token of argv) {
|
|
257
|
+
if (!token.startsWith("-")) continue;
|
|
258
|
+
const optionName = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
|
|
259
|
+
if (allowedOptions.has(optionName)) continue;
|
|
260
|
+
throw new Error(i18nText(`'${command}' 命令不支持参数 '${optionName}'`, `Command '${command}' does not support option '${optionName}'`));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
205
263
|
const COMMAND_DEFINITIONS = {
|
|
206
264
|
"navigate": createDefinition({
|
|
207
265
|
description: {
|
|
@@ -404,85 +462,26 @@ const COMMAND_DEFINITIONS = {
|
|
|
404
462
|
})
|
|
405
463
|
};
|
|
406
464
|
const AUTOMATOR_COMMAND_NAMES = ["screenshot", ...Object.keys(COMMAND_DEFINITIONS)];
|
|
407
|
-
const
|
|
465
|
+
const AUTOMATOR_COMMAND_SET = new Set(AUTOMATOR_COMMAND_NAMES);
|
|
408
466
|
/**
|
|
409
467
|
* @description 判断是否属于 automator 子命令。
|
|
410
468
|
*/
|
|
411
469
|
function isAutomatorCommand(command) {
|
|
412
|
-
return Boolean(command &&
|
|
470
|
+
return Boolean(command && AUTOMATOR_COMMAND_SET.has(command));
|
|
413
471
|
}
|
|
414
472
|
/**
|
|
415
|
-
* @description
|
|
416
|
-
*/
|
|
417
|
-
async function runAutomatorCommand(command, argv) {
|
|
418
|
-
if (command === "screenshot") {
|
|
419
|
-
await runScreenshot(argv);
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
const definition = COMMAND_DEFINITIONS[command];
|
|
423
|
-
if (!definition) throw new Error(i18nText(`未知 automator 命令: ${command}`, `Unknown automator command: ${command}`));
|
|
424
|
-
if (argv.includes("-h") || argv.includes("--help")) {
|
|
425
|
-
printCommandHelp(command);
|
|
426
|
-
return;
|
|
427
|
-
}
|
|
428
|
-
validateUnsupportedOptions(command, argv, definition.allowedOptions);
|
|
429
|
-
const args = parseAutomatorArgs(argv);
|
|
430
|
-
await definition.handler({
|
|
431
|
-
argv,
|
|
432
|
-
args
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
/**
|
|
436
|
-
* @description 获取 automator 命令帮助文本。
|
|
473
|
+
* @description 获取 automator 子命令帮助文本。
|
|
437
474
|
*/
|
|
438
475
|
function getAutomatorCommandHelp(command) {
|
|
439
476
|
const definition = COMMAND_DEFINITIONS[command];
|
|
440
477
|
if (!definition) return;
|
|
441
|
-
const optionLines = [
|
|
442
|
-
...definition.options,
|
|
443
|
-
{
|
|
444
|
-
flag: "-p, --project <path>",
|
|
445
|
-
description: {
|
|
446
|
-
zh: "项目路径(默认:当前目录)",
|
|
447
|
-
en: "Project path (default: current directory)"
|
|
448
|
-
}
|
|
449
|
-
},
|
|
450
|
-
{
|
|
451
|
-
flag: "-t, --timeout <ms>",
|
|
452
|
-
description: {
|
|
453
|
-
zh: "连接超时时间(默认:30000)",
|
|
454
|
-
en: "Connection timeout (default: 30000)"
|
|
455
|
-
}
|
|
456
|
-
},
|
|
457
|
-
{
|
|
458
|
-
flag: "--json",
|
|
459
|
-
description: {
|
|
460
|
-
zh: "支持时以 JSON 输出",
|
|
461
|
-
en: "Output as JSON when supported"
|
|
462
|
-
}
|
|
463
|
-
},
|
|
464
|
-
{
|
|
465
|
-
flag: "--lang <lang>",
|
|
466
|
-
description: {
|
|
467
|
-
zh: "语言切换:zh | en(默认:zh)",
|
|
468
|
-
en: "Language: zh | en (default: zh)"
|
|
469
|
-
}
|
|
470
|
-
},
|
|
471
|
-
{
|
|
472
|
-
flag: "-h, --help",
|
|
473
|
-
description: {
|
|
474
|
-
zh: "显示命令帮助",
|
|
475
|
-
en: "Show command help"
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
];
|
|
479
478
|
return [
|
|
480
479
|
i18nText(definition.description.zh, definition.description.en),
|
|
481
480
|
"",
|
|
482
481
|
`Usage: ${definition.usage}`,
|
|
483
482
|
"",
|
|
484
483
|
i18nText("参数:", "Options:"),
|
|
485
|
-
...
|
|
484
|
+
...[...definition.options, ...COMMON_OPTION_DEFINITIONS].map((option) => ` ${option.flag.padEnd(24)} ${i18nText(option.description.zh, option.description.en)}`)
|
|
486
485
|
].join("\n");
|
|
487
486
|
}
|
|
488
487
|
function printCommandHelp(command) {
|
|
@@ -493,28 +492,26 @@ function printCommandHelp(command) {
|
|
|
493
492
|
}
|
|
494
493
|
logger_default.warn(i18nText(`命令 ${command} 暂无帮助信息`, `No help available for command: ${command}`));
|
|
495
494
|
}
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
allowedOptions,
|
|
504
|
-
handler: input.handler
|
|
505
|
-
};
|
|
506
|
-
}
|
|
507
|
-
function validateUnsupportedOptions(command, argv, allowedOptions) {
|
|
508
|
-
for (const token of argv) {
|
|
509
|
-
if (!token.startsWith("-")) continue;
|
|
510
|
-
const optionName = token.includes("=") ? token.slice(0, token.indexOf("=")) : token;
|
|
511
|
-
if (allowedOptions.has(optionName)) continue;
|
|
512
|
-
throw new Error(i18nText(`'${command}' 命令不支持参数 '${optionName}'`, `Unknown option '${optionName}' for '${command}' command`));
|
|
495
|
+
/**
|
|
496
|
+
* @description 执行 automator 子命令。
|
|
497
|
+
*/
|
|
498
|
+
async function runAutomatorCommand(command, argv) {
|
|
499
|
+
if (command === "screenshot") {
|
|
500
|
+
await runScreenshot(argv);
|
|
501
|
+
return;
|
|
513
502
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
if (
|
|
517
|
-
|
|
503
|
+
const definition = COMMAND_DEFINITIONS[command];
|
|
504
|
+
if (!definition) throw new Error(i18nText(`未知 automator 命令: ${command}`, `Unknown automator command: ${command}`));
|
|
505
|
+
if (argv.includes("-h") || argv.includes("--help")) {
|
|
506
|
+
printCommandHelp(command);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
validateUnsupportedOptions(command, argv, definition.allowedOptions);
|
|
510
|
+
const args = parseAutomatorArgs(argv);
|
|
511
|
+
await definition.handler({
|
|
512
|
+
argv,
|
|
513
|
+
args
|
|
514
|
+
});
|
|
518
515
|
}
|
|
519
516
|
//#endregion
|
|
520
517
|
//#region src/cli/command-catalog.ts
|
|
@@ -558,93 +555,6 @@ function isWeappIdeTopLevelCommand(command) {
|
|
|
558
555
|
return Boolean(command && WEAPP_IDE_TOP_LEVEL_COMMAND_SET.has(command));
|
|
559
556
|
}
|
|
560
557
|
//#endregion
|
|
561
|
-
//#region src/utils/path.ts
|
|
562
|
-
/**
|
|
563
|
-
* @description 解析为绝对路径(基于当前工作目录)
|
|
564
|
-
*/
|
|
565
|
-
function resolvePath(filePath) {
|
|
566
|
-
if (path.isAbsolute(filePath)) return filePath;
|
|
567
|
-
return path.resolve(process.cwd(), filePath);
|
|
568
|
-
}
|
|
569
|
-
//#endregion
|
|
570
|
-
//#region src/config/paths.ts
|
|
571
|
-
const homedir = os.homedir();
|
|
572
|
-
/**
|
|
573
|
-
* @description 默认自定义配置目录
|
|
574
|
-
*/
|
|
575
|
-
const defaultCustomConfigDirPath = path.join(homedir, ".weapp-ide-cli");
|
|
576
|
-
/**
|
|
577
|
-
* @description 默认自定义配置文件路径
|
|
578
|
-
*/
|
|
579
|
-
const defaultCustomConfigFilePath = path.join(defaultCustomConfigDirPath, "config.json");
|
|
580
|
-
//#endregion
|
|
581
|
-
//#region src/config/custom.ts
|
|
582
|
-
const JSON_OPTIONS = {
|
|
583
|
-
encoding: "utf8",
|
|
584
|
-
spaces: 2
|
|
585
|
-
};
|
|
586
|
-
/**
|
|
587
|
-
* @description 写入自定义 CLI 路径配置
|
|
588
|
-
*/
|
|
589
|
-
async function createCustomConfig(params) {
|
|
590
|
-
const trimmedCliPath = params.cliPath.trim();
|
|
591
|
-
if (!trimmedCliPath) throw new Error("cliPath cannot be empty");
|
|
592
|
-
const normalizedCliPath = resolvePath(trimmedCliPath);
|
|
593
|
-
await writeCustomConfig({ cliPath: normalizedCliPath });
|
|
594
|
-
return normalizedCliPath;
|
|
595
|
-
}
|
|
596
|
-
/**
|
|
597
|
-
* @description 写入语言配置(zh / en)。
|
|
598
|
-
*/
|
|
599
|
-
async function createLocaleConfig(locale) {
|
|
600
|
-
await writeCustomConfig({ locale });
|
|
601
|
-
return locale;
|
|
602
|
-
}
|
|
603
|
-
/**
|
|
604
|
-
* @description 删除指定配置项。
|
|
605
|
-
*/
|
|
606
|
-
async function removeCustomConfigKey(key) {
|
|
607
|
-
const currentConfig = await readCustomConfig();
|
|
608
|
-
if (!(key in currentConfig)) return;
|
|
609
|
-
const nextConfig = { ...currentConfig };
|
|
610
|
-
delete nextConfig[key];
|
|
611
|
-
await writeCustomConfig(nextConfig, { replace: true });
|
|
612
|
-
}
|
|
613
|
-
/**
|
|
614
|
-
* @description 覆盖写入配置内容(会替换原内容)。
|
|
615
|
-
*/
|
|
616
|
-
async function overwriteCustomConfig(config) {
|
|
617
|
-
const nextConfig = {};
|
|
618
|
-
if (typeof config.cliPath === "string" && config.cliPath.trim()) nextConfig.cliPath = resolvePath(config.cliPath.trim());
|
|
619
|
-
if (config.locale === "zh" || config.locale === "en") nextConfig.locale = config.locale;
|
|
620
|
-
await writeCustomConfig(nextConfig, { replace: true });
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* @description 读取原始自定义配置。
|
|
624
|
-
*/
|
|
625
|
-
async function readCustomConfig() {
|
|
626
|
-
if (!await fs.pathExists(defaultCustomConfigFilePath)) return {};
|
|
627
|
-
try {
|
|
628
|
-
const config = await fs.readJSON(defaultCustomConfigFilePath);
|
|
629
|
-
if (!config || typeof config !== "object") return {};
|
|
630
|
-
const candidate = config;
|
|
631
|
-
const next = {};
|
|
632
|
-
if (typeof candidate.cliPath === "string" && candidate.cliPath.trim()) next.cliPath = candidate.cliPath.trim();
|
|
633
|
-
if (candidate.locale === "zh" || candidate.locale === "en") next.locale = candidate.locale;
|
|
634
|
-
return next;
|
|
635
|
-
} catch {
|
|
636
|
-
return {};
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
async function writeCustomConfig(patch, options = {}) {
|
|
640
|
-
const nextConfig = {
|
|
641
|
-
...options.replace ? {} : await readCustomConfig(),
|
|
642
|
-
...patch
|
|
643
|
-
};
|
|
644
|
-
await fs.ensureDir(defaultCustomConfigDirPath);
|
|
645
|
-
await fs.writeJSON(defaultCustomConfigFilePath, nextConfig, JSON_OPTIONS);
|
|
646
|
-
}
|
|
647
|
-
//#endregion
|
|
648
558
|
//#region src/cli/prompt.ts
|
|
649
559
|
/**
|
|
650
560
|
* @description 交互式提示并保存 CLI 路径
|
|
@@ -680,134 +590,6 @@ async function promptForCliPath() {
|
|
|
680
590
|
}
|
|
681
591
|
}
|
|
682
592
|
//#endregion
|
|
683
|
-
//#region src/runtime/platform.ts
|
|
684
|
-
/**
|
|
685
|
-
* @description 官方微信开发者工具只支持 Windows、macOS,Linux 只有社区版
|
|
686
|
-
* https://github.com/msojocs/wechat-web-devtools-linux
|
|
687
|
-
*/
|
|
688
|
-
const SupportedPlatformsMap = {
|
|
689
|
-
Windows_NT: "Windows_NT",
|
|
690
|
-
Darwin: "Darwin",
|
|
691
|
-
Linux: "Linux"
|
|
692
|
-
};
|
|
693
|
-
/**
|
|
694
|
-
* @description 判断当前系统是否支持微信开发者工具
|
|
695
|
-
*/
|
|
696
|
-
function isOperatingSystemSupported(osName = os.type()) {
|
|
697
|
-
return osName === SupportedPlatformsMap.Windows_NT || osName === SupportedPlatformsMap.Darwin || osName === SupportedPlatformsMap.Linux;
|
|
698
|
-
}
|
|
699
|
-
/**
|
|
700
|
-
* @description 当前系统名称
|
|
701
|
-
*/
|
|
702
|
-
const operatingSystemName = os.type();
|
|
703
|
-
function createLinuxCliResolver() {
|
|
704
|
-
let resolvedPath;
|
|
705
|
-
let attempted = false;
|
|
706
|
-
let pending = null;
|
|
707
|
-
return async () => {
|
|
708
|
-
if (attempted) return resolvedPath;
|
|
709
|
-
if (!pending) pending = (async () => {
|
|
710
|
-
try {
|
|
711
|
-
const envPath = await getFirstBinaryPath("wechat-devtools-cli");
|
|
712
|
-
if (envPath) resolvedPath = envPath;
|
|
713
|
-
} catch (error) {
|
|
714
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
715
|
-
logger_default.warn(`获取 Linux wechat-devtools-cli 路径失败:${reason}`);
|
|
716
|
-
} finally {
|
|
717
|
-
attempted = true;
|
|
718
|
-
}
|
|
719
|
-
return resolvedPath;
|
|
720
|
-
})();
|
|
721
|
-
return pending;
|
|
722
|
-
};
|
|
723
|
-
}
|
|
724
|
-
const linuxCliResolver = createLinuxCliResolver();
|
|
725
|
-
const WINDOWS_DEFAULT_CLI = "C:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat";
|
|
726
|
-
const DARWIN_DEFAULT_CLI = "/Applications/wechatwebdevtools.app/Contents/MacOS/cli";
|
|
727
|
-
const cliPathResolvers = {
|
|
728
|
-
[SupportedPlatformsMap.Windows_NT]: async () => WINDOWS_DEFAULT_CLI,
|
|
729
|
-
[SupportedPlatformsMap.Darwin]: async () => DARWIN_DEFAULT_CLI,
|
|
730
|
-
[SupportedPlatformsMap.Linux]: linuxCliResolver
|
|
731
|
-
};
|
|
732
|
-
/**
|
|
733
|
-
* @description 获取默认 CLI 路径(按系统)
|
|
734
|
-
*/
|
|
735
|
-
async function getDefaultCliPath(targetOs = operatingSystemName) {
|
|
736
|
-
if (!isOperatingSystemSupported(targetOs)) return;
|
|
737
|
-
const resolver = cliPathResolvers[targetOs];
|
|
738
|
-
return await resolver();
|
|
739
|
-
}
|
|
740
|
-
async function getFirstBinaryPath(command) {
|
|
741
|
-
const pathDirs = (process.env.PATH || "").split(path.delimiter);
|
|
742
|
-
for (const dir of pathDirs) {
|
|
743
|
-
const fullPath = path.join(dir, command);
|
|
744
|
-
try {
|
|
745
|
-
await fs.access(fullPath, fs.constants.X_OK);
|
|
746
|
-
return fullPath;
|
|
747
|
-
} catch {
|
|
748
|
-
continue;
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
//#endregion
|
|
753
|
-
//#region src/config/resolver.ts
|
|
754
|
-
/**
|
|
755
|
-
* @description 读取并解析 CLI 配置(自定义优先)
|
|
756
|
-
*/
|
|
757
|
-
async function getConfig() {
|
|
758
|
-
if (await fs.pathExists(defaultCustomConfigFilePath)) try {
|
|
759
|
-
const config = await fs.readJSON(defaultCustomConfigFilePath);
|
|
760
|
-
const cliPath = typeof config.cliPath === "string" ? config.cliPath.trim() : "";
|
|
761
|
-
const locale = config.locale === "zh" || config.locale === "en" ? config.locale : void 0;
|
|
762
|
-
if (cliPath) {
|
|
763
|
-
logger_default.info(`全局配置文件路径:${colors.green(defaultCustomConfigFilePath)}`);
|
|
764
|
-
logger_default.info(`自定义 CLI 路径:${colors.green(cliPath)}`);
|
|
765
|
-
return {
|
|
766
|
-
cliPath,
|
|
767
|
-
locale,
|
|
768
|
-
source: "custom"
|
|
769
|
-
};
|
|
770
|
-
}
|
|
771
|
-
logger_default.warn("自定义配置文件缺少有效的 CLI 路径,将尝试使用默认路径。");
|
|
772
|
-
} catch (error) {
|
|
773
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
774
|
-
logger_default.warn(`解析自定义配置失败,将尝试使用默认路径。原因:${reason}`);
|
|
775
|
-
}
|
|
776
|
-
const fallbackPath = await getDefaultCliPath();
|
|
777
|
-
if (fallbackPath) return {
|
|
778
|
-
cliPath: fallbackPath,
|
|
779
|
-
locale: void 0,
|
|
780
|
-
source: "default"
|
|
781
|
-
};
|
|
782
|
-
return {
|
|
783
|
-
cliPath: "",
|
|
784
|
-
locale: void 0,
|
|
785
|
-
source: "missing"
|
|
786
|
-
};
|
|
787
|
-
}
|
|
788
|
-
/**
|
|
789
|
-
* @description 获取用户配置的语言偏好。
|
|
790
|
-
*/
|
|
791
|
-
async function getConfiguredLocale() {
|
|
792
|
-
return (await readCustomConfig()).locale;
|
|
793
|
-
}
|
|
794
|
-
//#endregion
|
|
795
|
-
//#region src/cli/resolver.ts
|
|
796
|
-
/**
|
|
797
|
-
* @description 解析 CLI 路径并校验可用性
|
|
798
|
-
*/
|
|
799
|
-
async function resolveCliPath() {
|
|
800
|
-
const config = await getConfig();
|
|
801
|
-
if (!config.cliPath) return {
|
|
802
|
-
cliPath: null,
|
|
803
|
-
source: config.source
|
|
804
|
-
};
|
|
805
|
-
return {
|
|
806
|
-
cliPath: await fs.pathExists(config.cliPath) ? config.cliPath : null,
|
|
807
|
-
source: config.source
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
//#endregion
|
|
811
593
|
//#region src/cli/config-command.ts
|
|
812
594
|
/**
|
|
813
595
|
* @description 处理 config 子命令。
|
|
@@ -917,6 +699,123 @@ async function handleConfigCommand(argv) {
|
|
|
917
699
|
throw new Error(i18nText("支持的 config 子命令:lang | set-lang | show | get | set | unset | doctor | import | export", "Supported config subcommands: lang | set-lang | show | get | set | unset | doctor | import | export"));
|
|
918
700
|
}
|
|
919
701
|
//#endregion
|
|
702
|
+
//#region src/cli/forwardConsole.ts
|
|
703
|
+
const DEFAULT_FORWARD_CONSOLE_LEVELS = [
|
|
704
|
+
"log",
|
|
705
|
+
"info",
|
|
706
|
+
"warn",
|
|
707
|
+
"error"
|
|
708
|
+
];
|
|
709
|
+
/**
|
|
710
|
+
* @description 启动小程序控制台日志转发,并保持 automator 会话常驻。
|
|
711
|
+
*/
|
|
712
|
+
async function startForwardConsole(options) {
|
|
713
|
+
const miniProgram = await connectMiniProgram(options);
|
|
714
|
+
const logLevels = new Set(options.logLevels?.length ? options.logLevels : DEFAULT_FORWARD_CONSOLE_LEVELS);
|
|
715
|
+
const logHandler = options.onLog ?? printForwardConsoleEvent;
|
|
716
|
+
const onConsole = (payload) => {
|
|
717
|
+
const event = normalizeConsoleEvent(payload);
|
|
718
|
+
if (!logLevels.has(event.level)) return;
|
|
719
|
+
logHandler(event);
|
|
720
|
+
};
|
|
721
|
+
const onException = (payload) => {
|
|
722
|
+
if (options.unhandledErrors === false) return;
|
|
723
|
+
logHandler(normalizeExceptionEvent(payload));
|
|
724
|
+
};
|
|
725
|
+
miniProgram.on("console", onConsole);
|
|
726
|
+
miniProgram.on("exception", onException);
|
|
727
|
+
options.onReady?.();
|
|
728
|
+
let closed = false;
|
|
729
|
+
return { async close() {
|
|
730
|
+
if (closed) return;
|
|
731
|
+
closed = true;
|
|
732
|
+
detachMiniProgramListener(miniProgram, "console", onConsole);
|
|
733
|
+
detachMiniProgramListener(miniProgram, "exception", onException);
|
|
734
|
+
await miniProgram.close();
|
|
735
|
+
} };
|
|
736
|
+
}
|
|
737
|
+
function detachMiniProgramListener(miniProgram, event, listener) {
|
|
738
|
+
if (typeof miniProgram.off === "function") miniProgram.off(event, listener);
|
|
739
|
+
}
|
|
740
|
+
function printForwardConsoleEvent(event) {
|
|
741
|
+
const line = `${colors.dim(`[mini:${event.level}]`)} ${event.message}`;
|
|
742
|
+
switch (event.level) {
|
|
743
|
+
case "error":
|
|
744
|
+
logger_default.error(line);
|
|
745
|
+
return;
|
|
746
|
+
case "warn":
|
|
747
|
+
logger_default.warn(line);
|
|
748
|
+
return;
|
|
749
|
+
case "info":
|
|
750
|
+
logger_default.info(line);
|
|
751
|
+
return;
|
|
752
|
+
default: logger_default.log(line);
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
function normalizeConsoleEvent(payload) {
|
|
756
|
+
const record = toPlainObject(payload);
|
|
757
|
+
return {
|
|
758
|
+
level: normalizeLogLevel(record.type ?? record.level ?? record.method),
|
|
759
|
+
message: resolveLogMessage(record, payload),
|
|
760
|
+
raw: payload
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
function normalizeExceptionEvent(payload) {
|
|
764
|
+
const record = toPlainObject(payload);
|
|
765
|
+
const error = toPlainObject(record.error);
|
|
766
|
+
return {
|
|
767
|
+
level: "error",
|
|
768
|
+
message: [getStringValue(error.message) ?? getStringValue(record.message), getStringValue(error.stack) ?? getStringValue(record.stack)].filter(Boolean).join("\n") || inspect(payload, {
|
|
769
|
+
depth: 4,
|
|
770
|
+
colors: false,
|
|
771
|
+
compact: true
|
|
772
|
+
}),
|
|
773
|
+
raw: payload
|
|
774
|
+
};
|
|
775
|
+
}
|
|
776
|
+
function normalizeLogLevel(value) {
|
|
777
|
+
const normalized = String(value ?? "log").toLowerCase();
|
|
778
|
+
if (normalized === "warning") return "warn";
|
|
779
|
+
if (normalized === "debug" || normalized === "info" || normalized === "warn" || normalized === "error") return normalized;
|
|
780
|
+
return "log";
|
|
781
|
+
}
|
|
782
|
+
function resolveLogMessage(record, payload) {
|
|
783
|
+
const text = getStringValue(record.text) ?? getStringValue(record.message);
|
|
784
|
+
if (text) return text;
|
|
785
|
+
if (Array.isArray(record.args) && record.args.length > 0) return record.args.map(formatConsoleArgument).join(" ");
|
|
786
|
+
if (typeof payload === "string") return payload;
|
|
787
|
+
return inspect(payload, {
|
|
788
|
+
depth: 4,
|
|
789
|
+
colors: false,
|
|
790
|
+
compact: true
|
|
791
|
+
});
|
|
792
|
+
}
|
|
793
|
+
function formatConsoleArgument(value) {
|
|
794
|
+
const record = toPlainObject(value);
|
|
795
|
+
const rawValue = record.value;
|
|
796
|
+
const description = getStringValue(record.description);
|
|
797
|
+
if (typeof rawValue === "string" || typeof rawValue === "number" || typeof rawValue === "boolean") return String(rawValue);
|
|
798
|
+
if (rawValue !== void 0) return inspect(rawValue, {
|
|
799
|
+
depth: 4,
|
|
800
|
+
colors: false,
|
|
801
|
+
compact: true
|
|
802
|
+
});
|
|
803
|
+
if (description) return description;
|
|
804
|
+
if (typeof value === "string") return value;
|
|
805
|
+
return inspect(value, {
|
|
806
|
+
depth: 4,
|
|
807
|
+
colors: false,
|
|
808
|
+
compact: true
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
function getStringValue(value) {
|
|
812
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
813
|
+
}
|
|
814
|
+
function toPlainObject(value) {
|
|
815
|
+
if (!value || typeof value !== "object") return {};
|
|
816
|
+
return value;
|
|
817
|
+
}
|
|
818
|
+
//#endregion
|
|
920
819
|
//#region src/utils/argv.ts
|
|
921
820
|
function ensurePathArgument(argv, optionIndex) {
|
|
922
821
|
const paramIdx = optionIndex + 1;
|
|
@@ -1069,10 +968,9 @@ async function waitForRetryKeypress(options = {}) {
|
|
|
1069
968
|
process.stdin.resume();
|
|
1070
969
|
return new Promise((resolve) => {
|
|
1071
970
|
let settled = false;
|
|
1072
|
-
const normalizedTimeoutMs = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e4;
|
|
1073
971
|
const timeout = setTimeout(() => {
|
|
1074
972
|
done("timeout");
|
|
1075
|
-
},
|
|
973
|
+
}, Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 3e4);
|
|
1076
974
|
const cleanup = () => {
|
|
1077
975
|
clearTimeout(timeout);
|
|
1078
976
|
process.stdin.off("keypress", onKeypress);
|
|
@@ -1258,16 +1156,8 @@ function isNonEmptyText(value) {
|
|
|
1258
1156
|
}
|
|
1259
1157
|
//#endregion
|
|
1260
1158
|
//#region src/cli/run.ts
|
|
1261
|
-
const MINIDEV_NAMESPACE = new Set(
|
|
1262
|
-
|
|
1263
|
-
"ali",
|
|
1264
|
-
"minidev"
|
|
1265
|
-
]);
|
|
1266
|
-
const ALIPAY_PLATFORM_ALIASES = new Set([
|
|
1267
|
-
"alipay",
|
|
1268
|
-
"ali",
|
|
1269
|
-
"minidev"
|
|
1270
|
-
]);
|
|
1159
|
+
const MINIDEV_NAMESPACE = new Set(MINIDEV_NAMESPACE_COMMAND_NAMES);
|
|
1160
|
+
const ALIPAY_PLATFORM_ALIASES = new Set(MINIDEV_NAMESPACE_COMMAND_NAMES);
|
|
1271
1161
|
const ARG_TRANSFORMS = [
|
|
1272
1162
|
createAlias({
|
|
1273
1163
|
find: "-p",
|
|
@@ -1281,40 +1171,108 @@ const ARG_TRANSFORMS = [
|
|
|
1281
1171
|
createPathCompat("-i")
|
|
1282
1172
|
];
|
|
1283
1173
|
/**
|
|
1174
|
+
* @description 基于 cac 注册顶层命令,用于统一识别入口。
|
|
1175
|
+
*/
|
|
1176
|
+
function createCli() {
|
|
1177
|
+
const cli = cac("weapp");
|
|
1178
|
+
cli.command("help [command]", "显示命令帮助").allowUnknownOptions();
|
|
1179
|
+
for (const command of WECHAT_CLI_COMMAND_NAMES) cli.command(command, "微信开发者工具官方命令透传").allowUnknownOptions();
|
|
1180
|
+
for (const command of MINIDEV_NAMESPACE_COMMAND_NAMES) cli.command(`${command} [...args]`, "支付宝 minidev 命令透传").allowUnknownOptions();
|
|
1181
|
+
cli.command(`${CONFIG_COMMAND_NAME} [...args]`, "配置 weapp-ide-cli").allowUnknownOptions();
|
|
1182
|
+
for (const command of [
|
|
1183
|
+
"screenshot",
|
|
1184
|
+
"navigate",
|
|
1185
|
+
"redirect",
|
|
1186
|
+
"back",
|
|
1187
|
+
"relaunch",
|
|
1188
|
+
"switch-tab",
|
|
1189
|
+
"page-stack",
|
|
1190
|
+
"current-page",
|
|
1191
|
+
"system-info",
|
|
1192
|
+
"page-data",
|
|
1193
|
+
"tap",
|
|
1194
|
+
"input",
|
|
1195
|
+
"scroll",
|
|
1196
|
+
"audit",
|
|
1197
|
+
"remote"
|
|
1198
|
+
]) cli.command(`${command} [...args]`, "automator 增强命令").allowUnknownOptions();
|
|
1199
|
+
return cli;
|
|
1200
|
+
}
|
|
1201
|
+
async function handleHelpCommand(args) {
|
|
1202
|
+
const targetCommand = args[0];
|
|
1203
|
+
if (!targetCommand) {
|
|
1204
|
+
createCli().outputHelp();
|
|
1205
|
+
return;
|
|
1206
|
+
}
|
|
1207
|
+
if (targetCommand === "screenshot") {
|
|
1208
|
+
printScreenshotHelp();
|
|
1209
|
+
return;
|
|
1210
|
+
}
|
|
1211
|
+
if (isAutomatorCommand(targetCommand)) {
|
|
1212
|
+
const help = getAutomatorCommandHelp(targetCommand);
|
|
1213
|
+
if (help) {
|
|
1214
|
+
console.log(help);
|
|
1215
|
+
return;
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
createCli().outputHelp();
|
|
1219
|
+
}
|
|
1220
|
+
async function handleMissingCliPath(source) {
|
|
1221
|
+
const message = source === "custom" ? i18nText("在当前自定义路径中未找到微信web开发者命令行工具,请重新指定路径。", "Cannot find Wechat Web DevTools CLI in custom path, please reconfigure it.") : i18nText(`未检测到微信web开发者命令行工具,请执行 ${colors.bold(colors.green("weapp-ide-cli config"))} 指定路径。`, `Wechat Web DevTools CLI not found, please run ${colors.bold(colors.green("weapp-ide-cli config"))} to configure it.`);
|
|
1222
|
+
logger_default.warn(message);
|
|
1223
|
+
await promptForCliPath();
|
|
1224
|
+
}
|
|
1225
|
+
/**
|
|
1226
|
+
* @description 判断 open 指令是否应转发到 minidev。
|
|
1227
|
+
*/
|
|
1228
|
+
function shouldDelegateOpenToMinidev(argv) {
|
|
1229
|
+
if (argv[0] !== "open") return false;
|
|
1230
|
+
const platform = readOptionValue(argv, "--platform");
|
|
1231
|
+
if (!platform) return false;
|
|
1232
|
+
return ALIPAY_PLATFORM_ALIASES.has(platform.toLowerCase());
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* @description 将 open 命令参数改写为 minidev ide 参数。
|
|
1236
|
+
*/
|
|
1237
|
+
function createMinidevOpenArgv(argv) {
|
|
1238
|
+
const nextArgv = [...argv];
|
|
1239
|
+
nextArgv[0] = "ide";
|
|
1240
|
+
return removeOption(nextArgv, "--platform");
|
|
1241
|
+
}
|
|
1242
|
+
/**
|
|
1284
1243
|
* @description CLI 入口解析与分发。
|
|
1285
1244
|
*/
|
|
1286
1245
|
async function parse(argv) {
|
|
1287
1246
|
validateLocaleOption(argv);
|
|
1288
1247
|
configureLocaleFromArgv(argv, await getConfiguredLocale());
|
|
1289
|
-
const
|
|
1290
|
-
|
|
1248
|
+
const cli = createCli();
|
|
1249
|
+
cli.parse([
|
|
1250
|
+
"node",
|
|
1251
|
+
"weapp",
|
|
1252
|
+
...argv
|
|
1253
|
+
], { run: false });
|
|
1254
|
+
const matchedCommand = cli.matchedCommandName;
|
|
1255
|
+
if (matchedCommand === "help") {
|
|
1256
|
+
await handleHelpCommand(cli.args);
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1259
|
+
if (matchedCommand && MINIDEV_NAMESPACE.has(matchedCommand)) {
|
|
1291
1260
|
await runMinidev(argv.slice(1));
|
|
1292
1261
|
return;
|
|
1293
1262
|
}
|
|
1294
|
-
if (
|
|
1295
|
-
await
|
|
1263
|
+
if (matchedCommand === "config") {
|
|
1264
|
+
await handleConfigCommand(argv.slice(1));
|
|
1296
1265
|
return;
|
|
1297
1266
|
}
|
|
1298
|
-
if (
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
printScreenshotHelp();
|
|
1302
|
-
return;
|
|
1303
|
-
}
|
|
1304
|
-
if (isAutomatorCommand(targetCommand)) {
|
|
1305
|
-
await runAutomatorCommand(targetCommand, ["--help"]);
|
|
1306
|
-
return;
|
|
1307
|
-
}
|
|
1267
|
+
if (matchedCommand && isAutomatorCommand(matchedCommand)) {
|
|
1268
|
+
await runAutomatorCommand(matchedCommand, argv.slice(1));
|
|
1269
|
+
return;
|
|
1308
1270
|
}
|
|
1309
1271
|
const formattedArgv = transformArgv(argv, ARG_TRANSFORMS);
|
|
1310
1272
|
if (shouldDelegateOpenToMinidev(formattedArgv)) {
|
|
1311
1273
|
await runMinidev(createMinidevOpenArgv(formattedArgv));
|
|
1312
1274
|
return;
|
|
1313
1275
|
}
|
|
1314
|
-
if (command === "config") {
|
|
1315
|
-
await handleConfigCommand(argv.slice(1));
|
|
1316
|
-
return;
|
|
1317
|
-
}
|
|
1318
1276
|
if (!isOperatingSystemSupported(operatingSystemName)) {
|
|
1319
1277
|
logger_default.warn(i18nText(`微信web开发者工具不支持当前平台:${operatingSystemName} !`, `Wechat Web DevTools CLI is not supported on current platform: ${operatingSystemName}!`));
|
|
1320
1278
|
return;
|
|
@@ -1322,29 +1280,10 @@ async function parse(argv) {
|
|
|
1322
1280
|
validateWechatCliCommandArgs(formattedArgv);
|
|
1323
1281
|
const { cliPath, source } = await resolveCliPath();
|
|
1324
1282
|
if (!cliPath) {
|
|
1325
|
-
|
|
1326
|
-
logger_default.warn(message);
|
|
1327
|
-
await promptForCliPath();
|
|
1283
|
+
await handleMissingCliPath(source);
|
|
1328
1284
|
return;
|
|
1329
1285
|
}
|
|
1330
1286
|
await runWechatCliWithRetry(cliPath, formattedArgv);
|
|
1331
1287
|
}
|
|
1332
|
-
/**
|
|
1333
|
-
* @description 判断 open 指令是否应分发到 minidev。
|
|
1334
|
-
*/
|
|
1335
|
-
function shouldDelegateOpenToMinidev(argv) {
|
|
1336
|
-
if (argv[0] !== "open") return false;
|
|
1337
|
-
const platform = readOptionValue(argv, "--platform");
|
|
1338
|
-
if (!platform) return false;
|
|
1339
|
-
return ALIPAY_PLATFORM_ALIASES.has(platform.toLowerCase());
|
|
1340
|
-
}
|
|
1341
|
-
/**
|
|
1342
|
-
* @description 将 open 命令参数转换为 minidev ide 参数。
|
|
1343
|
-
*/
|
|
1344
|
-
function createMinidevOpenArgv(argv) {
|
|
1345
|
-
const nextArgv = [...argv];
|
|
1346
|
-
nextArgv[0] = "ide";
|
|
1347
|
-
return removeOption(nextArgv, "--platform");
|
|
1348
|
-
}
|
|
1349
1288
|
//#endregion
|
|
1350
|
-
export {
|
|
1289
|
+
export { parseAutomatorArgs as A, isWeappIdeTopLevelCommand as C, runAutomatorCommand as D, isAutomatorCommand as E, removeOption as M, parseScreenshotArgs as O, WECHAT_CLI_COMMAND_NAMES as S, getAutomatorCommandHelp as T, handleConfigCommand as _, createWechatIdeLoginRequiredExitError as a, MINIDEV_NAMESPACE_COMMAND_NAMES as b, formatWechatIdeLoginRequiredError as c, runMinidev as d, execute as f, startForwardConsole as g, transformArgv as h, runWechatCliWithRetry as i, readOptionValue as j, printScreenshotHelp as k, isWechatIdeLoginRequiredError as l, createPathCompat as m, parse as n, extractExecutionErrorText as o, createAlias as p, validateWechatCliCommandArgs as r, formatRetryHotkeyPrompt as s, createCli as t, waitForRetryKeypress as u, promptForCliPath as v, AUTOMATOR_COMMAND_NAMES as w, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES as x, CONFIG_COMMAND_NAME as y };
|