Skip to content

Commit 66365c0

Browse files
committed
comments respect props w/ sort & added test cases
1 parent 847da6a commit 66365c0

File tree

2 files changed

+282
-42
lines changed

2 files changed

+282
-42
lines changed

lib/util/propTypesSort.js

+31-4
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,35 @@ 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+
let 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, { start: firstCommentBefore.range[0], end: firstCommentAfter.range[1], hasComment: true });
145+
}
146+
}
147+
};
122148
const nodeGroups = allNodes.reduce((acc, curr) => {
123149
if (curr.type === 'ExperimentalSpreadProperty' || curr.type === 'SpreadElement') {
124150
acc.push([]);
@@ -135,7 +161,8 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs
135161

136162
source = nodes.reduceRight((acc, attr, index) => {
137163
const sortedAttr = sortedAttributes[index];
138-
let sortedAttrText = context.getSourceCode().getText(sortedAttr);
164+
let sourceCodeText = sourceCode.getText();
165+
let sortedAttrText = sourceCodeText.substring(commentnodeMap.get(sortedAttr).start, commentnodeMap.get(sortedAttr).end);
139166
if (sortShapeProp && isShapeProp(sortedAttr.value)) {
140167
const shape = getShapeProperties(sortedAttr.value);
141168
if (shape) {
@@ -146,16 +173,16 @@ function fixPropTypesSort(fixer, context, declarations, ignoreCase, requiredFirs
146173
sortedAttrText = attrSource.slice(sortedAttr.range[0], sortedAttr.range[1]);
147174
}
148175
}
149-
return `${acc.slice(0, attr.range[0])}${sortedAttrText}${acc.slice(attr.range[1])}`;
176+
return `${acc.slice(0, commentnodeMap.get(attr).start)}${sortedAttrText}${acc.slice(commentnodeMap.get(attr).end)}`;
150177
}, source);
151178
});
152179
return source;
153180
}
154181

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

157-
const rangeStart = declarations[0].range[0];
158-
const rangeEnd = declarations[declarations.length - 1].range[1];
184+
const rangeStart = commentnodeMap.get(declarations[0]).start;
185+
const rangeEnd = commentnodeMap.get(declarations[declarations.length - 1]).end;
159186
return fixer.replaceTextRange([rangeStart, rangeEnd], source.slice(rangeStart, rangeEnd));
160187
}
161188

tests/lib/rules/sort-prop-types.js

+251-38
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
const babelEslintVersion = require('babel-eslint/package.json').version;
1212
const semver = require('semver');
13+
const eslintPkg = require('eslint/package.json');
1314
const RuleTester = require('eslint').RuleTester;
1415

