Skip to content

Commit

Permalink
fix: fix sorting objects with inline comments
Browse files Browse the repository at this point in the history
  • Loading branch information
azat-io committed Jun 6, 2023
1 parent 30f801b commit 37a537d
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 89 deletions.
4 changes: 2 additions & 2 deletions rules/sort-imports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import isCoreModule from 'is-core-module'
import { minimatch } from 'minimatch'

import { createEslintRule } from '../utils/create-eslint-rule'
import { getCommentBefore } from '../utils/get-comment-before'
import { getNodeRange } from '../utils/get-node-range'
import { rangeToDiff } from '../utils/range-to-diff'
import { TSConfig } from '../utils/read-ts-config'
import { getComment } from '../utils/get-comment'
import { SortType, SortOrder } from '../typings'
import { sortNodes } from '../utils/sort-nodes'
import { complete } from '../utils/complete'
Expand Down Expand Up @@ -272,7 +272,7 @@ export default createEslintRule<Options, MESSAGE_ID>({
): boolean =>
!!source.getTokensBetween(
left.node,
getComment(right.node, source).before || right.node,
getCommentBefore(right.node, source) || right.node,
{
includeComments: true,
},
Expand Down
18 changes: 1 addition & 17 deletions rules/sort-objects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,11 @@ import type { TSESTree } from '@typescript-eslint/types'
import type { TSESLint } from '@typescript-eslint/utils'
import type { SortingNode } from '../typings'

import { AST_NODE_TYPES, AST_TOKEN_TYPES } from '@typescript-eslint/types'
import { AST_NODE_TYPES } from '@typescript-eslint/types'

import { createEslintRule } from '../utils/create-eslint-rule'
import { toSingleLine } from '../utils/to-single-line'
import { rangeToDiff } from '../utils/range-to-diff'
import { getComment } from '../utils/get-comment'
import { SortType, SortOrder } from '../typings'
import { makeFixes } from '../utils/make-fixes'
import { sortNodes } from '../utils/sort-nodes'
Expand Down Expand Up @@ -161,14 +160,6 @@ export default createEslintRule<Options, MESSAGE_ID>({
}

if (comparison) {
let nextToken = source.getTokenAfter(nodes.at(-1)!.node, {
includeComments: true,
})

let hasTrailingComma =
nextToken?.type === AST_TOKEN_TYPES.Punctuator &&
nextToken.value === ','

let fix:
| ((fixer: TSESLint.RuleFixer) => TSESLint.RuleFix[])
| undefined = fixer => {
Expand All @@ -189,13 +180,6 @@ export default createEslintRule<Options, MESSAGE_ID>({
return makeFixes(fixer, nodes, sortedNodes, source)
}

if (
!hasTrailingComma &&
getComment(nodes.at(-1)!.node, source).after
) {
fix = undefined
}

context.report({
messageId: 'unexpectedObjectsOrder',
data: {
Expand Down
22 changes: 20 additions & 2 deletions test/sort-objects.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ describe(RULE_NAME, () => {
{
code: dedent`
let yokokawaFamily = {
sister: 'Setsuko', // Setsuko completely adores her older brother Seita
sister: 'Setsuko',// Setsuko completely adores her older brother Seita
'mrs-yokokawa': 'Mrs. Yokokawa', // Seita's and Setsuko's mother
brother: 'Seita', // Seita is responsible, mature, and tough
}
Expand All @@ -400,7 +400,7 @@ describe(RULE_NAME, () => {
let yokokawaFamily = {
brother: 'Seita', // Seita is responsible, mature, and tough
'mrs-yokokawa': 'Mrs. Yokokawa', // Seita's and Setsuko's mother
sister: 'Setsuko', // Setsuko completely adores her older brother Seita
sister: 'Setsuko',// Setsuko completely adores her older brother Seita
}
`,
options: [
Expand Down Expand Up @@ -442,6 +442,12 @@ describe(RULE_NAME, () => {
kazuki: 'Kazuki Kurusu' // daddy #2
}
`,
output: dedent`
let daddies = {
kazuki: 'Kazuki Kurusu', // daddy #2
rei: 'Rei Suwa' // daddy #1
}
`,
options: [
{
type: SortType.alphabetical,
Expand Down Expand Up @@ -895,6 +901,12 @@ describe(RULE_NAME, () => {
kazuki: 'Kazuki Kurusu' // daddy #2
}
`,
output: dedent`
let daddies = {
kazuki: 'Kazuki Kurusu', // daddy #2
rei: 'Rei Suwa' // daddy #1
}
`,
options: [
{
type: SortType.natural,
Expand Down Expand Up @@ -1348,6 +1360,12 @@ describe(RULE_NAME, () => {
kazuki: 'Kazuki Kurusu' // daddy #2
}
`,
output: dedent`
let daddies = {
kazuki: 'Kazuki Kurusu', // daddy #2
rei: 'Rei Suwa' // daddy #1
}
`,
options: [
{
type: SortType['line-length'],
Expand Down
25 changes: 25 additions & 0 deletions utils/get-comment-after.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import type { TSESLint } from '@typescript-eslint/utils'
import type { TSESTree } from '@typescript-eslint/types'

import { AST_TOKEN_TYPES } from '@typescript-eslint/types'

export let getCommentAfter = (
node: TSESTree.Node,
source: TSESLint.SourceCode,
): TSESTree.Comment | null => {
let token = source.getTokenAfter(node, {
includeComments: true,
filter: ({ type, value }) =>
!(type === AST_TOKEN_TYPES.Punctuator && [',', ';'].includes(value)),
})

if (
(token?.type === AST_TOKEN_TYPES.Block ||
token?.type === AST_TOKEN_TYPES.Line) &&
node.loc.end.line === token.loc.end.line
) {
return token
}

return null
}
27 changes: 27 additions & 0 deletions utils/get-comment-before.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { TSESLint } from '@typescript-eslint/utils'
import type { TSESTree } from '@typescript-eslint/types'

import { AST_TOKEN_TYPES } from '@typescript-eslint/types'

export let getCommentBefore = (
node: TSESTree.Node,
source: TSESLint.SourceCode,
): TSESTree.Comment | null => {
let [tokenBefore, tokenOrCommentBefore] = source.getTokensBefore(node, {
includeComments: true,
count: 2,
filter: ({ type, value }) =>
!(type === AST_TOKEN_TYPES.Punctuator && [',', ';'].includes(value)),
}) as (TSESTree.Token | null)[]

if (
(tokenOrCommentBefore?.type === AST_TOKEN_TYPES.Block ||
tokenOrCommentBefore?.type === AST_TOKEN_TYPES.Line) &&
node.loc.start.line - tokenOrCommentBefore.loc.end.line <= 1 &&
tokenBefore?.loc.end.line !== tokenOrCommentBefore.loc.start.line
) {
return tokenOrCommentBefore
}

return null
}
53 changes: 0 additions & 53 deletions utils/get-comment.ts

This file was deleted.

12 changes: 4 additions & 8 deletions utils/get-node-range.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { TSESTree } from '@typescript-eslint/types'

import { ASTUtils } from '@typescript-eslint/utils'

import { getComment } from './get-comment'
import { getCommentBefore } from './get-comment-before'

export let getNodeRange = (
node: TSESTree.Node,
Expand All @@ -29,18 +29,14 @@ export let getNodeRange = (
end = bodyClosingParen.range.at(1)!
}

let comment = getComment(node, sourceCode)
let comment = getCommentBefore(node, sourceCode)

if (raw.endsWith(';') || raw.endsWith(',')) {
end -= 1
}

if (comment.before) {
start = comment.before.range.at(0)!
}

if (comment.after) {
end = comment.after.range.at(1)!
if (comment) {
start = comment.range.at(0)!
}

return [start, end]
Expand Down
46 changes: 39 additions & 7 deletions utils/make-fixes.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,49 @@
import type { TSESLint } from '@typescript-eslint/utils'
import type { TSESTree } from '@typescript-eslint/types'
import type { SortingNode } from '../typings'

import { getCommentAfter } from './get-comment-after'
import { getNodeRange } from './get-node-range'

export let makeFixes = (
fixer: TSESLint.RuleFixer,
nodes: SortingNode[],
sortedNodes: SortingNode[],
source: TSESLint.SourceCode,
) =>
nodes.map(({ node }, index) =>
fixer.replaceTextRange(
getNodeRange(node, source),
source.text.slice(...getNodeRange(sortedNodes[index].node, source)),
),
)
) => {
let fixes: TSESLint.RuleFix[] = []

nodes.forEach(({ node }, index) => {
fixes.push(
fixer.replaceTextRange(
getNodeRange(node, source),
source.text.slice(...getNodeRange(sortedNodes[index].node, source)),
),
)

let commentAfter = getCommentAfter(sortedNodes[index].node, source)

if (commentAfter) {
let tokenBefore = source.getTokenBefore(commentAfter)

let range: TSESTree.Range = [
tokenBefore!.range.at(1)!,
commentAfter.range.at(1)!,
]

fixes.push(fixer.replaceTextRange(range, ''))

let tokenAfterNode = source.getTokenAfter(node)

fixes.push(
fixer.insertTextAfter(
tokenAfterNode?.loc.end.line === node.loc.end.line
? tokenAfterNode
: node,
source.text.slice(...range),
),
)
}
})
return fixes
}

0 comments on commit 37a537d

Please sign in to comment.