poku 1.4.0 → 1.5.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
@@ -4,15 +4,12 @@
4
4
  [bun-version-image]: https://img.shields.io/badge/Bun->=0.5.3-f471b5
5
5
  [deno-version-url]: https://github.com/denoland/deno
6
6
  [deno-version-image]: https://img.shields.io/badge/Deno->=1.30.0-70ffaf
7
- [npm-image]: https://img.shields.io/npm/v/poku.svg?color=3dc1d3
8
- [npm-url]: https://npmjs.org/package/poku
9
7
  [typescript-url]: https://github.com/microsoft/TypeScript
8
+ [typescript-version-image]: https://img.shields.io/badge/TypeScript->=5.0.2-3077c6
10
9
  [ci-url]: https://github.com/wellwelwel/poku/actions/workflows/ci.yml?query=branch%3Amain
11
10
  [ci-image]: https://img.shields.io/github/actions/workflow/status/wellwelwel/poku/ci.yml?event=push&style=flat&label=CI&branch=main
12
11
  [ql-url]: https://github.com/wellwelwel/poku/actions/workflows/codeql.yml?query=branch%3Amain
13
12
  [ql-image]: https://img.shields.io/github/actions/workflow/status/wellwelwel/poku/codeql.yml?event=push&style=flat&label=Code%20QL&branch=main
14
- [license-url]: https://github.com/wellwelwel/poku/blob/main/LICENSE
15
- [license-image]: https://img.shields.io/npm/l/poku.svg?maxAge=2592000&color=9c88ff
16
13
 
17
14
  # Poku
18
15
 
@@ -23,22 +20,23 @@
23
20
  [![Node.js Version][node-version-image]][node-version-url]
24
21
  [![Bun Version][bun-version-image]][bun-version-url]
25
22
  [![Deno Version][deno-version-image]][deno-version-url]
26
- [![NPM Version][npm-image]][npm-url]
27
- [![License][license-image]][license-url]
23
+ [![TypeScript Version][typescript-version-image]][typescript-url]
28
24
  [![GitHub Workflow Status (with event)][ci-image]][ci-url]
29
25
  [![GitHub Workflow Status (with event)][ql-image]][ql-url]
30
26
 
31
- Enjoying Poku? Consider giving him a star ⭐️
27
+ Enjoying **Poku**? Consider giving him a star ⭐️
32
28
 
33
29
  ---
34
30
 
