Skip to content

Commit

Permalink
feat: add partition by comment and partition by new line in sort-vari…
Browse files Browse the repository at this point in the history
…able-declarations
  • Loading branch information
hugop95 authored Sep 22, 2024
1 parent 7bf6756 commit aa29335
Show file tree
Hide file tree
Showing 3 changed files with 294 additions and 5 deletions.
36 changes: 36 additions & 0 deletions docs/content/rules/sort-variable-declarations.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,38 @@ Controls whether sorting should be case-sensitive or not.
- `true` — Ignore case when sorting alphabetically or naturally (e.g., “A” and “a” are the same).
- `false` — Consider case when sorting (e.g., “A” comes before “a”).


### partitionByComment

<sub>default: `false`</sub>

Allows you to use comments to separate the members of variable declarations into logical groups. This can help in organizing and maintaining large enums by creating partitions within the enum based on comments.

- `true` — All comments will be treated as delimiters, creating partitions.
- `false` — Comments will not be used as delimiters.
- `string` — A glob pattern to specify which comments should act as delimiters.
- `string[]` — A list of glob patterns to specify which comments should act as delimiters.

### partitionByNewLine

<sub>default: `false`</sub>

When `true`, the rule will not sort the members of a variable declaration if there is an empty line between them. This can be useful for keeping logically separated groups of members in their defined order.

```ts
const
// Group 1
fiat = "Fiat",
honda = "Honda",

// Group 2
ferrari = "Ferrari",

// Group 3
chevrolet = "Chevrolet",
ford = "Ford"
```

## Usage

