diff --git a/lib/rules/jsx-sort-props.js b/lib/rules/jsx-sort-props.js
index 7528c1905c..a0b83a4d06 100644
--- a/lib/rules/jsx-sort-props.js
+++ b/lib/rules/jsx-sort-props.js
@@ -27,22 +27,48 @@ function isReservedPropName(name, list) {
return list.indexOf(name) >= 0;
}
-function propNameCompare(a, b, options) {
- if (options.ignoreCase) {
- a = a.toLowerCase();
- b = b.toLowerCase();
- }
+function contextCompare(a, b, options) {
+ let aProp = propName(a);
+ let bProp = propName(b);
+
if (options.reservedFirst) {
- const aIsReserved = isReservedPropName(a, options.reservedList);
- const bIsReserved = isReservedPropName(b, options.reservedList);
- if ((aIsReserved && bIsReserved) || (!aIsReserved && !bIsReserved)) {
- return a.localeCompare(b);
- } else if (aIsReserved && !bIsReserved) {
+ const aIsReserved = isReservedPropName(aProp, options.reservedList);
+ const bIsReserved = isReservedPropName(bProp, options.reservedList);
+ if (aIsReserved && !bIsReserved) {
return -1;
+ } else if (!aIsReserved && bIsReserved) {
+ return 1;
+ }
+ }
+
+ if (options.callbacksLast) {
+ const aIsCallback = isCallbackPropName(aProp);
+ const bIsCallback = isCallbackPropName(bProp);
+ if (aIsCallback && !bIsCallback) {
+ return 1;
+ } else if (!aIsCallback && bIsCallback) {
+ return -1;
+ }
+ }
+
+ if (options.shorthandFirst || options.shorthandLast) {
+ const shorthandSign = options.shorthandFirst ? -1 : 1;
+ if (!a.value && b.value) {
+ return shorthandSign;
+ } else if (a.value && !b.value) {
+ return -shorthandSign;
}
- return 1;
}
- return a.localeCompare(b);
+
+ if (options.noSortAlphabetically) {
+ return 0;
+ }
+
+ if (options.ignoreCase) {
+ aProp = aProp.toLowerCase();
+ bProp = bProp.toLowerCase();
+ }
+ return aProp.localeCompare(bProp);
}
/**
@@ -79,15 +105,21 @@ const generateFixerFunction = (node, context, reservedList) => {
const attributes = node.attributes.slice(0);
const configuration = context.options[0] || {};
const ignoreCase = configuration.ignoreCase || false;
+ const callbacksLast = configuration.callbacksLast || false;
+ const shorthandFirst = configuration.shorthandFirst || false;
+ const shorthandLast = configuration.shorthandLast || false;
+ const noSortAlphabetically = configuration.noSortAlphabetically || false;
const reservedFirst = configuration.reservedFirst || false;
// Sort props according to the context. Only supports ignoreCase.
// Since we cannot safely move JSXSpreadAttribute (due to potential variable overrides),
// we only consider groups of sortable attributes.
+ const options = {ignoreCase, callbacksLast, shorthandFirst, shorthandLast,
+ noSortAlphabetically, reservedFirst, reservedList};
const sortableAttributeGroups = getGroupsOfSortableAttributes(attributes);
const sortedAttributeGroups = sortableAttributeGroups.slice(0).map(group =>
group.slice(0).sort((a, b) =>
- propNameCompare(propName(a), propName(b), {ignoreCase, reservedFirst, reservedList})
+ contextCompare(a, b, options)
)
);
@@ -267,7 +299,8 @@ module.exports = {
// Encountered a non-callback prop after a callback prop
context.report({
node: memo,
- message: 'Callbacks must be listed after all other props'
+ message: 'Callbacks must be listed after all other props',
+ fix: generateFixerFunction(node, context, reservedList)
});
return memo;
}
@@ -280,7 +313,8 @@ module.exports = {
if (!currentValue && previousValue) {
context.report({
node: memo,
- message: 'Shorthand props must be listed before all other props'
+ message: 'Shorthand props must be listed before all other props',
+ fix: generateFixerFunction(node, context, reservedList)
});
return memo;
}
@@ -293,7 +327,8 @@ module.exports = {
if (currentValue && !previousValue) {
context.report({
node: memo,
- message: 'Shorthand props must be listed after all other props'
+ message: 'Shorthand props must be listed after all other props',
+ fix: generateFixerFunction(node, context, reservedList)
});
return memo;
}
diff --git a/tests/lib/rules/jsx-sort-props.js b/tests/lib/rules/jsx-sort-props.js
index 082ef11f4e..a58dd57c91 100644
--- a/tests/lib/rules/jsx-sort-props.js
+++ b/tests/lib/rules/jsx-sort-props.js
@@ -336,59 +336,75 @@ ruleTester.run('jsx-sort-props', rule, {
{
code: '