Skip to content

Commit 3534818

Browse files
authored
feat: implement autofix for sort-keys (#216)
* feat: implement autofix for `sort-keys` * skip swaps when either member has an adjacent comment * add block comment test cases * add more tests
1 parent 9661eac commit 3534818

2 files changed

Lines changed: 482 additions & 0 deletions

File tree

src/rules/sort-keys.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import { getKey, getRawKey } from "../util.js";
3939
//-----------------------------------------------------------------------------
4040

4141
const hasNonWhitespace = /\S/u;
42+
const commentTypes = new Set(["LineComment", "BlockComment"]);
4243

4344
/** @type {ComparatorMap} */
4445
const comparators = {
@@ -79,6 +80,8 @@ const rule = {
7980
meta: {
8081
type: "suggestion",
8182

83+
fixable: "code",
84+
8285
defaultOptions: [
8386
"asc",
8487
{
@@ -184,6 +187,30 @@ const rule = {
184187
return false;
185188
}
186189

190+
/**
191+
* Checks if a member has a comment before or after it.
192+
* @param {MemberNode} member The member to check.
193+
* @returns {boolean} True if a comment is adjacent to the member.
194+
*/
195+
function hasAdjacentComment(member) {
196+
const before = sourceCode.getTokenBefore(member, {
197+
includeComments: true,
198+
});
199+
let after = sourceCode.getTokenAfter(member, {
200+
includeComments: true,
201+
});
202+
203+
if (after.type === "Comma") {
204+
after = sourceCode.getTokenAfter(after, {
205+
includeComments: true,
206+
});
207+
}
208+
209+
return (
210+
commentTypes.has(before.type) || commentTypes.has(after.type)
211+
);
212+
}
213+
187214
return {
188215
Object(node) {
189216
/** @type {MemberNode} */
@@ -200,6 +227,9 @@ const rule = {
200227
for (const member of node.members) {
201228
const thisName = getKey(member);
202229
const thisRawName = getRawKey(member, sourceCode);
230+
// Capture `prevMember` for this iteration so the fixer closure uses the
231+
// intended node even though `prevMember` is reassigned in the loop.
232+
const prevMemberNode = prevMember;
203233

204234
if (
205235
prevMember &&
@@ -217,6 +247,25 @@ const rule = {
217247
sensitivity,
218248
sortName,
219249
},
250+
fix(fixer) {
251+
if (
252+
hasAdjacentComment(member) ||
253+
hasAdjacentComment(prevMemberNode)
254+
) {
255+
return null;
256+
}
257+
258+
return [
259+
fixer.replaceText(
260+
member,
261+
sourceCode.getText(prevMemberNode),
262+
),
263+
fixer.replaceText(
264+
prevMemberNode,
265+
sourceCode.getText(member),
266+
),
267+
];
268+
},
220269
});
221270
}
222271

0 commit comments

Comments
 (0)