Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add jsx-sort-props ignoreTags option #2979

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 10 additions & 0 deletions docs/rules/jsx-sort-props.md
Expand Up @@ -98,6 +98,16 @@ With `reservedFirst: ["key"]`, the following will **not** warn:
<Hello key={'uuid'} name="John" ref="ref" />
```

### `ignoreTags`

An array of element (tag) names to ignore when checking the properties order.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these aren't tag names, they're custom component names, so the terminology needs tweaking

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it necessary to be a custom component name? The rule is not limited to sort props on the components only. It currently sorts the attributes of "normal" HTML elements, too. If you accept the ignore option, it should be possible to whitelist normal tags, too.


With `ignoreTags: ["Can"]`, the following will **not** warn:

```jsx
<Can i="create" a="post" />
Comment on lines +105 to +108
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think rather than ignoring, it would be better to specify a custom ordering that applies to a specific custom component name. What do you think?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, it makes sense in the case of the CASL's Can component.

I can also think about using this in FontAwesome components (I'd like to have the fixedWitdth after icon because it is better to read then: <FontAwesomeIcon icon="coffee" fixedWidth />.

However, I'm reluctant because it will be less generic (uou don't always know all possible props that can be used with an element). Moreover, this will make the configuration much more complicated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very very rare use case; I'm not aware of anything in the entire JS ecosystem besides CASL that has a props API like this. I think it's totally fine to be not generic, since I very much doubt there will ever be a second use case (where the order is sentence-like).

In the case of FontAwesome, just ignoring it wouldn't enforce your preference, it'd just remove enforcement - which is strictly less useful, even if the alternative would require more config.

```

## When not to use

This rule is a formatting preference and not following it won't negatively affect the quality of your code. If alphabetizing props isn't a part of your coding standards, then you can leave this rule off.
21 changes: 21 additions & 0 deletions lib/rules/jsx-sort-props.js
Expand Up @@ -249,6 +249,9 @@ module.exports = {
},
reservedFirst: {
type: ['array', 'boolean']
},
ignoreTags: {
type: 'array'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would need to ensure the items are unique, and are valid custom component names

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree as for the uniqueness. Not sure about validity of component names - see my comment above.

}
},
additionalProperties: false
Expand All @@ -265,9 +268,27 @@ module.exports = {
const reservedFirst = configuration.reservedFirst || false;
const reservedFirstError = validateReservedFirstConfig(context, reservedFirst);
let reservedList = Array.isArray(reservedFirst) ? reservedFirst : RESERVED_PROPS_LIST;
const ignoreTags = configuration.ignoreTags || [];
const getTagNameFromMemberExpression = (node) => `${node.property.parent.object.name}.${node.property.name}`;

return {
JSXOpeningElement(node) {
if (ignoreTags.length > 0) {
const jsxOpeningElement = node.name;
const type = jsxOpeningElement.type;
let tagName;
if (type === 'JSXIdentifier') {
tagName = jsxOpeningElement.name;
} else if (type === 'JSXMemberExpression') {
tagName = getTagNameFromMemberExpression(jsxOpeningElement);
} else {
tagName = undefined;
}
if (tagName && ignoreTags.includes(tagName)) {
return;
}
}

// `dangerouslySetInnerHTML` is only "reserved" on DOM components
if (reservedFirst && !jsxUtil.isDOMComponent(node)) {
reservedList = reservedList.filter((prop) => prop !== 'dangerouslySetInnerHTML');
Expand Down
13 changes: 13 additions & 0 deletions tests/lib/rules/jsx-sort-props.js
Expand Up @@ -99,6 +99,9 @@ const reservedFirstAsEmptyArrayArgs = [{
const reservedFirstAsInvalidArrayArgs = [{
reservedFirst: ['notReserved']
}];
const ignoreTagsApp = [{
ignoreTags: ['App']
}];

ruleTester.run('jsx-sort-props', rule, {
valid: [
Expand Down Expand Up @@ -165,6 +168,10 @@ ruleTester.run('jsx-sort-props', rule, {
{
code: '<App key="key" c="c" b />',
options: reservedFirstWithShorthandLast
},
{
code: '<App c b a />;',
options: ignoreTagsApp
}
],
invalid: [
Expand Down Expand Up @@ -484,6 +491,12 @@ ruleTester.run('jsx-sort-props', rule, {
code: '<App key={5} />',
options: reservedFirstAsInvalidArrayArgs,
errors: [expectedInvalidReservedFirstError]
},
{
code: '<NoApp c b a />;',
options: ignoreTagsApp,
errors: [expectedError],
output: '<NoApp a b c />;'
}
]
});