@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
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.noRedundantThisParams = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
exports.noRedundantThisParams = (0, createRule_1.createRule)({
|
|
7
|
+
name: 'no-redundant-this-params',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'suggestion',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Disallow passing class instance members (this.foo) into class instance methods; access the member from this inside the method instead.',
|
|
12
|
+
recommended: 'error',
|
|
13
|
+
},
|
|
14
|
+
fixable: undefined,
|
|
15
|
+
schema: [],
|
|
16
|
+
messages: {
|
|
17
|
+
redundantInstanceArg: 'Method "{{methodName}}" receives "{{memberText}}"{{parameterNote}}. Instance state already lives on "this"; threading it through parameters duplicates class state and bloats the signature. Read "{{memberText}}" inside "{{methodName}}" instead of accepting it as an argument.',
|
|
18
|
+
redundantInstanceValueInObject: 'Method "{{methodName}}" receives an argument that contains "{{memberText}}"{{parameterNote}}. Routing instance state through parameters hides the shared `this` contract and complicates refactors. Remove that property from the call and read "{{memberText}}" directly inside "{{methodName}}".',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
create(context) {
|
|
23
|
+
const classInfoMap = new WeakMap();
|
|
24
|
+
function isFunctionLike(node) {
|
|
25
|
+
return (node?.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
26
|
+
node?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
27
|
+
node?.type === utils_1.AST_NODE_TYPES.FunctionDeclaration);
|
|
28
|
+
}
|
|
29
|
+
function getNameFromPropertyName(key) {
|
|
30
|
+
if (key.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
31
|
+
return key.name;
|
|
32
|
+
}
|
|
33
|
+
if (key.type === utils_1.AST_NODE_TYPES.Literal) {
|
|
34
|
+
return typeof key.value === 'string' ? key.value : String(key.value);
|
|
35
|
+
}
|
|
36
|
+
if (key.type === utils_1.AST_NODE_TYPES.PrivateIdentifier) {
|
|
37
|
+
return `#${key.name}`;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
function getMethodNameFromCallee(callee) {
|
|
42
|
+
const maybeChain = callee;
|
|
43
|
+
const unwrapped = maybeChain.type === utils_1.AST_NODE_TYPES.ChainExpression
|
|
44
|
+
? maybeChain.expression
|
|
45
|
+
: callee;
|
|
46
|
+
if (unwrapped.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
47
|
+
!unwrapped.computed &&
|
|
48
|
+
unwrapped.object.type === utils_1.AST_NODE_TYPES.ThisExpression &&
|
|
49
|
+
(unwrapped.property.type === utils_1.AST_NODE_TYPES.Identifier ||
|
|
50
|
+
unwrapped.property.type === utils_1.AST_NODE_TYPES.PrivateIdentifier)) {
|
|
51
|
+
return getNameFromPropertyName(unwrapped.property);
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
function getMethodParams(member) {
|
|
56
|
+
const value = member.value;
|
|
57
|
+
if (value &&
|
|
58
|
+
(value.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
59
|
+
value.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression)) {
|
|
60
|
+
return value.params;
|
|
61
|
+
}
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
function getPropertyMethodParams(member) {
|
|
65
|
+
if (member.value &&
|
|
66
|
+
(member.value.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
67
|
+
member.value.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression)) {
|
|
68
|
+
return member.value.params;
|
|
69
|
+
}
|
|
70
|
+
const annotation = member.typeAnnotation?.typeAnnotation;
|
|
71
|
+
if (!member.value &&
|
|
72
|
+
member.optional &&
|
|
73
|
+
annotation &&
|
|
74
|
+
annotation.type === utils_1.AST_NODE_TYPES.TSFunctionType) {
|
|
75
|
+
return annotation.params;
|
|
76
|
+
}
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
function collectClassInfo(node) {
|
|
80
|
+
const methods = new Map();
|
|
81
|
+
function setMethod(methodName, meta) {
|
|
82
|
+
/**
|
|
83
|
+
* Prefer instance methods over static methods when names collide.
|
|
84
|
+
* Calls like `this.method()` always resolve to the instance member, so the rule tracks the
|
|
85
|
+
* instance signature even if a static overload exists in the AST.
|
|
86
|
+
*/
|
|
87
|
+
const existing = methods.get(methodName);
|
|
88
|
+
if (!existing) {
|
|
89
|
+
methods.set(methodName, meta);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (existing.isStatic && !meta.isStatic) {
|
|
93
|
+
methods.set(methodName, meta);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (!existing.isStatic && meta.isStatic) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
methods.set(methodName, meta);
|
|
100
|
+
}
|
|
101
|
+
for (const member of node.body.body) {
|
|
102
|
+
if (member.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
|
|
103
|
+
member.type === utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition) {
|
|
104
|
+
if (member.kind === 'constructor') {
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const methodName = getNameFromPropertyName(member.key);
|
|
108
|
+
if (!methodName) {
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
setMethod(methodName, {
|
|
112
|
+
params: getMethodParams(member),
|
|
113
|
+
isStatic: Boolean(member.static),
|
|
114
|
+
isAbstract: member.type === utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition,
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
else if (member.type === utils_1.AST_NODE_TYPES.PropertyDefinition) {
|
|
118
|
+
const methodName = member.key
|
|
119
|
+
? getNameFromPropertyName(member.key)
|
|
120
|
+
: null;
|
|
121
|
+
if (!methodName || member.static) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const params = getPropertyMethodParams(member);
|
|
125
|
+
if (params.length === 0) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
setMethod(methodName, {
|
|
129
|
+
params,
|
|
130
|
+
isStatic: false,
|
|
131
|
+
isAbstract: false,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
classInfoMap.set(node, { methods });
|
|
136
|
+
}
|
|
137
|
+
function findEnclosingClass(node) {
|
|
138
|
+
let current = node.parent;
|
|
139
|
+
while (current) {
|
|
140
|
+
if (current.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
|
|
141
|
+
current.type === utils_1.AST_NODE_TYPES.ClassExpression) {
|
|
142
|
+
return current;
|
|
143
|
+
}
|
|
144
|
+
current = current.parent;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
function findEnclosingMember(node) {
|
|
149
|
+
let current = node.parent;
|
|
150
|
+
while (current) {
|
|
151
|
+
if (current.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
|
|
152
|
+
current.type === utils_1.AST_NODE_TYPES.PropertyDefinition) {
|
|
153
|
+
return current;
|
|
154
|
+
}
|
|
155
|
+
current = current.parent;
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
function getMemberFunction(member) {
|
|
160
|
+
if (!member) {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
if (member.type === utils_1.AST_NODE_TYPES.MethodDefinition &&
|
|
164
|
+
member.value &&
|
|
165
|
+
member.value.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
166
|
+
return member.value;
|
|
167
|
+
}
|
|
168
|
+
if (member.type === utils_1.AST_NODE_TYPES.PropertyDefinition &&
|
|
169
|
+
member.value &&
|
|
170
|
+
(member.value.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
|
|
171
|
+
member.value.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression)) {
|
|
172
|
+
return member.value;
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
function hasNestedFunctionBetween(leaf, boundary) {
|
|
177
|
+
let current = leaf.parent;
|
|
178
|
+
while (current && current !== boundary) {
|
|
179
|
+
if (isFunctionLike(current)) {
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
current = current.parent;
|
|
183
|
+
}
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
function isTransparentExpressionWrapper(node) {
|
|
187
|
+
// Babel emits ParenthesizedExpression nodes that are not modeled in TSESTree; treating them
|
|
188
|
+
// as transparent prevents parentheses from changing nested/transformed classification.
|
|
189
|
+
return (node.type === utils_1.AST_NODE_TYPES.TSAsExpression ||
|
|
190
|
+
node.type === utils_1.AST_NODE_TYPES.TSTypeAssertion ||
|
|
191
|
+
node.type === utils_1.AST_NODE_TYPES.TSNonNullExpression ||
|
|
192
|
+
node.type === utils_1.AST_NODE_TYPES.TSSatisfiesExpression ||
|
|
193
|
+
node.type === utils_1.AST_NODE_TYPES.TSInstantiationExpression ||
|
|
194
|
+
node.type === 'ParenthesizedExpression');
|
|
195
|
+
}
|
|
196
|
+
function unwrapTransparentExpression(node) {
|
|
197
|
+
let current = node;
|
|
198
|
+
while (isTransparentExpressionWrapper(current)) {
|
|
199
|
+
current = current.expression;
|
|
200
|
+
}
|
|
201
|
+
return current;
|
|
202
|
+
}
|
|
203
|
+
function isExpressionMemberChainObject(node) {
|
|
204
|
+
let current = node;
|
|
205
|
+
let parent = current.parent;
|
|
206
|
+
while (parent &&
|
|
207
|
+
isTransparentExpressionWrapper(parent) &&
|
|
208
|
+
parent.expression === current) {
|
|
209
|
+
current = parent;
|
|
210
|
+
parent = current.parent;
|
|
211
|
+
}
|
|
212
|
+
return (parent?.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
213
|
+
parent.object === current);
|
|
214
|
+
}
|
|
215
|
+
function getMemberText(propertyName) {
|
|
216
|
+
return `this.${propertyName}`;
|
|
217
|
+
}
|
|
218
|
+
function isTransformingNode(node) {
|
|
219
|
+
switch (node.type) {
|
|
220
|
+
case utils_1.AST_NODE_TYPES.CallExpression:
|
|
221
|
+
case utils_1.AST_NODE_TYPES.NewExpression:
|
|
222
|
+
case utils_1.AST_NODE_TYPES.TaggedTemplateExpression:
|
|
223
|
+
case utils_1.AST_NODE_TYPES.TemplateLiteral:
|
|
224
|
+
case utils_1.AST_NODE_TYPES.BinaryExpression:
|
|
225
|
+
case utils_1.AST_NODE_TYPES.LogicalExpression:
|
|
226
|
+
case utils_1.AST_NODE_TYPES.ConditionalExpression:
|
|
227
|
+
case utils_1.AST_NODE_TYPES.SequenceExpression:
|
|
228
|
+
case utils_1.AST_NODE_TYPES.UnaryExpression:
|
|
229
|
+
case utils_1.AST_NODE_TYPES.UpdateExpression:
|
|
230
|
+
case utils_1.AST_NODE_TYPES.AwaitExpression:
|
|
231
|
+
case utils_1.AST_NODE_TYPES.YieldExpression:
|
|
232
|
+
case utils_1.AST_NODE_TYPES.AssignmentExpression:
|
|
233
|
+
return true;
|
|
234
|
+
default:
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function collectThisAccesses(expression) {
|
|
239
|
+
const normalized = unwrapTransparentExpression(expression);
|
|
240
|
+
const results = [];
|
|
241
|
+
function visit(node, nested, transformed) {
|
|
242
|
+
const isParenthesized = node.type === 'ParenthesizedExpression';
|
|
243
|
+
const isMemberChainObject = isExpressionMemberChainObject(node);
|
|
244
|
+
if (isParenthesized) {
|
|
245
|
+
visit(node.expression, nested || (node !== normalized && !isMemberChainObject), transformed);
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
const nextNested = nested || (node !== normalized && !isMemberChainObject);
|
|
249
|
+
const nextTransformed = transformed || isTransformingNode(node);
|
|
250
|
+
switch (node.type) {
|
|
251
|
+
case utils_1.AST_NODE_TYPES.MemberExpression: {
|
|
252
|
+
if (!node.computed &&
|
|
253
|
+
node.object.type === utils_1.AST_NODE_TYPES.ThisExpression &&
|
|
254
|
+
(node.property.type === utils_1.AST_NODE_TYPES.Identifier ||
|
|
255
|
+
node.property.type === utils_1.AST_NODE_TYPES.PrivateIdentifier)) {
|
|
256
|
+
const propertyName = getNameFromPropertyName(node.property);
|
|
257
|
+
if (propertyName && !nextTransformed) {
|
|
258
|
+
results.push({
|
|
259
|
+
node,
|
|
260
|
+
propertyName,
|
|
261
|
+
nested: nextNested,
|
|
262
|
+
transformed: nextTransformed,
|
|
263
|
+
});
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
visit(node.object, nextNested, nextTransformed);
|
|
268
|
+
if (node.computed) {
|
|
269
|
+
visit(node.property, true, nextTransformed);
|
|
270
|
+
}
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
case utils_1.AST_NODE_TYPES.ChainExpression:
|
|
274
|
+
visit(node.expression, nextNested, nextTransformed);
|
|
275
|
+
return;
|
|
276
|
+
case utils_1.AST_NODE_TYPES.ObjectExpression:
|
|
277
|
+
for (const prop of node.properties) {
|
|
278
|
+
if (prop.type === utils_1.AST_NODE_TYPES.Property) {
|
|
279
|
+
if (prop.computed) {
|
|
280
|
+
visit(prop.key, true, nextTransformed);
|
|
281
|
+
}
|
|
282
|
+
visit(prop.value, true, nextTransformed);
|
|
283
|
+
}
|
|
284
|
+
else if (prop.type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
|
285
|
+
visit(prop.argument, true, nextTransformed);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return;
|
|
289
|
+
case utils_1.AST_NODE_TYPES.ArrayExpression:
|
|
290
|
+
for (const element of node.elements) {
|
|
291
|
+
if (!element) {
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (element.type === utils_1.AST_NODE_TYPES.SpreadElement) {
|
|
295
|
+
visit(element.argument, true, nextTransformed);
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
visit(element, true, nextTransformed);
|
|
299
|
+
}
|
|
300
|
+
return;
|
|
301
|
+
case utils_1.AST_NODE_TYPES.CallExpression:
|
|
302
|
+
case utils_1.AST_NODE_TYPES.NewExpression:
|
|
303
|
+
for (const arg of node.arguments) {
|
|
304
|
+
if (arg) {
|
|
305
|
+
visit(arg, true, true);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return;
|
|
309
|
+
case utils_1.AST_NODE_TYPES.SpreadElement:
|
|
310
|
+
visit(node.argument, true, nextTransformed);
|
|
311
|
+
return;
|
|
312
|
+
case utils_1.AST_NODE_TYPES.BinaryExpression:
|
|
313
|
+
case utils_1.AST_NODE_TYPES.LogicalExpression:
|
|
314
|
+
visit(node.left, true, true);
|
|
315
|
+
visit(node.right, true, true);
|
|
316
|
+
return;
|
|
317
|
+
case utils_1.AST_NODE_TYPES.ConditionalExpression:
|
|
318
|
+
visit(node.test, true, true);
|
|
319
|
+
visit(node.consequent, true, true);
|
|
320
|
+
visit(node.alternate, true, true);
|
|
321
|
+
return;
|
|
322
|
+
case utils_1.AST_NODE_TYPES.TemplateLiteral:
|
|
323
|
+
node.expressions.forEach((expr) => visit(expr, true, true));
|
|
324
|
+
return;
|
|
325
|
+
case utils_1.AST_NODE_TYPES.TaggedTemplateExpression:
|
|
326
|
+
visit(node.tag, true, true);
|
|
327
|
+
visit(node.quasi, true, true);
|
|
328
|
+
return;
|
|
329
|
+
case utils_1.AST_NODE_TYPES.SequenceExpression:
|
|
330
|
+
node.expressions.forEach((expr) => visit(expr, true, true));
|
|
331
|
+
return;
|
|
332
|
+
case utils_1.AST_NODE_TYPES.UnaryExpression:
|
|
333
|
+
case utils_1.AST_NODE_TYPES.UpdateExpression:
|
|
334
|
+
case utils_1.AST_NODE_TYPES.AwaitExpression:
|
|
335
|
+
case utils_1.AST_NODE_TYPES.YieldExpression:
|
|
336
|
+
if (node.argument) {
|
|
337
|
+
visit(node.argument, true, true);
|
|
338
|
+
}
|
|
339
|
+
return;
|
|
340
|
+
case utils_1.AST_NODE_TYPES.AssignmentExpression:
|
|
341
|
+
visit(node.left, true, true);
|
|
342
|
+
visit(node.right, true, true);
|
|
343
|
+
return;
|
|
344
|
+
case utils_1.AST_NODE_TYPES.TSAsExpression:
|
|
345
|
+
case utils_1.AST_NODE_TYPES.TSTypeAssertion:
|
|
346
|
+
case utils_1.AST_NODE_TYPES.TSNonNullExpression:
|
|
347
|
+
case utils_1.AST_NODE_TYPES.TSSatisfiesExpression:
|
|
348
|
+
case utils_1.AST_NODE_TYPES.TSInstantiationExpression:
|
|
349
|
+
visit(node.expression, nextNested, nextTransformed);
|
|
350
|
+
return;
|
|
351
|
+
default:
|
|
352
|
+
if (isFunctionLike(node)) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
visit(normalized, false, false);
|
|
358
|
+
return results;
|
|
359
|
+
}
|
|
360
|
+
function getParameterName(param) {
|
|
361
|
+
if (!param) {
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
if (param.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
365
|
+
return param.name;
|
|
366
|
+
}
|
|
367
|
+
if (param.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
368
|
+
if (param.left.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
369
|
+
return param.left.name;
|
|
370
|
+
}
|
|
371
|
+
if (param.left.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
if (param.type === utils_1.AST_NODE_TYPES.RestElement) {
|
|
376
|
+
return param.argument.type === utils_1.AST_NODE_TYPES.Identifier
|
|
377
|
+
? param.argument.name
|
|
378
|
+
: null;
|
|
379
|
+
}
|
|
380
|
+
if (param.type === utils_1.AST_NODE_TYPES.TSParameterProperty) {
|
|
381
|
+
const { parameter } = param;
|
|
382
|
+
if (parameter.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
383
|
+
return parameter.name;
|
|
384
|
+
}
|
|
385
|
+
if (parameter.type === utils_1.AST_NODE_TYPES.AssignmentPattern &&
|
|
386
|
+
parameter.left.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
387
|
+
return parameter.left.name;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
function buildParameterNote(paramName) {
|
|
393
|
+
return paramName ? ` (parameter "${paramName}")` : '';
|
|
394
|
+
}
|
|
395
|
+
function reportAccess(methodName, methodMeta, argIndex, access) {
|
|
396
|
+
const paramName = getParameterName(methodMeta.params[argIndex]);
|
|
397
|
+
const parameterNote = buildParameterNote(paramName);
|
|
398
|
+
const memberText = getMemberText(access.propertyName);
|
|
399
|
+
const messageId = access.nested
|
|
400
|
+
? 'redundantInstanceValueInObject'
|
|
401
|
+
: 'redundantInstanceArg';
|
|
402
|
+
context.report({
|
|
403
|
+
node: access.node,
|
|
404
|
+
messageId,
|
|
405
|
+
data: {
|
|
406
|
+
methodName,
|
|
407
|
+
memberText,
|
|
408
|
+
parameterNote,
|
|
409
|
+
},
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
return {
|
|
413
|
+
'ClassDeclaration, ClassExpression'(node) {
|
|
414
|
+
collectClassInfo(node);
|
|
415
|
+
},
|
|
416
|
+
CallExpression(node) {
|
|
417
|
+
const methodName = getMethodNameFromCallee(node.callee);
|
|
418
|
+
if (!methodName || methodName === 'constructor') {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const classNode = findEnclosingClass(node);
|
|
422
|
+
if (!classNode) {
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
const classInfo = classInfoMap.get(classNode);
|
|
426
|
+
const methodMeta = classInfo?.methods.get(methodName);
|
|
427
|
+
if (!methodMeta || methodMeta.isStatic) {
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const member = findEnclosingMember(node);
|
|
431
|
+
const memberFunction = getMemberFunction(member);
|
|
432
|
+
if (memberFunction) {
|
|
433
|
+
if (hasNestedFunctionBetween(node, memberFunction)) {
|
|
434
|
+
return;
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
if (!member || member.type !== utils_1.AST_NODE_TYPES.PropertyDefinition) {
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
if (hasNestedFunctionBetween(node, member)) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
node.arguments.forEach((arg, index) => {
|
|
446
|
+
if (!arg) {
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
449
|
+
const targetNode = arg.type === utils_1.AST_NODE_TYPES.SpreadElement ? arg.argument : arg;
|
|
450
|
+
const accesses = collectThisAccesses(targetNode);
|
|
451
|
+
for (const access of accesses) {
|
|
452
|
+
reportAccess(methodName, methodMeta, index, access);
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
},
|
|
456
|
+
};
|
|
457
|
+
},
|
|
458
|
+
});
|
|
459
|
+
//# sourceMappingURL=no-redundant-this-params.js.map
|
|
@@ -131,7 +131,7 @@ exports.noRedundantUseCallbackWrapper = (0, createRule_1.createRule)({
|
|
|
131
131
|
},
|
|
132
132
|
],
|
|
133
133
|
messages: {
|
|
134
|
-
redundantWrapper: '
|
|
134
|
+
redundantWrapper: 'useCallback is wrapping memoized callback "{{callbackName}}", adding a redundant dependency array without improving stability. Pass the hook/context callback directly so React keeps the original stable reference and avoids wrapper allocations and dependency drift.',
|
|
135
135
|
},
|
|
136
136
|
},
|
|
137
137
|
defaultOptions: [{}],
|
|
@@ -139,6 +139,7 @@ exports.noRedundantUseCallbackWrapper = (0, createRule_1.createRule)({
|
|
|
139
139
|
const option = context.options?.[0] ?? {};
|
|
140
140
|
const knownHooks = new Set(option.memoizedHookNames ?? []);
|
|
141
141
|
const assumeAllUseAreMemoized = option.assumeAllUseAreMemoized === true;
|
|
142
|
+
const sourceCode = context.sourceCode;
|
|
142
143
|
// Track identifiers coming from hook-like calls
|
|
143
144
|
const hookReturnObjects = new Set(); // variables assigned to a hook call result (object or function)
|
|
144
145
|
const hookReturnProps = new Set(); // properties destructured from a hook call result
|
|
@@ -203,12 +204,17 @@ exports.noRedundantUseCallbackWrapper = (0, createRule_1.createRule)({
|
|
|
203
204
|
context.report({
|
|
204
205
|
node,
|
|
205
206
|
messageId: 'redundantWrapper',
|
|
207
|
+
data: { callbackName: sourceCode.getText(unwrappedArg) },
|
|
206
208
|
fix: (fixer) => fixer.replaceText(node, replaceText),
|
|
207
209
|
});
|
|
208
210
|
}
|
|
209
211
|
else {
|
|
210
212
|
// Member function — report only, no fix to avoid breaking `this`.
|
|
211
|
-
context.report({
|
|
213
|
+
context.report({
|
|
214
|
+
node,
|
|
215
|
+
messageId: 'redundantWrapper',
|
|
216
|
+
data: { callbackName: sourceCode.getText(unwrappedArg) },
|
|
217
|
+
});
|
|
212
218
|
}
|
|
213
219
|
}
|
|
214
220
|
return;
|
|
@@ -240,12 +246,17 @@ exports.noRedundantUseCallbackWrapper = (0, createRule_1.createRule)({
|
|
|
240
246
|
context.report({
|
|
241
247
|
node,
|
|
242
248
|
messageId: 'redundantWrapper',
|
|
249
|
+
data: { callbackName: sourceCode.getText(callee) },
|
|
243
250
|
fix: (fixer) => fixer.replaceText(node, replaceText),
|
|
244
251
|
});
|
|
245
252
|
}
|
|
246
253
|
else {
|
|
247
254
|
// Member function — report only, no fix to avoid breaking `this`.
|
|
248
|
-
context.report({
|
|
255
|
+
context.report({
|
|
256
|
+
node,
|
|
257
|
+
messageId: 'redundantWrapper',
|
|
258
|
+
data: { callbackName: sourceCode.getText(callee) },
|
|
259
|
+
});
|
|
249
260
|
}
|
|
250
261
|
}
|
|
251
262
|
}
|
|
@@ -289,6 +300,7 @@ exports.noRedundantUseCallbackWrapper = (0, createRule_1.createRule)({
|
|
|
289
300
|
context.report({
|
|
290
301
|
node,
|
|
291
302
|
messageId: 'redundantWrapper',
|
|
303
|
+
data: { callbackName: sourceCode.getText(callee) },
|
|
292
304
|
fix: (fixer) => fixer.replaceText(node, replaceText),
|
|
293
305
|
});
|
|
294
306
|
}
|
|
@@ -297,6 +309,7 @@ exports.noRedundantUseCallbackWrapper = (0, createRule_1.createRule)({
|
|
|
297
309
|
context.report({
|
|
298
310
|
node,
|
|
299
311
|
messageId: 'redundantWrapper',
|
|
312
|
+
data: { callbackName: sourceCode.getText(callee) },
|
|
300
313
|
});
|
|
301
314
|
}
|
|
302
315
|
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type MessageIds = 'useHttpsErrorForStatus' | 'useHttpsErrorForComputedStatus' | 'useHttpsErrorForWrapper';
|
|
3
|
+
export declare const requireHttpsErrorInOnRequestHandlers: TSESLint.RuleModule<MessageIds, never[]>;
|
|
4
|
+
export {};
|