source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/prefer-exact-props.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 4.9 KB
Line 
1/**
2 * @fileoverview Prefer exact proptype definitions
3 */
4
5'use strict';
6
7const Components = require('../util/Components');
8const docsUrl = require('../util/docsUrl');
9const propsUtil = require('../util/props');
10const propWrapperUtil = require('../util/propWrapper');
11const variableUtil = require('../util/variable');
12const report = require('../util/report');
13const getText = require('../util/eslint').getText;
14
15// -----------------------------------------------------------------------------
16// Rule Definition
17// -----------------------------------------------------------------------------
18
19const messages = {
20 propTypes: 'Component propTypes should be exact by using {{exactPropWrappers}}.',
21 flow: 'Component flow props should be set with exact objects.',
22};
23
24/** @type {import('eslint').Rule.RuleModule} */
25module.exports = {
26 meta: {
27 docs: {
28 description: 'Prefer exact proptype definitions',
29 category: 'Possible Errors',
30 recommended: false,
31 url: docsUrl('prefer-exact-props'),
32 },
33 messages,
34 schema: [],
35 },
36
37 create: Components.detect((context, components, utils) => {
38 const typeAliases = {};
39 const exactWrappers = propWrapperUtil.getExactPropWrapperFunctions(context);
40
41 function getPropTypesErrorMessage() {
42 const formattedWrappers = propWrapperUtil.formatPropWrapperFunctions(exactWrappers);
43 const message = exactWrappers.size > 1 ? `one of ${formattedWrappers}` : formattedWrappers;
44 return { exactPropWrappers: message };
45 }
46
47 function isNonExactObjectTypeAnnotation(node) {
48 return (
49 node
50 && node.type === 'ObjectTypeAnnotation'
51 && node.properties.length > 0
52 && !node.exact
53 );
54 }
55
56 function hasNonExactObjectTypeAnnotation(node) {
57 const typeAnnotation = node.typeAnnotation;
58 return (
59 typeAnnotation
60 && typeAnnotation.typeAnnotation
61 && isNonExactObjectTypeAnnotation(typeAnnotation.typeAnnotation)
62 );
63 }
64
65 function hasGenericTypeAnnotation(node) {
66 const typeAnnotation = node.typeAnnotation;
67 return (
68 typeAnnotation
69 && typeAnnotation.typeAnnotation
70 && typeAnnotation.typeAnnotation.type === 'GenericTypeAnnotation'
71 );
72 }
73
74 function isNonEmptyObjectExpression(node) {
75 return (
76 node
77 && node.type === 'ObjectExpression'
78 && node.properties.length > 0
79 );
80 }
81
82 function isNonExactPropWrapperFunction(node) {
83 return (
84 node
85 && node.type === 'CallExpression'
86 && !propWrapperUtil.isExactPropWrapperFunction(context, getText(context, node.callee))
87 );
88 }
89
90 function reportPropTypesError(node) {
91 report(context, messages.propTypes, 'propTypes', {
92 node,
93 data: getPropTypesErrorMessage(),
94 });
95 }
96
97 function reportFlowError(node) {
98 report(context, messages.flow, 'flow', {
99 node,
100 });
101 }
102
103 return {
104 TypeAlias(node) {
105 // working around an issue with eslint@3 and babel-eslint not finding the TypeAlias in scope
106 typeAliases[node.id.name] = node;
107 },
108
109 'ClassProperty, PropertyDefinition'(node) {
110 if (!propsUtil.isPropTypesDeclaration(node)) {
111 return;
112 }
113
114 if (hasNonExactObjectTypeAnnotation(node)) {
115 reportFlowError(node);
116 } else if (exactWrappers.size > 0 && isNonEmptyObjectExpression(node.value)) {
117 reportPropTypesError(node);
118 } else if (exactWrappers.size > 0 && isNonExactPropWrapperFunction(node.value)) {
119 reportPropTypesError(node);
120 }
121 },
122
123 Identifier(node) {
124 if (!utils.getStatelessComponent(node.parent)) {
125 return;
126 }
127
128 if (hasNonExactObjectTypeAnnotation(node)) {
129 reportFlowError(node);
130 } else if (hasGenericTypeAnnotation(node)) {
131 const identifier = node.typeAnnotation.typeAnnotation.id.name;
132 const typeAlias = typeAliases[identifier];
133 const propsDefinition = typeAlias ? typeAlias.right : null;
134 if (isNonExactObjectTypeAnnotation(propsDefinition)) {
135 reportFlowError(node);
136 }
137 }
138 },
139
140 MemberExpression(node) {
141 if (!propsUtil.isPropTypesDeclaration(node) || exactWrappers.size === 0) {
142 return;
143 }
144
145 const right = node.parent.right;
146 if (isNonEmptyObjectExpression(right)) {
147 reportPropTypesError(node);
148 } else if (isNonExactPropWrapperFunction(right)) {
149 reportPropTypesError(node);
150 } else if (right.type === 'Identifier') {
151 const identifier = right.name;
152 const propsDefinition = variableUtil.findVariableByName(context, node, identifier);
153 if (isNonEmptyObjectExpression(propsDefinition)) {
154 reportPropTypesError(node);
155 } else if (isNonExactPropWrapperFunction(propsDefinition)) {
156 reportPropTypesError(node);
157 }
158 }
159 },
160 };
161 }),
162};
Note: See TracBrowser for help on using the repository browser.