weapp-ide-cli 5.1.2 → 5.1.4
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-g8B8r0xg.js → cli-BkQJ3Aww.js} +175 -353
- package/dist/cli.js +2 -2
- package/dist/{commands-BwCMEmX-.js → commands-CSbpftLN.js} +350 -97
- package/dist/index.d.ts +71 -43
- package/dist/index.js +3 -3
- package/package.json +4 -3
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import process from "node:process";
|
|
1
|
+
import { Launcher } from "@weapp-vite/miniprogram-automator";
|
|
2
|
+
import fs from "fs-extra";
|
|
4
3
|
import logger, { colors } from "@weapp-core/logger";
|
|
4
|
+
import os from "node:os";
|
|
5
|
+
import process from "node:process";
|
|
6
|
+
import path from "pathe";
|
|
5
7
|
import { Buffer as Buffer$1 } from "node:buffer";
|
|
6
|
-
import fs from "node:fs/promises";
|
|
8
|
+
import fs$1 from "node:fs/promises";
|
|
7
9
|
//#region \0rolldown/runtime.js
|
|
8
10
|
var __defProp = Object.defineProperty;
|
|
9
11
|
var __exportAll = (all, no_symbols) => {
|
|
@@ -16,7 +18,232 @@ var __exportAll = (all, no_symbols) => {
|
|
|
16
18
|
return target;
|
|
17
19
|
};
|
|
18
20
|
//#endregion
|
|
21
|
+
//#region src/logger.ts
|
|
22
|
+
var logger_default = logger;
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region src/runtime/platform.ts
|
|
25
|
+
/**
|
|
26
|
+
* @description 官方微信开发者工具只支持 Windows、macOS,Linux 只有社区版
|
|
27
|
+
* https://github.com/msojocs/wechat-web-devtools-linux
|
|
28
|
+
*/
|
|
29
|
+
const SupportedPlatformsMap = {
|
|
30
|
+
Windows_NT: "Windows_NT",
|
|
31
|
+
Darwin: "Darwin",
|
|
32
|
+
Linux: "Linux"
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @description 判断当前系统是否支持微信开发者工具
|
|
36
|
+
*/
|
|
37
|
+
function isOperatingSystemSupported(osName = os.type()) {
|
|
38
|
+
return osName === SupportedPlatformsMap.Windows_NT || osName === SupportedPlatformsMap.Darwin || osName === SupportedPlatformsMap.Linux;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* @description 当前系统名称
|
|
42
|
+
*/
|
|
43
|
+
const operatingSystemName = os.type();
|
|
44
|
+
function createLinuxCliResolver() {
|
|
45
|
+
let resolvedPath;
|
|
46
|
+
let attempted = false;
|
|
47
|
+
let pending = null;
|
|
48
|
+
return async () => {
|
|
49
|
+
if (attempted) return resolvedPath;
|
|
50
|
+
if (!pending) pending = (async () => {
|
|
51
|
+
try {
|
|
52
|
+
const envPath = await getFirstBinaryPath("wechat-devtools-cli");
|
|
53
|
+
if (envPath) resolvedPath = envPath;
|
|
54
|
+
} catch (error) {
|
|
55
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
56
|
+
logger_default.warn(`获取 Linux wechat-devtools-cli 路径失败:${reason}`);
|
|
57
|
+
} finally {
|
|
58
|
+
attempted = true;
|
|
59
|
+
}
|
|
60
|
+
return resolvedPath;
|
|
61
|
+
})();
|
|
62
|
+
return pending;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const linuxCliResolver = createLinuxCliResolver();
|
|
66
|
+
const WINDOWS_DEFAULT_CLI = "C:\\Program Files (x86)\\Tencent\\微信web开发者工具\\cli.bat";
|
|
67
|
+
const DARWIN_DEFAULT_CLI = "/Applications/wechatwebdevtools.app/Contents/MacOS/cli";
|
|
68
|
+
const cliPathResolvers = {
|
|
69
|
+
[SupportedPlatformsMap.Windows_NT]: async () => WINDOWS_DEFAULT_CLI,
|
|
70
|
+
[SupportedPlatformsMap.Darwin]: async () => DARWIN_DEFAULT_CLI,
|
|
71
|
+
[SupportedPlatformsMap.Linux]: linuxCliResolver
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* @description 获取默认 CLI 路径(按系统)
|
|
75
|
+
*/
|
|
76
|
+
async function getDefaultCliPath(targetOs = operatingSystemName) {
|
|
77
|
+
if (!isOperatingSystemSupported(targetOs)) return;
|
|
78
|
+
const resolver = cliPathResolvers[targetOs];
|
|
79
|
+
return await resolver();
|
|
80
|
+
}
|
|
81
|
+
async function getFirstBinaryPath(command) {
|
|
82
|
+
const pathDirs = (process.env.PATH || "").split(path.delimiter);
|
|
83
|
+
for (const dir of pathDirs) {
|
|
84
|
+
const fullPath = path.join(dir, command);
|
|
85
|
+
try {
|
|
86
|
+
await fs.access(fullPath, fs.constants.X_OK);
|
|
87
|
+
return fullPath;
|
|
88
|
+
} catch {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region src/utils/path.ts
|
|
95
|
+
/**
|
|
96
|
+
* @description 解析为绝对路径(基于当前工作目录)
|
|
97
|
+
*/
|
|
98
|
+
function resolvePath(filePath) {
|
|
99
|
+
if (path.isAbsolute(filePath)) return filePath;
|
|
100
|
+
return path.resolve(process.cwd(), filePath);
|
|
101
|
+
}
|
|
102
|
+
//#endregion
|
|
103
|
+
//#region src/config/paths.ts
|
|
104
|
+
const homedir = os.homedir();
|
|
105
|
+
/**
|
|
106
|
+
* @description 默认自定义配置目录
|
|
107
|
+
*/
|
|
108
|
+
const defaultCustomConfigDirPath = path.join(homedir, ".weapp-ide-cli");
|
|
109
|
+
/**
|
|
110
|
+
* @description 默认自定义配置文件路径
|
|
111
|
+
*/
|
|
112
|
+
const defaultCustomConfigFilePath = path.join(defaultCustomConfigDirPath, "config.json");
|
|
113
|
+
//#endregion
|
|
114
|
+
//#region src/config/custom.ts
|
|
115
|
+
const JSON_OPTIONS = {
|
|
116
|
+
encoding: "utf8",
|
|
117
|
+
spaces: 2
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* @description 写入自定义 CLI 路径配置
|
|
121
|
+
*/
|
|
122
|
+
async function createCustomConfig(params) {
|
|
123
|
+
const trimmedCliPath = params.cliPath.trim();
|
|
124
|
+
if (!trimmedCliPath) throw new Error("cliPath cannot be empty");
|
|
125
|
+
const normalizedCliPath = resolvePath(trimmedCliPath);
|
|
126
|
+
await writeCustomConfig({ cliPath: normalizedCliPath });
|
|
127
|
+
return normalizedCliPath;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @description 写入语言配置(zh / en)。
|
|
131
|
+
*/
|
|
132
|
+
async function createLocaleConfig(locale) {
|
|
133
|
+
await writeCustomConfig({ locale });
|
|
134
|
+
return locale;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* @description 删除指定配置项。
|
|
138
|
+
*/
|
|
139
|
+
async function removeCustomConfigKey(key) {
|
|
140
|
+
const currentConfig = await readCustomConfig();
|
|
141
|
+
if (!(key in currentConfig)) return;
|
|
142
|
+
const nextConfig = { ...currentConfig };
|
|
143
|
+
delete nextConfig[key];
|
|
144
|
+
await writeCustomConfig(nextConfig, { replace: true });
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* @description 覆盖写入配置内容(会替换原内容)。
|
|
148
|
+
*/
|
|
149
|
+
async function overwriteCustomConfig(config) {
|
|
150
|
+
const nextConfig = {};
|
|
151
|
+
if (typeof config.cliPath === "string" && config.cliPath.trim()) nextConfig.cliPath = resolvePath(config.cliPath.trim());
|
|
152
|
+
if (config.locale === "zh" || config.locale === "en") nextConfig.locale = config.locale;
|
|
153
|
+
await writeCustomConfig(nextConfig, { replace: true });
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* @description 读取原始自定义配置。
|
|
157
|
+
*/
|
|
158
|
+
async function readCustomConfig() {
|
|
159
|
+
if (!await fs.pathExists(defaultCustomConfigFilePath)) return {};
|
|
160
|
+
try {
|
|
161
|
+
const config = await fs.readJSON(defaultCustomConfigFilePath);
|
|
162
|
+
if (!config || typeof config !== "object") return {};
|
|
163
|
+
const candidate = config;
|
|
164
|
+
const next = {};
|
|
165
|
+
if (typeof candidate.cliPath === "string" && candidate.cliPath.trim()) next.cliPath = candidate.cliPath.trim();
|
|
166
|
+
if (candidate.locale === "zh" || candidate.locale === "en") next.locale = candidate.locale;
|
|
167
|
+
return next;
|
|
168
|
+
} catch {
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function writeCustomConfig(patch, options = {}) {
|
|
173
|
+
const nextConfig = {
|
|
174
|
+
...options.replace ? {} : await readCustomConfig(),
|
|
175
|
+
...patch
|
|
176
|
+
};
|
|
177
|
+
await fs.ensureDir(defaultCustomConfigDirPath);
|
|
178
|
+
await fs.writeJSON(defaultCustomConfigFilePath, nextConfig, JSON_OPTIONS);
|
|
179
|
+
}
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/config/resolver.ts
|
|
182
|
+
/**
|
|
183
|
+
* @description 读取并解析 CLI 配置(自定义优先)
|
|
184
|
+
*/
|
|
185
|
+
async function getConfig() {
|
|
186
|
+
if (await fs.pathExists(defaultCustomConfigFilePath)) try {
|
|
187
|
+
const config = await fs.readJSON(defaultCustomConfigFilePath);
|
|
188
|
+
const cliPath = typeof config.cliPath === "string" ? config.cliPath.trim() : "";
|
|
189
|
+
const locale = config.locale === "zh" || config.locale === "en" ? config.locale : void 0;
|
|
190
|
+
if (cliPath) {
|
|
191
|
+
logger_default.info(`全局配置文件路径:${colors.green(defaultCustomConfigFilePath)}`);
|
|
192
|
+
logger_default.info(`自定义 CLI 路径:${colors.green(cliPath)}`);
|
|
193
|
+
return {
|
|
194
|
+
cliPath,
|
|
195
|
+
locale,
|
|
196
|
+
source: "custom"
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
logger_default.warn("自定义配置文件缺少有效的 CLI 路径,将尝试使用默认路径。");
|
|
200
|
+
} catch (error) {
|
|
201
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
202
|
+
logger_default.warn(`解析自定义配置失败,将尝试使用默认路径。原因:${reason}`);
|
|
203
|
+
}
|
|
204
|
+
const fallbackPath = await getDefaultCliPath();
|
|
205
|
+
if (fallbackPath) return {
|
|
206
|
+
cliPath: fallbackPath,
|
|
207
|
+
locale: void 0,
|
|
208
|
+
source: "default"
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
cliPath: "",
|
|
212
|
+
locale: void 0,
|
|
213
|
+
source: "missing"
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* @description 获取用户配置的语言偏好。
|
|
218
|
+
*/
|
|
219
|
+
async function getConfiguredLocale() {
|
|
220
|
+
return (await readCustomConfig()).locale;
|
|
221
|
+
}
|
|
222
|
+
//#endregion
|
|
223
|
+
//#region src/cli/resolver.ts
|
|
224
|
+
/**
|
|
225
|
+
* @description 解析 CLI 路径并校验可用性
|
|
226
|
+
*/
|
|
227
|
+
async function resolveCliPath() {
|
|
228
|
+
const config = await getConfig();
|
|
229
|
+
if (!config.cliPath) return {
|
|
230
|
+
cliPath: null,
|
|
231
|
+
source: config.source
|
|
232
|
+
};
|
|
233
|
+
return {
|
|
234
|
+
cliPath: await fs.pathExists(config.cliPath) ? config.cliPath : null,
|
|
235
|
+
source: config.source
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
//#endregion
|
|
19
239
|
//#region src/cli/automator.ts
|
|
240
|
+
const ERROR_STACK_PREFIX_RE = /^at /;
|
|
241
|
+
const ERROR_PREFIX_RE = /^\[error\]\s*/i;
|
|
242
|
+
const ERROR_LABEL_PREFIX_RE = /^error\s*:\s*/i;
|
|
243
|
+
const ERROR_LINE_SPLIT_RE = /\r?\n/;
|
|
244
|
+
const LOGIN_REQUIRED_CN_RE = /需要重新登录/;
|
|
245
|
+
const LOGIN_REQUIRED_EN_RE = /need\s+re-?login|re-?login/i;
|
|
246
|
+
const LOGIN_REQUIRED_CODE_RE = /code\s*[:=]\s*(\d+)/i;
|
|
20
247
|
const DEVTOOLS_HTTP_PORT_ERROR = "Failed to launch wechat web devTools, please make sure http port is open";
|
|
21
248
|
const DEVTOOLS_INFRA_ERROR_PATTERNS = [
|
|
22
249
|
/listen EPERM/i,
|
|
@@ -31,57 +258,40 @@ const DEVTOOLS_LOGIN_REQUIRED_PATTERNS = [
|
|
|
31
258
|
/need\s+re-?login/i,
|
|
32
259
|
/re-?login/i
|
|
33
260
|
];
|
|
34
|
-
let localhostListenPatched = false;
|
|
35
|
-
function patchNetListenToLoopback() {
|
|
36
|
-
if (localhostListenPatched) return;
|
|
37
|
-
localhostListenPatched = true;
|
|
38
|
-
const rawListen = net.Server.prototype.listen;
|
|
39
|
-
net.Server.prototype.listen = function patchedListen(...args) {
|
|
40
|
-
const firstArg = args[0];
|
|
41
|
-
if (firstArg && typeof firstArg === "object" && !Array.isArray(firstArg)) {
|
|
42
|
-
if (!("host" in firstArg) || !firstArg.host) args[0] = {
|
|
43
|
-
...firstArg,
|
|
44
|
-
host: "127.0.0.1"
|
|
45
|
-
};
|
|
46
|
-
return rawListen.apply(this, args);
|
|
47
|
-
}
|
|
48
|
-
if ((typeof firstArg === "number" || typeof firstArg === "string") && typeof args[1] !== "string") args.splice(1, 0, "127.0.0.1");
|
|
49
|
-
return rawListen.apply(this, args);
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
261
|
/**
|
|
53
|
-
* @description
|
|
262
|
+
* @description 从错误对象中提取可读文本。
|
|
54
263
|
*/
|
|
55
264
|
function extractErrorText(error) {
|
|
56
265
|
if (!error || typeof error !== "object") return "";
|
|
57
|
-
const parts = [];
|
|
58
266
|
const candidate = error;
|
|
59
|
-
|
|
267
|
+
return [
|
|
60
268
|
candidate.message,
|
|
61
269
|
candidate.shortMessage,
|
|
62
270
|
candidate.stderr,
|
|
63
271
|
candidate.stdout
|
|
64
|
-
])
|
|
65
|
-
return parts.join("\n");
|
|
272
|
+
].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n");
|
|
66
273
|
}
|
|
274
|
+
/**
|
|
275
|
+
* @description 提取登录失效时最适合展示给用户的一行信息。
|
|
276
|
+
*/
|
|
67
277
|
function extractLoginRequiredMessage(text) {
|
|
68
278
|
if (!text) return "";
|
|
69
|
-
if (
|
|
70
|
-
const englishMatch = text.match(
|
|
279
|
+
if (LOGIN_REQUIRED_CN_RE.test(text)) return "需要重新登录";
|
|
280
|
+
const englishMatch = text.match(LOGIN_REQUIRED_EN_RE);
|
|
71
281
|
if (englishMatch?.[0]) return englishMatch[0].toLowerCase();
|
|
72
|
-
const firstLine = text.split(
|
|
282
|
+
const firstLine = text.split(ERROR_LINE_SPLIT_RE).map((line) => line.trim()).find((line) => Boolean(line) && !ERROR_STACK_PREFIX_RE.test(line));
|
|
73
283
|
if (!firstLine) return "";
|
|
74
|
-
return firstLine.replace(
|
|
284
|
+
return firstLine.replace(ERROR_PREFIX_RE, "").replace(ERROR_LABEL_PREFIX_RE, "").slice(0, 120);
|
|
75
285
|
}
|
|
76
286
|
/**
|
|
77
|
-
* @description
|
|
287
|
+
* @description 判断错误是否属于开发者工具服务端口不可用。
|
|
78
288
|
*/
|
|
79
289
|
function isDevtoolsHttpPortError(error) {
|
|
80
290
|
const message = error instanceof Error ? error.message : String(error);
|
|
81
291
|
return message.includes(DEVTOOLS_HTTP_PORT_ERROR) || DEVTOOLS_INFRA_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
82
292
|
}
|
|
83
293
|
/**
|
|
84
|
-
* @description
|
|
294
|
+
* @description 判断错误是否属于开发者工具登录失效。
|
|
85
295
|
*/
|
|
86
296
|
function isAutomatorLoginError(error) {
|
|
87
297
|
const text = extractErrorText(error);
|
|
@@ -89,11 +299,11 @@ function isAutomatorLoginError(error) {
|
|
|
89
299
|
return DEVTOOLS_LOGIN_REQUIRED_PATTERNS.some((pattern) => pattern.test(text));
|
|
90
300
|
}
|
|
91
301
|
/**
|
|
92
|
-
* @description
|
|
302
|
+
* @description 格式化开发者工具登录失效错误,便于终端展示。
|
|
93
303
|
*/
|
|
94
304
|
function formatAutomatorLoginError(error) {
|
|
95
305
|
const text = extractErrorText(error);
|
|
96
|
-
const code = text.match(
|
|
306
|
+
const code = text.match(LOGIN_REQUIRED_CODE_RE)?.[1];
|
|
97
307
|
const message = extractLoginRequiredMessage(text);
|
|
98
308
|
const lines = ["微信开发者工具返回登录错误:"];
|
|
99
309
|
if (code) lines.push(`- code: ${code}`);
|
|
@@ -102,12 +312,13 @@ function formatAutomatorLoginError(error) {
|
|
|
102
312
|
return lines.join("\n");
|
|
103
313
|
}
|
|
104
314
|
/**
|
|
105
|
-
* @description
|
|
315
|
+
* @description 基于当前配置解析 CLI 路径,并通过现代化 automator 入口启动会话。
|
|
106
316
|
*/
|
|
107
317
|
async function launchAutomator(options) {
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
return
|
|
318
|
+
const { cliPath, projectPath, timeout = 3e4 } = options;
|
|
319
|
+
const resolvedCliPath = cliPath ?? (await resolveCliPath()).cliPath ?? void 0;
|
|
320
|
+
return await new Launcher().launch({
|
|
321
|
+
cliPath: resolvedCliPath,
|
|
111
322
|
projectPath,
|
|
112
323
|
timeout
|
|
113
324
|
});
|
|
@@ -178,10 +389,20 @@ function readLangOption(argv) {
|
|
|
178
389
|
}
|
|
179
390
|
}
|
|
180
391
|
//#endregion
|
|
181
|
-
//#region src/logger.ts
|
|
182
|
-
var logger_default = logger;
|
|
183
|
-
//#endregion
|
|
184
392
|
//#region src/cli/automator-session.ts
|
|
393
|
+
function normalizeMiniProgramConnectionError(error) {
|
|
394
|
+
if (isAutomatorLoginError(error)) {
|
|
395
|
+
logger_default.error(i18nText("检测到微信开发者工具登录状态失效,请先登录后重试。", "Wechat DevTools login has expired. Please login and retry."));
|
|
396
|
+
logger_default.warn(formatAutomatorLoginError(error));
|
|
397
|
+
return /* @__PURE__ */ new Error("DEVTOOLS_LOGIN_REQUIRED");
|
|
398
|
+
}
|
|
399
|
+
if (isDevtoolsHttpPortError(error)) {
|
|
400
|
+
logger_default.error(i18nText("无法连接到微信开发者工具,请确保已开启 HTTP 服务端口。", "Cannot connect to Wechat DevTools. Please ensure HTTP service port is enabled."));
|
|
401
|
+
logger_default.warn(i18nText("请在微信开发者工具中:设置 -> 安全设置 -> 开启服务端口", "Please enable service port in Wechat DevTools: Settings -> Security -> Service Port"));
|
|
402
|
+
return /* @__PURE__ */ new Error("DEVTOOLS_HTTP_PORT_ERROR");
|
|
403
|
+
}
|
|
404
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
405
|
+
}
|
|
185
406
|
/**
|
|
186
407
|
* @description 建立 automator 会话,并统一处理常见连接错误提示。
|
|
187
408
|
*/
|
|
@@ -193,7 +414,7 @@ async function connectMiniProgram(options) {
|
|
|
193
414
|
}
|
|
194
415
|
}
|
|
195
416
|
/**
|
|
196
|
-
* @description 统一管理 automator
|
|
417
|
+
* @description 统一管理 automator 会话生命周期。
|
|
197
418
|
*/
|
|
198
419
|
async function withMiniProgram(options, runner) {
|
|
199
420
|
let miniProgram = null;
|
|
@@ -206,19 +427,6 @@ async function withMiniProgram(options, runner) {
|
|
|
206
427
|
if (miniProgram) await miniProgram.close();
|
|
207
428
|
}
|
|
208
429
|
}
|
|
209
|
-
function normalizeMiniProgramConnectionError(error) {
|
|
210
|
-
if (isAutomatorLoginError(error)) {
|
|
211
|
-
logger_default.error(i18nText("检测到微信开发者工具登录状态失效,请先登录后重试。", "Wechat DevTools login has expired. Please login and retry."));
|
|
212
|
-
logger_default.warn(formatAutomatorLoginError(error));
|
|
213
|
-
return /* @__PURE__ */ new Error("DEVTOOLS_LOGIN_REQUIRED");
|
|
214
|
-
}
|
|
215
|
-
if (isDevtoolsHttpPortError(error)) {
|
|
216
|
-
logger_default.error(i18nText("无法连接到微信开发者工具,请确保已开启 HTTP 服务端口。", "Cannot connect to Wechat DevTools. Please ensure HTTP service port is enabled."));
|
|
217
|
-
logger_default.warn(i18nText("请在微信开发者工具中:设置 -> 安全设置 -> 开启服务端口", "Please enable service port in Wechat DevTools: Settings -> Security -> Service Port"));
|
|
218
|
-
return /* @__PURE__ */ new Error("DEVTOOLS_HTTP_PORT_ERROR");
|
|
219
|
-
}
|
|
220
|
-
return error instanceof Error ? error : new Error(String(error));
|
|
221
|
-
}
|
|
222
430
|
//#endregion
|
|
223
431
|
//#region src/cli/commands.ts
|
|
224
432
|
var commands_exports = /* @__PURE__ */ __exportAll({
|
|
@@ -238,50 +446,106 @@ var commands_exports = /* @__PURE__ */ __exportAll({
|
|
|
238
446
|
takeScreenshot: () => takeScreenshot,
|
|
239
447
|
tap: () => tap
|
|
240
448
|
});
|
|
449
|
+
async function runRouteCommand(options, startMessage, successMessage, action) {
|
|
450
|
+
await withMiniProgram(options, async (miniProgram) => {
|
|
451
|
+
logger_default.info(startMessage);
|
|
452
|
+
await action(miniProgram);
|
|
453
|
+
logger_default.success(successMessage);
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
function toPageSnapshot(page) {
|
|
457
|
+
return {
|
|
458
|
+
path: page.path ?? "",
|
|
459
|
+
query: page.query
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
function printStructuredResult(result, json, title) {
|
|
463
|
+
if (json) {
|
|
464
|
+
console.log(JSON.stringify(result, null, 2));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
logger_default.info(title);
|
|
468
|
+
console.log(JSON.stringify(result, null, 2));
|
|
469
|
+
}
|
|
470
|
+
async function requireElement(page, selector) {
|
|
471
|
+
const element = await page.$(selector);
|
|
472
|
+
if (!element) throw new Error(i18nText(`未找到元素: ${selector}`, `Element not found: ${selector}`));
|
|
473
|
+
return element;
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* @description 执行保留栈页面跳转。
|
|
477
|
+
*/
|
|
241
478
|
async function navigateTo(options) {
|
|
242
479
|
await runRouteCommand(options, i18nText(`正在跳转到 ${colors.cyan(options.url)}...`, `Navigating to ${colors.cyan(options.url)}...`), i18nText(`已跳转到 ${colors.cyan(options.url)}`, `Navigated to ${colors.cyan(options.url)}`), (miniProgram) => miniProgram.navigateTo(options.url));
|
|
243
480
|
}
|
|
481
|
+
/**
|
|
482
|
+
* @description 执行关闭当前页的重定向。
|
|
483
|
+
*/
|
|
244
484
|
async function redirectTo(options) {
|
|
245
485
|
await runRouteCommand(options, i18nText(`正在重定向到 ${colors.cyan(options.url)}...`, `Redirecting to ${colors.cyan(options.url)}...`), i18nText(`已重定向到 ${colors.cyan(options.url)}`, `Redirected to ${colors.cyan(options.url)}`), (miniProgram) => miniProgram.redirectTo(options.url));
|
|
246
486
|
}
|
|
487
|
+
/**
|
|
488
|
+
* @description 返回上一页。
|
|
489
|
+
*/
|
|
247
490
|
async function navigateBack(options) {
|
|
248
491
|
await runRouteCommand(options, i18nText("正在返回上一页...", "Navigating back..."), i18nText("已返回上一页", "Navigated back"), (miniProgram) => miniProgram.navigateBack());
|
|
249
492
|
}
|
|
493
|
+
/**
|
|
494
|
+
* @description 重启到指定页面。
|
|
495
|
+
*/
|
|
250
496
|
async function reLaunch(options) {
|
|
251
497
|
await runRouteCommand(options, i18nText(`正在重启到 ${colors.cyan(options.url)}...`, `Relaunching to ${colors.cyan(options.url)}...`), i18nText(`已重启到 ${colors.cyan(options.url)}`, `Relaunched to ${colors.cyan(options.url)}`), (miniProgram) => miniProgram.reLaunch(options.url));
|
|
252
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* @description 切换到 tabBar 页面。
|
|
501
|
+
*/
|
|
253
502
|
async function switchTab(options) {
|
|
254
503
|
await runRouteCommand(options, i18nText(`正在切换 tab 到 ${colors.cyan(options.url)}...`, `Switching tab to ${colors.cyan(options.url)}...`), i18nText(`已切换 tab 到 ${colors.cyan(options.url)}`, `Switched tab to ${colors.cyan(options.url)}`), (miniProgram) => miniProgram.switchTab(options.url));
|
|
255
504
|
}
|
|
505
|
+
/**
|
|
506
|
+
* @description 获取页面栈。
|
|
507
|
+
*/
|
|
256
508
|
async function pageStack(options) {
|
|
257
|
-
return withMiniProgram(options, async (miniProgram) => {
|
|
509
|
+
return await withMiniProgram(options, async (miniProgram) => {
|
|
258
510
|
const result = (await miniProgram.pageStack()).map(toPageSnapshot);
|
|
259
511
|
printStructuredResult(result, options.json, i18nText("页面栈:", "Page stack:"));
|
|
260
512
|
return result;
|
|
261
513
|
});
|
|
262
514
|
}
|
|
515
|
+
/**
|
|
516
|
+
* @description 获取当前页面信息。
|
|
517
|
+
*/
|
|
263
518
|
async function currentPage(options) {
|
|
264
|
-
return withMiniProgram(options, async (miniProgram) => {
|
|
519
|
+
return await withMiniProgram(options, async (miniProgram) => {
|
|
265
520
|
const result = toPageSnapshot(await miniProgram.currentPage());
|
|
266
521
|
if (options.json) console.log(JSON.stringify(result, null, 2));
|
|
267
522
|
else logger_default.info(i18nText(`当前页面: ${result.path}${result.query ? ` ${JSON.stringify(result.query)}` : ""}`, `Current page: ${result.path}${result.query ? ` ${JSON.stringify(result.query)}` : ""}`));
|
|
268
523
|
return result;
|
|
269
524
|
});
|
|
270
525
|
}
|
|
526
|
+
/**
|
|
527
|
+
* @description 获取系统信息。
|
|
528
|
+
*/
|
|
271
529
|
async function systemInfo(options) {
|
|
272
|
-
return withMiniProgram(options, async (miniProgram) => {
|
|
273
|
-
const
|
|
274
|
-
printStructuredResult(
|
|
275
|
-
return
|
|
530
|
+
return await withMiniProgram(options, async (miniProgram) => {
|
|
531
|
+
const result = await miniProgram.systemInfo();
|
|
532
|
+
printStructuredResult(result, options.json, i18nText("系统信息:", "System info:"));
|
|
533
|
+
return result;
|
|
276
534
|
});
|
|
277
535
|
}
|
|
536
|
+
/**
|
|
537
|
+
* @description 获取当前页面数据。
|
|
538
|
+
*/
|
|
278
539
|
async function pageData(options) {
|
|
279
|
-
return withMiniProgram(options, async (miniProgram) => {
|
|
280
|
-
const
|
|
281
|
-
printStructuredResult(
|
|
282
|
-
return
|
|
540
|
+
return await withMiniProgram(options, async (miniProgram) => {
|
|
541
|
+
const result = await (await miniProgram.currentPage()).data(options.path);
|
|
542
|
+
printStructuredResult(result, options.json, i18nText("页面数据:", "Page data:"));
|
|
543
|
+
return result;
|
|
283
544
|
});
|
|
284
545
|
}
|
|
546
|
+
/**
|
|
547
|
+
* @description 点击页面元素。
|
|
548
|
+
*/
|
|
285
549
|
async function tap(options) {
|
|
286
550
|
await withMiniProgram(options, async (miniProgram) => {
|
|
287
551
|
logger_default.info(i18nText(`正在点击元素 ${colors.cyan(options.selector)}...`, `Tapping element ${colors.cyan(options.selector)}...`));
|
|
@@ -289,6 +553,9 @@ async function tap(options) {
|
|
|
289
553
|
logger_default.success(i18nText(`已点击元素 ${colors.cyan(options.selector)}`, `Tapped element ${colors.cyan(options.selector)}`));
|
|
290
554
|
});
|
|
291
555
|
}
|
|
556
|
+
/**
|
|
557
|
+
* @description 向页面元素输入文本。
|
|
558
|
+
*/
|
|
292
559
|
async function input(options) {
|
|
293
560
|
await withMiniProgram(options, async (miniProgram) => {
|
|
294
561
|
logger_default.info(i18nText(`正在向 ${colors.cyan(options.selector)} 输入 "${colors.cyan(options.value)}"...`, `Inputting "${colors.cyan(options.value)}" into ${colors.cyan(options.selector)}...`));
|
|
@@ -298,6 +565,9 @@ async function input(options) {
|
|
|
298
565
|
logger_default.success(i18nText(`已向 ${colors.cyan(options.selector)} 输入 "${colors.cyan(options.value)}"`, `Inputted "${colors.cyan(options.value)}" into ${colors.cyan(options.selector)}`));
|
|
299
566
|
});
|
|
300
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* @description 滚动页面到指定位置。
|
|
570
|
+
*/
|
|
301
571
|
async function scrollTo(options) {
|
|
302
572
|
await withMiniProgram(options, async (miniProgram) => {
|
|
303
573
|
logger_default.info(i18nText(`正在滚动到位置 ${colors.cyan(String(options.scrollTop))}...`, `Scrolling to position ${colors.cyan(String(options.scrollTop))}...`));
|
|
@@ -305,12 +575,15 @@ async function scrollTo(options) {
|
|
|
305
575
|
logger_default.success(i18nText(`已滚动到位置 ${colors.cyan(String(options.scrollTop))}`, `Scrolled to position ${colors.cyan(String(options.scrollTop))}`));
|
|
306
576
|
});
|
|
307
577
|
}
|
|
578
|
+
/**
|
|
579
|
+
* @description 执行体验评分审计。
|
|
580
|
+
*/
|
|
308
581
|
async function audit(options) {
|
|
309
|
-
return withMiniProgram(options, async (miniProgram) => {
|
|
582
|
+
return await withMiniProgram(options, async (miniProgram) => {
|
|
310
583
|
logger_default.info(i18nText("正在执行体验审计...", "Running experience audit..."));
|
|
311
584
|
const result = await miniProgram.stopAudits();
|
|
312
585
|
if (options.outputPath) {
|
|
313
|
-
await fs.writeFile(options.outputPath, JSON.stringify(result, null, 2));
|
|
586
|
+
await fs$1.writeFile(options.outputPath, JSON.stringify(result, null, 2));
|
|
314
587
|
logger_default.success(i18nText(`审计报告已保存到 ${colors.cyan(options.outputPath)}`, `Audit report saved to ${colors.cyan(options.outputPath)}`));
|
|
315
588
|
return result;
|
|
316
589
|
}
|
|
@@ -318,8 +591,11 @@ async function audit(options) {
|
|
|
318
591
|
return result;
|
|
319
592
|
});
|
|
320
593
|
}
|
|
594
|
+
/**
|
|
595
|
+
* @description 获取当前小程序截图。
|
|
596
|
+
*/
|
|
321
597
|
async function takeScreenshot(options) {
|
|
322
|
-
return withMiniProgram(options, async (miniProgram) => {
|
|
598
|
+
return await withMiniProgram(options, async (miniProgram) => {
|
|
323
599
|
logger_default.info(i18nText(`正在连接 DevTools:${colors.cyan(options.projectPath)}...`, `Connecting to DevTools at ${colors.cyan(options.projectPath)}...`));
|
|
324
600
|
if (options.page) {
|
|
325
601
|
logger_default.info(i18nText(`正在跳转页面 ${colors.cyan(options.page)}...`, `Navigating to page ${colors.cyan(options.page)}...`));
|
|
@@ -330,13 +606,16 @@ async function takeScreenshot(options) {
|
|
|
330
606
|
const base64 = typeof screenshot === "string" ? screenshot : Buffer$1.from(screenshot).toString("base64");
|
|
331
607
|
if (!base64) throw new Error(i18nText("截图失败", "Failed to capture screenshot"));
|
|
332
608
|
if (options.outputPath) {
|
|
333
|
-
await fs.writeFile(options.outputPath, Buffer$1.from(base64, "base64"));
|
|
609
|
+
await fs$1.writeFile(options.outputPath, Buffer$1.from(base64, "base64"));
|
|
334
610
|
logger_default.success(i18nText(`截图已保存到 ${colors.cyan(options.outputPath)}`, `Screenshot saved to ${colors.cyan(options.outputPath)}`));
|
|
335
611
|
return { path: options.outputPath };
|
|
336
612
|
}
|
|
337
613
|
return { base64 };
|
|
338
614
|
});
|
|
339
615
|
}
|
|
616
|
+
/**
|
|
617
|
+
* @description 开关远程调试。
|
|
618
|
+
*/
|
|
340
619
|
async function remote(options) {
|
|
341
620
|
const enable = options.enable ?? true;
|
|
342
621
|
await withMiniProgram(options, async (miniProgram) => {
|
|
@@ -345,31 +624,5 @@ async function remote(options) {
|
|
|
345
624
|
logger_default.success(enable ? i18nText("远程调试已开启", "Remote debugging enabled") : i18nText("远程调试已关闭", "Remote debugging disabled"));
|
|
346
625
|
});
|
|
347
626
|
}
|
|
348
|
-
async function runRouteCommand(options, startMessage, successMessage, run) {
|
|
349
|
-
await withMiniProgram(options, async (miniProgram) => {
|
|
350
|
-
logger_default.info(startMessage);
|
|
351
|
-
await run(miniProgram);
|
|
352
|
-
logger_default.success(successMessage);
|
|
353
|
-
});
|
|
354
|
-
}
|
|
355
|
-
function toPageSnapshot(page) {
|
|
356
|
-
return {
|
|
357
|
-
path: page.path ?? "",
|
|
358
|
-
query: page.query
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
function printStructuredResult(result, json, title) {
|
|
362
|
-
if (json) {
|
|
363
|
-
console.log(JSON.stringify(result, null, 2));
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
logger_default.info(title);
|
|
367
|
-
console.log(JSON.stringify(result, null, 2));
|
|
368
|
-
}
|
|
369
|
-
async function requireElement(page, selector) {
|
|
370
|
-
const element = await page.$(selector);
|
|
371
|
-
if (!element) throw new Error(i18nText(`未找到元素: ${selector}`, `Element not found: ${selector}`));
|
|
372
|
-
return element;
|
|
373
|
-
}
|
|
374
627
|
//#endregion
|
|
375
|
-
export {
|
|
628
|
+
export { createLocaleConfig as A, operatingSystemName as B, isAutomatorLoginError as C, getConfig as D, resolveCliPath as E, defaultCustomConfigFilePath as F, logger_default as H, resolvePath as I, SupportedPlatformsMap as L, readCustomConfig as M, removeCustomConfigKey as N, getConfiguredLocale as O, defaultCustomConfigDirPath as P, getDefaultCliPath as R, formatAutomatorLoginError as S, launchAutomator as T, colors as V, connectMiniProgram as _, navigateBack as a, i18nText as b, pageStack as c, remote as d, scrollTo as f, tap as g, takeScreenshot as h, input as i, overwriteCustomConfig as j, createCustomConfig as k, reLaunch as l, systemInfo as m, commands_exports as n, navigateTo as o, switchTab as p, currentPage as r, pageData as s, audit as t, redirectTo as u, withMiniProgram as v, isDevtoolsHttpPortError as w, validateLocaleOption as x, configureLocaleFromArgv as y, isOperatingSystemSupported as z };
|