@fedify/init 2.5.0-dev.2516 → 2.5.0-dev.2541

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.
Files changed (40) hide show
  1. package/README.md +17 -7
  2. package/dist/_virtual/_rolldown/runtime.js +26 -0
  3. package/dist/action/configs.js +23 -11
  4. package/dist/ask/kv.js +10 -10
  5. package/dist/ask/mq.js +10 -10
  6. package/dist/ask/pm.js +8 -5
  7. package/dist/command.d.ts +21 -1
  8. package/dist/json/kv.js +1 -0
  9. package/dist/json/kv.json +1 -0
  10. package/dist/json/mq.js +1 -0
  11. package/dist/json/mq.json +1 -0
  12. package/dist/lib.js +2 -2
  13. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.js +29 -0
  14. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js +42 -0
  15. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js +67 -0
  16. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js +23 -0
  17. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js +22 -0
  18. package/dist/node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js +36 -0
  19. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js +47 -0
  20. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js +33 -0
  21. package/dist/node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js +33 -0
  22. package/dist/node_modules/.pnpm/path-key@3.1.1/node_modules/path-key/index.js +14 -0
  23. package/dist/node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.js +17 -0
  24. package/dist/node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.js +8 -0
  25. package/dist/node_modules/.pnpm/which@2.0.2/node_modules/which/which.js +77 -0
  26. package/dist/{deno.js → packages/init/deno.js} +1 -1
  27. package/dist/scripts/tooling_main.js +17 -0
  28. package/dist/test/action.d.ts +6 -0
  29. package/dist/test/action.js +15 -5
  30. package/dist/test/cancel.js +14 -0
  31. package/dist/test/create.js +10 -5
  32. package/dist/test/lookup.js +17 -7
  33. package/dist/test/mod.d.ts +6 -1
  34. package/dist/test/mod.js +13 -6
  35. package/dist/test/node.js +6 -0
  36. package/dist/test/port.js +34 -13
  37. package/dist/test/run.js +15 -9
  38. package/dist/test/server.js +136 -108
  39. package/dist/types.d.ts +4 -0
  40. package/package.json +4 -3
