@blumintinc/eslint-plugin-blumint 1.1.9 → 1.2.1
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 +3 -0
- package/lib/index.js +7 -1
- package/lib/rules/dynamic-https-errors.js +1 -1
- package/lib/rules/enforce-callback-memo.js +21 -3
- package/lib/rules/enforce-exported-function-types.d.ts +3 -0
- package/lib/rules/enforce-exported-function-types.js +249 -0
- package/lib/rules/enforce-firestore-doc-ref-generic.d.ts +10 -0
- package/lib/rules/enforce-firestore-doc-ref-generic.js +134 -0
- package/lib/rules/enforce-memoize-async.d.ts +1 -0
- package/lib/rules/enforce-memoize-async.js +70 -0
- package/lib/rules/export-if-in-doubt.js +1 -1
- package/lib/rules/global-const-style.d.ts +2 -4
- package/lib/rules/global-const-style.js +44 -22
- package/lib/rules/no-compositing-layer-props.d.ts +1 -0
- package/lib/rules/no-compositing-layer-props.js +161 -0
- package/lib/rules/no-entire-object-hook-deps.js +68 -60
- package/lib/rules/no-unused-props.js +33 -8
- package/lib/rules/no-useless-fragment.js +1 -1
- package/lib/rules/prefer-fragment-shorthand.js +1 -1
- package/lib/rules/prefer-settings-object.d.ts +11 -0
- package/lib/rules/prefer-settings-object.js +129 -0
- package/lib/rules/prefer-type-over-interface.js +1 -1
- package/lib/rules/require-https-error.js +32 -23
- package/lib/rules/require-image-overlayed.js +2 -0
- package/lib/rules/use-custom-memo.d.ts +1 -0
- package/lib/rules/use-custom-memo.js +65 -0
- package/lib/utils/ASTHelpers.js +14 -0
- package/package.json +1 -1
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preferSettingsObject = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
const defaultOptions = {
|
|
7
|
+
minimumParameters: 3,
|
|
8
|
+
checkSameTypeParameters: true,
|
|
9
|
+
ignoreBoundMethods: true,
|
|
10
|
+
ignoreVariadicFunctions: true,
|
|
11
|
+
};
|
|
12
|
+
exports.preferSettingsObject = (0, createRule_1.createRule)({
|
|
13
|
+
name: 'prefer-settings-object',
|
|
14
|
+
meta: {
|
|
15
|
+
type: 'suggestion',
|
|
16
|
+
docs: {
|
|
17
|
+
description: 'Enforce using a settings object for functions with multiple parameters',
|
|
18
|
+
recommended: 'error',
|
|
19
|
+
},
|
|
20
|
+
fixable: 'code',
|
|
21
|
+
schema: [
|
|
22
|
+
{
|
|
23
|
+
type: 'object',
|
|
24
|
+
properties: {
|
|
25
|
+
minimumParameters: {
|
|
26
|
+
type: 'number',
|
|
27
|
+
minimum: 2,
|
|
28
|
+
},
|
|
29
|
+
checkSameTypeParameters: {
|
|
30
|
+
type: 'boolean',
|
|
31
|
+
},
|
|
32
|
+
ignoreBoundMethods: {
|
|
33
|
+
type: 'boolean',
|
|
34
|
+
},
|
|
35
|
+
ignoreVariadicFunctions: {
|
|
36
|
+
type: 'boolean',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
additionalProperties: false,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
messages: {
|
|
43
|
+
tooManyParams: 'Function has too many parameters ({{count}}). Use a settings object instead.',
|
|
44
|
+
sameTypeParams: 'Function has multiple parameters of the same type. Use a settings object instead.',
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
defaultOptions: [defaultOptions],
|
|
48
|
+
create(context, [options]) {
|
|
49
|
+
const finalOptions = { ...defaultOptions, ...options };
|
|
50
|
+
function getParameterType(param) {
|
|
51
|
+
if (param.type === utils_1.AST_NODE_TYPES.Identifier && param.typeAnnotation) {
|
|
52
|
+
const typeNode = param.typeAnnotation.typeAnnotation;
|
|
53
|
+
if (typeNode.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
54
|
+
return typeNode.typeName.type === utils_1.AST_NODE_TYPES.Identifier
|
|
55
|
+
? typeNode.typeName.name
|
|
56
|
+
: 'unknown';
|
|
57
|
+
}
|
|
58
|
+
return typeNode.type;
|
|
59
|
+
}
|
|
60
|
+
return 'unknown';
|
|
61
|
+
}
|
|
62
|
+
function hasSameTypeParameters(params) {
|
|
63
|
+
const typeMap = new Map();
|
|
64
|
+
for (const param of params) {
|
|
65
|
+
const type = getParameterType(param);
|
|
66
|
+
typeMap.set(type, (typeMap.get(type) || 0) + 1);
|
|
67
|
+
if (typeMap.get(type) > 1) {
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
function shouldIgnoreNode(node) {
|
|
74
|
+
// Ignore variadic functions if configured
|
|
75
|
+
if (finalOptions.ignoreVariadicFunctions) {
|
|
76
|
+
const hasRestParam = node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration &&
|
|
77
|
+
node.params.some(param => param.type === utils_1.AST_NODE_TYPES.RestElement);
|
|
78
|
+
if (hasRestParam)
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
// Ignore bound methods if configured
|
|
82
|
+
if (finalOptions.ignoreBoundMethods) {
|
|
83
|
+
let parent = node.parent;
|
|
84
|
+
while (parent) {
|
|
85
|
+
if (parent.type === utils_1.AST_NODE_TYPES.CallExpression ||
|
|
86
|
+
parent.type === utils_1.AST_NODE_TYPES.TSCallSignatureDeclaration) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
parent = parent.parent;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
function checkFunction(node) {
|
|
95
|
+
if (shouldIgnoreNode(node))
|
|
96
|
+
return;
|
|
97
|
+
const params = node.params;
|
|
98
|
+
// Check for too many parameters
|
|
99
|
+
const minParams = finalOptions.minimumParameters !== undefined
|
|
100
|
+
? finalOptions.minimumParameters
|
|
101
|
+
: defaultOptions.minimumParameters;
|
|
102
|
+
if (params.length >= minParams) {
|
|
103
|
+
context.report({
|
|
104
|
+
node,
|
|
105
|
+
messageId: 'tooManyParams',
|
|
106
|
+
data: { count: params.length },
|
|
107
|
+
});
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
// Check for same type parameters if enabled
|
|
111
|
+
if (finalOptions.checkSameTypeParameters && params.length >= 2) {
|
|
112
|
+
if (hasSameTypeParameters(params)) {
|
|
113
|
+
context.report({
|
|
114
|
+
node,
|
|
115
|
+
messageId: 'sameTypeParams',
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
FunctionDeclaration: checkFunction,
|
|
122
|
+
FunctionExpression: checkFunction,
|
|
123
|
+
ArrowFunctionExpression: checkFunction,
|
|
124
|
+
TSMethodSignature: checkFunction,
|
|
125
|
+
TSFunctionType: checkFunction,
|
|
126
|
+
};
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=prefer-settings-object.js.map
|
|
@@ -42,30 +42,39 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
ThrowStatement(node) {
|
|
45
|
+
if (!node.argument) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
45
48
|
const argument = node.argument;
|
|
46
|
-
if (argument
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
49
|
+
if (argument.type !== utils_1.AST_NODE_TYPES.NewExpression) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const callee = argument.callee;
|
|
53
|
+
// Check for direct Error usage
|
|
54
|
+
if (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
55
|
+
callee.name === 'Error') {
|
|
56
|
+
context.report({
|
|
57
|
+
node,
|
|
58
|
+
messageId: 'useHttpsError',
|
|
59
|
+
});
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
// Check for firebase-admin HttpsError usage
|
|
63
|
+
if (!hasFirebaseAdminImport) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const isHttpsError = callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
67
|
+
callee.name === 'HttpsError';
|
|
68
|
+
const isFirebaseHttpsError = callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
69
|
+
callee.object.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
70
|
+
callee.object.name === httpsIdentifier &&
|
|
71
|
+
callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
72
|
+
callee.property.name === 'HttpsError';
|
|
73
|
+
if (isHttpsError || isFirebaseHttpsError) {
|
|
74
|
+
context.report({
|
|
75
|
+
node,
|
|
76
|
+
messageId: 'useProprietaryHttpsError',
|
|
77
|
+
});
|
|
69
78
|
}
|
|
70
79
|
},
|
|
71
80
|
};
|
|
@@ -7,6 +7,7 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
7
7
|
docs: {
|
|
8
8
|
description: 'Enforce using ImageOverlayed component instead of next/image or img tags',
|
|
9
9
|
recommended: 'error',
|
|
10
|
+
requiresTypeChecking: false,
|
|
10
11
|
},
|
|
11
12
|
fixable: 'code',
|
|
12
13
|
schema: [
|
|
@@ -15,6 +16,7 @@ module.exports = (0, createRule_1.createRule)({
|
|
|
15
16
|
properties: {
|
|
16
17
|
componentPath: {
|
|
17
18
|
type: 'string',
|
|
19
|
+
description: 'The import path for the ImageOverlayed component',
|
|
18
20
|
default: 'src/components/ImageOverlayed',
|
|
19
21
|
},
|
|
20
22
|
},
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const useCustomMemo: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"useCustomMemo", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.useCustomMemo = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
exports.useCustomMemo = (0, createRule_1.createRule)({
|
|
7
|
+
name: 'use-custom-memo',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'suggestion',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Enforce using src/util/memo instead of React memo',
|
|
12
|
+
recommended: 'error',
|
|
13
|
+
},
|
|
14
|
+
fixable: 'code',
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
useCustomMemo: 'Import memo from src/util/memo instead of react',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
return {
|
|
23
|
+
ImportDeclaration(node) {
|
|
24
|
+
if (node.source.value === 'react') {
|
|
25
|
+
const specifiers = node.specifiers.filter((specifier) => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
|
|
26
|
+
specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
27
|
+
specifier.imported.name === 'memo');
|
|
28
|
+
if (specifiers.length > 0) {
|
|
29
|
+
context.report({
|
|
30
|
+
node,
|
|
31
|
+
messageId: 'useCustomMemo',
|
|
32
|
+
fix(fixer) {
|
|
33
|
+
// If there are other imports from react, keep them
|
|
34
|
+
const otherSpecifiers = node.specifiers.filter((specifier) => specifier.type !== utils_1.AST_NODE_TYPES.ImportSpecifier ||
|
|
35
|
+
(specifier.imported.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
36
|
+
specifier.imported.name !== 'memo'));
|
|
37
|
+
if (otherSpecifiers.length === 0) {
|
|
38
|
+
// If memo is the only import, replace the entire import
|
|
39
|
+
return fixer.replaceText(node, `import { ${specifiers
|
|
40
|
+
.map((s) => s.local.name !== s.imported.name
|
|
41
|
+
? `memo as ${s.local.name}`
|
|
42
|
+
: 'memo')
|
|
43
|
+
.join(', ')} } from 'src/util/memo';`);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
// Create a new import for memo and keep other imports
|
|
47
|
+
const memoImport = `import { ${specifiers
|
|
48
|
+
.map((s) => s.local.name !== s.imported.name
|
|
49
|
+
? `memo as ${s.local.name}`
|
|
50
|
+
: 'memo')
|
|
51
|
+
.join(', ')} } from 'src/util/memo';\n`;
|
|
52
|
+
const otherImports = `import { ${otherSpecifiers
|
|
53
|
+
.map((s) => s.local.name)
|
|
54
|
+
.join(', ')} } from 'react';`;
|
|
55
|
+
return fixer.replaceText(node, memoImport + otherImports);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=use-custom-memo.js.map
|
package/lib/utils/ASTHelpers.js
CHANGED
|
@@ -91,6 +91,20 @@ class ASTHelpers {
|
|
|
91
91
|
return node.expressions.some((expr) => this.declarationIncludesIdentifier(expr));
|
|
92
92
|
case 'TSAsExpression':
|
|
93
93
|
return this.declarationIncludesIdentifier(node.expression);
|
|
94
|
+
case 'TSTypeReference':
|
|
95
|
+
// Handle type references (e.g., T in generic types)
|
|
96
|
+
return false;
|
|
97
|
+
case 'TSTypeParameterDeclaration':
|
|
98
|
+
// Handle type parameter declarations (e.g., <T extends ...>)
|
|
99
|
+
return false;
|
|
100
|
+
case 'TSTypeParameterInstantiation':
|
|
101
|
+
// Handle type parameter instantiations (e.g., <string>)
|
|
102
|
+
return false;
|
|
103
|
+
case 'TSIntersectionType':
|
|
104
|
+
case 'TSUnionType':
|
|
105
|
+
case 'TSTypeLiteral':
|
|
106
|
+
// Handle type constraints and literals
|
|
107
|
+
return false;
|
|
94
108
|
default:
|
|
95
109
|
return false;
|
|
96
110
|
}
|