@pixui-dev/inflight-test-webpack-plugin 0.0.7-inflight.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/index.cjs ADDED
@@ -0,0 +1,226 @@
1
+ Object.defineProperties(exports, {
2
+ __esModule: { value: true },
3
+ [Symbol.toStringTag]: { value: "Module" }
4
+ });
5
+ //#region \0rolldown/runtime.js
6
+ var __create = Object.create;
7
+ var __defProp = Object.defineProperty;
8
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
9
+ var __getOwnPropNames = Object.getOwnPropertyNames;
10
+ var __getProtoOf = Object.getPrototypeOf;
11
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
14
+ key = keys[i];
15
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
16
+ get: ((k) => from[k]).bind(null, key),
17
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
18
+ });
19
+ }
20
+ return to;
21
+ };
22
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
23
+ value: mod,
24
+ enumerable: true
25
+ }) : target, mod));
26
+ //#endregion
27
+ let node_fs = require("node:fs");
28
+ let node_path = require("node:path");
29
+ let picomatch = require("picomatch");
30
+ picomatch = __toESM(picomatch, 1);
31
+ //#region src/index.ts
32
+ /**
33
+ * @pixui-dev/inflight-test-webpack-plugin
34
+ *
35
+ * Wires inflight-test into a PixUI activity's webpack build:
36
+ * - discovers test files by glob (default `**\/*.test.{ts,tsx,js,jsx}`),
37
+ * - generates a runner module that binds the discovered cases to the
38
+ * inflight-test runtime, exporting `start` / `startWithoutReport`,
39
+ * - and aliases `@pixui-dev/inflight-test/runner` to that generated module,
40
+ * so the activity just does
41
+ * `import { start } from '@pixui-dev/inflight-test/runner'`
42
+ * and calls it (from a button / QA panel) — no globals, no separate
43
+ * entry/chunk to load.
44
+ *
45
+ * The cases are inlined (`webpackMode: "eager"`) into whatever chunk imports the
46
+ * runner, because the PixUI QuickJS runtime has no async chunk loader.
47
+ *
48
+ * Cross-version: it only mutates `resolve.alias` (+ writes a file), which is
49
+ * identical on webpack 4 and 5 — no version-specific entry/asset APIs.
50
+ */
51
+ const ALWAYS_EXCLUDE = [
52
+ "**/node_modules/**",
53
+ "**/dist/**",
54
+ "**/build/**",
55
+ "**/.git/**"
56
+ ];
57
+ function toArray(v, fallback) {
58
+ if (v == null) return fallback;
59
+ return Array.isArray(v) ? v : [v];
60
+ }
61
+ var InflightTestPlugin = class {
62
+ _opts;
63
+ constructor(options = {}) {
64
+ this._opts = options;
65
+ }
66
+ apply(compiler) {
67
+ if (this._opts.enabled === false) return;
68
+ const cwd = (0, node_path.resolve)(this._opts.cwd ?? compiler.context ?? process.cwd());
69
+ const runtimeImport = this._opts.runtimeImport ?? "@pixui-dev/inflight-test";
70
+ const opts = {
71
+ include: toArray(this._opts.include, ["**/*.test.{ts,tsx,js,jsx}"]),
72
+ exclude: toArray(this._opts.exclude, []),
73
+ cwd,
74
+ runtimeImport,
75
+ runnerImport: this._opts.runnerImport ?? `${runtimeImport}/runner`,
76
+ bridge: this._opts.bridge ?? "gamelet",
77
+ gameletImport: this._opts.gameletImport ?? "gamelet-pixui-frame"
78
+ };
79
+ const testFiles = this._discover(opts);
80
+ const runnerFile = this._writeRunnerModule(opts, testFiles);
81
+ this._aliasRunner(compiler, opts.runnerImport, runnerFile);
82
+ this._aliasRuntimeForWebpack4(compiler, opts.runtimeImport);
83
+ }
84
+ /**
85
+ * Point the runner specifier at the generated module via `resolve.alias`.
86
+ * Works identically on webpack 4 and 5 (object or array alias forms).
87
+ */
88
+ _aliasRunner(compiler, specifier, file) {
89
+ const resolveOpts = compiler.options.resolve ??= {};
90
+ const alias = resolveOpts.alias ??= {};
91
+ if (Array.isArray(alias)) alias.push({
92
+ name: specifier,
93
+ alias: file,
94
+ onlyModule: true
95
+ });
96
+ else alias[`${specifier}$`] = file;
97
+ }
98
+ /**
99
+ * webpack 4 doesn't support package.json `exports`. Alias the runtime's main
100
+ * entry to its dist file so `import … from '@pixui-dev/inflight-test'` resolves.
101
+ * On webpack 5 the alias is redundant but harmless.
102
+ */
103
+ _aliasRuntimeForWebpack4(compiler, runtimeImport) {
104
+ let pkgDir;
105
+ try {
106
+ pkgDir = require.resolve(`${runtimeImport}/package.json`).replace(/[\\/]package\.json$/, "");
107
+ } catch {
108
+ return;
109
+ }
110
+ const main = (0, node_path.join)(pkgDir, "dist", "index.js");
111
+ if (!(0, node_fs.existsSync)(main)) return;
112
+ const resolveOpts = compiler.options.resolve ??= {};
113
+ const alias = resolveOpts.alias ??= {};
114
+ if (Array.isArray(alias)) alias.push({
115
+ name: runtimeImport,
116
+ alias: main,
117
+ onlyModule: true
118
+ });
119
+ else alias[`${runtimeImport}$`] = main;
120
+ }
121
+ _discover(opts) {
122
+ const isMatch = (0, picomatch.default)(opts.include, { dot: false });
123
+ const isExcluded = (0, picomatch.default)([...ALWAYS_EXCLUDE, ...opts.exclude], { dot: true });
124
+ const out = [];
125
+ const walk = (dir) => {
126
+ let entries;
127
+ try {
128
+ entries = (0, node_fs.readdirSync)(dir);
129
+ } catch {
130
+ return;
131
+ }
132
+ for (const name of entries) {
133
+ const abs = (0, node_path.join)(dir, name);
134
+ const rel = (0, node_path.relative)(opts.cwd, abs).replace(/\\/g, "/");
135
+ if (isExcluded(rel)) continue;
136
+ let st;
137
+ try {
138
+ st = (0, node_fs.statSync)(abs);
139
+ } catch {
140
+ continue;
141
+ }
142
+ if (st.isDirectory()) walk(abs);
143
+ else if (isMatch(rel)) out.push({
144
+ id: rel,
145
+ absolute: abs.replace(/\\/g, "/")
146
+ });
147
+ }
148
+ };
149
+ walk(opts.cwd);
150
+ out.sort((a, b) => a.id.localeCompare(b.id));
151
+ return out;
152
+ }
153
+ _writeRunnerModule(opts, testFiles) {
154
+ const cacheDir = (0, node_path.join)(opts.cwd, "node_modules", ".cache", "inflight-test");
155
+ if (!(0, node_fs.existsSync)(cacheDir)) (0, node_fs.mkdirSync)(cacheDir, { recursive: true });
156
+ const runnerFile = (0, node_path.join)(cacheDir, "runner.mjs");
157
+ const specs = testFiles.map((f) => {
158
+ return ` { id: ${JSON.stringify(f.id)}, load: () => import(/* webpackMode: "eager" */ ${JSON.stringify(f.absolute)}) },`;
159
+ }).join("\n");
160
+ const useGamelet = opts.bridge === "gamelet";
161
+ const gameletImportLine = useGamelet ? `import __inflightGamelet from ${JSON.stringify(opts.gameletImport)}\n` : "";
162
+ const bridgeBlock = useGamelet ? `
163
+ // Default activity bridge over gamelet-pixui-frame (host screenshot protocol etc.).
164
+ var GameletAPI = __inflightGamelet.GameletAPI
165
+ function makeActivityBridge() {
166
+ return {
167
+ callGame: function (protocol, payload) {
168
+ // gamelet-pixui-frame fills appId/appName automatically; we only send the
169
+ // type + content envelope and the call-specific payload.
170
+ GameletAPI.callGame(JSON.stringify(Object.assign({ type: protocol, content: '' }, payload)))
171
+ },
172
+ onSDKMessage: function (protocol, handler) {
173
+ var myAppId = GameletAPI.getAppID()
174
+ var listener = function (cmd) {
175
+ var msg
176
+ try { msg = JSON.parse(cmd) } catch (e) { return }
177
+ if (!msg || msg.type !== protocol) return
178
+ // Ignore messages addressed to another app: addOnGameCommandListener
179
+ // also subscribes the GLOBAL game-message channel, which isn't
180
+ // app-scoped, so a different app's callback can reach us. Compare as
181
+ // strings — the backend sends appId as a string ("7442") while
182
+ // getAppID() returns a number (7442).
183
+ if (msg.appId != null && String(msg.appId) !== String(myAppId)) return
184
+ handler(msg)
185
+ }
186
+ GameletAPI.addOnGameCommandListener(listener)
187
+ return function () { GameletAPI.removeOnGameCommandListener(listener) }
188
+ },
189
+ }
190
+ }
191
+ ` : "";
192
+ const applyBridge = useGamelet ? ` if (!o.activityBridge) o.activityBridge = makeActivityBridge()\n` : "";
193
+ (0, node_fs.writeFileSync)(runnerFile, `// AUTO-GENERATED by @pixui-dev/inflight-test-webpack-plugin — do not edit.
194
+ import { start as _start } from ${JSON.stringify(opts.runtimeImport)}
195
+ ${gameletImportLine}
196
+ const specs = [
197
+ ${specs}
198
+ ]
199
+
200
+ /** Ids of the discovered test files. */
201
+ export const testFiles = specs.map(function (s) { return s.id })
202
+ ${bridgeBlock}
203
+ /**
204
+ * Run the discovered inflight tests. Writes a Vitest blob report by default
205
+ * (auto-wired from the PixUI host \`os\` / \`external.writeablePath\`); pass
206
+ * \`{ report: false }\` to skip. Call from a button / QA panel — no options
207
+ * needed in the normal case.
208
+ */
209
+ export function start(options) {
210
+ var o = Object.assign({}, options)
211
+ ${applyBridge} return _start(specs, o)
212
+ }
213
+
214
+ /** Run the discovered inflight tests without writing a report. */
215
+ export function startWithoutReport(options) {
216
+ return start(Object.assign({}, options, { report: false }))
217
+ }
218
+ `, "utf8");
219
+ return runnerFile;
220
+ }
221
+ };
222
+ //#endregion
223
+ exports.InflightTestPlugin = InflightTestPlugin;
224
+ exports.default = InflightTestPlugin;
225
+
226
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":[],"sources":["../src/index.ts"],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { Compiler } from "webpack";
2
+
3
+ //#region src/index.d.ts
4
+ interface InflightTestPluginOptions {
5
+ /** Glob(s) for discovering test files. Default: `**\/*.test.{ts,tsx,js,jsx}`. */
6
+ include?: string | string[];
7
+ /** Glob(s) to exclude. `node_modules` / build dirs are always excluded. */
8
+ exclude?: string | string[];
9
+ /** Root directory to scan. Default: the webpack `context`. */
10
+ cwd?: string;
11
+ /**
12
+ * Enable the plugin. Default `true` — inflight-test is meant to ship with the
13
+ * activity (including production), that's the point. Set `false` to opt out.
14
+ */
15
+ enabled?: boolean;
16
+ /** The inflight-test runtime package the generated runner imports. */
17
+ runtimeImport?: string;
18
+ /**
19
+ * The subpath specifier the activity imports the runner from. Default
20
+ * `${runtimeImport}/runner` (i.e. `@pixui-dev/inflight-test/runner`).
21
+ */
22
+ runnerImport?: string;
23
+ /**
24
+ * Default activity bridge wired into `start()` so the activity needs no
25
+ * options for screenshots:
26
+ * - `'gamelet'` (default): wire a bridge over `gamelet-pixui-frame`
27
+ * (`GameletAPI.callGame` + `addOnGameCommandListener`). All normal PixUI
28
+ * activities use this SDK, so the bridge lives here — no per-repo file.
29
+ * - `'none'`: wire nothing (caller passes their own `activityBridge`); use
30
+ * for non-gamelet hosts.
31
+ */
32
+ bridge?: 'gamelet' | 'none';
33
+ /** The SDK package the `'gamelet'` bridge imports. Default `gamelet-pixui-frame`. */
34
+ gameletImport?: string;
35
+ }
36
+ declare class InflightTestPlugin {
37
+ private readonly _opts;
38
+ constructor(options?: InflightTestPluginOptions);
39
+ apply(compiler: Compiler): void;
40
+ /**
41
+ * Point the runner specifier at the generated module via `resolve.alias`.
42
+ * Works identically on webpack 4 and 5 (object or array alias forms).
43
+ */
44
+ private _aliasRunner;
45
+ /**
46
+ * webpack 4 doesn't support package.json `exports`. Alias the runtime's main
47
+ * entry to its dist file so `import … from '@pixui-dev/inflight-test'` resolves.
48
+ * On webpack 5 the alias is redundant but harmless.
49
+ */
50
+ private _aliasRuntimeForWebpack4;
51
+ private _discover;
52
+ private _writeRunnerModule;
53
+ }
54
+ //#endregion
55
+ export { InflightTestPlugin, InflightTestPlugin as default, InflightTestPluginOptions };
56
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;UAyBiB,yBAAA;EAmDE;EAjDjB,OAAA;EAmDqB;EAjDrB,OAAA;EAqDA;EAnDA,GAAA;EAmDM;;;;EA9CN,OAAA;EAsJ0B;EApJ1B,aAAA;;;;;EAKA,YAAA;;;;;;;;;;EAUA,MAAA;;EAEA,aAAA;AAAA;AAAA,cAoBW,kBAAA;EAAA,iBACM,KAAA;cAEL,OAAA,GAAS,yBAAA;EAIrB,KAAA,CAAM,QAAA,EAAU,QAAA;;;;;UA0BR,YAAA;;;;;;UAgBA,wBAAA;EAAA,QAuBA,SAAA;EAAA,QAuCA,kBAAA;AAAA"}
@@ -0,0 +1,56 @@
1
+ import { Compiler } from "webpack";
2
+
3
+ //#region src/index.d.ts
4
+ interface InflightTestPluginOptions {
5
+ /** Glob(s) for discovering test files. Default: `**\/*.test.{ts,tsx,js,jsx}`. */
6
+ include?: string | string[];
7
+ /** Glob(s) to exclude. `node_modules` / build dirs are always excluded. */
8
+ exclude?: string | string[];
9
+ /** Root directory to scan. Default: the webpack `context`. */
10
+ cwd?: string;
11
+ /**
12
+ * Enable the plugin. Default `true` — inflight-test is meant to ship with the
13
+ * activity (including production), that's the point. Set `false` to opt out.
14
+ */
15
+ enabled?: boolean;
16
+ /** The inflight-test runtime package the generated runner imports. */
17
+ runtimeImport?: string;
18
+ /**
19
+ * The subpath specifier the activity imports the runner from. Default
20
+ * `${runtimeImport}/runner` (i.e. `@pixui-dev/inflight-test/runner`).
21
+ */
22
+ runnerImport?: string;
23
+ /**
24
+ * Default activity bridge wired into `start()` so the activity needs no
25
+ * options for screenshots:
26
+ * - `'gamelet'` (default): wire a bridge over `gamelet-pixui-frame`
27
+ * (`GameletAPI.callGame` + `addOnGameCommandListener`). All normal PixUI
28
+ * activities use this SDK, so the bridge lives here — no per-repo file.
29
+ * - `'none'`: wire nothing (caller passes their own `activityBridge`); use
30
+ * for non-gamelet hosts.
31
+ */
32
+ bridge?: 'gamelet' | 'none';
33
+ /** The SDK package the `'gamelet'` bridge imports. Default `gamelet-pixui-frame`. */
34
+ gameletImport?: string;
35
+ }
36
+ declare class InflightTestPlugin {
37
+ private readonly _opts;
38
+ constructor(options?: InflightTestPluginOptions);
39
+ apply(compiler: Compiler): void;
40
+ /**
41
+ * Point the runner specifier at the generated module via `resolve.alias`.
42
+ * Works identically on webpack 4 and 5 (object or array alias forms).
43
+ */
44
+ private _aliasRunner;
45
+ /**
46
+ * webpack 4 doesn't support package.json `exports`. Alias the runtime's main
47
+ * entry to its dist file so `import … from '@pixui-dev/inflight-test'` resolves.
48
+ * On webpack 5 the alias is redundant but harmless.
49
+ */
50
+ private _aliasRuntimeForWebpack4;
51
+ private _discover;
52
+ private _writeRunnerModule;
53
+ }
54
+ //#endregion
55
+ export { InflightTestPlugin, InflightTestPlugin as default, InflightTestPluginOptions };
56
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;UAyBiB,yBAAA;EAmDE;EAjDjB,OAAA;EAmDqB;EAjDrB,OAAA;EAqDA;EAnDA,GAAA;EAmDM;;;;EA9CN,OAAA;EAsJ0B;EApJ1B,aAAA;;;;;EAKA,YAAA;;;;;;;;;;EAUA,MAAA;;EAEA,aAAA;AAAA;AAAA,cAoBW,kBAAA;EAAA,iBACM,KAAA;cAEL,OAAA,GAAS,yBAAA;EAIrB,KAAA,CAAM,QAAA,EAAU,QAAA;;;;;UA0BR,YAAA;;;;;;UAgBA,wBAAA;EAAA,QAuBA,SAAA;EAAA,QAuCA,kBAAA;AAAA"}
package/dist/index.mjs ADDED
@@ -0,0 +1,202 @@
1
+ import { createRequire } from "node:module";
2
+ import { existsSync, mkdirSync, readdirSync, statSync, writeFileSync } from "node:fs";
3
+ import { join, relative, resolve } from "node:path";
4
+ import picomatch from "picomatch";
5
+ //#region \0rolldown/runtime.js
6
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
7
+ //#endregion
8
+ //#region src/index.ts
9
+ /**
10
+ * @pixui-dev/inflight-test-webpack-plugin
11
+ *
12
+ * Wires inflight-test into a PixUI activity's webpack build:
13
+ * - discovers test files by glob (default `**\/*.test.{ts,tsx,js,jsx}`),
14
+ * - generates a runner module that binds the discovered cases to the
15
+ * inflight-test runtime, exporting `start` / `startWithoutReport`,
16
+ * - and aliases `@pixui-dev/inflight-test/runner` to that generated module,
17
+ * so the activity just does
18
+ * `import { start } from '@pixui-dev/inflight-test/runner'`
19
+ * and calls it (from a button / QA panel) — no globals, no separate
20
+ * entry/chunk to load.
21
+ *
22
+ * The cases are inlined (`webpackMode: "eager"`) into whatever chunk imports the
23
+ * runner, because the PixUI QuickJS runtime has no async chunk loader.
24
+ *
25
+ * Cross-version: it only mutates `resolve.alias` (+ writes a file), which is
26
+ * identical on webpack 4 and 5 — no version-specific entry/asset APIs.
27
+ */
28
+ const ALWAYS_EXCLUDE = [
29
+ "**/node_modules/**",
30
+ "**/dist/**",
31
+ "**/build/**",
32
+ "**/.git/**"
33
+ ];
34
+ function toArray(v, fallback) {
35
+ if (v == null) return fallback;
36
+ return Array.isArray(v) ? v : [v];
37
+ }
38
+ var InflightTestPlugin = class {
39
+ _opts;
40
+ constructor(options = {}) {
41
+ this._opts = options;
42
+ }
43
+ apply(compiler) {
44
+ if (this._opts.enabled === false) return;
45
+ const cwd = resolve(this._opts.cwd ?? compiler.context ?? process.cwd());
46
+ const runtimeImport = this._opts.runtimeImport ?? "@pixui-dev/inflight-test";
47
+ const opts = {
48
+ include: toArray(this._opts.include, ["**/*.test.{ts,tsx,js,jsx}"]),
49
+ exclude: toArray(this._opts.exclude, []),
50
+ cwd,
51
+ runtimeImport,
52
+ runnerImport: this._opts.runnerImport ?? `${runtimeImport}/runner`,
53
+ bridge: this._opts.bridge ?? "gamelet",
54
+ gameletImport: this._opts.gameletImport ?? "gamelet-pixui-frame"
55
+ };
56
+ const testFiles = this._discover(opts);
57
+ const runnerFile = this._writeRunnerModule(opts, testFiles);
58
+ this._aliasRunner(compiler, opts.runnerImport, runnerFile);
59
+ this._aliasRuntimeForWebpack4(compiler, opts.runtimeImport);
60
+ }
61
+ /**
62
+ * Point the runner specifier at the generated module via `resolve.alias`.
63
+ * Works identically on webpack 4 and 5 (object or array alias forms).
64
+ */
65
+ _aliasRunner(compiler, specifier, file) {
66
+ const resolveOpts = compiler.options.resolve ??= {};
67
+ const alias = resolveOpts.alias ??= {};
68
+ if (Array.isArray(alias)) alias.push({
69
+ name: specifier,
70
+ alias: file,
71
+ onlyModule: true
72
+ });
73
+ else alias[`${specifier}$`] = file;
74
+ }
75
+ /**
76
+ * webpack 4 doesn't support package.json `exports`. Alias the runtime's main
77
+ * entry to its dist file so `import … from '@pixui-dev/inflight-test'` resolves.
78
+ * On webpack 5 the alias is redundant but harmless.
79
+ */
80
+ _aliasRuntimeForWebpack4(compiler, runtimeImport) {
81
+ let pkgDir;
82
+ try {
83
+ pkgDir = __require.resolve(`${runtimeImport}/package.json`).replace(/[\\/]package\.json$/, "");
84
+ } catch {
85
+ return;
86
+ }
87
+ const main = join(pkgDir, "dist", "index.js");
88
+ if (!existsSync(main)) return;
89
+ const resolveOpts = compiler.options.resolve ??= {};
90
+ const alias = resolveOpts.alias ??= {};
91
+ if (Array.isArray(alias)) alias.push({
92
+ name: runtimeImport,
93
+ alias: main,
94
+ onlyModule: true
95
+ });
96
+ else alias[`${runtimeImport}$`] = main;
97
+ }
98
+ _discover(opts) {
99
+ const isMatch = picomatch(opts.include, { dot: false });
100
+ const isExcluded = picomatch([...ALWAYS_EXCLUDE, ...opts.exclude], { dot: true });
101
+ const out = [];
102
+ const walk = (dir) => {
103
+ let entries;
104
+ try {
105
+ entries = readdirSync(dir);
106
+ } catch {
107
+ return;
108
+ }
109
+ for (const name of entries) {
110
+ const abs = join(dir, name);
111
+ const rel = relative(opts.cwd, abs).replace(/\\/g, "/");
112
+ if (isExcluded(rel)) continue;
113
+ let st;
114
+ try {
115
+ st = statSync(abs);
116
+ } catch {
117
+ continue;
118
+ }
119
+ if (st.isDirectory()) walk(abs);
120
+ else if (isMatch(rel)) out.push({
121
+ id: rel,
122
+ absolute: abs.replace(/\\/g, "/")
123
+ });
124
+ }
125
+ };
126
+ walk(opts.cwd);
127
+ out.sort((a, b) => a.id.localeCompare(b.id));
128
+ return out;
129
+ }
130
+ _writeRunnerModule(opts, testFiles) {
131
+ const cacheDir = join(opts.cwd, "node_modules", ".cache", "inflight-test");
132
+ if (!existsSync(cacheDir)) mkdirSync(cacheDir, { recursive: true });
133
+ const runnerFile = join(cacheDir, "runner.mjs");
134
+ const specs = testFiles.map((f) => {
135
+ return ` { id: ${JSON.stringify(f.id)}, load: () => import(/* webpackMode: "eager" */ ${JSON.stringify(f.absolute)}) },`;
136
+ }).join("\n");
137
+ const useGamelet = opts.bridge === "gamelet";
138
+ const gameletImportLine = useGamelet ? `import __inflightGamelet from ${JSON.stringify(opts.gameletImport)}\n` : "";
139
+ const bridgeBlock = useGamelet ? `
140
+ // Default activity bridge over gamelet-pixui-frame (host screenshot protocol etc.).
141
+ var GameletAPI = __inflightGamelet.GameletAPI
142
+ function makeActivityBridge() {
143
+ return {
144
+ callGame: function (protocol, payload) {
145
+ // gamelet-pixui-frame fills appId/appName automatically; we only send the
146
+ // type + content envelope and the call-specific payload.
147
+ GameletAPI.callGame(JSON.stringify(Object.assign({ type: protocol, content: '' }, payload)))
148
+ },
149
+ onSDKMessage: function (protocol, handler) {
150
+ var myAppId = GameletAPI.getAppID()
151
+ var listener = function (cmd) {
152
+ var msg
153
+ try { msg = JSON.parse(cmd) } catch (e) { return }
154
+ if (!msg || msg.type !== protocol) return
155
+ // Ignore messages addressed to another app: addOnGameCommandListener
156
+ // also subscribes the GLOBAL game-message channel, which isn't
157
+ // app-scoped, so a different app's callback can reach us. Compare as
158
+ // strings — the backend sends appId as a string ("7442") while
159
+ // getAppID() returns a number (7442).
160
+ if (msg.appId != null && String(msg.appId) !== String(myAppId)) return
161
+ handler(msg)
162
+ }
163
+ GameletAPI.addOnGameCommandListener(listener)
164
+ return function () { GameletAPI.removeOnGameCommandListener(listener) }
165
+ },
166
+ }
167
+ }
168
+ ` : "";
169
+ const applyBridge = useGamelet ? ` if (!o.activityBridge) o.activityBridge = makeActivityBridge()\n` : "";
170
+ writeFileSync(runnerFile, `// AUTO-GENERATED by @pixui-dev/inflight-test-webpack-plugin — do not edit.
171
+ import { start as _start } from ${JSON.stringify(opts.runtimeImport)}
172
+ ${gameletImportLine}
173
+ const specs = [
174
+ ${specs}
175
+ ]
176
+
177
+ /** Ids of the discovered test files. */
178
+ export const testFiles = specs.map(function (s) { return s.id })
179
+ ${bridgeBlock}
180
+ /**
181
+ * Run the discovered inflight tests. Writes a Vitest blob report by default
182
+ * (auto-wired from the PixUI host \`os\` / \`external.writeablePath\`); pass
183
+ * \`{ report: false }\` to skip. Call from a button / QA panel — no options
184
+ * needed in the normal case.
185
+ */
186
+ export function start(options) {
187
+ var o = Object.assign({}, options)
188
+ ${applyBridge} return _start(specs, o)
189
+ }
190
+
191
+ /** Run the discovered inflight tests without writing a report. */
192
+ export function startWithoutReport(options) {
193
+ return start(Object.assign({}, options, { report: false }))
194
+ }
195
+ `, "utf8");
196
+ return runnerFile;
197
+ }
198
+ };
199
+ //#endregion
200
+ export { InflightTestPlugin, InflightTestPlugin as default };
201
+
202
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@pixui-dev/inflight-test-webpack-plugin",
3
+ "license": "UNLICENSED",
4
+ "version": "0.0.7-inflight.1",
5
+ "description": "Webpack plugin that discovers *.test.ts cases and wires them into a PixUI activity as an opt-in inflight-test chunk",
6
+ "type": "module",
7
+ "types": "./dist/index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.mts",
12
+ "default": "./dist/index.mjs"
13
+ },
14
+ "require": {
15
+ "types": "./dist/index.d.cts",
16
+ "default": "./dist/index.cjs"
17
+ }
18
+ },
19
+ "./package.json": "./package.json"
20
+ },
21
+ "main": "./dist/index.cjs",
22
+ "module": "./dist/index.mjs",
23
+ "files": [
24
+ "dist"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsdown",
28
+ "test": "vitest run"
29
+ },
30
+ "dependencies": {
31
+ "picomatch": "^4.0.4"
32
+ },
33
+ "peerDependencies": {
34
+ "webpack": "^4.0.0 || ^5.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@types/picomatch": "^4.0.3",
38
+ "tsdown": "^0.21.10",
39
+ "webpack": "^5.0.0"
40
+ }
41
+ }