Skip to content

Commit 6075926

Browse files
authored
Merge pull request #1942 from alexzherdev/default-props-detection
Extract defaultProps detection
2 parents bd083bf + b81e19a commit 6075926

File tree

5 files changed

+304
-236
lines changed

5 files changed

+304
-236
lines changed

lib/rules/default-props-match-prop-types.js

Lines changed: 16 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -200,39 +200,6 @@ module.exports = {
200200
});
201201
}
202202

203-
/**
204-
* Extracts a DefaultProp from an ObjectExpression node.
205-
* @param {ASTNode} objectExpression ObjectExpression node.
206-
* @returns {Object|string} Object representation of a defaultProp, to be consumed by
207-
* `addDefaultPropsToComponent`, or string "unresolved", if the defaultProps
208-
* from this ObjectExpression can't be resolved.
209-
*/
210-
function getDefaultPropsFromObjectExpression(objectExpression) {
211-
const hasSpread = objectExpression.properties.find(property => property.type === 'ExperimentalSpreadProperty' || property.type === 'SpreadElement');
212-
213-
if (hasSpread) {
214-
return 'unresolved';
215-
}
216-
217-
return objectExpression.properties.map(defaultProp => ({
218-
name: defaultProp.key.name,
219-
node: defaultProp
220-
}));
221-
}
222-
223-
/**
224-
* Marks a component's DefaultProps declaration as "unresolved". A component's DefaultProps is
225-
* marked as "unresolved" if we cannot safely infer the values of its defaultProps declarations
226-
* without risking false negatives.
227-
* @param {Object} component The component to mark.
228-
* @returns {void}
229-
*/
230-
function markDefaultPropsAsUnresolved(component) {
231-
components.set(component.node, {
232-
defaultProps: 'unresolved'
233-
});
234-
}
235-
236203
/**
237204
* Adds propTypes to the component passed in.
238205
* @param {ASTNode} component The component to add the propTypes to.
@@ -247,31 +214,6 @@ module.exports = {
247214
});
248215
}
249216

250-
/**
251-
* Adds defaultProps to the component passed in.
252-
* @param {ASTNode} component The component to add the defaultProps to.
253-
* @param {String[]|String} defaultProps defaultProps to add to the component or the string "unresolved"
254-
* if this component has defaultProps that can't be resolved.
255-
* @returns {void}
256-
*/
257-
function addDefaultPropsToComponent(component, defaultProps) {
258-
// Early return if this component's defaultProps is already marked as "unresolved".
259-
if (component.defaultProps === 'unresolved') {
260-
return;
261-
}
262-
263-
if (defaultProps === 'unresolved') {
264-
markDefaultPropsAsUnresolved(component);
265-
return;
266-
}
267-
268-
const defaults = component.defaultProps || [];
269-
270-
components.set(component.node, {
271-
defaultProps: defaults.concat(defaultProps)
272-
});
273-
}
274-
275217
/**
276218
* Tries to find a props type annotation in a stateless component.
277219
* @param {ASTNode} node The AST node to look for a props type annotation.
@@ -322,8 +264,9 @@ module.exports = {
322264
return;
323265
}
324266

325-
defaultProps.forEach(defaultProp => {
326-
const prop = propFromName(propTypes, defaultProp.name);
267+
Object.keys(defaultProps).forEach(defaultPropName => {
268+
const defaultProp = defaultProps[defaultPropName];
269+
const prop = propFromName(propTypes, defaultPropName);
327270

328271
if (prop && (allowRequiredDefaults || !prop.isRequired)) {
329272
return;
@@ -333,13 +276,13 @@ module.exports = {
333276
context.report(
334277
defaultProp.node,
335278
'defaultProp "{{name}}" defined for isRequired propType.',
336-
{name: defaultProp.name}
279+
{name: defaultPropName}
337280
);
338281
} else {
339282
context.report(
340283
defaultProp.node,
341284
'defaultProp "{{name}}" has no corresponding propTypes declaration.',
342-
{name: defaultProp.name}
285+
{name: defaultPropName}
343286
);
344287
}
345288
});
@@ -352,9 +295,8 @@ module.exports = {
352295
return {
353296
MemberExpression: function(node) {
354297
const isPropType = propsUtil.isPropTypesDeclaration(node);
355-
const isDefaultProp = propsUtil.isDefaultPropsDeclaration(node);
356298

357-
if (!isPropType && !isDefaultProp) {
299+
if (!isPropType) {
358300
return;
359301
}
360302

@@ -375,21 +317,8 @@ module.exports = {
375317
// MyComponent.propTypes = myPropTypes;
376318
if (node.parent.type === 'AssignmentExpression') {
377319
const expression = resolveNodeValue(node.parent.right);
378-
if (!expression || expression.type !== 'ObjectExpression') {
379-
// If a value can't be found, we mark the defaultProps declaration as "unresolved", because
380-
// we should ignore this component and not report any errors for it, to avoid false-positives
381-
// with e.g. external defaultProps declarations.
382-
if (isDefaultProp) {
383-
markDefaultPropsAsUnresolved(component);
384-
}
385-
386-
return;
387-
}
388-
389-
if (isPropType) {
320+
if (expression && expression.type === 'ObjectExpression') {
390321
addPropTypesToComponent(component, getPropTypesFromObjectExpression(expression));
391-
} else {
392-
addDefaultPropsToComponent(component, getDefaultPropsFromObjectExpression(expression));
393322
}
394323

395324
return;
@@ -399,20 +328,11 @@ module.exports = {
399328
// MyComponent.propTypes.baz = React.PropTypes.string;
400329
if (node.parent.type === 'MemberExpression' && node.parent.parent &&
401330
node.parent.parent.type === 'AssignmentExpression') {
402-
if (isPropType) {
403-
addPropTypesToComponent(component, [{
404-
name: node.parent.property.name,
405-
isRequired: propsUtil.isRequiredPropType(node.parent.parent.right),
406-
node: node.parent.parent
407-
}]);
408-
} else {
409-
addDefaultPropsToComponent(component, [{
410-
name: node.parent.property.name,
411-
node: node.parent.parent
412-
}]);
413-
}
414-
415-
return;
331+
addPropTypesToComponent(component, [{
332+
name: node.parent.property.name,
333+
isRequired: propsUtil.isRequiredPropType(node.parent.parent.right),
334+
node: node.parent.parent
335+
}]);
416336
}
417337
},
418338

@@ -438,9 +358,8 @@ module.exports = {
438358
}
439359

440360
const isPropType = propsUtil.isPropTypesDeclaration(node);
441-
const isDefaultProp = propsUtil.isDefaultPropsDeclaration(node);
442361

443-
if (!isPropType && !isDefaultProp) {
362+
if (!isPropType) {
444363
return;
445364
}
446365

@@ -460,11 +379,7 @@ module.exports = {
460379
return;
461380
}
462381

463-
if (isPropType) {
464-
addPropTypesToComponent(component, getPropTypesFromObjectExpression(expression));
465-
} else {
466-
addDefaultPropsToComponent(component, getDefaultPropsFromObjectExpression(expression));
467-
}
382+
addPropTypesToComponent(component, getPropTypesFromObjectExpression(expression));
468383
},
469384

470385
// e.g.:
@@ -495,9 +410,8 @@ module.exports = {
495410

496411
const propName = astUtil.getPropertyName(node);
497412
const isPropType = propName === 'propTypes';
498-
const isDefaultProp = propName === 'defaultProps' || propName === 'getDefaultProps';
499413

500-
if (!isPropType && !isDefaultProp) {
414+
if (!isPropType) {
501415
return;
502416
}
503417

@@ -512,11 +426,7 @@ module.exports = {
512426
return;
513427
}
514428

515-
if (isPropType) {
516-
addPropTypesToComponent(component, getPropTypesFromObjectExpression(expression));
517-
} else {
518-
addDefaultPropsToComponent(component, getDefaultPropsFromObjectExpression(expression));
519-
}
429+
addPropTypesToComponent(component, getPropTypesFromObjectExpression(expression));
520430
},
521431

522432
// e.g.:
@@ -547,25 +457,11 @@ module.exports = {
547457
}
548458

549459
const isPropType = propsUtil.isPropTypesDeclaration(property);
550-
const isDefaultProp = propsUtil.isDefaultPropsDeclaration(property);
551-
552-
if (!isPropType && !isDefaultProp) {
553-
return;
554-
}
555460

556461
if (isPropType && property.value.type === 'ObjectExpression') {
557462
addPropTypesToComponent(component, getPropTypesFromObjectExpression(property.value));
558463
return;
559464
}
560-
561-
if (isDefaultProp && property.value.type === 'FunctionExpression') {
562-
const returnStatement = utils.findReturnStatement(property);
563-
if (!returnStatement || returnStatement.argument.type !== 'ObjectExpression') {
564-
return;
565-
}
566-
567-
addDefaultPropsToComponent(component, getDefaultPropsFromObjectExpression(returnStatement.argument));
568-
}
569465
});
570466
},
571467

0 commit comments

Comments
 (0)