Skip to content

Commit 540e462

Browse files
fix: keep standalone comments with TypeScript props
1 parent 8ace124 commit 540e462

2 files changed

Lines changed: 120 additions & 2 deletions

File tree

lib/util/propTypesSort.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,25 @@ function sorter(a, b, context, ignoreCase, requiredFirst, callbacksLast, noSortA
122122

123123
const commentnodeMap = new WeakMap(); // all nodes reference WeakMap for start and end range
124124

125+
/**
126+
* Returns comments that belong to the preceding declaration rather than the
127+
* next declaration.
128+
*
129+
* @param {SourceCode} sourceCode The source code object.
130+
* @param {ASTNode} node The declaration node.
131+
* @returns {Array} The trailing comments for the declaration.
132+
*/
133+
function getTrailingComments(sourceCode, node) {
134+
const comments = sourceCode.getCommentsAfter(node);
135+
const nextToken = sourceCode.getTokenAfter(node);
136+
137+
if (nextToken && [',', ';', '}'].includes(nextToken.value)) {
138+
return comments.filter((comment) => comment.range[1] <= nextToken.range[0]);
139+
}
140+
141+
return comments.filter((comment) => comment.loc.start.line === node.loc.end.line);
142+
}
143+
125144
/**
126145
* Fixes sort order of prop types.
127146
*
@@ -161,7 +180,7 @@ function fixPropTypesSort(
161180
try {
162181
commentBefore = sourceCode.getCommentsBefore(node)
163182
.filter((comment) => !trailingCommentRanges.has(comment.range.join(':')));
164-
commentAfter = sourceCode.getCommentsAfter(node);
183+
commentAfter = getTrailingComments(sourceCode, node);
165184
commentAfter.forEach((comment) => trailingCommentRanges.add(comment.range.join(':')));
166185
} catch (e) { /**/ }
167186

@@ -213,7 +232,7 @@ function fixPropTypesSort(
213232
sortedAttrTextStart = sortedAttr.range[0];
214233
}
215234
}
216-
const trailingComment = sourceCode.getCommentsAfter(sortedAttr)[0];
235+
const trailingComment = getTrailingComments(sourceCode, sortedAttr)[0];
217236
const separatorIndex = trailingComment ? trailingComment.range[0] - sortedAttrTextStart : sortedAttrText.length;
218237
const sortedAttrTextLastChar = sortedAttrText.slice(0, separatorIndex).trim().slice(-1);
219238
if (!separator && [';', ','].some((allowedSep) => sortedAttrTextLastChar === allowedSep)) {

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

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2346,6 +2346,105 @@ ruleTester.run('sort-prop-types', rule, {
23462346
},
23472347
],
23482348
},
2349+
{
2350+
code: `
2351+
type Props = {
2352+
onClose: () => void;
2353+
// identifies the dialog
2354+
id: string;
2355+
};
2356+
function Dialog(props: Props) {
2357+
return <div />;
2358+
}
2359+
`,
2360+
output: `
2361+
type Props = {
2362+
// identifies the dialog
2363+
id: string;
2364+
onClose: () => void;
2365+
};
2366+
function Dialog(props: Props) {
2367+
return <div />;
2368+
}
2369+
`,
2370+
parser: parsers.TYPESCRIPT_ESLINT,
2371+
options: [{
2372+
callbacksLast: true,
2373+
noSortAlphabetically: true,
2374+
checkTypes: true,
2375+
}],
2376+
errors: [
2377+
{
2378+
messageId: 'callbackPropsLast',
2379+
},
2380+
],
2381+
},
2382+
{
2383+
code: `
2384+
type Props = {
2385+
onClose: () => void; // closes the dialog
2386+
// identifies the dialog
2387+
id: string;
2388+
};
2389+
function Dialog(props: Props) {
2390+
return <div />;
2391+
}
2392+
`,
2393+
output: `
2394+
type Props = {
2395+
// identifies the dialog
2396+
id: string;
2397+
onClose: () => void; // closes the dialog
2398+
};
2399+
function Dialog(props: Props) {
2400+
return <div />;
2401+
}
2402+
`,
2403+
parser: parsers.TYPESCRIPT_ESLINT,
2404+
options: [{
2405+
callbacksLast: true,
2406+
noSortAlphabetically: true,
2407+
checkTypes: true,
2408+
}],
2409+
errors: [
2410+
{
2411+
messageId: 'callbackPropsLast',
2412+
},
2413+
],
2414+
},
2415+
{
2416+
code: `
2417+
type Props = {
2418+
onClose: () => void; /* closes the dialog */
2419+
/* identifies the dialog */
2420+
id: string;
2421+
};
2422+
function Dialog(props: Props) {
2423+
return <div />;
2424+
}
2425+
`,
2426+
output: `
2427+
type Props = {
2428+
/* identifies the dialog */
2429+
id: string;
2430+
onClose: () => void; /* closes the dialog */
2431+
};
2432+
function Dialog(props: Props) {
2433+
return <div />;
2434+
}
2435+
`,
2436+
parser: parsers.TYPESCRIPT_ESLINT,
2437+
options: [{
2438+
callbacksLast: true,
2439+
noSortAlphabetically: true,
2440+
checkTypes: true,
2441+
}],
2442+
errors: [
2443+
{
2444+
messageId: 'callbackPropsLast',
2445+
},
2446+
],
2447+
},
23492448
{
23502449
code: `
23512450
type Props = {

0 commit comments

Comments
 (0)