@blumintinc/eslint-plugin-blumint 1.12.6 → 1.13.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 +140 -99
- package/lib/index.js +111 -17
- package/lib/rules/array-methods-this-context.js +20 -2
- package/lib/rules/avoid-utils-directory.js +11 -2
- package/lib/rules/dynamic-https-errors.d.ts +3 -1
- package/lib/rules/dynamic-https-errors.js +48 -10
- package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
- package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +51 -95
- package/lib/rules/enforce-assert-throws.d.ts +3 -1
- package/lib/rules/enforce-assert-throws.js +493 -51
- package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
- package/lib/rules/enforce-boolean-naming-prefixes.js +832 -39
- package/lib/rules/enforce-callable-types.js +4 -4
- package/lib/rules/enforce-callback-memo.js +143 -18
- package/lib/rules/enforce-centralized-mock-firestore.js +4 -1
- package/lib/rules/enforce-console-error.d.ts +3 -0
- package/lib/rules/enforce-console-error.js +250 -0
- package/lib/rules/enforce-css-media-queries.js +24 -46
- package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
- package/lib/rules/enforce-dynamic-imports.js +1 -1
- package/lib/rules/enforce-exported-function-types.js +3 -3
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +212 -0
- package/lib/rules/enforce-firestore-doc-ref-generic.js +335 -0
- package/lib/rules/enforce-firestore-facade.js +347 -157
- package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
- package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
- package/lib/rules/enforce-global-constants.d.ts +4 -1
- package/lib/rules/enforce-global-constants.js +240 -12
- package/lib/rules/enforce-memoize-async.d.ts +2 -1
- package/lib/rules/enforce-memoize-async.js +96 -27
- package/lib/rules/enforce-memoize-getters.d.ts +3 -0
- package/lib/rules/enforce-memoize-getters.js +123 -0
- package/lib/rules/enforce-microdiff.js +2 -1
- package/lib/rules/enforce-positive-naming.js +5 -7
- package/lib/rules/enforce-props-argument-name.d.ts +2 -7
- package/lib/rules/enforce-props-argument-name.js +165 -151
- package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
- package/lib/rules/enforce-props-naming-consistency.js +145 -0
- package/lib/rules/enforce-querykey-ts.d.ts +9 -0
- package/lib/rules/enforce-querykey-ts.js +274 -0
- package/lib/rules/enforce-singular-type-names.js +9 -5
- package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
- package/lib/rules/enforce-typescript-markdown-code-blocks.js +96 -0
- package/lib/rules/enforce-verb-noun-naming.js +85 -10
- package/lib/rules/extract-global-constants.js +57 -45
- package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
- package/lib/rules/fast-deep-equal-over-microdiff.js +356 -78
- package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
- package/lib/rules/firestore-transaction-reads-before-writes.js +231 -0
- package/lib/rules/generic-starts-with-t.js +8 -2
- package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
- package/lib/rules/memoize-root-level-hocs.js +242 -0
- package/lib/rules/no-array-length-in-deps.d.ts +12 -0
- package/lib/rules/no-array-length-in-deps.js +308 -0
- package/lib/rules/no-async-array-filter.js +5 -2
- package/lib/rules/no-complex-cloud-params.js +15 -2
- package/lib/rules/no-compositing-layer-props.js +4 -2
- package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
- package/lib/rules/no-entire-object-hook-deps.js +317 -63
- package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
- package/lib/rules/no-excessive-parent-chain.js +273 -0
- package/lib/rules/no-firestore-object-arrays.js +345 -30
- package/lib/rules/no-hungarian.js +13 -13
- package/lib/rules/no-margin-properties.d.ts +7 -1
- package/lib/rules/no-margin-properties.js +16 -3
- package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
- package/lib/rules/no-misleading-boolean-prefixes.js +327 -0
- package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
- package/lib/rules/no-overridable-method-calls-in-constructor.js +260 -0
- package/lib/rules/no-passthrough-getters.d.ts +4 -0
- package/lib/rules/no-passthrough-getters.js +170 -0
- package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
- package/lib/rules/no-redundant-usecallback-wrapper.js +315 -0
- package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
- package/lib/rules/no-restricted-properties-fix.js +172 -0
- package/lib/rules/no-separate-loading-state.d.ts +8 -0
- package/lib/rules/no-separate-loading-state.js +142 -0
- package/lib/rules/no-stale-state-across-await.d.ts +1 -0
- package/lib/rules/no-stale-state-across-await.js +185 -0
- package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
- package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
- package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
- package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
- package/lib/rules/no-type-assertion-returns.js +6 -0
- package/lib/rules/no-undefined-null-passthrough.js +166 -19
- package/lib/rules/no-unnecessary-verb-suffix.js +0 -2
- package/lib/rules/no-unsafe-firestore-spread.js +8 -5
- package/lib/rules/no-unused-props.d.ts +3 -0
- package/lib/rules/no-unused-props.js +213 -78
- package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
- package/lib/rules/optimize-object-boolean-conditions.js +234 -0
- package/lib/rules/parallelize-async-operations.d.ts +8 -0
- package/lib/rules/parallelize-async-operations.js +375 -0
- package/lib/rules/prefer-batch-operations.js +199 -33
- package/lib/rules/prefer-block-comments-for-declarations.js +13 -3
- package/lib/rules/prefer-document-flattening.d.ts +4 -0
- package/lib/rules/prefer-document-flattening.js +239 -0
- package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
- package/lib/rules/prefer-field-paths-in-transforms.js +250 -0
- package/lib/rules/prefer-fragment-component.js +3 -3
- package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
- package/lib/rules/prefer-global-router-state-key.js +230 -31
- package/lib/rules/prefer-next-dynamic.d.ts +9 -0
- package/lib/rules/prefer-next-dynamic.js +366 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.js +430 -0
- package/lib/rules/prefer-nullish-coalescing-override.d.ts +6 -0
- package/lib/rules/prefer-nullish-coalescing-override.js +182 -0
- package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
- package/lib/rules/prefer-params-over-parent-id.js +228 -0
- package/lib/rules/prefer-settings-object.js +23 -15
- package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
- package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
- package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
- package/lib/rules/prefer-url-tostring-over-tojson.js +166 -0
- package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
- package/lib/rules/prefer-use-deep-compare-memo.js +428 -0
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +24 -1
- package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
- package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
- package/lib/rules/react-usememo-should-be-component.js +144 -78
- package/lib/rules/require-dynamic-firebase-imports.js +2 -1
- package/lib/rules/require-image-optimized.js +1 -1
- package/lib/rules/require-memo.js +11 -1
- package/lib/rules/require-usememo-object-literals.js +7 -1
- package/lib/rules/semantic-function-prefixes.js +38 -18
- package/lib/rules/sync-onwrite-name-func.js +5 -1
- package/lib/rules/test-file-location-enforcement.d.ts +1 -0
- package/lib/rules/test-file-location-enforcement.js +57 -0
- package/lib/rules/use-custom-link.js +6 -1
- package/lib/rules/use-custom-router.js +6 -1
- package/lib/rules/use-latest-callback.d.ts +3 -0
- package/lib/rules/use-latest-callback.js +270 -0
- package/lib/utils/ASTHelpers.js +10 -0
- package/lib/utils/createRule.js +1 -1
- package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
- package/lib/utils/ruleTester.d.ts +1 -0
- package/lib/utils/ruleTester.js +4 -1
- package/package.json +21 -14
- package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
|
@@ -3,60 +3,23 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.enforcePropsArgumentName = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
5
|
const createRule_1 = require("../utils/createRule");
|
|
6
|
-
const defaultOptions = {
|
|
7
|
-
enforceDestructuring: false,
|
|
8
|
-
ignoreExternalInterfaces: true,
|
|
9
|
-
};
|
|
10
6
|
exports.enforcePropsArgumentName = (0, createRule_1.createRule)({
|
|
11
7
|
name: 'enforce-props-argument-name',
|
|
12
8
|
meta: {
|
|
13
9
|
type: 'suggestion',
|
|
14
10
|
docs: {
|
|
15
|
-
description: '
|
|
11
|
+
description: 'Authoritative rule: parameters with types ending in "Props" should be named "props" (or prefixed variants when multiple Props params exist)',
|
|
16
12
|
recommended: 'error',
|
|
17
13
|
},
|
|
18
14
|
fixable: 'code',
|
|
19
|
-
schema: [
|
|
20
|
-
{
|
|
21
|
-
type: 'object',
|
|
22
|
-
properties: {
|
|
23
|
-
enforceDestructuring: {
|
|
24
|
-
type: 'boolean',
|
|
25
|
-
},
|
|
26
|
-
ignoreExternalInterfaces: {
|
|
27
|
-
type: 'boolean',
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
additionalProperties: false,
|
|
31
|
-
},
|
|
32
|
-
],
|
|
15
|
+
schema: [],
|
|
33
16
|
messages: {
|
|
34
|
-
|
|
17
|
+
usePropsParameterName: 'Parameter with type "{{ typeName }}" should be named "props"',
|
|
18
|
+
usePropsParameterNameWithPrefix: 'Parameter with type "{{ typeName }}" should be named "{{ suggestedName }}"',
|
|
35
19
|
},
|
|
36
20
|
},
|
|
37
|
-
defaultOptions: [
|
|
38
|
-
create(context
|
|
39
|
-
const finalOptions = { ...defaultOptions, ...options };
|
|
40
|
-
// Check if a node is from an external library
|
|
41
|
-
function isFromExternalLibrary(node) {
|
|
42
|
-
if (!finalOptions.ignoreExternalInterfaces) {
|
|
43
|
-
return false;
|
|
44
|
-
}
|
|
45
|
-
let current = node;
|
|
46
|
-
while (current.parent) {
|
|
47
|
-
if (current.type === utils_1.AST_NODE_TYPES.TSInterfaceDeclaration) {
|
|
48
|
-
// Check if the interface extends something from an external library
|
|
49
|
-
const interfaceDecl = current;
|
|
50
|
-
if (interfaceDecl.extends && interfaceDecl.extends.length > 0) {
|
|
51
|
-
// Check if any of the extended interfaces are from external libraries
|
|
52
|
-
// This is a simplified check - a more robust implementation would trace imports
|
|
53
|
-
return true;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
current = current.parent;
|
|
57
|
-
}
|
|
58
|
-
return false;
|
|
59
|
-
}
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
create(context) {
|
|
60
23
|
// Extract type name from a type annotation
|
|
61
24
|
function getTypeName(typeAnnotation) {
|
|
62
25
|
if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
@@ -67,137 +30,188 @@ exports.enforcePropsArgumentName = (0, createRule_1.createRule)({
|
|
|
67
30
|
}
|
|
68
31
|
return null;
|
|
69
32
|
}
|
|
70
|
-
// Check if a type name
|
|
71
|
-
function
|
|
72
|
-
|
|
73
|
-
|
|
33
|
+
// Check if a type name ends with "Props"
|
|
34
|
+
function endsWithProps(typeName) {
|
|
35
|
+
return typeName.endsWith('Props');
|
|
36
|
+
}
|
|
37
|
+
// Generate suggested parameter name for Props types
|
|
38
|
+
function getSuggestedParameterName(typeName, allParams, currentParam) {
|
|
39
|
+
const currentId = getIdFromParam(currentParam);
|
|
40
|
+
const currentName = currentId?.name;
|
|
41
|
+
const existingNames = new Set(allParams
|
|
42
|
+
.map((p) => getIdFromParam(p))
|
|
43
|
+
.filter((id) => !!id && id.name !== currentName)
|
|
44
|
+
.map((id) => id.name));
|
|
45
|
+
if (typeName === 'Props') {
|
|
46
|
+
let candidate = 'props';
|
|
47
|
+
let suffix = 2;
|
|
48
|
+
while (existingNames.has(candidate)) {
|
|
49
|
+
candidate = `props${suffix++}`;
|
|
50
|
+
}
|
|
51
|
+
return candidate;
|
|
74
52
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
'Arguments',
|
|
83
|
-
];
|
|
84
|
-
for (const suffix of suffixes) {
|
|
85
|
-
if (typeName.endsWith(suffix)) {
|
|
86
|
-
return suffix;
|
|
53
|
+
// Count how many parameters have Props types
|
|
54
|
+
const propsParams = allParams.filter((param) => {
|
|
55
|
+
if (param.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
56
|
+
param.typeAnnotation &&
|
|
57
|
+
param.typeAnnotation.typeAnnotation) {
|
|
58
|
+
const paramTypeName = getTypeName(param.typeAnnotation.typeAnnotation);
|
|
59
|
+
return paramTypeName && endsWithProps(paramTypeName);
|
|
87
60
|
}
|
|
61
|
+
return false;
|
|
62
|
+
});
|
|
63
|
+
// If there's only one Props parameter, suggest "props"
|
|
64
|
+
if (propsParams.length <= 1) {
|
|
65
|
+
let candidate = 'props';
|
|
66
|
+
let suffix = 2;
|
|
67
|
+
while (existingNames.has(candidate)) {
|
|
68
|
+
candidate = `props${suffix++}`;
|
|
69
|
+
}
|
|
70
|
+
return candidate;
|
|
88
71
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
72
|
+
// If there are multiple Props parameters, use prefixed names
|
|
73
|
+
// For types like "UserProps", suggest "userProps"
|
|
74
|
+
const baseName = typeName.slice(0, -5); // Remove "Props"
|
|
75
|
+
const camelCaseBase = baseName.charAt(0).toLowerCase() + baseName.slice(1);
|
|
76
|
+
let candidate = `${camelCaseBase}Props`;
|
|
77
|
+
let i = 2;
|
|
78
|
+
while (existingNames.has(candidate)) {
|
|
79
|
+
candidate = `${camelCaseBase}Props${i++}`;
|
|
97
80
|
}
|
|
98
|
-
return
|
|
81
|
+
return candidate;
|
|
99
82
|
}
|
|
100
|
-
// Check
|
|
101
|
-
function
|
|
102
|
-
if (
|
|
103
|
-
|
|
83
|
+
// Check if parameter is destructured
|
|
84
|
+
function isDestructuredParameter(param) {
|
|
85
|
+
if (param.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
86
|
+
param.type === utils_1.AST_NODE_TYPES.ArrayPattern) {
|
|
87
|
+
return true;
|
|
104
88
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
(param.typeAnnotation.typeAnnotation.type ===
|
|
110
|
-
utils_1.AST_NODE_TYPES.TSStringKeyword ||
|
|
111
|
-
param.typeAnnotation.typeAnnotation.type ===
|
|
112
|
-
utils_1.AST_NODE_TYPES.TSNumberKeyword ||
|
|
113
|
-
param.typeAnnotation.typeAnnotation.type ===
|
|
114
|
-
utils_1.AST_NODE_TYPES.TSBooleanKeyword)) {
|
|
115
|
-
return;
|
|
89
|
+
if (param.type === utils_1.AST_NODE_TYPES.AssignmentPattern &&
|
|
90
|
+
(param.left.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
91
|
+
param.left.type === utils_1.AST_NODE_TYPES.ArrayPattern)) {
|
|
92
|
+
return true;
|
|
116
93
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
messageId: 'usePropsForType',
|
|
128
|
-
data: { typeSuffix: nonPropsSuffix },
|
|
129
|
-
fix: (fixer) => fixTypeName(fixer, param.typeAnnotation.typeAnnotation, typeName, nonPropsSuffix),
|
|
130
|
-
});
|
|
131
|
-
}
|
|
94
|
+
if (param.type === utils_1.AST_NODE_TYPES.TSParameterProperty) {
|
|
95
|
+
const inner = param.parameter;
|
|
96
|
+
if (inner.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
97
|
+
inner.type === utils_1.AST_NODE_TYPES.ArrayPattern) {
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
if (inner.type === utils_1.AST_NODE_TYPES.AssignmentPattern &&
|
|
101
|
+
(inner.left.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
102
|
+
inner.left.type === utils_1.AST_NODE_TYPES.ArrayPattern)) {
|
|
103
|
+
return true;
|
|
132
104
|
}
|
|
133
105
|
}
|
|
106
|
+
return false;
|
|
134
107
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
108
|
+
function getIdFromParam(param) {
|
|
109
|
+
if (param.type === utils_1.AST_NODE_TYPES.Identifier)
|
|
110
|
+
return param;
|
|
111
|
+
if (param.type === utils_1.AST_NODE_TYPES.AssignmentPattern &&
|
|
112
|
+
param.left.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
113
|
+
return param.left;
|
|
139
114
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
(param.typeAnnotation.typeAnnotation.type ===
|
|
149
|
-
utils_1.AST_NODE_TYPES.TSStringKeyword ||
|
|
150
|
-
param.typeAnnotation.typeAnnotation.type ===
|
|
151
|
-
utils_1.AST_NODE_TYPES.TSNumberKeyword ||
|
|
152
|
-
param.typeAnnotation.typeAnnotation.type ===
|
|
153
|
-
utils_1.AST_NODE_TYPES.TSBooleanKeyword)) {
|
|
154
|
-
return;
|
|
115
|
+
if (param.type === utils_1.AST_NODE_TYPES.TSParameterProperty) {
|
|
116
|
+
const inner = param.parameter;
|
|
117
|
+
if (inner.type === utils_1.AST_NODE_TYPES.Identifier)
|
|
118
|
+
return inner;
|
|
119
|
+
if (inner.type === utils_1.AST_NODE_TYPES.AssignmentPattern &&
|
|
120
|
+
inner.left.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
121
|
+
return inner.left;
|
|
122
|
+
}
|
|
155
123
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
param.typeAnnotation.typeAnnotation) {
|
|
160
|
-
const typeName = getTypeName(param.typeAnnotation.typeAnnotation);
|
|
161
|
-
if (typeName) {
|
|
162
|
-
const nonPropsSuffix = hasNonPropsSuffix(typeName);
|
|
163
|
-
if (nonPropsSuffix) {
|
|
164
|
-
context.report({
|
|
165
|
-
node: param.typeAnnotation.typeAnnotation,
|
|
166
|
-
messageId: 'usePropsForType',
|
|
167
|
-
data: { typeSuffix: nonPropsSuffix },
|
|
168
|
-
fix: (fixer) => fixTypeName(fixer, param.typeAnnotation.typeAnnotation, typeName, nonPropsSuffix),
|
|
169
|
-
});
|
|
170
|
-
}
|
|
124
|
+
if (param.type === utils_1.AST_NODE_TYPES.RestElement) {
|
|
125
|
+
if (param.argument.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
126
|
+
return param.argument;
|
|
171
127
|
}
|
|
172
128
|
}
|
|
129
|
+
return null;
|
|
173
130
|
}
|
|
174
|
-
// Check
|
|
175
|
-
function
|
|
176
|
-
|
|
131
|
+
// Check function parameters
|
|
132
|
+
function checkFunctionParams(node) {
|
|
133
|
+
// Skip function expressions that are part of method definitions
|
|
134
|
+
// to avoid duplicate processing
|
|
135
|
+
if (node.type === utils_1.AST_NODE_TYPES.FunctionExpression &&
|
|
136
|
+
node.parent &&
|
|
137
|
+
node.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition) {
|
|
177
138
|
return;
|
|
178
139
|
}
|
|
179
|
-
const
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
140
|
+
const sourceCode = context.getSourceCode();
|
|
141
|
+
node.params.forEach((param) => {
|
|
142
|
+
if (isDestructuredParameter(param)) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const id = getIdFromParam(param);
|
|
146
|
+
if (id && id.typeAnnotation && id.typeAnnotation.typeAnnotation) {
|
|
147
|
+
const typeName = getTypeName(id.typeAnnotation.typeAnnotation);
|
|
148
|
+
if (typeName && endsWithProps(typeName)) {
|
|
149
|
+
const suggestedName = getSuggestedParameterName(typeName, node.params, param);
|
|
150
|
+
if (id.name !== suggestedName) {
|
|
151
|
+
const messageId = suggestedName === 'props'
|
|
152
|
+
? 'usePropsParameterName'
|
|
153
|
+
: 'usePropsParameterNameWithPrefix';
|
|
154
|
+
context.report({
|
|
155
|
+
node: id,
|
|
156
|
+
messageId,
|
|
157
|
+
data: {
|
|
158
|
+
typeName,
|
|
159
|
+
suggestedName,
|
|
160
|
+
},
|
|
161
|
+
fix: (fixer) => {
|
|
162
|
+
const token = sourceCode.getFirstToken(id);
|
|
163
|
+
if (!token)
|
|
164
|
+
return null;
|
|
165
|
+
return fixer.replaceTextRange([token.range[0], token.range[1]], suggestedName);
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Check class method parameters (including constructors)
|
|
174
|
+
function checkClassMethod(node) {
|
|
175
|
+
const method = node.value;
|
|
176
|
+
const sourceCode = context.getSourceCode();
|
|
177
|
+
method.params.forEach((param) => {
|
|
178
|
+
if (isDestructuredParameter(param)) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
const id = getIdFromParam(param);
|
|
182
|
+
if (id && id.typeAnnotation && id.typeAnnotation.typeAnnotation) {
|
|
183
|
+
const typeName = getTypeName(id.typeAnnotation.typeAnnotation);
|
|
184
|
+
if (typeName && endsWithProps(typeName)) {
|
|
185
|
+
const suggestedName = getSuggestedParameterName(typeName, method.params, param);
|
|
186
|
+
if (id.name !== suggestedName) {
|
|
187
|
+
const messageId = suggestedName === 'props'
|
|
188
|
+
? 'usePropsParameterName'
|
|
189
|
+
: 'usePropsParameterNameWithPrefix';
|
|
190
|
+
context.report({
|
|
191
|
+
node: id,
|
|
192
|
+
messageId,
|
|
193
|
+
data: {
|
|
194
|
+
typeName,
|
|
195
|
+
suggestedName,
|
|
196
|
+
},
|
|
197
|
+
fix: (fixer) => {
|
|
198
|
+
const token = sourceCode.getFirstToken(id);
|
|
199
|
+
if (!token)
|
|
200
|
+
return null;
|
|
201
|
+
return fixer.replaceTextRange([token.range[0], token.range[1]], suggestedName);
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
193
208
|
}
|
|
194
209
|
return {
|
|
195
210
|
FunctionDeclaration: checkFunctionParams,
|
|
196
211
|
FunctionExpression: checkFunctionParams,
|
|
197
212
|
ArrowFunctionExpression: checkFunctionParams,
|
|
198
213
|
TSMethodSignature: checkFunctionParams,
|
|
199
|
-
MethodDefinition:
|
|
200
|
-
TSTypeAliasDeclaration: checkTypeDefinition,
|
|
214
|
+
MethodDefinition: checkClassMethod,
|
|
201
215
|
};
|
|
202
216
|
},
|
|
203
217
|
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enforcePropsNamingConsistency = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
exports.enforcePropsNamingConsistency = (0, createRule_1.createRule)({
|
|
7
|
+
name: 'enforce-props-naming-consistency',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'suggestion',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Prefer naming single "Props"-typed parameters as "props"; enforcement defers to enforce-props-argument-name for multi-Props cases',
|
|
12
|
+
recommended: 'warn',
|
|
13
|
+
},
|
|
14
|
+
fixable: 'code',
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
usePropsName: 'Parameter with a type ending in "Props" should be named "props" instead of "{{ paramName }}"',
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
// Extract type name from a type annotation
|
|
23
|
+
function getTypeName(typeAnnotation) {
|
|
24
|
+
if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
25
|
+
const typeName = typeAnnotation.typeName;
|
|
26
|
+
if (typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
27
|
+
return typeName.name;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
// Check if a parameter should be named "props"
|
|
33
|
+
function shouldBeNamedProps(param) {
|
|
34
|
+
// Only check non-destructured parameters
|
|
35
|
+
if (param.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
// Check if the parameter has a type annotation
|
|
39
|
+
if (!param.typeAnnotation || !param.typeAnnotation.typeAnnotation) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
// Get the type name
|
|
43
|
+
const typeName = getTypeName(param.typeAnnotation.typeAnnotation);
|
|
44
|
+
if (!typeName) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
// Check if the type name ends with "Props"
|
|
48
|
+
return typeName.endsWith('Props');
|
|
49
|
+
}
|
|
50
|
+
// Check if a parameter name is already prefixed with "props"
|
|
51
|
+
function isPropsNameWithPrefix(paramName) {
|
|
52
|
+
return paramName.endsWith('Props') || paramName === 'props';
|
|
53
|
+
}
|
|
54
|
+
// Fix parameter name to "props"
|
|
55
|
+
function fixParameterName(fixer, param) {
|
|
56
|
+
return fixer.replaceText(param, 'props');
|
|
57
|
+
}
|
|
58
|
+
// Check function parameters
|
|
59
|
+
function checkFunctionParams(node) {
|
|
60
|
+
// Skip functions with multiple parameters that have Props types
|
|
61
|
+
const propsTypeParams = node.params.filter((param) => {
|
|
62
|
+
if (param.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
63
|
+
return false;
|
|
64
|
+
if (!param.typeAnnotation || !param.typeAnnotation.typeAnnotation)
|
|
65
|
+
return false;
|
|
66
|
+
const typeName = getTypeName(param.typeAnnotation.typeAnnotation);
|
|
67
|
+
return typeName && typeName.endsWith('Props');
|
|
68
|
+
});
|
|
69
|
+
if (propsTypeParams.length > 1) {
|
|
70
|
+
return; // Skip functions with multiple Props parameters
|
|
71
|
+
}
|
|
72
|
+
for (const param of node.params) {
|
|
73
|
+
if (shouldBeNamedProps(param) &&
|
|
74
|
+
param.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
75
|
+
!isPropsNameWithPrefix(param.name)) {
|
|
76
|
+
context.report({
|
|
77
|
+
node: param,
|
|
78
|
+
messageId: 'usePropsName',
|
|
79
|
+
data: { paramName: param.name },
|
|
80
|
+
fix: (fixer) => fixParameterName(fixer, param),
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Check class constructor parameters
|
|
86
|
+
function checkClassConstructor(node) {
|
|
87
|
+
if (node.kind !== 'constructor') {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const constructor = node.value;
|
|
91
|
+
// Skip constructors with multiple parameters that have Props types
|
|
92
|
+
const propsTypeParams = constructor.params.filter((param) => {
|
|
93
|
+
if (param.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
94
|
+
if (!param.typeAnnotation || !param.typeAnnotation.typeAnnotation)
|
|
95
|
+
return false;
|
|
96
|
+
const typeName = getTypeName(param.typeAnnotation.typeAnnotation);
|
|
97
|
+
return typeName && typeName.endsWith('Props');
|
|
98
|
+
}
|
|
99
|
+
else if (param.type === utils_1.AST_NODE_TYPES.TSParameterProperty &&
|
|
100
|
+
param.parameter.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
101
|
+
if (!param.parameter.typeAnnotation ||
|
|
102
|
+
!param.parameter.typeAnnotation.typeAnnotation)
|
|
103
|
+
return false;
|
|
104
|
+
const typeName = getTypeName(param.parameter.typeAnnotation.typeAnnotation);
|
|
105
|
+
return typeName && typeName.endsWith('Props');
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
});
|
|
109
|
+
if (propsTypeParams.length > 1) {
|
|
110
|
+
return; // Skip constructors with multiple Props parameters
|
|
111
|
+
}
|
|
112
|
+
for (const param of constructor.params) {
|
|
113
|
+
if (shouldBeNamedProps(param) &&
|
|
114
|
+
param.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
115
|
+
!isPropsNameWithPrefix(param.name)) {
|
|
116
|
+
context.report({
|
|
117
|
+
node: param,
|
|
118
|
+
messageId: 'usePropsName',
|
|
119
|
+
data: { paramName: param.name },
|
|
120
|
+
fix: (fixer) => fixParameterName(fixer, param),
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
else if (param.type === utils_1.AST_NODE_TYPES.TSParameterProperty &&
|
|
124
|
+
param.parameter.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
125
|
+
shouldBeNamedProps(param.parameter) &&
|
|
126
|
+
!isPropsNameWithPrefix(param.parameter.name)) {
|
|
127
|
+
context.report({
|
|
128
|
+
node: param.parameter,
|
|
129
|
+
messageId: 'usePropsName',
|
|
130
|
+
data: { paramName: param.parameter.name },
|
|
131
|
+
fix: (fixer) => fixParameterName(fixer, param.parameter),
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
FunctionDeclaration: checkFunctionParams,
|
|
138
|
+
FunctionExpression: checkFunctionParams,
|
|
139
|
+
ArrowFunctionExpression: checkFunctionParams,
|
|
140
|
+
TSMethodSignature: checkFunctionParams,
|
|
141
|
+
MethodDefinition: checkClassConstructor,
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=enforce-props-naming-consistency.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type MessageIds = 'enforceQueryKeyImport' | 'enforceQueryKeyConstant';
|
|
3
|
+
/**
|
|
4
|
+
* Rule to enforce the use of centralized router state key constants imported from
|
|
5
|
+
* `src/util/routing/queryKeys.ts` instead of arbitrary string literals when calling
|
|
6
|
+
* router methods that accept key parameters.
|
|
7
|
+
*/
|
|
8
|
+
export declare const enforceQueryKeyTs: TSESLint.RuleModule<MessageIds, [], TSESLint.RuleListener>;
|
|
9
|
+
export {};
|