<CodeTabs
Expand All @@ -127,6 +159,8 @@ Controls whether sorting should be case-sensitive or not.
type: 'alphabetical',
order: 'asc',
ignoreCase: true,
partitionByNewLine: false,
partitionByComment: false,
},
],
},
Expand All @@ -150,6 +184,8 @@ Controls whether sorting should be case-sensitive or not.
type: 'alphabetical',
order: 'asc',
ignoreCase: true,
partitionByNewLine: false,
partitionByComment: false,
},
],
},
Expand Down
67 changes: 62 additions & 5 deletions rules/sort-variable-declarations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {
getFirstUnorderedNodeDependentOn,
sortNodesByDependencies,
} from '../utils/sort-nodes-by-dependencies'
import { hasPartitionComment } from '../utils/is-partition-comment'
import { getCommentsBefore } from '../utils/get-comments-before'
import { createEslintRule } from '../utils/create-eslint-rule'
import { getLinesBetween } from '../utils/get-lines-between'
import { getSourceCode } from '../utils/get-source-code'
import { toSingleLine } from '../utils/to-single-line'
import { rangeToDiff } from '../utils/range-to-diff'
Expand All @@ -23,6 +26,8 @@ type MESSAGE_ID =
type Options = [
Partial<{
type: 'alphabetical' | 'line-length' | 'natural'
partitionByComment: string[] | boolean | string
partitionByNewLine: boolean
order: 'desc' | 'asc'
ignoreCase: boolean
}>,
Expand Down Expand Up @@ -56,6 +61,29 @@ export default createEslintRule<Options, MESSAGE_ID>({
'Controls whether sorting should be case-sensitive or not.',
type: 'boolean',
},
partitionByComment: {
description:
'Allows you to use comments to separate the variable declarations into logical groups.',
anyOf: [
{
type: 'array',
items: {
type: 'string',
},
},
{
type: 'boolean',
},
{
type: 'string',
},
],
},
partitionByNewLine: {
description:
'Allows to use spaces to separate the nodes into logical groups.',
type: 'boolean',
},
},
additionalProperties: false,
},
Expand All @@ -72,6 +100,8 @@ export default createEslintRule<Options, MESSAGE_ID>({
type: 'alphabetical',
order: 'asc',
ignoreCase: true,
partitionByComment: false,
partitionByNewLine: false,
},
],
create: context => ({
Expand All @@ -82,10 +112,13 @@ export default createEslintRule<Options, MESSAGE_ID>({
let options = complete(context.options.at(0), settings, {
type: 'alphabetical',
ignoreCase: true,
partitionByNewLine: false,
partitionByComment: false,
order: 'asc',
} as const)

let sourceCode = getSourceCode(context)
let partitionComment = options.partitionByComment

let extractDependencies = (init: TSESTree.Expression): string[] => {
let dependencies: string[] = []
Expand Down Expand Up @@ -170,8 +203,8 @@ export default createEslintRule<Options, MESSAGE_ID>({
return dependencies
}

let nodes = node.declarations.map(
(declaration): SortingNodeWithDependencies => {
let formattedMembers = node.declarations.reduce(
(accumulator: SortingNodeWithDependencies[][], declaration) => {
let name

if (
Expand All @@ -188,16 +221,37 @@ export default createEslintRule<Options, MESSAGE_ID>({
dependencies = extractDependencies(declaration.init)
}

return {
let lastSortingNode = accumulator.at(-1)?.at(-1)
let sortingNode: SortingNodeWithDependencies = {
size: rangeToDiff(declaration.range),
node: declaration,
dependencies,
name,
}
if (
(partitionComment &&
hasPartitionComment(
partitionComment,
getCommentsBefore(declaration, sourceCode),
)) ||
(options.partitionByNewLine &&
lastSortingNode &&
getLinesBetween(sourceCode, lastSortingNode, sortingNode))
) {
accumulator.push([])
}

accumulator.at(-1)?.push(sortingNode)

return accumulator
},
[[]],
)
let sortedNodes = sortNodesByDependencies(sortNodes(nodes, options))

let sortedNodes = sortNodesByDependencies(
formattedMembers.map(nodes => sortNodes(nodes, options)).flat(),
)
let nodes = formattedMembers.flat()
pairwise(nodes, (left, right) => {
let indexOfLeft = sortedNodes.indexOf(left)
let indexOfRight = sortedNodes.indexOf(right)
Expand All @@ -214,7 +268,10 @@ export default createEslintRule<Options, MESSAGE_ID>({
nodeDependentOnRight: firstUnorderedNodeDependentOnRight?.name,
},
node: right.node,
fix: fixer => makeFixes(fixer, nodes, sortedNodes, sourceCode),
fix: fixer =>
makeFixes(fixer, nodes, sortedNodes, sourceCode, {
partitionComment,
}),
})
}
})
Expand Down
196 changes: 196 additions & 0 deletions test/sort-variable-declarations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,202 @@ describe(ruleName, () => {
invalid: [],
},
)

ruleTester.run(
`${ruleName}(${type}): allows to use new line as partition`,
rule,
{
valid: [],
invalid: [
{
code: dedent`
const
d = 'D',
a = 'A',
c = 'C',
e = 'E',
b = 'B'
`,
output: dedent`
const
a = 'A',
d = 'D',
c = 'C',
b = 'B',
e = 'E'
`,
options: [
{
type: 'alphabetical',
partitionByNewLine: true,
},
],
errors: [
{
messageId: 'unexpectedVariableDeclarationsOrder',
data: {
left: 'd',
right: 'a',
},
},
{
messageId: 'unexpectedVariableDeclarationsOrder',
data: {
left: 'e',
right: 'b',
},
},
],
},
],
},
)

describe(`${ruleName}(${type}): partition comments`, () => {
ruleTester.run(
`${ruleName}(${type}): allows to use partition comments`,
rule,
{
valid: [],
invalid: [
{
code: dedent`
const
// Part: A
cc = 'CC',
d = 'D',
// Not partition comment
bbb = 'BBB',
// Part: B
aaa = 'AAA',
e = 'E',
// Part: C
gg = 'GG',
// Not partition comment
fff = 'FFF'
`,
output: dedent`
const
// Part: A
// Not partition comment
bbb = 'BBB',
cc = 'CC',
d = 'D',
// Part: B
aaa = 'AAA',
e = 'E',
// Part: C
// Not partition comment
fff = 'FFF',
gg = 'GG'
`,
options: [
{
...options,
partitionByComment: 'Part**',
},
],
errors: [
{
messageId: 'unexpectedVariableDeclarationsOrder',
data: {
left: 'd',
right: 'bbb',
},
},
{
messageId: 'unexpectedVariableDeclarationsOrder',
data: {
left: 'gg',
right: 'fff',
},
},
],
},
],
},
)

ruleTester.run(
`${ruleName}(${type}): allows to use all comments as parts`,
rule,
{
valid: [
{
code: dedent`
const
// Comment
bb = 'bb',
// Other comment
a = 'a'
`,
options: [
{
...options,
partitionByComment: true,
},
],
},
],
invalid: [],
},
)

ruleTester.run(
`${ruleName}(${type}): allows to use multiple partition comments`,
rule,
{
valid: [],
invalid: [
{
code: dedent`
const
/* Partition Comment */
// Part: A
d = 'D',
// Part: B
aaa = 'AAA',
c = 'C',
bb = 'BB',
/* Other */
e = 'E'
`,
output: dedent`
const
/* Partition Comment */
// Part: A
d = 'D',
// Part: B
aaa = 'AAA',
bb = 'BB',
c = 'C',
/* Other */
e = 'E'
`,
options: [
{
...options,
partitionByComment: ['Partition Comment', 'Part: *', 'Other'],
},
],
errors: [
{
messageId: 'unexpectedVariableDeclarationsOrder',
data: {
left: 'c',
right: 'bb',
},
},
],
},
],
},
)
})
})

describe(`${ruleName}: sorting by natural order`, () => {
Expand Down

0 comments on commit aa29335

Please sign in to comment.