weapp-ide-cli 5.0.4 → 5.1.1

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.d.ts CHANGED
@@ -1,2 +1 @@
1
-
2
- export { }
1
+ export { };
package/dist/cli.js CHANGED
@@ -1,20 +1,18 @@
1
- import {
2
- logger_default,
3
- parse
4
- } from "./chunk-QTQD5BFV.js";
5
-
6
- // src/cli.ts
7
- import process from "process";
8
- var argv = process.argv.slice(2);
9
- parse(argv).catch((err) => {
10
- logger_default.error(err);
11
- if (typeof err?.exitCode === "number") {
12
- process.exitCode = err.exitCode;
13
- return;
14
- }
15
- if (typeof err?.code === "number") {
16
- process.exitCode = err.code;
17
- return;
18
- }
19
- process.exitCode = 1;
1
+ import { y as logger_default } from "./commands-9F3ycbXU.js";
2
+ import { t as parse } from "./cli-Dv5EAvYh.js";
3
+ import process from "node:process";
4
+ //#region src/cli.ts
5
+ parse(process.argv.slice(2)).catch((err) => {
6
+ logger_default.error(err);
7
+ if (typeof err?.exitCode === "number") {
8
+ process.exitCode = err.exitCode;
9
+ return;
10
+ }
11
+ if (typeof err?.code === "number") {
12
+ process.exitCode = err.code;
13
+ return;
14
+ }
15
+ process.exitCode = 1;
20
16
  });
17
+ //#endregion
18
+ export {};
@@ -0,0 +1,342 @@
1
+ import automator from "miniprogram-automator";
2
+ import process from "node:process";
3
+ import logger, { colors } from "@weapp-core/logger";
4
+ import { Buffer as Buffer$1 } from "node:buffer";
5
+ import fs from "node:fs/promises";
6
+ //#region \0rolldown/runtime.js
7
+ var __defProp = Object.defineProperty;
8
+ var __exportAll = (all, no_symbols) => {
9
+ let target = {};
10
+ for (var name in all) __defProp(target, name, {
11
+ get: all[name],
12
+ enumerable: true
13
+ });
14
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
15
+ return target;
16
+ };
17
+ //#endregion
18
+ //#region src/cli/automator.ts
19
+ const DEVTOOLS_HTTP_PORT_ERROR = "Failed to launch wechat web devTools, please make sure http port is open";
20
+ const DEVTOOLS_INFRA_ERROR_PATTERNS = [
21
+ /listen EPERM/i,
22
+ /operation not permitted 0\.0\.0\.0/i,
23
+ /EACCES/i,
24
+ /ECONNREFUSED/i,
25
+ /connect ECONNREFUSED/i
26
+ ];
27
+ const DEVTOOLS_LOGIN_REQUIRED_PATTERNS = [
28
+ /code\s*[:=]\s*10/i,
29
+ /需要重新登录/,
30
+ /need\s+re-?login/i,
31
+ /re-?login/i
32
+ ];
33
+ /**
34
+ * @description Extract error text from various error types
35
+ */
36
+ function extractErrorText(error) {
37
+ if (!error || typeof error !== "object") return "";
38
+ const parts = [];
39
+ const candidate = error;
40
+ for (const field of [
41
+ candidate.message,
42
+ candidate.shortMessage,
43
+ candidate.stderr,
44
+ candidate.stdout
45
+ ]) if (typeof field === "string" && field.trim()) parts.push(field);
46
+ return parts.join("\n");
47
+ }
48
+ function extractLoginRequiredMessage(text) {
49
+ if (!text) return "";
50
+ if (/需要重新登录/.test(text)) return "需要重新登录";
51
+ const englishMatch = text.match(/need\s+re-?login|re-?login/i);
52
+ if (englishMatch?.[0]) return englishMatch[0].toLowerCase();
53
+ const firstLine = text.split(/\r?\n/).map((line) => line.trim()).find((line) => Boolean(line) && !line.startsWith("at "));
54
+ if (!firstLine) return "";
55
+ return firstLine.replace(/^\[error\]\s*/i, "").replace(/^error\s*:\s*/i, "").slice(0, 120);
56
+ }
57
+ /**
58
+ * @description Check if error is a DevTools HTTP port error
59
+ */
60
+ function isDevtoolsHttpPortError(error) {
61
+ const message = error instanceof Error ? error.message : String(error);
62
+ return message.includes(DEVTOOLS_HTTP_PORT_ERROR) || DEVTOOLS_INFRA_ERROR_PATTERNS.some((pattern) => pattern.test(message));
63
+ }
64
+ /**
65
+ * @description Check if error is a login required error
66
+ */
67
+ function isAutomatorLoginError(error) {
68
+ const text = extractErrorText(error);
69
+ if (!text) return false;
70
+ return DEVTOOLS_LOGIN_REQUIRED_PATTERNS.some((pattern) => pattern.test(text));
71
+ }
72
+ /**
73
+ * @description Format login error for display
74
+ */
75
+ function formatAutomatorLoginError(error) {
76
+ const text = extractErrorText(error);
77
+ const code = text.match(/code\s*[:=]\s*(\d+)/i)?.[1];
78
+ const message = extractLoginRequiredMessage(text);
79
+ const lines = ["微信开发者工具返回登录错误:"];
80
+ if (code) lines.push(`- code: ${code}`);
81
+ if (message) lines.push(`- message: ${message}`);
82
+ if (!code && !message) lines.push("- message: 需要重新登录");
83
+ return lines.join("\n");
84
+ }
85
+ /**
86
+ * @description Launch automator with default options
87
+ */
88
+ async function launchAutomator(options) {
89
+ const { projectPath, timeout = 3e4 } = options;
90
+ return automator.launch({
91
+ projectPath,
92
+ timeout
93
+ });
94
+ }
95
+ //#endregion
96
+ //#region src/i18n.ts
97
+ let currentLocale = "zh";
98
+ /**
99
+ * @description 设置当前语言。
100
+ */
101
+ function setLocale(locale) {
102
+ currentLocale = normalizeLocale(locale);
103
+ }
104
+ /**
105
+ * @description 从 argv 和环境变量中解析语言并设置。
106
+ */
107
+ function configureLocaleFromArgv(argv, fallbackLocale) {
108
+ const localeFromArgv = readLangOption(argv);
109
+ if (localeFromArgv) {
110
+ setLocale(localeFromArgv);
111
+ return currentLocale;
112
+ }
113
+ if (fallbackLocale) {
114
+ setLocale(fallbackLocale);
115
+ return currentLocale;
116
+ }
117
+ const localeFromEnv = process.env.WEAPP_IDE_CLI_LANG || process.env.LANG;
118
+ if (localeFromEnv) {
119
+ setLocale(localeFromEnv);
120
+ return currentLocale;
121
+ }
122
+ setLocale("zh");
123
+ return currentLocale;
124
+ }
125
+ /**
126
+ * @description 根据当前语言选择文案。
127
+ */
128
+ function i18nText(zh, en) {
129
+ return currentLocale === "en" ? en : zh;
130
+ }
131
+ /**
132
+ * @description 校验 --lang 参数是否合法。
133
+ */
134
+ function validateLocaleOption(argv) {
135
+ const localeFromArgv = readLangOption(argv);
136
+ if (!localeFromArgv) return;
137
+ if (!isLocaleTokenSupported(localeFromArgv)) throw new Error(`不支持的语言: ${localeFromArgv},仅支持 zh 或 en`);
138
+ }
139
+ function normalizeLocale(raw) {
140
+ if (!raw) return "zh";
141
+ const normalized = raw.trim().toLowerCase();
142
+ if (normalized === "en" || normalized.startsWith("en_") || normalized.startsWith("en-")) return "en";
143
+ return "zh";
144
+ }
145
+ function isLocaleTokenSupported(raw) {
146
+ const normalized = raw.trim().toLowerCase();
147
+ return normalized === "zh" || normalized === "en" || normalized.startsWith("zh_") || normalized.startsWith("zh-") || normalized.startsWith("en_") || normalized.startsWith("en-");
148
+ }
149
+ function readLangOption(argv) {
150
+ for (let index = 0; index < argv.length; index += 1) {
151
+ const token = argv[index];
152
+ if (!token) continue;
153
+ if (token === "--lang") {
154
+ const value = argv[index + 1];
155
+ return typeof value === "string" ? value : void 0;
156
+ }
157
+ if (token.startsWith("--lang=")) return token.slice(7);
158
+ }
159
+ }
160
+ //#endregion
161
+ //#region src/logger.ts
162
+ var logger_default = logger;
163
+ //#endregion
164
+ //#region src/cli/automator-session.ts
165
+ /**
166
+ * @description 统一管理 automator 会话生命周期与常见连接错误提示。
167
+ */
168
+ async function withMiniProgram(options, runner) {
169
+ let miniProgram = null;
170
+ try {
171
+ miniProgram = await launchAutomator(options);
172
+ return await runner(miniProgram);
173
+ } catch (error) {
174
+ if (isAutomatorLoginError(error)) {
175
+ logger_default.error(i18nText("检测到微信开发者工具登录状态失效,请先登录后重试。", "Wechat DevTools login has expired. Please login and retry."));
176
+ logger_default.warn(formatAutomatorLoginError(error));
177
+ throw new Error("DEVTOOLS_LOGIN_REQUIRED");
178
+ }
179
+ if (isDevtoolsHttpPortError(error)) {
180
+ logger_default.error(i18nText("无法连接到微信开发者工具,请确保已开启 HTTP 服务端口。", "Cannot connect to Wechat DevTools. Please ensure HTTP service port is enabled."));
181
+ logger_default.warn(i18nText("请在微信开发者工具中:设置 -> 安全设置 -> 开启服务端口", "Please enable service port in Wechat DevTools: Settings -> Security -> Service Port"));
182
+ throw new Error("DEVTOOLS_HTTP_PORT_ERROR");
183
+ }
184
+ throw error;
185
+ } finally {
186
+ if (miniProgram) await miniProgram.close();
187
+ }
188
+ }
189
+ //#endregion
190
+ //#region src/cli/commands.ts
191
+ var commands_exports = /* @__PURE__ */ __exportAll({
192
+ audit: () => audit,
193
+ currentPage: () => currentPage,
194
+ input: () => input,
195
+ navigateBack: () => navigateBack,
196
+ navigateTo: () => navigateTo,
197
+ pageData: () => pageData,
198
+ pageStack: () => pageStack,
199
+ reLaunch: () => reLaunch,
200
+ redirectTo: () => redirectTo,
201
+ remote: () => remote,
202
+ scrollTo: () => scrollTo,
203
+ switchTab: () => switchTab,
204
+ systemInfo: () => systemInfo,
205
+ takeScreenshot: () => takeScreenshot,
206
+ tap: () => tap
207
+ });
208
+ async function navigateTo(options) {
209
+ 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));
210
+ }
211
+ async function redirectTo(options) {
212
+ 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));
213
+ }
214
+ async function navigateBack(options) {
215
+ await runRouteCommand(options, i18nText("正在返回上一页...", "Navigating back..."), i18nText("已返回上一页", "Navigated back"), (miniProgram) => miniProgram.navigateBack());
216
+ }
217
+ async function reLaunch(options) {
218
+ 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));
219
+ }
220
+ async function switchTab(options) {
221
+ 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));
222
+ }
223
+ async function pageStack(options) {
224
+ return withMiniProgram(options, async (miniProgram) => {
225
+ const result = (await miniProgram.pageStack()).map(toPageSnapshot);
226
+ printStructuredResult(result, options.json, i18nText("页面栈:", "Page stack:"));
227
+ return result;
228
+ });
229
+ }
230
+ async function currentPage(options) {
231
+ return withMiniProgram(options, async (miniProgram) => {
232
+ const result = toPageSnapshot(await miniProgram.currentPage());
233
+ if (options.json) console.log(JSON.stringify(result, null, 2));
234
+ else logger_default.info(i18nText(`当前页面: ${result.path}${result.query ? ` ${JSON.stringify(result.query)}` : ""}`, `Current page: ${result.path}${result.query ? ` ${JSON.stringify(result.query)}` : ""}`));
235
+ return result;
236
+ });
237
+ }
238
+ async function systemInfo(options) {
239
+ return withMiniProgram(options, async (miniProgram) => {
240
+ const info = await miniProgram.systemInfo();
241
+ printStructuredResult(info, options.json, i18nText("系统信息:", "System info:"));
242
+ return info;
243
+ });
244
+ }
245
+ async function pageData(options) {
246
+ return withMiniProgram(options, async (miniProgram) => {
247
+ const data = await (await miniProgram.currentPage()).data(options.path);
248
+ printStructuredResult(data, options.json, i18nText("页面数据:", "Page data:"));
249
+ return data;
250
+ });
251
+ }
252
+ async function tap(options) {
253
+ await withMiniProgram(options, async (miniProgram) => {
254
+ logger_default.info(i18nText(`正在点击元素 ${colors.cyan(options.selector)}...`, `Tapping element ${colors.cyan(options.selector)}...`));
255
+ await (await requireElement(await miniProgram.currentPage(), options.selector)).tap();
256
+ logger_default.success(i18nText(`已点击元素 ${colors.cyan(options.selector)}`, `Tapped element ${colors.cyan(options.selector)}`));
257
+ });
258
+ }
259
+ async function input(options) {
260
+ await withMiniProgram(options, async (miniProgram) => {
261
+ logger_default.info(i18nText(`正在向 ${colors.cyan(options.selector)} 输入 "${colors.cyan(options.value)}"...`, `Inputting "${colors.cyan(options.value)}" into ${colors.cyan(options.selector)}...`));
262
+ const element = await requireElement(await miniProgram.currentPage(), options.selector);
263
+ if (typeof element.input !== "function") throw new TypeError(i18nText(`元素不支持输入: ${options.selector}`, `Element does not support input: ${options.selector}`));
264
+ await element.input(options.value);
265
+ logger_default.success(i18nText(`已向 ${colors.cyan(options.selector)} 输入 "${colors.cyan(options.value)}"`, `Inputted "${colors.cyan(options.value)}" into ${colors.cyan(options.selector)}`));
266
+ });
267
+ }
268
+ async function scrollTo(options) {
269
+ await withMiniProgram(options, async (miniProgram) => {
270
+ logger_default.info(i18nText(`正在滚动到位置 ${colors.cyan(String(options.scrollTop))}...`, `Scrolling to position ${colors.cyan(String(options.scrollTop))}...`));
271
+ await miniProgram.pageScrollTo(options.scrollTop);
272
+ logger_default.success(i18nText(`已滚动到位置 ${colors.cyan(String(options.scrollTop))}`, `Scrolled to position ${colors.cyan(String(options.scrollTop))}`));
273
+ });
274
+ }
275
+ async function audit(options) {
276
+ return withMiniProgram(options, async (miniProgram) => {
277
+ logger_default.info(i18nText("正在执行体验审计...", "Running experience audit..."));
278
+ const result = await miniProgram.stopAudits();
279
+ if (options.outputPath) {
280
+ await fs.writeFile(options.outputPath, JSON.stringify(result, null, 2));
281
+ logger_default.success(i18nText(`审计报告已保存到 ${colors.cyan(options.outputPath)}`, `Audit report saved to ${colors.cyan(options.outputPath)}`));
282
+ return result;
283
+ }
284
+ console.log(JSON.stringify(result, null, 2));
285
+ return result;
286
+ });
287
+ }
288
+ async function takeScreenshot(options) {
289
+ return withMiniProgram(options, async (miniProgram) => {
290
+ logger_default.info(i18nText(`正在连接 DevTools:${colors.cyan(options.projectPath)}...`, `Connecting to DevTools at ${colors.cyan(options.projectPath)}...`));
291
+ if (options.page) {
292
+ logger_default.info(i18nText(`正在跳转页面 ${colors.cyan(options.page)}...`, `Navigating to page ${colors.cyan(options.page)}...`));
293
+ await miniProgram.reLaunch(options.page);
294
+ }
295
+ logger_default.info(i18nText("正在截图...", "Taking screenshot..."));
296
+ const screenshot = await miniProgram.screenshot();
297
+ const base64 = typeof screenshot === "string" ? screenshot : Buffer$1.from(screenshot).toString("base64");
298
+ if (!base64) throw new Error(i18nText("截图失败", "Failed to capture screenshot"));
299
+ if (options.outputPath) {
300
+ await fs.writeFile(options.outputPath, Buffer$1.from(base64, "base64"));
301
+ logger_default.success(i18nText(`截图已保存到 ${colors.cyan(options.outputPath)}`, `Screenshot saved to ${colors.cyan(options.outputPath)}`));
302
+ return { path: options.outputPath };
303
+ }
304
+ return { base64 };
305
+ });
306
+ }
307
+ async function remote(options) {
308
+ const enable = options.enable ?? true;
309
+ await withMiniProgram(options, async (miniProgram) => {
310
+ logger_default.info(enable ? i18nText("正在开启远程调试...", "Enabling remote debugging...") : i18nText("正在关闭远程调试...", "Disabling remote debugging..."));
311
+ await miniProgram.remote(enable);
312
+ logger_default.success(enable ? i18nText("远程调试已开启", "Remote debugging enabled") : i18nText("远程调试已关闭", "Remote debugging disabled"));
313
+ });
314
+ }
315
+ async function runRouteCommand(options, startMessage, successMessage, run) {
316
+ await withMiniProgram(options, async (miniProgram) => {
317
+ logger_default.info(startMessage);
318
+ await run(miniProgram);
319
+ logger_default.success(successMessage);
320
+ });
321
+ }
322
+ function toPageSnapshot(page) {
323
+ return {
324
+ path: page.path ?? "",
325
+ query: page.query
326
+ };
327
+ }
328
+ function printStructuredResult(result, json, title) {
329
+ if (json) {
330
+ console.log(JSON.stringify(result, null, 2));
331
+ return;
332
+ }
333
+ logger_default.info(title);
334
+ console.log(JSON.stringify(result, null, 2));
335
+ }
336
+ async function requireElement(page, selector) {
337
+ const element = await page.$(selector);
338
+ if (!element) throw new Error(i18nText(`未找到元素: ${selector}`, `Element not found: ${selector}`));
339
+ return element;
340
+ }
341
+ //#endregion
342
+ export { formatAutomatorLoginError as C, launchAutomator as E, validateLocaleOption as S, isDevtoolsHttpPortError as T, withMiniProgram as _, navigateBack as a, configureLocaleFromArgv as b, pageStack as c, remote as d, scrollTo as f, tap as g, takeScreenshot as h, input as i, 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, colors as v, isAutomatorLoginError as w, i18nText as x, logger_default as y };