source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/forbid-component-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: 7.6 KB
Line 
1/**
2 * @fileoverview Forbid certain props on components
3 * @author Joe Lencioni
4 */
5
6'use strict';
7
8const minimatch = require('minimatch');
9const docsUrl = require('../util/docsUrl');
10const report = require('../util/report');
11
12// ------------------------------------------------------------------------------
13// Constants
14// ------------------------------------------------------------------------------
15
16const DEFAULTS = ['className', 'style'];
17
18// ------------------------------------------------------------------------------
19// Rule Definition
20// ------------------------------------------------------------------------------
21
22const messages = {
23 propIsForbidden: 'Prop "{{prop}}" is forbidden on Components',
24};
25
26/** @type {import('eslint').Rule.RuleModule} */
27module.exports = {
28 meta: {
29 docs: {
30 description: 'Disallow certain props on components',
31 category: 'Best Practices',
32 recommended: false,
33 url: docsUrl('forbid-component-props'),
34 },
35
36 messages,
37
38 schema: [{
39 type: 'object',
40 properties: {
41 forbid: {
42 type: 'array',
43 items: {
44 anyOf: [
45 { type: 'string' },
46 {
47 type: 'object',
48 properties: {
49 propName: { type: 'string' },
50 allowedFor: {
51 type: 'array',
52 uniqueItems: true,
53 items: { type: 'string' },
54 },
55 allowedForPatterns: {
56 type: 'array',
57 uniqueItems: true,
58 items: { type: 'string' },
59 },
60 message: { type: 'string' },
61 },
62 additionalProperties: false,
63 },
64 {
65 type: 'object',
66 properties: {
67 propName: { type: 'string' },
68 disallowedFor: {
69 type: 'array',
70 uniqueItems: true,
71 minItems: 1,
72 items: { type: 'string' },
73 },
74 disallowedForPatterns: {
75 type: 'array',
76 uniqueItems: true,
77 minItems: 1,
78 items: { type: 'string' },
79 },
80 message: { type: 'string' },
81 },
82 anyOf: [
83 { required: ['disallowedFor'] },
84 { required: ['disallowedForPatterns'] },
85 ],
86 additionalProperties: false,
87 },
88 {
89 type: 'object',
90 properties: {
91 propNamePattern: { type: 'string' },
92 allowedFor: {
93 type: 'array',
94 uniqueItems: true,
95 items: { type: 'string' },
96 },
97 allowedForPatterns: {
98 type: 'array',
99 uniqueItems: true,
100 items: { type: 'string' },
101 },
102 message: { type: 'string' },
103 },
104 additionalProperties: false,
105 },
106 {
107 type: 'object',
108 properties: {
109 propNamePattern: { type: 'string' },
110 disallowedFor: {
111 type: 'array',
112 uniqueItems: true,
113 minItems: 1,
114 items: { type: 'string' },
115 },
116 disallowedForPatterns: {
117 type: 'array',
118 uniqueItems: true,
119 minItems: 1,
120 items: { type: 'string' },
121 },
122 message: { type: 'string' },
123 },
124 anyOf: [
125 { required: ['disallowedFor'] },
126 { required: ['disallowedForPatterns'] },
127 ],
128 additionalProperties: false,
129 },
130 ],
131 },
132 },
133 },
134 }],
135 },
136
137 create(context) {
138 const configuration = context.options[0] || {};
139 const forbid = new Map((configuration.forbid || DEFAULTS).map((value) => {
140 const propName = typeof value === 'string' ? value : value.propName;
141 const propPattern = value.propNamePattern;
142 const prop = propName || propPattern;
143 const options = {
144 allowList: [].concat(value.allowedFor || []),
145 allowPatternList: [].concat(value.allowedForPatterns || []),
146 disallowList: [].concat(value.disallowedFor || []),
147 disallowPatternList: [].concat(value.disallowedForPatterns || []),
148 message: typeof value === 'string' ? null : value.message,
149 isPattern: !!value.propNamePattern,
150 };
151 return [prop, options];
152 }));
153
154 function getPropOptions(prop) {
155 // Get config options having pattern
156 const propNamePatternArray = Array.from(forbid.entries()).filter((propEntry) => propEntry[1].isPattern);
157 // Match current prop with pattern options, return if matched
158 const propNamePattern = propNamePatternArray.find((propPatternVal) => minimatch(prop, propPatternVal[0]));
159 // Get options for matched propNamePattern
160 const propNamePatternOptions = propNamePattern && propNamePattern[1];
161
162 const options = forbid.get(prop) || propNamePatternOptions;
163 return options;
164 }
165
166 function isForbidden(prop, tagName) {
167 const options = getPropOptions(prop);
168 if (!options) {
169 return false;
170 }
171
172 function checkIsTagForbiddenByAllowOptions() {
173 if (options.allowList.indexOf(tagName) !== -1) {
174 return false;
175 }
176
177 if (options.allowPatternList.length === 0) {
178 return true;
179 }
180
181 return options.allowPatternList.every(
182 (pattern) => !minimatch(tagName, pattern)
183 );
184 }
185
186 function checkIsTagForbiddenByDisallowOptions() {
187 if (options.disallowList.indexOf(tagName) !== -1) {
188 return true;
189 }
190
191 if (options.disallowPatternList.length === 0) {
192 return false;
193 }
194
195 return options.disallowPatternList.some(
196 (pattern) => minimatch(tagName, pattern)
197 );
198 }
199
200 const hasDisallowOptions = options.disallowList.length > 0 || options.disallowPatternList.length > 0;
201
202 // disallowList should have a least one item (schema configuration)
203 const isTagForbidden = hasDisallowOptions
204 ? checkIsTagForbiddenByDisallowOptions()
205 : checkIsTagForbiddenByAllowOptions();
206
207 // if the tagName is undefined (`<this.something>`), we assume it's a forbidden element
208 return typeof tagName === 'undefined' || isTagForbidden;
209 }
210
211 return {
212 JSXAttribute(node) {
213 const parentName = node.parent.name;
214 // Extract a component name when using a "namespace", e.g. `<AntdLayout.Content />`.
215 const tag = parentName.name || `${parentName.object.name}.${parentName.property.name}`;
216 const componentName = parentName.name || parentName.property.name;
217 if (componentName && typeof componentName[0] === 'string' && componentName[0] !== componentName[0].toUpperCase()) {
218 // This is a DOM node, not a Component, so exit.
219 return;
220 }
221
222 const prop = node.name.name;
223
224 if (!isForbidden(prop, tag)) {
225 return;
226 }
227
228 const customMessage = getPropOptions(prop).message;
229
230 report(context, customMessage || messages.propIsForbidden, !customMessage && 'propIsForbidden', {
231 node,
232 data: {
233 prop,
234 },
235 });
236 },
237 };
238 },
239};
Note: See TracBrowser for help on using the repository browser.