1516
const rule = require('../../../lib/rules/sort-prop-types');
@@ -501,43 +502,42 @@ ruleTester.run('sort-prop-types', rule, {
501502
},
502503
],
503504
},
504-
//{
505-
// code: `
506-
// var First = createReactClass({
507-
// propTypes: {
508-
// /* z */
509-
// z: PropTypes.string,
510-
// /* a */
511-
// a: PropTypes.any
512-
// },
513-
// render: function() {
514-
// return <div />;
515-
// }
516-
// });
517-
// `,
518-
// // Disabled test for comments -- fails
519-
// // output: `
520-
// // var First = createReactClass({
521-
// // propTypes: {
522-
// // /* a */
523-
// // a: PropTypes.any,
524-
// // /* z */
525-
// // z: PropTypes.string
526-
// // },
527-
// // render: function() {
528-
// // return <div />;
529-
// // }
530-
// // });
531-
// // `,
532-
// errors: [
533-
// {
534-
// messageId: 'propsNotSorted',
535-
// line: 7,
536-
// column: 13,
537-
// type: 'Property',
538-
// },
539-
// ],
540-
//},
505+
semver.satisfies(eslintPkg.version, '>= 3') ? {
506+
code: `
507+
var First = createReactClass({
508+
propTypes: {
509+
/* z */
510+
z: PropTypes.string,
511+
/* a */
512+
a: PropTypes.any
513+
},
514+
render: function() {
515+
return <div />;
516+
}
517+
});
518+
`,
519+
output: `
520+
var First = createReactClass({
521+
propTypes: {
522+
/* a */
523+
a: PropTypes.any,
524+
/* z */
525+
z: PropTypes.string
526+
},
527+
render: function() {
528+
return <div />;
529+
}
530+
});
531+
`,
532+
errors: [
533+
{
534+
messageId: 'propsNotSorted',
535+
line: 7,
536+
column: 13,
537+
type: 'Property',
538+
},
539+
],
540+
} : [],
541541
{
542542
code: `
543543
var First = createReactClass({
@@ -1885,6 +1885,219 @@ ruleTester.run('sort-prop-types', rule, {
18851885
line: 4,
18861886
},
18871887
],
1888-
}
1888+
},
1889+
semver.satisfies(eslintPkg.version, '>= 3') ? {
1890+
code: `
1891+
var First = createReactClass({
1892+
propTypes: {
1893+
z: PropTypes.string /* z */,
1894+
a: PropTypes.any /* a */,
1895+
b: PropTypes.any /* b */
1896+
},
1897+
render: function() {
1898+
return <div />;
1899+
}
1900+
});
1901+
`,
1902+
output: `
1903+
var First = createReactClass({
1904+
propTypes: {
1905+
a: PropTypes.any /* a */,
1906+
b: PropTypes.any /* b */,
1907+
z: PropTypes.string /* z */
1908+
},
1909+
render: function() {
1910+
return <div />;
1911+
}
1912+
});
1913+
`,
1914+
errors: [
1915+
{
1916+
messageId: 'propsNotSorted',
1917+
line: 5,
1918+
column: 13,
1919+
type: 'Property',
1920+
},
1921+
{
1922+
messageId: 'propsNotSorted',
1923+
line: 6,
1924+
column: 13,
1925+
type: 'Property',
1926+
},
1927+
],
1928+
} : [],
1929+
semver.satisfies(eslintPkg.version, '>= 3') ? {
1930+
code: `
1931+
var First = createReactClass({
1932+
propTypes: {
1933+
/* z */ z: PropTypes.string,
1934+
/* a */ a: PropTypes.any,
1935+
/* b */ b: PropTypes.any
1936+
},
1937+
render: function() {
1938+
return <div />;
1939+
}
1940+
});
1941+
`,
1942+
output: `
1943+
var First = createReactClass({
1944+
propTypes: {
1945+
/* a */ a: PropTypes.any,
1946+
/* b */ b: PropTypes.any,
1947+
/* z */ z: PropTypes.string
1948+
},
1949+
render: function() {
1950+
return <div />;
1951+
}
1952+
});
1953+
`,
1954+
errors: [
1955+
{
1956+
messageId: 'propsNotSorted',
1957+
line: 5,
1958+
column: 21,
1959+
type: 'Property',
1960+
},
1961+
{
1962+
messageId: 'propsNotSorted',
1963+
line: 6,
1964+
column: 21,
1965+
type: 'Property',
1966+
},
1967+
],
1968+
} : [],
1969+
semver.satisfies(eslintPkg.version, '>= 3') ? {
1970+
code: `
1971+
var First = createReactClass({
1972+
propTypes: {
1973+
/* z */ z: PropTypes.string /* z */,
1974+
/* a */ a: PropTypes.any /* a */,
1975+
/* b */ b: PropTypes.any /* b */
1976+
},
1977+
render: function() {
1978+
return <div />;
1979+
}
1980+
});
1981+
`,
1982+
output: `
1983+
var First = createReactClass({
1984+
propTypes: {
1985+
/* a */ a: PropTypes.any /* a */,
1986+
/* b */ b: PropTypes.any /* b */,
1987+
/* z */ z: PropTypes.string /* z */
1988+
},
1989+
render: function() {
1990+
return <div />;
1991+
}
1992+
});
1993+
`,
1994+
errors: [
1995+
{
1996+
messageId: 'propsNotSorted',
1997+
line: 5,
1998+
column: 21,
1999+
type: 'Property',
2000+
},
2001+
{
2002+
messageId: 'propsNotSorted',
2003+
line: 6,
2004+
column: 21,
2005+
type: 'Property',
2006+
},
2007+
],
2008+
} : [],
2009+
semver.satisfies(eslintPkg.version, '>= 3') ? {
2010+
code: `
2011+
var First = createReactClass({
2012+
propTypes: {
2013+
/* z */ z: PropTypes.string, /* a */ a: PropTypes.any, /* b */ b: PropTypes.any
2014+
},
2015+
render: function() {
2016+
return <div />;
2017+
}
2018+
});
2019+
`,
2020+
output: `
2021+
var First = createReactClass({
2022+
propTypes: {
2023+
/* a */ a: PropTypes.any, /* b */ b: PropTypes.any, /* z */ z: PropTypes.string
2024+
},
2025+
render: function() {
2026+
return <div />;
2027+
}
2028+
});
2029+
`,
2030+
errors: [
2031+
{
2032+
messageId: 'propsNotSorted',
2033+
line: 4,
2034+
column: 50,
2035+
type: 'Property',
2036+
},
2037+
{
2038+
messageId: 'propsNotSorted',
2039+
line: 4,
2040+
column: 76,
2041+
type: 'Property',
2042+
},
2043+
],
2044+
} : [],
2045+
semver.satisfies(eslintPkg.version, '>= 3') ? {
2046+
code: `
2047+
class Component extends React.Component {
2048+
render() {
2049+
return <div />;
2050+
}
2051+
}
2052+
Component.propTypes = {
2053+
x: PropTypes.any,
2054+
y: PropTypes.any,
2055+
z: PropTypes.shape({
2056+
a: PropTypes.string,
2057+
c: PropTypes.number.isRequired /* c */,
2058+
b: PropTypes.any,
2059+
...otherPropTypes,
2060+
f: PropTypes.bool,
2061+
/* d */
2062+
d: PropTypes.string,
2063+
}),
2064+
};
2065+
`,
2066+
output: `
2067+
class Component extends React.Component {
2068+
render() {
2069+
return <div />;
2070+
}
2071+
}
2072+
Component.propTypes = {
2073+
x: PropTypes.any,
2074+
y: PropTypes.any,
2075+
z: PropTypes.shape({
2076+
a: PropTypes.string,
2077+
b: PropTypes.any,
2078+
c: PropTypes.number.isRequired /* c */,
2079+
...otherPropTypes,
2080+
/* d */
2081+
d: PropTypes.string,
2082+
f: PropTypes.bool,
2083+
}),
2084+
};
2085+
`,
2086+
options: [{ sortShapeProp: true }],
2087+
errors: [
2088+
{
2089+
messageId: 'propsNotSorted',
2090+
line: 13,
2091+
column: 13,
2092+
type: 'Property',
2093+
},
2094+
{
2095+
messageId: 'propsNotSorted',
2096+
line: 17,
2097+
column: 13,
2098+
type: 'Property',
2099+
},
2100+
],
2101+
} : []
18892102
)),
18902103
});

0 commit comments

Comments
 (0)