es-toolkit-eslint-plugin 0.1.0 → 0.1.2
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/rules/prefer-compact.js +29 -3
- package/dist/rules/prefer-delay.js +25 -11
- package/dist/rules/prefer-is-empty.js +4 -1
- package/dist/rules/prefer-random-int.js +12 -5
- package/dist/rules/prefer-sample.js +12 -3
- package/docs/rules/prefer-compact.md +10 -2
- package/docs/rules/prefer-delay.md +11 -5
- package/docs/rules/prefer-is-empty.md +3 -2
- package/docs/rules/prefer-random-int.md +11 -6
- package/docs/rules/prefer-sample.md +8 -2
- package/package.json +7 -9
|
@@ -1,20 +1,46 @@
|
|
|
1
1
|
import { createRule } from '../utils/create-rule.js';
|
|
2
2
|
const filterBoolean = 'CallExpression[callee.property.name="filter"][arguments.length=1][arguments.0.name="Boolean"]';
|
|
3
|
+
// `.filter(x => …)` with a single single-parameter arrow predicate; its body is checked below.
|
|
4
|
+
const filterArrow = 'CallExpression[callee.property.name="filter"][arguments.length=1][arguments.0.type="ArrowFunctionExpression"][arguments.0.params.length=1][arguments.0.params.0.type="Identifier"]';
|
|
5
|
+
const isParam = (node, param) => node.type === 'Identifier' && node.name === param;
|
|
3
6
|
export const preferCompact = createRule({
|
|
4
7
|
name: 'prefer-compact',
|
|
5
8
|
meta: {
|
|
6
9
|
type: 'suggestion',
|
|
7
10
|
docs: {
|
|
8
|
-
description: 'Prefer `compact` from es-toolkit over
|
|
11
|
+
description: 'Prefer `compact` from es-toolkit over a truthiness filter.',
|
|
9
12
|
},
|
|
10
13
|
schema: [],
|
|
11
14
|
messages: {
|
|
12
|
-
preferCompact: 'Prefer `compact` from es-toolkit instead of
|
|
15
|
+
preferCompact: 'Prefer `compact` from es-toolkit instead of filtering by truthiness.',
|
|
13
16
|
},
|
|
14
17
|
},
|
|
15
18
|
create(context) {
|
|
19
|
+
const report = (node) => context.report({ node, messageId: 'preferCompact' });
|
|
16
20
|
return {
|
|
17
|
-
[filterBoolean]:
|
|
21
|
+
[filterBoolean]: report,
|
|
22
|
+
[filterArrow](node) {
|
|
23
|
+
const arrow = node.arguments[0];
|
|
24
|
+
if (arrow.type !== 'ArrowFunctionExpression')
|
|
25
|
+
return;
|
|
26
|
+
const [param] = arrow.params;
|
|
27
|
+
if (param.type !== 'Identifier')
|
|
28
|
+
return;
|
|
29
|
+
const { body } = arrow;
|
|
30
|
+
// The predicate keeps only truthy values: `x => !!x` or `x => Boolean(x)`.
|
|
31
|
+
const isDoubleBang = body.type === 'UnaryExpression'
|
|
32
|
+
&& body.operator === '!'
|
|
33
|
+
&& body.argument.type === 'UnaryExpression'
|
|
34
|
+
&& body.argument.operator === '!'
|
|
35
|
+
&& isParam(body.argument.argument, param.name);
|
|
36
|
+
const isBooleanCall = body.type === 'CallExpression'
|
|
37
|
+
&& body.callee.type === 'Identifier'
|
|
38
|
+
&& body.callee.name === 'Boolean'
|
|
39
|
+
&& body.arguments.length === 1
|
|
40
|
+
&& isParam(body.arguments[0], param.name);
|
|
41
|
+
if (isDoubleBang || isBooleanCall)
|
|
42
|
+
report(node);
|
|
43
|
+
},
|
|
18
44
|
};
|
|
19
45
|
},
|
|
20
46
|
});
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { createRule } from '../utils/create-rule.js';
|
|
2
2
|
// `new Promise(resolve => setTimeout(resolve, ms))` — a single-param executor whose
|
|
3
3
|
// expression body is a two-argument `setTimeout` whose first argument is an identifier.
|
|
4
|
-
const
|
|
4
|
+
const expressionExecutor = 'NewExpression[callee.name="Promise"][arguments.length=1] > ArrowFunctionExpression[params.length=1][params.0.type="Identifier"][body.callee.name="setTimeout"][body.arguments.length=2][body.arguments.0.type="Identifier"]';
|
|
5
|
+
// The block-bodied form `new Promise(resolve => { setTimeout(resolve, ms); })` — a single
|
|
6
|
+
// statement that is the same two-argument `setTimeout`.
|
|
7
|
+
const blockExecutor = 'NewExpression[callee.name="Promise"][arguments.length=1] > ArrowFunctionExpression[params.length=1][params.0.type="Identifier"][body.type="BlockStatement"][body.body.length=1][body.body.0.type="ExpressionStatement"][body.body.0.expression.callee.name="setTimeout"][body.body.0.expression.arguments.length=2][body.body.0.expression.arguments.0.type="Identifier"]';
|
|
5
8
|
export const preferDelay = createRule({
|
|
6
9
|
name: 'prefer-delay',
|
|
7
10
|
meta: {
|
|
@@ -15,18 +18,29 @@ export const preferDelay = createRule({
|
|
|
15
18
|
},
|
|
16
19
|
},
|
|
17
20
|
create(context) {
|
|
21
|
+
// Confirm the timeout callback IS the promise's own `resolve` (a pure delay).
|
|
22
|
+
const isPureDelay = (param, timeout) => {
|
|
23
|
+
const [callback] = timeout.arguments;
|
|
24
|
+
return (param.type === 'Identifier'
|
|
25
|
+
&& callback.type === 'Identifier'
|
|
26
|
+
&& param.name === callback.name);
|
|
27
|
+
};
|
|
28
|
+
const reportPromise = (node) => context.report({ node: node.parent, messageId: 'preferDelay' });
|
|
18
29
|
return {
|
|
19
|
-
[
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
30
|
+
[expressionExecutor](node) {
|
|
31
|
+
if (node.body.type === 'CallExpression'
|
|
32
|
+
&& isPureDelay(node.params[0], node.body)) {
|
|
33
|
+
reportPromise(node);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
[blockExecutor](node) {
|
|
37
|
+
if (node.body.type !== 'BlockStatement')
|
|
24
38
|
return;
|
|
25
|
-
const [
|
|
26
|
-
if (
|
|
27
|
-
&&
|
|
28
|
-
&&
|
|
29
|
-
|
|
39
|
+
const [statement] = node.body.body;
|
|
40
|
+
if (statement.type === 'ExpressionStatement'
|
|
41
|
+
&& statement.expression.type === 'CallExpression'
|
|
42
|
+
&& isPureDelay(node.params[0], statement.expression)) {
|
|
43
|
+
reportPromise(node);
|
|
30
44
|
}
|
|
31
45
|
},
|
|
32
46
|
};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { createRule } from '../utils/create-rule.js';
|
|
2
|
-
const objectKeysLength = (
|
|
2
|
+
const objectKeysLength = (path) => `[${path}.property.name="length"][${path}.object.callee.object.name="Object"][${path}.object.callee.property.name="keys"]`;
|
|
3
3
|
// `Object.keys(obj).length === 0`, in either operand order.
|
|
4
4
|
const keysLengthZero = (zero, keys) => `BinaryExpression[operator=/^===?$/][${zero}.value=0]${objectKeysLength(keys)}`;
|
|
5
|
+
// `!Object.keys(obj).length` — a falsy length means no keys.
|
|
6
|
+
const notKeysLength = `UnaryExpression[operator="!"]${objectKeysLength('argument')}`;
|
|
5
7
|
export const preferIsEmpty = createRule({
|
|
6
8
|
name: 'prefer-is-empty',
|
|
7
9
|
meta: {
|
|
@@ -19,6 +21,7 @@ export const preferIsEmpty = createRule({
|
|
|
19
21
|
return {
|
|
20
22
|
[keysLengthZero('right', 'left')]: report,
|
|
21
23
|
[keysLengthZero('left', 'right')]: report,
|
|
24
|
+
[notKeysLength]: report,
|
|
22
25
|
};
|
|
23
26
|
},
|
|
24
27
|
});
|
|
@@ -1,22 +1,29 @@
|
|
|
1
1
|
import { createRule } from '../utils/create-rule.js';
|
|
2
2
|
const random = 'CallExpression[callee.object.name="Math"][callee.property.name="random"]';
|
|
3
|
-
// `Math.
|
|
4
|
-
const
|
|
3
|
+
// `Math.random() * X`. A `.length` multiplier is left to `prefer-sample`.
|
|
4
|
+
const product = `BinaryExpression[operator="*"]:has(> ${random}):not(:has(> MemberExpression[property.name="length"]))`;
|
|
5
|
+
// Each idiom truncates that product to an int: `Math.floor`/`Math.trunc`, `~~`, or `| 0`.
|
|
6
|
+
const truncCall = `CallExpression[callee.object.name="Math"][callee.property.name=/^(floor|trunc)$/][arguments.length=1]:has(> ${product})`;
|
|
7
|
+
const doubleTilde = `UnaryExpression[operator="~"]:has(> UnaryExpression[operator="~"]:has(> ${product}))`;
|
|
8
|
+
const bitwiseOr = `BinaryExpression[operator="|"][right.value=0]:has(> ${product})`;
|
|
5
9
|
export const preferRandomInt = createRule({
|
|
6
10
|
name: 'prefer-random-int',
|
|
7
11
|
meta: {
|
|
8
12
|
type: 'suggestion',
|
|
9
13
|
docs: {
|
|
10
|
-
description: 'Prefer `randomInt` from es-toolkit over `Math.
|
|
14
|
+
description: 'Prefer `randomInt` from es-toolkit over truncating `Math.random() * …` to an int.',
|
|
11
15
|
},
|
|
12
16
|
schema: [],
|
|
13
17
|
messages: {
|
|
14
|
-
preferRandomInt: 'Prefer `randomInt` from es-toolkit instead of `Math.
|
|
18
|
+
preferRandomInt: 'Prefer `randomInt` from es-toolkit instead of truncating `Math.random() * …` to an int.',
|
|
15
19
|
},
|
|
16
20
|
},
|
|
17
21
|
create(context) {
|
|
22
|
+
const report = (node) => context.report({ node, messageId: 'preferRandomInt' });
|
|
18
23
|
return {
|
|
19
|
-
[
|
|
24
|
+
[truncCall]: report,
|
|
25
|
+
[doubleTilde]: report,
|
|
26
|
+
[bitwiseOr]: report,
|
|
20
27
|
};
|
|
21
28
|
},
|
|
22
29
|
});
|
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
import { createRule } from '../utils/create-rule.js';
|
|
2
|
-
|
|
3
|
-
const
|
|
2
|
+
const random = 'CallExpression[callee.object.name="Math"][callee.property.name="random"]';
|
|
3
|
+
const length = 'MemberExpression[property.name="length"]';
|
|
4
|
+
// A computed access `arr[<index>]` whose index draws on `Math.random()` and an array `.length`.
|
|
5
|
+
const randomIndexAccess = (index) => `MemberExpression[computed=true]${index}:has(${random}):has(${length})`;
|
|
6
|
+
// The index truncates to an int via `Math.floor`/`Math.trunc`, `~~`, or `| 0`.
|
|
7
|
+
const truncCall = '[property.callee.object.name="Math"][property.callee.property.name=/^(floor|trunc)$/]';
|
|
8
|
+
const doubleTilde = '[property.type="UnaryExpression"][property.operator="~"][property.argument.type="UnaryExpression"][property.argument.operator="~"]';
|
|
9
|
+
const bitwiseOr = '[property.type="BinaryExpression"][property.operator="|"][property.right.value=0]';
|
|
4
10
|
export const preferSample = createRule({
|
|
5
11
|
name: 'prefer-sample',
|
|
6
12
|
meta: {
|
|
@@ -14,8 +20,11 @@ export const preferSample = createRule({
|
|
|
14
20
|
},
|
|
15
21
|
},
|
|
16
22
|
create(context) {
|
|
23
|
+
const report = (node) => context.report({ node, messageId: 'preferSample' });
|
|
17
24
|
return {
|
|
18
|
-
[
|
|
25
|
+
[randomIndexAccess(truncCall)]: report,
|
|
26
|
+
[randomIndexAccess(doubleTilde)]: report,
|
|
27
|
+
[randomIndexAccess(bitwiseOr)]: report,
|
|
19
28
|
};
|
|
20
29
|
},
|
|
21
30
|
});
|
|
@@ -4,16 +4,19 @@ Prefer [`compact`](https://es-toolkit.dev/reference/array/compact.html) from es-
|
|
|
4
4
|
over `.filter(Boolean)`.
|
|
5
5
|
|
|
6
6
|
`compact(arr)` removes all falsy values (`false`, `null`, `0`, `''`, `undefined`, `NaN`) —
|
|
7
|
-
exactly what
|
|
7
|
+
exactly what a truthiness filter does, but named and (in TypeScript) better typed.
|
|
8
8
|
|
|
9
9
|
## Rule details
|
|
10
10
|
|
|
11
|
-
This rule reports — it does **not** auto-fix — a single-argument
|
|
11
|
+
This rule reports — it does **not** auto-fix — a single-argument truthiness filter:
|
|
12
|
+
`.filter(Boolean)`, `.filter(x => !!x)`, or `.filter(x => Boolean(x))`.
|
|
12
13
|
|
|
13
14
|
### ❌ Incorrect
|
|
14
15
|
|
|
15
16
|
```js
|
|
16
17
|
arr.filter(Boolean);
|
|
18
|
+
arr.filter(x => !!x);
|
|
19
|
+
arr.filter(x => Boolean(x));
|
|
17
20
|
items.filter(Boolean).map(x => x.id);
|
|
18
21
|
```
|
|
19
22
|
|
|
@@ -26,11 +29,16 @@ compact(arr);
|
|
|
26
29
|
|
|
27
30
|
// Not a falsy filter — left untouched:
|
|
28
31
|
arr.filter(x => x);
|
|
32
|
+
arr.filter(x => !!y); // filters by a different value
|
|
33
|
+
arr.filter(x => Boolean(x.foo)); // filters by a property, not the element
|
|
29
34
|
arr.map(Boolean);
|
|
30
35
|
```
|
|
31
36
|
|
|
32
37
|
## Limitations
|
|
33
38
|
|
|
39
|
+
- **Arrow predicate is identity-checked.** `x => !!x` and `x => Boolean(x)` are reported only
|
|
40
|
+
when the negated/wrapped value is the predicate's own parameter, so `x => !!y` and
|
|
41
|
+
`x => Boolean(x.foo)` are left alone.
|
|
34
42
|
- **Syntactic match.** A shadowed local `Boolean` could produce a false positive. This is
|
|
35
43
|
rare in practice.
|
|
36
44
|
- **TypeScript bonus.** Beyond readability, `compact` narrows nullable element types, while
|
|
@@ -9,12 +9,16 @@ hand-rolled `new Promise((resolve) => setTimeout(resolve, ms))` sleep idiom.
|
|
|
9
9
|
## Rule details
|
|
10
10
|
|
|
11
11
|
This rule reports — it does **not** auto-fix — a `new Promise` whose single-parameter
|
|
12
|
-
executor immediately calls `setTimeout` with that same parameter as the callback
|
|
12
|
+
executor immediately calls `setTimeout` with that same parameter as the callback, whether the
|
|
13
|
+
executor has an expression body or a single-statement block body.
|
|
13
14
|
|
|
14
15
|
### ❌ Incorrect
|
|
15
16
|
|
|
16
17
|
```js
|
|
17
18
|
new Promise(resolve => setTimeout(resolve, 1000));
|
|
19
|
+
new Promise(resolve => {
|
|
20
|
+
setTimeout(resolve, ms);
|
|
21
|
+
});
|
|
18
22
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
19
23
|
```
|
|
20
24
|
|
|
@@ -28,15 +32,17 @@ await delay(1000);
|
|
|
28
32
|
// Not a pure delay — left untouched:
|
|
29
33
|
new Promise(resolve => setTimeout(doWork, 1000)); // runs work, not just a delay
|
|
30
34
|
new Promise(resolve => {
|
|
31
|
-
|
|
35
|
+
doWork();
|
|
36
|
+
setTimeout(resolve, ms); // does more than wait, see Limitations
|
|
32
37
|
});
|
|
33
38
|
```
|
|
34
39
|
|
|
35
40
|
## Limitations
|
|
36
41
|
|
|
37
|
-
- **
|
|
38
|
-
`new Promise((resolve) => { setTimeout(resolve, ms); })`
|
|
39
|
-
`setTimeout(() => resolve(), ms)` are not reported, to keep the rule
|
|
42
|
+
- **Single-statement executors only.** A block body that does more than the one `setTimeout`
|
|
43
|
+
(e.g. `new Promise((resolve) => { doWork(); setTimeout(resolve, ms); })`), arrow-only forms,
|
|
44
|
+
and wrapped forms like `setTimeout(() => resolve(), ms)` are not reported, to keep the rule
|
|
45
|
+
precise. Function-expression executors (`function (resolve) { … }`) are also not flagged.
|
|
40
46
|
- **Identity-checked.** The rule reports only when `setTimeout`'s callback is the promise's
|
|
41
47
|
own `resolve` parameter, so `setTimeout(doWork, ms)` inside a `new Promise` is left alone.
|
|
42
48
|
- **No auto-fix by design.** The fix requires adding an `import { delay } from 'es-toolkit'`.
|
|
@@ -8,14 +8,15 @@ allocating an intermediate keys array.
|
|
|
8
8
|
|
|
9
9
|
## Rule details
|
|
10
10
|
|
|
11
|
-
This rule reports — it does **not** auto-fix —
|
|
12
|
-
|
|
11
|
+
This rule reports — it does **not** auto-fix — a check that `Object.keys(...).length` is
|
|
12
|
+
zero: an equality comparison against `0` in either operand order, or the `!`-negated length.
|
|
13
13
|
|
|
14
14
|
### ❌ Incorrect
|
|
15
15
|
|
|
16
16
|
```js
|
|
17
17
|
Object.keys(obj).length === 0;
|
|
18
18
|
0 === Object.keys(obj).length;
|
|
19
|
+
!Object.keys(obj).length;
|
|
19
20
|
```
|
|
20
21
|
|
|
21
22
|
### ✅ Correct
|
|
@@ -8,14 +8,17 @@ formula; `randomInt` names the intent and removes the off-by-one foot-guns.
|
|
|
8
8
|
|
|
9
9
|
## Rule details
|
|
10
10
|
|
|
11
|
-
This rule reports — it does **not** auto-fix — `Math.
|
|
12
|
-
|
|
13
|
-
[`prefer-sample`](./prefer-sample.md) instead.
|
|
11
|
+
This rule reports — it does **not** auto-fix — a `Math.random() * …` product truncated to an
|
|
12
|
+
integer, whether by `Math.floor(...)`, `Math.trunc(...)`, `~~(...)`, or `… | 0`. A `.length`
|
|
13
|
+
multiplier is left to [`prefer-sample`](./prefer-sample.md) instead.
|
|
14
14
|
|
|
15
15
|
### ❌ Incorrect
|
|
16
16
|
|
|
17
17
|
```js
|
|
18
18
|
Math.floor(Math.random() * 6);
|
|
19
|
+
Math.trunc(Math.random() * 6);
|
|
20
|
+
~~(Math.random() * 6);
|
|
21
|
+
(Math.random() * 6) | 0;
|
|
19
22
|
Math.floor(Math.random() * (max - min + 1)) + min;
|
|
20
23
|
```
|
|
21
24
|
|
|
@@ -28,7 +31,8 @@ randomInt(0, 6);
|
|
|
28
31
|
|
|
29
32
|
// Not this rule's concern — left untouched:
|
|
30
33
|
Math.random(); // a float in [0, 1)
|
|
31
|
-
Math.round(Math.random() * n); // rounds, not
|
|
34
|
+
Math.round(Math.random() * n); // rounds, not truncates
|
|
35
|
+
Math.ceil(Math.random() * n); // changes the bounds
|
|
32
36
|
arr[Math.floor(Math.random() * arr.length)]; // see prefer-sample
|
|
33
37
|
```
|
|
34
38
|
|
|
@@ -37,7 +41,8 @@ arr[Math.floor(Math.random() * arr.length)]; // see prefer-sample
|
|
|
37
41
|
- **Bounds differ.** The inclusive idiom `Math.floor(Math.random() * (max - min + 1)) + min`
|
|
38
42
|
yields `[min, max]`, whereas `randomInt(min, max)` yields `[min, max)`. Adjust the upper
|
|
39
43
|
bound when rewriting.
|
|
40
|
-
-
|
|
41
|
-
|
|
44
|
+
- **Truncation only.** `Math.floor`, `Math.trunc`, `~~`, and `| 0` are reported (all truncate
|
|
45
|
+
toward zero for the non-negative `Math.random() * n` range). `Math.round(...)` and
|
|
46
|
+
`Math.ceil(...)` are **not** — they change the distribution or bounds.
|
|
42
47
|
- **Syntactic match.** A shadowed local `Math` could produce a false positive.
|
|
43
48
|
- **No auto-fix by design.** The fix requires adding an `import { randomInt } from 'es-toolkit'`.
|
|
@@ -8,13 +8,17 @@ out the same idea by hand and repeats the array.
|
|
|
8
8
|
|
|
9
9
|
## Rule details
|
|
10
10
|
|
|
11
|
-
This rule reports — it does **not** auto-fix — a computed access whose index
|
|
12
|
-
`Math.
|
|
11
|
+
This rule reports — it does **not** auto-fix — a computed access whose index truncates
|
|
12
|
+
`Math.random() * …length` to an integer, whether by `Math.floor`/`Math.trunc`, `~~`, or
|
|
13
|
+
`… | 0`.
|
|
13
14
|
|
|
14
15
|
### ❌ Incorrect
|
|
15
16
|
|
|
16
17
|
```js
|
|
17
18
|
arr[Math.floor(Math.random() * arr.length)];
|
|
19
|
+
arr[Math.trunc(Math.random() * arr.length)];
|
|
20
|
+
arr[~~(Math.random() * arr.length)];
|
|
21
|
+
arr[(Math.random() * arr.length) | 0];
|
|
18
22
|
items[Math.floor(Math.random() * items.length)];
|
|
19
23
|
```
|
|
20
24
|
|
|
@@ -35,5 +39,7 @@ arr[i];
|
|
|
35
39
|
- **Object identity is not checked.** The selector matches `a[Math.floor(Math.random() *
|
|
36
40
|
b.length)]`, so the rare case where the indexed array and the `.length` array differ would
|
|
37
41
|
also be reported.
|
|
42
|
+
- **Truncation only.** The index must truncate toward zero (`Math.floor`, `Math.trunc`, `~~`,
|
|
43
|
+
or `| 0`); `Math.round`/`Math.ceil` indices are not reported.
|
|
38
44
|
- **Syntactic match.** A shadowed local `Math` could produce a false positive.
|
|
39
45
|
- **No auto-fix by design.** The fix requires adding an `import { sample } from 'es-toolkit'`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "es-toolkit-eslint-plugin",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "ESLint plugin that suggests es-toolkit utilities in place of verbose JS/TS",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -32,20 +32,18 @@
|
|
|
32
32
|
"url": "https://github.com/syxov/es-toolkit-eslint-plugin/issues"
|
|
33
33
|
},
|
|
34
34
|
"homepage": "https://github.com/syxov/es-toolkit-eslint-plugin#readme",
|
|
35
|
-
"dependencies": {
|
|
36
|
-
"@typescript-eslint/utils": "^8.61.1"
|
|
37
|
-
},
|
|
38
35
|
"peerDependencies": {
|
|
36
|
+
"@typescript-eslint/utils": "^8.61.1",
|
|
39
37
|
"eslint": ">=10"
|
|
40
38
|
},
|
|
41
39
|
"devDependencies": {
|
|
42
|
-
"@types/node": "^
|
|
43
|
-
"@typescript-eslint/parser": "^8.
|
|
44
|
-
"@typescript-eslint/rule-tester": "^8.
|
|
45
|
-
"eslint": "^10.
|
|
40
|
+
"@types/node": "^26.0.0",
|
|
41
|
+
"@typescript-eslint/parser": "^8.61.1",
|
|
42
|
+
"@typescript-eslint/rule-tester": "^8.61.1",
|
|
43
|
+
"eslint": "^10.5.0",
|
|
46
44
|
"prettier": "^3.8.4",
|
|
47
45
|
"typescript": "^6.0.3",
|
|
48
|
-
"vitest": "^
|
|
46
|
+
"vitest": "^4.1.9"
|
|
49
47
|
},
|
|
50
48
|
"scripts": {
|
|
51
49
|
"build": "tsc",
|