Skip to content

Commit baa939c

Browse files
tagoro9ljharb
authored andcommitted
[fix] jsx-sort-props: enforce prop sort when reservedFirst is enabled
If reservedFirst is enabled and noSortAlphabetically is off, then alphabetical order is only enforced in the reserved props but not in the other props. * Update generateFixerFunction to accept the reservedList. * Rename alphabeticalCompare to be propNameCompare. Accept a reservedFirst and reservedList parameters in order to be able to compare prop names according to the configuration.
1 parent 409515f commit baa939c

File tree

2 files changed

+33
-10
lines changed

2 files changed

+33
-10
lines changed

lib/rules/jsx-sort-props.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,21 @@ function isReservedPropName(name, list) {
4040
return list.indexOf(name) >= 0;
4141
}
4242

43-
function alphabeticalCompare(a, b, ignoreCase) {
44-
if (ignoreCase) {
43+
function propNameCompare(a, b, options) {
44+
if (options.ignoreCase) {
4545
a = a.toLowerCase();
4646
b = b.toLowerCase();
4747
}
48+
if (options.reservedFirst) {
49+
const aIsReserved = isReservedPropName(a, options.reservedList);
50+
const bIsReserved = isReservedPropName(b, options.reservedList);
51+
if ((aIsReserved && bIsReserved) || (!aIsReserved && !bIsReserved)) {
52+
return a.localeCompare(b);
53+
} else if (aIsReserved && !bIsReserved) {
54+
return -1;
55+
}
56+
return 1;
57+
}
4858
return a.localeCompare(b);
4959
}
5060

@@ -77,19 +87,20 @@ function getGroupsOfSortableAttributes(attributes) {
7787
return sortableAttributeGroups;
7888
}
7989

80-
const generateFixerFunction = (node, context) => {
90+
const generateFixerFunction = (node, context, reservedList) => {
8191
const sourceCode = context.getSourceCode();
8292
const attributes = node.attributes.slice(0);
8393
const configuration = context.options[0] || {};
8494
const ignoreCase = configuration.ignoreCase || false;
95+
const reservedFirst = configuration.reservedFirst || false;
8596

8697
// Sort props according to the context. Only supports ignoreCase.
8798
// Since we cannot safely move JSXSpreadAttribute (due to potential variable overrides),
8899
// we only consider groups of sortable attributes.
89100
const sortableAttributeGroups = getGroupsOfSortableAttributes(attributes);
90101
const sortedAttributeGroups = sortableAttributeGroups.slice(0).map(group =>
91102
group.slice(0).sort((a, b) =>
92-
alphabeticalCompare(propName(a), propName(b), ignoreCase)
103+
propNameCompare(propName(a), propName(b), {ignoreCase, reservedFirst, reservedList})
93104
)
94105
);
95106

@@ -235,23 +246,22 @@ module.exports = {
235246
const previousIsReserved = isReservedPropName(previousPropName, reservedList);
236247
const currentIsReserved = isReservedPropName(currentPropName, reservedList);
237248

238-
if (previousIsReserved && currentIsReserved) {
249+
if ((previousIsReserved && currentIsReserved) || (!previousIsReserved && !currentIsReserved)) {
239250
if (!noSortAlphabetically && currentPropName < previousPropName) {
240251
context.report({
241252
node: decl,
242253
message: 'Props should be sorted alphabetically',
243-
fix: generateFixerFunction(node, context)
254+
fix: generateFixerFunction(node, context, reservedList)
244255
});
245256
return memo;
246257
}
247-
return decl;
248258
}
249259
if (!previousIsReserved && currentIsReserved) {
250260
context.report({
251261
node: decl,
252-
message: 'Reserved props must be listed before all other props'
262+
message: 'Reserved props must be listed before all other props',
263+
fix: generateFixerFunction(node, context, reservedList)
253264
});
254-
return memo;
255265
}
256266
return decl;
257267
}

tests/lib/rules/jsx-sort-props.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,8 +271,21 @@ ruleTester.run('jsx-sort-props', rule, {
271271
errors: [expectedError]
272272
},
273273
{
274-
code: '<App dangerouslySetInnerHTML={{__html: "EPR"}} key={2} b />',
274+
code: '<App key={2} b a />',
275275
options: reservedFirstAsBooleanArgs,
276+
output: '<App key={2} a b />',
277+
errors: [expectedError]
278+
},
279+
{
280+
code: '<App b a />',
281+
options: reservedFirstAsBooleanArgs,
282+
output: '<App a b />',
283+
errors: [expectedError]
284+
},
285+
{
286+
code: '<App dangerouslySetInnerHTML={{__html: "EPR"}} e key={2} b />',
287+
options: reservedFirstAsBooleanArgs,
288+
output: '<App key={2} b dangerouslySetInnerHTML={{__html: "EPR"}} e />',
276289
errors: [expectedReservedFirstError]
277290
},
278291
{

0 commit comments

Comments
 (0)