@@ -0,0 +1,17 @@
1
+ import { __commonJSMin } from "../../../../../_virtual/_rolldown/runtime.js";
2
+ import { require_shebang_regex } from "../../../shebang-regex@3.0.0/node_modules/shebang-regex/index.js";
3
+ //#region ../../node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.js
4
+ var require_shebang_command = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5
+ const shebangRegex = require_shebang_regex();
6
+ module.exports = (string = "") => {
7
+ const match = string.match(shebangRegex);
8
+ if (!match) return null;
9
+ const [path, argument] = match[0].replace(/#! ?/, "").split(" ");
10
+ const binary = path.split("/").pop();
11
+ if (binary === "env") return argument;
12
+ return argument ? `${binary} ${argument}` : binary;
13
+ };
14
+ }));
15
+ //#endregion
16
+ export default require_shebang_command();
17
+ export { require_shebang_command };
@@ -0,0 +1,8 @@
1
+ import { __commonJSMin } from "../../../../../_virtual/_rolldown/runtime.js";
2
+ //#region ../../node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.js
3
+ var require_shebang_regex = /* @__PURE__ */ __commonJSMin(((exports, module) => {
4
+ module.exports = /^#!(.*)/;
5
+ }));
6
+ //#endregion
7
+ export default require_shebang_regex();
8
+ export { require_shebang_regex };
@@ -0,0 +1,77 @@
1
+ import { __commonJSMin, __require } from "../../../../../_virtual/_rolldown/runtime.js";
2
+ import { require_isexe } from "../../../isexe@2.0.0/node_modules/isexe/index.js";
3
+ //#region ../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js
4
+ var require_which = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5
+ const isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
6
+ const path = __require("path");
7
+ const COLON = isWindows ? ";" : ":";
8
+ const isexe = require_isexe();
9
+ const getNotFoundError = (cmd) => Object.assign(/* @__PURE__ */ new Error(`not found: ${cmd}`), { code: "ENOENT" });
10
+ const getPathInfo = (cmd, opt) => {
11
+ const colon = opt.colon || COLON;
12
+ const pathEnv = cmd.match(/\//) || isWindows && cmd.match(/\\/) ? [""] : [...isWindows ? [process.cwd()] : [], ...(opt.path || process.env.PATH || "").split(colon)];
13
+ const pathExtExe = isWindows ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
14
+ const pathExt = isWindows ? pathExtExe.split(colon) : [""];
15
+ if (isWindows) {
16
+ if (cmd.indexOf(".") !== -1 && pathExt[0] !== "") pathExt.unshift("");
17
+ }
18
+ return {
19
+ pathEnv,
20
+ pathExt,
21
+ pathExtExe
22
+ };
23
+ };
24
+ const which = (cmd, opt, cb) => {
25
+ if (typeof opt === "function") {
26
+ cb = opt;
27
+ opt = {};
28
+ }
29
+ if (!opt) opt = {};
30
+ const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
31
+ const found = [];
32
+ const step = (i) => new Promise((resolve, reject) => {
33
+ if (i === pathEnv.length) return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
34
+ const ppRaw = pathEnv[i];
35
+ const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
36
+ const pCmd = path.join(pathPart, cmd);
37
+ const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
38
+ resolve(subStep(p, i, 0));
39
+ });
40
+ const subStep = (p, i, ii) => new Promise((resolve, reject) => {
41
+ if (ii === pathExt.length) return resolve(step(i + 1));
42
+ const ext = pathExt[ii];
43
+ isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
44
+ if (!er && is) if (opt.all) found.push(p + ext);
45
+ else return resolve(p + ext);
46
+ return resolve(subStep(p, i, ii + 1));
47
+ });
48
+ });
49
+ return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
50
+ };
51
+ const whichSync = (cmd, opt) => {
52
+ opt = opt || {};
53
+ const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
54
+ const found = [];
55
+ for (let i = 0; i < pathEnv.length; i++) {
56
+ const ppRaw = pathEnv[i];
57
+ const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
58
+ const pCmd = path.join(pathPart, cmd);
59
+ const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
60
+ for (let j = 0; j < pathExt.length; j++) {
61
+ const cur = p + pathExt[j];
62
+ try {
63
+ if (isexe.sync(cur, { pathExt: pathExtExe })) if (opt.all) found.push(cur);
64
+ else return cur;
65
+ } catch (ex) {}
66
+ }
67
+ }
68
+ if (opt.all && found.length) return found;
69
+ if (opt.nothrow) return null;
70
+ throw getNotFoundError(cmd);
71
+ };
72
+ module.exports = which;
73
+ which.sync = whichSync;
74
+ }));
75
+ //#endregion
76
+ export default require_which();
77
+ export { require_which };
@@ -1,4 +1,4 @@
1
1
  //#region deno.json
2
- var version = "2.5.0-dev.2516+42d3ed0b";
2
+ var version = "2.5.0-dev.2541+d39a2437";
3
3
  //#endregion
4
4
  export { version };
