Skip to content

Commit abaf18b

Browse files
committed
cover disallowedForPatterns option with tests and implement
1 parent 9ff162d commit abaf18b

File tree

2 files changed

+102
-6
lines changed

2 files changed

+102
-6
lines changed

lib/rules/forbid-component-props.js

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ module.exports = {
177177
allowList: typeof value === 'string' ? [] : (value.allowedFor || []),
178178
allowPatternList: typeof value === 'string' ? [] : value.allowedForPatterns || [],
179179
disallowList: typeof value === 'string' ? [] : (value.disallowedFor || []),
180+
disallowPatternList: typeof value === 'string' ? [] : value.disallowedForPatterns || [],
180181
message: typeof value === 'string' ? null : value.message,
181182
isPattern: !!value.propNamePattern,
182183
};
@@ -201,6 +202,10 @@ module.exports = {
201202
return false;
202203
}
203204

205+
function checkIsTagForbiddenByAllowList() {
206+
return options.allowList.indexOf(tagName) === -1;
207+
}
208+
204209
function checkIsTagForbiddenByAllowPatternList() {
205210
if (options.allowPatternList.length === 0) {
206211
return true;
@@ -211,17 +216,33 @@ module.exports = {
211216
);
212217
}
213218

214-
function checkIsTagForbiddenByAllowList() {
215-
return options.allowList.indexOf(tagName) === -1;
219+
function checkIsTagForbiddenByAllowOptions() {
220+
return checkIsTagForbiddenByAllowList() && checkIsTagForbiddenByAllowPatternList();
216221
}
217222

218-
function checkIsTagForbiddenByAllowOptions() {
219-
return checkIsTagForbiddenByAllowPatternList() && checkIsTagForbiddenByAllowList();
223+
function checkIsTagForbiddenByDisallowList() {
224+
return options.disallowList.indexOf(tagName) !== -1;
220225
}
221226

227+
function checkIsTagForbiddenByDisallowPatternList() {
228+
if (options.disallowPatternList.length === 0) {
229+
return false;
230+
}
231+
232+
return options.disallowPatternList.some(
233+
(pattern) => minimatch(tagName, pattern)
234+
);
235+
}
236+
237+
function checkIsTagForbiddenByDisallowOptions() {
238+
return checkIsTagForbiddenByDisallowList() || checkIsTagForbiddenByDisallowPatternList();
239+
}
240+
241+
const hasDisallowOptions = options.disallowList.length > 0 || options.disallowPatternList.length > 0;
242+
222243
// disallowList should have a least one item (schema configuration)
223-
const isTagForbidden = options.disallowList.length > 0
224-
? options.disallowList.indexOf(tagName) !== -1
244+
const isTagForbidden = hasDisallowOptions
245+
? checkIsTagForbiddenByDisallowOptions()
225246
: checkIsTagForbiddenByAllowOptions();
226247

227248
// if the tagName is undefined (`<this.something>`), we assume it's a forbidden element

tests/lib/rules/forbid-component-props.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,30 @@ ruleTester.run('forbid-component-props', rule, {
298298
},
299299
],
300300
},
301+
{
302+
code: `
303+
const rootElement = (
304+
<Root>
305+
<SomeIcon className="size-lg" />
306+
<AnotherIcon className="size-lg" />
307+
<SomeSvg className="size-lg" />
308+
<UICard className="size-lg" />
309+
<UIButton className="size-lg" />
310+
</Root>
311+
);
312+
`,
313+
options: [
314+
{
315+
forbid: [
316+
{
317+
propName: 'className',
318+
disallowedFor: ['Modal'],
319+
disallowedForPatterns: ['*Legacy', 'Shared*'],
320+
},
321+
],
322+
},
323+
],
324+
},
301325
]),
302326

303327
invalid: parsers.all([
@@ -797,5 +821,56 @@ ruleTester.run('forbid-component-props', rule, {
797821
},
798822
],
799823
},
824+
{
825+
code: `
826+
const rootElement = (
827+
<Root>
828+
<SomeIcon className="size-lg" />
829+
<AnotherIcon className="size-lg" />
830+
<SomeSvg className="size-lg" />
831+
<UICard className="size-lg" />
832+
<ButtonLegacy className="size-lg" />
833+
</Root>
834+
);
835+
`,
836+
options: [
837+
{
838+
forbid: [
839+
{
840+
propName: 'className',
841+
disallowedFor: ['SomeSvg'],
842+
disallowedForPatterns: ['UI*', '*Icon'],
843+
message: 'Avoid using className for SomeSvg and components that match the `UI*` and `*Icon` patterns',
844+
},
845+
],
846+
},
847+
],
848+
errors: [
849+
{
850+
message: 'Avoid using className for SomeSvg and components that match the `UI*` and `*Icon` patterns',
851+
line: 4,
852+
column: 23,
853+
type: 'JSXAttribute',
854+
},
855+
{
856+
message: 'Avoid using className for SomeSvg and components that match the `UI*` and `*Icon` patterns',
857+
line: 5,
858+
column: 26,
859+
type: 'JSXAttribute',
860+
},
861+
{
862+
message: 'Avoid using className for SomeSvg and components that match the `UI*` and `*Icon` patterns',
863+
line: 6,
864+
column: 22,
865+
type: 'JSXAttribute',
866+
},
867+
{
868+
message: 'Avoid using className for SomeSvg and components that match the `UI*` and `*Icon` patterns',
869+
line: 7,
870+
column: 21,
871+
type: 'JSXAttribute',
872+
},
873+
],
874+
},
800875
]),
801876
});

0 commit comments

Comments
 (0)