@blumintinc/eslint-plugin-blumint 0.1.24 → 1.0.3
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/lib/index.d.ts +1 -0
- package/lib/index.js +1 -1
- package/lib/rules/array-methods-this-context.d.ts +3 -0
- package/lib/rules/class-methods-read-top-to-bottom.d.ts +2 -0
- package/lib/rules/dynamic-https-errors.d.ts +2 -0
- package/lib/rules/export-if-in-doubt.d.ts +2 -0
- package/lib/rules/extract-global-constants.d.ts +2 -0
- package/lib/rules/generic-starts-with-t.d.ts +2 -0
- package/lib/rules/no-async-array-filter.d.ts +2 -0
- package/lib/rules/no-async-foreach.d.ts +2 -0
- package/lib/rules/no-conditional-literals-in-jsx.d.ts +2 -0
- package/lib/rules/no-filter-without-return.d.ts +2 -0
- package/lib/rules/no-misused-switch-case.d.ts +2 -0
- package/lib/rules/no-unpinned-dependencies.d.ts +2 -0
- package/lib/rules/no-useless-fragment.d.ts +2 -0
- package/lib/rules/prefer-fragment-shorthand.d.ts +3 -0
- package/lib/rules/prefer-type-over-interface.d.ts +2 -0
- package/lib/rules/require-memo.d.ts +6 -0
- package/lib/rules/require-memo.js +39 -7
- package/lib/utils/ASTHelpers.d.ts +12 -0
- package/lib/utils/createRule.d.ts +2 -0
- package/lib/utils/graph/ClassGraphBuilder.d.ts +29 -0
- package/lib/utils/graph/ClassGraphSorter.d.ts +7 -0
- package/lib/utils/graph/ClassGraphSorterReadability.d.ts +16 -0
- package/lib/utils/ruleTester.d.ts +5 -0
- package/package.json +81 -12
- package/docs/rules/array-methods-this-context.md +0 -30
- package/docs/rules/class-methods-read-top-to-bottom.md +0 -46
- package/docs/rules/dynamic-https-errors.md +0 -23
- package/docs/rules/export-if-in-doubt.md +0 -26
- package/docs/rules/extract-global-constants.md +0 -33
- package/docs/rules/generic-starts-with-t.md +0 -33
- package/docs/rules/no-async-array-filter.md +0 -32
- package/docs/rules/no-async-foreach.md +0 -41
- package/docs/rules/no-conditional-literals-in-jsx.md +0 -27
- package/docs/rules/no-filter-without-return.md +0 -43
- package/docs/rules/no-misused-switch-case.md +0 -38
- package/docs/rules/no-unpinned-dependencies.md +0 -34
- package/docs/rules/no-useless-fragment.md +0 -25
- package/docs/rules/prefer-fragment-shorthand.md +0 -25
- package/docs/rules/prefer-type-over-interface.md +0 -25
- package/docs/rules/require-memo.md +0 -33
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/index.js
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { TSESLint, TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export type NodeWithParent = TSESTree.Node & {
|
|
3
|
+
parent: NodeWithParent;
|
|
4
|
+
};
|
|
5
|
+
export type ComponentNode = TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | TSESTree.FunctionDeclaration;
|
|
6
|
+
export declare const requireMemo: TSESLint.RuleModule<'requireMemo', []>;
|
|
@@ -41,6 +41,10 @@ const isUnmemoizedExportedFunctionComponent = (parentNode, node) => {
|
|
|
41
41
|
node.id &&
|
|
42
42
|
!isComponentExplicitlyUnmemoized(node.id.name));
|
|
43
43
|
};
|
|
44
|
+
function isMemoImport(importPath) {
|
|
45
|
+
// Match both absolute and relative paths ending with util/memo
|
|
46
|
+
return /(?:^|\/)util\/memo$/.test(importPath);
|
|
47
|
+
}
|
|
44
48
|
function checkFunction(context, node) {
|
|
45
49
|
const fileName = context.getFilename();
|
|
46
50
|
if (!fileName.endsWith('.tsx')) {
|
|
@@ -67,21 +71,33 @@ function checkFunction(context, node) {
|
|
|
67
71
|
? function fix(fixer) {
|
|
68
72
|
const sourceCode = context.getSourceCode();
|
|
69
73
|
let importFix = null;
|
|
70
|
-
// Search for
|
|
74
|
+
// Search for memo import statement
|
|
71
75
|
const importDeclarations = sourceCode.ast.body.filter((node) => node.type === 'ImportDeclaration');
|
|
72
|
-
const
|
|
73
|
-
if (
|
|
76
|
+
const memoImport = importDeclarations.find((importDeclaration) => isMemoImport(importDeclaration.source.value));
|
|
77
|
+
if (memoImport) {
|
|
74
78
|
// Check if memo is already imported
|
|
75
|
-
if (!
|
|
79
|
+
if (!memoImport.specifiers.some((specifier) => specifier.local.name === 'memo')) {
|
|
76
80
|
// Add memo to existing import statement
|
|
77
|
-
const lastSpecifier =
|
|
81
|
+
const lastSpecifier = memoImport.specifiers[memoImport.specifiers.length - 1];
|
|
78
82
|
importFix = fixer.insertTextAfter(lastSpecifier, ', memo');
|
|
79
83
|
}
|
|
80
84
|
}
|
|
81
85
|
else {
|
|
86
|
+
// Calculate relative path based on current file location
|
|
87
|
+
const currentFilePath = context.getFilename();
|
|
88
|
+
const importPath = calculateImportPath(currentFilePath);
|
|
89
|
+
// Find the first import statement to insert after
|
|
90
|
+
const firstImport = importDeclarations[0];
|
|
82
91
|
// Add new import statement for memo
|
|
83
|
-
const importStatement =
|
|
84
|
-
|
|
92
|
+
const importStatement = `import { memo } from '${importPath}';\n`;
|
|
93
|
+
if (firstImport) {
|
|
94
|
+
// Insert after the first import with a single newline
|
|
95
|
+
importFix = fixer.insertTextAfter(firstImport, '\n' + importStatement.trim());
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
// Insert at the start of the file
|
|
99
|
+
importFix = fixer.insertTextBeforeRange([sourceCode.ast.range[0], sourceCode.ast.range[0]], importStatement.trim() + '\n');
|
|
100
|
+
}
|
|
85
101
|
}
|
|
86
102
|
const functionKeywordRange = [
|
|
87
103
|
node.range[0],
|
|
@@ -105,6 +121,22 @@ function checkFunction(context, node) {
|
|
|
105
121
|
}
|
|
106
122
|
}
|
|
107
123
|
}
|
|
124
|
+
function calculateImportPath(currentFilePath) {
|
|
125
|
+
// Default to absolute path if we can't calculate relative path
|
|
126
|
+
if (!currentFilePath)
|
|
127
|
+
return 'src/util/memo';
|
|
128
|
+
// Split the current file path into parts and normalize
|
|
129
|
+
const parts = currentFilePath.split(/[\\/]/); // Handle both Unix and Windows paths
|
|
130
|
+
const srcIndex = parts.indexOf('src');
|
|
131
|
+
if (srcIndex === -1) {
|
|
132
|
+
// If we're not in a src directory, use absolute path
|
|
133
|
+
return 'src/util/memo';
|
|
134
|
+
}
|
|
135
|
+
// Calculate relative path based on current file depth from src
|
|
136
|
+
// Subtract 1 from depth to exclude the filename itself
|
|
137
|
+
const depth = parts.length - (srcIndex + 1) - 1;
|
|
138
|
+
return '../'.repeat(depth) + 'util/memo';
|
|
139
|
+
}
|
|
108
140
|
exports.requireMemo = {
|
|
109
141
|
create: (context) => ({
|
|
110
142
|
ArrowFunctionExpression(node) {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import { Graph } from './graph/ClassGraphBuilder';
|
|
3
|
+
export declare class ASTHelpers {
|
|
4
|
+
static blockIncludesIdentifier(block: TSESTree.BlockStatement): boolean;
|
|
5
|
+
static declarationIncludesIdentifier(node: TSESTree.Node | null): boolean;
|
|
6
|
+
static classMethodDependenciesOf(node: TSESTree.Node | null, graph: Graph, className: string): string[];
|
|
7
|
+
static isNode(value: unknown): value is TSESTree.Node;
|
|
8
|
+
static hasReturnStatement(node: TSESTree.Node): boolean;
|
|
9
|
+
static isNodeExported(node: TSESTree.Node): boolean;
|
|
10
|
+
static returnsJSX(node: TSESTree.Node): boolean;
|
|
11
|
+
static hasParameters(node: TSESTree.ArrowFunctionExpression | TSESTree.FunctionExpression | TSESTree.FunctionDeclaration): boolean;
|
|
12
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
export declare const createRule: <TOptions extends readonly unknown[], TMessageIds extends string, TRuleListener extends import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener = import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>({ name, meta, ...rule }: Readonly<ESLintUtils.RuleWithMetaAndName<TOptions, TMessageIds, TRuleListener>>) => import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<TMessageIds, TOptions, TRuleListener>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export type GraphNode = {
|
|
3
|
+
name: string;
|
|
4
|
+
type: 'method' | 'property' | 'constructor';
|
|
5
|
+
accessibility?: TSESTree.Accessibility;
|
|
6
|
+
isStatic: boolean;
|
|
7
|
+
dependencies: string[];
|
|
8
|
+
};
|
|
9
|
+
export type Graph = Record<string, GraphNode>;
|
|
10
|
+
/**
|
|
11
|
+
* Builds a graph of class methods and properties with their dependencies from a class declaration.
|
|
12
|
+
* A dependency in this case is the name of another class method.
|
|
13
|
+
*/
|
|
14
|
+
export declare class ClassGraphBuilder {
|
|
15
|
+
private className;
|
|
16
|
+
private classBody;
|
|
17
|
+
graph: Graph;
|
|
18
|
+
private sorter;
|
|
19
|
+
constructor(className: string, classBody: TSESTree.ClassBody);
|
|
20
|
+
private buildGraph;
|
|
21
|
+
private static isClassMember;
|
|
22
|
+
private addMemberToGraph;
|
|
23
|
+
private static nodeTypeOf;
|
|
24
|
+
private static createGraphNode;
|
|
25
|
+
private static isNamedClassMethod;
|
|
26
|
+
private addDependencies;
|
|
27
|
+
get graphSorted(): GraphNode[];
|
|
28
|
+
get memberNamesSorted(): string[];
|
|
29
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Graph, GraphNode } from './ClassGraphBuilder';
|
|
2
|
+
import { ClassGraphSorter } from './ClassGraphSorter';
|
|
3
|
+
type GraphNodeModifier = 'isStatic' | 'accessibility';
|
|
4
|
+
export declare class ClassGraphSorterReadability extends ClassGraphSorter {
|
|
5
|
+
graph: Graph;
|
|
6
|
+
static readonly MODIFIER_PRIORITY_MAP: Record<GraphNodeModifier, any[]>;
|
|
7
|
+
private static readonly SEARCH_NODE_PRIORITY_FUNCTIONS;
|
|
8
|
+
constructor(graph: Graph);
|
|
9
|
+
get nodeNamesSorted(): string[];
|
|
10
|
+
get nodesSorted(): GraphNode[];
|
|
11
|
+
sortNodes(): GraphNode[];
|
|
12
|
+
private groupNodesByType;
|
|
13
|
+
private static sortMembersForReadability;
|
|
14
|
+
private dependencyDfs;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,45 +1,114 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blumintinc/eslint-plugin-blumint",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Custom eslint rules for use
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Custom eslint rules for use within BluMint",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Brodie McGuire",
|
|
7
|
+
"email": "brodie@blumint.io"
|
|
8
|
+
},
|
|
9
|
+
"main": "lib/index.js",
|
|
10
|
+
"exports": "./lib/index.js",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/BluMintInc/custom-eslint-rules.git"
|
|
17
|
+
},
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/BluMintInc/custom-eslint-rules/issues"
|
|
20
|
+
},
|
|
21
|
+
"homepage": "https://github.com/BluMintInc/custom-eslint-rules#readme",
|
|
5
22
|
"keywords": [
|
|
6
23
|
"eslint",
|
|
7
24
|
"eslintplugin",
|
|
8
25
|
"eslint-plugin"
|
|
9
26
|
],
|
|
10
|
-
"
|
|
11
|
-
"main": "./lib/index.js",
|
|
12
|
-
"exports": "./lib/index.js",
|
|
27
|
+
"private": false,
|
|
13
28
|
"scripts": {
|
|
14
29
|
"lint": "npm-run-all \"lint:*\"",
|
|
15
30
|
"lint:eslint-docs": "npm-run-all \"update:eslint-docs -- --check\"",
|
|
16
31
|
"lint:js": "eslint ./src",
|
|
17
|
-
"
|
|
32
|
+
"lint:md": "remark .",
|
|
33
|
+
"lint:shell": "shellcheck .devcontainer/git-flow-completion.bash",
|
|
34
|
+
"lint:fix": "tsc && eslint ./**/* --quiet --fix",
|
|
35
|
+
"test": "jest --passWithNoTests --reporters=default --reporters=jest-junit",
|
|
36
|
+
"test:ci": "jest --ci --passWithNoTests --reporters=default --reporters=jest-junit",
|
|
18
37
|
"docs": "./scripts/make-docs.sh && npm run update:eslint-docs",
|
|
19
|
-
"update:eslint-docs": "eslint-doc-generator"
|
|
38
|
+
"update:eslint-docs": "eslint-doc-generator",
|
|
39
|
+
"build": "tsc",
|
|
40
|
+
"prepare": "npm run build",
|
|
41
|
+
"version": "git add -A src",
|
|
42
|
+
"postversion": "git push && git push --tags",
|
|
43
|
+
"remove-hooks": "del-cli ./.husky/",
|
|
44
|
+
"release:dry-run": "semantic-release --dry-run --no-ci",
|
|
45
|
+
"test:release": "node scripts/test-release.js"
|
|
20
46
|
},
|
|
21
47
|
"dependencies": {
|
|
22
48
|
"requireindex": "1.2.0"
|
|
23
49
|
},
|
|
24
50
|
"devDependencies": {
|
|
51
|
+
"@semantic-release/changelog": "6.0.1",
|
|
52
|
+
"@semantic-release/commit-analyzer": "9.0.2",
|
|
53
|
+
"@semantic-release/git": "10.0.1",
|
|
54
|
+
"@semantic-release/npm": "9.0.1",
|
|
55
|
+
"@semantic-release/release-notes-generator": "10.0.3",
|
|
25
56
|
"@types/eslint": "8.37.0",
|
|
57
|
+
"@types/node": "18.7.13",
|
|
58
|
+
"@typescript-eslint/eslint-plugin": "5.34.0",
|
|
59
|
+
"@typescript-eslint/parser": "5.48.0",
|
|
26
60
|
"@typescript-eslint/utils": "5.59.6",
|
|
27
|
-
"
|
|
61
|
+
"chai": "4.3.6",
|
|
62
|
+
"chai-as-promised": "7.1.1",
|
|
63
|
+
"cross-env": "7.0.3",
|
|
64
|
+
"cz-conventional-changelog": "3.3.0",
|
|
65
|
+
"del-cli": "4.0.1",
|
|
66
|
+
"dotenv-cli": "5.0.0",
|
|
67
|
+
"eslint": "8.11.0",
|
|
68
|
+
"eslint-config-prettier": "8.5.0",
|
|
28
69
|
"eslint-doc-generator": "1.0.0",
|
|
29
70
|
"eslint-import-resolver-typescript": "3.5.5",
|
|
30
71
|
"eslint-plugin-eslint-plugin": "5.0.0",
|
|
31
|
-
"
|
|
72
|
+
"eslint-plugin-import": "2.26.0",
|
|
32
73
|
"eslint-plugin-node": "11.1.0",
|
|
74
|
+
"eslint-plugin-jsdoc": "44.0.0",
|
|
75
|
+
"eslint-plugin-prettier": "4.2.1",
|
|
76
|
+
"eslint-plugin-security": "1.5.0",
|
|
77
|
+
"fs": "0.0.1-security",
|
|
33
78
|
"jest": "29.3.1",
|
|
79
|
+
"jest-junit": "14.0.0",
|
|
34
80
|
"jsonc-eslint-parser": "2.3.0",
|
|
35
81
|
"npm-run-all": "4.1.5",
|
|
36
|
-
"
|
|
82
|
+
"prettier": "2.7.1",
|
|
83
|
+
"remark-cli": "10.0.1",
|
|
84
|
+
"remark-lint": "9.1.1",
|
|
85
|
+
"remark-preset-lint-recommended": "6.1.2",
|
|
86
|
+
"semantic-release": "19.0.3",
|
|
87
|
+
"ts-jest": "29.0.5",
|
|
88
|
+
"ts-node": "10.9.1",
|
|
89
|
+
"typescript": "4.9.5",
|
|
90
|
+
"@types/jest": "^29.3.1",
|
|
91
|
+
"@semantic-release/exec": "^6.0.3"
|
|
92
|
+
},
|
|
93
|
+
"peerDependencies": {
|
|
94
|
+
"eslint": ">=7"
|
|
37
95
|
},
|
|
38
96
|
"engines": {
|
|
39
97
|
"node": "^20.0.0"
|
|
40
98
|
},
|
|
41
|
-
"
|
|
42
|
-
"
|
|
99
|
+
"config": {
|
|
100
|
+
"commitizen": {
|
|
101
|
+
"path": "./node_modules/cz-conventional-changelog"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"jest-junit": {
|
|
105
|
+
"outputDirectory": "reports",
|
|
106
|
+
"outputName": "jest-junit.xml",
|
|
107
|
+
"ancestorSeparator": " › ",
|
|
108
|
+
"uniqueOutputName": "false",
|
|
109
|
+
"suiteNameTemplate": "{filepath}",
|
|
110
|
+
"classNameTemplate": "{classname}",
|
|
111
|
+
"titleTemplate": "{title}"
|
|
43
112
|
},
|
|
44
113
|
"license": "ISC"
|
|
45
114
|
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# Prevent misuse of Array methods in OOP (`@blumintinc/blumint/array-methods-this-context`)
|
|
2
|
-
|
|
3
|
-
⚠️ This rule _warns_ in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
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.
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
This rule enforces that no class methods are directly used in Array methods. It also prefers the use of arrow functions over `bind(this)`
|
|
12
|
-
|
|
13
|
-
### Examples of incorrect code for this rule:
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
['a', 'b', 'c'].map(this.processItem)
|
|
17
|
-
['a', 'b', 'c'].map(this.processItem, otherArgument)
|
|
18
|
-
['a', 'b', 'c'].filter(this.checkItem)
|
|
19
|
-
['a', 'b', 'c'].forEach(this.printItem)
|
|
20
|
-
['a', 'b', 'c'].some(this.testItem)
|
|
21
|
-
['a', 'b', 'c'].every(this.validateItem)
|
|
22
|
-
['a', 'b', 'c'].reduce(this.combineItems)
|
|
23
|
-
['a', 'b', 'c'].map(function(item) { return this.processItem(item) }.bind(this))
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Examples of correct code for this rule:
|
|
27
|
-
```typescript
|
|
28
|
-
['a', 'b', 'c'].map((item) => this.processItem(item))
|
|
29
|
-
['a', 'b', 'c'].map(processItem)
|
|
30
|
-
```
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# Ensures classes read linearly from top to bottom (`@blumintinc/blumint/class-methods-read-top-to-bottom`)
|
|
2
|
-
|
|
3
|
-
⚠️ This rule _warns_ in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
6
|
-
|
|
7
|
-
<!-- end auto-generated rule header -->
|
|
8
|
-
|
|
9
|
-
This rule enforces an ordering of class methods according to BluMint's code style.
|
|
10
|
-
|
|
11
|
-
## Rule Details
|
|
12
|
-
|
|
13
|
-
This rule warns for classes that don't follow the 'top to bottom' ordering - such that properties appear at the top of the class, the constructor (if present) follows, and other methods follow in a top-to-bottom order.
|
|
14
|
-
|
|
15
|
-
### Examples of incorrect code for this rule:
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
class IncorrectlyOrdered {
|
|
19
|
-
field1: string;
|
|
20
|
-
field2: number;
|
|
21
|
-
methodA() {
|
|
22
|
-
this.methodB();
|
|
23
|
-
}
|
|
24
|
-
constructor() {
|
|
25
|
-
this.methodA();
|
|
26
|
-
this.methodC();
|
|
27
|
-
}
|
|
28
|
-
methodB() {}
|
|
29
|
-
methodC() {}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Examples of correct code for this rule:
|
|
34
|
-
```typescript
|
|
35
|
-
class CorrectlyOrdered {
|
|
36
|
-
field1: string;
|
|
37
|
-
field2: number;
|
|
38
|
-
constructor() {
|
|
39
|
-
this.methodA();
|
|
40
|
-
}
|
|
41
|
-
methodA() {
|
|
42
|
-
this.methodB();
|
|
43
|
-
}
|
|
44
|
-
methodB() {}
|
|
45
|
-
}
|
|
46
|
-
```
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Dynamic error details should only be in the third argument of the HttpsError constructor. The second argument is hashed to produce a unique id (`@blumintinc/blumint/dynamic-https-errors`)
|
|
2
|
-
|
|
3
|
-
⚠️ This rule _warns_ in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
This rule warns against the use of template literals in the `message` field of the `HttpsError` constructor, and suggests their use in the `details` field instead.
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
Examples of **incorrect** code for this rule:
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
throw new https.HttpsError('foo', `Error: ${bar}`, 'baz');
|
|
15
|
-
throw new HttpsError('foo', `Error: ${bar}`, 'baz');
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
Examples of **correct** code for this rule:
|
|
19
|
-
|
|
20
|
-
```typescript
|
|
21
|
-
throw new https.HttpsError('foo', 'bar', 'baz');
|
|
22
|
-
throw new https.HttpsError('foo', 'bar', `Details: ${baz}`);
|
|
23
|
-
```
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# All top-level const definitions, type definitions, and functions should be exported (`@blumintinc/blumint/export-if-in-doubt`)
|
|
2
|
-
|
|
3
|
-
<!-- end auto-generated rule header -->
|
|
4
|
-
|
|
5
|
-
This rule enforces that all top-level const definitions, type definitions, and functions should always be exported. If not done, this rule will trigger a warning message suggesting to export the declaration.
|
|
6
|
-
|
|
7
|
-
## Rule Details
|
|
8
|
-
|
|
9
|
-
This rule targets `VariableDeclaration`, `FunctionDeclaration`, and `TSTypeAliasDeclaration` at the top-level of the file. It will issue a warning if these are not part of an `ExportNamedDeclaration`.
|
|
10
|
-
|
|
11
|
-
### Examples of incorrect code for this rule:
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
const someVar = "Hello, world!";
|
|
15
|
-
function someFunc() { return someVar; }
|
|
16
|
-
type SomeType = { val: number };
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
### Examples of correct code for this rule:
|
|
20
|
-
|
|
21
|
-
```typescript
|
|
22
|
-
export const someVar = "Hello, world!";
|
|
23
|
-
export function someFunc() { return someVar; }
|
|
24
|
-
export type SomeType = { val: number };
|
|
25
|
-
```
|
|
26
|
-
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# Extract constants/functions to the global scope when possible (`@blumintinc/blumint/extract-global-constants`)
|
|
2
|
-
|
|
3
|
-
<!-- end auto-generated rule header -->
|
|
4
|
-
|
|
5
|
-
This rule suggests that if a constant or a function within a function or block scope doesn't depend on any other identifiers in that scope, it should be moved to the global scope. This aims to improve the readability of the code and the possibility of reuse.
|
|
6
|
-
|
|
7
|
-
## Rule Details
|
|
8
|
-
|
|
9
|
-
This rule enforces that all `const` declarations and `FunctionDeclaration` at a non-global scope, which have no dependencies on other identifiers within the scope, should be extracted to the global scope.
|
|
10
|
-
|
|
11
|
-
### Examples of incorrect code for this rule:
|
|
12
|
-
|
|
13
|
-
```typescript
|
|
14
|
-
function someFunc() {
|
|
15
|
-
const SOME_CONST = "Hello, world!";
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function parentFunc() {
|
|
19
|
-
function childFunc() { return "Hello, world!"; }
|
|
20
|
-
}
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
### Examples of correct code for this rule:
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
const SOME_CONST = "Hello, world!";
|
|
27
|
-
function someFunc() { /* ... */ }
|
|
28
|
-
|
|
29
|
-
function childFunc() { return "Hello, world!"; }
|
|
30
|
-
function parentFunc() { /* ... */ }
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
In the correct examples, each declaration is moved to the global scope since they don't depend on any identifier in their previous block or function scope. This aligns with the rule and promotes potential reuse of these declarations.
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# Enforce TypeScript generic types to start with T (`@blumintinc/blumint/generic-starts-with-t`)
|
|
2
|
-
|
|
3
|
-
⚠️ This rule _warns_ in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
This rule enforces that all TypeScript generic types start with the letter "T".
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
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.
|
|
12
|
-
|
|
13
|
-
This rule enforces that all TypeScript generic types start with the letter "T".
|
|
14
|
-
|
|
15
|
-
Examples of **incorrect** code for this rule:
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
type GenericType<Param> = Param[];
|
|
19
|
-
type GenericType<TParam, Param> = [TParam, Param];
|
|
20
|
-
type GenericType<P> = P[];
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Examples of **correct** code for this rule:
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
type GenericType<TParam> = TParam[];
|
|
27
|
-
type GenericType<TParam1, TParam2> = [TParam1, TParam2];
|
|
28
|
-
type GenericType<T> = T[];
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## When Not To Use It
|
|
32
|
-
If you have a different convention for naming generic types in your codebase, you may want to disable this rule.
|
|
33
|
-
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# Disallow async callbacks for Array.filter (`@blumintinc/blumint/no-async-array-filter`)
|
|
2
|
-
|
|
3
|
-
💼 This rule is enabled in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
Async callbacks in array filters are dangerous and not picked up by the standard eslint rules.
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
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.
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
|
|
17
|
-
['a'].filter(async (x) => true)
|
|
18
|
-
['a'].filter(async function(x) {
|
|
19
|
-
return true
|
|
20
|
-
})
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Examples of **correct** code for this rule:
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
|
|
27
|
-
['a'].filter((x) => true)
|
|
28
|
-
['a'].filter(function (x) {
|
|
29
|
-
return true
|
|
30
|
-
})
|
|
31
|
-
```
|
|
32
|
-
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
# Disallow Array.forEach with an async callback function (`@blumintinc/blumint/no-async-foreach`)
|
|
2
|
-
|
|
3
|
-
💼 This rule is enabled in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
This rule disallows the use of `Array.forEach` callbacks with the async keyword. These are typically found when sequential promise execution is desired, but in fact these will execute almost concurrently. The use of a standard `for` loop is suggested instead, which will execute sequentially. If concurrent execution is required, `Promise.all` or `Promise.allSettled` should be used.
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
This rule is aimed at ensuring that the async keyword is not used in an `Array.forEach` callback.
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
['a','b','c'].forEach(async (letter) => {
|
|
17
|
-
await someAsyncFunction(letter)
|
|
18
|
-
console.log(letter)
|
|
19
|
-
})
|
|
20
|
-
['foo','bar'].forEach(async function (letter) {
|
|
21
|
-
await someAsyncFunction(letter)
|
|
22
|
-
console.log(letter)
|
|
23
|
-
})
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Examples of **correct** code for this rule:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
['a','b','c'].forEach(letter) => {
|
|
30
|
-
someSyncFunction(letter)
|
|
31
|
-
console.log(letter)
|
|
32
|
-
})
|
|
33
|
-
['foo','bar'].forEach(function (letter) {
|
|
34
|
-
someSyncFunction(letter)
|
|
35
|
-
console.log(letter)
|
|
36
|
-
})
|
|
37
|
-
for (const letter of ['a', 'b', 'c']) {
|
|
38
|
-
someSyncFunction(letter);
|
|
39
|
-
console.log(letter);
|
|
40
|
-
}
|
|
41
|
-
```
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Disallow use of conditional literals in JSX code (`@blumintinc/blumint/no-conditional-literals-in-jsx`)
|
|
2
|
-
|
|
3
|
-
💼 This rule is enabled in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
This rule disallows the use of conditional literals in JSX.
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
Browser auto-translation will break if pieces of text nodes are be rendered conditionally.
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```jsx
|
|
16
|
-
<div>This will cause {conditional && 'errors'}</div>
|
|
17
|
-
<div><span>This will {conditional && 'also'} cause errors </span></div>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Examples of **correct** code for this rule:
|
|
21
|
-
|
|
22
|
-
```jsx
|
|
23
|
-
<div>Foo</div>
|
|
24
|
-
<div>
|
|
25
|
-
Bar {conditional && <span>Baz</span>}
|
|
26
|
-
</div>
|
|
27
|
-
```
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
# Disallow Array.filter callbacks without an explicit return (if part of a block statement) (`@blumintinc/blumint/no-filter-without-return`)
|
|
2
|
-
|
|
3
|
-
💼 This rule is enabled in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
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.
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
This rule is aimed at ensuring that there is an explicit return statement in `Array.filter` callbacks that are part of a block statement.
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
['a'].filter((x) => {console.log(x)})
|
|
17
|
-
['a'].filter((x) => {if (x) {
|
|
18
|
-
return true
|
|
19
|
-
}
|
|
20
|
-
else {}
|
|
21
|
-
}
|
|
22
|
-
)
|
|
23
|
-
['a'].filter((x) => { if (x !== 'a') { console.log(x) } else { return true } })
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
Examples of **correct** code for this rule:
|
|
27
|
-
|
|
28
|
-
```typescript
|
|
29
|
-
['a'].filter((x) => !x)
|
|
30
|
-
['a'].filter((x) => !!x)
|
|
31
|
-
['a'].filter((x) => {
|
|
32
|
-
if (x === 'test') {
|
|
33
|
-
return true
|
|
34
|
-
}
|
|
35
|
-
else {
|
|
36
|
-
return false
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
['a'].filter(function (x) {
|
|
40
|
-
return true
|
|
41
|
-
})
|
|
42
|
-
['a'].filter((x) => x === 'a' ? true : false)
|
|
43
|
-
```
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
# Prevent misuse of logical OR in switch case statements (`@blumintinc/blumint/no-misused-switch-case`)
|
|
2
|
-
|
|
3
|
-
💼 This rule is enabled in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
<!-- end auto-generated rule header -->
|
|
6
|
-
|
|
7
|
-
This rule prevents the misuse of logical OR in switch case statements. Instead, cascading cases should be used. This improves code readability and understanding.
|
|
8
|
-
|
|
9
|
-
## Rule Details
|
|
10
|
-
|
|
11
|
-
This rule specifically targets `SwitchStatement` and issues a warning if a case uses a logical OR in its test.
|
|
12
|
-
|
|
13
|
-
### Examples of incorrect code for this rule:
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
switch (value) {
|
|
17
|
-
case 'a' || 'b':
|
|
18
|
-
console.log('It is a or b');
|
|
19
|
-
break;
|
|
20
|
-
default:
|
|
21
|
-
console.log('Unknown value');
|
|
22
|
-
}
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
### Examples of correct code for this rule:
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
switch (value) {
|
|
29
|
-
case 'a':
|
|
30
|
-
case 'b':
|
|
31
|
-
console.log('It is a or b');
|
|
32
|
-
break;
|
|
33
|
-
default:
|
|
34
|
-
console.log('Unknown value');
|
|
35
|
-
}
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
In the correct example, instead of using a logical OR in the case test, cascading cases are used to capture the multiple possibilities. This is the standard way to handle multiple possibilities in a switch case and adheres to the rule.
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# Enforces pinned dependencies (`@blumintinc/blumint/no-unpinned-dependencies`)
|
|
2
|
-
|
|
3
|
-
💼 This rule is enabled in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
6
|
-
|
|
7
|
-
<!-- end auto-generated rule header -->
|
|
8
|
-
|
|
9
|
-
Unpinned dependencies can cause problems, including hard to diagnose breaking changes.
|
|
10
|
-
|
|
11
|
-
## Rule Details
|
|
12
|
-
|
|
13
|
-
This rule aims to prevent the use of unpinned dependencies.
|
|
14
|
-
|
|
15
|
-
Examples of **incorrect** code for this rule:
|
|
16
|
-
|
|
17
|
-
```json
|
|
18
|
-
|
|
19
|
-
{dependencies: {eslint: "^8.19.0"}}
|
|
20
|
-
{dependencies: {eslint: "~8.19.0"}}
|
|
21
|
-
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
Examples of **correct** code for this rule:
|
|
25
|
-
|
|
26
|
-
```json
|
|
27
|
-
|
|
28
|
-
{dependencies: {eslint: "8.19.0"}}
|
|
29
|
-
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## When Not To Use It
|
|
33
|
-
|
|
34
|
-
If pinned dependencies are ok in your codebase.
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Prevent unnecessary use of React fragments (`@blumintinc/blumint/no-useless-fragment`)
|
|
2
|
-
|
|
3
|
-
⚠️ This rule _warns_ in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
6
|
-
|
|
7
|
-
<!-- end auto-generated rule header -->
|
|
8
|
-
|
|
9
|
-
This rule enforces that React fragments (`<>...</>`) are only used when necessary. A fragment is deemed unnecessary if it wraps only a single child.
|
|
10
|
-
|
|
11
|
-
## Rule Details
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```jsx
|
|
16
|
-
<><ChildComponent /></>
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Examples of **correct** code for this rule:
|
|
20
|
-
|
|
21
|
-
```jsx
|
|
22
|
-
<><ChildComponent /><AnotherChild /></>
|
|
23
|
-
<><ChildComponent />Some Text<AnotherChild /></>
|
|
24
|
-
```
|
|
25
|
-
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Prefer <> shorthand for <React.Fragment> (`@blumintinc/blumint/prefer-fragment-shorthand`)
|
|
2
|
-
|
|
3
|
-
⚠️ This rule _warns_ in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
6
|
-
|
|
7
|
-
<!-- end auto-generated rule header -->
|
|
8
|
-
|
|
9
|
-
This rule prefers the use of fragment shorthand, `<>` over `<React.Fragment>`
|
|
10
|
-
|
|
11
|
-
## Rule Details
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```jsx
|
|
16
|
-
<React.Fragment>Hello World</React.Fragment>
|
|
17
|
-
<React.Fragment><ChildComponent /></React.Fragment>
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Examples of **correct** code for this rule:
|
|
21
|
-
|
|
22
|
-
```jsx
|
|
23
|
-
<>Hello World</>
|
|
24
|
-
<><ChildComponent /></>
|
|
25
|
-
```
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Prefer using type alias over interface (`@blumintinc/blumint/prefer-type-over-interface`)
|
|
2
|
-
|
|
3
|
-
⚠️ This rule _warns_ in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
6
|
-
|
|
7
|
-
<!-- end auto-generated rule header -->
|
|
8
|
-
|
|
9
|
-
This rule prefers the use of `Type` over `Interface` in Typescript.
|
|
10
|
-
|
|
11
|
-
## Rule Details
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
interface SomeInterface { field: string; };
|
|
17
|
-
interface AnotherInterface extends SomeInterface { otherField: number; };
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Examples of **correct** code for this rule:
|
|
21
|
-
|
|
22
|
-
```typescript
|
|
23
|
-
type SomeType = { field: string; };
|
|
24
|
-
type AnotherType = SomeType & { otherField: number; };
|
|
25
|
-
```
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# React components must be memoized (`@blumintinc/blumint/require-memo`)
|
|
2
|
-
|
|
3
|
-
💼 This rule is enabled in the ✅ `recommended` config.
|
|
4
|
-
|
|
5
|
-
🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix).
|
|
6
|
-
|
|
7
|
-
<!-- end auto-generated rule header -->
|
|
8
|
-
|
|
9
|
-
This rule enforces that React components (that are not pure) to be memoized. If the component name includes "Unmemoized", then this rule is ignored.
|
|
10
|
-
|
|
11
|
-
## Rule Details
|
|
12
|
-
|
|
13
|
-
Examples of **incorrect** code for this rule:
|
|
14
|
-
|
|
15
|
-
```jsx
|
|
16
|
-
const Component = ({foo, bar}) => return (
|
|
17
|
-
<SomeOtherComponent>{foo}{bar}</SomeOtherComponent>
|
|
18
|
-
)
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Examples of **correct** code for this rule:
|
|
22
|
-
|
|
23
|
-
```jsx
|
|
24
|
-
const MemoizedComponent = memo(function BigComponent({foo, bar}) {
|
|
25
|
-
return (
|
|
26
|
-
<SomeOtherComponent>{foo}{bar}</SomeOtherComponent>
|
|
27
|
-
)
|
|
28
|
-
})
|
|
29
|
-
const ComponentUnmemoized = ({foo, bar}) => return (
|
|
30
|
-
<SomeOtherComponent>{foo}{bar}</SomeOtherComponent>
|
|
31
|
-
)
|
|
32
|
-
```
|
|
33
|
-
|