@blumintinc/eslint-plugin-blumint 1.13.0 → 1.14.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 +170 -139
- package/lib/index.js +190 -1
- package/lib/rules/array-methods-this-context.js +1 -1
- package/lib/rules/class-methods-read-top-to-bottom.js +24 -5
- package/lib/rules/consistent-callback-naming.js +1 -1
- package/lib/rules/dynamic-https-errors.js +3 -4
- package/lib/rules/enforce-assert-safe-object-key.js +11 -11
- package/lib/rules/enforce-boolean-naming-prefixes.js +11 -23
- package/lib/rules/enforce-callback-memo.js +1 -1
- package/lib/rules/enforce-centralized-mock-firestore.js +1 -1
- package/lib/rules/enforce-console-error.js +35 -7
- package/lib/rules/enforce-dynamic-file-naming.d.ts +2 -0
- package/lib/rules/enforce-dynamic-file-naming.js +53 -28
- package/lib/rules/enforce-early-destructuring.d.ts +2 -0
- package/lib/rules/enforce-early-destructuring.js +980 -0
- package/lib/rules/enforce-empty-object-check.d.ts +11 -0
- package/lib/rules/enforce-empty-object-check.js +502 -0
- package/lib/rules/enforce-exported-function-types.js +1 -1
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +100 -50
- package/lib/rules/enforce-firestore-doc-ref-generic.js +15 -3
- package/lib/rules/enforce-firestore-facade.js +4 -2
- package/lib/rules/enforce-firestore-set-merge.js +3 -4
- package/lib/rules/enforce-global-constants.js +1 -1
- package/lib/rules/enforce-identifiable-firestore-type.js +108 -58
- package/lib/rules/enforce-memoize-async.js +2 -6
- package/lib/rules/enforce-memoize-getters.js +39 -15
- package/lib/rules/enforce-microdiff.js +1 -1
- package/lib/rules/enforce-object-literal-as-const.js +4 -4
- package/lib/rules/enforce-positive-naming.js +4 -0
- package/lib/rules/enforce-props-argument-name.js +2 -2
- package/lib/rules/enforce-safe-stringify.js +1 -1
- package/lib/rules/enforce-serializable-params.js +3 -3
- package/lib/rules/enforce-singular-type-names.js +1 -1
- package/lib/rules/enforce-stable-hash-spread-props.d.ts +13 -0
- package/lib/rules/enforce-stable-hash-spread-props.js +342 -0
- package/lib/rules/enforce-storage-context.d.ts +9 -0
- package/lib/rules/enforce-storage-context.js +646 -0
- package/lib/rules/enforce-timestamp-now.js +23 -7
- package/lib/rules/enforce-transform-memoization.d.ts +4 -0
- package/lib/rules/enforce-transform-memoization.js +416 -0
- package/lib/rules/enforce-typescript-markdown-code-blocks.js +7 -3
- package/lib/rules/enforce-unique-cursor-headers.d.ts +16 -0
- package/lib/rules/enforce-unique-cursor-headers.js +365 -0
- package/lib/rules/enforce-verb-noun-naming.js +5 -4
- package/lib/rules/ensure-pointer-events-none.js +28 -2
- package/lib/rules/export-if-in-doubt.js +27 -4
- package/lib/rules/extract-global-constants.js +40 -13
- package/lib/rules/fast-deep-equal-over-microdiff.js +29 -39
- package/lib/rules/firestore-transaction-reads-before-writes.js +50 -4
- package/lib/rules/flatten-push-calls.d.ts +2 -0
- package/lib/rules/flatten-push-calls.js +428 -0
- package/lib/rules/global-const-style.js +50 -19
- package/lib/rules/jsdoc-above-field.d.ts +11 -0
- package/lib/rules/jsdoc-above-field.js +208 -0
- package/lib/rules/key-only-outermost-element.js +21 -3
- package/lib/rules/logical-top-to-bottom-grouping.d.ts +5 -0
- package/lib/rules/logical-top-to-bottom-grouping.js +1258 -0
- package/lib/rules/memo-compare-deeply-complex-props.d.ts +3 -0
- package/lib/rules/memo-compare-deeply-complex-props.js +788 -0
- package/lib/rules/memo-nested-react-components.d.ts +8 -0
- package/lib/rules/memo-nested-react-components.js +410 -0
- package/lib/rules/no-always-true-false-conditions.d.ts +2 -1
- package/lib/rules/no-always-true-false-conditions.js +68 -8
- package/lib/rules/no-array-length-in-deps.js +9 -3
- package/lib/rules/no-async-foreach.js +210 -12
- package/lib/rules/no-circular-references.js +18 -17
- package/lib/rules/no-class-instance-destructuring.js +55 -12
- package/lib/rules/no-complex-cloud-params.js +7 -3
- package/lib/rules/no-compositing-layer-props.js +2 -2
- package/lib/rules/no-conditional-literals-in-jsx.js +37 -12
- package/lib/rules/no-console-error.d.ts +9 -0
- package/lib/rules/no-console-error.js +525 -0
- package/lib/rules/no-curly-brackets-around-commented-properties.d.ts +2 -0
- package/lib/rules/no-curly-brackets-around-commented-properties.js +258 -0
- package/lib/rules/no-empty-dependency-use-callbacks.d.ts +11 -0
- package/lib/rules/no-empty-dependency-use-callbacks.js +576 -0
- package/lib/rules/no-entire-object-hook-deps.js +4 -6
- package/lib/rules/no-excessive-parent-chain.js +1 -1
- package/lib/rules/no-explicit-return-type.d.ts +2 -1
- package/lib/rules/no-explicit-return-type.js +215 -26
- package/lib/rules/no-filter-without-return.js +5 -1
- package/lib/rules/no-firestore-jest-mock.d.ts +2 -1
- package/lib/rules/no-firestore-jest-mock.js +126 -8
- package/lib/rules/no-firestore-object-arrays.js +67 -12
- package/lib/rules/no-handler-suffix.d.ts +12 -0
- package/lib/rules/no-handler-suffix.js +305 -0
- package/lib/rules/no-hungarian.js +1 -1
- package/lib/rules/no-inline-component-prop.d.ts +10 -0
- package/lib/rules/no-inline-component-prop.js +456 -0
- package/lib/rules/no-jsx-in-hooks.js +6 -1
- package/lib/rules/no-jsx-whitespace-literal.js +8 -2
- package/lib/rules/no-margin-properties.js +6 -6
- package/lib/rules/no-memoize-on-static.js +9 -1
- package/lib/rules/no-misleading-boolean-prefixes.js +7 -3
- package/lib/rules/no-misused-switch-case.js +22 -1
- package/lib/rules/no-mixed-firestore-transactions.d.ts +3 -1
- package/lib/rules/no-mixed-firestore-transactions.js +296 -34
- package/lib/rules/no-mock-firebase-admin.js +5 -2
- package/lib/rules/no-object-values-on-strings.js +10 -2
- package/lib/rules/no-overridable-method-calls-in-constructor.js +29 -17
- package/lib/rules/no-passthrough-getters.js +38 -2
- package/lib/rules/no-redundant-annotation-assertion.d.ts +2 -0
- package/lib/rules/no-redundant-annotation-assertion.js +402 -0
- package/lib/rules/no-redundant-param-types.js +16 -6
- package/lib/rules/no-redundant-this-params.d.ts +3 -0
- package/lib/rules/no-redundant-this-params.js +459 -0
- package/lib/rules/no-redundant-usecallback-wrapper.js +16 -3
- package/lib/rules/no-res-error-status-in-onrequest.d.ts +4 -0
- package/lib/rules/no-res-error-status-in-onrequest.js +521 -0
- package/lib/rules/no-restricted-properties-fix.js +11 -10
- package/lib/rules/no-separate-loading-state.js +7 -16
- package/lib/rules/no-stale-state-across-await.js +1 -1
- package/lib/rules/no-type-assertion-returns.js +43 -49
- package/lib/rules/no-undefined-null-passthrough.js +61 -31
- package/lib/rules/no-unmemoized-memo-without-props.d.ts +8 -0
- package/lib/rules/no-unmemoized-memo-without-props.js +426 -0
- package/lib/rules/no-unnecessary-destructuring-rename.d.ts +2 -0
- package/lib/rules/no-unnecessary-destructuring-rename.js +347 -0
- package/lib/rules/no-unnecessary-destructuring.js +14 -4
- package/lib/rules/no-unnecessary-verb-suffix.js +2 -1
- package/lib/rules/no-unpinned-dependencies.js +36 -5
- package/lib/rules/no-unused-props.d.ts +2 -2
- package/lib/rules/no-unused-props.js +295 -91
- package/lib/rules/no-unused-usestate.js +6 -2
- package/lib/rules/no-useless-fragment.js +28 -2
- package/lib/rules/no-useless-usememo-primitives.d.ts +9 -0
- package/lib/rules/no-useless-usememo-primitives.js +393 -0
- package/lib/rules/no-usememo-for-pass-by-value.d.ts +13 -0
- package/lib/rules/no-usememo-for-pass-by-value.js +757 -0
- package/lib/rules/no-uuidv4-base62-as-key.js +18 -13
- package/lib/rules/omit-index-html.d.ts +2 -1
- package/lib/rules/omit-index-html.js +62 -7
- package/lib/rules/optimize-object-boolean-conditions.js +6 -4
- package/lib/rules/parallelize-async-operations.js +24 -5
- package/lib/rules/prefer-batch-operations.d.ts +1 -3
- package/lib/rules/prefer-batch-operations.js +32 -5
- package/lib/rules/prefer-block-comments-for-declarations.js +9 -4
- package/lib/rules/prefer-clone-deep.js +3 -3
- package/lib/rules/prefer-destructuring-no-class.d.ts +2 -1
- package/lib/rules/prefer-destructuring-no-class.js +244 -59
- package/lib/rules/prefer-docsetter-setall.d.ts +2 -0
- package/lib/rules/prefer-docsetter-setall.js +243 -0
- package/lib/rules/prefer-field-paths-in-transforms.js +4 -3
- package/lib/rules/prefer-fragment-component.js +1 -1
- package/lib/rules/prefer-fragment-shorthand.js +2 -1
- package/lib/rules/prefer-getter-over-parameterless-method.d.ts +13 -0
- package/lib/rules/prefer-getter-over-parameterless-method.js +648 -0
- package/lib/rules/prefer-global-router-state-key.js +88 -13
- package/lib/rules/prefer-memoized-props.d.ts +3 -0
- package/lib/rules/prefer-memoized-props.js +445 -0
- package/lib/rules/prefer-next-dynamic.js +60 -69
- package/lib/rules/prefer-nullish-coalescing-boolean-props.js +9 -4
- package/lib/rules/prefer-nullish-coalescing-override.d.ts +2 -1
- package/lib/rules/prefer-nullish-coalescing-override.js +11 -5
- package/lib/rules/prefer-params-over-parent-id.js +220 -171
- package/lib/rules/prefer-settings-object.js +2 -2
- package/lib/rules/prefer-type-over-interface.js +7 -2
- package/lib/rules/prefer-url-tostring-over-tojson.js +6 -3
- package/lib/rules/prefer-use-deep-compare-memo.js +8 -5
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +1 -1
- package/lib/rules/prefer-utility-function-over-private-static.js +34 -2
- package/lib/rules/prevent-children-clobber.d.ts +2 -0
- package/lib/rules/prevent-children-clobber.js +536 -0
- package/lib/rules/react-memoize-literals.d.ts +4 -0
- package/lib/rules/react-memoize-literals.js +495 -0
- package/lib/rules/react-usememo-should-be-component.js +2 -2
- package/lib/rules/require-hooks-default-params.js +17 -16
- package/lib/rules/require-https-error-cause.d.ts +4 -0
- package/lib/rules/require-https-error-cause.js +136 -0
- package/lib/rules/require-https-error.js +43 -21
- package/lib/rules/require-image-optimized.js +1 -1
- package/lib/rules/require-memo.js +1 -1
- package/lib/rules/require-memoize-jsx-returners.d.ts +3 -0
- package/lib/rules/require-memoize-jsx-returners.js +485 -0
- package/lib/rules/require-usememo-object-literals.js +2 -3
- package/lib/rules/test-file-location-enforcement.js +1 -1
- package/lib/rules/use-latest-callback.js +6 -5
- package/lib/rules/vertically-group-related-functions.d.ts +16 -0
- package/lib/rules/vertically-group-related-functions.js +480 -0
- package/lib/utils/ASTHelpers.d.ts +13 -1
- package/lib/utils/ASTHelpers.js +24 -0
- package/lib/utils/getMethodName.d.ts +27 -0
- package/lib/utils/getMethodName.js +35 -0
- package/lib/utils/tsTypeClassifier.d.ts +30 -0
- package/lib/utils/tsTypeClassifier.js +149 -0
- package/package.json +3 -1
|
@@ -104,7 +104,7 @@ exports.preferDestructuringNoClass = (0, createRule_1.createRule)({
|
|
|
104
104
|
},
|
|
105
105
|
],
|
|
106
106
|
messages: {
|
|
107
|
-
preferDestructuring: '
|
|
107
|
+
preferDestructuring: 'Property "{{property}}" from "{{object}}" is assigned via dot access{{targetNote}}. Destructure the property so the dependency is declared once and stays aligned with the source object. Use destructuring{{renamingHint}} (e.g., {{example}}).',
|
|
108
108
|
},
|
|
109
109
|
},
|
|
110
110
|
defaultOptions,
|
|
@@ -114,6 +114,7 @@ exports.preferDestructuringNoClass = (0, createRule_1.createRule)({
|
|
|
114
114
|
enforceForRenamedProperties: defaultOptions[0].enforceForRenamedProperties,
|
|
115
115
|
...context.options[0],
|
|
116
116
|
};
|
|
117
|
+
const sourceCode = context.getSourceCode();
|
|
117
118
|
/**
|
|
118
119
|
* Check if we're inside a class method
|
|
119
120
|
*/
|
|
@@ -128,32 +129,228 @@ exports.preferDestructuringNoClass = (0, createRule_1.createRule)({
|
|
|
128
129
|
}
|
|
129
130
|
return false;
|
|
130
131
|
}
|
|
132
|
+
function isIdentifierTarget(node) {
|
|
133
|
+
return node.type === utils_1.AST_NODE_TYPES.Identifier;
|
|
134
|
+
}
|
|
135
|
+
function isSkippedClassMemberAccess(memberExpression) {
|
|
136
|
+
return (isClassInstance(memberExpression, context) ||
|
|
137
|
+
isStaticClassMember(memberExpression, context));
|
|
138
|
+
}
|
|
139
|
+
function isThisMemberInClassMethod(memberExpression) {
|
|
140
|
+
return (memberExpression.object.type === utils_1.AST_NODE_TYPES.ThisExpression &&
|
|
141
|
+
isInsideClassMethod(memberExpression));
|
|
142
|
+
}
|
|
143
|
+
function findEnclosingMethodDefinition(node) {
|
|
144
|
+
let current = node;
|
|
145
|
+
while (current) {
|
|
146
|
+
if (current.type === utils_1.AST_NODE_TYPES.MethodDefinition) {
|
|
147
|
+
return current;
|
|
148
|
+
}
|
|
149
|
+
current = current.parent ?? undefined;
|
|
150
|
+
}
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
function isInsideConstructorBody(node) {
|
|
154
|
+
let current = node;
|
|
155
|
+
while (current) {
|
|
156
|
+
if (current.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
|
|
157
|
+
current.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
158
|
+
current.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
159
|
+
const enclosingMethod = findEnclosingMethodDefinition(current);
|
|
160
|
+
return (!!enclosingMethod &&
|
|
161
|
+
enclosingMethod.kind === 'constructor' &&
|
|
162
|
+
enclosingMethod.value === current);
|
|
163
|
+
}
|
|
164
|
+
current = current.parent ?? undefined;
|
|
165
|
+
}
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
function isPrivateIdentifierProperty(property) {
|
|
169
|
+
return property.type === utils_1.AST_NODE_TYPES.PrivateIdentifier;
|
|
170
|
+
}
|
|
171
|
+
function canDestructureObjectProperty(memberExpression, identifier) {
|
|
172
|
+
if (isPrivateIdentifierProperty(memberExpression.property)) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
if (!options.object) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
if (options.enforceForRenamedProperties) {
|
|
179
|
+
return true;
|
|
180
|
+
}
|
|
181
|
+
return isMatchingPropertyName(memberExpression.property, identifier.name);
|
|
182
|
+
}
|
|
183
|
+
function getPatternKeyText(memberExpression, propertyText) {
|
|
184
|
+
if (memberExpression.computed) {
|
|
185
|
+
return `[${sourceCode.getText(memberExpression.property)}]`;
|
|
186
|
+
}
|
|
187
|
+
return propertyText;
|
|
188
|
+
}
|
|
189
|
+
function getDestructuringBindingText(memberExpression, propertyText, targetName) {
|
|
190
|
+
if (isPrivateIdentifierProperty(memberExpression.property)) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
const patternKeyText = getPatternKeyText(memberExpression, propertyText);
|
|
194
|
+
if (memberExpression.computed ||
|
|
195
|
+
(options.enforceForRenamedProperties &&
|
|
196
|
+
!isMatchingPropertyName(memberExpression.property, targetName))) {
|
|
197
|
+
return `${patternKeyText}: ${targetName}`;
|
|
198
|
+
}
|
|
199
|
+
return patternKeyText;
|
|
200
|
+
}
|
|
131
201
|
/**
|
|
132
202
|
* Check if destructuring should be used for this node
|
|
133
203
|
*/
|
|
134
204
|
function shouldUseDestructuring(node, leftNode) {
|
|
135
|
-
|
|
136
|
-
if (isClassInstance(node, context) ||
|
|
137
|
-
isStaticClassMember(node, context)) {
|
|
205
|
+
if (!isIdentifierTarget(leftNode)) {
|
|
138
206
|
return false;
|
|
139
207
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
208
|
+
return (!isSkippedClassMemberAccess(node) &&
|
|
209
|
+
!isThisMemberInClassMethod(node) &&
|
|
210
|
+
canDestructureObjectProperty(node, leftNode));
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Extracts the property name from a MemberExpression when it can be safely compared.
|
|
214
|
+
*/
|
|
215
|
+
function getMemberExpressionPropertyName(memberExpression) {
|
|
216
|
+
if (isPrivateIdentifierProperty(memberExpression.property)) {
|
|
217
|
+
return null;
|
|
144
218
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return true;
|
|
219
|
+
if (!memberExpression.computed) {
|
|
220
|
+
if (memberExpression.property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
221
|
+
return memberExpression.property.name;
|
|
149
222
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
if (memberExpression.property.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
226
|
+
typeof memberExpression.property.value === 'string') {
|
|
227
|
+
return memberExpression.property.value;
|
|
228
|
+
}
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Look up a variable by name within a scope.
|
|
233
|
+
*/
|
|
234
|
+
function findVariableInScope(scope, name) {
|
|
235
|
+
return scope?.variables.find((variable) => variable.name === name);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Check whether a variable definition originates from a parameter.
|
|
239
|
+
*/
|
|
240
|
+
function isParameterDefinition(variable) {
|
|
241
|
+
if (!variable || !Array.isArray(variable.defs)) {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
return variable.defs.some((definition) => definition.type === 'Parameter');
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Determine whether an identifier refers to a function or method parameter.
|
|
248
|
+
*/
|
|
249
|
+
function isFunctionParameter(identifier) {
|
|
250
|
+
let scope = context.getScope();
|
|
251
|
+
while (scope) {
|
|
252
|
+
const variable = findVariableInScope(scope, identifier.name);
|
|
253
|
+
if (variable) {
|
|
254
|
+
return isParameterDefinition(variable);
|
|
153
255
|
}
|
|
256
|
+
scope = scope.upper;
|
|
154
257
|
}
|
|
155
258
|
return false;
|
|
156
259
|
}
|
|
260
|
+
function buildReportDetails(memberExpr, targetName, examplePrefix, exampleSuffix) {
|
|
261
|
+
const objectText = sourceCode.getText(memberExpr.object);
|
|
262
|
+
const propertyText = getPropertyText(memberExpr.property, memberExpr.computed, sourceCode);
|
|
263
|
+
const usesRenaming = options.enforceForRenamedProperties &&
|
|
264
|
+
!!targetName &&
|
|
265
|
+
!isMatchingPropertyName(memberExpr.property, targetName);
|
|
266
|
+
const aliasName = targetName ?? propertyText;
|
|
267
|
+
const patternKeyText = getPatternKeyText(memberExpr, propertyText);
|
|
268
|
+
const destructuringBinding = getDestructuringBindingText(memberExpr, propertyText, aliasName) ??
|
|
269
|
+
patternKeyText;
|
|
270
|
+
return {
|
|
271
|
+
propertyText,
|
|
272
|
+
objectText,
|
|
273
|
+
destructuringBinding,
|
|
274
|
+
data: {
|
|
275
|
+
property: propertyText,
|
|
276
|
+
object: objectText,
|
|
277
|
+
targetNote: usesRenaming && targetName ? ` to "${targetName}"` : '',
|
|
278
|
+
renamingHint: usesRenaming ? ' with renaming' : '',
|
|
279
|
+
example: usesRenaming
|
|
280
|
+
? `${examplePrefix}{ ${destructuringBinding} } = ${objectText}${exampleSuffix}`
|
|
281
|
+
: `${examplePrefix}{ ${destructuringBinding} } = ${objectText}${exampleSuffix}`,
|
|
282
|
+
},
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function generateVariableDeclaratorFix(fixer, node, propertyText, objectText, memberExpr) {
|
|
286
|
+
const parentNode = node.parent;
|
|
287
|
+
if (!parentNode ||
|
|
288
|
+
parentNode.type !== utils_1.AST_NODE_TYPES.VariableDeclaration) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
if (parentNode.declarations.length > 1) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const kind = parentNode.kind;
|
|
295
|
+
if (node.id.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
const destructuringBinding = getDestructuringBindingText(memberExpr, propertyText, node.id.name);
|
|
299
|
+
if (!destructuringBinding) {
|
|
300
|
+
return null;
|
|
301
|
+
}
|
|
302
|
+
return fixer.replaceText(parentNode, `${kind} { ${destructuringBinding} } = ${objectText};`);
|
|
303
|
+
}
|
|
304
|
+
function generateAssignmentExpressionFix(fixer, node, propertyText, objectText, memberExpr) {
|
|
305
|
+
if (node.left.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
|
306
|
+
return null;
|
|
307
|
+
}
|
|
308
|
+
const destructuringBinding = getDestructuringBindingText(memberExpr, propertyText, node.left.name);
|
|
309
|
+
if (!destructuringBinding) {
|
|
310
|
+
return null;
|
|
311
|
+
}
|
|
312
|
+
return fixer.replaceText(node, `({ ${destructuringBinding} } = ${objectText})`);
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Report assignments that copy properties from parameter objects to class fields.
|
|
316
|
+
* These are reported without a fixer to avoid changing function signatures.
|
|
317
|
+
*/
|
|
318
|
+
function handleClassPropertyAssignment(node) {
|
|
319
|
+
// Caller ensures node.right is a MemberExpression.
|
|
320
|
+
if (!options.object ||
|
|
321
|
+
node.left.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
|
|
322
|
+
node.left.object.type !== utils_1.AST_NODE_TYPES.ThisExpression) {
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
if (!isInsideConstructorBody(node)) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
const rightObject = node.right.object;
|
|
329
|
+
if (rightObject.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
330
|
+
!isFunctionParameter(rightObject)) {
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const leftPropertyName = getMemberExpressionPropertyName(node.left);
|
|
334
|
+
const rightPropertyName = getMemberExpressionPropertyName(node.right);
|
|
335
|
+
if (!leftPropertyName || !rightPropertyName) {
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
if (!options.enforceForRenamedProperties &&
|
|
339
|
+
leftPropertyName !== rightPropertyName) {
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
if (isClassInstance(node.right, context) ||
|
|
343
|
+
isStaticClassMember(node.right, context)) {
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
const { data } = buildReportDetails(node.right, leftPropertyName, '(', ')');
|
|
347
|
+
// No fixer here because destructuring parameters changes the function signature and must stay manual.
|
|
348
|
+
context.report({
|
|
349
|
+
node,
|
|
350
|
+
messageId: 'preferDestructuring',
|
|
351
|
+
data,
|
|
352
|
+
});
|
|
353
|
+
}
|
|
157
354
|
return {
|
|
158
355
|
VariableDeclarator(node) {
|
|
159
356
|
// Skip if variable is declared without assignment or if init is not a MemberExpression
|
|
@@ -161,57 +358,45 @@ exports.preferDestructuringNoClass = (0, createRule_1.createRule)({
|
|
|
161
358
|
return;
|
|
162
359
|
if (node.init.type !== utils_1.AST_NODE_TYPES.MemberExpression)
|
|
163
360
|
return;
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
361
|
+
const memberInit = node.init;
|
|
362
|
+
if (!shouldUseDestructuring(memberInit, node.id)) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const targetName = node.id.type === utils_1.AST_NODE_TYPES.Identifier ? node.id.name : null;
|
|
366
|
+
const { propertyText, objectText, data } = buildReportDetails(memberInit, targetName, `${node.parent?.type === utils_1.AST_NODE_TYPES.VariableDeclaration
|
|
367
|
+
? node.parent.kind
|
|
368
|
+
: 'const'} `, ';');
|
|
369
|
+
context.report({
|
|
370
|
+
node,
|
|
371
|
+
messageId: 'preferDestructuring',
|
|
372
|
+
data,
|
|
373
|
+
fix(fixer) {
|
|
374
|
+
return generateVariableDeclaratorFix(fixer, node, propertyText, objectText, memberInit);
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
},
|
|
378
|
+
AssignmentExpression(node) {
|
|
379
|
+
if (node.operator !== '=' ||
|
|
380
|
+
node.right.type !== utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
const memberRight = node.right;
|
|
384
|
+
if (shouldUseDestructuring(memberRight, node.left)) {
|
|
385
|
+
const targetName = node.left.type === utils_1.AST_NODE_TYPES.Identifier
|
|
386
|
+
? node.left.name
|
|
387
|
+
: null;
|
|
388
|
+
const { propertyText, objectText, data } = buildReportDetails(memberRight, targetName, '(', ')');
|
|
168
389
|
context.report({
|
|
169
390
|
node,
|
|
170
391
|
messageId: 'preferDestructuring',
|
|
392
|
+
data,
|
|
171
393
|
fix(fixer) {
|
|
172
|
-
|
|
173
|
-
const parentNode = node.parent;
|
|
174
|
-
if (!parentNode ||
|
|
175
|
-
parentNode.type !== utils_1.AST_NODE_TYPES.VariableDeclaration) {
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
const kind = parentNode.kind;
|
|
179
|
-
// Handle renamed properties
|
|
180
|
-
if (options.enforceForRenamedProperties &&
|
|
181
|
-
node.id.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
182
|
-
node.init &&
|
|
183
|
-
node.init.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
184
|
-
!isMatchingPropertyName(node.init.property, node.id.name)) {
|
|
185
|
-
return fixer.replaceText(parentNode, `${kind} { ${propertyText}: ${node.id.name} } = ${objectText};`);
|
|
186
|
-
}
|
|
187
|
-
return fixer.replaceText(parentNode, `${kind} { ${propertyText} } = ${objectText};`);
|
|
394
|
+
return generateAssignmentExpressionFix(fixer, node, propertyText, objectText, memberRight);
|
|
188
395
|
},
|
|
189
396
|
});
|
|
397
|
+
return;
|
|
190
398
|
}
|
|
191
|
-
|
|
192
|
-
AssignmentExpression(node) {
|
|
193
|
-
if (node.operator === '=' &&
|
|
194
|
-
node.right.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
195
|
-
if (shouldUseDestructuring(node.right, node.left)) {
|
|
196
|
-
const sourceCode = context.getSourceCode();
|
|
197
|
-
const objectText = sourceCode.getText(node.right.object);
|
|
198
|
-
const propertyText = getPropertyText(node.right.property, node.right.computed, sourceCode);
|
|
199
|
-
context.report({
|
|
200
|
-
node,
|
|
201
|
-
messageId: 'preferDestructuring',
|
|
202
|
-
fix(fixer) {
|
|
203
|
-
// Handle renamed properties
|
|
204
|
-
if (options.enforceForRenamedProperties &&
|
|
205
|
-
node.left.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
206
|
-
node.right.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
207
|
-
!isMatchingPropertyName(node.right.property, node.left.name)) {
|
|
208
|
-
return fixer.replaceText(node, `({ ${propertyText}: ${node.left.name} } = ${objectText})`);
|
|
209
|
-
}
|
|
210
|
-
return fixer.replaceText(node, `({ ${propertyText} } = ${objectText})`);
|
|
211
|
-
},
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
}
|
|
399
|
+
handleClassPropertyAssignment(node);
|
|
215
400
|
},
|
|
216
401
|
};
|
|
217
402
|
},
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.preferDocSetterSetAll = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
const ITERATING_METHODS = new Set(['map', 'forEach']);
|
|
7
|
+
const DOC_SETTER_NAMES = new Set([
|
|
8
|
+
'DocSetter',
|
|
9
|
+
'DocSetterTransaction',
|
|
10
|
+
]);
|
|
11
|
+
function unwrapCallee(callee) {
|
|
12
|
+
return callee.type === utils_1.AST_NODE_TYPES.ChainExpression
|
|
13
|
+
? callee.expression
|
|
14
|
+
: callee;
|
|
15
|
+
}
|
|
16
|
+
function getEntityIdentifier(entity) {
|
|
17
|
+
if (entity.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
18
|
+
return entity.name;
|
|
19
|
+
}
|
|
20
|
+
return getEntityIdentifier(entity.right);
|
|
21
|
+
}
|
|
22
|
+
function getTypeName(typeNode) {
|
|
23
|
+
if (!typeNode || typeNode.type !== utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
return getEntityIdentifier(typeNode.typeName);
|
|
27
|
+
}
|
|
28
|
+
function isDocSetterName(name) {
|
|
29
|
+
return Boolean(name && DOC_SETTER_NAMES.has(name));
|
|
30
|
+
}
|
|
31
|
+
function getNewExpressionKind(expression) {
|
|
32
|
+
if (expression?.type !== utils_1.AST_NODE_TYPES.NewExpression) {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
if (expression.callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
36
|
+
isDocSetterName(expression.callee.name)) {
|
|
37
|
+
return expression.callee.name;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function getTypeAnnotationKind(identifier) {
|
|
42
|
+
const typeName = getTypeName(identifier.typeAnnotation?.typeAnnotation);
|
|
43
|
+
if (isDocSetterName(typeName)) {
|
|
44
|
+
return typeName;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function extractKindFromDefinition(definition) {
|
|
49
|
+
const nameNode = definition.name;
|
|
50
|
+
if (!nameNode || nameNode.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
51
|
+
return null;
|
|
52
|
+
const parent = nameNode.parent;
|
|
53
|
+
if (parent?.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
54
|
+
const ctorKind = getNewExpressionKind(parent.init);
|
|
55
|
+
if (ctorKind)
|
|
56
|
+
return ctorKind;
|
|
57
|
+
}
|
|
58
|
+
const annotationKind = getTypeAnnotationKind(nameNode);
|
|
59
|
+
if (annotationKind)
|
|
60
|
+
return annotationKind;
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
function resolveDocSetterFromScope(identifier, context) {
|
|
64
|
+
let scope = context.getScope();
|
|
65
|
+
while (scope) {
|
|
66
|
+
const variable = scope.set.get(identifier.name);
|
|
67
|
+
if (variable) {
|
|
68
|
+
for (const def of variable.defs) {
|
|
69
|
+
const kind = extractKindFromDefinition(def);
|
|
70
|
+
if (kind) {
|
|
71
|
+
return { setterName: identifier.name, setterKind: kind };
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
scope = scope.upper;
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
function resolveDocSetterFromClassProperty(propertyName, startNode) {
|
|
80
|
+
let current = startNode;
|
|
81
|
+
while (current) {
|
|
82
|
+
if (current.type === utils_1.AST_NODE_TYPES.ClassBody) {
|
|
83
|
+
for (const element of current.body) {
|
|
84
|
+
if (element.type === utils_1.AST_NODE_TYPES.PropertyDefinition &&
|
|
85
|
+
element.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
86
|
+
element.key.name === propertyName) {
|
|
87
|
+
const ctorKind = getNewExpressionKind(element.value);
|
|
88
|
+
if (ctorKind)
|
|
89
|
+
return ctorKind;
|
|
90
|
+
const annotationKind = getTypeName(element.typeAnnotation?.typeAnnotation);
|
|
91
|
+
if (isDocSetterName(annotationKind)) {
|
|
92
|
+
return annotationKind;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
const classNode = current.parent;
|
|
97
|
+
if (classNode &&
|
|
98
|
+
(classNode.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
|
|
99
|
+
classNode.type === utils_1.AST_NODE_TYPES.ClassExpression)) {
|
|
100
|
+
const constructor = classNode.body.body.find((member) => member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
|
101
|
+
member.kind === 'constructor');
|
|
102
|
+
if (constructor) {
|
|
103
|
+
for (const param of constructor.value.params) {
|
|
104
|
+
if (param.type === utils_1.AST_NODE_TYPES.TSParameterProperty) {
|
|
105
|
+
const parameter = param.parameter;
|
|
106
|
+
if (parameter.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
107
|
+
parameter.name === propertyName) {
|
|
108
|
+
const annotationKind = getTypeAnnotationKind(parameter);
|
|
109
|
+
if (annotationKind)
|
|
110
|
+
return annotationKind;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return null;
|
|
117
|
+
}
|
|
118
|
+
current = current.parent;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
function isAncestor(ancestor, node) {
|
|
123
|
+
let current = node;
|
|
124
|
+
while (current) {
|
|
125
|
+
if (current === ancestor)
|
|
126
|
+
return true;
|
|
127
|
+
current = current.parent;
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
function findIterationContext(node) {
|
|
132
|
+
let current = node.parent;
|
|
133
|
+
while (current) {
|
|
134
|
+
switch (current.type) {
|
|
135
|
+
case utils_1.AST_NODE_TYPES.ForStatement:
|
|
136
|
+
case utils_1.AST_NODE_TYPES.ForInStatement:
|
|
137
|
+
case utils_1.AST_NODE_TYPES.ForOfStatement:
|
|
138
|
+
case utils_1.AST_NODE_TYPES.WhileStatement:
|
|
139
|
+
case utils_1.AST_NODE_TYPES.DoWhileStatement:
|
|
140
|
+
return { kind: 'loop', loopType: current.type };
|
|
141
|
+
case utils_1.AST_NODE_TYPES.CallExpression: {
|
|
142
|
+
const callee = unwrapCallee(current.callee);
|
|
143
|
+
if (callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
144
|
+
callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
145
|
+
ITERATING_METHODS.has(callee.property.name)) {
|
|
146
|
+
const callback = current.arguments[0];
|
|
147
|
+
if (callback &&
|
|
148
|
+
(callback.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
149
|
+
callback.type === utils_1.AST_NODE_TYPES.FunctionExpression) &&
|
|
150
|
+
isAncestor(callback, node)) {
|
|
151
|
+
return { kind: 'array-callback', methodName: callee.property.name };
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case utils_1.AST_NODE_TYPES.Program:
|
|
157
|
+
return null;
|
|
158
|
+
default:
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
current = current.parent;
|
|
162
|
+
}
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
function formatContext(iteration) {
|
|
166
|
+
if (iteration.kind === 'array-callback') {
|
|
167
|
+
return `${iteration.methodName} callback`;
|
|
168
|
+
}
|
|
169
|
+
switch (iteration.loopType) {
|
|
170
|
+
case utils_1.AST_NODE_TYPES.ForOfStatement:
|
|
171
|
+
return 'for...of loop';
|
|
172
|
+
case utils_1.AST_NODE_TYPES.ForInStatement:
|
|
173
|
+
return 'for...in loop';
|
|
174
|
+
case utils_1.AST_NODE_TYPES.ForStatement:
|
|
175
|
+
return 'for loop';
|
|
176
|
+
case utils_1.AST_NODE_TYPES.WhileStatement:
|
|
177
|
+
return 'while loop';
|
|
178
|
+
case utils_1.AST_NODE_TYPES.DoWhileStatement:
|
|
179
|
+
return 'do...while loop';
|
|
180
|
+
default:
|
|
181
|
+
return 'loop';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
function resolveDocSetterInfo(callee, context) {
|
|
185
|
+
if (callee.property.type !== utils_1.AST_NODE_TYPES.Identifier)
|
|
186
|
+
return null;
|
|
187
|
+
const object = callee.object;
|
|
188
|
+
if (object.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
189
|
+
return resolveDocSetterFromScope(object, context);
|
|
190
|
+
}
|
|
191
|
+
if (object.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
192
|
+
object.object.type === utils_1.AST_NODE_TYPES.ThisExpression &&
|
|
193
|
+
object.property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
194
|
+
const setterKind = resolveDocSetterFromClassProperty(object.property.name, callee);
|
|
195
|
+
if (setterKind) {
|
|
196
|
+
return { setterName: object.property.name, setterKind };
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
exports.preferDocSetterSetAll = (0, createRule_1.createRule)({
|
|
202
|
+
name: 'prefer-docsetter-setall',
|
|
203
|
+
meta: {
|
|
204
|
+
type: 'suggestion',
|
|
205
|
+
docs: {
|
|
206
|
+
description: 'Enforce batching DocSetter and DocSetterTransaction writes by using setAll instead of set inside loops or array callbacks.',
|
|
207
|
+
recommended: 'error',
|
|
208
|
+
},
|
|
209
|
+
schema: [],
|
|
210
|
+
messages: {
|
|
211
|
+
preferSetAll: '{{setterName}}.set() runs inside a {{context}}, which sends one Firestore write per iteration. Collect the document payloads and call setAll() once to batch writes, cut round-trips, and keep payload types narrow (build an updates array and mark entries as const when needed).',
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
defaultOptions: [],
|
|
215
|
+
create(context) {
|
|
216
|
+
return {
|
|
217
|
+
CallExpression(node) {
|
|
218
|
+
const callee = unwrapCallee(node.callee);
|
|
219
|
+
if (callee.type !== utils_1.AST_NODE_TYPES.MemberExpression ||
|
|
220
|
+
callee.property.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
221
|
+
callee.property.name !== 'set') {
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
const setterInfo = resolveDocSetterInfo(callee, context);
|
|
225
|
+
if (!setterInfo)
|
|
226
|
+
return;
|
|
227
|
+
const iterationContext = findIterationContext(node);
|
|
228
|
+
if (!iterationContext)
|
|
229
|
+
return;
|
|
230
|
+
const contextLabel = formatContext(iterationContext);
|
|
231
|
+
context.report({
|
|
232
|
+
node: callee.property,
|
|
233
|
+
messageId: 'preferSetAll',
|
|
234
|
+
data: {
|
|
235
|
+
setterName: setterInfo.setterName,
|
|
236
|
+
context: contextLabel,
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
//# sourceMappingURL=prefer-docsetter-setall.js.map
|
|
@@ -74,8 +74,9 @@ function isBoundToName(fn, name) {
|
|
|
74
74
|
if (parent.type === utils_1.AST_NODE_TYPES.Property ||
|
|
75
75
|
parent.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
|
|
76
76
|
parent.type === utils_1.AST_NODE_TYPES.PropertyDefinition) {
|
|
77
|
-
const
|
|
78
|
-
|
|
77
|
+
const narrowedParent = parent;
|
|
78
|
+
const key = narrowedParent.key;
|
|
79
|
+
if (narrowedParent.computed) {
|
|
79
80
|
return key.type === utils_1.AST_NODE_TYPES.Literal && key.value === name;
|
|
80
81
|
}
|
|
81
82
|
if (key.type === utils_1.AST_NODE_TYPES.Identifier)
|
|
@@ -84,7 +85,7 @@ function isBoundToName(fn, name) {
|
|
|
84
85
|
return key.value === name;
|
|
85
86
|
}
|
|
86
87
|
if (parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator) {
|
|
87
|
-
return parent.id.type === utils_1.AST_NODE_TYPES.Identifier && parent.id.name === name;
|
|
88
|
+
return (parent.id.type === utils_1.AST_NODE_TYPES.Identifier && parent.id.name === name);
|
|
88
89
|
}
|
|
89
90
|
if (parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression) {
|
|
90
91
|
const left = parent.left;
|
|
@@ -20,7 +20,7 @@ exports.preferFragmentComponent = (0, createRule_1.createRule)({
|
|
|
20
20
|
},
|
|
21
21
|
defaultOptions: [],
|
|
22
22
|
create(context) {
|
|
23
|
-
const sourceCode = context.
|
|
23
|
+
const sourceCode = context.sourceCode;
|
|
24
24
|
let hasFragmentImport = false;
|
|
25
25
|
let reactImportNode = null;
|
|
26
26
|
let defaultReactImportNode = null;
|
|
@@ -14,6 +14,7 @@ exports.preferFragmentShorthand = {
|
|
|
14
14
|
context.report({
|
|
15
15
|
node,
|
|
16
16
|
messageId: 'preferShorthand',
|
|
17
|
+
data: { fragmentName: 'React.Fragment' },
|
|
17
18
|
fix: (fixer) => [
|
|
18
19
|
fixer.replaceTextRange(openingElement.range, '<>'),
|
|
19
20
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
@@ -31,7 +32,7 @@ exports.preferFragmentShorthand = {
|
|
|
31
32
|
recommended: 'error',
|
|
32
33
|
},
|
|
33
34
|
messages: {
|
|
34
|
-
preferShorthand: '
|
|
35
|
+
preferShorthand: 'Fragment "{{fragmentName}}" is written with the long <React.Fragment> syntax. That form adds React namespace noise and is only necessary when you need a key or other attributes on the fragment. Prefer the <>...</> shorthand to keep JSX concise, and keep the long form only when fragment attributes are required.',
|
|
35
36
|
},
|
|
36
37
|
schema: [],
|
|
37
38
|
fixable: 'code',
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type OptionShape = {
|
|
2
|
+
stripPrefixes?: string[];
|
|
3
|
+
ignoredMethods?: string[];
|
|
4
|
+
ignoreAsync?: boolean;
|
|
5
|
+
ignoreVoidReturn?: boolean;
|
|
6
|
+
ignoreAbstract?: boolean;
|
|
7
|
+
respectJsDocSideEffects?: boolean;
|
|
8
|
+
minBodyLines?: number;
|
|
9
|
+
};
|
|
10
|
+
type Options = [OptionShape];
|
|
11
|
+
type MessageIds = 'preferGetter' | 'preferGetterSideEffect';
|
|
12
|
+
export declare const preferGetterOverParameterlessMethod: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
13
|
+
export default preferGetterOverParameterlessMethod;
|