@@ -0,0 +1,17 @@
1
+ import process from "node:process";
2
+ import { realpathSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
+ //#region ../../scripts/tooling_main.ts
6
+ /** Whether Node.js launched this module as its entry point. */
7
+ function isMain(url) {
8
+ const entry = process.argv[1];
9
+ if (entry == null) return false;
10
+ try {
11
+ return realpathSync(resolve(entry)) === realpathSync(fileURLToPath(url));
12
+ } catch {
13
+ return pathToFileURL(resolve(entry)).href === url;
14
+ }
15
+ }
16
+ //#endregion
17
+ export { isMain };
@@ -0,0 +1,6 @@
1
+ import { TestInitCommand } from "../command.js";
2
+
3
+ //#region src/test/action.d.ts
4
+ declare function runTestInit(options: TestInitCommand): Promise<boolean>;
5
+ //#endregion
6
+ export { runTestInit as default };
@@ -1,12 +1,22 @@
1
- import { set } from "../utils.js";
2
1
  import { checkRequiredDbs } from "./db.js";
3
2
  import { fillEmptyOptions } from "./fill.js";
4
3
  import runTests from "./run.js";
5
4
  import { emptyTestDir, genRunId, genTestDirPrefix, logTestDir } from "./utils.js";
6
- import { pipe, tap, when } from "@fxts/core";
7
5
  //#region src/test/action.ts
8
- const runTestInit = (options) => pipe(options, set("runId", genRunId), set("testDirPrefix", genTestDirPrefix), tap(emptyTestDir), fillEmptyOptions, tap(checkRequiredDbs), tap(logTestDir), tap(when(isDryRun, runTests(true))), tap(when(isHydRun, runTests(false))));
9
- const isDryRun = ({ dryRun }) => dryRun;
10
- const isHydRun = ({ hydRun }) => hydRun;
6
+ async function runTestInit(options) {
7
+ const runId = genRunId();
8
+ const data = fillEmptyOptions({
9
+ ...options,
10
+ runId,
11
+ testDirPrefix: genTestDirPrefix({ runId })
12
+ });
13
+ await emptyTestDir(data);
14
+ await checkRequiredDbs(data);
15
+ logTestDir(data);
16
+ let success = true;
17
+ if (data.dryRun) success = await runTests(true)(data) && success;
18
+ if (data.hydRun) success = await runTests(false)(data) && success;
19
+ return success;
20
+ }
11
21
  //#endregion
12
22
  export { runTestInit as default };
@@ -0,0 +1,14 @@
1
+ //#region src/test/cancel.ts
2
+ /** An OS request to stop the initializer matrix after cleaning up its server. */
3
+ var TestInterruptedError = class extends Error {
4
+ signal;
5
+ exitCode;
6
+ constructor(signal) {
7
+ super(`Initializer tests interrupted by ${signal}`);
8
+ this.signal = signal;
9
+ this.name = "TestInterruptedError";
10
+ this.exitCode = signal === "SIGINT" ? 130 : 143;
11
+ }
12
+ };
13
+ //#endregion
14
+ export { TestInterruptedError };
@@ -2,6 +2,7 @@ import pm_default from "../json/pm.js";
2
2
  import { printErrorMessage, printMessage, product } from "../utils.js";
3
3
  import { getBuildCommand, kvStores, messageQueues } from "../lib.js";
4
4
  import webFrameworks from "../webframeworks/mod.js";
5
+ import { nodeExecutable } from "./node.js";
5
6
  import { filter, isEmpty, pipe, toArray } from "@fxts/core";
6
7
  import process from "node:process";
7
8
  import $ from "@david/dax";
@@ -11,9 +12,10 @@ import { values } from "@optique/core";
11
12
  //#region src/test/create.ts
12
13
  const BANNED_PMS = ["bun", "yarn"];
13
14
  const createTestApp = (testDirPrefix, dry) => async (options) => {
15
+ if (!dry && options[1] === "deno") await ensureDenoWorkspaceCache();
14
16
  const testDir = join$1(testDirPrefix, ...options);
15
17
  const vals = values(testDir.split(sep).slice(-4));
16
- const result = await $`${toArray(genInitCommand(testDir, dry, options))}`.cwd(join$1(import.meta.dirname, "..", "..")).stdin("null").stdout("piped").stderr("piped").noThrow().spawn();
18
+ const result = await $`${toArray(genInitCommand(testDir, dry, options))}`.cwd(join$1(import.meta.dirname, "..", "..")).env("FEDIFY_TEST_MODE", "true").stdin("null").stdout("piped").stderr("piped").noThrow().spawn();
17
19
  await saveOutputs(testDir, result);
18
20
  if (result.code === 0) {
19
21
  if (!dry && (!await validateDevToolScripts(testDir, options) || !await validateFrameworkBuild(testDir, options))) {
@@ -33,9 +35,8 @@ ${join$1(testDir, "err.txt")}\n`;
33
35
  return "";
34
36
  };
35
37
  function* genInitCommand(testDir, dry, [webFramework, packageManager, kvStore, messageQueue]) {
36
- yield "deno";
37
- yield "run";
38
- yield "-A";
38
+ yield nodeExecutable;
39
+ yield "--experimental-transform-types";
39
40
  yield "src/test/execute.ts";
40
41
  yield "init";
41
42
  yield testDir;
@@ -128,5 +129,9 @@ function filterOptions(options) {
128
129
  messageQueues[mq].packageManagers
129
130
  ].every((pms) => pms.includes(pm));
130
131
  }
132
+ let denoWorkspaceCache;
133
+ function ensureDenoWorkspaceCache() {
134
+ return denoWorkspaceCache ??= $`mise run deno:cache`.cwd(join$1(import.meta.dirname, "..", "..", "..", "..")).stdin("null").spawn();
135
+ }
131
136
  //#endregion
132
- export { createTestApp as default, filterOptions, generateTestCases };
137
+ export { createTestApp as default, filterOptions, genInitCommand, generateTestCases };
@@ -1,12 +1,15 @@
1
1
  import { printErrorMessage, printMessage } from "../utils.js";
2
2
  import { getDevCommand, kvStores, messageQueues, packageManagers } from "../lib.js";
3
3
  import webFrameworks from "../webframeworks/mod.js";
4
+ import { nodeExecutable } from "./node.js";
5
+ import { TestInterruptedError } from "./cancel.js";
4
6
  import { replacePortInApp, reservePort } from "./port.js";
5
7
  import { STARTUP_TIMEOUT, serverClosure, waitForServer } from "./server.js";
6
8
  import { join } from "@fxts/core";
7
9
  import $ from "@david/dax";
8
10
  import { join as join$1, sep } from "node:path";
9
11
  import { values } from "@optique/core";
12
+ import { fileURLToPath } from "node:url";
10
13
  //#region src/test/lookup.ts
11
14
  const HANDLE = "john";
12
15
  const BANNED_LOOKUP_REASONS = {
@@ -22,13 +25,13 @@ const BANNED_LOOKUP_CASES = Object.keys(BANNED_LOOKUP_REASONS).map((key) => key.
22
25
  *
23
26
  * @param dirs - Array of paths to generated app directories
24
27
  */
25
- async function runServerAndLookupUser(dirs) {
28
+ async function runServerAndLookupUser(dirs, test = testApp) {
26
29
  const valid = dirs.filter(Boolean).filter(isTestable);
27
30
  printSkippedCases(dirs);
28
31
  if (valid.length === 0) printErrorMessage`\nNo directories to lookup test.`;
29
32
  printMessage``;
30
33
  printMessage`Lookup Test start for ${String(valid.length)} app(s)!`;
31
- const results = await Array.fromAsync(valid, testApp);
34
+ const results = await Array.fromAsync(valid, test);
32
35
  const successCount = results.filter(Boolean).length;
33
36
  const failCount = results.length - successCount;
34
37
  printMessage`Lookup Test Results:
@@ -36,6 +39,7 @@ async function runServerAndLookupUser(dirs) {
36
39
  Passed: ${String(successCount)}
37
40
  Failed: ${String(failCount)}\n\n`;
38
41
  printFailedCases(valid, results);
42
+ return valid.length > 0 && results.every(Boolean);
39
43
  }
40
44
  const parseLookupCase = (dir) => dir.split(sep).slice(-4);
41
45
  const matchesLookupCasePattern = (target) => (pattern) => pattern.every((value, index) => value === "*" || value === target[index]);
@@ -80,7 +84,10 @@ async function testApp(dir) {
80
84
  const { port, release } = await reservePort();
81
85
  await replacePortInApp(dir, wf, defaultPort, port);
82
86
  printMessage` Using port ${String(port)}`;
83
- const result = await serverClosure(dir, getDevCommand(pm), port, sendLookup, release).catch(() => false);
87
+ const result = await serverClosure(dir, getDevCommand(pm), port, (port, signal) => sendLookup(port, void 0, signal), release).catch((error) => {
88
+ if (error instanceof TestInterruptedError) throw error;
89
+ return false;
90
+ });
84
91
  printMessage` Lookup ${result ? "successful" : "failed"} for ${values([
85
92
  wf,
86
93
  pm,
@@ -93,21 +100,24 @@ ${join$1(dir, "err.txt")}\n`;
93
100
  printMessage`\n`;
94
101
  return result;
95
102
  }
96
- async function sendLookup(port) {
103
+ async function sendLookup(port, cliEntry = fileURLToPath(new URL("../../../cli/dist/mod.js", import.meta.url)), signal) {
97
104
  const serverUrl = `http://localhost:${port}`;
98
105
  const lookupTarget = `${serverUrl}/users/${HANDLE}`;
99
106
  printMessage` Waiting for server to start at ${serverUrl}...`;
100
- if (!await waitForServer(serverUrl)) {
107
+ if (!await waitForServer(serverUrl, 1e4, signal)) {
101
108
  printErrorMessage`Server did not start within ${String(STARTUP_TIMEOUT)}ms`;
102
109
  return false;
103
110
  }
104
111
  printMessage` Server is ready. Running lookup command...`;
105
112
  try {
106
- return (await $`deno task cli lookup ${lookupTarget} -p`.stdin("null").stdout("piped").stderr("piped").noThrow().spawn()).stdout.includes(`id: URL '${lookupTarget}',`);
113
+ let command = $`${nodeExecutable} ${cliEntry} lookup ${lookupTarget} -p`.stdin("null").stdout("piped").stderr("piped").noThrow();
114
+ if (signal != null) command = command.signal(signal);
115
+ const res = await command.spawn();
116
+ return res.code === 0 && res.stdout.includes(`id: URL '${lookupTarget}',`);
107
117
  } catch (error) {
108
118
  if (error instanceof Error) printErrorMessage`${error.message}`;
109
119
  }
110
120
  return false;
111
121
  }
112
122
  //#endregion
113
- export { runServerAndLookupUser as default, isTestable, matchesLookupCasePattern, parseLookupCase };
123
+ export { runServerAndLookupUser as default, isTestable, matchesLookupCasePattern, parseLookupCase, sendLookup };
@@ -1 +1,6 @@
1
- export { };
1
+ import runTestInit from "./action.js";
2
+
3
+ //#region src/test/mod.d.ts
4
+ declare function main(action?: typeof runTestInit): Promise<void>;
5
+ //#endregion
6
+ export { main };
package/dist/test/mod.js CHANGED
@@ -1,15 +1,22 @@
1
1
  import { testInitCommand } from "../command.js";
2
+ import { isMain } from "../scripts/tooling_main.js";
3
+ import { TestInterruptedError } from "./cancel.js";
2
4
  import runTestInit from "./action.js";
3
5
  import process from "node:process";
4
6
  import { run } from "@optique/run";
5
7
  //#region src/test/mod.ts
6
- async function main() {
7
- await runTestInit(run(testInitCommand, {
8
+ async function main(action = runTestInit) {
9
+ const result = run(testInitCommand, {
8
10
  programName: "fedify-test-init",
9
11
  help: "both"
10
- }));
11
- process.exit(0);
12
+ });
13
+ try {
14
+ process.exitCode = await action(result) ? 0 : 1;
15
+ } catch (error) {
16
+ if (!(error instanceof TestInterruptedError)) throw error;
17
+ process.exitCode = error.exitCode;
18
+ }
12
19
  }
13
- await main();
20
+ if (isMain(import.meta.url)) await main();
14
21
  //#endregion
15
- export {};
22
+ export { main };
@@ -0,0 +1,6 @@
1
+ import process from "node:process";
2
+ //#region src/test/node.ts
3
+ /** Select Node.js even when a compatibility test imports the harness in Deno. */
4
+ const nodeExecutable = process.versions.deno != null || process.versions.bun != null ? "node" : process.execPath;
5
+ //#endregion
6
+ export { nodeExecutable };
package/dist/test/port.js CHANGED
@@ -41,26 +41,47 @@ async function waitForPortRelease(port, timeout = 5e3) {
41
41
  }
42
42
  return false;
43
43
  }
44
- /**
45
- * Attempt to kill any process listening on the given port using lsof.
46
- */
44
+ /** Attempt to stop remaining listeners using the platform's process tools. */
47
45
  async function killProcessOnPort(port) {
46
+ const windows = process.platform === "win32";
48
47
  try {
49
- const pids = await new Promise((resolve, reject) => {
50
- execFile("lsof", [
48
+ const output = await new Promise((resolve, reject) => {
49
+ execFile(windows ? "netstat" : "lsof", windows ? [
50
+ "-ano",
51
+ "-p",
52
+ "tcp"
53
+ ] : [
51
54
  "-t",
52
55
  `-i:${port}`,
53
56
  "-sTCP:LISTEN"
54
- ], (err, stdout) => {
55
- if (err) reject(err);
56
- else resolve(stdout);
57
- });
57
+ ], {
58
+ timeout: 1e3,
59
+ windowsHide: true
60
+ }, (error, stdout) => error ? reject(error) : resolve(stdout));
58
61
  });
59
- for (const pid of pids.trim().split("\n").filter(Boolean)) try {
60
- process.kill(parseInt(pid, 10), "SIGKILL");
62
+ const pids = windows ? parseWindowsListeners(output, port) : output.trim().split(/\s+/).filter((pid) => /^\d+$/.test(pid));
63
+ for (const pid of new Set(pids)) if (windows) await new Promise((resolve) => {
64
+ execFile("taskkill", [
65
+ "/pid",
66
+ pid,
67
+ "/t",
68
+ "/f"
69
+ ], {
70
+ timeout: 1e3,
71
+ windowsHide: true
72
+ }, () => resolve());
73
+ });
74
+ else try {
75
+ process.kill(Number(pid), "SIGKILL");
61
76
  } catch {}
62
77
  } catch {}
63
78
  }
79
+ function parseWindowsListeners(output, port) {
80
+ return output.split(/\r?\n/).flatMap((line) => {
81
+ const [protocol, localAddress, , state, pid] = line.trim().split(/\s+/);
82
+ return protocol === "TCP" && localAddress?.endsWith(`:${port}`) && state === "LISTENING" && /^\d+$/.test(pid) ? [pid] : [];
83
+ });
84
+ }
64
85
  /**
65
86
  * Reserve a free port by binding to port 0 and letting the OS assign one.
66
87
  * The socket is held until the returned `release` function is called,
@@ -123,8 +144,8 @@ async function ensurePortReleased(port) {
123
144
  if (!await waitForPortRelease(port, 5e3)) {
124
145
  printMessage` Port ${String(port)} still in use—force-killing...`;
125
146
  await killProcessOnPort(port);
126
- await waitForPortRelease(port, 3e3);
147
+ if (!await waitForPortRelease(port, 3e3)) throw new Error(`Port ${port} is still in use after server cleanup`);
127
148
  }
128
149
  }
129
150
  //#endregion
130
- export { ensurePortReleased, isPortInUse, killProcessOnPort, replacePortInApp, reservePort, waitForPortRelease };
151
+ export { ensurePortReleased, isPortInUse, killProcessOnPort, parseWindowsListeners, replacePortInApp, reservePort, waitForPortRelease };
package/dist/test/run.js CHANGED
@@ -1,19 +1,25 @@
1
1
  import { printMessage } from "../utils.js";
2
2
  import createTestApp, { filterOptions, generateTestCases } from "./create.js";
3
3
  import runServerAndLookupUser from "./lookup.js";
4
- import { always, filter, map, pipe, tap, unless } from "@fxts/core";
5
- import { join as join$1 } from "node:path";
4
+ import { join } from "node:path";
6
5
  import { optionNames } from "@optique/core";
7
6
  //#region src/test/run.ts
8
- const runTests = (dry) => ({ testDirPrefix, dryRun, hydRun, ...options }) => pipe(options, printStartMessage(dry), generateTestCases, filter(filterOptions), map(createTestApp(join$1(testDirPrefix, getMid(dryRun, hydRun, dry)), dry)), Array.fromAsync, unless(always(dry), runServerAndLookupUser));
9
- const printStartMessage = (dry) => tap(() => printMessage`\n
7
+ const runTests = (dry, runners) => async ({ testDirPrefix, dryRun, hydRun, ...options }) => {
8
+ printMessage`\n
10
9
  Init ${dry ? "Dry" : "Hyd"} Test start!
11
10
  Options: ${optionNames([
12
- "Web Framework",
13
- "Package Manager",
14
- "KV Store",
15
- "Message Queue"
16
- ])}`);
11
+ "Web Framework",
12
+ "Package Manager",
13
+ "KV Store",
14
+ "Message Queue"
15
+ ])}`;
16
+ const create = runners?.create ?? createTestApp(join(testDirPrefix, getMid(dryRun, hydRun, dry)), dry);
17
+ const dirs = [];
18
+ for (const testCase of generateTestCases(options)) if (filterOptions(testCase)) dirs.push(await create(testCase));
19
+ const generated = dirs.length > 0 && dirs.every(Boolean);
20
+ const lookup = dry ? true : await (runners?.lookup ?? runServerAndLookupUser)(dirs);
21
+ return generated && lookup;
22
+ };
17
23
  const getMid = (dryRun, hydRun, dry) => dryRun === hydRun ? dry ? "dry" : "hyd" : "";
18
24
  //#endregion
19
25
  export { runTests as default };