@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.
Files changed (42) hide show
  1. package/lib/index.d.ts +1 -0
  2. package/lib/index.js +1 -1
  3. package/lib/rules/array-methods-this-context.d.ts +3 -0
  4. package/lib/rules/class-methods-read-top-to-bottom.d.ts +2 -0
  5. package/lib/rules/dynamic-https-errors.d.ts +2 -0
  6. package/lib/rules/export-if-in-doubt.d.ts +2 -0
  7. package/lib/rules/extract-global-constants.d.ts +2 -0
  8. package/lib/rules/generic-starts-with-t.d.ts +2 -0
  9. package/lib/rules/no-async-array-filter.d.ts +2 -0
  10. package/lib/rules/no-async-foreach.d.ts +2 -0
  11. package/lib/rules/no-conditional-literals-in-jsx.d.ts +2 -0
  12. package/lib/rules/no-filter-without-return.d.ts +2 -0
  13. package/lib/rules/no-misused-switch-case.d.ts +2 -0
  14. package/lib/rules/no-unpinned-dependencies.d.ts +2 -0
  15. package/lib/rules/no-useless-fragment.d.ts +2 -0
  16. package/lib/rules/prefer-fragment-shorthand.d.ts +3 -0
  17. package/lib/rules/prefer-type-over-interface.d.ts +2 -0
  18. package/lib/rules/require-memo.d.ts +6 -0
  19. package/lib/rules/require-memo.js +39 -7
  20. package/lib/utils/ASTHelpers.d.ts +12 -0
  21. package/lib/utils/createRule.d.ts +2 -0
  22. package/lib/utils/graph/ClassGraphBuilder.d.ts +29 -0
  23. package/lib/utils/graph/ClassGraphSorter.d.ts +7 -0
  24. package/lib/utils/graph/ClassGraphSorterReadability.d.ts +16 -0
  25. package/lib/utils/ruleTester.d.ts +5 -0
  26. package/package.json +81 -12
  27. package/docs/rules/array-methods-this-context.md +0 -30
  28. package/docs/rules/class-methods-read-top-to-bottom.md +0 -46
  29. package/docs/rules/dynamic-https-errors.md +0 -23
  30. package/docs/rules/export-if-in-doubt.md +0 -26
  31. package/docs/rules/extract-global-constants.md +0 -33
  32. package/docs/rules/generic-starts-with-t.md +0 -33
  33. package/docs/rules/no-async-array-filter.md +0 -32
  34. package/docs/rules/no-async-foreach.md +0 -41
  35. package/docs/rules/no-conditional-literals-in-jsx.md +0 -27
  36. package/docs/rules/no-filter-without-return.md +0 -43
  37. package/docs/rules/no-misused-switch-case.md +0 -38
  38. package/docs/rules/no-unpinned-dependencies.md +0 -34
  39. package/docs/rules/no-useless-fragment.md +0 -25
  40. package/docs/rules/prefer-fragment-shorthand.md +0 -25
  41. package/docs/rules/prefer-type-over-interface.md +0 -25
  42. package/docs/rules/require-memo.md +0 -33
package/lib/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
package/lib/index.js CHANGED
@@ -19,7 +19,7 @@ const require_memo_1 = require("./rules/require-memo");
19
19
  module.exports = {
20
20
  meta: {
21
21
  name: '@blumintinc/eslint-plugin-blumint',
22
- version: '0.1.23',
22
+ version: '1.0.3',
23
23
  },
24
24
  parseOptions: {
25
25
  ecmaVersion: 2020,
@@ -0,0 +1,3 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const ARRAY_METHODS: string[];
3
+ export declare const arrayMethodsThisContext: TSESLint.RuleModule<'preferArrow' | 'unexpected', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const classMethodsReadTopToBottom: TSESLint.RuleModule<'classMethodsReadTopToBottom', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const dynamicHttpsErrors: TSESLint.RuleModule<'dynamicHttpsErrors', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const exportIfInDoubt: TSESLint.RuleModule<'exportIfInDoubt', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const extractGlobalConstants: TSESLint.RuleModule<'extractGlobalConstants', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const genericStartsWithT: TSESLint.RuleModule<'genericStartsWithT', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noAsyncArrayFilter: TSESLint.RuleModule<'unexpected', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noAsyncForEach: TSESLint.RuleModule<'noAsyncForEach', []>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noConditionalLiteralsInJsx: TSESLint.RuleModule<'unexpected', any[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noFilterWithoutReturn: TSESLint.RuleModule<'unexpected', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noMisusedSwitchCase: TSESLint.RuleModule<'noMisusedSwitchCase', never[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noUnpinnedDependencies: TSESLint.RuleModule<'unexpected', any[]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const noUselessFragment: TSESLint.RuleModule<'noUselessFragment', []>;
@@ -0,0 +1,3 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const preferFragmentShorthand: TSESLint.RuleModule<'preferShorthand', [
3
+ ]>;
@@ -0,0 +1,2 @@
1
+ import { TSESLint } from '@typescript-eslint/utils';
2
+ export declare const preferTypeOverInterface: TSESLint.RuleModule<'preferType', never[]>;
@@ -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 React import statement
74
+ // Search for memo import statement
71
75
  const importDeclarations = sourceCode.ast.body.filter((node) => node.type === 'ImportDeclaration');
72
- const reactImport = importDeclarations.find((importDeclaration) => importDeclaration.source.value === 'react');
73
- if (reactImport) {
76
+ const memoImport = importDeclarations.find((importDeclaration) => isMemoImport(importDeclaration.source.value));
77
+ if (memoImport) {
74
78
  // Check if memo is already imported
75
- if (!reactImport.specifiers.some((specifier) => specifier.local.name === 'memo')) {
79
+ if (!memoImport.specifiers.some((specifier) => specifier.local.name === 'memo')) {
76
80
  // Add memo to existing import statement
77
- const lastSpecifier = reactImport.specifiers[reactImport.specifiers.length - 1];
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 = "import { memo } from 'react';\n";
84
- importFix = fixer.insertTextBeforeRange([sourceCode.ast.range[0], sourceCode.ast.range[0]], importStatement);
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,7 @@
1
+ import { Graph, GraphNode } from './ClassGraphBuilder';
2
+ export declare abstract class ClassGraphSorter {
3
+ graph: Graph;
4
+ constructor(graph: Graph);
5
+ abstract nodesSorted: GraphNode[];
6
+ abstract nodeNamesSorted: GraphNode['name'][];
7
+ }
@@ -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 {};
@@ -0,0 +1,5 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ import { RuleTester } from 'eslint';
3
+ export declare const ruleTesterTs: ESLintUtils.RuleTester;
4
+ export declare const ruleTesterJsx: ESLintUtils.RuleTester;
5
+ export declare const ruleTesterJson: RuleTester;
package/package.json CHANGED
@@ -1,45 +1,114 @@
1
1
  {
2
2
  "name": "@blumintinc/eslint-plugin-blumint",
3
- "version": "0.1.24",
4
- "description": "Custom eslint rules for use at BluMint",
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
- "author": "Brodie McGuire",
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
- "test": "jest",
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
- "eslint": "8.19.0",
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
- "@blumintinc/eslint-plugin-blumint": "file:./",
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
- "ts-jest": "29.0.5"
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
- "peerDependencies": {
42
- "eslint": ">=7"
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
-