weapp-ide-cli 5.2.0 → 5.2.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-DXJCUYYI.js → cli-DKrUhSmB.js} +34 -15
- package/dist/cli.js +10 -13
- package/dist/{commands-BfdE1eYN.js → commands--vppy2pX.js} +352 -65
- package/dist/commands-Bg8hQbPE.js +2 -0
- package/dist/index.d.ts +53 -6
- package/dist/index.js +3 -3
- package/package.json +2 -2
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
1
|
+
import { B as createLocaleConfig, C as configureLocaleFromArgv, G as defaultCustomConfigFilePath, H as readCustomConfig, I as resolveCliPath, K as resolvePath, Q as logger_default, R as getConfiguredLocale, T as validateLocaleOption, U as removeCustomConfigKey, V as overwriteCustomConfig, X as operatingSystemName, Y as isOperatingSystemSupported, Z as colors, a as navigateBack, c as pageStack, d as remote, f as scrollTo, g as tap, i as input, l as reLaunch, m as systemInfo, n as captureScreenshotBuffer, o as navigateTo, p as switchTab, r as currentPage, s as pageData, t as audit, u as redirectTo, w as i18nText, y as connectMiniProgram, z as createCustomConfig } from "./commands--vppy2pX.js";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import { fs as fs$1 } from "@weapp-core/shared";
|
|
3
4
|
import process, { stdin, stdout } from "node:process";
|
|
4
|
-
import fs$1 from "node:fs/promises";
|
|
5
|
-
import pixelmatch from "pixelmatch";
|
|
6
5
|
import { PNG } from "pngjs";
|
|
6
|
+
import pixelmatch from "pixelmatch";
|
|
7
7
|
import { createInterface } from "node:readline/promises";
|
|
8
8
|
import { inspect } from "node:util";
|
|
9
9
|
import { emitKeypressEvents } from "node:readline";
|
|
@@ -122,20 +122,20 @@ function readPng(buffer, label) {
|
|
|
122
122
|
async function comparePngWithBaseline(options) {
|
|
123
123
|
let baselineBuffer;
|
|
124
124
|
try {
|
|
125
|
-
baselineBuffer = await fs
|
|
125
|
+
baselineBuffer = await fs.readFile(options.baselinePath);
|
|
126
126
|
} catch (error) {
|
|
127
127
|
throw new Error(i18nText(`无法读取基准图: ${options.baselinePath}`, `Failed to read baseline image: ${options.baselinePath}`), { cause: error });
|
|
128
128
|
}
|
|
129
129
|
const baselinePng = readPng(baselineBuffer, i18nText("基准图", "Baseline image"));
|
|
130
130
|
const currentPng = readPng(options.currentPngBuffer, i18nText("当前截图", "Current screenshot"));
|
|
131
131
|
if (baselinePng.width !== currentPng.width || baselinePng.height !== currentPng.height) throw new Error(i18nText("基准图与当前截图尺寸不一致", "Baseline image size does not match current screenshot"));
|
|
132
|
-
if (options.currentOutputPath) await fs
|
|
132
|
+
if (options.currentOutputPath) await fs.writeFile(options.currentOutputPath, options.currentPngBuffer);
|
|
133
133
|
const diffPng = new PNG({
|
|
134
134
|
width: currentPng.width,
|
|
135
135
|
height: currentPng.height
|
|
136
136
|
});
|
|
137
137
|
const diffPixels = pixelmatch(baselinePng.data, currentPng.data, diffPng.data, currentPng.width, currentPng.height, { threshold: options.threshold });
|
|
138
|
-
if (options.diffOutputPath) await fs
|
|
138
|
+
if (options.diffOutputPath) await fs.writeFile(options.diffOutputPath, PNG.sync.write(diffPng));
|
|
139
139
|
return {
|
|
140
140
|
baselinePath: options.baselinePath,
|
|
141
141
|
currentPath: options.currentOutputPath,
|
|
@@ -178,6 +178,7 @@ ${colors.bold("参数:")}
|
|
|
178
178
|
--current-output <path> 当前截图输出路径
|
|
179
179
|
--diff-output <path> diff 图片输出路径
|
|
180
180
|
--page <path> 对比前先跳转页面
|
|
181
|
+
--full-page 对比时使用整页长截图
|
|
181
182
|
--threshold <number> pixelmatch threshold(默认:0.1)
|
|
182
183
|
--max-diff-pixels <count> 最大允许差异像素数
|
|
183
184
|
--max-diff-ratio <number> 最大允许差异占比(0-1)
|
|
@@ -192,6 +193,8 @@ ${colors.bold("规则:")}
|
|
|
192
193
|
- baseline 与当前截图尺寸不一致时直接失败
|
|
193
194
|
|
|
194
195
|
${colors.bold("示例:")}
|
|
196
|
+
weapp compare -p ./dist/build/mp-weixin --page pages/index/index --full-page --baseline .screenshots/baseline/index.full.png --current-output .screenshots/current/index.full.png --diff-output .screenshots/diff/index.full.diff.png --max-diff-pixels 100 --json
|
|
197
|
+
|
|
195
198
|
weapp compare -p ./dist/build/mp-weixin --page pages/index/index --baseline .screenshots/baseline/index.png --current-output .screenshots/current/index.png --diff-output .screenshots/diff/index.diff.png --max-diff-pixels 100 --json
|
|
196
199
|
|
|
197
200
|
weapp compare -p ./dist/build/mp-weixin --baseline .screenshots/baseline/index.png --max-diff-ratio 0.001
|
|
@@ -204,6 +207,7 @@ ${colors.bold("Options:")}
|
|
|
204
207
|
--current-output <path> Output file path for current screenshot
|
|
205
208
|
--diff-output <path> Output file path for diff image
|
|
206
209
|
--page <path> Navigate to page before comparison
|
|
210
|
+
--full-page Use stitched full-page screenshots for comparison
|
|
207
211
|
--threshold <number> Pixelmatch threshold (default: 0.1)
|
|
208
212
|
--max-diff-pixels <count> Maximum allowed diff pixels
|
|
209
213
|
--max-diff-ratio <number> Maximum allowed diff ratio (0-1)
|
|
@@ -218,6 +222,8 @@ ${colors.bold("Rules:")}
|
|
|
218
222
|
- Baseline and current screenshot must have identical dimensions
|
|
219
223
|
|
|
220
224
|
${colors.bold("Examples:")}
|
|
225
|
+
weapp compare -p ./dist/build/mp-weixin --page pages/index/index --full-page --baseline .screenshots/baseline/index.full.png --current-output .screenshots/current/index.full.png --diff-output .screenshots/diff/index.full.diff.png --max-diff-pixels 100 --json
|
|
226
|
+
|
|
221
227
|
weapp compare -p ./dist/build/mp-weixin --page pages/index/index --baseline .screenshots/baseline/index.png --current-output .screenshots/current/index.png --diff-output .screenshots/diff/index.diff.png --max-diff-pixels 100 --json
|
|
222
228
|
|
|
223
229
|
weapp compare -p ./dist/build/mp-weixin --baseline .screenshots/baseline/index.png --max-diff-ratio 0.001
|
|
@@ -238,6 +244,7 @@ function parseCompareArgs(argv) {
|
|
|
238
244
|
projectPath: parsed.projectPath,
|
|
239
245
|
timeout: parsed.timeout,
|
|
240
246
|
page: readOptionValue(argv, "--page"),
|
|
247
|
+
fullPage: argv.includes("--full-page"),
|
|
241
248
|
baselinePath,
|
|
242
249
|
currentOutputPath: readOptionValue(argv, "--current-output"),
|
|
243
250
|
diffOutputPath: readOptionValue(argv, "--diff-output"),
|
|
@@ -318,6 +325,7 @@ ${colors.bold("参数:")}
|
|
|
318
325
|
-p, --project <path> 项目路径(默认:当前目录)
|
|
319
326
|
-o, --output <path> 截图输出文件路径
|
|
320
327
|
--page <path> 截图前先跳转页面
|
|
328
|
+
--full-page 输出整页长截图
|
|
321
329
|
-t, --timeout <ms> 连接超时时间(默认:30000)
|
|
322
330
|
--json 以 JSON 格式输出
|
|
323
331
|
--lang <lang> 语言切换:zh | en(默认:zh)
|
|
@@ -333,6 +341,9 @@ ${colors.bold("示例:")}
|
|
|
333
341
|
# 先跳转页面再截图
|
|
334
342
|
weapp screenshot -p /path/to/project --page pages/index/index
|
|
335
343
|
|
|
344
|
+
# 输出整页长截图
|
|
345
|
+
weapp screenshot -p /path/to/project --page pages/index/index --full-page -o full.png
|
|
346
|
+
|
|
336
347
|
# 以 JSON 输出便于脚本解析
|
|
337
348
|
weapp screenshot -p /path/to/project --json
|
|
338
349
|
`, `
|
|
@@ -342,6 +353,7 @@ ${colors.bold("Options:")}
|
|
|
342
353
|
-p, --project <path> Project path (default: current directory)
|
|
343
354
|
-o, --output <path> Output file path for screenshot
|
|
344
355
|
--page <path> Navigate to page before taking screenshot
|
|
356
|
+
--full-page Capture a stitched full-page screenshot
|
|
345
357
|
-t, --timeout <ms> Connection timeout in milliseconds (default: 30000)
|
|
346
358
|
--json Output as JSON format
|
|
347
359
|
--lang <lang> Language: zh | en (default: zh)
|
|
@@ -357,6 +369,9 @@ ${colors.bold("Examples:")}
|
|
|
357
369
|
# Navigate to page first
|
|
358
370
|
weapp screenshot -p /path/to/project --page pages/index/index
|
|
359
371
|
|
|
372
|
+
# Capture a stitched full-page screenshot
|
|
373
|
+
weapp screenshot -p /path/to/project --page pages/index/index --full-page -o full.png
|
|
374
|
+
|
|
360
375
|
# JSON output for parsing
|
|
361
376
|
weapp screenshot -p /path/to/project --json
|
|
362
377
|
`));
|
|
@@ -366,11 +381,15 @@ ${colors.bold("Examples:")}
|
|
|
366
381
|
*/
|
|
367
382
|
function parseScreenshotArgs(argv) {
|
|
368
383
|
const parsed = parseAutomatorArgs(argv);
|
|
384
|
+
const outputPath = readOptionValue(argv, "-o") || readOptionValue(argv, "--output");
|
|
385
|
+
const page = readOptionValue(argv, "--page");
|
|
386
|
+
const fullPage = argv.includes("--full-page");
|
|
369
387
|
return {
|
|
370
388
|
projectPath: parsed.projectPath,
|
|
371
|
-
timeout: parsed.timeout,
|
|
372
|
-
outputPath
|
|
373
|
-
page:
|
|
389
|
+
...parsed.timeout ? { timeout: parsed.timeout } : {},
|
|
390
|
+
...outputPath ? { outputPath } : {},
|
|
391
|
+
...page ? { page } : {},
|
|
392
|
+
...fullPage ? { fullPage: true } : {}
|
|
374
393
|
};
|
|
375
394
|
}
|
|
376
395
|
/**
|
|
@@ -383,7 +402,7 @@ async function runScreenshot(argv) {
|
|
|
383
402
|
}
|
|
384
403
|
const options = parseScreenshotArgs(argv);
|
|
385
404
|
const isJsonOutput = argv.includes("--json");
|
|
386
|
-
const { takeScreenshot } = await import("./commands-
|
|
405
|
+
const { takeScreenshot } = await import("./commands-Bg8hQbPE.js");
|
|
387
406
|
const result = await takeScreenshot(options);
|
|
388
407
|
if (isJsonOutput) {
|
|
389
408
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -787,7 +806,7 @@ async function promptForCliPath() {
|
|
|
787
806
|
try {
|
|
788
807
|
const normalizedPath = await createCustomConfig({ cliPath });
|
|
789
808
|
logger_default.info(`全局配置存储位置:${colors.green(defaultCustomConfigFilePath)}`);
|
|
790
|
-
if (!await fs.pathExists(normalizedPath)) logger_default.warn("在当前路径未找到微信web开发者命令行工具,请确认路径是否正确。");
|
|
809
|
+
if (!await fs$1.pathExists(normalizedPath)) logger_default.warn("在当前路径未找到微信web开发者命令行工具,请确认路径是否正确。");
|
|
791
810
|
return normalizedPath;
|
|
792
811
|
} catch (error) {
|
|
793
812
|
const reason = error instanceof Error ? error.message : String(error);
|
|
@@ -859,7 +878,7 @@ async function handleConfigCommand(argv) {
|
|
|
859
878
|
}
|
|
860
879
|
if (action === "doctor") {
|
|
861
880
|
const rawConfig = await readCustomConfig();
|
|
862
|
-
const hasConfigFile = await fs.pathExists(defaultCustomConfigFilePath);
|
|
881
|
+
const hasConfigFile = await fs$1.pathExists(defaultCustomConfigFilePath);
|
|
863
882
|
const resolvedCli = await resolveCliPath();
|
|
864
883
|
const hasCustomCli = typeof rawConfig.cliPath === "string" && rawConfig.cliPath.length > 0;
|
|
865
884
|
const hasValidCli = Boolean(resolvedCli.cliPath);
|
|
@@ -882,7 +901,7 @@ async function handleConfigCommand(argv) {
|
|
|
882
901
|
const outputPath = argv[1];
|
|
883
902
|
const config = await readCustomConfig();
|
|
884
903
|
if (outputPath) {
|
|
885
|
-
await fs.writeJSON(outputPath, config, {
|
|
904
|
+
await fs$1.writeJSON(outputPath, config, {
|
|
886
905
|
spaces: 2,
|
|
887
906
|
encoding: "utf8"
|
|
888
907
|
});
|
|
@@ -895,7 +914,7 @@ async function handleConfigCommand(argv) {
|
|
|
895
914
|
if (action === "import") {
|
|
896
915
|
const inputPath = argv[1];
|
|
897
916
|
if (!inputPath) throw new Error(i18nText("请提供导入文件路径,例如:weapp config import ./weapp-config.json", "Please provide import file path, e.g. weapp config import ./weapp-config.json"));
|
|
898
|
-
const imported = await fs.readJSON(inputPath);
|
|
917
|
+
const imported = await fs$1.readJSON(inputPath);
|
|
899
918
|
if (!imported || typeof imported !== "object") throw new Error(i18nText("导入文件格式无效:应为 JSON 对象", "Invalid import file format: expected a JSON object"));
|
|
900
919
|
const candidate = imported;
|
|
901
920
|
await overwriteCustomConfig({
|
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,15 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as parse } from "./cli-
|
|
1
|
+
import { Q as logger_default } from "./commands--vppy2pX.js";
|
|
2
|
+
import { n as parse } from "./cli-DKrUhSmB.js";
|
|
3
3
|
import process from "node:process";
|
|
4
4
|
//#region src/cli.ts
|
|
5
|
-
|
|
5
|
+
const argv = process.argv.slice(2);
|
|
6
|
+
try {
|
|
7
|
+
await parse(argv);
|
|
8
|
+
} catch (err) {
|
|
6
9
|
logger_default.error(err);
|
|
7
|
-
if (typeof err?.exitCode === "number")
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (typeof err?.code === "number") {
|
|
12
|
-
process.exitCode = err.code;
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
process.exitCode = 1;
|
|
16
|
-
});
|
|
10
|
+
if (typeof err?.exitCode === "number") process.exitCode = err.exitCode;
|
|
11
|
+
else if (typeof err?.code === "number") process.exitCode = err.code;
|
|
12
|
+
else process.exitCode = 1;
|
|
13
|
+
}
|
|
17
14
|
//#endregion
|
|
18
15
|
export {};
|
|
@@ -1,23 +1,13 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
1
5
|
import { Launcher } from "@weapp-vite/miniprogram-automator";
|
|
2
|
-
import { fs } from "@weapp-core/shared";
|
|
6
|
+
import { fs as fs$1 } from "@weapp-core/shared";
|
|
3
7
|
import logger, { colors } from "@weapp-core/logger";
|
|
4
|
-
import os from "node:os";
|
|
5
8
|
import process from "node:process";
|
|
6
|
-
import path from "pathe";
|
|
7
|
-
import {
|
|
8
|
-
import fs$1 from "node:fs/promises";
|
|
9
|
-
//#region \0rolldown/runtime.js
|
|
10
|
-
var __defProp = Object.defineProperty;
|
|
11
|
-
var __exportAll = (all, no_symbols) => {
|
|
12
|
-
let target = {};
|
|
13
|
-
for (var name in all) __defProp(target, name, {
|
|
14
|
-
get: all[name],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
18
|
-
return target;
|
|
19
|
-
};
|
|
20
|
-
//#endregion
|
|
9
|
+
import path$1 from "pathe";
|
|
10
|
+
import { PNG } from "pngjs";
|
|
21
11
|
//#region src/logger.ts
|
|
22
12
|
var logger_default = logger;
|
|
23
13
|
//#endregion
|
|
@@ -42,11 +32,11 @@ function isOperatingSystemSupported(osName = os.type()) {
|
|
|
42
32
|
*/
|
|
43
33
|
const operatingSystemName = os.type();
|
|
44
34
|
async function getFirstBinaryPath(command) {
|
|
45
|
-
const pathDirs = (process.env.PATH || "").split(path.delimiter);
|
|
35
|
+
const pathDirs = (process.env.PATH || "").split(path$1.delimiter);
|
|
46
36
|
for (const dir of pathDirs) {
|
|
47
|
-
const fullPath = path.join(dir, command);
|
|
37
|
+
const fullPath = path$1.join(dir, command);
|
|
48
38
|
try {
|
|
49
|
-
await fs.access(fullPath, fs.constants.X_OK);
|
|
39
|
+
await fs$1.access(fullPath, fs$1.constants.X_OK);
|
|
50
40
|
return fullPath;
|
|
51
41
|
} catch {
|
|
52
42
|
continue;
|
|
@@ -96,8 +86,8 @@ async function getDefaultCliPath(targetOs = operatingSystemName) {
|
|
|
96
86
|
* @description 解析为绝对路径(基于当前工作目录)
|
|
97
87
|
*/
|
|
98
88
|
function resolvePath(filePath) {
|
|
99
|
-
if (path.isAbsolute(filePath)) return filePath;
|
|
100
|
-
return path.resolve(process.cwd(), filePath);
|
|
89
|
+
if (path$1.isAbsolute(filePath)) return filePath;
|
|
90
|
+
return path$1.resolve(process.cwd(), filePath);
|
|
101
91
|
}
|
|
102
92
|
//#endregion
|
|
103
93
|
//#region src/config/paths.ts
|
|
@@ -105,11 +95,11 @@ const homedir = os.homedir();
|
|
|
105
95
|
/**
|
|
106
96
|
* @description 默认自定义配置目录
|
|
107
97
|
*/
|
|
108
|
-
const defaultCustomConfigDirPath = path.join(homedir, ".weapp-ide-cli");
|
|
98
|
+
const defaultCustomConfigDirPath = path$1.join(homedir, ".weapp-ide-cli");
|
|
109
99
|
/**
|
|
110
100
|
* @description 默认自定义配置文件路径
|
|
111
101
|
*/
|
|
112
|
-
const defaultCustomConfigFilePath = path.join(defaultCustomConfigDirPath, "config.json");
|
|
102
|
+
const defaultCustomConfigFilePath = path$1.join(defaultCustomConfigDirPath, "config.json");
|
|
113
103
|
//#endregion
|
|
114
104
|
//#region src/config/custom.ts
|
|
115
105
|
const JSON_OPTIONS = {
|
|
@@ -117,9 +107,9 @@ const JSON_OPTIONS = {
|
|
|
117
107
|
spaces: 2
|
|
118
108
|
};
|
|
119
109
|
async function readCustomConfig() {
|
|
120
|
-
if (!await fs.pathExists(defaultCustomConfigFilePath)) return {};
|
|
110
|
+
if (!await fs$1.pathExists(defaultCustomConfigFilePath)) return {};
|
|
121
111
|
try {
|
|
122
|
-
const config = await fs.readJSON(defaultCustomConfigFilePath);
|
|
112
|
+
const config = await fs$1.readJSON(defaultCustomConfigFilePath);
|
|
123
113
|
if (!config || typeof config !== "object") return {};
|
|
124
114
|
const candidate = config;
|
|
125
115
|
const next = {};
|
|
@@ -135,8 +125,8 @@ async function writeCustomConfig(patch, options = {}) {
|
|
|
135
125
|
...options.replace ? {} : await readCustomConfig(),
|
|
136
126
|
...patch
|
|
137
127
|
};
|
|
138
|
-
await fs.ensureDir(defaultCustomConfigDirPath);
|
|
139
|
-
await fs.writeJSON(defaultCustomConfigFilePath, nextConfig, JSON_OPTIONS);
|
|
128
|
+
await fs$1.ensureDir(defaultCustomConfigDirPath);
|
|
129
|
+
await fs$1.writeJSON(defaultCustomConfigFilePath, nextConfig, JSON_OPTIONS);
|
|
140
130
|
}
|
|
141
131
|
/**
|
|
142
132
|
* @description 写入自定义 CLI 路径配置
|
|
@@ -180,8 +170,8 @@ async function overwriteCustomConfig(config) {
|
|
|
180
170
|
* @description 读取并解析 CLI 配置(自定义优先)
|
|
181
171
|
*/
|
|
182
172
|
async function getConfig() {
|
|
183
|
-
if (await fs.pathExists(defaultCustomConfigFilePath)) try {
|
|
184
|
-
const config = await fs.readJSON(defaultCustomConfigFilePath);
|
|
173
|
+
if (await fs$1.pathExists(defaultCustomConfigFilePath)) try {
|
|
174
|
+
const config = await fs$1.readJSON(defaultCustomConfigFilePath);
|
|
185
175
|
const cliPath = typeof config.cliPath === "string" ? config.cliPath.trim() : "";
|
|
186
176
|
const locale = config.locale === "zh" || config.locale === "en" ? config.locale : void 0;
|
|
187
177
|
if (cliPath) {
|
|
@@ -228,7 +218,7 @@ async function resolveCliPath() {
|
|
|
228
218
|
source: config.source
|
|
229
219
|
};
|
|
230
220
|
return {
|
|
231
|
-
cliPath: await fs.pathExists(config.cliPath) ? config.cliPath : null,
|
|
221
|
+
cliPath: await fs$1.pathExists(config.cliPath) ? config.cliPath : null,
|
|
232
222
|
source: config.source
|
|
233
223
|
};
|
|
234
224
|
}
|
|
@@ -242,6 +232,10 @@ const LOGIN_REQUIRED_CN_RE = /需要重新登录/;
|
|
|
242
232
|
const LOGIN_REQUIRED_EN_RE = /need\s+re-?login|re-?login/i;
|
|
243
233
|
const LOGIN_REQUIRED_CODE_RE = /code\s*[:=]\s*(\d+)/i;
|
|
244
234
|
const DEVTOOLS_HTTP_PORT_ERROR = "Failed to launch wechat web devTools, please make sure http port is open";
|
|
235
|
+
const DEVTOOLS_EXTENSION_CONTEXT_INVALIDATED_RE = /Extension context invalidated/i;
|
|
236
|
+
const AUTOMATOR_LAUNCH_TIMEOUT_RE = /Wait timed out after \d+ ms/i;
|
|
237
|
+
const AUTOMATOR_WS_CONNECT_RE = /Failed connecting to ws:\/\/127\.0\.0\.1:\d+/i;
|
|
238
|
+
const DEVTOOLS_PROTOCOL_TIMEOUT_RE = /DevTools did not respond to protocol method (\S+) within \d+ms/i;
|
|
245
239
|
const DEVTOOLS_INFRA_ERROR_PATTERNS = [
|
|
246
240
|
/listen EPERM/i,
|
|
247
241
|
/operation not permitted 0\.0\.0\.0/i,
|
|
@@ -249,6 +243,8 @@ const DEVTOOLS_INFRA_ERROR_PATTERNS = [
|
|
|
249
243
|
/ECONNREFUSED/i,
|
|
250
244
|
/connect ECONNREFUSED/i
|
|
251
245
|
];
|
|
246
|
+
const DEFAULT_WECHAT_DEVTOOLS_WS_ENDPOINT = "ws://127.0.0.1:9420";
|
|
247
|
+
const AUTOMATOR_SESSION_DIR = path.join(os.tmpdir(), "weapp-vite-automator-sessions");
|
|
252
248
|
const DEVTOOLS_LOGIN_REQUIRED_PATTERNS = [
|
|
253
249
|
/code\s*[:=]\s*10/i,
|
|
254
250
|
/需要重新登录/,
|
|
@@ -268,6 +264,38 @@ function extractErrorText(error) {
|
|
|
268
264
|
candidate.stdout
|
|
269
265
|
].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n");
|
|
270
266
|
}
|
|
267
|
+
function resolveAutomatorSessionFilePath(projectPath) {
|
|
268
|
+
const normalizedProjectPath = path.resolve(projectPath);
|
|
269
|
+
const encodedProjectPath = Buffer.from(normalizedProjectPath).toString("base64url");
|
|
270
|
+
return path.join(AUTOMATOR_SESSION_DIR, `${encodedProjectPath}.json`);
|
|
271
|
+
}
|
|
272
|
+
async function persistAutomatorSession(projectPath, wsEndpoint) {
|
|
273
|
+
const filePath = resolveAutomatorSessionFilePath(projectPath);
|
|
274
|
+
const payload = {
|
|
275
|
+
projectPath: path.resolve(projectPath),
|
|
276
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
277
|
+
wsEndpoint
|
|
278
|
+
};
|
|
279
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
280
|
+
await fs.writeFile(filePath, JSON.stringify(payload, null, 2), "utf8");
|
|
281
|
+
}
|
|
282
|
+
async function readPersistedAutomatorSession(projectPath) {
|
|
283
|
+
const filePath = resolveAutomatorSessionFilePath(projectPath);
|
|
284
|
+
try {
|
|
285
|
+
const raw = await fs.readFile(filePath, "utf8");
|
|
286
|
+
const payload = JSON.parse(raw);
|
|
287
|
+
if (payload.projectPath !== path.resolve(projectPath) || typeof payload.wsEndpoint !== "string" || !payload.wsEndpoint.trim()) return null;
|
|
288
|
+
return payload;
|
|
289
|
+
} catch {
|
|
290
|
+
return null;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
async function removePersistedAutomatorSession(projectPath) {
|
|
294
|
+
const filePath = resolveAutomatorSessionFilePath(projectPath);
|
|
295
|
+
try {
|
|
296
|
+
await fs.rm(filePath, { force: true });
|
|
297
|
+
} catch {}
|
|
298
|
+
}
|
|
271
299
|
/**
|
|
272
300
|
* @description 提取登录失效时最适合展示给用户的一行信息。
|
|
273
301
|
*/
|
|
@@ -288,6 +316,40 @@ function isDevtoolsHttpPortError(error) {
|
|
|
288
316
|
return message.includes(DEVTOOLS_HTTP_PORT_ERROR) || DEVTOOLS_INFRA_ERROR_PATTERNS.some((pattern) => pattern.test(message));
|
|
289
317
|
}
|
|
290
318
|
/**
|
|
319
|
+
* @description 判断错误是否属于开发者工具 automator 扩展上下文尚未就绪。
|
|
320
|
+
*/
|
|
321
|
+
function isDevtoolsExtensionContextInvalidatedError(error) {
|
|
322
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
323
|
+
return DEVTOOLS_EXTENSION_CONTEXT_INVALIDATED_RE.test(message);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* @description 判断错误是否属于可重试的 automator 启动抖动。
|
|
327
|
+
*/
|
|
328
|
+
function isRetryableAutomatorLaunchError(error) {
|
|
329
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
330
|
+
return DEVTOOLS_EXTENSION_CONTEXT_INVALIDATED_RE.test(message) || AUTOMATOR_LAUNCH_TIMEOUT_RE.test(message) || AUTOMATOR_WS_CONNECT_RE.test(message);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* @description 判断错误是否属于开发者工具 websocket 连接失败。
|
|
334
|
+
*/
|
|
335
|
+
function isAutomatorWsConnectError(error) {
|
|
336
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
337
|
+
return AUTOMATOR_WS_CONNECT_RE.test(message);
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* @description 判断错误是否属于开发者工具协议调用超时。
|
|
341
|
+
*/
|
|
342
|
+
function isAutomatorProtocolTimeoutError(error) {
|
|
343
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
344
|
+
return DEVTOOLS_PROTOCOL_TIMEOUT_RE.test(message);
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* @description 提取协议超时的方法名。
|
|
348
|
+
*/
|
|
349
|
+
function getAutomatorProtocolTimeoutMethod(error) {
|
|
350
|
+
return (error instanceof Error ? error.message : String(error)).match(DEVTOOLS_PROTOCOL_TIMEOUT_RE)?.[1];
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
291
353
|
* @description 判断错误是否属于开发者工具登录失效。
|
|
292
354
|
*/
|
|
293
355
|
function isAutomatorLoginError(error) {
|
|
@@ -312,13 +374,40 @@ function formatAutomatorLoginError(error) {
|
|
|
312
374
|
* @description 基于当前配置解析 CLI 路径,并通过现代化 automator 入口启动会话。
|
|
313
375
|
*/
|
|
314
376
|
async function launchAutomator(options) {
|
|
315
|
-
const { cliPath, projectPath, timeout = 3e4 } = options;
|
|
377
|
+
const { cliPath, projectPath, timeout = 3e4, trustProject = false } = options;
|
|
316
378
|
const resolvedCliPath = cliPath ?? (await resolveCliPath()).cliPath ?? void 0;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
379
|
+
const launcher = new Launcher();
|
|
380
|
+
let lastError = null;
|
|
381
|
+
for (let attempt = 0; attempt < 2; attempt += 1) try {
|
|
382
|
+
const miniProgram = await launcher.launch({
|
|
383
|
+
cliPath: resolvedCliPath,
|
|
384
|
+
projectPath,
|
|
385
|
+
timeout,
|
|
386
|
+
trustProject
|
|
387
|
+
});
|
|
388
|
+
const sessionMetadata = Reflect.get(miniProgram, "__WEAPP_VITE_SESSION_METADATA");
|
|
389
|
+
if (typeof sessionMetadata?.wsEndpoint === "string" && sessionMetadata.wsEndpoint) await persistAutomatorSession(projectPath, sessionMetadata.wsEndpoint);
|
|
390
|
+
return miniProgram;
|
|
391
|
+
} catch (error) {
|
|
392
|
+
lastError = error;
|
|
393
|
+
if (!isRetryableAutomatorLaunchError(error) || attempt === 1) throw error;
|
|
394
|
+
}
|
|
395
|
+
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
396
|
+
}
|
|
397
|
+
/**
|
|
398
|
+
* @description 连接当前项目已打开的开发者工具自动化会话,不触发新的 IDE 拉起。
|
|
399
|
+
*/
|
|
400
|
+
async function connectOpenedAutomator(options) {
|
|
401
|
+
const { projectPath } = options;
|
|
402
|
+
const launcher = new Launcher();
|
|
403
|
+
const persistedSession = await readPersistedAutomatorSession(projectPath);
|
|
404
|
+
const wsEndpoint = persistedSession?.wsEndpoint ?? DEFAULT_WECHAT_DEVTOOLS_WS_ENDPOINT;
|
|
405
|
+
try {
|
|
406
|
+
return await launcher.connect({ wsEndpoint });
|
|
407
|
+
} catch (error) {
|
|
408
|
+
if (persistedSession) await removePersistedAutomatorSession(projectPath);
|
|
409
|
+
throw error;
|
|
410
|
+
}
|
|
322
411
|
}
|
|
323
412
|
//#endregion
|
|
324
413
|
//#region src/i18n.ts
|
|
@@ -387,6 +476,7 @@ function readLangOption(argv) {
|
|
|
387
476
|
}
|
|
388
477
|
//#endregion
|
|
389
478
|
//#region src/cli/automator-session.ts
|
|
479
|
+
const sharedMiniProgramSessions = /* @__PURE__ */ new Map();
|
|
390
480
|
function normalizeMiniProgramConnectionError(error) {
|
|
391
481
|
if (isAutomatorLoginError(error)) {
|
|
392
482
|
logger_default.error(i18nText("检测到微信开发者工具登录状态失效,请先登录后重试。", "Wechat DevTools login has expired. Please login and retry."));
|
|
@@ -398,22 +488,106 @@ function normalizeMiniProgramConnectionError(error) {
|
|
|
398
488
|
logger_default.warn(i18nText("请在微信开发者工具中:设置 -> 安全设置 -> 开启服务端口", "Please enable service port in Wechat DevTools: Settings -> Security -> Service Port"));
|
|
399
489
|
return /* @__PURE__ */ new Error("DEVTOOLS_HTTP_PORT_ERROR");
|
|
400
490
|
}
|
|
491
|
+
if (isDevtoolsExtensionContextInvalidatedError(error)) {
|
|
492
|
+
logger_default.error(i18nText("微信开发者工具自动化上下文尚未就绪,通常是刚启动或正在重载。", "Wechat DevTools automation context is not ready yet, usually because the IDE has just started or is still reloading."));
|
|
493
|
+
logger_default.warn(i18nText("请稍后重试;若持续失败,关闭多余的开发者工具窗口后重试。", "Please retry shortly. If it keeps failing, close extra DevTools windows and try again."));
|
|
494
|
+
return /* @__PURE__ */ new Error("DEVTOOLS_EXTENSION_CONTEXT_INVALIDATED");
|
|
495
|
+
}
|
|
496
|
+
if (isAutomatorWsConnectError(error)) {
|
|
497
|
+
logger_default.error(i18nText("无法连接到当前项目的微信开发者工具自动化 websocket。", "Cannot connect to the Wechat DevTools automation websocket for the current project."));
|
|
498
|
+
logger_default.warn(i18nText("请确认当前打开的是目标项目;若之前跑过其他 e2e / screenshot 任务,关闭多余的微信开发者工具窗口,或结束残留的 `wechatwebdevtools cli auto --project ...` 进程后重试。", "Please confirm the current DevTools window is the target project. If you recently ran other e2e or screenshot tasks, close extra DevTools windows or stop stale `wechatwebdevtools cli auto --project ...` processes and retry."));
|
|
499
|
+
return /* @__PURE__ */ new Error("DEVTOOLS_WS_CONNECT_ERROR");
|
|
500
|
+
}
|
|
501
|
+
if (isAutomatorProtocolTimeoutError(error)) {
|
|
502
|
+
const method = getAutomatorProtocolTimeoutMethod(error) ?? "unknown";
|
|
503
|
+
logger_default.error(i18nText(`微信开发者工具在协议调用 ${method} 上超时,未按预期返回结果。`, `Wechat DevTools timed out while executing protocol method ${method} and did not return a result.`));
|
|
504
|
+
logger_default.warn(i18nText("这通常表示当前 DevTools 自动化会话已卡住、窗口不在目标项目、或当前 DevTools 版本对该协议调用无响应。请重开目标项目窗口后重试;若仍复现,优先记录当前 DevTools 版本与协议方法名继续排查。", "This usually means the current DevTools automation session is stuck, the window is not on the target project, or the current DevTools version is not responding to that protocol method. Reopen the target project window and retry. If it still reproduces, record the current DevTools version and protocol method name for follow-up debugging."));
|
|
505
|
+
return /* @__PURE__ */ new Error("DEVTOOLS_PROTOCOL_TIMEOUT");
|
|
506
|
+
}
|
|
401
507
|
return error instanceof Error ? error : new Error(String(error));
|
|
402
508
|
}
|
|
403
509
|
/**
|
|
404
510
|
* @description 建立 automator 会话,并统一处理常见连接错误提示。
|
|
405
511
|
*/
|
|
406
512
|
async function connectMiniProgram(options) {
|
|
407
|
-
try {
|
|
513
|
+
if (options.preferOpenedSession === false) try {
|
|
408
514
|
return await launchAutomator(options);
|
|
409
515
|
} catch (error) {
|
|
410
516
|
throw normalizeMiniProgramConnectionError(error);
|
|
411
517
|
}
|
|
518
|
+
try {
|
|
519
|
+
return await connectOpenedAutomator(options);
|
|
520
|
+
} catch (error) {
|
|
521
|
+
const normalizedOpenSessionError = normalizeMiniProgramConnectionError(error);
|
|
522
|
+
if (normalizedOpenSessionError instanceof Error && normalizedOpenSessionError.message === "DEVTOOLS_PROTOCOL_TIMEOUT") throw normalizedOpenSessionError;
|
|
523
|
+
try {
|
|
524
|
+
return await launchAutomator(options);
|
|
525
|
+
} catch (launchError) {
|
|
526
|
+
throw normalizeMiniProgramConnectionError(launchError);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* @description 获取指定项目的共享 automator 会话;若不存在则自动创建。
|
|
532
|
+
*/
|
|
533
|
+
async function acquireSharedMiniProgram(options) {
|
|
534
|
+
const existing = sharedMiniProgramSessions.get(options.projectPath);
|
|
535
|
+
if (existing) {
|
|
536
|
+
existing.refs += 1;
|
|
537
|
+
return await existing.session;
|
|
538
|
+
}
|
|
539
|
+
const session = connectMiniProgram(options);
|
|
540
|
+
const entry = {
|
|
541
|
+
refs: 1,
|
|
542
|
+
session
|
|
543
|
+
};
|
|
544
|
+
sharedMiniProgramSessions.set(options.projectPath, entry);
|
|
545
|
+
try {
|
|
546
|
+
return await session;
|
|
547
|
+
} catch (error) {
|
|
548
|
+
sharedMiniProgramSessions.delete(options.projectPath);
|
|
549
|
+
throw error;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* @description 释放指定项目的共享会话引用;会话对象会继续缓存,直到显式关闭或重置。
|
|
554
|
+
*/
|
|
555
|
+
function releaseSharedMiniProgram(projectPath) {
|
|
556
|
+
const entry = sharedMiniProgramSessions.get(projectPath);
|
|
557
|
+
if (!entry) return;
|
|
558
|
+
entry.refs = Math.max(0, entry.refs - 1);
|
|
559
|
+
}
|
|
560
|
+
/**
|
|
561
|
+
* @description 关闭并移除指定项目的共享 automator 会话。
|
|
562
|
+
*/
|
|
563
|
+
async function closeSharedMiniProgram(projectPath) {
|
|
564
|
+
const entry = sharedMiniProgramSessions.get(projectPath);
|
|
565
|
+
if (!entry) return;
|
|
566
|
+
sharedMiniProgramSessions.delete(projectPath);
|
|
567
|
+
(await entry.session.catch(() => null))?.disconnect();
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* @description 获取当前共享会话数量,供测试断言使用。
|
|
571
|
+
*/
|
|
572
|
+
function getSharedMiniProgramSessionCount() {
|
|
573
|
+
return sharedMiniProgramSessions.size;
|
|
412
574
|
}
|
|
413
575
|
/**
|
|
414
576
|
* @description 统一管理 automator 会话生命周期。
|
|
415
577
|
*/
|
|
416
578
|
async function withMiniProgram(options, runner) {
|
|
579
|
+
if (options.miniProgram) return await runner(options.miniProgram);
|
|
580
|
+
if (options.sharedSession) {
|
|
581
|
+
const miniProgram = await acquireSharedMiniProgram(options);
|
|
582
|
+
try {
|
|
583
|
+
return await runner(miniProgram);
|
|
584
|
+
} catch (error) {
|
|
585
|
+
await closeSharedMiniProgram(options.projectPath);
|
|
586
|
+
throw normalizeMiniProgramConnectionError(error);
|
|
587
|
+
} finally {
|
|
588
|
+
releaseSharedMiniProgram(options.projectPath);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
417
591
|
let miniProgram = null;
|
|
418
592
|
try {
|
|
419
593
|
miniProgram = await connectMiniProgram(options);
|
|
@@ -425,25 +599,112 @@ async function withMiniProgram(options, runner) {
|
|
|
425
599
|
}
|
|
426
600
|
}
|
|
427
601
|
//#endregion
|
|
602
|
+
//#region src/cli/fullPageScreenshot.ts
|
|
603
|
+
function decodeScreenshotBuffer(raw) {
|
|
604
|
+
const buffer = typeof raw === "string" ? Buffer.from(raw, "base64") : Buffer.from(raw);
|
|
605
|
+
if (buffer.length === 0) throw new Error("Failed to capture screenshot");
|
|
606
|
+
return buffer;
|
|
607
|
+
}
|
|
608
|
+
function toPositiveNumber(value) {
|
|
609
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
610
|
+
}
|
|
611
|
+
function createScrollPositions(totalHeight, viewportHeight) {
|
|
612
|
+
if (totalHeight <= viewportHeight) return [0];
|
|
613
|
+
const positions = [];
|
|
614
|
+
const lastStart = Math.max(totalHeight - viewportHeight, 0);
|
|
615
|
+
for (let scrollTop = 0; scrollTop < lastStart; scrollTop += viewportHeight) positions.push(scrollTop);
|
|
616
|
+
if (positions.at(-1) !== lastStart) positions.push(lastStart);
|
|
617
|
+
return positions;
|
|
618
|
+
}
|
|
619
|
+
function cropPngRows(source, startRow, rowCount) {
|
|
620
|
+
const cropped = new PNG({
|
|
621
|
+
width: source.width,
|
|
622
|
+
height: rowCount
|
|
623
|
+
});
|
|
624
|
+
const bytesPerRow = source.width * 4;
|
|
625
|
+
for (let row = 0; row < rowCount; row += 1) {
|
|
626
|
+
const sourceStart = (startRow + row) * bytesPerRow;
|
|
627
|
+
const sourceEnd = sourceStart + bytesPerRow;
|
|
628
|
+
source.data.copy(cropped.data, row * bytesPerRow, sourceStart, sourceEnd);
|
|
629
|
+
}
|
|
630
|
+
return cropped;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* @description 通过多次滚动和拼接生成整页长截图。
|
|
634
|
+
*/
|
|
635
|
+
async function captureFullPageScreenshotBuffer(options) {
|
|
636
|
+
const { miniProgram, timeoutMs, runWithTimeout, screenshotTimeoutMessage } = options;
|
|
637
|
+
const page = await miniProgram.currentPage();
|
|
638
|
+
const pageSize = await page.size();
|
|
639
|
+
const systemInfo = await miniProgram.systemInfo();
|
|
640
|
+
const pageHeight = toPositiveNumber(pageSize.height);
|
|
641
|
+
const viewportHeight = toPositiveNumber(systemInfo.windowHeight);
|
|
642
|
+
if (!pageHeight || !viewportHeight) return decodeScreenshotBuffer(await runWithTimeout(miniProgram.screenshot(), timeoutMs, screenshotTimeoutMessage, "DEVTOOLS_SCREENSHOT_TIMEOUT"));
|
|
643
|
+
const segments = [];
|
|
644
|
+
const positions = createScrollPositions(pageHeight, viewportHeight);
|
|
645
|
+
let coveredUntil = 0;
|
|
646
|
+
let scale = 1;
|
|
647
|
+
for (const scrollTop of positions) {
|
|
648
|
+
await miniProgram.pageScrollTo(scrollTop);
|
|
649
|
+
await page.waitFor(150);
|
|
650
|
+
const rawScreenshot = await runWithTimeout(miniProgram.screenshot(), timeoutMs, screenshotTimeoutMessage, "DEVTOOLS_SCREENSHOT_TIMEOUT");
|
|
651
|
+
const png = PNG.sync.read(decodeScreenshotBuffer(rawScreenshot));
|
|
652
|
+
if (viewportHeight > 0) scale = png.height / viewportHeight;
|
|
653
|
+
const visibleEnd = Math.min(scrollTop + viewportHeight, pageHeight);
|
|
654
|
+
const cropTopCss = Math.max(coveredUntil - scrollTop, 0);
|
|
655
|
+
const segmentHeightCss = Math.max(visibleEnd - scrollTop - cropTopCss, 0);
|
|
656
|
+
if (segmentHeightCss <= 0) continue;
|
|
657
|
+
const cropTopRows = Math.min(Math.max(Math.round(cropTopCss * scale), 0), png.height);
|
|
658
|
+
const segmentRows = Math.min(Math.max(Math.round(segmentHeightCss * scale), 1), png.height - cropTopRows);
|
|
659
|
+
segments.push(cropPngRows(png, cropTopRows, segmentRows));
|
|
660
|
+
coveredUntil = visibleEnd;
|
|
661
|
+
}
|
|
662
|
+
if (segments.length === 0) throw new Error("Failed to capture screenshot");
|
|
663
|
+
const width = segments[0].width;
|
|
664
|
+
const merged = new PNG({
|
|
665
|
+
width,
|
|
666
|
+
height: segments.reduce((sum, segment) => sum + segment.height, 0)
|
|
667
|
+
});
|
|
668
|
+
const bytesPerRow = width * 4;
|
|
669
|
+
let offsetY = 0;
|
|
670
|
+
for (const segment of segments) {
|
|
671
|
+
if (segment.width !== width) throw new Error("Full-page screenshots have inconsistent widths");
|
|
672
|
+
for (let row = 0; row < segment.height; row += 1) {
|
|
673
|
+
const sourceStart = row * bytesPerRow;
|
|
674
|
+
const sourceEnd = sourceStart + bytesPerRow;
|
|
675
|
+
segment.data.copy(merged.data, (offsetY + row) * bytesPerRow, sourceStart, sourceEnd);
|
|
676
|
+
}
|
|
677
|
+
offsetY += segment.height;
|
|
678
|
+
}
|
|
679
|
+
return PNG.sync.write(merged);
|
|
680
|
+
}
|
|
681
|
+
//#endregion
|
|
428
682
|
//#region src/cli/commands.ts
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
683
|
+
function createTimeoutError(message, code) {
|
|
684
|
+
const error = new Error(message);
|
|
685
|
+
error.code = code;
|
|
686
|
+
return error;
|
|
687
|
+
}
|
|
688
|
+
function normalizePagePath(page) {
|
|
689
|
+
return page.startsWith("/") ? page : `/${page}`;
|
|
690
|
+
}
|
|
691
|
+
function sleep(ms) {
|
|
692
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
693
|
+
}
|
|
694
|
+
function withCommandTimeout(task, timeoutMs, message, code) {
|
|
695
|
+
return new Promise((resolve, reject) => {
|
|
696
|
+
const timeout = setTimeout(() => {
|
|
697
|
+
reject(createTimeoutError(message, code));
|
|
698
|
+
}, timeoutMs);
|
|
699
|
+
task.then((value) => {
|
|
700
|
+
clearTimeout(timeout);
|
|
701
|
+
resolve(value);
|
|
702
|
+
}).catch((error) => {
|
|
703
|
+
clearTimeout(timeout);
|
|
704
|
+
reject(error);
|
|
705
|
+
});
|
|
706
|
+
});
|
|
707
|
+
}
|
|
447
708
|
async function runRouteCommand(options, startMessage, successMessage, action) {
|
|
448
709
|
await withMiniProgram(options, async (miniProgram) => {
|
|
449
710
|
logger_default.info(startMessage);
|
|
@@ -581,7 +842,7 @@ async function audit(options) {
|
|
|
581
842
|
logger_default.info(i18nText("正在执行体验审计...", "Running experience audit..."));
|
|
582
843
|
const result = await miniProgram.stopAudits();
|
|
583
844
|
if (options.outputPath) {
|
|
584
|
-
await fs
|
|
845
|
+
await fs.writeFile(options.outputPath, JSON.stringify(result, null, 2));
|
|
585
846
|
logger_default.success(i18nText(`审计报告已保存到 ${colors.cyan(options.outputPath)}`, `Audit report saved to ${colors.cyan(options.outputPath)}`));
|
|
586
847
|
return result;
|
|
587
848
|
}
|
|
@@ -594,14 +855,27 @@ async function audit(options) {
|
|
|
594
855
|
*/
|
|
595
856
|
async function captureScreenshotBuffer(options) {
|
|
596
857
|
return await withMiniProgram(options, async (miniProgram) => {
|
|
597
|
-
|
|
858
|
+
const commandTimeout = options.timeout ?? 3e4;
|
|
859
|
+
const screenshotTimeoutMessage = i18nText(`截图请求在 ${commandTimeout}ms 内未收到 DevTools 回包,请检查当前微信开发者工具是否仍停留在目标项目;若近期执行过其他 e2e / screenshot 任务,关闭多余窗口并清理残留 automator 会话后重试。`, `Screenshot request did not receive a DevTools response within ${commandTimeout}ms. Check that the current Wechat DevTools window is still the target project. If you recently ran other e2e or screenshot tasks, close extra windows and clean up stale automator sessions before retrying.`);
|
|
860
|
+
if (!options.miniProgram) logger_default.info(i18nText(`正在连接 DevTools:${colors.cyan(options.projectPath)}...`, `Connecting to DevTools at ${colors.cyan(options.projectPath)}...`));
|
|
598
861
|
if (options.page) {
|
|
599
|
-
|
|
600
|
-
|
|
862
|
+
const normalizedPage = normalizePagePath(options.page);
|
|
863
|
+
logger_default.info(i18nText(`正在跳转页面 ${colors.cyan(normalizedPage)}...`, `Navigating to page ${colors.cyan(normalizedPage)}...`));
|
|
864
|
+
await miniProgram.reLaunch(normalizedPage);
|
|
865
|
+
if (options.fullPage) await sleep(1e3);
|
|
866
|
+
}
|
|
867
|
+
if (options.fullPage) {
|
|
868
|
+
logger_default.info(i18nText("正在生成整页长截图...", "Capturing full-page screenshot..."));
|
|
869
|
+
return await captureFullPageScreenshotBuffer({
|
|
870
|
+
miniProgram,
|
|
871
|
+
timeoutMs: commandTimeout,
|
|
872
|
+
runWithTimeout: withCommandTimeout,
|
|
873
|
+
screenshotTimeoutMessage
|
|
874
|
+
});
|
|
601
875
|
}
|
|
602
876
|
logger_default.info(i18nText("正在截图...", "Taking screenshot..."));
|
|
603
|
-
const screenshot = await miniProgram.screenshot();
|
|
604
|
-
const buffer = typeof screenshot === "string" ? Buffer
|
|
877
|
+
const screenshot = await withCommandTimeout(miniProgram.screenshot(), commandTimeout, screenshotTimeoutMessage, "DEVTOOLS_SCREENSHOT_TIMEOUT");
|
|
878
|
+
const buffer = typeof screenshot === "string" ? Buffer.from(screenshot, "base64") : Buffer.from(screenshot);
|
|
605
879
|
if (buffer.length === 0) throw new Error(i18nText("截图失败", "Failed to capture screenshot"));
|
|
606
880
|
return buffer;
|
|
607
881
|
});
|
|
@@ -610,10 +884,23 @@ async function captureScreenshotBuffer(options) {
|
|
|
610
884
|
* @description 获取当前小程序截图。
|
|
611
885
|
*/
|
|
612
886
|
async function takeScreenshot(options) {
|
|
613
|
-
|
|
887
|
+
let screenshotBuffer;
|
|
888
|
+
try {
|
|
889
|
+
screenshotBuffer = await captureScreenshotBuffer(options);
|
|
890
|
+
} catch (error) {
|
|
891
|
+
const isProtocolTimeout = error instanceof Error && error.message === "DEVTOOLS_PROTOCOL_TIMEOUT";
|
|
892
|
+
if (!Boolean(options.sharedSession && !options.miniProgram && isProtocolTimeout)) throw error;
|
|
893
|
+
await closeSharedMiniProgram(options.projectPath);
|
|
894
|
+
logger_default.warn(i18nText("当前共享 DevTools 会话截图超时,正在改用全新自动化会话重试一次...", "The current shared DevTools session timed out while capturing screenshot. Retrying once with a fresh automation session..."));
|
|
895
|
+
screenshotBuffer = await captureScreenshotBuffer({
|
|
896
|
+
...options,
|
|
897
|
+
preferOpenedSession: false,
|
|
898
|
+
sharedSession: false
|
|
899
|
+
});
|
|
900
|
+
}
|
|
614
901
|
const base64 = screenshotBuffer.toString("base64");
|
|
615
902
|
if (options.outputPath) {
|
|
616
|
-
await fs
|
|
903
|
+
await fs.writeFile(options.outputPath, screenshotBuffer);
|
|
617
904
|
logger_default.success(i18nText(`截图已保存到 ${colors.cyan(options.outputPath)}`, `Screenshot saved to ${colors.cyan(options.outputPath)}`));
|
|
618
905
|
return { path: options.outputPath };
|
|
619
906
|
}
|
|
@@ -631,4 +918,4 @@ async function remote(options) {
|
|
|
631
918
|
});
|
|
632
919
|
}
|
|
633
920
|
//#endregion
|
|
634
|
-
export {
|
|
921
|
+
export { isAutomatorProtocolTimeoutError as A, createLocaleConfig as B, configureLocaleFromArgv as C, formatAutomatorLoginError as D, connectOpenedAutomator as E, launchAutomator as F, defaultCustomConfigFilePath as G, readCustomConfig as H, resolveCliPath as I, getDefaultCliPath as J, resolvePath as K, getConfig as L, isDevtoolsExtensionContextInvalidatedError as M, isDevtoolsHttpPortError as N, getAutomatorProtocolTimeoutMethod as O, isRetryableAutomatorLaunchError as P, logger_default as Q, getConfiguredLocale as R, withMiniProgram as S, validateLocaleOption as T, removeCustomConfigKey as U, overwriteCustomConfig as V, defaultCustomConfigDirPath as W, operatingSystemName as X, isOperatingSystemSupported as Y, colors as Z, acquireSharedMiniProgram as _, navigateBack as a, getSharedMiniProgramSessionCount as b, pageStack as c, remote as d, scrollTo as f, tap as g, takeScreenshot as h, input as i, isAutomatorWsConnectError as j, isAutomatorLoginError as k, reLaunch as l, systemInfo as m, captureScreenshotBuffer as n, navigateTo as o, switchTab as p, SupportedPlatformsMap as q, currentPage as r, pageData as s, audit as t, redirectTo as u, closeSharedMiniProgram as v, i18nText as w, releaseSharedMiniProgram as x, connectMiniProgram as y, createCustomConfig as z };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Element, MiniProgram, Page } from "@weapp-vite/miniprogram-automator";
|
|
2
1
|
import { Buffer } from "node:buffer";
|
|
2
|
+
import * as _weapp_vite_miniprogram_automator0 from "@weapp-vite/miniprogram-automator";
|
|
3
|
+
import { Element, MiniProgram, Page } from "@weapp-vite/miniprogram-automator";
|
|
3
4
|
import * as cac$1 from "cac";
|
|
4
5
|
import * as execa from "execa";
|
|
5
6
|
|
|
@@ -8,11 +9,33 @@ interface AutomatorOptions {
|
|
|
8
9
|
projectPath: string;
|
|
9
10
|
timeout?: number;
|
|
10
11
|
cliPath?: string;
|
|
12
|
+
trustProject?: boolean;
|
|
13
|
+
preferOpenedSession?: boolean;
|
|
11
14
|
}
|
|
12
15
|
/**
|
|
13
16
|
* @description 判断错误是否属于开发者工具服务端口不可用。
|
|
14
17
|
*/
|
|
15
18
|
declare function isDevtoolsHttpPortError(error: unknown): boolean;
|
|
19
|
+
/**
|
|
20
|
+
* @description 判断错误是否属于开发者工具 automator 扩展上下文尚未就绪。
|
|
21
|
+
*/
|
|
22
|
+
declare function isDevtoolsExtensionContextInvalidatedError(error: unknown): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* @description 判断错误是否属于可重试的 automator 启动抖动。
|
|
25
|
+
*/
|
|
26
|
+
declare function isRetryableAutomatorLaunchError(error: unknown): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* @description 判断错误是否属于开发者工具 websocket 连接失败。
|
|
29
|
+
*/
|
|
30
|
+
declare function isAutomatorWsConnectError(error: unknown): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* @description 判断错误是否属于开发者工具协议调用超时。
|
|
33
|
+
*/
|
|
34
|
+
declare function isAutomatorProtocolTimeoutError(error: unknown): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* @description 提取协议超时的方法名。
|
|
37
|
+
*/
|
|
38
|
+
declare function getAutomatorProtocolTimeoutMethod(error: unknown): string | undefined;
|
|
16
39
|
/**
|
|
17
40
|
* @description 判断错误是否属于开发者工具登录失效。
|
|
18
41
|
*/
|
|
@@ -25,6 +48,10 @@ declare function formatAutomatorLoginError(error: unknown): string;
|
|
|
25
48
|
* @description 基于当前配置解析 CLI 路径,并通过现代化 automator 入口启动会话。
|
|
26
49
|
*/
|
|
27
50
|
declare function launchAutomator(options: AutomatorOptions): Promise<any>;
|
|
51
|
+
/**
|
|
52
|
+
* @description 连接当前项目已打开的开发者工具自动化会话,不触发新的 IDE 拉起。
|
|
53
|
+
*/
|
|
54
|
+
declare function connectOpenedAutomator(options: AutomatorOptions): Promise<_weapp_vite_miniprogram_automator0.MiniProgram>;
|
|
28
55
|
//#endregion
|
|
29
56
|
//#region src/cli/automator-argv.d.ts
|
|
30
57
|
interface ParsedAutomatorArgs {
|
|
@@ -47,10 +74,6 @@ declare function readOptionValue(argv: readonly string[], optionName: string): s
|
|
|
47
74
|
declare function removeOption(argv: readonly string[], optionName: string): string[];
|
|
48
75
|
//#endregion
|
|
49
76
|
//#region src/cli/automator-session.d.ts
|
|
50
|
-
interface AutomatorSessionOptions {
|
|
51
|
-
projectPath: string;
|
|
52
|
-
timeout?: number;
|
|
53
|
-
}
|
|
54
77
|
interface MiniProgramEventMap {
|
|
55
78
|
console: (payload: unknown) => void;
|
|
56
79
|
exception: (payload: unknown) => void;
|
|
@@ -60,10 +83,33 @@ type MiniProgramPage = InstanceType<typeof Page>;
|
|
|
60
83
|
type MiniProgramElement = InstanceType<typeof Element> & {
|
|
61
84
|
input?: (value: string) => Promise<void>;
|
|
62
85
|
};
|
|
86
|
+
interface AutomatorSessionOptions {
|
|
87
|
+
miniProgram?: MiniProgramLike;
|
|
88
|
+
preferOpenedSession?: boolean;
|
|
89
|
+
projectPath: string;
|
|
90
|
+
sharedSession?: boolean;
|
|
91
|
+
timeout?: number;
|
|
92
|
+
}
|
|
63
93
|
/**
|
|
64
94
|
* @description 建立 automator 会话,并统一处理常见连接错误提示。
|
|
65
95
|
*/
|
|
66
96
|
declare function connectMiniProgram(options: AutomatorSessionOptions): Promise<MiniProgramLike>;
|
|
97
|
+
/**
|
|
98
|
+
* @description 获取指定项目的共享 automator 会话;若不存在则自动创建。
|
|
99
|
+
*/
|
|
100
|
+
declare function acquireSharedMiniProgram(options: AutomatorSessionOptions): Promise<MiniProgramLike>;
|
|
101
|
+
/**
|
|
102
|
+
* @description 释放指定项目的共享会话引用;会话对象会继续缓存,直到显式关闭或重置。
|
|
103
|
+
*/
|
|
104
|
+
declare function releaseSharedMiniProgram(projectPath: string): void;
|
|
105
|
+
/**
|
|
106
|
+
* @description 关闭并移除指定项目的共享 automator 会话。
|
|
107
|
+
*/
|
|
108
|
+
declare function closeSharedMiniProgram(projectPath: string): Promise<void>;
|
|
109
|
+
/**
|
|
110
|
+
* @description 获取当前共享会话数量,供测试断言使用。
|
|
111
|
+
*/
|
|
112
|
+
declare function getSharedMiniProgramSessionCount(): number;
|
|
67
113
|
/**
|
|
68
114
|
* @description 统一管理 automator 会话生命周期。
|
|
69
115
|
*/
|
|
@@ -106,6 +152,7 @@ interface AuditOptions extends AutomatorCommandOptions {
|
|
|
106
152
|
interface ScreenshotOptions extends AutomatorCommandOptions {
|
|
107
153
|
outputPath?: string;
|
|
108
154
|
page?: string;
|
|
155
|
+
fullPage?: boolean;
|
|
109
156
|
}
|
|
110
157
|
interface ScreenshotResult {
|
|
111
158
|
base64?: string;
|
|
@@ -460,4 +507,4 @@ declare function execute(cliPath: string, argv: string[], options?: ExecuteOptio
|
|
|
460
507
|
*/
|
|
461
508
|
declare function resolvePath(filePath: string): string;
|
|
462
509
|
//#endregion
|
|
463
|
-
export { AUTOMATOR_COMMAND_NAMES, ArgvTransform, AuditOptions, AutomatorCommandOptions, AutomatorOptions, AutomatorSessionOptions, type BaseConfig, CONFIG_COMMAND_NAME, type ConfigSource, ForwardConsoleEvent, ForwardConsoleLogLevel, ForwardConsoleOptions, ForwardConsoleSession, InputOptions, LoginRetryMode, MINIDEV_NAMESPACE_COMMAND_NAMES, MiniProgramElement, MiniProgramEventMap, MiniProgramLike, MiniProgramPage, NavigateOptions, PageDataOptions, PageInfoOptions, ParsedAutomatorArgs, RemoteOptions, type ResolvedConfig, RetryKeypressOptions, RetryPromptResult, type ScreenshotOptions, type ScreenshotResult, ScrollOptions, SelectorOptions, SupportedPlatform, SupportedPlatformsMap, TapOptions, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES, WECHAT_CLI_COMMAND_NAMES, audit, captureScreenshotBuffer, connectMiniProgram, createAlias, createCli, createCustomConfig, createLocaleConfig, createPathCompat, createWechatIdeLoginRequiredExitError, currentPage, defaultCustomConfigDirPath, defaultCustomConfigFilePath, execute, extractExecutionErrorText, formatAutomatorLoginError, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getAutomatorCommandHelp, getConfig, getConfiguredLocale, getDefaultCliPath, handleConfigCommand, input, isAutomatorCommand, isAutomatorLoginError, isDevtoolsHttpPortError, isOperatingSystemSupported, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, launchAutomator, navigateBack, navigateTo, operatingSystemName, overwriteCustomConfig, pageData, pageStack, parse, parseAutomatorArgs, parseCompareArgs, parseScreenshotArgs, printCompareHelp, printScreenshotHelp, promptForCliPath, reLaunch, readCustomConfig, readOptionValue, redirectTo, remote, removeCustomConfigKey, removeOption, resolveCliPath, resolvePath, runAutomatorCommand, runMinidev, runWechatCliWithRetry, scrollTo, startForwardConsole, switchTab, systemInfo, takeScreenshot, tap, transformArgv, validateWechatCliCommandArgs, waitForRetryKeypress, withMiniProgram };
|
|
510
|
+
export { AUTOMATOR_COMMAND_NAMES, ArgvTransform, AuditOptions, AutomatorCommandOptions, AutomatorOptions, AutomatorSessionOptions, type BaseConfig, CONFIG_COMMAND_NAME, type ConfigSource, ForwardConsoleEvent, ForwardConsoleLogLevel, ForwardConsoleOptions, ForwardConsoleSession, InputOptions, LoginRetryMode, MINIDEV_NAMESPACE_COMMAND_NAMES, MiniProgramElement, MiniProgramEventMap, MiniProgramLike, MiniProgramPage, NavigateOptions, PageDataOptions, PageInfoOptions, ParsedAutomatorArgs, RemoteOptions, type ResolvedConfig, RetryKeypressOptions, RetryPromptResult, type ScreenshotOptions, type ScreenshotResult, ScrollOptions, SelectorOptions, SupportedPlatform, SupportedPlatformsMap, TapOptions, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES, WECHAT_CLI_COMMAND_NAMES, acquireSharedMiniProgram, audit, captureScreenshotBuffer, closeSharedMiniProgram, connectMiniProgram, connectOpenedAutomator, createAlias, createCli, createCustomConfig, createLocaleConfig, createPathCompat, createWechatIdeLoginRequiredExitError, currentPage, defaultCustomConfigDirPath, defaultCustomConfigFilePath, execute, extractExecutionErrorText, formatAutomatorLoginError, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getAutomatorCommandHelp, getAutomatorProtocolTimeoutMethod, getConfig, getConfiguredLocale, getDefaultCliPath, getSharedMiniProgramSessionCount, handleConfigCommand, input, isAutomatorCommand, isAutomatorLoginError, isAutomatorProtocolTimeoutError, isAutomatorWsConnectError, isDevtoolsExtensionContextInvalidatedError, isDevtoolsHttpPortError, isOperatingSystemSupported, isRetryableAutomatorLaunchError, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, launchAutomator, navigateBack, navigateTo, operatingSystemName, overwriteCustomConfig, pageData, pageStack, parse, parseAutomatorArgs, parseCompareArgs, parseScreenshotArgs, printCompareHelp, printScreenshotHelp, promptForCliPath, reLaunch, readCustomConfig, readOptionValue, redirectTo, releaseSharedMiniProgram, remote, removeCustomConfigKey, removeOption, resolveCliPath, resolvePath, runAutomatorCommand, runMinidev, runWechatCliWithRetry, scrollTo, startForwardConsole, switchTab, systemInfo, takeScreenshot, tap, transformArgv, validateWechatCliCommandArgs, waitForRetryKeypress, withMiniProgram };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { A as
|
|
2
|
-
import { A as parseCompareArgs, C as isWeappIdeTopLevelCommand, D as runAutomatorCommand, E as isAutomatorCommand, M as parseAutomatorArgs, N as readOptionValue, O as parseScreenshotArgs, P as removeOption, S as WECHAT_CLI_COMMAND_NAMES, T as getAutomatorCommandHelp, _ as handleConfigCommand, a as createWechatIdeLoginRequiredExitError, b as MINIDEV_NAMESPACE_COMMAND_NAMES, c as formatWechatIdeLoginRequiredError, d as runMinidev, f as execute, g as startForwardConsole, h as transformArgv, i as runWechatCliWithRetry, j as printCompareHelp, k as printScreenshotHelp, l as isWechatIdeLoginRequiredError, m as createPathCompat, n as parse, o as extractExecutionErrorText, p as createAlias, r as validateWechatCliCommandArgs, s as formatRetryHotkeyPrompt, t as createCli, u as waitForRetryKeypress, v as promptForCliPath, w as AUTOMATOR_COMMAND_NAMES, x as WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES, y as CONFIG_COMMAND_NAME } from "./cli-
|
|
3
|
-
export { AUTOMATOR_COMMAND_NAMES, CONFIG_COMMAND_NAME, MINIDEV_NAMESPACE_COMMAND_NAMES, SupportedPlatformsMap, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES, WECHAT_CLI_COMMAND_NAMES, audit, captureScreenshotBuffer, connectMiniProgram, createAlias, createCli, createCustomConfig, createLocaleConfig, createPathCompat, createWechatIdeLoginRequiredExitError, currentPage, defaultCustomConfigDirPath, defaultCustomConfigFilePath, execute, extractExecutionErrorText, formatAutomatorLoginError, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getAutomatorCommandHelp, getConfig, getConfiguredLocale, getDefaultCliPath, handleConfigCommand, input, isAutomatorCommand, isAutomatorLoginError, isDevtoolsHttpPortError, isOperatingSystemSupported, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, launchAutomator, navigateBack, navigateTo, operatingSystemName, overwriteCustomConfig, pageData, pageStack, parse, parseAutomatorArgs, parseCompareArgs, parseScreenshotArgs, printCompareHelp, printScreenshotHelp, promptForCliPath, reLaunch, readCustomConfig, readOptionValue, redirectTo, remote, removeCustomConfigKey, removeOption, resolveCliPath, resolvePath, runAutomatorCommand, runMinidev, runWechatCliWithRetry, scrollTo, startForwardConsole, switchTab, systemInfo, takeScreenshot, tap, transformArgv, validateWechatCliCommandArgs, waitForRetryKeypress, withMiniProgram };
|
|
1
|
+
import { A as isAutomatorProtocolTimeoutError, B as createLocaleConfig, D as formatAutomatorLoginError, E as connectOpenedAutomator, F as launchAutomator, G as defaultCustomConfigFilePath, H as readCustomConfig, I as resolveCliPath, J as getDefaultCliPath, K as resolvePath, L as getConfig, M as isDevtoolsExtensionContextInvalidatedError, N as isDevtoolsHttpPortError, O as getAutomatorProtocolTimeoutMethod, P as isRetryableAutomatorLaunchError, R as getConfiguredLocale, S as withMiniProgram, U as removeCustomConfigKey, V as overwriteCustomConfig, W as defaultCustomConfigDirPath, X as operatingSystemName, Y as isOperatingSystemSupported, _ as acquireSharedMiniProgram, a as navigateBack, b as getSharedMiniProgramSessionCount, c as pageStack, d as remote, f as scrollTo, g as tap, h as takeScreenshot, i as input, j as isAutomatorWsConnectError, k as isAutomatorLoginError, l as reLaunch, m as systemInfo, n as captureScreenshotBuffer, o as navigateTo, p as switchTab, q as SupportedPlatformsMap, r as currentPage, s as pageData, t as audit, u as redirectTo, v as closeSharedMiniProgram, x as releaseSharedMiniProgram, y as connectMiniProgram, z as createCustomConfig } from "./commands--vppy2pX.js";
|
|
2
|
+
import { A as parseCompareArgs, C as isWeappIdeTopLevelCommand, D as runAutomatorCommand, E as isAutomatorCommand, M as parseAutomatorArgs, N as readOptionValue, O as parseScreenshotArgs, P as removeOption, S as WECHAT_CLI_COMMAND_NAMES, T as getAutomatorCommandHelp, _ as handleConfigCommand, a as createWechatIdeLoginRequiredExitError, b as MINIDEV_NAMESPACE_COMMAND_NAMES, c as formatWechatIdeLoginRequiredError, d as runMinidev, f as execute, g as startForwardConsole, h as transformArgv, i as runWechatCliWithRetry, j as printCompareHelp, k as printScreenshotHelp, l as isWechatIdeLoginRequiredError, m as createPathCompat, n as parse, o as extractExecutionErrorText, p as createAlias, r as validateWechatCliCommandArgs, s as formatRetryHotkeyPrompt, t as createCli, u as waitForRetryKeypress, v as promptForCliPath, w as AUTOMATOR_COMMAND_NAMES, x as WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES, y as CONFIG_COMMAND_NAME } from "./cli-DKrUhSmB.js";
|
|
3
|
+
export { AUTOMATOR_COMMAND_NAMES, CONFIG_COMMAND_NAME, MINIDEV_NAMESPACE_COMMAND_NAMES, SupportedPlatformsMap, WEAPP_IDE_TOP_LEVEL_COMMAND_NAMES, WECHAT_CLI_COMMAND_NAMES, acquireSharedMiniProgram, audit, captureScreenshotBuffer, closeSharedMiniProgram, connectMiniProgram, connectOpenedAutomator, createAlias, createCli, createCustomConfig, createLocaleConfig, createPathCompat, createWechatIdeLoginRequiredExitError, currentPage, defaultCustomConfigDirPath, defaultCustomConfigFilePath, execute, extractExecutionErrorText, formatAutomatorLoginError, formatRetryHotkeyPrompt, formatWechatIdeLoginRequiredError, getAutomatorCommandHelp, getAutomatorProtocolTimeoutMethod, getConfig, getConfiguredLocale, getDefaultCliPath, getSharedMiniProgramSessionCount, handleConfigCommand, input, isAutomatorCommand, isAutomatorLoginError, isAutomatorProtocolTimeoutError, isAutomatorWsConnectError, isDevtoolsExtensionContextInvalidatedError, isDevtoolsHttpPortError, isOperatingSystemSupported, isRetryableAutomatorLaunchError, isWeappIdeTopLevelCommand, isWechatIdeLoginRequiredError, launchAutomator, navigateBack, navigateTo, operatingSystemName, overwriteCustomConfig, pageData, pageStack, parse, parseAutomatorArgs, parseCompareArgs, parseScreenshotArgs, printCompareHelp, printScreenshotHelp, promptForCliPath, reLaunch, readCustomConfig, readOptionValue, redirectTo, releaseSharedMiniProgram, remote, removeCustomConfigKey, removeOption, resolveCliPath, resolvePath, runAutomatorCommand, runMinidev, runWechatCliWithRetry, scrollTo, startForwardConsole, switchTab, systemInfo, takeScreenshot, tap, transformArgv, validateWechatCliCommandArgs, waitForRetryKeypress, withMiniProgram };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "weapp-ide-cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.2.
|
|
4
|
+
"version": "5.2.1",
|
|
5
5
|
"description": "让微信开发者工具,用起来更加方便!",
|
|
6
6
|
"author": "ice breaker <1324318532@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
"pngjs": "^7.0.0",
|
|
70
70
|
"@weapp-core/logger": "^3.1.1",
|
|
71
71
|
"@weapp-core/shared": "^3.0.3",
|
|
72
|
-
"@weapp-vite/miniprogram-automator": "1.0.
|
|
72
|
+
"@weapp-vite/miniprogram-automator": "1.0.2"
|
|
73
73
|
},
|
|
74
74
|
"scripts": {
|
|
75
75
|
"dev": "tsdown -w --sourcemap",
|