1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 | 'use strict';
|
7 |
|
8 | const Components = require('../util/Components');
|
9 | const docsUrl = require('../util/docsUrl');
|
10 | const astUtil = require('../util/ast');
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 | module.exports = {
|
17 | meta: {
|
18 | docs: {
|
19 | description: 'Enforce a defaultProps definition for every prop that is not a required prop.',
|
20 | category: 'Best Practices',
|
21 | url: docsUrl('require-default-props')
|
22 | },
|
23 |
|
24 | schema: [{
|
25 | type: 'object',
|
26 | properties: {
|
27 | forbidDefaultForRequired: {
|
28 | type: 'boolean'
|
29 | },
|
30 | ignoreFunctionalComponents: {
|
31 | type: 'boolean'
|
32 | }
|
33 | },
|
34 | additionalProperties: false
|
35 | }]
|
36 | },
|
37 |
|
38 | create: Components.detect((context, components) => {
|
39 | const configuration = context.options[0] || {};
|
40 | const forbidDefaultForRequired = configuration.forbidDefaultForRequired || false;
|
41 | const ignoreFunctionalComponents = configuration.ignoreFunctionalComponents || false;
|
42 |
|
43 | |
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | function reportPropTypesWithoutDefault(propTypes, defaultProps) {
|
50 |
|
51 |
|
52 | if (defaultProps === 'unresolved') {
|
53 | return;
|
54 | }
|
55 |
|
56 | Object.keys(propTypes).forEach((propName) => {
|
57 | const prop = propTypes[propName];
|
58 | if (prop.isRequired) {
|
59 | if (forbidDefaultForRequired && defaultProps[propName]) {
|
60 | context.report({
|
61 | node: prop.node,
|
62 | message: 'propType "{{name}}" is required and should not have a defaultProps declaration.',
|
63 | data: {name: propName}
|
64 | });
|
65 | }
|
66 | return;
|
67 | }
|
68 |
|
69 | if (defaultProps[propName]) {
|
70 | return;
|
71 | }
|
72 |
|
73 | context.report({
|
74 | node: prop.node,
|
75 | message: 'propType "{{name}}" is not required, but has no corresponding defaultProps declaration.',
|
76 | data: {name: propName}
|
77 | });
|
78 | });
|
79 | }
|
80 |
|
81 |
|
82 |
|
83 |
|
84 |
|
85 | return {
|
86 | 'Program:exit'() {
|
87 | const list = components.list();
|
88 |
|
89 | Object.keys(list).filter((component) => {
|
90 | if (ignoreFunctionalComponents
|
91 | && (astUtil.isFunction(list[component].node) || astUtil.isFunctionLikeExpression(list[component].node))) {
|
92 | return false;
|
93 | }
|
94 | return list[component].declaredPropTypes;
|
95 | }).forEach((component) => {
|
96 | reportPropTypesWithoutDefault(
|
97 | list[component].declaredPropTypes,
|
98 | list[component].defaultProps || {}
|
99 | );
|
100 | });
|
101 | }
|
102 | };
|
103 | })
|
104 | };
|