Skip to content

Commit 98d8159

Browse files
committed
[types] add type annotations
1 parent 983b88d commit 98d8159

31 files changed

+142
-57
lines changed

lib/rules/button-has-type.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const messages = {
2828
forbiddenValue: '"{{value}}" is an invalid value for button type attribute',
2929
};
3030

31+
/** @type { import('eslint').Rule.RuleModule } */
3132
module.exports = {
3233
meta: {
3334
docs: {
@@ -149,9 +150,11 @@ module.exports = {
149150
}
150151

151152
const props = node.arguments[1].properties;
152-
const typeProp = props.find((prop) => prop.key && prop.key.name === 'type');
153+
const typeProp = props.find(
154+
(prop) => prop.type === 'Property' && prop.key && prop.key.type === 'Identifier' && prop.key.name === 'type'
155+
);
153156

154-
if (!typeProp) {
157+
if (!typeProp || typeProp.type !== 'Property') {
155158
reportMissing(node);
156159
return;
157160
}

lib/rules/checked-requires-onchange-or-readonly.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ const defaultOptions = {
2424
};
2525

2626
/**
27-
* @param {string[]} properties
27+
* @param {object[]} properties
2828
* @param {string} keyName
2929
* @returns {Set<string>}
3030
*/
@@ -41,6 +41,7 @@ function extractTargetProps(properties, keyName) {
4141
);
4242
}
4343

44+
/** @type { import('eslint').Rule.RuleModule } */
4445
module.exports = {
4546
meta: {
4647
docs: {

lib/rules/forbid-elements.js

+4-5
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const messages = {
2020
forbiddenElement_message: '<{{element}}> is forbidden, {{message}}',
2121
};
2222

23+
/** @type { import('eslint').Rule.RuleModule } */
2324
module.exports = {
2425
meta: {
2526
docs: {
@@ -105,13 +106,11 @@ module.exports = {
105106
return;
106107
}
107108

108-
const argType = argument.type;
109-
110-
if (argType === 'Identifier' && /^[A-Z_]/.test(argument.name)) {
109+
if (argument.type === 'Identifier' && /^[A-Z_]/.test(argument.name)) {
111110
reportIfForbidden(argument.name, argument);
112-
} else if (argType === 'Literal' && /^[a-z][^.]*$/.test(argument.value)) {
111+
} else if (argument.type === 'Literal' && /^[a-z][^.]*$/.test(String(argument.value))) {
113112
reportIfForbidden(argument.value, argument);
114-
} else if (argType === 'MemberExpression') {
113+
} else if (argument.type === 'MemberExpression') {
115114
reportIfForbidden(getText(context, argument), argument);
116115
}
117116
},

lib/rules/forbid-foreign-prop-types.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const messages = {
1313
forbiddenPropType: 'Using propTypes from another component is not safe because they may be removed in production builds',
1414
};
1515

16+
/** @type { import('eslint').Rule.RuleModule } */
1617
module.exports = {
1718
meta: {
1819
docs: {
@@ -108,8 +109,8 @@ module.exports = {
108109
&& !ast.isAssignmentLHS(node)
109110
&& !isAllowedAssignment(node)
110111
)) || (
111-
(node.property.type === 'Literal' || node.property.type === 'JSXText')
112-
&& node.property.value === 'propTypes'
112+
// @ts-expect-error The JSXText type is not present in the estree type definitions
113+
(node.property.type === 'Literal' || node.property.type === 'JSXText') && node.property.value === 'propTypes'
113114
&& !ast.isAssignmentLHS(node)
114115
&& !isAllowedAssignment(node)
115116
)
@@ -121,7 +122,7 @@ module.exports = {
121122
},
122123

123124
ObjectPattern(node) {
124-
const propTypesNode = node.properties.find((property) => property.type === 'Property' && property.key.name === 'propTypes');
125+
const propTypesNode = node.properties.find((property) => property.type === 'Property' && property.key.type === 'Identifier' && property.key.name === 'propTypes');
125126

126127
if (propTypesNode) {
127128
report(context, messages.forbiddenPropType, 'forbiddenPropType', {

lib/rules/forbid-prop-types.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const messages = {
2626
forbiddenPropType: 'Prop type "{{target}}" is forbidden',
2727
};
2828

29+
/** @type { import('eslint').Rule.RuleModule } */
2930
module.exports = {
3031
meta: {
3132
docs: {
@@ -196,7 +197,7 @@ module.exports = {
196197
}
197198
if (node.specifiers.length >= 1) {
198199
const propTypesSpecifier = node.specifiers.find((specifier) => (
199-
specifier.imported && specifier.imported.name === 'PropTypes'
200+
specifier.type === 'ImportSpecifier' && specifier.imported && specifier.imported.name === 'PropTypes'
200201
));
201202
if (propTypesSpecifier) {
202203
propTypesPackageName = propTypesSpecifier.local.name;
@@ -231,13 +232,17 @@ module.exports = {
231232
) {
232233
return;
233234
}
235+
if (node.parent.type !== 'AssignmentExpression') {
236+
return;
237+
}
234238

235239
checkNode(node.parent.right);
236240
},
237241

238242
CallExpression(node) {
239243
if (
240-
node.callee.object
244+
node.callee.type === 'MemberExpression'
245+
&& node.callee.object
241246
&& !isPropTypesPackage(node.callee.object)
242247
&& !propsUtil.isPropTypesDeclaration(node.callee)
243248
) {
@@ -246,7 +251,8 @@ module.exports = {
246251

247252
if (
248253
node.arguments.length > 0
249-
&& (node.callee.name === 'shape' || astUtil.getPropertyName(node.callee) === 'shape')
254+
&& ((node.callee.type === 'Identifier' && node.callee.name === 'shape') || astUtil.getPropertyName(node.callee) === 'shape')
255+
&& node.arguments[0].type === 'ObjectExpression'
250256
) {
251257
checkProperties(node.arguments[0].properties);
252258
}
@@ -271,7 +277,7 @@ module.exports = {
271277

272278
ObjectExpression(node) {
273279
node.properties.forEach((property) => {
274-
if (!property.key) {
280+
if (property.type !== 'Property') {
275281
return;
276282
}
277283

lib/rules/hook-use-state.js

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const messages = {
2626
suggestMemo: 'Replace useState call with useMemo',
2727
};
2828

29+
/** @type { import('eslint').Rule.RuleModule } */
2930
module.exports = {
3031
meta: {
3132
docs: {

lib/rules/jsx-closing-bracket-location.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const messages = {
2020
bracketLocation: 'The closing bracket must be {{location}}{{details}}',
2121
};
2222

23+
/** @type { import('eslint').Rule.RuleModule } */
2324
module.exports = {
2425
meta: {
2526
docs: {

lib/rules/jsx-curly-spacing.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ const messages = {
3535
spaceNeededBefore: 'A space is required before \'{{token}}\'',
3636
};
3737

38+
/** @type { import('eslint').Rule.RuleModule } */
3839
module.exports = {
3940
meta: {
4041
docs: {
@@ -393,7 +394,8 @@ module.exports = {
393394
if (spacing === SPACING.always) {
394395
if (!sourceCode.isSpaceBetweenTokens(first, second)) {
395396
reportRequiredBeginningSpace(node, first);
396-
} else if (!config.allowMultiline && isMultiline(first, second)) {
397+
} else if (!config.allowMultiline && isMultiline(first, second)
398+
) {
397399
reportNoBeginningNewline(node, first, spacing);
398400
}
399401
if (!sourceCode.isSpaceBetweenTokens(penultimate, last)) {
@@ -410,9 +412,10 @@ module.exports = {
410412
reportNoBeginningSpace(node, first);
411413
}
412414
if (isMultiline(penultimate, last)) {
413-
if (!config.allowMultiline) {
414-
reportNoEndingNewline(node, last, spacing);
415+
if (config.allowMultiline) {
416+
return;
415417
}
418+
reportNoEndingNewline(node, last, spacing);
416419
} else if (sourceCode.isSpaceBetweenTokens(penultimate, last)) {
417420
reportNoEndingSpace(node, last);
418421
}

lib/rules/jsx-equals-spacing.js

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ const messages = {
2020
needSpaceAfter: 'A space is required after \'=\'',
2121
};
2222

23+
/** @type { import('eslint').Rule.RuleModule } */
2324
module.exports = {
2425
meta: {
2526
docs: {

lib/rules/jsx-fragments.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ const messages = {
2828
preferFragment: 'Prefer fragment shorthand over {{react}}.{{fragment}}',
2929
};
3030

31+
/** @type { import('eslint').Rule.RuleModule } */
3132
module.exports = {
3233
meta: {
3334
docs: {
@@ -170,7 +171,7 @@ module.exports = {
170171
ImportDeclaration(node) {
171172
if (node.source && node.source.value === 'react') {
172173
node.specifiers.forEach((spec) => {
173-
if (spec.imported && spec.imported.name === fragmentPragma) {
174+
if (spec.type === "ImportSpecifier" && spec.imported && spec.imported.name === fragmentPragma) {
174175
if (spec.local) {
175176
fragmentNames.add(spec.local.name);
176177
}

lib/rules/jsx-indent-props.js

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ const messages = {
4545
wrongIndent: 'Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}.',
4646
};
4747

48+
/** @type { import('eslint').Rule.RuleModule } */
4849
module.exports = {
4950
meta: {
5051
docs: {

lib/rules/jsx-indent.js

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ const messages = {
5050
wrongIndent: 'Expected indentation of {{needed}} {{type}} {{characters}} but found {{gotten}}.',
5151
};
5252

53+
/** @type { import('eslint').Rule.RuleModule } */
5354
module.exports = {
5455
meta: {
5556
docs: {

lib/rules/jsx-no-bind.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const messages = {
2424
func: 'JSX props should not use functions',
2525
};
2626

27+
/** @type { import('eslint').Rule.RuleModule } */
2728
module.exports = {
2829
meta: {
2930
docs: {
@@ -172,10 +173,12 @@ module.exports = {
172173
const blockAncestors = getBlockStatementAncestors(node);
173174
const variableViolationType = getNodeViolationType(node.init);
174175

176+
const nodeParent = /** @type {import("estree").VariableDeclaration} */(node.parent);
175177
if (
176178
blockAncestors.length > 0
177179
&& variableViolationType
178-
&& node.parent.kind === 'const' // only support const right now
180+
&& nodeParent.kind === 'const' // only support const right now
181+
&& node.id.type === 'Identifier'
179182
) {
180183
addVariableNameToSet(
181184
variableViolationType, node.id.name, blockAncestors[0].range[0]

lib/rules/jsx-sort-default-props.js

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const messages = {
2525
propsNotSorted: 'Default prop types declarations should be sorted alphabetically',
2626
};
2727

28+
/** @type { import('eslint').Rule.RuleModule } */
2829
module.exports = {
2930
meta: {
3031
deprecated: true,
@@ -178,6 +179,10 @@ module.exports = {
178179
return;
179180
}
180181

182+
if (node.parent.type !== 'AssignmentExpression') {
183+
return;
184+
}
185+
181186
checkNode(node.parent.right);
182187
},
183188

lib/rules/jsx-space-before-closing.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const messages = {
2323
needSpaceBeforeClose: 'A space is required before closing bracket',
2424
};
2525

26+
/** @type { import('eslint').Rule.RuleModule } */
2627
module.exports = {
2728
meta: {
2829
deprecated: true,
@@ -58,7 +59,7 @@ module.exports = {
5859
const sourceCode = getSourceCode(context);
5960

6061
const leftToken = getTokenBeforeClosingBracket(node);
61-
const closingSlash = sourceCode.getTokenAfter(leftToken);
62+
const closingSlash = /** @type {import("eslint").AST.Token} */ (sourceCode.getTokenAfter(leftToken));
6263

6364
if (leftToken.loc.end.line !== closingSlash.loc.start.line) {
6465
return;

lib/rules/no-access-state-in-setstate.js

+20-11
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const messages = {
1818
useCallback: 'Use callback in setState when referencing the previous state.',
1919
};
2020

21+
/** @type { import('eslint').Rule.RuleModule } */
2122
module.exports = {
2223
meta: {
2324
docs: {
@@ -72,10 +73,10 @@ module.exports = {
7273
// Appends all the methods that are calling another
7374
// method containing this.state to the methods array
7475
methods.forEach((method) => {
75-
if (node.callee.name === method.methodName) {
76+
if (node.callee.type === 'Identifier' && node.callee.name === method.methodName) {
7677
let current = node.parent;
7778
while (current.type !== 'Program') {
78-
if (current.type === 'MethodDefinition') {
79+
if (current.type === 'MethodDefinition' && current.key.type === 'PrivateIdentifier') {
7980
methods.push({
8081
methodName: current.key.name,
8182
node: method.node,
@@ -91,7 +92,7 @@ module.exports = {
9192
// to further check if they contains this.state
9293
let current = node.parent;
9394
while (current.type !== 'Program') {
94-
if (isFirstArgumentInSetStateCall(current, node)) {
95+
if (isFirstArgumentInSetStateCall(current, node) && node.callee.type === 'Identifier') {
9596
const methodName = node.callee.name;
9697
methods.forEach((method) => {
9798
if (method.methodName === methodName) {
@@ -109,10 +110,12 @@ module.exports = {
109110

110111
MemberExpression(node) {
111112
if (
112-
node.property.name === 'state'
113+
node.property.type === 'Identifier'
114+
&& node.property.name === 'state'
113115
&& node.object.type === 'ThisExpression'
114116
&& isClassComponent(node)
115117
) {
118+
/** @type {import("eslint").Rule.Node} */
116119
let current = node;
117120
while (current.type !== 'Program') {
118121
// Reporting if this.state is directly within this.setState
@@ -124,13 +127,18 @@ module.exports = {
124127
}
125128

126129
// Storing all functions and methods that contains this.state
127-
if (current.type === 'MethodDefinition') {
130+
if (current.type === 'MethodDefinition' && current.key.type === 'Identifier') {
128131
methods.push({
129132
methodName: current.key.name,
130133
node,
131134
});
132135
break;
133-
} else if (current.type === 'FunctionExpression' && current.parent.key) {
136+
} else if (
137+
current.type === 'FunctionExpression'
138+
&& (current.parent.type === 'Property' || current.parent.type === 'MethodDefinition')
139+
&& current.parent.key.type === 'Identifier'
140+
&& current.parent.key
141+
) {
134142
methods.push({
135143
methodName: current.parent.key.name,
136144
node,
@@ -139,7 +147,7 @@ module.exports = {
139147
}
140148

141149
// Storing all variables containing this.state
142-
if (current.type === 'VariableDeclarator') {
150+
if (current.type === 'VariableDeclarator' && current.id.type === 'Identifier') {
143151
vars.push({
144152
node,
145153
scope: getScope(context, node),
@@ -155,13 +163,14 @@ module.exports = {
155163

156164
Identifier(node) {
157165
// Checks if the identifier is a variable within an object
166+
/** @type {import("eslint").Rule.Node} */
158167
let current = node;
159168
while (current.parent.type === 'BinaryExpression') {
160169
current = current.parent;
161170
}
162171
if (
163-
current.parent.value === current
164-
|| current.parent.object === current
172+
(current.parent.type === 'Property' && current.parent.value === current)
173+
|| (current.parent.type === 'MemberExpression' && current.parent.object === current)
165174
) {
166175
while (current.type !== 'Program') {
167176
if (isFirstArgumentInSetStateCall(current, node)) {
@@ -179,9 +188,9 @@ module.exports = {
179188
},
180189

181190
ObjectPattern(node) {
182-
const isDerivedFromThis = node.parent.init && node.parent.init.type === 'ThisExpression';
191+
const isDerivedFromThis = (node.parent.type === 'ForStatement' || node.parent.type === 'VariableDeclarator') && node.parent.init && node.parent.init.type === 'ThisExpression';
183192
node.properties.forEach((property) => {
184-
if (property && property.key && property.key.name === 'state' && isDerivedFromThis) {
193+
if (property.type === 'Property' && property.key.type === 'Identifier' && property.key.name === 'state' && isDerivedFromThis) {
185194
vars.push({
186195
node: property.key,
187196
scope: getScope(context, node),

0 commit comments

Comments
 (0)