@blumintinc/eslint-plugin-blumint 1.7.2 → 1.7.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.js +1 -1
- package/lib/rules/enforce-centralized-mock-firestore.js +1 -1
- package/lib/rules/enforce-mock-firestore.js +2 -2
- package/lib/rules/enforce-render-hits-memoization.js +20 -0
- package/lib/rules/enforce-verb-noun-naming.js +1 -0
- package/lib/rules/no-firestore-jest-mock.js +1 -1
- package/lib/rules/no-mock-firebase-admin.js +1 -1
- package/lib/rules/no-unused-props.js +47 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.enforceCentralizedMockFirestore = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
5
|
const createRule_1 = require("../utils/createRule");
|
|
6
|
-
const MOCK_FIRESTORE_PATH = '../../../../../
|
|
6
|
+
const MOCK_FIRESTORE_PATH = '../../../../../__test-utils__/mockFirestore';
|
|
7
7
|
exports.enforceCentralizedMockFirestore = (0, createRule_1.createRule)({
|
|
8
8
|
name: 'enforce-centralized-mock-firestore',
|
|
9
9
|
meta: {
|
|
@@ -18,8 +18,8 @@ exports.enforceFirestoreMock = (0, createRule_1.createRule)({
|
|
|
18
18
|
},
|
|
19
19
|
schema: [],
|
|
20
20
|
messages: {
|
|
21
|
-
noManualFirestoreMock: 'Use mockFirestore from
|
|
22
|
-
noMockFirebase: 'Use mockFirestore from
|
|
21
|
+
noManualFirestoreMock: 'Use mockFirestore from __test-utils__/mockFirestore instead of manually mocking Firestore. Replace `jest.mock("firebase-admin", () => ({ firestore: () => ({ /* mock */ }) }))` with `import { mockFirestore } from "__test-utils__/mockFirestore"; jest.mock("firebase-admin", () => mockFirestore)`.',
|
|
22
|
+
noMockFirebase: 'Use mockFirestore from __test-utils__/mockFirestore instead of mockFirebase. Replace `import { mockFirebase } from "firestore-jest-mock"` with `import { mockFirestore } from "__test-utils__/mockFirestore"`.',
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
25
|
defaultOptions: [],
|
|
@@ -35,7 +35,27 @@ exports.enforceRenderHitsMemoization = (0, createRule_1.createRule)({
|
|
|
35
35
|
const name = node.name;
|
|
36
36
|
return /^[A-Z]/.test(name);
|
|
37
37
|
};
|
|
38
|
+
const isMemoizedVariable = (node) => {
|
|
39
|
+
if (node.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
40
|
+
return false;
|
|
41
|
+
// Get the variable declaration for this identifier
|
|
42
|
+
const variable = context.getScope().variables.find(v => v.name === node.name);
|
|
43
|
+
if (!variable)
|
|
44
|
+
return false;
|
|
45
|
+
// Check if the variable is initialized with a memoized call
|
|
46
|
+
const def = variable.defs[0];
|
|
47
|
+
if (!def || !def.node)
|
|
48
|
+
return false;
|
|
49
|
+
if (def.node.type === utils_1.AST_NODE_TYPES.VariableDeclarator && def.node.init) {
|
|
50
|
+
return isMemoizedCall(def.node.init);
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
};
|
|
38
54
|
const isInsideMemoizedCall = (node) => {
|
|
55
|
+
// Check if the node is a reference to a memoized variable
|
|
56
|
+
if (isMemoizedVariable(node))
|
|
57
|
+
return true;
|
|
58
|
+
// Check if the node is inside a memoization hook call
|
|
39
59
|
let current = node;
|
|
40
60
|
while (current?.parent) {
|
|
41
61
|
if (isMemoizedCall(current.parent))
|
|
@@ -10,6 +10,7 @@ const compromise_1 = __importDefault(require("compromise"));
|
|
|
10
10
|
const PREPOSITIONS = new Set(['to', 'from', 'with', 'by', 'at', 'of']);
|
|
11
11
|
// Create a Set from the verbs list for O(1) lookup
|
|
12
12
|
const VERBS_SET = new Set([
|
|
13
|
+
'clean',
|
|
13
14
|
'abbreviate',
|
|
14
15
|
'abort',
|
|
15
16
|
'abstract',
|
|
@@ -32,7 +32,7 @@ exports.noFirestoreJestMock = (0, createRule_1.createRule)({
|
|
|
32
32
|
messageId: 'noFirestoreJestMock',
|
|
33
33
|
fix(fixer) {
|
|
34
34
|
// Replace with mockFirestore import
|
|
35
|
-
return fixer.replaceText(node, "import { mockFirestore } from '../../../../../
|
|
35
|
+
return fixer.replaceText(node, "import { mockFirestore } from '../../../../../__test-utils__/mockFirestore';");
|
|
36
36
|
},
|
|
37
37
|
});
|
|
38
38
|
}
|
|
@@ -19,7 +19,7 @@ exports.noMockFirebaseAdmin = (0, createRule_1.createRule)({
|
|
|
19
19
|
},
|
|
20
20
|
schema: [],
|
|
21
21
|
messages: {
|
|
22
|
-
noMockFirebaseAdmin: 'Do not mock firebaseAdmin directly. Use mockFirestore from
|
|
22
|
+
noMockFirebaseAdmin: 'Do not mock firebaseAdmin directly. Use mockFirestore from __test-utils__/mockFirestore instead.',
|
|
23
23
|
},
|
|
24
24
|
},
|
|
25
25
|
defaultOptions: [],
|
|
@@ -36,7 +36,53 @@ exports.noUnusedProps = (0, createRule_1.createRule)({
|
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
38
|
else if (typeNode.type === utils_1.AST_NODE_TYPES.TSIntersectionType) {
|
|
39
|
-
typeNode.types.forEach(
|
|
39
|
+
typeNode.types.forEach((type) => {
|
|
40
|
+
if (type.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
41
|
+
const typeName = type.typeName;
|
|
42
|
+
if (typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
43
|
+
if (typeName.name === 'Pick' && type.typeParameters) {
|
|
44
|
+
// Handle Pick utility type in intersection
|
|
45
|
+
const [baseType, pickedProps] = type.typeParameters.params;
|
|
46
|
+
if (baseType.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
47
|
+
baseType.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
48
|
+
// Extract the picked properties from the union type
|
|
49
|
+
if (pickedProps.type === utils_1.AST_NODE_TYPES.TSUnionType) {
|
|
50
|
+
pickedProps.types.forEach((t) => {
|
|
51
|
+
if (t.type === utils_1.AST_NODE_TYPES.TSLiteralType &&
|
|
52
|
+
t.literal.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
53
|
+
typeof t.literal.value === 'string') {
|
|
54
|
+
// Add each picked property as a regular prop
|
|
55
|
+
props[t.literal.value] = t.literal;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else if (pickedProps.type === utils_1.AST_NODE_TYPES.TSLiteralType &&
|
|
60
|
+
pickedProps.literal.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
61
|
+
typeof pickedProps.literal.value === 'string') {
|
|
62
|
+
// Single property pick
|
|
63
|
+
props[pickedProps.literal.value] = pickedProps.literal;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// For referenced types in intersections, we need to find their type declaration
|
|
69
|
+
const scope = context.getScope();
|
|
70
|
+
const variable = scope.variables.find(v => v.name === typeName.name);
|
|
71
|
+
if (variable && variable.defs[0]?.node.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration) {
|
|
72
|
+
extractProps(variable.defs[0].node.typeAnnotation);
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// If we can't find the type declaration, it's likely an imported type
|
|
76
|
+
// Mark it as a forwarded prop
|
|
77
|
+
props[`...${typeName.name}`] = typeName;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
extractProps(type);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
40
86
|
}
|
|
41
87
|
else if (typeNode.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
42
88
|
if (typeNode.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|