Skip to content

Commit

Permalink
feat: Allow polymorphic linting to be restricted
Browse files Browse the repository at this point in the history
This changes allows the consumer to restrict polymorphic linting to specified components.
Linting components may raise false positives when a component handles behavior that the linter has no way to know.

This means that linting components is preferred on very basic utility components.
  • Loading branch information
khiga8 committed May 6, 2024
1 parent 0d5321a commit 3889dd1
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 1 deletion.
34 changes: 34 additions & 0 deletions __tests__/src/util/getElementType-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,4 +76,38 @@ describe('getElementType', () => {
expect(elementType(JSXElementMock('CustomButton', [JSXAttributeMock('as', 'a')]).openingElement)).toBe('button');
});
});

describe('polymorphicPropName settings and explicitly defined polymorphicAllowList in context', () => {
const elementType = getElementType({
settings: {
'jsx-a11y': {
polymorphicPropName: 'asChild',
polymorphicAllowList: [
'Box',
'Icon',
],
components: {
Box: 'div',
Icon: 'svg',
},
},
},
});

it('should not use the polymorphic prop if polymorphicAllowList is defined, but element is not part of polymorphicAllowList', () => {
expect(elementType(JSXElementMock('Spinner', [JSXAttributeMock('asChild', 'img')]).openingElement)).toBe('Spinner');
});

it('should use the polymorphic prop if it is in explicitly defined polymorphicAllowList', () => {
expect(elementType(JSXElementMock('Icon', [JSXAttributeMock('asChild', 'img')]).openingElement)).toBe('img');
});

it('should return the tag name provided by the polymorphic prop, "asChild", defined in the settings instead of the component mapping tag', () => {
expect(elementType(JSXElementMock('Box', [JSXAttributeMock('asChild', 'span')]).openingElement)).toBe('span');
});

it('should return the tag name provided by the component mapping if the polymorphic prop, "asChild", defined in the settings is not set', () => {
expect(elementType(JSXElementMock('Box', [JSXAttributeMock('as', 'a')]).openingElement)).toBe('div');
});
});
});
1 change: 1 addition & 0 deletions flow/eslint.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export type ESLintSettings = {
[string]: mixed,
'jsx-a11y'?: {
polymorphicPropName?: string,
polymorphicAllowList?: Array<string>,
components?: {[string]: string},
},
}
Expand Down
12 changes: 11 additions & 1 deletion src/util/getElementType.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,21 @@ import type { ESLintContext } from '../../flow/eslint';
const getElementType = (context: ESLintContext): ((node: JSXOpeningElement) => string) => {
const { settings } = context;
const polymorphicPropName = settings['jsx-a11y']?.polymorphicPropName;
const polymorphicAllowList = settings['jsx-a11y']?.polymorphicAllowList;

const componentMap = settings['jsx-a11y']?.components;

return (node: JSXOpeningElement): string => {
const polymorphicProp = polymorphicPropName ? getLiteralPropValue(getProp(node.attributes, polymorphicPropName)) : undefined;
const rawType = polymorphicProp ?? elementType(node);

let rawType = elementType(node);
if (polymorphicProp) {
if (!polymorphicAllowList) {
rawType = polymorphicProp;
} else if (polymorphicAllowList.includes(rawType)) {
rawType = polymorphicProp;
}
}

if (!componentMap) {
return rawType;
Expand Down

0 comments on commit 3889dd1

Please sign in to comment.