source: imaps-frontend/node_modules/eslint-plugin-react/lib/rules/forbid-component-props.js@ d565449

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

Update repo after prototype presentation

  • Property mode set to 100644
File size: 5.7 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 message: { type: 'string' },
56 },
57 additionalProperties: false,
58 },
59 {
60 type: 'object',
61 properties: {
62 propName: { type: 'string' },
63 disallowedFor: {
64 type: 'array',
65 uniqueItems: true,
66 minItems: 1,
67 items: { type: 'string' },
68 },
69 message: { type: 'string' },
70 },
71 required: ['disallowedFor'],
72 additionalProperties: false,
73 },
74
75 {
76 type: 'object',
77 properties: {
78 propNamePattern: { type: 'string' },
79 allowedFor: {
80 type: 'array',
81 uniqueItems: true,
82 items: { type: 'string' },
83 },
84 message: { type: 'string' },
85 },
86 additionalProperties: false,
87 },
88 {
89 type: 'object',
90 properties: {
91 propNamePattern: { type: 'string' },
92 disallowedFor: {
93 type: 'array',
94 uniqueItems: true,
95 minItems: 1,
96 items: { type: 'string' },
97 },
98 message: { type: 'string' },
99 },
100 required: ['disallowedFor'],
101 additionalProperties: false,
102 },
103 ],
104 },
105 },
106 },
107 }],
108 },
109
110 create(context) {
111 const configuration = context.options[0] || {};
112 const forbid = new Map((configuration.forbid || DEFAULTS).map((value) => {
113 const propName = typeof value === 'string' ? value : value.propName;
114 const propPattern = value.propNamePattern;
115 const prop = propName || propPattern;
116 const options = {
117 allowList: typeof value === 'string' ? [] : (value.allowedFor || []),
118 disallowList: typeof value === 'string' ? [] : (value.disallowedFor || []),
119 message: typeof value === 'string' ? null : value.message,
120 isPattern: !!value.propNamePattern,
121 };
122 return [prop, options];
123 }));
124
125 function getPropOptions(prop) {
126 // Get config options having pattern
127 const propNamePatternArray = Array.from(forbid.entries()).filter((propEntry) => propEntry[1].isPattern);
128 // Match current prop with pattern options, return if matched
129 const propNamePattern = propNamePatternArray.find((propPatternVal) => minimatch(prop, propPatternVal[0]));
130 // Get options for matched propNamePattern
131 const propNamePatternOptions = propNamePattern && propNamePattern[1];
132
133 const options = forbid.get(prop) || propNamePatternOptions;
134 return options;
135 }
136
137 function isForbidden(prop, tagName) {
138 const options = getPropOptions(prop);
139 if (!options) {
140 return false;
141 }
142
143 // disallowList should have a least one item (schema configuration)
144 const isTagForbidden = options.disallowList.length > 0
145 ? options.disallowList.indexOf(tagName) !== -1
146 : options.allowList.indexOf(tagName) === -1;
147
148 // if the tagName is undefined (`<this.something>`), we assume it's a forbidden element
149 return typeof tagName === 'undefined' || isTagForbidden;
150 }
151
152 return {
153 JSXAttribute(node) {
154 const parentName = node.parent.name;
155 // Extract a component name when using a "namespace", e.g. `<AntdLayout.Content />`.
156 const tag = parentName.name || `${parentName.object.name}.${parentName.property.name}`;
157 const componentName = parentName.name || parentName.property.name;
158 if (componentName && typeof componentName[0] === 'string' && componentName[0] !== componentName[0].toUpperCase()) {
159 // This is a DOM node, not a Component, so exit.
160 return;
161 }
162
163 const prop = node.name.name;
164
165 if (!isForbidden(prop, tag)) {
166 return;
167 }
168
169 const customMessage = getPropOptions(prop).message;
170
171 report(context, customMessage || messages.propIsForbidden, !customMessage && 'propIsForbidden', {
172 node,
173 data: {
174 prop,
175 },
176 });
177 },
178 };
179 },
180};
Note: See TracBrowser for help on using the repository browser.