35
- 🐷 [**Documentation Website**](https://poku.dev)
31
+ 🐷 [**Documentation Website**](https://poku.dev) • 🔬 [**Compare Poku with the Most Popular Test Runners**](https://poku.dev/docs/comparing)
36
32
 
37
33
  ---
38
34
 
39
35
  ## Why Poku?
40
36
 
41
- > **Poku** starts from the premise where tests come to help, not overcomplicate: runs test files in an individual process per file, shows progress and exits 🧙🏻
37
+ Don't worry about `describe`, `it`, `beforeEach` and everything else 🚀
38
+
39
+ > You don't need to learn what you already know ✨
42
40
 
43
41
  - Supports **ESM** and **CJS**
44
42
  - Designed to be highly intuitive
@@ -47,45 +45,61 @@ Enjoying Poku? Consider giving him a star ⭐️
47
45
  - Allows both **in-code** and **CLI** usage
48
46
  - [**Node.js**][node-version-url], [**Bun**][bun-version-url] and [**Deno**][deno-version-url] compatibility
49
47
  - Zero configurations, except you want
50
- - No constraints or rules, code in your own signature style
48
+ - Poku adapts to your test, not the other way around
51
49
  - [**And much more!**](https://poku.dev)
52
50
 
53
51
  ---
54
52
 
55
- - <img src="https://img.shields.io/bundlephobia/min/poku?label=Final%20Size">
56
- - **Zero** external dependencies
53
+ - <img src="https://img.shields.io/bundlephobia/min/poku">
54
+ - **Zero** external dependencies 🌱
57
55
 
58
56
  ---
59
57
 
60
58
  ## Documentation
61
59
 
62
- - See detailed specifications and usage in [**Documentation**](https://poku.dev/docs/category/documentation) section for queries, advanced concepts and much more.
60
+ - See detailed usage in [**Documentation**](https://poku.dev/docs/category/documentation) section for **Poku**'s **CLI**, **API (_in-code_)** and **assert**, advanced concepts and much more.
63
61
 
64
62
  ---
65
63
 
66
64
  ## Overview
67
65
 
68
- | Sequential | Parallel |
69
- | ------------------------------------------------------------ | ---------------------------------------------------------- |
70
- | `npx poku test/unit,test/integration` | `npx poku --parallel test/unit,test/integration` |
71
- | <img src=".github/assets/readme/sequential.png" width="360"> | <img src=".github/assets/readme/parallel.png" width="360"> |
66
+ | Sequential | Concurrent |
67
+ | -------------------------------------------------- | ------------------------------------------------ |
68
+ | <img src=".github/assets/readme/sequential.png" /> | <img src=".github/assets/readme/parallel.png" /> |
69
+
70
+ - By default, **Poku**:
71
+ - Searches for all _`.test.`_ and `.spec.` files, but you can customize it using the option [**`filter`**](https://poku.dev/docs/documentation/poku/configs/filter).
72
+ - Uses `sequential` mode.
73
+ - You can use concurrecy by use the flag `--parallel` for **CLI** or the option `parallel` to `true` in **API** (_in-code_) usage.
72
74
 
73
- - By default, **Poku** searches for all _`.test.`_ files, but you can customize it using the option [`filter`](https://github.com/wellwelwel/poku#filter-rexexp).
74
- - The same idea for [**Bun**][bun-version-url] and [**Deno**][deno-version-url] (see bellow).
75
+ > Follow the same idea for [**Bun**][bun-version-url] and [**Deno**][deno-version-url].
75
76
 
76
77
  ---
77
78
 
78
- **Poku** also includes the `assert` method, keeping everything as it is, but providing human readability:
79
+ **Poku** also includes the `assert` method, keeping everything as it is, but providing human readability and automatic `describe` and `it`:
80
+
81
+ > Compatible with **Node.js**, **Bun** and **Deno**.
79
82
 
80
83
  ```ts
81
84
  import { assert } from 'poku'; // Node and Bun
82
85
  import { assert } from 'npm:poku'; // Deno
83
86
 
84
- assert(true);
85
- assert.deepStrictEqual(1, '1', 'My optional custom message');
87
+ const actual = '1';
88
+
89
+ assert(actual, 'My first assert');
90
+ assert.deepStrictEqual(actual, 1, 'My first assert error');
86
91
  ```
87
92
 
88
- > <img src=".github/assets/readme/assert.png" width="468" />
93
+ | Using `poku` | Using `node` |
94
+ | --------------------------------------------------- | --------------------------------------------------- |
95
+ | <img src=".github/assets/readme/assert-poku.png" /> | <img src=".github/assets/readme/assert-node.png" /> |
96
+
97
+ - ❌ Both cases finish with `code 1`, as expected
98
+ - 🧑🏻‍🎓 The `message` param is optional, as it's in **Node.js**
99
+ - 💚 Yes, you can use **Poku**'s `assert` running `node ./my-file.js`
100
+ - 🐷 Unlike most, **Poku** adapts to your test, not the other way around
101
+
102
+ > [**See the complete assert's documentation**](https://poku.dev/docs/documentation/assert).
89
103
 
90
104
  ---
91
105
 
@@ -93,66 +107,48 @@ assert.deepStrictEqual(1, '1', 'My optional custom message');
93
107
 
94
108
  ### **Node.js**
95
109
 
96
- > <img src=".github/assets/readme/node-js.svg" width="24" />
97
-
98
110
  ```bash
99
- npm install --save-dev poku
111
+ npm i -D poku
100
112
  ```
101
113
 
102
114
  ### TypeScript (Node.js)
103
115
 
104
- > <img src=".github/assets/readme/node-js.svg" width="24" />
105
- > <img src=".github/assets/readme/plus.svg" width="24" />
106
- > <img src=".github/assets/readme/typescript.svg" width="24" />
107
-
108
116
  ```bash
109
- npm install --save-dev poku tsx
117
+ npm i -D poku tsx
110
118
  ```
111
119
 
112
120
  ### Bun
113
121
 
114
- > <img src=".github/assets/readme/bun.svg" width="24" />
115
- > <img src=".github/assets/readme/plus.svg" width="24" />
116
- > <img src=".github/assets/readme/typescript.svg" width="24" />
117
-
118
122
  ```bash
119
- bun add --dev poku
123
+ bun add -d poku
120
124
  ```
121
125
 
122
126
  ### **Deno**
123
127
 
124
- > <img src=".github/assets/readme/deno.svg" width="24" />
125
- > <img src=".github/assets/readme/plus.svg" width="24" />
126
- > <img src=".github/assets/readme/typescript.svg" width="24" />
127
-
128
128
  ```ts
129
129
  import { poku } from 'npm:poku';
130
130
  ```
131
131
 
132
- - **Poku** requires these permissions by default: `--allow-read`, `--allow-env` and `--allow-run`.
133
-
134
132
  ---
135
133
 
136
134
  ## Quick Start
137
135
 
138
136
  ### In-code
139
137
 
140
- > <img src=".github/assets/readme/node-js.svg" width="24" />
141
- > <img src=".github/assets/readme/plus.svg" width="24" />
142
- > <img src=".github/assets/readme/bun.svg" width="24" />
138
+ #### Node.js and Bun
143
139
 
144
140
  ```ts
145
141
  import { poku } from 'poku';
146
142
 
147
- await poku(['targetDirA', 'targetDirB']);
143
+ await poku(['targetDir']);
148
144
  ```
149
145
 
150
- > <img src=".github/assets/readme/deno.svg" width="24" />
146
+ #### Deno
151
147
 
152
148
  ```ts
153
149
  import { poku } from 'npm:poku';
154
150
 
155
- await poku(['targetDirA', 'targetDirB']);
151
+ await poku(['targetDir']);
156
152
  ```
157
153
 
158
154
  ### CLI
@@ -160,19 +156,19 @@ await poku(['targetDirA', 'targetDirB']);
160
156
  > <img src=".github/assets/readme/node-js.svg" width="24" />
161
157
 
162
158
  ```bash
163
- npx poku targetDirA,targetDirB
159
+ npx poku targetDir
164
160
  ```
165
161
 
166
162
  > <img src=".github/assets/readme/bun.svg" width="24" />
167
163
 
168
164
  ```bash
169
- bun poku targetDirA,targetDirB
165
+ bun poku targetDir
170
166
  ```
171
167
 
172
168
  > <img src=".github/assets/readme/deno.svg" width="24" />
173
169
 
174
170
  ```bash
175
- deno run npm:poku targetDirA,targetDirB
171
+ deno run npm:poku targetDir
176
172
  ```
177
173
 
178
174
  ---
@@ -9,14 +9,19 @@ export type Configs = {
9
9
  */
10
10
  noExit?: boolean;
11
11
  /**
12
+ * @deprecated
12
13
  * Customize `stdout` options.
13
14
  */
14
15
  log?: {
15
16
  /**
17
+ * @deprecated
18
+ *
16
19
  * @default false
17
20
  */
18
21
  success?: boolean;
19
22
  /**
23
+ * @deprecated
24
+ *
20
25
  * @default true
21
26
  */
22
27
  fail?: boolean;
@@ -26,6 +31,12 @@ export type Configs = {
26
31
  *
27
32
  * @default false
28
33
  */
34
+ debug?: boolean;
35
+ /**
36
+ * This option overwrites the `debug` settings.
37
+ *
38
+ * @default false
39
+ */
29
40
  quiet?: boolean;
30
41
  /**
31
42
  * Determines the mode of test execution.
package/lib/bin/index.js CHANGED
@@ -6,6 +6,7 @@ const list_files_js_1 = require("../modules/list-files.js");
6
6
  const get_arg_js_1 = require("../helpers/get-arg.js");
7
7
  const index_js_1 = require("../index.js");
8
8
  const get_runtime_js_1 = require("../helpers/get-runtime.js");
9
+ const format_js_1 = require("../helpers/format.js");
9
10
  const dirs = ((0, get_arg_js_1.hasArg)('include')
10
11
  ? (_a = (0, get_arg_js_1.getArg)('include')) === null || _a === void 0 ? void 0 : _a.split(',')
11
12
  : (_b = (0, get_arg_js_1.getLastParam)()) === null || _b === void 0 ? void 0 : _b.split(',')) || [];
@@ -14,14 +15,14 @@ const filter = (0, get_arg_js_1.getArg)('filter');
14
15
  const exclude = (0, get_arg_js_1.getArg)('exclude');
15
16
  const parallel = (0, get_arg_js_1.hasArg)('parallel');
16
17
  const quiet = (0, get_arg_js_1.hasArg)('quiet');
17
- const logSuccess = (0, get_arg_js_1.hasArg)('log-success');
18
+ const debug = (0, get_arg_js_1.hasArg)('debug');
19
+ if ((0, get_arg_js_1.hasArg)('log-success'))
20
+ console.log(`The flag ${format_js_1.format.bold('--log-success')} is deprecated. Use ${format_js_1.format.bold('--debug')} instead.`);
18
21
  (0, index_js_1.poku)(dirs, {
19
22
  platform: (0, get_runtime_js_1.platformIsValid)(platform) ? platform : undefined,
20
23
  filter: filter ? new RegExp((0, list_files_js_1.escapeRegExp)(filter)) : undefined,
21
24
  exclude: exclude ? new RegExp((0, list_files_js_1.escapeRegExp)(exclude)) : undefined,
22
25
  parallel,
23
26
  quiet,
24
- log: {
25
- success: logSuccess,
26
- },
27
+ debug,
27
28
  });
@@ -6,4 +6,6 @@ export declare const format: {
6
6
  info: (value: string) => string;
7
7
  success: (value: string) => string;
8
8
  fail: (value: string) => string;
9
+ bg: (bg: number, text: string) => string;
9
10
  };
11
+ export declare const getLargestStringLength: (arr: string[]) => number;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.format = void 0;
3
+ exports.getLargestStringLength = exports.format = void 0;
4
4
  const pad_js_1 = require("./pad.js");
5
5
  exports.format = {
6
6
  counter: (current, total, pad = '0') => {
@@ -10,7 +10,14 @@ exports.format = {
10
10
  dim: (value) => `\x1b[2m${value}\x1b[0m`,
11
11
  bold: (value) => `\x1b[1m${value}\x1b[0m`,
12
12
  underline: (value) => `\x1b[4m${value}\x1b[0m`,
13
- info: (value) => `\x1b[36m${value}\x1b[0m`,
13
+ info: (value) => `\x1b[94m${value}\x1b[0m`,
14
14
  success: (value) => `\x1b[32m${value}\x1b[0m`,
15
- fail: (value) => `\x1b[31m${value}\x1b[0m`,
15
+ fail: (value) => `\x1b[91m${value}\x1b[0m`,
16
+ bg: (bg, text) => {
17
+ const padding = ' '.repeat(1);
18
+ const paddedText = `${padding}${text}${padding}`;
19
+ return `\x1b[${bg}m\x1b[1m${paddedText}\x1b[0m`;
20
+ },
16
21
  };
22
+ const getLargestStringLength = (arr) => arr.reduce((max, current) => Math.max(max, current.length), 0);
23
+ exports.getLargestStringLength = getLargestStringLength;
package/lib/helpers/hr.js CHANGED
@@ -7,8 +7,7 @@ exports.hr = void 0;
7
7
  const node_os_1 = require("os");
8
8
  const node_process_1 = __importDefault(require("process"));
9
9
  const hr = () => {
10
- const columns = node_process_1.default.stdout.columns;
11
- const line = '_'.repeat(columns - 10 || 30);
12
- console.log(`\x1b[2m${line}\x1b[0m${node_os_1.EOL}`);
10
+ const line = '⎯'.repeat(node_process_1.default.stdout.columns - 10);
11
+ console.log(`${node_os_1.EOL}\x1b[2m\x1b[90m${line}\x1b[0m${node_os_1.EOL}`);
13
12
  };
14
13
  exports.hr = hr;
@@ -1,4 +1,3 @@
1
1
  import { Configs } from '../@types/poku.js';
2
2
  export declare const isQuiet: (configs?: Configs) => boolean;
3
- export declare const showSuccesses: (configs?: Configs) => boolean;
4
- export declare const showFailures: (configs?: Configs) => boolean;
3
+ export declare const isDebug: (configs?: Configs) => boolean;
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.showFailures = exports.showSuccesses = exports.isQuiet = void 0;
3
+ exports.isDebug = exports.isQuiet = void 0;
4
4
  const isQuiet = (configs) => typeof (configs === null || configs === void 0 ? void 0 : configs.quiet) === 'boolean' && Boolean(configs === null || configs === void 0 ? void 0 : configs.quiet);
5
5
  exports.isQuiet = isQuiet;
6
- const showSuccesses = (configs) => { var _a; return Boolean((_a = configs === null || configs === void 0 ? void 0 : configs.log) === null || _a === void 0 ? void 0 : _a.success); };
7
- exports.showSuccesses = showSuccesses;
8
- const showFailures = (configs) => { var _a, _b; return typeof ((_a = configs === null || configs === void 0 ? void 0 : configs.log) === null || _a === void 0 ? void 0 : _a.fail) === 'undefined' || Boolean((_b = configs === null || configs === void 0 ? void 0 : configs.log) === null || _b === void 0 ? void 0 : _b.fail); };
9
- exports.showFailures = showFailures;
6
+ const isDebug = (configs) => Boolean(configs === null || configs === void 0 ? void 0 : configs.debug);
7
+ exports.isDebug = isDebug;
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.parseAssertion = void 0;
7
7
  const node_process_1 = __importDefault(require("process"));
8
+ const node_path_1 = __importDefault(require("path"));
8
9
  const node_assert_1 = __importDefault(require("assert"));
9
10
  const node_os_1 = require("os");
10
11
  const format_js_1 = require("./format.js");
@@ -25,35 +26,50 @@ const findFile = (error) => {
25
26
  }
26
27
  return file;
27
28
  };
29
+ const formatFail = (str) => format_js_1.format.bold(format_js_1.format.fail(`✘ ${str}`));
28
30
  const parseAssertion = (cb, options) => {
31
+ var _a, _b;
32
+ const isPoku = typeof ((_a = node_process_1.default.env) === null || _a === void 0 ? void 0 : _a.FILE) === 'string' && ((_b = node_process_1.default.env) === null || _b === void 0 ? void 0 : _b.FILE.length) > 0;
33
+ const FILE = node_process_1.default.env.FILE;
29
34
  try {
30
35
  cb();
36
+ if (typeof options.message === 'string') {
37
+ const message = isPoku
38
+ ? `${format_js_1.format.bold(format_js_1.format.success(`✔ ${options.message}`))} ${format_js_1.format.dim(format_js_1.format.success(`› ${FILE}`))}`
39
+ : format_js_1.format.bold(format_js_1.format.success(`✔ ${options.message}`));
40
+ console.log(message);
41
+ }
31
42
  }
32
43
  catch (error) {
33
44
  if (error instanceof node_assert_1.default.AssertionError) {
34
45
  const { code, actual, expected, operator } = error;
35
- const file = findFile(error);
36
- (0, hr_js_1.hr)();
46
+ const absoultePath = findFile(error);
47
+ const file = node_path_1.default.relative(node_path_1.default.resolve(node_process_1.default.cwd()), absoultePath);
48
+ let message = '';
37
49
  if (typeof options.message === 'string')
38
- console.log(format_js_1.format.bold(options.message), node_os_1.EOL);
50
+ message = options.message;
39
51
  else if (options.message instanceof Error)
40
- console.log(format_js_1.format.bold(options.message.message), node_os_1.EOL);
52
+ message = options.message.message;
41
53
  else if (typeof options.defaultMessage === 'string')
42
- console.log(options.defaultMessage, node_os_1.EOL);
43
- console.log(format_js_1.format.dim('Code: '), format_js_1.format.bold(format_js_1.format.fail(code)));
44
- file && console.log(format_js_1.format.dim('File: '), file);
45
- console.log(format_js_1.format.dim('Operator:'), operator);
46
- (0, hr_js_1.hr)();
54
+ message = options.defaultMessage;
55
+ const finalMessage = (message === null || message === void 0 ? void 0 : message.trim().length) > 0
56
+ ? `${formatFail(message)}`
57
+ : `${formatFail('No Message')}`;
58
+ console.log(isPoku
59
+ ? `${finalMessage} ${format_js_1.format.dim(format_js_1.format.fail(`› ${FILE}`))}`
60
+ : finalMessage);
61
+ file && console.log(`${format_js_1.format.dim(' File')} ${file}`);
62
+ console.log(`${format_js_1.format.dim(' Code')} ${code}`);
63
+ console.log(`${format_js_1.format.dim(' Operator')} ${operator}${node_os_1.EOL}`);
47
64
  if (!(options === null || options === void 0 ? void 0 : options.hideDiff)) {
48
- console.log(format_js_1.format.dim(`${(options === null || options === void 0 ? void 0 : options.actual) || 'Actual'}:`));
65
+ console.log(format_js_1.format.dim(` ${(options === null || options === void 0 ? void 0 : options.actual) || 'Actual'}:`));
49
66
  console.log(format_js_1.format.bold(typeof actual === 'function' || actual instanceof RegExp
50
- ? String(actual)
51
- : format_js_1.format.fail(JSON.stringify(actual))));
52
- console.log(`${node_os_1.EOL}${format_js_1.format.dim(`${(options === null || options === void 0 ? void 0 : options.expected) || 'Expected'}:`)}`);
53
- console.log(format_js_1.format.bold(typeof expected === 'function' || expected instanceof RegExp
54
- ? String(expected)
55
- : format_js_1.format.success(JSON.stringify(expected))));
56
- (0, hr_js_1.hr)();
67
+ ? ` ${String(actual)}`
68
+ : ` ${format_js_1.format.fail(JSON.stringify(actual))}`));
69
+ console.log(`${node_os_1.EOL} ${format_js_1.format.dim(`${(options === null || options === void 0 ? void 0 : options.expected) || 'Expected'}:`)}`);
70
+ console.log(format_js_1.format.bold(`${typeof expected === 'function' || expected instanceof RegExp
71
+ ? ` ${String(expected)}`
72
+ : ` ${format_js_1.format.success(JSON.stringify(expected))}`}`));
57
73
  }
58
74
  if (options.throw) {
59
75
  console.log(error);
@@ -0,0 +1 @@
1
+ export declare const removeConsecutiveRepeats: (arr: string[], specificItem: RegExp) => string[];
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.removeConsecutiveRepeats = void 0;
4
+ const removeConsecutiveRepeats = (arr, specificItem) => {
5
+ const result = [];
6
+ let consecutiveCount = 0;
7
+ for (let i = 0; i < arr.length; i++) {
8
+ if (specificItem.test(arr[i])) {
9
+ consecutiveCount++;
10
+ if (consecutiveCount <= 2) {
11
+ result.push(arr[i]);
12
+ }
13
+ }
14
+ else {
15
+ consecutiveCount = 0;
16
+ result.push(arr[i]);
17
+ }
18
+ // Check if the next item is different or we're at the end of the array
19
+ if (i + 1 === arr.length || !specificItem.test(arr[i + 1])) {
20
+ // If more than two consecutive, remove them from the result
21
+ if (consecutiveCount > 2) {
22
+ result.splice(-consecutiveCount);
23
+ }
24
+ consecutiveCount = 0; // Reset the counter for the next group
25
+ }
26
+ }
27
+ return result;
28
+ };
29
+ exports.removeConsecutiveRepeats = removeConsecutiveRepeats;
@@ -35,7 +35,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
35
35
  exports.assert = void 0;
36
36
  const nodeAssert = __importStar(require("assert"));
37
37
  const parseAsssetion_js_1 = require("../helpers/parseAsssetion.js");
38
- const format_js_1 = require("../helpers/format.js");
39
38
  const ok = (value, message) => (0, parseAsssetion_js_1.parseAssertion)(() => nodeAssert.ok(value), { message });
40
39
  const equal = (actual, expected, message) => (0, parseAsssetion_js_1.parseAssertion)(() => nodeAssert.equal(actual, expected), { message });
41
40
  const deepEqual = (actual, expected, message) => (0, parseAsssetion_js_1.parseAssertion)(() => nodeAssert.deepEqual(actual, expected), { message });
@@ -47,7 +46,7 @@ const doesNotMatch = (value, regExp, message) => (0, parseAsssetion_js_1.parseAs
47
46
  message,
48
47
  actual: 'Value',
49
48
  expected: 'RegExp',
50
- defaultMessage: format_js_1.format.bold('Value should not match regExp'),
49
+ defaultMessage: 'Value should not match regExp',
51
50
  });
52
51
  function doesNotReject(block, errorOrMessage, message) {
53
52
  return __awaiter(this, void 0, void 0, function* () {
@@ -62,7 +61,7 @@ function doesNotReject(block, errorOrMessage, message) {
62
61
  throw error;
63
62
  }, {
64
63
  message,
65
- defaultMessage: format_js_1.format.bold('Got unwanted rejection'),
64
+ defaultMessage: 'Got unwanted rejection',
66
65
  hideDiff: true,
67
66
  throw: true,
68
67
  });
@@ -77,7 +76,7 @@ function doesNotReject(block, errorOrMessage, message) {
77
76
  throw error_1;
78
77
  }, {
79
78
  message: typeof errorOrMessage === 'string' ? errorOrMessage : undefined,
80
- defaultMessage: format_js_1.format.bold('Got unwanted rejection'),
79
+ defaultMessage: 'Got unwanted rejection',
81
80
  hideDiff: true,
82
81
  throw: true,
83
82
  });
@@ -97,7 +96,7 @@ function doesNotThrow(block, errorOrMessage, message) {
97
96
  throw error;
98
97
  }, {
99
98
  message: message,
100
- defaultMessage: format_js_1.format.bold('Expected function not to throw'),
99
+ defaultMessage: 'Expected function not to throw',
101
100
  hideDiff: true,
102
101
  throw: true,
103
102
  });
@@ -113,7 +112,7 @@ function doesNotThrow(block, errorOrMessage, message) {
113
112
  throw error;
114
113
  }, {
115
114
  message: msg,
116
- defaultMessage: format_js_1.format.bold('Expected function not to throw'),
115
+ defaultMessage: 'Expected function not to throw',
117
116
  hideDiff: true,
118
117
  throw: true,
119
118
  });
@@ -132,7 +131,7 @@ function throws(block, errorOrMessage, message) {
132
131
  throw error;
133
132
  }, {
134
133
  message: message,
135
- defaultMessage: format_js_1.format.bold('Expected function to throw'),
134
+ defaultMessage: 'Expected function to throw',
136
135
  hideDiff: true,
137
136
  });
138
137
  }
@@ -147,7 +146,7 @@ function throws(block, errorOrMessage, message) {
147
146
  throw error;
148
147
  }, {
149
148
  message: msg,
150
- defaultMessage: format_js_1.format.bold('Expected function to throw'),
149
+ defaultMessage: 'Expected function to throw',
151
150
  hideDiff: true,
152
151
  });
153
152
  }
@@ -167,7 +166,7 @@ const match = (value, regExp, message) => (0, parseAsssetion_js_1.parseAssertion
167
166
  message,
168
167
  actual: 'Value',
169
168
  expected: 'RegExp',
170
- defaultMessage: format_js_1.format.bold('Value should match regExp'),
169
+ defaultMessage: 'Value should match regExp',
171
170
  });
172
171
  const ifError = (value) => {
173
172
  try {
@@ -177,7 +176,7 @@ const ifError = (value) => {
177
176
  (0, parseAsssetion_js_1.parseAssertion)(() => {
178
177
  throw error;
179
178
  }, {
180
- defaultMessage: format_js_1.format.bold('Expected no error, but received an error'),
179
+ defaultMessage: 'Expected no error, but received an error',
181
180
  hideDiff: true,
182
181
  throw: true,
183
182
  });
@@ -192,7 +191,7 @@ const fail = (message) => {
192
191
  throw error;
193
192
  }, {
194
193
  message,
195
- defaultMessage: format_js_1.format.bold('Test failed intentionally'),
194
+ defaultMessage: 'Test failed intentionally',
196
195
  hideDiff: true,
197
196
  });
198
197
  }
@@ -210,7 +209,7 @@ function rejects(block, errorOrMessage, message) {
210
209
  throw error;
211
210
  }, {
212
211
  message,
213
- defaultMessage: format_js_1.format.bold('Expected promise to be rejected with specified error'),
212
+ defaultMessage: 'Expected promise to be rejected with specified error',
214
213
  hideDiff: true,
215
214
  });
216
215
  }
@@ -225,7 +224,7 @@ function rejects(block, errorOrMessage, message) {
225
224
  throw error_1;
226
225
  }, {
227
226
  message: msg,
228
- defaultMessage: format_js_1.format.bold('Expected promise to be rejected'),
227
+ defaultMessage: 'Expected promise to be rejected',
229
228
  hideDiff: true,
230
229
  });
231
230
  }
@@ -5,23 +5,24 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.exit = void 0;
7
7
  const node_process_1 = __importDefault(require("process"));
8
- const node_os_1 = require("os");
9
8
  const hr_js_1 = require("../helpers/hr.js");
9
+ const run_tests_js_1 = require("../services/run-tests.js");
10
+ const format_js_1 = require("../helpers/format.js");
10
11
  const exit = (code, quiet) => {
12
+ const isPoku = run_tests_js_1.results.success > 0 || run_tests_js_1.results.fail > 0;
11
13
  !quiet &&
12
14
  node_process_1.default.on('exit', (code) => {
13
- console.log(`Exited with code`, code, node_os_1.EOL);
15
+ isPoku &&
16
+ console.log(format_js_1.format.bg(42, `PASS › ${run_tests_js_1.results.success}`), format_js_1.format.bg(run_tests_js_1.results.fail === 0 ? 100 : 41, `FAIL › ${run_tests_js_1.results.fail}`));
17
+ isPoku && (0, hr_js_1.hr)();
18
+ console.log(`${format_js_1.format.dim('Exited with code')} ${format_js_1.format.bold(format_js_1.format === null || format_js_1.format === void 0 ? void 0 : format_js_1.format[code === 0 ? 'success' : 'fail'](String(code)))}`);
14
19
  });
15
- !quiet && (0, hr_js_1.hr)();
16
- if (code !== 0) {
17
- !quiet && console.log('Some tests failed.');
20
+ isPoku && !quiet && (0, hr_js_1.hr)();
21
+ if (code !== 0)
18
22
  node_process_1.default.exit(1);
19
- }
20
- !quiet && console.log('All tests passed.');
21
23
  node_process_1.default.exit(0);
22
24
  };
23
25
  exports.exit = exit;
24
- node_process_1.default.stdout.on('resize', hr_js_1.hr);
25
26
  node_process_1.default.on('unhandledRejection', (reason) => {
26
27
  console.log('unhandledRejection', reason);
27
28
  node_process_1.default.exit(1);
@@ -15,7 +15,7 @@ const envFilter = ((_a = node_process_1.default.env.FILTER) === null || _a === v
15
15
  : null;
16
16
  const listFiles = (dirPath, files = [], configs) => {
17
17
  const currentFiles = node_fs_1.default.readdirSync(dirPath);
18
- const defaultRegExp = /\.test\./i;
18
+ const defaultRegExp = /\.(test|spec)\./i;
19
19
  const filter = (envFilter
20
20
  ? envFilter
21
21
  : (configs === null || configs === void 0 ? void 0 : configs.filter) instanceof RegExp
@@ -28,6 +28,8 @@ const listFiles = (dirPath, files = [], configs) => {
28
28
  : undefined;
29
29
  for (const file of currentFiles) {
30
30
  const fullPath = node_path_1.default.join(dirPath, file);
31
+ if (/node_modules/.test(fullPath))
32
+ continue;
31
33
  if (exclude && exclude.some((regex) => regex.test(fullPath)))
32
34
  continue;
33
35
  if (node_fs_1.default.statSync(fullPath).isDirectory())
@@ -10,17 +10,38 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.poku = void 0;
13
+ const node_os_1 = require("os");
13
14
  const force_array_js_1 = require("../helpers/force-array.js");
14
15
  const run_tests_js_1 = require("../services/run-tests.js");
15
16
  const exit_js_1 = require("./exit.js");
17
+ const format_js_1 = require("../helpers/format.js");
18
+ const logs_js_1 = require("../helpers/logs.js");
19
+ const hr_js_1 = require("../helpers/hr.js");
20
+ const run_test_file_js_1 = require("../services/run-test-file.js");
21
+ const indentation_js_1 = require("../helpers/indentation.js");
16
22
  function poku(targetDirs, configs) {
17
23
  return __awaiter(this, void 0, void 0, function* () {
18
24
  let code = 0;
19
- const dirs = (0, force_array_js_1.forceArray)(targetDirs);
25
+ const prepareDirs = (0, force_array_js_1.forceArray)(targetDirs);
26
+ const dirs = prepareDirs.length > 0 ? prepareDirs : ['./'];
27
+ const showLogs = !(0, logs_js_1.isQuiet)(configs);
20
28
  if (configs === null || configs === void 0 ? void 0 : configs.parallel) {
21
- const results = yield Promise.all(dirs.map((dir) => (0, run_tests_js_1.runTestsParallel)(dir, configs)));
22
- if (results.some((result) => !result))
29
+ if (showLogs) {
30
+ (0, hr_js_1.hr)();
31
+ console.log(`${format_js_1.format.bold('Running the Test Suite in Parallel')}${node_os_1.EOL}`);
32
+ }
33
+ const concurrency = yield Promise.all(dirs.map((dir) => (0, run_tests_js_1.runTestsParallel)(dir, configs)));
34
+ if (concurrency.some((result) => !result))
23
35
  code = 1;
36
+ showLogs && (0, hr_js_1.hr)();
37
+ if (showLogs && run_test_file_js_1.fileResults.success.length > 0)
38
+ console.log(run_test_file_js_1.fileResults.success
39
+ .map((current) => `${indentation_js_1.indentation.test}${format_js_1.format.success('✔')} ${format_js_1.format.dim(current)}`)
40
+ .join(node_os_1.EOL));
41
+ if (showLogs && run_test_file_js_1.fileResults.fail.length > 0)
42
+ console.log(run_test_file_js_1.fileResults.fail
43
+ .map((current) => `${indentation_js_1.indentation.test}${format_js_1.format.fail('✘')} ${current}`)
44
+ .join(node_os_1.EOL));
24
45
  if (configs === null || configs === void 0 ? void 0 : configs.noExit)
25
46
  return code;
26
47
  (0, exit_js_1.exit)(code, configs === null || configs === void 0 ? void 0 : configs.quiet);
@@ -1,2 +1,8 @@
1
1
  import { Configs } from '../@types/poku.js';
2
+ type FileResults = {
3
+ success: string[];
4
+ fail: string[];
5
+ };
6
+ export declare const fileResults: FileResults;
2
7
  export declare const runTestFile: (filePath: string, configs?: Configs) => Promise<boolean>;
8
+ export {};
@@ -3,44 +3,82 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.runTestFile = void 0;
6
+ exports.runTestFile = exports.fileResults = void 0;
7
7
  const node_process_1 = __importDefault(require("process"));
8
- const node_child_process_1 = require("child_process");
8
+ const node_os_1 = require("os");
9
9
  const node_path_1 = __importDefault(require("path"));
10
+ const node_child_process_1 = require("child_process");
10
11
  const runner_js_1 = require("../helpers/runner.js");
11
12
  const indentation_js_1 = require("../helpers/indentation.js");
12
13
  const format_js_1 = require("../helpers/format.js");
13
14
  const logs_js_1 = require("../helpers/logs.js");
15
+ const remove_repeats_js_1 = require("../helpers/remove-repeats.js");
16
+ exports.fileResults = {
17
+ success: [],
18
+ fail: [],
19
+ };
14
20
  const runTestFile = (filePath, configs) => new Promise((resolve) => {
15
- let output = '';
16
- const showLogs = !(0, logs_js_1.isQuiet)(configs);
17
- const showSuccess = (0, logs_js_1.showSuccesses)(configs);
18
- const showFailure = (0, logs_js_1.showFailures)(configs);
19
- const log = () => console.log(output === null || output === void 0 ? void 0 : output.trim());
20
- const fileRelative = node_path_1.default.relative(node_process_1.default.cwd(), filePath);
21
- showLogs &&
22
- console.log(`${indentation_js_1.indentation.test}${format_js_1.format.info('→')} ${fileRelative}`);
23
21
  const runtimeOptions = (0, runner_js_1.runner)(filePath, configs);
24
22
  const runtime = runtimeOptions.shift();
25
23
  const runtimeArguments = runtimeOptions.length > 1 ? [...runtimeOptions, filePath] : [filePath];
24
+ const fileRelative = node_path_1.default.relative(node_process_1.default.cwd(), filePath);
25
+ const showLogs = !(0, logs_js_1.isQuiet)(configs);
26
+ const showSuccess = (0, logs_js_1.isDebug)(configs);
27
+ const pad = (configs === null || configs === void 0 ? void 0 : configs.parallel) ? ' ' : ' ';
28
+ let output = '';
29
+ const log = () => {
30
+ const outputs = (0, remove_repeats_js_1.removeConsecutiveRepeats)(showSuccess
31
+ ? output.split(/(\r\n|\r|\n)/)
32
+ : output.split(/(\r\n|\r|\n)/).filter((current) => {
33
+ if (current.includes('Exited with code'))
34
+ return false;
35
+ return (/u001b\[0m|(\r\n|\r|\n)/i.test(JSON.stringify(current)) ||
36
+ current === '');
37
+ }), /(\r\n|\r|\n)|^$/);
38
+ // Remove last EOL
39
+ outputs.length > 1 && outputs.pop();
40
+ if (!showSuccess &&
41
+ /error:/i.test(output) &&
42
+ !/error:/i.test(outputs.join()))
43
+ Object.assign(outputs, [
44
+ ...outputs,
45
+ format_js_1.format.bold(format_js_1.format.fail(`✘ External Error ${format_js_1.format.dim(`› ${fileRelative}`)}`)),
46
+ format_js_1.format.dim(' For detailed diagnostics:'),
47
+ `${format_js_1.format.dim(` CLI ›`)} rerun with the ${format_js_1.format.bold('--debug')} flag enabled.`,
48
+ `${format_js_1.format.dim(` API ›`)} set the config option ${format_js_1.format.bold('debug')} to true.`,
49
+ `${format_js_1.format.dim(' RUN ›')} ${format_js_1.format.bold(`${runtime === 'tsx' ? 'npx tsx' : runtime}${runtimeArguments.slice(0, -1).join(' ')} ${fileRelative}`)}`,
50
+ ]);
51
+ const mappedOutputs = outputs.map((current) => `${pad}${current}`);
52
+ if (outputs.length === 1 && outputs[0] === '')
53
+ return;
54
+ console.log(showSuccess ? mappedOutputs.join('') : mappedOutputs.join(node_os_1.EOL));
55
+ };
56
+ const stdOut = (data) => {
57
+ output += String(data);
58
+ };
59
+ if (!(configs === null || configs === void 0 ? void 0 : configs.parallel)) {
60
+ showLogs &&
61
+ console.log(`${indentation_js_1.indentation.test}${format_js_1.format.info(format_js_1.format.dim('●'))} ${format_js_1.format.dim(fileRelative)}`);
62
+ }
26
63
  const child = (0, node_child_process_1.spawn)(runtime, runtimeArguments, {
27
64
  stdio: ['inherit', 'pipe', 'pipe'],
28
- env: node_process_1.default.env,
29
- });
30
- child.stdout.on('data', (data) => {
31
- output += data.toString();
32
- });
33
- child.stderr.on('data', (data) => {
34
- output += data.toString();
65
+ env: Object.assign(Object.assign({}, node_process_1.default.env), { FILE: (configs === null || configs === void 0 ? void 0 : configs.parallel) ? fileRelative : '' }),
35
66
  });
67
+ child.stdout.on('data', stdOut);
68
+ child.stderr.on('data', stdOut);
36
69
  child.on('close', (code) => {
37
- if (showLogs &&
38
- ((code === 0 && showSuccess) || (code !== 0 && showFailure)))
70
+ if (showLogs)
39
71
  log();
40
- resolve(code === 0);
72
+ const result = code === 0;
73
+ if (result)
74
+ exports.fileResults.success.push(fileRelative);
75
+ else
76
+ exports.fileResults.fail.push(fileRelative);
77
+ resolve(result);
41
78
  });
42
79
  child.on('error', (err) => {
43
80
  console.log(`Failed to start test: ${filePath}`, err);
81
+ exports.fileResults.fail.push(fileRelative);
44
82
  resolve(false);
45
83
  });
46
84
  });
@@ -1,3 +1,7 @@
1
1
  import { Configs } from '../@types/poku.js';
2
+ export declare const results: {
3
+ success: number;
4
+ fail: number;
5
+ };
2
6
  export declare const runTests: (dir: string, configs?: Configs) => Promise<boolean>;
3
7
  export declare const runTestsParallel: (dir: string, configs?: Configs) => Promise<boolean>;
@@ -12,7 +12,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.runTestsParallel = exports.runTests = void 0;
15
+ exports.runTestsParallel = exports.runTests = exports.results = void 0;
16
16
  const node_process_1 = __importDefault(require("process"));
17
17
  const node_os_1 = require("os");
18
18
  const node_path_1 = __importDefault(require("path"));
@@ -23,6 +23,10 @@ const hr_js_1 = require("../helpers/hr.js");
23
23
  const format_js_1 = require("../helpers/format.js");
24
24
  const run_test_file_js_1 = require("./run-test-file.js");
25
25
  const logs_js_1 = require("../helpers/logs.js");
26
+ exports.results = {
27
+ success: 0,
28
+ fail: 0,
29
+ };
26
30
  const runTests = (dir, configs) => __awaiter(void 0, void 0, void 0, function* () {
27
31
  const cwd = node_process_1.default.cwd();
28
32
  const testDir = node_path_1.default.join(cwd, dir);
@@ -33,7 +37,7 @@ const runTests = (dir, configs) => __awaiter(void 0, void 0, void 0, function* (
33
37
  let passed = true;
34
38
  if (showLogs) {
35
39
  (0, hr_js_1.hr)();
36
- console.log(`${format_js_1.format.bold('Directory:')} ${format_js_1.format.underline(currentDir)}${node_os_1.EOL}`);
40
+ console.log(`${format_js_1.format.bold('Directory:')} ${format_js_1.format.underline(`./${currentDir}`)}${node_os_1.EOL}`);
37
41
  }
38
42
  for (let i = 0; i < files.length; i++) {
39
43
  const filePath = files[i];
@@ -43,13 +47,16 @@ const runTests = (dir, configs) => __awaiter(void 0, void 0, void 0, function* (
43
47
  const counter = format_js_1.format.counter(testNumber, totalTests);
44
48
  const command = `${(0, runner_js_1.runner)(fileRelative, configs).join(' ')} ${fileRelative}`;
45
49
  const nextLine = i + 1 !== files.length ? node_os_1.EOL : '';
46
- const log = `${counter}/${totalTests} ${command}${nextLine}`;
50
+ const log = `${counter}/${totalTests} ${command}`;
47
51
  if (testPassed) {
52
+ ++exports.results.success;
48
53
  showLogs &&
49
- console.log(`${indentation_js_1.indentation.test}${format_js_1.format.success('✔')} ${log}`);
54
+ console.log(`${indentation_js_1.indentation.test}${format_js_1.format.success('✔')} ${log}`, nextLine);
50
55
  }
51
56
  else {
52
- showLogs && console.log(`${indentation_js_1.indentation.test}${format_js_1.format.fail('✖')} ${log}`);
57
+ ++exports.results.fail;
58
+ showLogs &&
59
+ console.log(`${indentation_js_1.indentation.test}${format_js_1.format.fail('✘')} ${log}`, nextLine);
53
60
  passed = false;
54
61
  }
55
62
  }
@@ -60,23 +67,16 @@ const runTestsParallel = (dir, configs) => __awaiter(void 0, void 0, void 0, fun
60
67
  const cwd = node_process_1.default.cwd();
61
68
  const testDir = node_path_1.default.join(cwd, dir);
62
69
  const files = (0, list_files_js_1.listFiles)(testDir, undefined, configs);
63
- const showLogs = !(0, logs_js_1.isQuiet)(configs);
64
70
  const promises = files.map((filePath) => __awaiter(void 0, void 0, void 0, function* () {
65
- const fileRelative = node_path_1.default.relative(cwd, filePath);
66
71
  const testPassed = yield (0, run_test_file_js_1.runTestFile)(filePath, configs);
67
- const command = `${(0, runner_js_1.runner)(fileRelative).join(' ')} ${fileRelative}`;
68
- if (testPassed) {
69
- showLogs &&
70
- console.log(`${indentation_js_1.indentation.test}${format_js_1.format.success('✔')} ${command}`);
71
- }
72
- else {
73
- showLogs &&
74
- console.log(`${indentation_js_1.indentation.test}${format_js_1.format.fail('✖')} ${command}`);
72
+ if (!testPassed) {
73
+ ++exports.results.fail;
75
74
  return false;
76
75
  }
76
+ ++exports.results.success;
77
77
  return true;
78
78
  }));
79
- const results = yield Promise.all(promises);
80
- return results.every((result) => result);
79
+ const concurrency = yield Promise.all(promises);
80
+ return concurrency.every((result) => result);
81
81
  });
82
82
  exports.runTestsParallel = runTestsParallel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "poku",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "🐷 Poku is your test runner pet for Node.js, Bun and Deno, combining flexibility, parallel and sequential runs, human-friendly assertion errors and high isolation level",
5
5
  "main": "./lib/index.js",
6
6
  "scripts": {
@@ -9,14 +9,16 @@
9
9
  "test:node": "FILTER='node-' npm run test:ci",
10
10
  "test:deno": "FILTER='deno-' npm run test:ci",
11
11
  "test:bun": "FILTER='bun-' npm run test:ci",
12
- "update": "npx npu;",
13
12
  "prebuild": "rm -rf ./lib ./ci",
14
13
  "build": "npx tsc; npx tsc -p tsconfig.test.json",
15
14
  "postbuild": "npx tsx ./tools/compatibility/node.ts; chmod +x lib/bin/index.js; npm audit",
16
15
  "eslint:checker": "npx eslint . --ext .js,.ts",
17
16
  "eslint:fix": "npx eslint . --fix --config ./.eslintrc.json",
17
+ "lint:checker": "npm run eslint:checker; npm run prettier:checker",
18
+ "lint:fix": "npm run eslint:fix; npm run prettier:fix",
18
19
  "prettier:checker": "npx prettier --check .",
19
- "prettier:fix": "npx prettier --write .github/workflows/*.yml ."
20
+ "prettier:fix": "npx prettier --write .github/workflows/*.yml .",
21
+ "update": "npx npu; npm i; npm run lint:fix; npm audit"
20
22
  },
21
23
  "license": "MIT",
22
24
  "repository": {
@@ -78,16 +80,17 @@
78
80
  "engines": {
79
81
  "node": ">=6.0.0",
80
82
  "bun": ">=0.5.3",
81
- "deno": ">=1.17.0"
83
+ "deno": ">=1.17.0",
84
+ "typescript": ">=5.0.2"
82
85
  },
83
86
  "files": [
84
87
  "lib"
85
88
  ],
86
89
  "type": "commonjs",
87
90
  "devDependencies": {
88
- "@types/node": "^20.11.19",
89
- "@typescript-eslint/eslint-plugin": "^7.0.1",
90
- "@typescript-eslint/parser": "^7.0.1",
91
+ "@types/node": "^20.11.20",
92
+ "@typescript-eslint/eslint-plugin": "^7.0.2",
93
+ "@typescript-eslint/parser": "^7.0.2",
91
94
  "eslint": "^8.56.0",
92
95
  "eslint-config-prettier": "^9.1.0",
93
96
  "eslint-import-resolver-typescript": "^3.6.1",