poku 1.10.1 → 1.11.0

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/README.md CHANGED
@@ -60,6 +60,7 @@ Enjoying **Poku**? Consider giving him a star ⭐️
60
60
  <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><img width="16" height="16" alt="check" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/check.svg"> No eval needed 🔐<br />
61
61
  <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><img width="16" height="16" alt="check" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/check.svg"> No global state<br />
62
62
  <img width="16" height="16" alt="check" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/check.svg"> **Parallel** and **Sequential** runs 🏃🏽🏃🏻<br />
63
+ <img width="16" height="16" alt="check" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/check.svg"> Easily handle **Background Services** and **Servers**, **Processes** and **Ports**<br />
63
64
 
64
65
  <img width="16" height="16" alt="check" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/check.svg"> **Poku** is [**100%** documented](https://poku.io/docs)<br />
65
66
  <img width="16" height="16" alt="check" src="https://raw.githubusercontent.com/wellwelwel/poku/main/.github/assets/readme/check.svg"> Designed to be human-friendly<br />
@@ -187,10 +188,15 @@ deno run npm:poku
187
188
 
188
189
  ### Essentials
189
190
 
190
- - [**poku**](https://poku.io/docs/category/poku) (_test runner_)
191
- - [**assert**](https://poku.io/docs/documentation/assert) (_test assertion_)
192
- - [**startScript**](https://poku.io/docs/documentation/startScript) (_run `package.json` scripts in a background process_)
193
- - [**startService**](https://poku.io/docs/documentation/startService) (_run files in a background process_)
191
+ - **Test**
192
+ - [**poku**](https://poku.io/docs/category/poku) (_test runner_)
193
+ - [**assert**](https://poku.io/docs/documentation/assert) (_test assertion_)
194
+ - **Background Services**
195
+ - [**startScript**](https://poku.io/docs/documentation/startScript) (_run `package.json` scripts in a background process_)
196
+ - [**startService**](https://poku.io/docs/documentation/startService) (_run files in a background process_)
197
+ - **Processes**
198
+ - [**kill**](https://poku.io/docs/documentation/processes/kill) (_terminate Ports, Port Ranges and PIDs_)
199
+ - [**getPIDs**](https://poku.io/docs/documentation/processes/get-pids) (_get all processes IDs using ports and port ranges_)
194
200
 
195
201
  ### Helpers
196
202
 
@@ -43,5 +43,5 @@ export type StartServiceOptions = {
43
43
  */
44
44
  readonly platform?: Configs['platform'];
45
45
  } & BackgroundProcessOptions;
46
- export type End = (port?: number) => Promise<void>;
46
+ export type End = (port?: number | number[]) => Promise<void>;
47
47
  export {};
package/lib/bin/index.js CHANGED
@@ -1,5 +1,14 @@
1
1
  #! /usr/bin/env node
2
2
  "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
3
12
  var _a, _b;
4
13
  Object.defineProperty(exports, "__esModule", { value: true });
5
14
  /* c8 ignore start */
@@ -14,19 +23,41 @@ const dirs = ((0, get_arg_js_1.hasArg)('include')
14
23
  const platform = (0, get_arg_js_1.getArg)('platform');
15
24
  const filter = (0, get_arg_js_1.getArg)('filter');
16
25
  const exclude = (0, get_arg_js_1.getArg)('exclude');
26
+ const killPort = (0, get_arg_js_1.getArg)('kill-port');
27
+ const killRange = (0, get_arg_js_1.getArg)('kill-range');
28
+ const killPID = (0, get_arg_js_1.getArg)('kill-pid');
17
29
  const parallel = (0, get_arg_js_1.hasArg)('parallel');
18
30
  const quiet = (0, get_arg_js_1.hasArg)('quiet');
19
31
  const debug = (0, get_arg_js_1.hasArg)('debug');
20
32
  const failFast = (0, get_arg_js_1.hasArg)('fail-fast');
21
33
  if ((0, get_arg_js_1.hasArg)('log-success'))
22
34
  console.log(`The flag ${format_js_1.format.bold('--log-success')} is deprecated. Use ${format_js_1.format.bold('--debug')} instead.`);
23
- (0, index_js_1.poku)(dirs, {
24
- platform: (0, get_runtime_js_1.platformIsValid)(platform) ? platform : undefined,
25
- filter: filter ? new RegExp((0, list_files_js_1.escapeRegExp)(filter)) : undefined,
26
- exclude: exclude ? new RegExp((0, list_files_js_1.escapeRegExp)(exclude)) : undefined,
27
- parallel,
28
- quiet,
29
- debug,
30
- failFast,
31
- });
35
+ (() => __awaiter(void 0, void 0, void 0, function* () {
36
+ if (killPort) {
37
+ const ports = killPort.split(',').map((port) => Number(port));
38
+ yield index_js_1.kill.port(ports);
39
+ }
40
+ if (killRange) {
41
+ const ranges = killRange.split(',');
42
+ for (const range of ranges) {
43
+ const ports = range.split('-').map((port) => Number(port));
44
+ const startsAt = ports[0];
45
+ const endsAt = ports[1];
46
+ yield index_js_1.kill.range(startsAt, endsAt);
47
+ }
48
+ }
49
+ if (killPID) {
50
+ const PIDs = killPID.split(',').map((port) => Number(port));
51
+ yield index_js_1.kill.pid(PIDs);
52
+ }
53
+ yield (0, index_js_1.poku)(dirs, {
54
+ platform: (0, get_runtime_js_1.platformIsValid)(platform) ? platform : undefined,
55
+ filter: filter ? new RegExp((0, list_files_js_1.escapeRegExp)(filter)) : undefined,
56
+ exclude: exclude ? new RegExp((0, list_files_js_1.escapeRegExp)(exclude)) : undefined,
57
+ parallel,
58
+ quiet,
59
+ debug,
60
+ failFast,
61
+ });
62
+ }))();
32
63
  /* c8 ignore stop */
package/lib/index.d.ts CHANGED
@@ -7,6 +7,7 @@ export { beforeEach, afterEach } from './modules/each.js';
7
7
  export { publicListFiles as listFiles } from './modules/list-files.js';
8
8
  export { test } from './modules/test.js';
9
9
  export { startService, startScript } from './modules/create-service.js';
10
+ export { getPIDs, kill } from './modules/processes.js';
10
11
  export type { Code } from './@types/code.js';
11
12
  export type { Configs } from './@types/poku.js';
12
13
  export type { Configs as ListFilesConfigs } from './@types/list-files.js';
package/lib/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.startScript = exports.startService = exports.test = exports.listFiles = exports.afterEach = exports.beforeEach = exports.assertPromise = exports.log = exports.describe = exports.assert = exports.exit = exports.poku = void 0;
3
+ exports.kill = exports.getPIDs = exports.startScript = exports.startService = exports.test = exports.listFiles = exports.afterEach = exports.beforeEach = exports.assertPromise = exports.log = exports.describe = exports.assert = exports.exit = exports.poku = void 0;
4
4
  /* c8 ignore start */
5
5
  var poku_js_1 = require("./modules/poku.js");
6
6
  Object.defineProperty(exports, "poku", { enumerable: true, get: function () { return poku_js_1.poku; } });
@@ -23,4 +23,7 @@ Object.defineProperty(exports, "test", { enumerable: true, get: function () { re
23
23
  var create_service_js_1 = require("./modules/create-service.js");
24
24
  Object.defineProperty(exports, "startService", { enumerable: true, get: function () { return create_service_js_1.startService; } });
25
25
  Object.defineProperty(exports, "startScript", { enumerable: true, get: function () { return create_service_js_1.startScript; } });
26
+ var processes_js_1 = require("./modules/processes.js");
27
+ Object.defineProperty(exports, "getPIDs", { enumerable: true, get: function () { return processes_js_1.getPIDs; } });
28
+ Object.defineProperty(exports, "kill", { enumerable: true, get: function () { return processes_js_1.kill; } });
26
29
  /* c8 ignore stop */
@@ -15,10 +15,6 @@ export declare const startService: (file: string, options?: StartServiceOptions)
15
15
  * By default, it uses **npm**, but you can costumize it using the `runner` option.
16
16
  *
17
17
  * Useful for servers, APIs, etc.
18
- *
19
- * ---
20
- *
21
- * For **Bun**, please see https://github.com/oven-sh/bun/issues/11055
22
18
  */
23
19
  export declare const startScript: (script: string, options?: StartScriptOptions) => Promise<{
24
20
  end: End;
@@ -18,7 +18,7 @@ const node_child_process_1 = require("child_process");
18
18
  const runner_js_1 = require("../helpers/runner.js");
19
19
  const node_path_1 = __importDefault(require("path"));
20
20
  const list_files_js_1 = require("./list-files.js");
21
- const pid_js_1 = require("../services/pid.js");
21
+ const processes_js_1 = require("./processes.js");
22
22
  const runningProcesses = new Map();
23
23
  /* c8 ignore start */
24
24
  node_process_1.default.once('SIGINT', () => __awaiter(void 0, void 0, void 0, function* () {
@@ -51,7 +51,7 @@ const backgroundProcess = (runtime, args, file, options) => new Promise((resolve
51
51
  try {
52
52
  runningProcesses.delete(PID);
53
53
  if (runner_js_1.isWindows) {
54
- pid_js_1.killPID.windows(PID);
54
+ processes_js_1.kill.pid(PID);
55
55
  return;
56
56
  }
57
57
  if (['bun', 'deno'].includes(runtime) ||
@@ -62,16 +62,7 @@ const backgroundProcess = (runtime, args, file, options) => new Promise((resolve
62
62
  node_process_1.default.kill(-PID, 'SIGKILL');
63
63
  if (port && ['bun', 'deno'].includes(runtime)) {
64
64
  setTimeout(() => __awaiter(void 0, void 0, void 0, function* () {
65
- const PIDs = runner_js_1.isWindows
66
- ? yield pid_js_1.findPID.windows(port)
67
- : yield pid_js_1.findPID.unix(port);
68
- for (const subPID of PIDs) {
69
- if (!subPID)
70
- continue;
71
- runner_js_1.isWindows
72
- ? yield pid_js_1.killPID.windows(subPID)
73
- : yield pid_js_1.killPID.unix(subPID);
74
- }
65
+ yield processes_js_1.kill.port(port);
75
66
  resolve(undefined);
76
67
  return;
77
68
  }));
@@ -170,10 +161,6 @@ exports.startService = startService;
170
161
  * By default, it uses **npm**, but you can costumize it using the `runner` option.
171
162
  *
172
163
  * Useful for servers, APIs, etc.
173
- *
174
- * ---
175
- *
176
- * For **Bun**, please see https://github.com/oven-sh/bun/issues/11055
177
164
  */
178
165
  const startScript = (script, options) => __awaiter(void 0, void 0, void 0, function* () {
179
166
  const runner = (options === null || options === void 0 ? void 0 : options.runner) || 'npm';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Returns an array containing the ID of all processes listening to the specified port
3
+ */
4
+ export declare const getPIDs: ((port: number | number[]) => Promise<number[]>) & {
5
+ /**
6
+ * Returns an array containing the ID of all processes listening to the specified range port
7
+ */
8
+ range: (startsAt: number, endsAt: number) => Promise<number[]>;
9
+ };
10
+ export declare const kill: {
11
+ /**
12
+ * Terminates the specified process ID
13
+ */
14
+ pid: (PID: number | number[]) => Promise<void>;
15
+ /**
16
+ * Terminates all processes listening on the specified port
17
+ */
18
+ port: (port: number | number[]) => Promise<void>;
19
+ /**
20
+ * Terminates all processes listening on the specified range ports
21
+ */
22
+ range: (startsAt: number, endsAt: number) => Promise<void>;
23
+ };
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /* c8 ignore start */
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ exports.kill = exports.getPIDs = void 0;
14
+ const runner_js_1 = require("../helpers/runner.js");
15
+ const pid_js_1 = require("../services/pid.js");
16
+ const getPIDsByPorts = (port) => __awaiter(void 0, void 0, void 0, function* () {
17
+ const ports = (0, pid_js_1.setPortsAndPIDs)(port);
18
+ const PIDs = [];
19
+ yield Promise.all(ports.map((p) => __awaiter(void 0, void 0, void 0, function* () {
20
+ PIDs.push(...(yield (runner_js_1.isWindows
21
+ ? pid_js_1.getPIDs.windows(p)
22
+ : pid_js_1.getPIDs.unix(p))));
23
+ })));
24
+ return PIDs;
25
+ });
26
+ const getPIDsByRange = (startsAt, endsAt) => __awaiter(void 0, void 0, void 0, function* () {
27
+ const ports = (0, pid_js_1.populateRange)(startsAt, endsAt);
28
+ return yield (0, exports.getPIDs)(ports);
29
+ });
30
+ /**
31
+ * Returns an array containing the ID of all processes listening to the specified port
32
+ */
33
+ exports.getPIDs = Object.assign(getPIDsByPorts, {
34
+ /**
35
+ * Returns an array containing the ID of all processes listening to the specified range port
36
+ */
37
+ range: getPIDsByRange,
38
+ });
39
+ const killPID = (PID) => __awaiter(void 0, void 0, void 0, function* () {
40
+ const PIDs = (0, pid_js_1.setPortsAndPIDs)(PID);
41
+ yield Promise.all(PIDs.map((p) => __awaiter(void 0, void 0, void 0, function* () {
42
+ runner_js_1.isWindows
43
+ ? yield pid_js_1.killPID.windows(p)
44
+ : yield pid_js_1.killPID.unix(p);
45
+ })));
46
+ });
47
+ const killPort = (port) => __awaiter(void 0, void 0, void 0, function* () {
48
+ const PIDs = yield (0, exports.getPIDs)(port);
49
+ for (const PID of PIDs) {
50
+ if (!PID)
51
+ continue;
52
+ yield killPID(PID);
53
+ }
54
+ });
55
+ const killRange = (startsAt, endsAt) => __awaiter(void 0, void 0, void 0, function* () {
56
+ const PIDs = yield exports.getPIDs.range(startsAt, endsAt);
57
+ for (const PID of PIDs) {
58
+ if (!PID)
59
+ continue;
60
+ yield killPID(PID);
61
+ }
62
+ });
63
+ exports.kill = {
64
+ /**
65
+ * Terminates the specified process ID
66
+ */
67
+ pid: killPID,
68
+ /**
69
+ * Terminates all processes listening on the specified port
70
+ */
71
+ port: killPort,
72
+ /**
73
+ * Terminates all processes listening on the specified range ports
74
+ */
75
+ range: killRange,
76
+ };
77
+ /* c8 ignore stop */
@@ -1,8 +1,10 @@
1
+ export declare const setPortsAndPIDs: (portOrPID: number | number[]) => number[];
2
+ export declare const populateRange: (startsAt: number, endsAt: number) => number[];
1
3
  export declare const killPID: {
2
4
  unix: (PID: number) => Promise<void>;
3
5
  windows: (PID: number) => Promise<void>;
4
6
  };
5
- export declare const findPID: {
7
+ export declare const getPIDs: {
6
8
  unix: (port: number) => Promise<number[]>;
7
9
  windows: (port: number) => Promise<number[]>;
8
10
  };
@@ -1,74 +1,86 @@
1
1
  "use strict";
2
2
  /* c8 ignore start */
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.findPID = exports.killPID = void 0;
4
+ exports.getPIDs = exports.killPID = exports.populateRange = exports.setPortsAndPIDs = void 0;
5
5
  const node_child_process_1 = require("child_process");
6
6
  const node_os_1 = require("os");
7
+ const force_array_js_1 = require("../helpers/force-array.js");
8
+ const setPortsAndPIDs = (portOrPID) => (0, force_array_js_1.forceArray)(portOrPID)
9
+ .map((p) => Number(p))
10
+ .filter((p) => !isNaN(p));
11
+ exports.setPortsAndPIDs = setPortsAndPIDs;
12
+ const populateRange = (startsAt, endsAt) => {
13
+ const first = Number(startsAt);
14
+ const last = Number(endsAt);
15
+ return Array.from({ length: last - first + 1 }, (_, i) => first + i);
16
+ };
17
+ exports.populateRange = populateRange;
7
18
  exports.killPID = {
8
19
  unix: (PID) => new Promise((resolve) => {
9
- try {
10
- const service = (0, node_child_process_1.spawn)('kill', ['-9', String(PID)]);
11
- service.on('close', () => {
12
- resolve(undefined);
13
- });
14
- }
15
- catch (_a) {
20
+ const service = (0, node_child_process_1.spawn)('kill', ['-9', String(Number(PID))]);
21
+ service.on('close', () => {
16
22
  resolve(undefined);
17
- }
23
+ });
18
24
  }),
19
25
  windows: (PID) => new Promise((resolve) => {
20
- try {
21
- const service = (0, node_child_process_1.spawn)('taskkill', ['/F', '/T', '/PID', String(PID)]);
22
- service.on('close', () => {
23
- resolve(undefined);
24
- });
25
- }
26
- catch (_a) {
26
+ const service = (0, node_child_process_1.spawn)('taskkill', [
27
+ '/F',
28
+ '/T',
29
+ '/PID',
30
+ String(Number(PID)),
31
+ ]);
32
+ service.on('close', () => {
27
33
  resolve(undefined);
28
- }
34
+ });
29
35
  }),
30
36
  };
31
- exports.findPID = {
37
+ exports.getPIDs = {
32
38
  unix: (port) => new Promise((resolve) => {
33
- try {
34
- const PIDs = new Set();
35
- const service = (0, node_child_process_1.spawn)('lsof', ['-t', '-i', `:${Number(port)}`]);
36
- service.stdout.on('data', (data) => {
37
- const output = data.toString().trim().split(node_os_1.EOL);
38
- output.forEach((pid) => {
39
- if (pid)
40
- PIDs.add(Number(pid));
41
- });
42
- service.on('close', () => {
43
- resolve(Array.from(PIDs));
44
- });
39
+ const PIDs = new Set();
40
+ const service = (0, node_child_process_1.spawn)('lsof', [
41
+ '-t',
42
+ '-i',
43
+ `:${Number(port)}`,
44
+ '-s',
45
+ 'TCP:LISTEN',
46
+ ]);
47
+ service.stdout.on('data', (data) => {
48
+ const output = data.toString().trim().split(node_os_1.EOL);
49
+ output.forEach((pid) => {
50
+ if (pid)
51
+ PIDs.add(Number(pid));
45
52
  });
46
- }
47
- catch (_a) { }
53
+ });
54
+ service.on('close', () => {
55
+ resolve(Array.from(PIDs));
56
+ });
48
57
  }),
49
58
  windows: (port) => new Promise((resolve) => {
50
- try {
51
- const PIDs = new Set();
52
- const service = (0, node_child_process_1.spawn)('cmd.exe', [
53
- '/c',
54
- `netstat -aon | findstr :${Number(port)}`,
55
- ]);
56
- service.stdout.on('data', (data) => {
57
- const output = data.toString().trim();
58
- const lines = output.trim().split(node_os_1.EOL);
59
- lines.map((line) => {
60
- const tokens = line.trim().split(/\s+/);
61
- PIDs.add(Number(tokens[4]));
62
- });
63
- });
64
- service.on('close', () => {
65
- resolve(Array.from(PIDs));
66
- });
67
- service.stderr.on('data', (data) => {
68
- console.error(`Erro: ${data}`);
59
+ const PIDs = new Set();
60
+ const service = (0, node_child_process_1.spawn)('cmd.exe', [
61
+ '/c',
62
+ `netstat -aon | findstr :${Number(port)}`,
63
+ ]);
64
+ service.stdout.on('data', (data) => {
65
+ const output = data.toString().trim();
66
+ const lines = output.trim().split(node_os_1.EOL);
67
+ /**
68
+ * TODO: Chack line for "/:\d+\s+\w+\s+\d+\s+(\d+)/" regex match to safe support multiple Windows versions
69
+ * (Tested against ReDos Checker)
70
+ */
71
+ lines.map((line) => {
72
+ const tokens = line.trim().split(/\s+/);
73
+ const stateIndex = tokens.indexOf('LISTENING');
74
+ if (stateIndex !== -1 && tokens[stateIndex + 1]) {
75
+ const pid = Number(tokens[stateIndex + 1]);
76
+ if (!isNaN(pid))
77
+ PIDs.add(pid);
78
+ }
69
79
  });
70
- }
71
- catch (_a) { }
80
+ });
81
+ service.on('close', () => {
82
+ resolve(Array.from(PIDs));
83
+ });
72
84
  }),
73
85
  };
74
86
  /* c8 ignore stop */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poku",
3
- "version": "1.10.1",
3
+ "version": "1.11.0",
4
4
  "description": "🐷 Poku makes testing easy for Node.js, Bun & Deno at the same time.",
5
5
  "main": "./lib/index.js",
6
6
  "scripts": {
@@ -83,8 +83,10 @@
83
83
  "files",
84
84
  "list-files",
85
85
  "tsx",
86
- "fast",
87
- "easy",
86
+ "kill",
87
+ "process",
88
+ "port",
89
+ "cross-platform",
88
90
  "poku",
89
91
  "pokujs"
90
92
  ],