Skip to content

Commit

Permalink
comments respect props w/ sort & added test cases
Browse files Browse the repository at this point in the history
  • Loading branch information
ROSSROSALES committed Oct 18, 2022
1 parent 847da6a commit 66365c0
Show file tree
Hide file tree
Showing 2 changed files with 282 additions and 42 deletions.
35 changes: 31 additions & 4 deletions lib/util/propTypesSort.js
Expand Up @@ -116,9 +116,35 @@ function sorter(a, b, context, ignoreCase, requiredFirst, callbacksLast) {
* @param {Boolean=} sortShapeProp whether or not to sort propTypes defined in PropTypes.shape.
* @returns {Object|*|{range, text}} the sort order of the two elements.
*/
let commentnodeMap = new WeakMap(); // all nodes reference WeakMap for start and end range
function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirst, callbacksLast, sortShapeProp) {
function sortInSource(allNodes, source) {
const originalSource = source;
const sourceCode = context.getSourceCode();
for (let i = 0; i < allNodes.length; i++) {
const node = allNodes[i];
let commentAfter = [];
let commentBefore = [];
try {
commentBefore = sourceCode.getCommentsBefore(node);
commentAfter = sourceCode.getCommentsAfter(node);
} catch (e) { /**/ };
if (commentAfter.length === 0 && commentBefore.length === 0) {
commentnodeMap.set(node, { start: node.range[0], end: node.range[1], hasComment: false });
} else {
const firstCommentBefore = commentBefore[0];
if (commentBefore.length === 1) {
commentnodeMap.set(node, { start: firstCommentBefore.range[0], end: node.range[1], hasComment: true });
}
const firstCommentAfter = commentAfter[0];
if (commentAfter.length === 1) {
commentnodeMap.set(node, { start: node.range[0], end: firstCommentAfter.range[1], hasComment: true });
}
if (commentBefore.length === 1 && commentAfter.length === 1) {
commentnodeMap.set(node, { start: firstCommentBefore.range[0], end: firstCommentAfter.range[1], hasComment: true });
}
}
};
const nodeGroups = allNodes.reduce((acc, curr) => {
if (curr.type === 'ExperimentalSpreadProperty' || curr.type === 'SpreadElement') {
acc.push([]);
Expand All @@ -135,7 +161,8 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs

source = nodes.reduceRight((acc, attr, index) => {
const sortedAttr = sortedAttributes[index];
let sortedAttrText = context.getSourceCode().getText(sortedAttr);
let sourceCodeText = sourceCode.getText();
let sortedAttrText = sourceCodeText.substring(commentnodeMap.get(sortedAttr).start, commentnodeMap.get(sortedAttr).end);
if (sortShapeProp && isShapeProp(sortedAttr.value)) {
const shape = getShapeProperties(sortedAttr.value);
if (shape) {
Expand All @@ -146,16 +173,16 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs
sortedAttrText = attrSource.slice(sortedAttr.range[0], sortedAttr.range[1]);
}
}
return `${acc.slice(0, attr.range[0])}${sortedAttrText}${acc.slice(attr.range[1])}`;
return `${acc.slice(0, commentnodeMap.get(attr).start)}${sortedAttrText}${acc.slice(commentnodeMap.get(attr).end)}`;
}, source);
});
return source;
}

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

const rangeStart = declarations[0].range[0];
const rangeEnd = declarations[declarations.length - 1].range[1];
const rangeStart = commentnodeMap.get(declarations[0]).start;
const rangeEnd = commentnodeMap.get(declarations[declarations.length - 1]).end;
return fixer.replaceTextRange([rangeStart, rangeEnd], source.slice(rangeStart, rangeEnd));
}

Expand Down
289 changes: 251 additions & 38 deletions tests/lib/rules/sort-prop-types.js
Expand Up @@ -10,6 +10,7 @@

const babelEslintVersion = require('babel-eslint/package.json').version;
const semver = require('semver');
const eslintPkg = require('eslint/package.json');
const RuleTester = require('eslint').RuleTester;

const rule = require('../../../lib/rules/sort-prop-types');
Expand Down Expand Up @@ -501,43 +502,42 @@ ruleTester.run('sort-prop-types', rule, {
},
],
},
//{
// code: `
// var First = createReactClass({
// propTypes: {
// /* z */
// z: PropTypes.string,
// /* a */
// a: PropTypes.any
// },
// render: function() {
// return <div />;
// }
// });
// `,
// // Disabled test for comments -- fails
// // output: `
// // var First = createReactClass({
// // propTypes: {
// // /* a */
// // a: PropTypes.any,
// // /* z */
// // z: PropTypes.string
// // },
// // render: function() {
// // return <div />;
// // }
// // });
// // `,
// errors: [
// {
// messageId: 'propsNotSorted',
// line: 7,
// column: 13,
// type: 'Property',
// },
// ],
//},
semver.satisfies(eslintPkg.version, '>= 3') ? {
code: `
var First = createReactClass({
propTypes: {
/* z */
z: PropTypes.string,
/* a */
a: PropTypes.any
},
render: function() {
return <div />;
}
});
`,
output: `
var First = createReactClass({
propTypes: {
/* a */
a: PropTypes.any,
/* z */
z: PropTypes.string
},
render: function() {
return <div />;
}
});
`,
errors: [
{
messageId: 'propsNotSorted',
line: 7,
column: 13,
type: 'Property',
},
],
} : [],
{
code: `
var First = createReactClass({
Expand Down Expand Up @@ -1885,6 +1885,219 @@ ruleTester.run('sort-prop-types', rule, {
line: 4,
},
],
}
},
semver.satisfies(eslintPkg.version, '>= 3') ? {
code: `
var First = createReactClass({
propTypes: {
z: PropTypes.string /* z */,
a: PropTypes.any /* a */,
b: PropTypes.any /* b */
},
render: function() {
return <div />;
}
});
`,
output: `
var First = createReactClass({
propTypes: {
a: PropTypes.any /* a */,
b: PropTypes.any /* b */,
z: PropTypes.string /* z */
},
render: function() {
return <div />;
}
});
`,
errors: [
{
messageId: 'propsNotSorted',
line: 5,
column: 13,
type: 'Property',
},
{
messageId: 'propsNotSorted',
line: 6,
column: 13,
type: 'Property',
},
],
} : [],
semver.satisfies(eslintPkg.version, '>= 3') ? {
code: `
var First = createReactClass({
propTypes: {
/* z */ z: PropTypes.string,
/* a */ a: PropTypes.any,
/* b */ b: PropTypes.any
},
render: function() {
return <div />;
}
});
`,
output: `
var First = createReactClass({
propTypes: {
/* a */ a: PropTypes.any,
/* b */ b: PropTypes.any,
/* z */ z: PropTypes.string
},
render: function() {
return <div />;
}
});
`,
errors: [
{
messageId: 'propsNotSorted',
line: 5,
column: 21,
type: 'Property',
},
{
messageId: 'propsNotSorted',
line: 6,
column: 21,
type: 'Property',
},
],
} : [],
semver.satisfies(eslintPkg.version, '>= 3') ? {
code: `
var First = createReactClass({
propTypes: {
/* z */ z: PropTypes.string /* z */,
/* a */ a: PropTypes.any /* a */,
/* b */ b: PropTypes.any /* b */
},
render: function() {
return <div />;
}
});
`,
output: `
var First = createReactClass({
propTypes: {
/* a */ a: PropTypes.any /* a */,
/* b */ b: PropTypes.any /* b */,
/* z */ z: PropTypes.string /* z */
},
render: function() {
return <div />;
}
});
`,
errors: [
{
messageId: 'propsNotSorted',
line: 5,
column: 21,
type: 'Property',
},
{
messageId: 'propsNotSorted',
line: 6,
column: 21,
type: 'Property',
},
],
} : [],
semver.satisfies(eslintPkg.version, '>= 3') ? {
code: `
var First = createReactClass({
propTypes: {
/* z */ z: PropTypes.string, /* a */ a: PropTypes.any, /* b */ b: PropTypes.any
},
render: function() {
return <div />;
}
});
`,
output: `
var First = createReactClass({
propTypes: {
/* a */ a: PropTypes.any, /* b */ b: PropTypes.any, /* z */ z: PropTypes.string
},
render: function() {
return <div />;
}
});
`,
errors: [
{
messageId: 'propsNotSorted',
line: 4,
column: 50,
type: 'Property',
},
{
messageId: 'propsNotSorted',
line: 4,
column: 76,
type: 'Property',
},
],
} : [],
semver.satisfies(eslintPkg.version, '>= 3') ? {
code: `
class Component extends React.Component {
render() {
return <div />;
}
}
Component.propTypes = {
x: PropTypes.any,
y: PropTypes.any,
z: PropTypes.shape({
a: PropTypes.string,
c: PropTypes.number.isRequired /* c */,
b: PropTypes.any,
...otherPropTypes,
f: PropTypes.bool,
/* d */
d: PropTypes.string,
}),
};
`,
output: `
class Component extends React.Component {
render() {
return <div />;
}
}
Component.propTypes = {
x: PropTypes.any,
y: PropTypes.any,
z: PropTypes.shape({
a: PropTypes.string,
b: PropTypes.any,
c: PropTypes.number.isRequired /* c */,
...otherPropTypes,
/* d */
d: PropTypes.string,
f: PropTypes.bool,
}),
};
`,
options: [{ sortShapeProp: true }],
errors: [
{
messageId: 'propsNotSorted',
line: 13,
column: 13,
type: 'Property',
},
{
messageId: 'propsNotSorted',
line: 17,
column: 13,
type: 'Property',
},
],
} : []
)),
});

0 comments on commit 66365c0

Please sign in to comment.