Skip to content

Commit 3a03579

Browse files
committed
[Refactor] usedPropTypes: avoid switch statements
1 parent 2c98b83 commit 3a03579

File tree

2 files changed

+87
-85
lines changed

2 files changed

+87
-85
lines changed

Diff for: lib/util/ast.js

+21
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,24 @@ function isTSTypeParameterInstantiation(node) {
448448
return node.type === 'TSTypeParameterInstantiation';
449449
}
450450

451+
function isMemberExpression(node) {
452+
if (!node) { return false; }
453+
454+
return node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression';
455+
}
456+
457+
function isObjectPattern(node) {
458+
if (!node) { return false; }
459+
460+
return node.type === 'ObjectPattern';
461+
}
462+
463+
function isVariableDeclarator(node) {
464+
if (!node) { return false; }
465+
466+
return node.type === 'VariableDeclarator';
467+
}
468+
451469
module.exports = {
452470
findReturnStatement,
453471
getComponentProperties,
@@ -462,7 +480,9 @@ module.exports = {
462480
isFunction,
463481
isFunctionLike,
464482
isFunctionLikeExpression,
483+
isMemberExpression,
465484
isNodeFirstInLine,
485+
isObjectPattern,
466486
isParenthesized,
467487
isTSAsExpression,
468488
isTSFunctionType,
@@ -477,6 +497,7 @@ module.exports = {
477497
isTSTypeParameterInstantiation,
478498
isTSTypeQuery,
479499
isTSTypeReference,
500+
isVariableDeclarator,
480501
traverse,
481502
traverseReturns,
482503
unwrapTSAsExpression,

Diff for: lib/util/usedPropTypes.js

+66-85
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ const values = require('object.values');
99
const astUtil = require('./ast');
1010
const componentUtil = require('./componentUtil');
1111
const testReactVersion = require('./version').testReactVersion;
12-
const ast = require('./ast');
1312
const eslintUtil = require('./eslint');
1413

1514
const getScope = eslintUtil.getScope;
@@ -164,7 +163,7 @@ function isInLifeCycleMethod(node, checkAsyncSafeLifeCycles) {
164163
*/
165164
function isSetStateUpdater(node) {
166165
const unwrappedParentCalleeNode = astUtil.isCallExpression(node.parent)
167-
&& ast.unwrapTSAsExpression(node.parent.callee);
166+
&& astUtil.unwrapTSAsExpression(node.parent.callee);
168167

169168
return unwrappedParentCalleeNode
170169
&& unwrappedParentCalleeNode.property
@@ -181,7 +180,7 @@ function isPropArgumentInSetStateUpdater(context, node, name) {
181180
while (scope) {
182181
const unwrappedParentCalleeNode = scope.block
183182
&& astUtil.isCallExpression(scope.block.parent)
184-
&& ast.unwrapTSAsExpression(scope.block.parent.callee);
183+
&& astUtil.unwrapTSAsExpression(scope.block.parent.callee);
185184
if (
186185
unwrappedParentCalleeNode
187186
&& unwrappedParentCalleeNode.property
@@ -215,7 +214,7 @@ function isInClassComponent(context, node) {
215214
function isThisDotProps(node) {
216215
return !!node
217216
&& node.type === 'MemberExpression'
218-
&& ast.unwrapTSAsExpression(node.object).type === 'ThisExpression'
217+
&& astUtil.unwrapTSAsExpression(node.object).type === 'ThisExpression'
219218
&& node.property.name === 'props';
220219
}
221220

@@ -239,7 +238,7 @@ function hasSpreadOperator(context, node) {
239238
* @returns {boolean}
240239
*/
241240
function isPropTypesUsageByMemberExpression(context, node, utils, checkAsyncSafeLifeCycles) {
242-
const unwrappedObjectNode = ast.unwrapTSAsExpression(node.object);
241+
const unwrappedObjectNode = astUtil.unwrapTSAsExpression(node.object);
243242

244243
if (isInClassComponent(context, node)) {
245244
// this.props.*
@@ -260,7 +259,7 @@ function isPropTypesUsageByMemberExpression(context, node, utils, checkAsyncSafe
260259
return false;
261260
}
262261
// props.* in function component
263-
return unwrappedObjectNode.name === 'props' && !ast.isAssignmentLHS(node);
262+
return unwrappedObjectNode.name === 'props' && !astUtil.isAssignmentLHS(node);
264263
}
265264

266265
/**
@@ -321,109 +320,91 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
321320
let name;
322321
let allNames;
323322
let properties;
324-
switch (node.type) {
325-
case 'OptionalMemberExpression':
326-
case 'MemberExpression':
327-
name = getPropertyName(context, node, utils, checkAsyncSafeLifeCycles);
328-
if (name) {
329-
allNames = parentNames.concat(name);
330-
if (
331-
// Match props.foo.bar, don't match bar[props.foo]
332-
node.parent.type === 'MemberExpression'
333-
&& node.parent.object === node
334-
) {
335-
markPropTypesAsUsed(node.parent, allNames);
336-
}
337-
// Handle the destructuring part of `const {foo} = props.a.b`
338-
if (
339-
node.parent.type === 'VariableDeclarator'
340-
&& node.parent.id.type === 'ObjectPattern'
341-
) {
342-
node.parent.id.parent = node.parent; // patch for bug in eslint@4 in which ObjectPattern has no parent
343-
markPropTypesAsUsed(node.parent.id, allNames);
344-
}
345-
346-
// const a = props.a
347-
if (
348-
node.parent.type === 'VariableDeclarator'
349-
&& node.parent.id.type === 'Identifier'
350-
) {
351-
propVariables.set(node.parent.id.name, allNames);
352-
}
353-
// Do not mark computed props as used.
354-
type = name !== '__COMPUTED_PROP__' ? 'direct' : null;
323+
if (astUtil.isMemberExpression(node)) {
324+
name = getPropertyName(context, node, utils, checkAsyncSafeLifeCycles);
325+
if (name) {
326+
allNames = parentNames.concat(name);
327+
const parent = node.parent;
328+
if (
329+
// Match props.foo.bar, don't match bar[props.foo]
330+
parent.type === 'MemberExpression'
331+
&& 'object' in parent
332+
&& parent.object === node
333+
) {
334+
markPropTypesAsUsed(parent, allNames);
355335
}
356-
break;
357-
case 'ArrowFunctionExpression':
358-
case 'FunctionDeclaration':
359-
case 'FunctionExpression': {
360-
if (node.params.length === 0) {
361-
break;
336+
// Handle the destructuring part of `const {foo} = props.a.b`
337+
if (
338+
astUtil.isVariableDeclarator(parent)
339+
&& parent.id.type === 'ObjectPattern'
340+
) {
341+
parent.id.parent = parent; // patch for bug in eslint@4 in which ObjectPattern has no parent
342+
markPropTypesAsUsed(parent.id, allNames);
343+
}
344+
345+
// const a = props.a
346+
if (
347+
astUtil.isVariableDeclarator(parent)
348+
&& parent.id.type === 'Identifier'
349+
) {
350+
propVariables.set(parent.id.name, allNames);
362351
}
352+
// Do not mark computed props as used.
353+
type = name !== '__COMPUTED_PROP__' ? 'direct' : null;
354+
}
355+
} else if (astUtil.isFunctionLike(node)) {
356+
if (node.params.length > 0) {
363357
type = 'destructuring';
364358
const propParam = isSetStateUpdater(node) ? node.params[1] : node.params[0];
365359
properties = propParam.type === 'AssignmentPattern'
366360
? propParam.left.properties
367361
: propParam.properties;
368-
break;
369362
}
370-
case 'ObjectPattern':
371-
type = 'destructuring';
372-
properties = node.properties;
373-
break;
374-
case 'TSEmptyBodyFunctionExpression':
375-
break;
376-
default:
377-
throw new Error(`${node.type} ASTNodes are not handled by markPropTypesAsUsed`);
363+
} else if (astUtil.isObjectPattern(node)) {
364+
type = 'destructuring';
365+
properties = node.properties;
366+
} else if (node.type !== 'TSEmptyBodyFunctionExpression') {
367+
throw new Error(`${node.type} ASTNodes are not handled by markPropTypesAsUsed`);
378368
}
379369

380370
const component = components.get(utils.getParentComponent(node));
381371
const usedPropTypes = (component && component.usedPropTypes) || [];
382372
let ignoreUnusedPropTypesValidation = (component && component.ignoreUnusedPropTypesValidation) || false;
383373

384-
switch (type) {
385-
case 'direct': {
386-
// Ignore Object methods
387-
if (name in Object.prototype) {
388-
break;
389-
}
390-
374+
if (type === 'direct') {
375+
// Ignore Object methods
376+
if (!(name in Object.prototype)) {
391377
const reportedNode = node.property;
392378
usedPropTypes.push({
393379
name,
394380
allNames,
395381
node: reportedNode,
396382
});
397-
break;
398383
}
399-
case 'destructuring': {
400-
for (let k = 0, l = (properties || []).length; k < l; k++) {
401-
if (hasSpreadOperator(context, properties[k]) || properties[k].computed) {
402-
ignoreUnusedPropTypesValidation = true;
403-
break;
404-
}
405-
const propName = ast.getKeyValue(context, properties[k]);
384+
} else if (type === 'destructuring') {
385+
for (let k = 0, l = (properties || []).length; k < l; k++) {
386+
if (hasSpreadOperator(context, properties[k]) || properties[k].computed) {
387+
ignoreUnusedPropTypesValidation = true;
388+
break;
389+
}
390+
const propName = astUtil.getKeyValue(context, properties[k]);
406391

407-
if (!propName || properties[k].type !== 'Property') {
408-
break;
409-
}
392+
if (!propName || properties[k].type !== 'Property') {
393+
break;
394+
}
410395

411-
usedPropTypes.push({
412-
allNames: parentNames.concat([propName]),
413-
name: propName,
414-
node: properties[k],
415-
});
396+
usedPropTypes.push({
397+
allNames: parentNames.concat([propName]),
398+
name: propName,
399+
node: properties[k],
400+
});
416401

417-
if (properties[k].value.type === 'ObjectPattern') {
418-
markPropTypesAsUsed(properties[k].value, parentNames.concat([propName]));
419-
} else if (properties[k].value.type === 'Identifier') {
420-
propVariables.set(properties[k].value.name, parentNames.concat(propName));
421-
}
402+
if (properties[k].value.type === 'ObjectPattern') {
403+
markPropTypesAsUsed(properties[k].value, parentNames.concat([propName]));
404+
} else if (properties[k].value.type === 'Identifier') {
405+
propVariables.set(properties[k].value.name, parentNames.concat(propName));
422406
}
423-
break;
424407
}
425-
default:
426-
break;
427408
}
428409

429410
components.set(component ? component.node : node, {
@@ -484,7 +465,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
484465

485466
return {
486467
VariableDeclarator(node) {
487-
const unwrappedInitNode = ast.unwrapTSAsExpression(node.init);
468+
const unwrappedInitNode = astUtil.unwrapTSAsExpression(node.init);
488469

489470
// let props = this.props
490471
if (isThisDotProps(unwrappedInitNode) && isInClassComponent(context, node) && node.id.type === 'Identifier') {
@@ -559,7 +540,7 @@ module.exports = function usedPropTypesInstructions(context, components, utils)
559540
return;
560541
}
561542

562-
const propVariable = propVariables.get(ast.unwrapTSAsExpression(node.object).name);
543+
const propVariable = propVariables.get(astUtil.unwrapTSAsExpression(node.object).name);
563544
if (propVariable) {
564545
markPropTypesAsUsed(node, propVariable);
565546
}

0 commit comments

Comments
 (0)