Skip to content

Commit 704faf2

Browse files
ROSSROSALESljharb
authored andcommitted
[Fix] sort-prop-types: restore autofixing
1 parent 5efd774 commit 704faf2

File tree

5 files changed

+759
-501
lines changed

5 files changed

+759
-501
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
1414
### Fixed
1515
* configs: avoid legacy config system error ([#3461][] @ljharb)
1616
* [`jsx-no-target-blank`]: allow ternaries with literals ([#3464][] @akulsr0)
17+
* [`sort-prop-types`]: restore autofixing ([#2574][] @ROSSROSALES)
1718

1819
### Changed
1920
* [Perf] component detection: improve performance by avoiding traversing parents unnecessarily ([#3459][] @golopot)
2021

2122
[#3464]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3464
2223
[#3461]: https://github.com/jsx-eslint/eslint-plugin-react/issues/3461
2324
[#3459]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3459
25+
[#3452]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3452
2426
[#3449]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3449
2527
[#3424]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3429
2628
[#2848]: https://github.com/jsx-eslint/eslint-plugin-react/pull/2848

docs/rules/sort-prop-types.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
💼 This rule is enabled in the following [configs](https://github.com/jsx-eslint/eslint-plugin-react#shareable-configurations): `all`.
44

5+
🔧 This rule is automatically fixable using the `--fix` [flag](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) on the command line.
6+
57
Some developers prefer to sort prop type declarations alphabetically to be able to find necessary declaration easier at the later time. Others feel that it adds complexity and becomes burden to maintain.
68

79
## Rule Details

lib/rules/sort-prop-types.js

+16-16
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const variableUtil = require('../util/variable');
88
const propsUtil = require('../util/props');
99
const docsUrl = require('../util/docsUrl');
1010
const propWrapperUtil = require('../util/propWrapper');
11-
// const propTypesSortUtil = require('../util/propTypesSort');
11+
const propTypesSortUtil = require('../util/propTypesSort');
1212
const report = require('../util/report');
1313

1414
// ------------------------------------------------------------------------------
@@ -29,7 +29,7 @@ module.exports = {
2929
recommended: false,
3030
url: docsUrl('sort-prop-types'),
3131
},
32-
// fixable: 'code',
32+
fixable: 'code',
3333

3434
messages,
3535

@@ -106,17 +106,17 @@ module.exports = {
106106
return;
107107
}
108108

109-
// function fix(fixer) {
110-
// return propTypesSortUtil.fixPropTypesSort(
111-
// fixer,
112-
// context,
113-
// declarations,
114-
// ignoreCase,
115-
// requiredFirst,
116-
// callbacksLast,
117-
// sortShapeProp
118-
// );
119-
// }
109+
function fix(fixer) {
110+
return propTypesSortUtil.fixPropTypesSort(
111+
fixer,
112+
context,
113+
declarations,
114+
ignoreCase,
115+
requiredFirst,
116+
callbacksLast,
117+
sortShapeProp
118+
);
119+
}
120120

121121
const callbackPropsLastSeen = new WeakSet();
122122
const requiredPropsFirstSeen = new WeakSet();
@@ -150,7 +150,7 @@ module.exports = {
150150
requiredPropsFirstSeen.add(curr);
151151
report(context, messages.requiredPropsFirst, 'requiredPropsFirst', {
152152
node: curr,
153-
// fix
153+
fix,
154154
});
155155
}
156156
return curr;
@@ -168,7 +168,7 @@ module.exports = {
168168
callbackPropsLastSeen.add(prev);
169169
report(context, messages.callbackPropsLast, 'callbackPropsLast', {
170170
node: prev,
171-
// fix
171+
fix,
172172
});
173173
}
174174
return prev;
@@ -180,7 +180,7 @@ module.exports = {
180180
propsNotSortedSeen.add(curr);
181181
report(context, messages.propsNotSorted, 'propsNotSorted', {
182182
node: curr,
183-
// fix
183+
fix,
184184
});
185185
}
186186
return prev;

lib/util/propTypesSort.js

+38-4
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,39 @@ function sorter(a, b, context, ignoreCase, requiredFirst, callbacksLast) {
116116
* @param {Boolean=} sortShapeProp whether or not to sort propTypes defined in PropTypes.shape.
117117
* @returns {Object|*|{range, text}} the sort order of the two elements.
118118
*/
119+
const commentnodeMap = new WeakMap(); // all nodes reference WeakMap for start and end range
119120
function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirst, callbacksLast, sortShapeProp) {
120121
function sortInSource(allNodes, source) {
121122
const originalSource = source;
123+
const sourceCode = context.getSourceCode();
124+
for (let i = 0; i < allNodes.length; i++) {
125+
const node = allNodes[i];
126+
let commentAfter = [];
127+
let commentBefore = [];
128+
try {
129+
commentBefore = sourceCode.getCommentsBefore(node);
130+
commentAfter = sourceCode.getCommentsAfter(node);
131+
} catch (e) { /**/ }
132+
if (commentAfter.length === 0 && commentBefore.length === 0) {
133+
commentnodeMap.set(node, { start: node.range[0], end: node.range[1], hasComment: false });
134+
} else {
135+
const firstCommentBefore = commentBefore[0];
136+
if (commentBefore.length === 1) {
137+
commentnodeMap.set(node, { start: firstCommentBefore.range[0], end: node.range[1], hasComment: true });
138+
}
139+
const firstCommentAfter = commentAfter[0];
140+
if (commentAfter.length === 1) {
141+
commentnodeMap.set(node, { start: node.range[0], end: firstCommentAfter.range[1], hasComment: true });
142+
}
143+
if (commentBefore.length === 1 && commentAfter.length === 1) {
144+
commentnodeMap.set(node, {
145+
start: firstCommentBefore.range[0],
146+
end: firstCommentAfter.range[1],
147+
hasComment: true,
148+
});
149+
}
150+
}
151+
}
122152
const nodeGroups = allNodes.reduce((acc, curr) => {
123153
if (curr.type === 'ExperimentalSpreadProperty' || curr.type === 'SpreadElement') {
124154
acc.push([]);
@@ -135,7 +165,11 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs
135165

136166
source = nodes.reduceRight((acc, attr, index) => {
137167
const sortedAttr = sortedAttributes[index];
138-
let sortedAttrText = context.getSourceCode().getText(sortedAttr);
168+
const sourceCodeText = sourceCode.getText();
169+
let sortedAttrText = sourceCodeText.substring(
170+
commentnodeMap.get(sortedAttr).start,
171+
commentnodeMap.get(sortedAttr).end
172+
);
139173
if (sortShapeProp && isShapeProp(sortedAttr.value)) {
140174
const shape = getShapeProperties(sortedAttr.value);
141175
if (shape) {
@@ -146,16 +180,16 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs
146180
sortedAttrText = attrSource.slice(sortedAttr.range[0], sortedAttr.range[1]);
147181
}
148182
}
149-
return `${acc.slice(0, attr.range[0])}${sortedAttrText}${acc.slice(attr.range[1])}`;
183+
return `${acc.slice(0, commentnodeMap.get(attr).start)}${sortedAttrText}${acc.slice(commentnodeMap.get(attr).end)}`;
150184
}, source);
151185
});
152186
return source;
153187
}
154188

155189
const source = sortInSource(declarations, context.getSourceCode().getText());
156190

157-
const rangeStart = declarations[0].range[0];
158-
const rangeEnd = declarations[declarations.length - 1].range[1];
191+
const rangeStart = commentnodeMap.get(declarations[0]).start;
192+
const rangeEnd = commentnodeMap.get(declarations[declarations.length - 1]).end;
159193
return fixer.replaceTextRange([rangeStart, rangeEnd], source.slice(rangeStart, rangeEnd));
160194
}
161195

0 commit comments

Comments
 (0)