UNPKG

3.15 kBJavaScriptView Raw
1/**
2 * @fileOverview Enforce all defaultProps are defined in propTypes
3 * @author Vitor Balocco
4 * @author Roy Sutton
5 */
6
7'use strict';
8
9const Components = require('../util/Components');
10const docsUrl = require('../util/docsUrl');
11
12// ------------------------------------------------------------------------------
13// Rule Definition
14// ------------------------------------------------------------------------------
15
16module.exports = {
17 meta: {
18 docs: {
19 description: 'Enforce all defaultProps are defined and not "required" in propTypes.',
20 category: 'Best Practices',
21 url: docsUrl('default-props-match-prop-types')
22 },
23
24 schema: [{
25 type: 'object',
26 properties: {
27 allowRequiredDefaults: {
28 default: false,
29 type: 'boolean'
30 }
31 },
32 additionalProperties: false
33 }]
34 },
35
36 create: Components.detect((context, components) => {
37 const configuration = context.options[0] || {};
38 const allowRequiredDefaults = configuration.allowRequiredDefaults || false;
39
40 /**
41 * Reports all defaultProps passed in that don't have an appropriate propTypes counterpart.
42 * @param {Object[]} propTypes Array of propTypes to check.
43 * @param {Object} defaultProps Object of defaultProps to check. Keys are the props names.
44 * @return {void}
45 */
46 function reportInvalidDefaultProps(propTypes, defaultProps) {
47 // If this defaultProps is "unresolved" or the propTypes is undefined, then we should ignore
48 // this component and not report any errors for it, to avoid false-positives with e.g.
49 // external defaultProps/propTypes declarations or spread operators.
50 if (defaultProps === 'unresolved' || !propTypes || Object.keys(propTypes).length === 0) {
51 return;
52 }
53
54 Object.keys(defaultProps).forEach((defaultPropName) => {
55 const defaultProp = defaultProps[defaultPropName];
56 const prop = propTypes[defaultPropName];
57
58 if (prop && (allowRequiredDefaults || !prop.isRequired)) {
59 return;
60 }
61
62 if (prop) {
63 context.report({
64 node: defaultProp.node,
65 message: 'defaultProp "{{name}}" defined for isRequired propType.',
66 data: {name: defaultPropName}
67 });
68 } else {
69 context.report({
70 node: defaultProp.node,
71 message: 'defaultProp "{{name}}" has no corresponding propTypes declaration.',
72 data: {name: defaultPropName}
73 });
74 }
75 });
76 }
77
78 // --------------------------------------------------------------------------
79 // Public API
80 // --------------------------------------------------------------------------
81
82 return {
83 'Program:exit'() {
84 const list = components.list();
85
86 // If no defaultProps could be found, we don't report anything.
87 Object.keys(list).filter((component) => list[component].defaultProps).forEach((component) => {
88 reportInvalidDefaultProps(
89 list[component].declaredPropTypes,
90 list[component].defaultProps || {}
91 );
92 });
93 }
94 };
95 })
96};