Skip to content

Commit 121c89a

Browse files
akulsr0ljharb
authored andcommitted
[New] sort-prop-types: give errors on TS types
1 parent 378de4c commit 121c89a

File tree

3 files changed

+172
-3
lines changed

3 files changed

+172
-3
lines changed

CHANGELOG.md

+5
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ This change log adheres to standards from [Keep a CHANGELOG](https://keepachange
55

66
## Unreleased
77

8+
### Added
9+
* [`sort-prop-types`]: give errors on TS types ([#3615][] @akulsr0)
10+
11+
[#3615]: https://github.com/jsx-eslint/eslint-plugin-react/pull/3615
12+
813
## [7.33.2] - 2023.08.15
914

1015
### Fixed

lib/rules/sort-prop-types.js

+68-2
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ module.exports = {
5252
sortShapeProp: {
5353
type: 'boolean',
5454
},
55+
checkTypes: {
56+
type: 'boolean',
57+
},
5558
},
5659
additionalProperties: false,
5760
}],
@@ -64,8 +67,14 @@ module.exports = {
6467
const ignoreCase = configuration.ignoreCase || false;
6568
const noSortAlphabetically = configuration.noSortAlphabetically || false;
6669
const sortShapeProp = configuration.sortShapeProp || false;
70+
const checkTypes = configuration.checkTypes || false;
71+
72+
const typeAnnotations = new Map();
6773

6874
function getKey(node) {
75+
if (node.type === 'ObjectTypeProperty') {
76+
return context.getSourceCode().getFirstToken(node).value;
77+
}
6978
if (node.key && node.key.value) {
7079
return node.key.value;
7180
}
@@ -215,7 +224,32 @@ module.exports = {
215224
}
216225
}
217226

218-
return {
227+
function handleFunctionComponent(node) {
228+
const firstArg = node.params[0].typeAnnotation && node.params[0].typeAnnotation.typeAnnotation;
229+
if (firstArg && firstArg.type === 'TSTypeReference') {
230+
const propType = typeAnnotations.get(firstArg.typeName.name)
231+
&& typeAnnotations.get(firstArg.typeName.name)[0];
232+
if (propType && propType.members) {
233+
checkSorted(propType.members);
234+
}
235+
} else if (firstArg && firstArg.type === 'TSTypeLiteral') {
236+
if (firstArg.members) {
237+
checkSorted(firstArg.members);
238+
}
239+
} else if (firstArg && firstArg.type === 'GenericTypeAnnotation') {
240+
const propType = typeAnnotations.get(firstArg.id.name)
241+
&& typeAnnotations.get(firstArg.id.name)[0];
242+
if (propType && propType.properties) {
243+
checkSorted(propType.properties);
244+
}
245+
} else if (firstArg && firstArg.type === 'ObjectTypeAnnotation') {
246+
if (firstArg.properties) {
247+
checkSorted(firstArg.properties);
248+
}
249+
}
250+
}
251+
252+
return Object.assign({
219253
CallExpression(node) {
220254
if (!sortShapeProp || !isShapeProp(node) || !(node.arguments && node.arguments[0])) {
221255
return;
@@ -261,6 +295,38 @@ module.exports = {
261295
}
262296
});
263297
},
264-
};
298+
}, checkTypes ? {
299+
TSTypeLiteral(node) {
300+
if (node && node.parent.id) {
301+
const currentNode = [].concat(
302+
typeAnnotations.get(node.parent.id.name) || [],
303+
node
304+
);
305+
typeAnnotations.set(node.parent.id.name, currentNode);
306+
}
307+
},
308+
309+
TypeAlias(node) {
310+
if (node.right.type === 'ObjectTypeAnnotation') {
311+
const currentNode = [].concat(
312+
typeAnnotations.get(node.id.name) || [],
313+
node.right
314+
);
315+
typeAnnotations.set(node.id.name, currentNode);
316+
}
317+
},
318+
319+
TSTypeAliasDeclaration(node) {
320+
if (node.typeAnnotation.type === 'TSTypeLiteral' || node.typeAnnotation.type === 'ObjectTypeAnnotation') {
321+
const currentNode = [].concat(
322+
typeAnnotations.get(node.id.name) || [],
323+
node.typeAnnotation
324+
);
325+
typeAnnotations.set(node.id.name, currentNode);
326+
}
327+
},
328+
FunctionDeclaration: handleFunctionComponent,
329+
ArrowFunctionExpression: handleFunctionComponent,
330+
} : null);
265331
},
266332
};

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

+99-1
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,19 @@ ruleTester.run('sort-prop-types', rule, {
480480
});
481481
`,
482482
options: [{ callbacksLast: true, noSortAlphabetically: true }],
483+
},
484+
{
485+
code: `
486+
type Props = {
487+
zzz: string;
488+
aaa: string;
489+
}
490+
function Foo(props: Props) {
491+
return null;
492+
}
493+
`,
494+
features: ['types'],
495+
options: [{ checkTypes: false }],
483496
}
484497
)),
485498
invalid: parsers.all([].concat(
@@ -2250,6 +2263,91 @@ ruleTester.run('sort-prop-types', rule, {
22502263
line: 4,
22512264
},
22522265
],
2253-
} : []
2266+
} : [],
2267+
{
2268+
code: `
2269+
type Props = {
2270+
zzz: string;
2271+
aaa: string;
2272+
}
2273+
function Foo(props: Props) {
2274+
return null;
2275+
}
2276+
`,
2277+
output: `
2278+
type Props = {
2279+
aaa: string;
2280+
zzz: string;
2281+
}
2282+
function Foo(props: Props) {
2283+
return null;
2284+
}
2285+
`,
2286+
features: ['types'],
2287+
options: [{ checkTypes: true }],
2288+
errors: [
2289+
{
2290+
messageId: 'propsNotSorted',
2291+
line: 4,
2292+
column: 11,
2293+
},
2294+
],
2295+
},
2296+
{
2297+
code: `
2298+
type Props = {
2299+
zzz: string;
2300+
aaa: string;
2301+
}
2302+
const Foo = (props: Props) => {
2303+
return null;
2304+
}
2305+
`,
2306+
output: `
2307+
type Props = {
2308+
aaa: string;
2309+
zzz: string;
2310+
}
2311+
const Foo = (props: Props) => {
2312+
return null;
2313+
}
2314+
`,
2315+
features: ['types'],
2316+
options: [{ checkTypes: true }],
2317+
errors: [
2318+
{
2319+
messageId: 'propsNotSorted',
2320+
line: 4,
2321+
column: 11,
2322+
},
2323+
],
2324+
},
2325+
{
2326+
code: `
2327+
const Foo = (props: {
2328+
zzz: string,
2329+
aaa: string,
2330+
}) => {
2331+
return null;
2332+
}
2333+
`,
2334+
output: `
2335+
const Foo = (props: {
2336+
aaa: string,
2337+
zzz: string,
2338+
}) => {
2339+
return null;
2340+
}
2341+
`,
2342+
features: ['types'],
2343+
options: [{ checkTypes: true }],
2344+
errors: [
2345+
{
2346+
messageId: 'propsNotSorted',
2347+
line: 4,
2348+
column: 11,
2349+
},
2350+
],
2351+
}
22542352
)),
22552353
});

0 commit comments

Comments
 (0)