@blumintinc/eslint-plugin-blumint 0.1.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 +60 -0
- package/docs/rules/array-methods-this-context.md +26 -0
- package/docs/rules/generic-starts-with-t.md +31 -0
- package/docs/rules/no-async-array-filter.md +30 -0
- package/docs/rules/no-filter-without-return.md +41 -0
- package/docs/rules/no-unpinned-dependencies.md +32 -0
- package/docs/rules/prefer-fragment-shorthand.md +23 -0
- package/docs/rules/prefer-type-over-interface.md +21 -0
- package/lib/index.js +28 -0
- package/lib/rules/array-methods-this-context.js +58 -0
- package/lib/rules/generic-starts-with-t.js +35 -0
- package/lib/rules/no-async-array-filter.js +41 -0
- package/lib/rules/no-filter-without-return.js +78 -0
- package/lib/rules/no-unpinned-dependencies.js +62 -0
- package/lib/rules/prefer-fragment-shorthand.js +41 -0
- package/lib/rules/prefer-type-over-interface.js +30 -0
- package/lib/utils/createRule.js +7 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# eslint-plugin-blumint
|
|
2
|
+
|
|
3
|
+
Custom eslint rules for use at BluMint
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
You'll first need to install [ESLint](https://eslint.org/):
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm i eslint --save-dev
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Next, install `eslint-plugin-blumint`:
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
npm install eslint-plugin-blumint --save-dev
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Add `blumint` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"plugins": [
|
|
26
|
+
"blumint"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
Then configure the rules you want to use under the rules section.
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"rules": {
|
|
37
|
+
"blumint/rule-name": "error"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Rules
|
|
43
|
+
|
|
44
|
+
<!-- begin auto-generated rules list -->
|
|
45
|
+
|
|
46
|
+
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).
|
|
47
|
+
|
|
48
|
+
| Name                      | Description | 🔧 |
|
|
49
|
+
| :--------------------------------------------------------------------- | :---------------------------------------------------------------------------------------- | :- |
|
|
50
|
+
| [array-methods-this-context](docs/rules/array-methods-this-context.md) | Disallow async callbacks for Array.filter | 🔧 |
|
|
51
|
+
| [generic-starts-with-t](docs/rules/generic-starts-with-t.md) | Enforce TypeScript generic types to start with T | 🔧 |
|
|
52
|
+
| [no-async-array-filter](docs/rules/no-async-array-filter.md) | Disallow async callbacks for Array.filter | 🔧 |
|
|
53
|
+
| [no-filter-without-return](docs/rules/no-filter-without-return.md) | Disallow Array.filter callbacks without an explicit return (if part of a block statement) | 🔧 |
|
|
54
|
+
| [no-unpinned-dependencies](docs/rules/no-unpinned-dependencies.md) | Enforces pinned dependencies | 🔧 |
|
|
55
|
+
| [prefer-fragment-shorthand](docs/rules/prefer-fragment-shorthand.md) | Prefer <> shorthand for <React.Fragment> | 🔧 |
|
|
56
|
+
| [prefer-type-over-interface](docs/rules/prefer-type-over-interface.md) | Prefer using type alias over interface | 🔧 |
|
|
57
|
+
|
|
58
|
+
<!-- end auto-generated rules list -->
|
|
59
|
+
|
|
60
|
+
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Disallow 'this' context in array methods (`blumint/array-methods-this-context`)
|
|
2
|
+
|
|
3
|
+
This rule disallows the direct use of class methods in Array methods like 'map', 'filter', 'forEach', 'reduce', 'some', 'every'. Instead, arrow functions should be used to preserve the 'this' context.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
This rule enforces that no class methods are directly used in Array methods. It also prefers the use of arrow functions over `bind(this)`
|
|
8
|
+
|
|
9
|
+
### Examples of incorrect code for this rule:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
['a', 'b', 'c'].map(this.processItem)
|
|
13
|
+
['a', 'b', 'c'].map(this.processItem, otherArgument)
|
|
14
|
+
['a', 'b', 'c'].filter(this.checkItem)
|
|
15
|
+
['a', 'b', 'c'].forEach(this.printItem)
|
|
16
|
+
['a', 'b', 'c'].some(this.testItem)
|
|
17
|
+
['a', 'b', 'c'].every(this.validateItem)
|
|
18
|
+
['a', 'b', 'c'].reduce(this.combineItems)
|
|
19
|
+
['a', 'b', 'c'].map(function(item) { return this.processItem(item) }.bind(this))
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Examples of correct code for this rule:
|
|
23
|
+
```typescript
|
|
24
|
+
['a', 'b', 'c'].map((item) => this.processItem(item))
|
|
25
|
+
['a', 'b', 'c'].map(processItem)
|
|
26
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Enforce TypeScript generic types to start with T (`blumint/generic-starts-with-t`)
|
|
2
|
+
|
|
3
|
+
<!-- end auto-generated rule header -->
|
|
4
|
+
|
|
5
|
+
This rule enforces that all TypeScript generic types start with the letter "T".
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
Generics are a way of creating reusable code components that work with a variety of types as opposed to a single one. By convention, generic type parameters often start with the letter "T". This makes it easier to recognize them as generic types and not regular variables or types.
|
|
10
|
+
|
|
11
|
+
This rule enforces that all TypeScript generic types start with the letter "T".
|
|
12
|
+
|
|
13
|
+
Examples of **incorrect** code for this rule:
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
type GenericType<Param> = Param[];
|
|
17
|
+
type GenericType<TParam, Param> = [TParam, Param];
|
|
18
|
+
type GenericType<P> = P[];
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Examples of **correct** code for this rule:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
type GenericType<TParam> = TParam[];
|
|
25
|
+
type GenericType<TParam1, TParam2> = [TParam1, TParam2];
|
|
26
|
+
type GenericType<T> = T[];
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## When Not To Use It
|
|
30
|
+
If you have a different convention for naming generic types in your codebase, you may want to disable this rule.
|
|
31
|
+
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Disallow async callbacks for Array.filter (`blumint/no-async-array-filter`)
|
|
2
|
+
|
|
3
|
+
<!-- end auto-generated rule header -->
|
|
4
|
+
|
|
5
|
+
Async callbacks in array filters are dangerous and not picked up by the standard eslint rules.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
This rule prevents the use of async callbacks in Array.filter. These will return a Promise object, which is truthy, thus rendering the filter function useless.
|
|
10
|
+
|
|
11
|
+
Examples of **incorrect** code for this rule:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
|
|
15
|
+
['a'].filter(async (x) => true)
|
|
16
|
+
['a'].filter(async function(x) {
|
|
17
|
+
return true
|
|
18
|
+
})
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Examples of **correct** code for this rule:
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
|
|
25
|
+
['a'].filter((x) => true)
|
|
26
|
+
['a'].filter(function (x) {
|
|
27
|
+
return true
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Disallow Array.filter callbacks without an explicit return (if part of a block statement) (`blumint/no-filter-without-return`)
|
|
2
|
+
|
|
3
|
+
<!-- end auto-generated rule header -->
|
|
4
|
+
|
|
5
|
+
This rule disallows the use of `Array.filter` callbacks that are part of a block statement but do not contain an explicit return statement. When using `Array.filter`, it's common to return a boolean value directly from a concise arrow function. However, if you're using a block statement (enclosed in `{}`), an explicit `return` statement is required.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
This rule is aimed at ensuring that there is an explicit return statement in `Array.filter` callbacks that are part of a block statement.
|
|
10
|
+
|
|
11
|
+
Examples of **incorrect** code for this rule:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
['a'].filter((x) => {console.log(x)})
|
|
15
|
+
['a'].filter((x) => {if (x) {
|
|
16
|
+
return true
|
|
17
|
+
}
|
|
18
|
+
else {}
|
|
19
|
+
}
|
|
20
|
+
)
|
|
21
|
+
['a'].filter((x) => { if (x !== 'a') { console.log(x) } else { return true } })
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Examples of **correct** code for this rule:
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
['a'].filter((x) => !x)
|
|
28
|
+
['a'].filter((x) => !!x)
|
|
29
|
+
['a'].filter((x) => {
|
|
30
|
+
if (x === 'test') {
|
|
31
|
+
return true
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
return false
|
|
35
|
+
}
|
|
36
|
+
})
|
|
37
|
+
['a'].filter(function (x) {
|
|
38
|
+
return true
|
|
39
|
+
})
|
|
40
|
+
['a'].filter((x) => x === 'a' ? true : false)
|
|
41
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Enforces pinned dependencies (`blumint/no-unpinned-dependencies`)
|
|
2
|
+
|
|
3
|
+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
Unpinned dependencies can cause problems, including hard to diagnose breaking changes.
|
|
8
|
+
|
|
9
|
+
## Rule Details
|
|
10
|
+
|
|
11
|
+
This rule aims to prevent the use of unpinned dependencies.
|
|
12
|
+
|
|
13
|
+
Examples of **incorrect** code for this rule:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
|
|
17
|
+
{dependencies: {eslint: "^8.19.0"}}
|
|
18
|
+
{dependencies: {eslint: "~8.19.0"}}
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Examples of **correct** code for this rule:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
|
|
26
|
+
{dependencies: {eslint: "8.19.0"}}
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## When Not To Use It
|
|
31
|
+
|
|
32
|
+
If pinned dependencies are ok in your codebase.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Prefer <> shorthand for <React.Fragment> (`blumint/prefer-fragment-shorthand`)
|
|
2
|
+
|
|
3
|
+
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
4
|
+
|
|
5
|
+
<!-- end auto-generated rule header -->
|
|
6
|
+
|
|
7
|
+
This rule prefers the use of fragment shorthand, `<>` over `<React.Fragment>`
|
|
8
|
+
|
|
9
|
+
## Rule Details
|
|
10
|
+
|
|
11
|
+
Examples of **incorrect** code for this rule:
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
<React.Fragment>Hello World</React.Fragment>
|
|
15
|
+
<React.Fragment><ChildComponent /></React.Fragment>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Examples of **correct** code for this rule:
|
|
19
|
+
|
|
20
|
+
```jsx
|
|
21
|
+
<>Hello World</>
|
|
22
|
+
<><ChildComponent /></>
|
|
23
|
+
```
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Prefer using type alias over interface (`blumint/prefer-type-over-interface`)
|
|
2
|
+
|
|
3
|
+
<!-- end auto-generated rule header -->
|
|
4
|
+
|
|
5
|
+
This rule prefers the use of `Type` over `Interface` in Typescript.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
interface SomeInterface { field: string; };
|
|
13
|
+
interface AnotherInterface extends SomeInterface { otherField: number; };
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Examples of **correct** code for this rule:
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
type SomeType = { field: string; };
|
|
20
|
+
type AnotherType = SomeType & { otherField: number; };
|
|
21
|
+
```
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const array_methods_this_context_1 = require("./rules/array-methods-this-context");
|
|
4
|
+
const generic_starts_with_t_1 = require("./rules/generic-starts-with-t");
|
|
5
|
+
const no_async_array_filter_1 = require("./rules/no-async-array-filter");
|
|
6
|
+
const no_filter_without_return_1 = require("./rules/no-filter-without-return");
|
|
7
|
+
const no_unpinned_dependencies_1 = require("./rules/no-unpinned-dependencies");
|
|
8
|
+
const prefer_fragment_shorthand_1 = require("./rules/prefer-fragment-shorthand");
|
|
9
|
+
const prefer_type_over_interface_1 = require("./rules/prefer-type-over-interface");
|
|
10
|
+
module.exports = {
|
|
11
|
+
meta: {
|
|
12
|
+
name: 'eslint-plugin-blumint',
|
|
13
|
+
version: '0.0.1',
|
|
14
|
+
},
|
|
15
|
+
parseOptions: {
|
|
16
|
+
ecmaVersion: 2020,
|
|
17
|
+
},
|
|
18
|
+
rules: {
|
|
19
|
+
'array-methods-this-context': array_methods_this_context_1.arrayMethodsThisContext,
|
|
20
|
+
'generic-starts-with-t': generic_starts_with_t_1.genericStartsWithT,
|
|
21
|
+
'no-async-array-filter': no_async_array_filter_1.noAsyncArrayFilter,
|
|
22
|
+
'no-filter-without-return': no_filter_without_return_1.noFilterWithoutReturn,
|
|
23
|
+
'no-unpinned-dependencies': no_unpinned_dependencies_1.noUnpinnedDependencies,
|
|
24
|
+
'prefer-fragment-shorthand': prefer_fragment_shorthand_1.preferFragmentShorthand,
|
|
25
|
+
'prefer-type-over-interface': prefer_type_over_interface_1.preferTypeOverInterface,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.arrayMethodsThisContext = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
const arrayMethods = ['map', 'filter', 'forEach', 'reduce', 'some', 'every'];
|
|
6
|
+
const arrayMethodsThisContext = (0, createRule_1.createRule)({
|
|
7
|
+
create(context) {
|
|
8
|
+
return {
|
|
9
|
+
CallExpression(node) {
|
|
10
|
+
// Array method called with a class method reference
|
|
11
|
+
if (node.callee.type === 'MemberExpression' &&
|
|
12
|
+
node.callee.property.type === 'Identifier' &&
|
|
13
|
+
arrayMethods.includes(node.callee.property.name) &&
|
|
14
|
+
node.arguments.length > 0 &&
|
|
15
|
+
node.arguments[0].type === 'MemberExpression' &&
|
|
16
|
+
node.arguments[0].object.type === 'ThisExpression') {
|
|
17
|
+
context.report({
|
|
18
|
+
node: node.arguments[0],
|
|
19
|
+
messageId: 'unexpected'
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
// Function expression bound to `this` in array method
|
|
23
|
+
else if (node.callee.type === 'MemberExpression' &&
|
|
24
|
+
node.callee.property.type === 'Identifier' &&
|
|
25
|
+
arrayMethods.includes(node.callee.property.name) &&
|
|
26
|
+
node.arguments.length > 0 &&
|
|
27
|
+
node.arguments[0].type === 'CallExpression' &&
|
|
28
|
+
node.arguments[0].callee.type === 'MemberExpression' &&
|
|
29
|
+
node.arguments[0].callee.object.type === 'FunctionExpression' &&
|
|
30
|
+
node.arguments[0].callee.property.type === 'Identifier' &&
|
|
31
|
+
node.arguments[0].callee.property.name === 'bind' &&
|
|
32
|
+
node.arguments[0].arguments.length > 0 &&
|
|
33
|
+
node.arguments[0].arguments[0].type === 'ThisExpression') {
|
|
34
|
+
context.report({
|
|
35
|
+
node: node.arguments[0],
|
|
36
|
+
messageId: 'preferArrow'
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
name: 'array-methods-this-context',
|
|
43
|
+
meta: {
|
|
44
|
+
type: 'problem',
|
|
45
|
+
docs: {
|
|
46
|
+
description: 'Disallow async callbacks for Array.filter',
|
|
47
|
+
recommended: 'error',
|
|
48
|
+
},
|
|
49
|
+
schema: [],
|
|
50
|
+
messages: {
|
|
51
|
+
unexpected: 'Use an arrow function to preserve "this" context.',
|
|
52
|
+
preferArrow: 'Use an arrow function instead of binding this.'
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
defaultOptions: [],
|
|
56
|
+
});
|
|
57
|
+
exports.arrayMethodsThisContext = arrayMethodsThisContext;
|
|
58
|
+
//# sourceMappingURL=array-methods-this-context.js.map
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.genericStartsWithT = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
const genericStartsWithT = (0, createRule_1.createRule)({
|
|
6
|
+
create(context) {
|
|
7
|
+
return {
|
|
8
|
+
TSTypeParameterDeclaration(node) {
|
|
9
|
+
for (const param of node.params) {
|
|
10
|
+
if (typeof param.name.name === 'string' && param.name.name[0] !== 'T') {
|
|
11
|
+
context.report({
|
|
12
|
+
node: param,
|
|
13
|
+
messageId: 'genericStartsWithT',
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
name: 'generic-starts-with-t',
|
|
21
|
+
meta: {
|
|
22
|
+
type: 'suggestion',
|
|
23
|
+
docs: {
|
|
24
|
+
description: 'Enforce TypeScript generic types to start with T',
|
|
25
|
+
recommended: 'error',
|
|
26
|
+
},
|
|
27
|
+
schema: [],
|
|
28
|
+
messages: {
|
|
29
|
+
genericStartsWithT: 'Generic type parameter should start with T.',
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
defaultOptions: [],
|
|
33
|
+
});
|
|
34
|
+
exports.genericStartsWithT = genericStartsWithT;
|
|
35
|
+
//# sourceMappingURL=generic-starts-with-t.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noAsyncArrayFilter = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
const noAsyncArrayFilter = (0, createRule_1.createRule)({
|
|
6
|
+
create(context) {
|
|
7
|
+
return {
|
|
8
|
+
CallExpression(node) {
|
|
9
|
+
if (node.callee.type === 'MemberExpression' &&
|
|
10
|
+
node.callee.property.type === 'Identifier' &&
|
|
11
|
+
node.callee.property.name === 'filter' &&
|
|
12
|
+
node.arguments.length > 0) {
|
|
13
|
+
const callback = node.arguments[0];
|
|
14
|
+
if ((callback.type === 'FunctionExpression' ||
|
|
15
|
+
callback.type === 'ArrowFunctionExpression') &&
|
|
16
|
+
callback.async === true) {
|
|
17
|
+
context.report({
|
|
18
|
+
node: callback,
|
|
19
|
+
messageId: 'unexpected',
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
name: 'no-async-array-filter',
|
|
27
|
+
meta: {
|
|
28
|
+
type: 'problem',
|
|
29
|
+
docs: {
|
|
30
|
+
description: 'Disallow async callbacks for Array.filter',
|
|
31
|
+
recommended: 'error',
|
|
32
|
+
},
|
|
33
|
+
schema: [],
|
|
34
|
+
messages: {
|
|
35
|
+
unexpected: 'Async array filter is dangerous as a Promise object will always be truthy. You should move the asynchronous logic elsewhere.',
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
defaultOptions: [],
|
|
39
|
+
});
|
|
40
|
+
exports.noAsyncArrayFilter = noAsyncArrayFilter;
|
|
41
|
+
//# sourceMappingURL=no-async-array-filter.js.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noFilterWithoutReturn = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
const noFilterWithoutReturn = (0, createRule_1.createRule)({
|
|
6
|
+
create(context) {
|
|
7
|
+
function isNode(value) {
|
|
8
|
+
return typeof value === 'object'
|
|
9
|
+
&& value !== null
|
|
10
|
+
&& 'type' in value;
|
|
11
|
+
}
|
|
12
|
+
function hasReturnStatement(node) {
|
|
13
|
+
if (node.type === 'ReturnStatement') {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
else if (node.type === 'IfStatement') {
|
|
17
|
+
// Check both branches of the if statement
|
|
18
|
+
const consequentHasReturn = hasReturnStatement(node.consequent);
|
|
19
|
+
const alternateHasReturn = !!node.alternate && hasReturnStatement(node.alternate);
|
|
20
|
+
return consequentHasReturn && alternateHasReturn;
|
|
21
|
+
}
|
|
22
|
+
else if (node.type === 'BlockStatement') {
|
|
23
|
+
// Check all statements in the block
|
|
24
|
+
for (const statement of node.body) {
|
|
25
|
+
if (hasReturnStatement(statement)) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
for (const key in node) {
|
|
31
|
+
if (key === 'parent') {
|
|
32
|
+
continue; // Ignore the parent property
|
|
33
|
+
}
|
|
34
|
+
const value = node[key];
|
|
35
|
+
if (isNode(value)) {
|
|
36
|
+
if (hasReturnStatement(value)) {
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
return {
|
|
44
|
+
'CallExpression[callee.property.name="filter"]'(node) {
|
|
45
|
+
const callback = node.arguments[0];
|
|
46
|
+
if (callback && callback.type === 'ArrowFunctionExpression') {
|
|
47
|
+
const { body } = callback;
|
|
48
|
+
if (body.type !== 'BlockStatement') {
|
|
49
|
+
// If the body is not a block statement, it's a direct return
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// Check if there's a ReturnStatement inside
|
|
53
|
+
if (!hasReturnStatement(body)) {
|
|
54
|
+
context.report({
|
|
55
|
+
node,
|
|
56
|
+
messageId: 'unexpected',
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
},
|
|
63
|
+
name: 'no-filter-without-return',
|
|
64
|
+
meta: {
|
|
65
|
+
type: 'problem',
|
|
66
|
+
docs: {
|
|
67
|
+
description: 'Disallow Array.filter callbacks without an explicit return (if part of a block statement)',
|
|
68
|
+
recommended: 'error',
|
|
69
|
+
},
|
|
70
|
+
schema: [],
|
|
71
|
+
messages: {
|
|
72
|
+
unexpected: 'An array filter callback with a block statement must contain a return statement',
|
|
73
|
+
},
|
|
74
|
+
},
|
|
75
|
+
defaultOptions: [],
|
|
76
|
+
});
|
|
77
|
+
exports.noFilterWithoutReturn = noFilterWithoutReturn;
|
|
78
|
+
//# sourceMappingURL=no-filter-without-return.js.map
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noUnpinnedDependencies = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.noUnpinnedDependencies = (0, createRule_1.createRule)({
|
|
6
|
+
meta: {
|
|
7
|
+
type: 'problem',
|
|
8
|
+
docs: {
|
|
9
|
+
description: 'Enforces pinned dependencies',
|
|
10
|
+
recommended: 'error',
|
|
11
|
+
},
|
|
12
|
+
fixable: 'code',
|
|
13
|
+
schema: [],
|
|
14
|
+
messages: {
|
|
15
|
+
unexpected: "Dependency '{{ propertyName }}' should be pinned to a specific version, but '{{ version }}' was found.",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
name: 'no-unpinned-dependencies',
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
JSONLiteral(node) {
|
|
23
|
+
const property = node?.parent;
|
|
24
|
+
const configSection = node?.parent?.parent?.parent;
|
|
25
|
+
if (!property || !configSection) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const configKey = configSection?.key;
|
|
29
|
+
if (!configKey) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Check if we're in the "dependencies" or "devDependencies" section of package.json
|
|
33
|
+
if (node.type === 'JSONLiteral' &&
|
|
34
|
+
property?.type === 'JSONProperty' &&
|
|
35
|
+
(configKey.name === 'devDependencies' || configKey.value === 'devDependencies' ||
|
|
36
|
+
configKey.name === 'dependencies' || configKey.value === 'dependencies')) {
|
|
37
|
+
// Get the version string
|
|
38
|
+
const version = node.value;
|
|
39
|
+
const propertyName = property.key.name ||
|
|
40
|
+
property.key.value;
|
|
41
|
+
// Check if the version string starts with a caret (^) or tilde (~), indicating a non-pinned version
|
|
42
|
+
if (typeof version === 'string' &&
|
|
43
|
+
(version.includes('^') || version.includes('~'))) {
|
|
44
|
+
context.report({
|
|
45
|
+
node: node,
|
|
46
|
+
messageId: 'unexpected',
|
|
47
|
+
data: {
|
|
48
|
+
propertyName,
|
|
49
|
+
version,
|
|
50
|
+
},
|
|
51
|
+
fix: function (fixer) {
|
|
52
|
+
const fixed = version.replace('^', '').replace('~', '');
|
|
53
|
+
return fixer.replaceTextRange(node.range, `"${fixed}"`);
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=no-unpinned-dependencies.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preferFragmentShorthand = void 0;
|
|
4
|
+
const preferFragmentShorthand = {
|
|
5
|
+
create(context) {
|
|
6
|
+
return {
|
|
7
|
+
JSXElement(node) {
|
|
8
|
+
const openingElement = node.openingElement;
|
|
9
|
+
if (openingElement.name.type === 'JSXMemberExpression' &&
|
|
10
|
+
openingElement.name.object.type === 'JSXIdentifier' &&
|
|
11
|
+
openingElement.name.object.name === 'React' &&
|
|
12
|
+
openingElement.name.property.type === 'JSXIdentifier' &&
|
|
13
|
+
openingElement.name.property.name === 'Fragment') {
|
|
14
|
+
context.report({
|
|
15
|
+
node,
|
|
16
|
+
messageId: 'preferShorthand',
|
|
17
|
+
fix: (fixer) => [
|
|
18
|
+
fixer.replaceTextRange(openingElement.range, '<>'),
|
|
19
|
+
fixer.replaceTextRange(node.closingElement.range, '</>'),
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
meta: {
|
|
27
|
+
type: 'suggestion',
|
|
28
|
+
docs: {
|
|
29
|
+
description: 'Prefer <> shorthand for <React.Fragment>',
|
|
30
|
+
recommended: 'warn',
|
|
31
|
+
},
|
|
32
|
+
messages: {
|
|
33
|
+
preferShorthand: 'Use <> shorthand for <React.Fragment>',
|
|
34
|
+
},
|
|
35
|
+
schema: [],
|
|
36
|
+
fixable: 'code',
|
|
37
|
+
},
|
|
38
|
+
defaultOptions: [],
|
|
39
|
+
};
|
|
40
|
+
exports.preferFragmentShorthand = preferFragmentShorthand;
|
|
41
|
+
//# sourceMappingURL=prefer-fragment-shorthand.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preferTypeOverInterface = void 0;
|
|
4
|
+
const createRule_1 = require("../utils/createRule");
|
|
5
|
+
exports.preferTypeOverInterface = (0, createRule_1.createRule)({
|
|
6
|
+
name: 'prefer-type-over-interface',
|
|
7
|
+
meta: {
|
|
8
|
+
type: 'suggestion',
|
|
9
|
+
docs: {
|
|
10
|
+
description: 'Prefer using type alias over interface',
|
|
11
|
+
recommended: 'warn',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
messages: {
|
|
15
|
+
preferType: 'Prefer using type alias over interface.',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultOptions: [],
|
|
19
|
+
create(context) {
|
|
20
|
+
return {
|
|
21
|
+
TSInterfaceDeclaration(node) {
|
|
22
|
+
context.report({
|
|
23
|
+
node,
|
|
24
|
+
messageId: 'preferType',
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
//# sourceMappingURL=prefer-type-over-interface.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRule = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule = utils_1.ESLintUtils.RuleCreator((name) => `https://github.com/BluMintInc/custom-eslint-rules/plugin/docs/rules/${name}.md`);
|
|
6
|
+
exports.createRule = createRule;
|
|
7
|
+
//# sourceMappingURL=createRule.js.map
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blumintinc/eslint-plugin-blumint",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Custom eslint rules for use at BluMint",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"eslint",
|
|
7
|
+
"eslintplugin",
|
|
8
|
+
"eslint-plugin"
|
|
9
|
+
],
|
|
10
|
+
"author": "Brodie McGuire",
|
|
11
|
+
"main": "./lib/index.js",
|
|
12
|
+
"exports": "./lib/index.js",
|
|
13
|
+
"scripts": {
|
|
14
|
+
"lint": "npm-run-all \"lint:*\"",
|
|
15
|
+
"lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"",
|
|
16
|
+
"lint:js": "eslint .",
|
|
17
|
+
"test": "jest",
|
|
18
|
+
"update:eslint-docs": "eslint-doc-generator"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"requireindex": "1.2.0"
|
|
22
|
+
},
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/eslint": "^8.37.0",
|
|
25
|
+
"@typescript-eslint/utils": "5.59.6",
|
|
26
|
+
"eslint": "8.19.0",
|
|
27
|
+
"eslint-doc-generator": "1.0.0",
|
|
28
|
+
"eslint-import-resolver-typescript": "^3.5.5",
|
|
29
|
+
"eslint-plugin-eslint-plugin": "^5.0.0",
|
|
30
|
+
"eslint-plugin-node": "11.1.0",
|
|
31
|
+
"jest": "29.3.1",
|
|
32
|
+
"jsonc-eslint-parser": "2.3.0",
|
|
33
|
+
"npm-run-all": "4.1.5",
|
|
34
|
+
"ts-jest": "^29.0.5"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": "16.0.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"eslint": ">=7"
|
|
41
|
+
},
|
|
42
|
+
"license": "ISC"
|
|
43
|
+
}
|