@nekosu/maa-tools 1.0.5 → 1.0.7

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/index.d.mts CHANGED
@@ -2,7 +2,7 @@
2
2
  import { DiagnosticType } from "@nekosu/maa-pipeline-manager";
3
3
  import { LocaleType } from "@nekosu/maa-locale";
4
4
 
5
- //#region pkgs/maa-tools/src/types/config.d.ts
5
+ //#region src/types/config.d.ts
6
6
  type BaseConfig = {
7
7
  cwd?: string;
8
8
  mode?: 'stdio' | 'github' | 'json';
@@ -34,7 +34,7 @@ type TestCases = {
34
34
  type TestConfig = {
35
35
  interfacePath: string;
36
36
  casesCwd?: string;
37
- cases: TestCases[];
37
+ cases: TestCases[] | (() => Promise<TestCases[]>);
38
38
  job?: number;
39
39
  maxNodePerJob?: number;
40
40
  };
@@ -43,17 +43,21 @@ type FullConfig = BaseConfig & {
43
43
  test?: TestConfig;
44
44
  };
45
45
  //#endregion
46
- //#region pkgs/maa-tools/src/check/index.d.ts
46
+ //#region src/check/index.d.ts
47
47
  declare function runCheck(cfg: FullConfig): Promise<boolean>;
48
48
  //#endregion
49
- //#region pkgs/maa-tools/src/test/index.d.ts
49
+ //#region src/test/index.d.ts
50
50
  declare function runTest(cfg: FullConfig): Promise<boolean>;
51
51
  //#endregion
52
- //#region pkgs/maa-tools/src/cli.d.ts
52
+ //#region src/cli.d.ts
53
53
  declare function runCli(cmd: string, cfg: string | FullConfig): Promise<boolean>;
54
54
  //#endregion
55
- //#region pkgs/maa-tools/src/utils/config.d.ts
56
- declare function loadConfig(file: string): Promise<FullConfig>;
55
+ //#region src/utils/config.d.ts
56
+ declare function loadConfig(file: string): Promise<FullConfig | null>;
57
57
  //#endregion
58
- export { BaseConfig, CheckConfig, FullConfig, TestCases, TestConfig, loadConfig, runCheck, runCli, runTest };
58
+ //#region src/utils/tools.d.ts
59
+ declare function loadTestCases(file: string): Promise<TestCases | null>;
60
+ declare function loadAllTestCases(folder: string, pattern: string): Promise<[testCases: TestCases[], failFiles: string[]]>;
61
+ //#endregion
62
+ export { BaseConfig, CheckConfig, FullConfig, TestCases, TestConfig, loadAllTestCases, loadConfig, loadTestCases, runCheck, runCli, runTest };
59
63
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/config.ts","../src/check/index.ts","../src/test/index.ts","../src/cli.ts","../src/utils/config.ts"],"mappings":";;;;;KAGY,UAAA;EACV,GAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA,GAAS,UAAA;EAET,UAAA;EACA,QAAA;EAEA,cAAA;AAAA;AAAA,KAKU,WAAA;EACV,aAAA;EAEA,QAAA,GAAW,OAAA,CAAQ,MAAA,CAAO,cAAA;AAAA;AAAA,KAGhB,SAAA;EACV,OAAA;IACE,IAAA;IACA,QAAA;IACA,UAAA;IACA,SAAA;EAAA;EAEF,KAAA;IACE,KAAA;IACA,IAAA;MAGM,IAAA;MACA,GAAA,EAAK,GAAA,CAAI,IAAA;IAAA;EAAA;AAAA;AAAA,KAMP,UAAA;EACV,aAAA;EACA,QAAA;EACA,KAAA,EAAO,SAAA;EAEP,GAAA;EACA,aAAA;AAAA;AAAA,KAGU,UAAA,GAAa,UAAA;EACvB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,UAAA;AAAA;;;iBCrCa,QAAA,CAAS,GAAA,EAAK,UAAA,GAAa,OAAA;;;iBCO3B,OAAA,CAAQ,GAAA,EAAK,UAAA,GAAU,OAAA;;;iBCAvB,MAAA,CAAO,GAAA,UAAa,GAAA,WAAc,UAAA,GAAU,OAAA;;;iBClB5C,UAAA,CAAW,IAAA,WAAY,OAAA,CAAA,UAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types/config.ts","../src/check/index.ts","../src/test/index.ts","../src/cli.ts","../src/utils/config.ts","../src/utils/tools.ts"],"mappings":";;;;;KAGY,UAAA;EACV,GAAA;EACA,IAAA;EACA,IAAA;EACA,MAAA,GAAS,UAAA;EAET,UAAA;EACA,QAAA;EAEA,cAAA;AAAA;AAAA,KAKU,WAAA;EACV,aAAA;EAEA,QAAA,GAAW,OAAA,CAAQ,MAAA,CAAO,cAAA;AAAA;AAAA,KAGhB,SAAA;EACV,OAAA;IACE,IAAA;IACA,QAAA;IACA,UAAA;IACA,SAAA;EAAA;EAEF,KAAA;IACE,KAAA;IACA,IAAA;MAGM,IAAA;MACA,GAAA,EAAK,GAAA,CAAI,IAAA;IAAA;EAAA;AAAA;AAAA,KAMP,UAAA;EACV,aAAA;EACA,QAAA;EACA,KAAA,EAAO,SAAA,YAAqB,OAAA,CAAQ,SAAA;EAEpC,GAAA;EACA,aAAA;AAAA;AAAA,KAGU,UAAA,GAAa,UAAA;EACvB,KAAA,GAAQ,WAAA;EACR,IAAA,GAAO,UAAA;AAAA;;;iBCrCa,QAAA,CAAS,GAAA,EAAK,UAAA,GAAa,OAAA;;;iBCQ3B,OAAA,CAAQ,GAAA,EAAK,UAAA,GAAU,OAAA;;;iBCDvB,MAAA,CAAO,GAAA,UAAa,GAAA,WAAc,UAAA,GAAU,OAAA;;;iBClB5C,UAAA,CAAW,IAAA,WAAY,OAAA,CAAA,UAAA;;;iBCCvB,aAAA,CAAc,IAAA,WAAY,OAAA,CAAA,SAAA;AAAA,iBAO1B,gBAAA,CACpB,MAAA,UACA,OAAA,WACC,OAAA,EAAS,SAAA,EAAW,SAAA,IAAa,SAAA"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,243 @@
1
- import{n as e,r as t,t as n}from"./maa-CkTs9UGP.mjs";import{endGroup as r,error as i,startGroup as a,warning as o}from"@actions/core";import*as s from"node:fs/promises";import*as c from"node:path";import{FsContentLoader as l,FsContentWatcher as u,InterfaceBundle as d,buildDiagnosticMessage as f,joinPath as p,performDiagnostic as m}from"@nekosu/maa-pipeline-manager";import{existsSync as h}from"node:fs";import*as g from"node:os";import*as _ from"workerpool";import{setLocale as v}from"@nekosu/maa-locale";import{createJiti as y}from"jiti";async function b(e){if(!h(e))return console.log(`${e} not exists`),null;let t=new d(new l,new u,!1,c.dirname(e),c.basename(e));return await t.load(),await t.flush(!1),t}function x(e,t){let n=e.slice(0,t),r=0,i=0;for(let e=0;e<n.length;e++)n[e]===`
2
- `&&(r+=1,i=e);return[r+1,t-i]}async function S(t){if(!t.check)return!1;let l=await e(t);if(!l)return!1;await n(l),t.maaStdoutLevel&&(maa.Global.stdout_level=t.maaStdoutLevel);let u=c.resolve(t.cwd??process.cwd(),t.repo??`.`),d=[],h=await b(c.resolve(t.cwd??process.cwd(),t.check.interfacePath));if(!h)return!1;let g={},_=async(e,t)=>{let n=g[e];return n||(n=await s.readFile(e,`utf8`),g[e]=n),x(n,t)},v=!1,y=h.allControllerNames();for(let e of y){let n=h.allResourceNames(e);for(let s of n){await h.switchActive(e,s),!t.mode||t.mode===`stdio`?console.log(`${e} ${s}`):t.mode===`github`&&a(`${e} ${s}`);let n=m(h,{}),l=[];for(let e of n){let n=t.check.override?.[e.type];n!==`ignore`&&(n?l.push({...e,level:n}):l.push(e))}for(let e of l){let[n,r,a]=await f(h.root,e,_,{}),[s,l]=n,d=c.relative(u,e.file);switch(t.mode??`stdio`){case`stdio`:console.log(` ${e.level}: ${d}:${s}:${l} ${a}`);break;case`github`:switch(e.level){case`warning`:o(a,{file:d,startLine:s,startColumn:l,endColumn:l+e.length});break;case`error`:i(a,{file:d,startLine:s,startColumn:l,endColumn:l+e.length});break}}}t.mode===`github`&&r(),d.push(...l);let g=new maa.Resource;for(let e of h.paths)await g.post_bundle(p(h.root,e)).wait().succeeded||(!t.mode||t.mode===`stdio`?console.error(` load resource failed`):t.mode===`github`&&i(` load resource failed`),v=!0);g.destroy()}}return t.mode===`json`?(process.stdout.write(JSON.stringify(d)),!0):d.length===0||!v}function C(e,t){return t[0]>=e[0]&&t[1]>=e[1]&&t[0]+t[2]<=e[0]+e[2]&&t[1]+t[3]<=e[1]+e[3]}function w(e,t){let n=[],r=0;for(;r<e.length;){let i=r+t;n.push(e.slice(r,i)),r=i}return n}async function T(t){if(!t.test)return!1;let n=await e(t);if(!n)return!1;let r=[],i=await b(c.resolve(t.cwd??process.cwd(),t.test.interfacePath));if(!i)return!1;let a=0,o=t.test.cases.map(e=>e.cases.length*e.cases.map(e=>e.hits.length).reduce((e,t)=>e+t,0)),s=t.test.maxNodePerJob??50;for(let e of t.test.cases){let l=e.cases.map(n=>({image:c.resolve(t.cwd??process.cwd(),t.test.casesCwd??`.`,e.configs.imageRoot??`.`,n.image)+`.png`,imageRaw:n.image})),u=[...new Set(e.cases.map(e=>e.hits.map(e=>typeof e==`string`?e:e.node).flat()).flat())];await i.switchActive(e.configs.controller,e.configs.resource);let d=i.paths.map(e=>p(i.root,e)),f=_.pool(c.join(import.meta.dirname,`test`,`worker.mjs`),{maxWorkers:t.test.job??g.cpus().length/4,workerType:`process`,forkOpts:{env:{MAAFW_MODULE_PATH:n,MAAFW_STDOUT_LEVEL:t.mode===`json`?`Off`:t.maaStdoutLevel,MAAFW_RESOURCE_PATHS:d.join(c.delimiter)}}}),m=[],h=(e,t)=>{let n=f.exec(`performReco`,[e]).then(e=>e).catch(e=>(console.log(e),[])).then(e=>{a+=e.length,t.push(...e),process.stderr.write(`${a} / ${o}\r`)});m.push(n)},v={cases:e,result:[]};r.push(v);for(let{image:e,imageRaw:t}of l){let n=w(u,s);for(let r of n)h({nodes:r,imagePath:e,imagePathRaw:t},v.result)}await Promise.all(m),await f.terminate()}for(let e of r){let t=e.cases.configs.name??`${e.cases.configs.controller}:${e.cases.configs.resource}`;console.log(`${t}`);for(let t of e.cases.cases)for(let n of e.result.filter(e=>e.imagePathRaw===t.image)){let e=t.hits.find(e=>typeof e==`string`?e===n.node:e.node===n.node);e?n.hit?typeof e!=`string`&&(n.detail?C(e.box,n.detail.box)||console.log(` ${t.image} ${n.node} box mismatch. Expect ${JSON.stringify(e.box)}, hit ${JSON.stringify(n.detail.box)}`):console.log(` ${t.image} ${n.node} missing detail.`)):console.log(` ${t.image} ${n.node} should hit but missed`):n.hit&&console.log(` ${t.image} ${n.node} should missed but hit`)}}return!0}async function E(e){try{return await y(import.meta.url).import(c.resolve(process.cwd(),e),{default:!0})}catch(e){return console.log(e),null}}const D=`import type { FullConfig } from '${t}'
1
+ import { n as setupMaa, r as name, t as loadMaa } from "./maa-CDsPQ-38.mjs";
2
+ import { endGroup, error, startGroup, warning } from "@actions/core";
3
+ import * as fs from "node:fs/promises";
4
+ import * as path from "node:path";
5
+ import { FsContentLoader, FsContentWatcher, InterfaceBundle, buildDiagnosticMessage, joinPath, performDiagnostic } from "@nekosu/maa-pipeline-manager";
6
+ import { existsSync } from "node:fs";
7
+ import * as os from "node:os";
8
+ import * as workerpool from "workerpool";
9
+ import { setLocale } from "@nekosu/maa-locale";
10
+ import { createJiti } from "jiti";
11
+ import { parse } from "jsonc-parser";
12
+
13
+ //#region src/utils/bundle.ts
14
+ async function loadBundle(interfacePath) {
15
+ if (!existsSync(interfacePath)) {
16
+ console.log(`${interfacePath} not exists`);
17
+ return null;
18
+ }
19
+ const bundle = new InterfaceBundle(new FsContentLoader(), new FsContentWatcher(), false, path.dirname(interfacePath), path.basename(interfacePath));
20
+ await bundle.load();
21
+ await bundle.flush(false);
22
+ return bundle;
23
+ }
24
+
25
+ //#endregion
26
+ //#region src/check/utils.ts
27
+ function calucateLocation(content, offset) {
28
+ const previous = content.slice(0, offset);
29
+ let line = 0;
30
+ let last = 0;
31
+ for (let i = 0; i < previous.length; i++) if (previous[i] === "\n") {
32
+ line += 1;
33
+ last = i;
34
+ }
35
+ return [line + 1, offset - last];
36
+ }
37
+
38
+ //#endregion
39
+ //#region src/check/index.ts
40
+ async function runCheck(cfg) {
41
+ if (!cfg.check) return false;
42
+ const modulePath = await setupMaa(cfg);
43
+ if (!modulePath) return false;
44
+ await loadMaa(modulePath);
45
+ if (cfg.maaStdoutLevel) maa.Global.stdout_level = cfg.maaStdoutLevel;
46
+ const repo = path.resolve(cfg.cwd ?? process.cwd(), cfg.repo ?? ".");
47
+ const result = [];
48
+ const bundle = await loadBundle(path.resolve(cfg.cwd ?? process.cwd(), cfg.check.interfacePath));
49
+ if (!bundle) return false;
50
+ const files = {};
51
+ const locate = async (file, offset) => {
52
+ let content = files[file];
53
+ if (!content) {
54
+ content = await fs.readFile(file, "utf8");
55
+ files[file] = content;
56
+ }
57
+ return calucateLocation(content, offset);
58
+ };
59
+ let loadResourceFailed = false;
60
+ const ctrlNames = bundle.allControllerNames();
61
+ for (const ctrlName of ctrlNames) {
62
+ const resNames = bundle.allResourceNames(ctrlName);
63
+ for (const resName of resNames) {
64
+ await bundle.switchActive(ctrlName, resName);
65
+ if (!cfg.mode || cfg.mode === "stdio") console.log(`${ctrlName} ${resName}`);
66
+ else if (cfg.mode === "github") startGroup(`${ctrlName} ${resName}`);
67
+ const rawDiags = performDiagnostic(bundle, {});
68
+ const currDiags = [];
69
+ for (const diag of rawDiags) {
70
+ const override = cfg.check.override?.[diag.type];
71
+ if (override === "ignore") continue;
72
+ if (override) currDiags.push({
73
+ ...diag,
74
+ level: override
75
+ });
76
+ else currDiags.push(diag);
77
+ }
78
+ for (const diag of currDiags) {
79
+ const [start, _end, brief] = await buildDiagnosticMessage(bundle.root, diag, locate, {});
80
+ const [line, col] = start;
81
+ const relative = path.relative(repo, diag.file);
82
+ switch (cfg.mode ?? "stdio") {
83
+ case "stdio":
84
+ console.log(` ${diag.level}: ${relative}:${line}:${col} ${brief}`);
85
+ break;
86
+ case "github": switch (diag.level) {
87
+ case "warning":
88
+ warning(brief, {
89
+ file: relative,
90
+ startLine: line,
91
+ startColumn: col,
92
+ endColumn: col + diag.length
93
+ });
94
+ break;
95
+ case "error":
96
+ error(brief, {
97
+ file: relative,
98
+ startLine: line,
99
+ startColumn: col,
100
+ endColumn: col + diag.length
101
+ });
102
+ break;
103
+ }
104
+ }
105
+ }
106
+ if (cfg.mode === "github") endGroup();
107
+ result.push(...currDiags);
108
+ const res = new maa.Resource();
109
+ for (const folder of bundle.paths) if (!await res.post_bundle(joinPath(bundle.root, folder)).wait().succeeded) {
110
+ if (!cfg.mode || cfg.mode === "stdio") console.error(" load resource failed");
111
+ else if (cfg.mode === "github") error(" load resource failed");
112
+ loadResourceFailed = true;
113
+ }
114
+ res.destroy();
115
+ }
116
+ }
117
+ if (cfg.mode === "json") {
118
+ process.stdout.write(JSON.stringify(result));
119
+ return true;
120
+ }
121
+ return result.length === 0 || !loadResourceFailed;
122
+ }
123
+
124
+ //#endregion
125
+ //#region src/test/utils.ts
126
+ function checkRect(expect, real) {
127
+ return real[0] >= expect[0] && real[1] >= expect[1] && real[0] + real[2] <= expect[0] + expect[2] && real[1] + real[3] <= expect[1] + expect[3];
128
+ }
129
+
130
+ //#endregion
131
+ //#region src/test/index.ts
132
+ function splitChunk(arr, size) {
133
+ const result = [];
134
+ let curr = 0;
135
+ while (curr < arr.length) {
136
+ const next = curr + size;
137
+ result.push(arr.slice(curr, next));
138
+ curr = next;
139
+ }
140
+ return result;
141
+ }
142
+ async function runTest(cfg) {
143
+ if (!cfg.test) return false;
144
+ const modulePath = await setupMaa(cfg);
145
+ if (!modulePath) return false;
146
+ const result = [];
147
+ const bundle = await loadBundle(path.resolve(cfg.cwd ?? process.cwd(), cfg.test.interfacePath));
148
+ if (!bundle) return false;
149
+ let finished = 0;
150
+ let allTestCases = cfg.test.cases;
151
+ if (typeof allTestCases === "function") allTestCases = await allTestCases();
152
+ const taskCount = allTestCases.map((testCase) => {
153
+ return testCase.cases.length * testCase.cases.map((c) => c.hits.length).reduce((a, b) => a + b, 0);
154
+ }).reduce((a, b) => a + b, 0);
155
+ const maxNodePerJob = cfg.test.maxNodePerJob ?? 50;
156
+ for (const testCases of allTestCases) {
157
+ const name = testCases.configs.name ?? `${testCases.configs.controller}:${testCases.configs.resource}`;
158
+ const allImages = testCases.cases.map((c) => ({
159
+ image: path.resolve(cfg.cwd ?? process.cwd(), cfg.test.casesCwd ?? ".", testCases.configs.imageRoot ?? ".", c.image) + ".png",
160
+ imageRaw: c.image
161
+ })).filter(({ image, imageRaw }) => {
162
+ if (!existsSync(image)) {
163
+ console.log(`${name} ${imageRaw} not exists, ignored`);
164
+ return false;
165
+ } else return true;
166
+ });
167
+ const allNodes = [...new Set(testCases.cases.map((c) => c.hits.map((hit) => typeof hit === "string" ? hit : hit.node).flat()).flat())];
168
+ await bundle.switchActive(testCases.configs.controller, testCases.configs.resource);
169
+ const resourcePaths = bundle.paths.map((folder) => joinPath(bundle.root, folder));
170
+ const pool = workerpool.pool(path.join(import.meta.dirname, "test", "worker.mjs"), {
171
+ maxWorkers: cfg.test.job ?? os.cpus().length / 4,
172
+ workerType: "process",
173
+ forkOpts: { env: {
174
+ MAAFW_MODULE_PATH: modulePath,
175
+ MAAFW_STDOUT_LEVEL: cfg.mode === "json" ? "Off" : cfg.maaStdoutLevel,
176
+ MAAFW_RESOURCE_PATHS: resourcePaths.join(path.delimiter)
177
+ } }
178
+ });
179
+ const tasks = [];
180
+ const scheduleJob = (job, result) => {
181
+ const task = pool.exec("performReco", [job]).then((res) => res).catch((err) => {
182
+ console.log(err);
183
+ return [];
184
+ }).then((res) => {
185
+ finished += res.length;
186
+ result.push(...res);
187
+ process.stderr.write(`${finished} / ${taskCount}\r`);
188
+ });
189
+ tasks.push(task);
190
+ };
191
+ const groupResult = {
192
+ cases: testCases,
193
+ result: []
194
+ };
195
+ result.push(groupResult);
196
+ for (const { image, imageRaw } of allImages) {
197
+ const nodesChunks = splitChunk(allNodes, maxNodePerJob);
198
+ for (const nodes of nodesChunks) scheduleJob({
199
+ nodes,
200
+ imagePath: image,
201
+ imagePathRaw: imageRaw
202
+ }, groupResult.result);
203
+ }
204
+ await Promise.all(tasks);
205
+ await pool.terminate();
206
+ }
207
+ for (const group of result) {
208
+ const groupName = group.cases.configs.name ?? `${group.cases.configs.controller}:${group.cases.configs.resource}`;
209
+ console.log(`${groupName}`);
210
+ for (const testCase of group.cases.cases) for (const res of group.result.filter((res) => res.imagePathRaw === testCase.image)) {
211
+ const hitCfg = testCase.hits.find((hit) => {
212
+ if (typeof hit === "string") return hit === res.node;
213
+ else return hit.node === res.node;
214
+ });
215
+ if (hitCfg) {
216
+ if (!res.hit) console.log(` ${testCase.image} ${res.node} should hit but missed`);
217
+ else if (typeof hitCfg !== "string") {
218
+ if (!res.detail) console.log(` ${testCase.image} ${res.node} missing detail.`);
219
+ else if (!checkRect(hitCfg.box, res.detail.box)) console.log(` ${testCase.image} ${res.node} box mismatch. Expect ${JSON.stringify(hitCfg.box)}, hit ${JSON.stringify(res.detail.box)}`);
220
+ }
221
+ } else if (res.hit) console.log(` ${testCase.image} ${res.node} should missed but hit`);
222
+ }
223
+ }
224
+ return true;
225
+ }
226
+
227
+ //#endregion
228
+ //#region src/utils/config.ts
229
+ async function loadConfig(file) {
230
+ try {
231
+ return await createJiti(import.meta.url).import(path.resolve(process.cwd(), file), { default: true });
232
+ } catch (_err) {
233
+ console.log(_err);
234
+ return null;
235
+ }
236
+ }
237
+
238
+ //#endregion
239
+ //#region src/cli.ts
240
+ const defaultConfig = `import type { FullConfig } from '${name}'
3
241
 
4
242
  const config: FullConfig = {
5
243
  cwd: import.meta.dirname,
@@ -9,5 +247,52 @@ const config: FullConfig = {
9
247
  }
10
248
 
11
249
  export default config
12
- `;async function O(e,n){if(e===`init`)return h(`maatools.config.mts`)?console.error(`maatools.config.mts exists`):await s.writeFile(`maatools.config.mts`,D),!0;if(typeof n==`string`){let e=await E(n);if(!e)return console.error(`load ${n} failed`),!1;n=e}switch(process.env.GITHUB_ACTIONS&&(n.mode||=`github`),n.locale&&v(n.locale),e){case`check`:return await S(n);case`test`:return await T(n)}return console.log(`Usage: npx ${t} <init|check|test> [path to maatools.config.mts]`),!1}export{E as loadConfig,S as runCheck,O as runCli,T as runTest};
250
+ `;
251
+ async function runCli(cmd, cfg) {
252
+ if (cmd === "init") {
253
+ if (!existsSync("maatools.config.mts")) await fs.writeFile("maatools.config.mts", defaultConfig);
254
+ else console.error("maatools.config.mts exists");
255
+ return true;
256
+ }
257
+ if (typeof cfg === "string") {
258
+ const resolvedCfg = await loadConfig(cfg);
259
+ if (!resolvedCfg) {
260
+ console.error(`load ${cfg} failed`);
261
+ return false;
262
+ }
263
+ cfg = resolvedCfg;
264
+ }
265
+ if (process.env["GITHUB_ACTIONS"]) {
266
+ if (!cfg.mode) cfg.mode = "github";
267
+ }
268
+ if (cfg.locale) setLocale(cfg.locale);
269
+ switch (cmd) {
270
+ case "check": return await runCheck(cfg);
271
+ case "test": return await runTest(cfg);
272
+ }
273
+ console.log(`Usage: npx ${name} <init|check|test> [path to maatools.config.mts]`);
274
+ return false;
275
+ }
276
+
277
+ //#endregion
278
+ //#region src/utils/tools.ts
279
+ async function loadTestCases(file) {
280
+ const content = await fs.readFile(file, "utf8");
281
+ const errors = [];
282
+ const result = parse(content, errors);
283
+ return errors.length > 0 ? null : result;
284
+ }
285
+ async function loadAllTestCases(folder, pattern) {
286
+ const results = [];
287
+ const fails = [];
288
+ for await (const file of fs.glob(pattern, { cwd: folder })) {
289
+ const testCases = await loadTestCases(path.resolve(pattern, file));
290
+ if (testCases) results.push(testCases);
291
+ else fails.push(file);
292
+ }
293
+ return [results, fails];
294
+ }
295
+
296
+ //#endregion
297
+ export { loadAllTestCases, loadConfig, loadTestCases, runCheck, runCli, runTest };
13
298
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["pkg.name"],"sources":["../src/utils/bundle.ts","../src/check/utils.ts","../src/check/index.ts","../src/test/utils.ts","../src/test/index.ts","../src/utils/config.ts","../src/cli.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport * as path from 'node:path'\n\nimport { FsContentLoader, FsContentWatcher, InterfaceBundle } from '@nekosu/maa-pipeline-manager'\n\nexport async function loadBundle(interfacePath: string) {\n if (!existsSync(interfacePath)) {\n console.log(`${interfacePath} not exists`)\n return null\n }\n\n const bundle = new InterfaceBundle(\n new FsContentLoader(),\n new FsContentWatcher(),\n false,\n path.dirname(interfacePath),\n path.basename(interfacePath)\n )\n await bundle.load()\n await bundle.flush(false) // 刷下 imports\n\n return bundle\n}\n","export function calucateLocation(content: string, offset: number): [line: number, col: number] {\n const previous = content.slice(0, offset)\n let line = 0\n let last = 0\n for (let i = 0; i < previous.length; i++) {\n if (previous[i] === '\\n') {\n line += 1\n last = i\n }\n }\n return [line + 1, offset - last]\n}\n","import { error as coreError, warning as coreWarning, endGroup, startGroup } from '@actions/core'\nimport * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\n\nimport {\n type Diagnostic,\n buildDiagnosticMessage,\n joinPath,\n performDiagnostic\n} from '@nekosu/maa-pipeline-manager'\n\nimport type { FullConfig } from '../types/config'\nimport { loadBundle } from '../utils/bundle'\nimport { loadMaa, setupMaa } from '../utils/maa'\nimport { calucateLocation } from './utils'\n\nexport async function runCheck(cfg: FullConfig): Promise<boolean> {\n if (!cfg.check) {\n return false\n }\n\n const modulePath = await setupMaa(cfg)\n if (!modulePath) {\n return false\n }\n await loadMaa(modulePath)\n if (cfg.maaStdoutLevel) {\n maa.Global.stdout_level = cfg.maaStdoutLevel\n }\n\n const repo = path.resolve(cfg.cwd ?? process.cwd(), cfg.repo ?? '.')\n\n const result: Diagnostic[] = []\n\n const bundle = await loadBundle(path.resolve(cfg.cwd ?? process.cwd(), cfg.check.interfacePath))\n if (!bundle) {\n return false\n }\n\n const files: Record<string, string> = {}\n const locate = async (file: string, offset: number) => {\n let content = files[file]\n if (!content) {\n content = await fs.readFile(file, 'utf8')\n files[file] = content\n }\n return calucateLocation(content, offset)\n }\n\n let loadResourceFailed = false\n\n const ctrlNames = bundle.allControllerNames()\n for (const ctrlName of ctrlNames) {\n const resNames = bundle.allResourceNames(ctrlName)\n for (const resName of resNames) {\n await bundle.switchActive(ctrlName, resName)\n\n if (!cfg.mode || cfg.mode === 'stdio') {\n console.log(`${ctrlName} ${resName}`)\n } else if (cfg.mode === 'github') {\n startGroup(`${ctrlName} ${resName}`)\n }\n\n const rawDiags = performDiagnostic(bundle, {})\n const currDiags: Diagnostic[] = []\n for (const diag of rawDiags) {\n const override = cfg.check.override?.[diag.type]\n if (override === 'ignore') {\n continue\n }\n if (override) {\n currDiags.push({\n ...diag,\n level: override\n })\n } else {\n currDiags.push(diag)\n }\n }\n\n for (const diag of currDiags) {\n const [start, _end, brief] = await buildDiagnosticMessage(bundle.root, diag, locate, {})\n\n const [line, col] = start\n const relative = path.relative(repo, diag.file)\n switch (cfg.mode ?? 'stdio') {\n case 'stdio':\n console.log(` ${diag.level}: ${relative}:${line}:${col} ${brief}`)\n break\n case 'github':\n switch (diag.level) {\n case 'warning':\n coreWarning(brief, {\n file: relative,\n startLine: line,\n startColumn: col,\n endColumn: col + diag.length\n })\n break\n case 'error':\n coreError(brief, {\n file: relative,\n startLine: line,\n startColumn: col,\n endColumn: col + diag.length\n })\n break\n }\n }\n }\n if (cfg.mode === 'github') {\n endGroup()\n }\n\n result.push(...currDiags)\n\n const res = new maa.Resource()\n for (const folder of bundle.paths) {\n const succ = await res.post_bundle(joinPath(bundle.root, folder)).wait().succeeded\n if (!succ) {\n if (!cfg.mode || cfg.mode === 'stdio') {\n console.error(' load resource failed')\n } else if (cfg.mode === 'github') {\n coreError(' load resource failed')\n }\n loadResourceFailed = true\n }\n }\n res.destroy()\n }\n }\n\n if (cfg.mode === 'json') {\n process.stdout.write(JSON.stringify(result))\n return true\n }\n\n return result.length === 0 || !loadResourceFailed\n}\n","// return if real inside expect\nexport function checkRect(expect: maa.Rect, real: maa.Rect) {\n return (\n real[0] >= expect[0] &&\n real[1] >= expect[1] &&\n real[0] + real[2] <= expect[0] + expect[2] &&\n real[1] + real[3] <= expect[1] + expect[3]\n )\n}\n","import * as os from 'node:os'\nimport * as path from 'node:path'\nimport * as workerpool from 'workerpool'\n\nimport { joinPath } from '@nekosu/maa-pipeline-manager'\n\nimport type { FullConfig } from '../types/config'\nimport { loadBundle } from '../utils/bundle'\nimport { setupMaa } from '../utils/maa'\nimport type { GroupRecoResult, RecoJob, RecoResult } from './types'\nimport { checkRect } from './utils'\n\nfunction splitChunk<T>(arr: T[], size: number) {\n const result: T[][] = []\n let curr = 0\n while (curr < arr.length) {\n const next = curr + size\n result.push(arr.slice(curr, next))\n curr = next\n }\n return result\n}\n\nexport async function runTest(cfg: FullConfig) {\n if (!cfg.test) {\n return false\n }\n\n const modulePath = await setupMaa(cfg)\n if (!modulePath) {\n return false\n }\n\n const result: GroupRecoResult[] = []\n\n const bundle = await loadBundle(path.resolve(cfg.cwd ?? process.cwd(), cfg.test.interfacePath))\n if (!bundle) {\n return false\n }\n\n let finished = 0\n\n const taskCount = cfg.test.cases.map(testCase => {\n const imageCount = testCase.cases.length\n const nodeCount = testCase.cases.map(c => c.hits.length).reduce((a, b) => a + b, 0)\n return imageCount * nodeCount\n })\n\n const maxNodePerJob = cfg.test.maxNodePerJob ?? 50\n\n for (const testCases of cfg.test.cases) {\n const allImages = testCases.cases.map(c => ({\n image:\n path.resolve(\n cfg.cwd ?? process.cwd(),\n cfg.test!.casesCwd ?? '.',\n testCases.configs.imageRoot ?? '.',\n c.image\n ) + '.png',\n imageRaw: c.image\n }))\n const allNodes = [\n ...new Set(\n testCases.cases\n .map(c => c.hits.map(hit => (typeof hit === 'string' ? hit : hit.node)).flat())\n .flat()\n )\n ]\n\n await bundle.switchActive(testCases.configs.controller, testCases.configs.resource)\n const resourcePaths = bundle.paths.map(folder => joinPath(bundle.root, folder))\n\n const pool = workerpool.pool(path.join(import.meta.dirname, 'test', 'worker.mjs'), {\n maxWorkers: cfg.test.job ?? os.cpus().length / 4,\n workerType: 'process',\n forkOpts: {\n env: {\n MAAFW_MODULE_PATH: modulePath,\n MAAFW_STDOUT_LEVEL: cfg.mode === 'json' ? 'Off' : cfg.maaStdoutLevel,\n MAAFW_RESOURCE_PATHS: resourcePaths.join(path.delimiter)\n }\n }\n })\n\n const tasks: Promise<void>[] = []\n const scheduleJob = (job: RecoJob, result: RecoResult[]) => {\n const task = pool\n .exec<(job: RecoJob) => RecoResult[]>('performReco', [job])\n .then(res => res)\n .catch(err => {\n console.log(err)\n return []\n })\n .then(res => {\n finished += res.length\n result.push(...res)\n process.stderr.write(`${finished} / ${taskCount}\\r`)\n })\n tasks.push(task)\n }\n\n const groupResult: GroupRecoResult = {\n cases: testCases,\n result: []\n }\n result.push(groupResult)\n for (const { image, imageRaw } of allImages) {\n const nodesChunks = splitChunk(allNodes, maxNodePerJob)\n for (const nodes of nodesChunks) {\n scheduleJob(\n {\n nodes,\n imagePath: image,\n imagePathRaw: imageRaw\n },\n groupResult.result\n )\n }\n }\n\n await Promise.all(tasks)\n await pool.terminate()\n }\n\n for (const group of result) {\n const groupName =\n group.cases.configs.name ??\n `${group.cases.configs.controller}:${group.cases.configs.resource}`\n\n console.log(`${groupName}`)\n for (const testCase of group.cases.cases) {\n for (const res of group.result.filter(res => res.imagePathRaw === testCase.image)) {\n const hitCfg = testCase.hits.find(hit => {\n if (typeof hit === 'string') {\n return hit === res.node\n } else {\n return hit.node === res.node\n }\n })\n if (hitCfg) {\n if (!res.hit) {\n console.log(` ${testCase.image} ${res.node} should hit but missed`)\n } else if (typeof hitCfg !== 'string') {\n if (!res.detail) {\n console.log(` ${testCase.image} ${res.node} missing detail.`)\n } else if (!checkRect(hitCfg.box, res.detail!.box)) {\n console.log(\n ` ${testCase.image} ${res.node} box mismatch. Expect ${JSON.stringify(hitCfg.box)}, hit ${JSON.stringify(res.detail.box)}`\n )\n }\n }\n } else {\n if (res.hit) {\n console.log(` ${testCase.image} ${res.node} should missed but hit`)\n }\n }\n }\n }\n }\n return true\n}\n","import { createJiti } from 'jiti'\nimport * as path from 'node:path'\n\nimport type { FullConfig } from '../types/config'\n\nexport async function loadConfig(file: string) {\n try {\n const jiti = createJiti(import.meta.url)\n return (await jiti.import(path.resolve(process.cwd(), file), { default: true })) as FullConfig\n } catch (_err) {\n console.log(_err)\n return null\n }\n}\n","import { existsSync } from 'node:fs'\nimport * as fs from 'node:fs/promises'\n\nimport { setLocale } from '@nekosu/maa-locale'\n\nimport pkg from '../package.json'\nimport { runCheck } from './check'\nimport { runTest } from './test'\nimport type { FullConfig } from './types/config'\nimport { loadConfig } from './utils/config'\n\nconst defaultConfig = `import type { FullConfig } from '${pkg.name}'\n\nconst config: FullConfig = {\n cwd: import.meta.dirname,\n check: {\n interfacePath: 'assets/interface.json'\n }\n}\n\nexport default config\n`\n\nexport async function runCli(cmd: string, cfg: string | FullConfig) {\n if (cmd === 'init') {\n if (!existsSync('maatools.config.mts')) {\n await fs.writeFile('maatools.config.mts', defaultConfig)\n } else {\n console.error('maatools.config.mts exists')\n }\n return true\n }\n\n if (typeof cfg === 'string') {\n const resolvedCfg = await loadConfig(cfg)\n if (!resolvedCfg) {\n console.error(`load ${cfg} failed`)\n return false\n }\n cfg = resolvedCfg\n }\n if (process.env['GITHUB_ACTIONS']) {\n if (!cfg.mode) {\n cfg.mode = 'github'\n }\n }\n if (cfg.locale) {\n setLocale(cfg.locale)\n }\n switch (cmd) {\n case 'check':\n return await runCheck(cfg)\n\n case 'test':\n return await runTest(cfg)\n }\n\n console.log(`Usage: npx ${pkg.name} <init|check|test> [path to maatools.config.mts]`)\n\n return false\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["pkg.name"],"sources":["../src/utils/bundle.ts","../src/check/utils.ts","../src/check/index.ts","../src/test/utils.ts","../src/test/index.ts","../src/utils/config.ts","../src/cli.ts","../src/utils/tools.ts"],"sourcesContent":["import { existsSync } from 'node:fs'\nimport * as path from 'node:path'\n\nimport { FsContentLoader, FsContentWatcher, InterfaceBundle } from '@nekosu/maa-pipeline-manager'\n\nexport async function loadBundle(interfacePath: string) {\n if (!existsSync(interfacePath)) {\n console.log(`${interfacePath} not exists`)\n return null\n }\n\n const bundle = new InterfaceBundle(\n new FsContentLoader(),\n new FsContentWatcher(),\n false,\n path.dirname(interfacePath),\n path.basename(interfacePath)\n )\n await bundle.load()\n await bundle.flush(false) // 刷下 imports\n\n return bundle\n}\n","export function calucateLocation(content: string, offset: number): [line: number, col: number] {\n const previous = content.slice(0, offset)\n let line = 0\n let last = 0\n for (let i = 0; i < previous.length; i++) {\n if (previous[i] === '\\n') {\n line += 1\n last = i\n }\n }\n return [line + 1, offset - last]\n}\n","import { error as coreError, warning as coreWarning, endGroup, startGroup } from '@actions/core'\nimport * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\n\nimport {\n type Diagnostic,\n buildDiagnosticMessage,\n joinPath,\n performDiagnostic\n} from '@nekosu/maa-pipeline-manager'\n\nimport type { FullConfig } from '../types/config'\nimport { loadBundle } from '../utils/bundle'\nimport { loadMaa, setupMaa } from '../utils/maa'\nimport { calucateLocation } from './utils'\n\nexport async function runCheck(cfg: FullConfig): Promise<boolean> {\n if (!cfg.check) {\n return false\n }\n\n const modulePath = await setupMaa(cfg)\n if (!modulePath) {\n return false\n }\n await loadMaa(modulePath)\n if (cfg.maaStdoutLevel) {\n maa.Global.stdout_level = cfg.maaStdoutLevel\n }\n\n const repo = path.resolve(cfg.cwd ?? process.cwd(), cfg.repo ?? '.')\n\n const result: Diagnostic[] = []\n\n const bundle = await loadBundle(path.resolve(cfg.cwd ?? process.cwd(), cfg.check.interfacePath))\n if (!bundle) {\n return false\n }\n\n const files: Record<string, string> = {}\n const locate = async (file: string, offset: number) => {\n let content = files[file]\n if (!content) {\n content = await fs.readFile(file, 'utf8')\n files[file] = content\n }\n return calucateLocation(content, offset)\n }\n\n let loadResourceFailed = false\n\n const ctrlNames = bundle.allControllerNames()\n for (const ctrlName of ctrlNames) {\n const resNames = bundle.allResourceNames(ctrlName)\n for (const resName of resNames) {\n await bundle.switchActive(ctrlName, resName)\n\n if (!cfg.mode || cfg.mode === 'stdio') {\n console.log(`${ctrlName} ${resName}`)\n } else if (cfg.mode === 'github') {\n startGroup(`${ctrlName} ${resName}`)\n }\n\n const rawDiags = performDiagnostic(bundle, {})\n const currDiags: Diagnostic[] = []\n for (const diag of rawDiags) {\n const override = cfg.check.override?.[diag.type]\n if (override === 'ignore') {\n continue\n }\n if (override) {\n currDiags.push({\n ...diag,\n level: override\n })\n } else {\n currDiags.push(diag)\n }\n }\n\n for (const diag of currDiags) {\n const [start, _end, brief] = await buildDiagnosticMessage(bundle.root, diag, locate, {})\n\n const [line, col] = start\n const relative = path.relative(repo, diag.file)\n switch (cfg.mode ?? 'stdio') {\n case 'stdio':\n console.log(` ${diag.level}: ${relative}:${line}:${col} ${brief}`)\n break\n case 'github':\n switch (diag.level) {\n case 'warning':\n coreWarning(brief, {\n file: relative,\n startLine: line,\n startColumn: col,\n endColumn: col + diag.length\n })\n break\n case 'error':\n coreError(brief, {\n file: relative,\n startLine: line,\n startColumn: col,\n endColumn: col + diag.length\n })\n break\n }\n }\n }\n if (cfg.mode === 'github') {\n endGroup()\n }\n\n result.push(...currDiags)\n\n const res = new maa.Resource()\n for (const folder of bundle.paths) {\n const succ = await res.post_bundle(joinPath(bundle.root, folder)).wait().succeeded\n if (!succ) {\n if (!cfg.mode || cfg.mode === 'stdio') {\n console.error(' load resource failed')\n } else if (cfg.mode === 'github') {\n coreError(' load resource failed')\n }\n loadResourceFailed = true\n }\n }\n res.destroy()\n }\n }\n\n if (cfg.mode === 'json') {\n process.stdout.write(JSON.stringify(result))\n return true\n }\n\n return result.length === 0 || !loadResourceFailed\n}\n","// return if real inside expect\nexport function checkRect(expect: maa.Rect, real: maa.Rect) {\n return (\n real[0] >= expect[0] &&\n real[1] >= expect[1] &&\n real[0] + real[2] <= expect[0] + expect[2] &&\n real[1] + real[3] <= expect[1] + expect[3]\n )\n}\n","import { existsSync } from 'node:fs'\nimport * as os from 'node:os'\nimport * as path from 'node:path'\nimport * as workerpool from 'workerpool'\n\nimport { joinPath } from '@nekosu/maa-pipeline-manager'\n\nimport type { FullConfig } from '../types/config'\nimport { loadBundle } from '../utils/bundle'\nimport { setupMaa } from '../utils/maa'\nimport type { GroupRecoResult, RecoJob, RecoResult } from './types'\nimport { checkRect } from './utils'\n\nfunction splitChunk<T>(arr: T[], size: number) {\n const result: T[][] = []\n let curr = 0\n while (curr < arr.length) {\n const next = curr + size\n result.push(arr.slice(curr, next))\n curr = next\n }\n return result\n}\n\nexport async function runTest(cfg: FullConfig) {\n if (!cfg.test) {\n return false\n }\n\n const modulePath = await setupMaa(cfg)\n if (!modulePath) {\n return false\n }\n\n const result: GroupRecoResult[] = []\n\n const bundle = await loadBundle(path.resolve(cfg.cwd ?? process.cwd(), cfg.test.interfacePath))\n if (!bundle) {\n return false\n }\n\n let finished = 0\n\n let allTestCases = cfg.test.cases\n if (typeof allTestCases === 'function') {\n allTestCases = await allTestCases()\n }\n\n const taskCount = allTestCases\n .map(testCase => {\n const imageCount = testCase.cases.length\n const nodeCount = testCase.cases.map(c => c.hits.length).reduce((a, b) => a + b, 0)\n return imageCount * nodeCount\n })\n .reduce((a, b) => a + b, 0)\n\n const maxNodePerJob = cfg.test.maxNodePerJob ?? 50\n\n for (const testCases of allTestCases) {\n const name =\n testCases.configs.name ?? `${testCases.configs.controller}:${testCases.configs.resource}`\n\n const allImages = testCases.cases\n .map(c => ({\n image:\n path.resolve(\n cfg.cwd ?? process.cwd(),\n cfg.test!.casesCwd ?? '.',\n testCases.configs.imageRoot ?? '.',\n c.image\n ) + '.png',\n imageRaw: c.image\n }))\n .filter(({ image, imageRaw }) => {\n if (!existsSync(image)) {\n console.log(`${name} ${imageRaw} not exists, ignored`)\n return false\n } else {\n return true\n }\n })\n const allNodes = [\n ...new Set(\n testCases.cases\n .map(c => c.hits.map(hit => (typeof hit === 'string' ? hit : hit.node)).flat())\n .flat()\n )\n ]\n\n await bundle.switchActive(testCases.configs.controller, testCases.configs.resource)\n const resourcePaths = bundle.paths.map(folder => joinPath(bundle.root, folder))\n\n const pool = workerpool.pool(path.join(import.meta.dirname, 'test', 'worker.mjs'), {\n maxWorkers: cfg.test.job ?? os.cpus().length / 4,\n workerType: 'process',\n forkOpts: {\n env: {\n MAAFW_MODULE_PATH: modulePath,\n MAAFW_STDOUT_LEVEL: cfg.mode === 'json' ? 'Off' : cfg.maaStdoutLevel,\n MAAFW_RESOURCE_PATHS: resourcePaths.join(path.delimiter)\n }\n }\n })\n\n const tasks: Promise<void>[] = []\n const scheduleJob = (job: RecoJob, result: RecoResult[]) => {\n const task = pool\n .exec<(job: RecoJob) => RecoResult[]>('performReco', [job])\n .then(res => res)\n .catch(err => {\n console.log(err)\n return []\n })\n .then(res => {\n finished += res.length\n result.push(...res)\n process.stderr.write(`${finished} / ${taskCount}\\r`)\n })\n tasks.push(task)\n }\n\n const groupResult: GroupRecoResult = {\n cases: testCases,\n result: []\n }\n result.push(groupResult)\n for (const { image, imageRaw } of allImages) {\n const nodesChunks = splitChunk(allNodes, maxNodePerJob)\n for (const nodes of nodesChunks) {\n scheduleJob(\n {\n nodes,\n imagePath: image,\n imagePathRaw: imageRaw\n },\n groupResult.result\n )\n }\n }\n\n await Promise.all(tasks)\n await pool.terminate()\n }\n\n for (const group of result) {\n const groupName =\n group.cases.configs.name ??\n `${group.cases.configs.controller}:${group.cases.configs.resource}`\n\n console.log(`${groupName}`)\n for (const testCase of group.cases.cases) {\n for (const res of group.result.filter(res => res.imagePathRaw === testCase.image)) {\n const hitCfg = testCase.hits.find(hit => {\n if (typeof hit === 'string') {\n return hit === res.node\n } else {\n return hit.node === res.node\n }\n })\n if (hitCfg) {\n if (!res.hit) {\n console.log(` ${testCase.image} ${res.node} should hit but missed`)\n } else if (typeof hitCfg !== 'string') {\n if (!res.detail) {\n console.log(` ${testCase.image} ${res.node} missing detail.`)\n } else if (!checkRect(hitCfg.box, res.detail!.box)) {\n console.log(\n ` ${testCase.image} ${res.node} box mismatch. Expect ${JSON.stringify(hitCfg.box)}, hit ${JSON.stringify(res.detail.box)}`\n )\n }\n }\n } else {\n if (res.hit) {\n console.log(` ${testCase.image} ${res.node} should missed but hit`)\n }\n }\n }\n }\n }\n return true\n}\n","import { createJiti } from 'jiti'\nimport * as path from 'node:path'\n\nimport type { FullConfig } from '../types/config'\n\nexport async function loadConfig(file: string) {\n try {\n const jiti = createJiti(import.meta.url)\n return (await jiti.import(path.resolve(process.cwd(), file), { default: true })) as FullConfig\n } catch (_err) {\n console.log(_err)\n return null\n }\n}\n","import { existsSync } from 'node:fs'\nimport * as fs from 'node:fs/promises'\n\nimport { setLocale } from '@nekosu/maa-locale'\n\nimport pkg from '../package.json'\nimport { runCheck } from './check'\nimport { runTest } from './test'\nimport type { FullConfig } from './types/config'\nimport { loadConfig } from './utils/config'\n\nconst defaultConfig = `import type { FullConfig } from '${pkg.name}'\n\nconst config: FullConfig = {\n cwd: import.meta.dirname,\n check: {\n interfacePath: 'assets/interface.json'\n }\n}\n\nexport default config\n`\n\nexport async function runCli(cmd: string, cfg: string | FullConfig) {\n if (cmd === 'init') {\n if (!existsSync('maatools.config.mts')) {\n await fs.writeFile('maatools.config.mts', defaultConfig)\n } else {\n console.error('maatools.config.mts exists')\n }\n return true\n }\n\n if (typeof cfg === 'string') {\n const resolvedCfg = await loadConfig(cfg)\n if (!resolvedCfg) {\n console.error(`load ${cfg} failed`)\n return false\n }\n cfg = resolvedCfg\n }\n if (process.env['GITHUB_ACTIONS']) {\n if (!cfg.mode) {\n cfg.mode = 'github'\n }\n }\n if (cfg.locale) {\n setLocale(cfg.locale)\n }\n switch (cmd) {\n case 'check':\n return await runCheck(cfg)\n\n case 'test':\n return await runTest(cfg)\n }\n\n console.log(`Usage: npx ${pkg.name} <init|check|test> [path to maatools.config.mts]`)\n\n return false\n}\n","import { type ParseError, parse } from 'jsonc-parser'\nimport * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\n\nimport type { TestCases } from '../types/config'\n\nexport async function loadTestCases(file: string) {\n const content = await fs.readFile(file, 'utf8')\n const errors: ParseError[] = []\n const result = parse(content, errors) as TestCases\n return errors.length > 0 ? null : result\n}\n\nexport async function loadAllTestCases(\n folder: string,\n pattern: string\n): Promise<[testCases: TestCases[], failFiles: string[]]> {\n const results: TestCases[] = []\n const fails: string[] = []\n for await (const file of fs.glob(pattern, { cwd: folder })) {\n const testCases = await loadTestCases(path.resolve(pattern, file))\n if (testCases) {\n results.push(testCases)\n } else {\n fails.push(file)\n }\n }\n return [results, fails]\n}\n"],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import * as path from "node:path";
2
+ import * as os from "node:os";
3
+ import * as url from "node:url";
4
+ import { MaaVersionManager } from "@nekosu/maa-version-manager";
5
+
6
+ //#region package.json
7
+ var name = "@nekosu/maa-tools";
8
+ var devDependencies = {
9
+ "@maaxyz/maa-node": "5.7.2",
10
+ "@tsconfig/node24": "^24.0.4",
11
+ "@types/node": "^25.3.0",
12
+ "@types/source-map-support": "^0.5.10",
13
+ "source-map-support": "^0.5.21",
14
+ "typescript": "^5.9.3"
15
+ };
16
+
17
+ //#endregion
18
+ //#region src/utils/maa.ts
19
+ async function setupMaa(cfg) {
20
+ const versionManager = new MaaVersionManager(cfg.maaCache ?? path.join(os.homedir(), ".maa-checker"));
21
+ let maaVersion = cfg.maaVersion;
22
+ if (maaVersion === "latest") {
23
+ const latest = (await versionManager.fetchLatest())?.version;
24
+ if (latest) {
25
+ maaVersion = latest;
26
+ if (cfg.mode !== "json") console.log(`use latest version ${latest}`);
27
+ }
28
+ }
29
+ if (!maaVersion) {
30
+ const fallback = devDependencies["@maaxyz/maa-node"];
31
+ maaVersion = fallback;
32
+ if (cfg.mode !== "json") console.log(`use fallback version ${fallback}`);
33
+ }
34
+ await versionManager.init();
35
+ if (!await versionManager.prepare(maaVersion, (msg) => {
36
+ if (cfg.mode !== "json") {
37
+ if (msg === "prepare-folder") console.log("preparing maafw");
38
+ console.log(" " + msg);
39
+ }
40
+ })) return null;
41
+ return versionManager.moduleFolder(maaVersion);
42
+ }
43
+ async function loadMaa(modulePath) {
44
+ const importTarget = path.join(modulePath, "@maaxyz/maa-node/dist/index-client.js");
45
+ await import(url.pathToFileURL(importTarget).toString());
46
+ }
47
+
48
+ //#endregion
49
+ export { setupMaa as n, name as r, loadMaa as t };
50
+ //# sourceMappingURL=maa-CDsPQ-38.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"maa-CkTs9UGP.mjs","names":[],"sources":["../package.json","../src/utils/maa.ts"],"sourcesContent":["","import * as os from 'node:os'\nimport * as path from 'node:path'\nimport * as url from 'node:url'\n\nimport { MaaVersionManager } from '@nekosu/maa-version-manager'\n\nimport pkg from '../../package.json'\nimport type { FullConfig } from '../types/config'\n\nexport async function setupMaa(cfg: FullConfig) {\n const versionManager = new MaaVersionManager(\n cfg.maaCache ?? path.join(os.homedir(), '.maa-checker')\n )\n\n let maaVersion = cfg.maaVersion\n if (maaVersion === 'latest') {\n const latest = (await versionManager.fetchLatest())?.version\n if (latest) {\n maaVersion = latest\n if (cfg.mode !== 'json') {\n console.log(`use latest version ${latest}`)\n }\n }\n }\n if (!maaVersion) {\n const fallback = pkg.devDependencies['@maaxyz/maa-node']\n maaVersion = fallback\n if (cfg.mode !== 'json') {\n console.log(`use fallback version ${fallback}`)\n }\n }\n\n await versionManager.init()\n if (\n !(await versionManager.prepare(maaVersion, msg => {\n if (cfg.mode !== 'json') {\n if (msg === 'prepare-folder') {\n console.log('preparing maafw')\n }\n console.log(' ' + msg)\n }\n }))\n ) {\n return null\n }\n return versionManager.moduleFolder(maaVersion)\n}\n\nexport async function loadMaa(modulePath: string) {\n const importTarget = path.join(modulePath, '@maaxyz/maa-node/dist/index-client.js')\n await import(url.pathToFileURL(importTarget).toString())\n}\n"],"mappings":"wVCSA,eAAsB,EAAS,EAAiB,CAC9C,IAAM,EAAiB,IAAI,EACzB,EAAI,UAAY,EAAK,KAAK,EAAG,SAAS,CAAE,eAAe,CACxD,CAEG,EAAa,EAAI,WACrB,GAAI,IAAe,SAAU,CAC3B,IAAM,GAAU,MAAM,EAAe,aAAa,GAAG,QACjD,IACF,EAAa,EACT,EAAI,OAAS,QACf,QAAQ,IAAI,sBAAsB,IAAS,EAIjD,GAAI,CAAC,EAAY,CACf,IAAM,EAAA,EAA+B,oBACrC,EAAa,EACT,EAAI,OAAS,QACf,QAAQ,IAAI,wBAAwB,IAAW,CAiBnD,OAbA,MAAM,EAAe,MAAM,CAEvB,MAAM,EAAe,QAAQ,EAAY,GAAO,CAC5C,EAAI,OAAS,SACX,IAAQ,kBACV,QAAQ,IAAI,kBAAkB,CAEhC,QAAQ,IAAI,OAAS,EAAI,GAE3B,CAIG,EAAe,aAAa,EAAW,CAFrC,KAKX,eAAsB,EAAQ,EAAoB,CAChD,IAAM,EAAe,EAAK,KAAK,EAAY,wCAAwC,CACnF,MAAM,OAAO,EAAI,cAAc,EAAa,CAAC,UAAU"}
1
+ {"version":3,"file":"maa-CDsPQ-38.mjs","names":[],"sources":["../package.json","../src/utils/maa.ts"],"sourcesContent":["","import * as os from 'node:os'\nimport * as path from 'node:path'\nimport * as url from 'node:url'\n\nimport { MaaVersionManager } from '@nekosu/maa-version-manager'\n\nimport pkg from '../../package.json'\nimport type { FullConfig } from '../types/config'\n\nexport async function setupMaa(cfg: FullConfig) {\n const versionManager = new MaaVersionManager(\n cfg.maaCache ?? path.join(os.homedir(), '.maa-checker')\n )\n\n let maaVersion = cfg.maaVersion\n if (maaVersion === 'latest') {\n const latest = (await versionManager.fetchLatest())?.version\n if (latest) {\n maaVersion = latest\n if (cfg.mode !== 'json') {\n console.log(`use latest version ${latest}`)\n }\n }\n }\n if (!maaVersion) {\n const fallback = pkg.devDependencies['@maaxyz/maa-node']\n maaVersion = fallback\n if (cfg.mode !== 'json') {\n console.log(`use fallback version ${fallback}`)\n }\n }\n\n await versionManager.init()\n if (\n !(await versionManager.prepare(maaVersion, msg => {\n if (cfg.mode !== 'json') {\n if (msg === 'prepare-folder') {\n console.log('preparing maafw')\n }\n console.log(' ' + msg)\n }\n }))\n ) {\n return null\n }\n return versionManager.moduleFolder(maaVersion)\n}\n\nexport async function loadMaa(modulePath: string) {\n const importTarget = path.join(modulePath, '@maaxyz/maa-node/dist/index-client.js')\n await import(url.pathToFileURL(importTarget).toString())\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;ACSA,eAAsB,SAAS,KAAiB;CAC9C,MAAM,iBAAiB,IAAI,kBACzB,IAAI,YAAY,KAAK,KAAK,GAAG,SAAS,EAAE,eAAe,CACxD;CAED,IAAI,aAAa,IAAI;AACrB,KAAI,eAAe,UAAU;EAC3B,MAAM,UAAU,MAAM,eAAe,aAAa,GAAG;AACrD,MAAI,QAAQ;AACV,gBAAa;AACb,OAAI,IAAI,SAAS,OACf,SAAQ,IAAI,sBAAsB,SAAS;;;AAIjD,KAAI,CAAC,YAAY;EACf,MAAM,2BAA+B;AACrC,eAAa;AACb,MAAI,IAAI,SAAS,OACf,SAAQ,IAAI,wBAAwB,WAAW;;AAInD,OAAM,eAAe,MAAM;AAC3B,KACE,CAAE,MAAM,eAAe,QAAQ,aAAY,QAAO;AAChD,MAAI,IAAI,SAAS,QAAQ;AACvB,OAAI,QAAQ,iBACV,SAAQ,IAAI,kBAAkB;AAEhC,WAAQ,IAAI,SAAS,IAAI;;GAE3B,CAEF,QAAO;AAET,QAAO,eAAe,aAAa,WAAW;;AAGhD,eAAsB,QAAQ,YAAoB;CAChD,MAAM,eAAe,KAAK,KAAK,YAAY,wCAAwC;AACnF,OAAM,OAAO,IAAI,cAAc,aAAa,CAAC,UAAU"}
@@ -1,2 +1,94 @@
1
- import{t as e}from"../maa-CkTs9UGP.mjs";import*as t from"node:fs/promises";import*as n from"node:path";import*as r from"workerpool";function i(e){return e.byteOffset===0&&e.byteLength===e.buffer.byteLength?e.buffer:e.buffer.slice(e.byteOffset,e.byteOffset+e.byteLength)}const a=i(Buffer.from(`iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=`,`base64`));async function o(){let e=new maa.CustomController({connect(){return!0},request_uuid(){return`0`},screencap(){return a}});return await e.post_connection().wait(),e}await e(process.env.MAAFW_MODULE_PATH),process.env.MAAFW_STDOUT_LEVEL&&[`Off`,`Fatal`,`Error`,`Warn`,`Info`,`Debug`,`Trace`,`All`].includes(process.env.MAAFW_STDOUT_LEVEL)&&(maa.Global.stdout_level=process.env.MAAFW_STDOUT_LEVEL);let s;const c=[];let l=()=>{};async function u(){let e=await o(),t=new maa.Resource;for(let e of process.env.MAAFW_RESOURCE_PATHS.split(n.delimiter))await t.post_bundle(e).wait();s=new maa.Tasker,s.resource=t,s.controller=e,t.register_custom_action(`@mse/action`,async e=>{for(;;){for(;c.length>0;)await c.shift()(e.context);if(await new Promise(e=>{l=e}),c.length===0)break}return!0}),s.post_task(`@mse/action`,{"@mse/action":{action:`Custom`,custom_action:`@mse/action`}})}async function d(e){s||await u();let n=i(await t.readFile(e.imagePath)),r=[],{promise:a,resolve:o}=Promise.withResolvers();return c.push(async t=>{for(let i of e.nodes){let a=await t.run_recognition(i,n);r.push({imagePath:e.imagePath,imagePathRaw:e.imagePathRaw,node:i,hit:!!a?.hit,detail:a})}o()}),l(),await a,r}r.worker({performReco:d},{onTerminate:()=>{l()}});export{};
1
+ import { t as loadMaa } from "../maa-CDsPQ-38.mjs";
2
+ import * as fs from "node:fs/promises";
3
+ import * as path from "node:path";
4
+ import * as workerpool from "workerpool";
5
+
6
+ //#region src/utils.ts
7
+ function toArrayBuffer(buffer) {
8
+ if (buffer.byteOffset === 0 && buffer.byteLength === buffer.buffer.byteLength) return buffer.buffer;
9
+ else return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
10
+ }
11
+ const image = toArrayBuffer(Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=", "base64"));
12
+ async function makeFakeController() {
13
+ const ctrl = new maa.CustomController({
14
+ connect() {
15
+ return true;
16
+ },
17
+ request_uuid() {
18
+ return "0";
19
+ },
20
+ screencap() {
21
+ return image;
22
+ }
23
+ });
24
+ await ctrl.post_connection().wait();
25
+ return ctrl;
26
+ }
27
+
28
+ //#endregion
29
+ //#region src/test/worker.ts
30
+ await loadMaa(process.env.MAAFW_MODULE_PATH);
31
+ if (process.env.MAAFW_STDOUT_LEVEL && [
32
+ "Off",
33
+ "Fatal",
34
+ "Error",
35
+ "Warn",
36
+ "Info",
37
+ "Debug",
38
+ "Trace",
39
+ "All"
40
+ ].includes(process.env.MAAFW_STDOUT_LEVEL)) maa.Global.stdout_level = process.env.MAAFW_STDOUT_LEVEL;
41
+ let inst = void 0;
42
+ const taskQueue = [];
43
+ let taskAddResolve = () => {};
44
+ async function setup() {
45
+ const ctrl = await makeFakeController();
46
+ const res = new maa.Resource();
47
+ for (const full of process.env.MAAFW_RESOURCE_PATHS.split(path.delimiter)) await res.post_bundle(full).wait();
48
+ inst = new maa.Tasker();
49
+ inst.resource = res;
50
+ inst.controller = ctrl;
51
+ res.register_custom_action("@mse/action", async (self) => {
52
+ while (true) {
53
+ while (taskQueue.length > 0) await taskQueue.shift()(self.context);
54
+ await new Promise((resolve) => {
55
+ taskAddResolve = resolve;
56
+ });
57
+ if (taskQueue.length === 0) break;
58
+ }
59
+ return true;
60
+ });
61
+ inst.post_task("@mse/action", { "@mse/action": {
62
+ action: "Custom",
63
+ custom_action: "@mse/action"
64
+ } });
65
+ }
66
+ async function performReco(job) {
67
+ if (!inst) await setup();
68
+ const image = toArrayBuffer(await fs.readFile(job.imagePath));
69
+ const result = [];
70
+ const { promise, resolve } = Promise.withResolvers();
71
+ taskQueue.push(async (context) => {
72
+ for (const node of job.nodes) {
73
+ const detail = await context.run_recognition(node, image);
74
+ result.push({
75
+ imagePath: job.imagePath,
76
+ imagePathRaw: job.imagePathRaw,
77
+ node,
78
+ hit: !!detail?.hit,
79
+ detail
80
+ });
81
+ }
82
+ resolve();
83
+ });
84
+ taskAddResolve();
85
+ await promise;
86
+ return result;
87
+ }
88
+ workerpool.worker({ performReco }, { onTerminate: () => {
89
+ taskAddResolve();
90
+ } });
91
+
92
+ //#endregion
93
+ export { };
2
94
  //# sourceMappingURL=worker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker.mjs","names":[],"sources":["../../src/utils.ts","../../src/test/worker.ts"],"sourcesContent":["import * as zlib from 'node:zlib'\n\nexport function toArrayBuffer(buffer: Buffer): ArrayBuffer {\n if (buffer.byteOffset === 0 && buffer.byteLength === buffer.buffer.byteLength) {\n return buffer.buffer as ArrayBuffer\n } else {\n return buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength\n ) as ArrayBuffer\n }\n}\n\nconst emptyPng = Buffer.from(\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',\n 'base64'\n)\nconst image = toArrayBuffer(emptyPng)\n\nexport async function makeFakeController() {\n const ctrl = new maa.CustomController({\n connect() {\n return true\n },\n request_uuid() {\n return '0'\n },\n screencap() {\n return image\n }\n })\n await ctrl.post_connection().wait()\n return ctrl\n}\n\nexport function gzCompress(data: string) {\n const buf = Buffer.from(data)\n const compressed = zlib.gzipSync(buf)\n return compressed.toString('base64')\n}\n\nexport function gzDecompress(data: string): string {\n return zlib.gunzipSync(Buffer.from(data, 'base64')).toString()\n}\n","import * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\nimport * as workerpool from 'workerpool'\n\nimport { makeFakeController, toArrayBuffer } from '../utils'\nimport { loadMaa } from '../utils/maa'\nimport type { RecoJob, RecoResult } from './types'\n\nawait loadMaa(process.env.MAAFW_MODULE_PATH!)\n\nconst stdoutLevels = ['Off', 'Fatal', 'Error', 'Warn', 'Info', 'Debug', 'Trace', 'All'] as const\ntype MaaStdoutLevel = (typeof stdoutLevels)[number]\nif (\n process.env.MAAFW_STDOUT_LEVEL &&\n stdoutLevels.includes(process.env.MAAFW_STDOUT_LEVEL as MaaStdoutLevel)\n) {\n maa.Global.stdout_level = process.env.MAAFW_STDOUT_LEVEL as MaaStdoutLevel\n}\n\nlet inst: maa.Tasker | undefined = undefined\nconst taskQueue: ((ctx: maa.Context) => Promise<void>)[] = []\nlet taskAddResolve: () => void = () => {}\n\nasync function setup() {\n const ctrl = await makeFakeController()\n const res = new maa.Resource()\n for (const full of process.env.MAAFW_RESOURCE_PATHS!.split(path.delimiter)) {\n await res.post_bundle(full).wait()\n }\n inst = new maa.Tasker()\n inst.resource = res\n inst.controller = ctrl\n\n res.register_custom_action('@mse/action', async self => {\n while (true) {\n while (taskQueue.length > 0) {\n const task = taskQueue.shift()!\n await task(self.context)\n }\n await new Promise<void>(resolve => {\n taskAddResolve = resolve\n })\n if (taskQueue.length === 0) {\n break\n }\n }\n return true\n })\n\n inst!.post_task('@mse/action', {\n '@mse/action': {\n action: 'Custom',\n custom_action: '@mse/action'\n }\n })\n}\n\nasync function performReco(job: RecoJob) {\n if (!inst) {\n await setup()\n }\n\n const image = toArrayBuffer(await fs.readFile(job.imagePath))\n const result: RecoResult[] = []\n\n const { promise, resolve } = Promise.withResolvers<void>()\n\n taskQueue.push(async context => {\n for (const node of job.nodes) {\n const detail = await context.run_recognition(node, image)\n result.push({\n imagePath: job.imagePath,\n imagePathRaw: job.imagePathRaw,\n node: node,\n hit: !!detail?.hit,\n detail\n })\n }\n resolve()\n })\n taskAddResolve()\n await promise\n\n return result\n}\n\nworkerpool.worker(\n {\n performReco\n },\n {\n onTerminate: () => {\n taskAddResolve()\n }\n }\n)\n"],"mappings":"oIAEA,SAAgB,EAAc,EAA6B,CAIvD,OAHE,EAAO,aAAe,GAAK,EAAO,aAAe,EAAO,OAAO,WAC1D,EAAO,OAEP,EAAO,OAAO,MACnB,EAAO,WACP,EAAO,WAAa,EAAO,WAC5B,CAQL,MAAM,EAAQ,EAJG,OAAO,KACtB,mIACA,SACD,CACoC,CAErC,eAAsB,GAAqB,CACzC,IAAM,EAAO,IAAI,IAAI,iBAAiB,CACpC,SAAU,CACR,MAAO,IAET,cAAe,CACb,MAAO,KAET,WAAY,CACV,OAAO,GAEV,CAAC,CAEF,OADA,MAAM,EAAK,iBAAiB,CAAC,MAAM,CAC5B,ECxBT,MAAM,EAAQ,QAAQ,IAAI,kBAAmB,CAK3C,QAAQ,IAAI,oBAHO,CAAC,MAAO,QAAS,QAAS,OAAQ,OAAQ,QAAS,QAAS,MAAM,CAIxE,SAAS,QAAQ,IAAI,mBAAqC,GAEvE,IAAI,OAAO,aAAe,QAAQ,IAAI,oBAGxC,IAAI,EACJ,MAAM,EAAqD,EAAE,CAC7D,IAAI,MAAmC,GAEvC,eAAe,GAAQ,CACrB,IAAM,EAAO,MAAM,GAAoB,CACjC,EAAM,IAAI,IAAI,SACpB,IAAK,IAAM,KAAQ,QAAQ,IAAI,qBAAsB,MAAM,EAAK,UAAU,CACxE,MAAM,EAAI,YAAY,EAAK,CAAC,MAAM,CAEpC,EAAO,IAAI,IAAI,OACf,EAAK,SAAW,EAChB,EAAK,WAAa,EAElB,EAAI,uBAAuB,cAAe,KAAM,IAAQ,CACtD,OAAa,CACX,KAAO,EAAU,OAAS,GAExB,MADa,EAAU,OAAO,CACnB,EAAK,QAAQ,CAK1B,GAHA,MAAM,IAAI,QAAc,GAAW,CACjC,EAAiB,GACjB,CACE,EAAU,SAAW,EACvB,MAGJ,MAAO,IACP,CAEF,EAAM,UAAU,cAAe,CAC7B,cAAe,CACb,OAAQ,SACR,cAAe,cAChB,CACF,CAAC,CAGJ,eAAe,EAAY,EAAc,CAClC,GACH,MAAM,GAAO,CAGf,IAAM,EAAQ,EAAc,MAAM,EAAG,SAAS,EAAI,UAAU,CAAC,CACvD,EAAuB,EAAE,CAEzB,CAAE,UAAS,WAAY,QAAQ,eAAqB,CAkB1D,OAhBA,EAAU,KAAK,KAAM,IAAW,CAC9B,IAAK,IAAM,KAAQ,EAAI,MAAO,CAC5B,IAAM,EAAS,MAAM,EAAQ,gBAAgB,EAAM,EAAM,CACzD,EAAO,KAAK,CACV,UAAW,EAAI,UACf,aAAc,EAAI,aACZ,OACN,IAAK,CAAC,CAAC,GAAQ,IACf,SACD,CAAC,CAEJ,GAAS,EACT,CACF,GAAgB,CAChB,MAAM,EAEC,EAGT,EAAW,OACT,CACE,cACD,CACD,CACE,gBAAmB,CACjB,GAAgB,EAEnB,CACF"}
1
+ {"version":3,"file":"worker.mjs","names":[],"sources":["../../src/utils.ts","../../src/test/worker.ts"],"sourcesContent":["import * as zlib from 'node:zlib'\n\nexport function toArrayBuffer(buffer: Buffer): ArrayBuffer {\n if (buffer.byteOffset === 0 && buffer.byteLength === buffer.buffer.byteLength) {\n return buffer.buffer as ArrayBuffer\n } else {\n return buffer.buffer.slice(\n buffer.byteOffset,\n buffer.byteOffset + buffer.byteLength\n ) as ArrayBuffer\n }\n}\n\nconst emptyPng = Buffer.from(\n 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=',\n 'base64'\n)\nconst image = toArrayBuffer(emptyPng)\n\nexport async function makeFakeController() {\n const ctrl = new maa.CustomController({\n connect() {\n return true\n },\n request_uuid() {\n return '0'\n },\n screencap() {\n return image\n }\n })\n await ctrl.post_connection().wait()\n return ctrl\n}\n\nexport function gzCompress(data: string) {\n const buf = Buffer.from(data)\n const compressed = zlib.gzipSync(buf)\n return compressed.toString('base64')\n}\n\nexport function gzDecompress(data: string): string {\n return zlib.gunzipSync(Buffer.from(data, 'base64')).toString()\n}\n","import * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\nimport * as workerpool from 'workerpool'\n\nimport { makeFakeController, toArrayBuffer } from '../utils'\nimport { loadMaa } from '../utils/maa'\nimport type { RecoJob, RecoResult } from './types'\n\nawait loadMaa(process.env.MAAFW_MODULE_PATH!)\n\nconst stdoutLevels = ['Off', 'Fatal', 'Error', 'Warn', 'Info', 'Debug', 'Trace', 'All'] as const\ntype MaaStdoutLevel = (typeof stdoutLevels)[number]\nif (\n process.env.MAAFW_STDOUT_LEVEL &&\n stdoutLevels.includes(process.env.MAAFW_STDOUT_LEVEL as MaaStdoutLevel)\n) {\n maa.Global.stdout_level = process.env.MAAFW_STDOUT_LEVEL as MaaStdoutLevel\n}\n\nlet inst: maa.Tasker | undefined = undefined\nconst taskQueue: ((ctx: maa.Context) => Promise<void>)[] = []\nlet taskAddResolve: () => void = () => {}\n\nasync function setup() {\n const ctrl = await makeFakeController()\n const res = new maa.Resource()\n for (const full of process.env.MAAFW_RESOURCE_PATHS!.split(path.delimiter)) {\n await res.post_bundle(full).wait()\n }\n inst = new maa.Tasker()\n inst.resource = res\n inst.controller = ctrl\n\n res.register_custom_action('@mse/action', async self => {\n while (true) {\n while (taskQueue.length > 0) {\n const task = taskQueue.shift()!\n await task(self.context)\n }\n await new Promise<void>(resolve => {\n taskAddResolve = resolve\n })\n if (taskQueue.length === 0) {\n break\n }\n }\n return true\n })\n\n inst!.post_task('@mse/action', {\n '@mse/action': {\n action: 'Custom',\n custom_action: '@mse/action'\n }\n })\n}\n\nasync function performReco(job: RecoJob) {\n if (!inst) {\n await setup()\n }\n\n const image = toArrayBuffer(await fs.readFile(job.imagePath))\n const result: RecoResult[] = []\n\n const { promise, resolve } = Promise.withResolvers<void>()\n\n taskQueue.push(async context => {\n for (const node of job.nodes) {\n const detail = await context.run_recognition(node, image)\n result.push({\n imagePath: job.imagePath,\n imagePathRaw: job.imagePathRaw,\n node: node,\n hit: !!detail?.hit,\n detail\n })\n }\n resolve()\n })\n taskAddResolve()\n await promise\n\n return result\n}\n\nworkerpool.worker(\n {\n performReco\n },\n {\n onTerminate: () => {\n taskAddResolve()\n }\n }\n)\n"],"mappings":";;;;;;AAEA,SAAgB,cAAc,QAA6B;AACzD,KAAI,OAAO,eAAe,KAAK,OAAO,eAAe,OAAO,OAAO,WACjE,QAAO,OAAO;KAEd,QAAO,OAAO,OAAO,MACnB,OAAO,YACP,OAAO,aAAa,OAAO,WAC5B;;AAQL,MAAM,QAAQ,cAJG,OAAO,KACtB,oIACA,SACD,CACoC;AAErC,eAAsB,qBAAqB;CACzC,MAAM,OAAO,IAAI,IAAI,iBAAiB;EACpC,UAAU;AACR,UAAO;;EAET,eAAe;AACb,UAAO;;EAET,YAAY;AACV,UAAO;;EAEV,CAAC;AACF,OAAM,KAAK,iBAAiB,CAAC,MAAM;AACnC,QAAO;;;;;ACxBT,MAAM,QAAQ,QAAQ,IAAI,kBAAmB;AAI7C,IACE,QAAQ,IAAI,sBAHO;CAAC;CAAO;CAAS;CAAS;CAAQ;CAAQ;CAAS;CAAS;CAAM,CAIxE,SAAS,QAAQ,IAAI,mBAAqC,CAEvE,KAAI,OAAO,eAAe,QAAQ,IAAI;AAGxC,IAAI,OAA+B;AACnC,MAAM,YAAqD,EAAE;AAC7D,IAAI,uBAAmC;AAEvC,eAAe,QAAQ;CACrB,MAAM,OAAO,MAAM,oBAAoB;CACvC,MAAM,MAAM,IAAI,IAAI,UAAU;AAC9B,MAAK,MAAM,QAAQ,QAAQ,IAAI,qBAAsB,MAAM,KAAK,UAAU,CACxE,OAAM,IAAI,YAAY,KAAK,CAAC,MAAM;AAEpC,QAAO,IAAI,IAAI,QAAQ;AACvB,MAAK,WAAW;AAChB,MAAK,aAAa;AAElB,KAAI,uBAAuB,eAAe,OAAM,SAAQ;AACtD,SAAO,MAAM;AACX,UAAO,UAAU,SAAS,EAExB,OADa,UAAU,OAAO,CACnB,KAAK,QAAQ;AAE1B,SAAM,IAAI,SAAc,YAAW;AACjC,qBAAiB;KACjB;AACF,OAAI,UAAU,WAAW,EACvB;;AAGJ,SAAO;GACP;AAEF,MAAM,UAAU,eAAe,EAC7B,eAAe;EACb,QAAQ;EACR,eAAe;EAChB,EACF,CAAC;;AAGJ,eAAe,YAAY,KAAc;AACvC,KAAI,CAAC,KACH,OAAM,OAAO;CAGf,MAAM,QAAQ,cAAc,MAAM,GAAG,SAAS,IAAI,UAAU,CAAC;CAC7D,MAAM,SAAuB,EAAE;CAE/B,MAAM,EAAE,SAAS,YAAY,QAAQ,eAAqB;AAE1D,WAAU,KAAK,OAAM,YAAW;AAC9B,OAAK,MAAM,QAAQ,IAAI,OAAO;GAC5B,MAAM,SAAS,MAAM,QAAQ,gBAAgB,MAAM,MAAM;AACzD,UAAO,KAAK;IACV,WAAW,IAAI;IACf,cAAc,IAAI;IACZ;IACN,KAAK,CAAC,CAAC,QAAQ;IACf;IACD,CAAC;;AAEJ,WAAS;GACT;AACF,iBAAgB;AAChB,OAAM;AAEN,QAAO;;AAGT,WAAW,OACT,EACE,aACD,EACD,EACE,mBAAmB;AACjB,iBAAgB;GAEnB,CACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nekosu/maa-tools",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "maa-tools": "bin/maa-tools"
@@ -21,9 +21,10 @@
21
21
  "dependencies": {
22
22
  "@actions/core": "^3.0.0",
23
23
  "jiti": "^2.6.1",
24
+ "jsonc-parser": "^3.3.1",
24
25
  "workerpool": "^10.0.1",
26
+ "@nekosu/maa-pipeline-manager": "1.0.1",
25
27
  "@nekosu/maa-locale": "1.0.0",
26
- "@nekosu/maa-pipeline-manager": "1.0.0",
27
28
  "@nekosu/maa-version-manager": "1.0.2"
28
29
  },
29
30
  "devDependencies": {
@@ -1,2 +0,0 @@
1
- import*as e from"node:path";import*as t from"node:os";import*as n from"node:url";import{MaaVersionManager as r}from"@nekosu/maa-version-manager";var i=`@nekosu/maa-tools`,a={"@maaxyz/maa-node":`5.7.2`,"@tsconfig/node24":`^24.0.4`,"@types/node":`^25.3.0`,"@types/source-map-support":`^0.5.10`,"source-map-support":`^0.5.21`,typescript:`^5.9.3`};async function o(n){let i=new r(n.maaCache??e.join(t.homedir(),`.maa-checker`)),o=n.maaVersion;if(o===`latest`){let e=(await i.fetchLatest())?.version;e&&(o=e,n.mode!==`json`&&console.log(`use latest version ${e}`))}if(!o){let e=a[`@maaxyz/maa-node`];o=e,n.mode!==`json`&&console.log(`use fallback version ${e}`)}return await i.init(),await i.prepare(o,e=>{n.mode!==`json`&&(e===`prepare-folder`&&console.log(`preparing maafw`),console.log(` `+e))})?i.moduleFolder(o):null}async function s(t){let r=e.join(t,`@maaxyz/maa-node/dist/index-client.js`);await import(n.pathToFileURL(r).toString())}export{o as n,i as r,s as t};
2
- //# sourceMappingURL=maa-CkTs9UGP.mjs.map