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

main
Last change on this file since 0c6b92a was 0c6b92a, checked in by stefan toskovski <stefantoska84@…>, 5 weeks ago

Pred finalna verzija

  • 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 astUtil = require('../util/ast');
10const propsUtil = require('../util/props');
11const propWrapperUtil = require('../util/propWrapper');
12const variableUtil = require('../util/variable');
13const report = require('../util/report');
14const getText = require('../util/eslint').getText;
15
16// -----------------------------------------------------------------------------
17// Rule Definition
18// -----------------------------------------------------------------------------
19
20const messages = {
21 propTypes: 'Component propTypes should be exact by using {{exactPropWrappers}}.',
22 flow: 'Component flow props should be set with exact objects.',
23};
24
25/** @type {import('eslint').Rule.RuleModule} */
26module.exports = {
27 meta: {
28 docs: {
29 description: 'Prefer exact proptype definitions',
30 category: 'Possible Errors',
31 recommended: false,
32 url: docsUrl('prefer-exact-props'),
33 },
34 messages,
35 schema: [],
36 },
37
38 create: Components.detect((context, components, utils) => {
39 const typeAliases = {};
40 const exactWrappers = propWrapperUtil.getExactPropWrapperFunctions(context);
41
42 function getPropTypesErrorMessage() {
43 const formattedWrappers = propWrapperUtil.formatPropWrapperFunctions(exactWrappers);
44 const message = exactWrappers.size > 1 ? `one of ${formattedWrappers}` : formattedWrappers;
45 return { exactPropWrappers: message };
46 }
47
48 function isNonExactObjectTypeAnnotation(node) {
49 return (
50 node
51 && node.type === 'ObjectTypeAnnotation'
52 && node.properties.length > 0
53 && !node.exact
54 );
55 }
56
57 function hasNonExactObjectTypeAnnotation(node) {
58 const typeAnnotation = node.typeAnnotation;
59 return (
60 typeAnnotation
61 && typeAnnotation.typeAnnotation
62 && isNonExactObjectTypeAnnotation(typeAnnotation.typeAnnotation)
63 );
64 }
65
66 function hasGenericTypeAnnotation(node) {
67 const typeAnnotation = node.typeAnnotation;
68 return (
69 typeAnnotation
70 && typeAnnotation.typeAnnotation
71 && typeAnnotation.typeAnnotation.type === 'GenericTypeAnnotation'
72 );
73 }
74
75 function isNonEmptyObjectExpression(node) {
76 return (
77 node
78 && node.type === 'ObjectExpression'
79 && node.properties.length > 0
80 );
81 }
82
83 function isNonExactPropWrapperFunction(node) {
84 return (
85 astUtil.isCallExpression(node)
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.