Skip to content

Commit 43e2861

Browse files
Alphabetize: new option groups (#1144)
* alphabetize Fix Fix alphabetize rule changeset Fix remove console error * fix Co-authored-by: Dimitri POSTOLOV <[email protected]>
1 parent b1f2730 commit 43e2861

File tree

5 files changed

+328
-1
lines changed

5 files changed

+328
-1
lines changed

.changeset/flat-apes-develop.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-eslint/eslint-plugin': minor
3+
---
4+
5+
Add new option `groups` to `alphabetize` rule

docs/rules/alphabetize.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,18 @@ Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `dir
176176

177177
Default: `false`
178178

179+
### `groups` (array)
180+
181+
Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt']` where `*` says for everything
182+
else.
183+
184+
The object is an array with all elements of the type `string`.
185+
186+
Additional restrictions:
187+
188+
- Minimum items: `2`
189+
- Unique items: `true`
190+
179191
## Resources
180192

181193
- [Rule source](../../packages/plugin/src/rules/alphabetize.ts)

packages/plugin/src/rules/alphabetize.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@ const schema = {
100100
'Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `directive`.',
101101
default: false,
102102
},
103+
groups: {
104+
...ARRAY_DEFAULT_OPTIONS,
105+
minItems: 2,
106+
description:
107+
"Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt']` where `*` says for everything else.",
108+
},
103109
},
104110
},
105111
} as const;
@@ -199,6 +205,7 @@ export const rule: GraphQLESLintRule<RuleOptions> = {
199205
arguments: argumentsEnum,
200206
// TODO: add in graphql-eslint v4
201207
// definitions: true,
208+
// groups: ['id', '*', 'createdAt', 'updatedAt']
202209
},
203210
],
204211
operations: [
@@ -277,8 +284,26 @@ export const rule: GraphQLESLintRule<RuleOptions> = {
277284
if (prevName) {
278285
// Compare with lexicographic order
279286
const compareResult = prevName.localeCompare(currName);
287+
288+
const { groups } = opts;
289+
let shouldSortByGroup = false;
290+
291+
if (groups?.length) {
292+
if (!groups.includes('*')) {
293+
throw new Error('`groups` option should contain `*` string.');
294+
}
295+
let indexForPrev = groups.indexOf(prevName);
296+
if (indexForPrev === -1) indexForPrev = groups.indexOf('*');
297+
let indexForCurr = groups.indexOf(currName);
298+
if (indexForCurr === -1) indexForCurr = groups.indexOf('*');
299+
shouldSortByGroup = indexForPrev - indexForCurr > 0;
300+
if (indexForPrev < indexForCurr) {
301+
continue;
302+
}
303+
}
304+
280305
const shouldSort = compareResult === 1;
281-
if (!shouldSort) {
306+
if (!shouldSortByGroup && !shouldSort) {
282307
const isSameName = compareResult === 0;
283308
if (
284309
!isSameName ||

packages/plugin/tests/__snapshots__/alphabetize.spec.md

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,228 @@ exports[`should move comment 1`] = `
622622
14 | } # } character
623623
`;
624624

625+
exports[`should sort by group when \`*\` at the start 1`] = `
626+
#### ⌨️ Code
627+
628+
1 | type User {
629+
2 | firstName: Int
630+
3 | createdAt: DateTime
631+
4 | author: Int
632+
5 | wagon: Int
633+
6 | id: ID
634+
7 | foo: Int
635+
8 | updatedAt: DateTime
636+
9 | bar: Int
637+
10 | nachos: Int
638+
11 | guild: Int
639+
12 | }
640+
641+
#### ⚙️ Options
642+
643+
{
644+
"fields": [
645+
"ObjectTypeDefinition"
646+
],
647+
"groups": [
648+
"*",
649+
"updatedAt",
650+
"id",
651+
"createdAt"
652+
]
653+
}
654+
655+
#### ❌ Error 1/4
656+
657+
3 | createdAt: DateTime
658+
> 4 | author: Int
659+
| ^^^^^^ \`author\` should be before \`createdAt\`.
660+
5 | wagon: Int
661+
662+
#### ❌ Error 2/4
663+
664+
6 | id: ID
665+
> 7 | foo: Int
666+
| ^^^ \`foo\` should be before \`id\`.
667+
8 | updatedAt: DateTime
668+
669+
#### ❌ Error 3/4
670+
671+
8 | updatedAt: DateTime
672+
> 9 | bar: Int
673+
| ^^^ \`bar\` should be before \`updatedAt\`.
674+
10 | nachos: Int
675+
676+
#### ❌ Error 4/4
677+
678+
10 | nachos: Int
679+
> 11 | guild: Int
680+
| ^^^^^ \`guild\` should be before \`nachos\`.
681+
12 | }
682+
683+
#### 🔧 Autofix output
684+
685+
1 | type User {
686+
2 | author: Int
687+
3 | bar: Int
688+
4 | firstName: Int
689+
5 | foo: Int
690+
6 | guild: Int
691+
7 | nachos: Int
692+
8 | wagon: Int
693+
9 | updatedAt: DateTime
694+
10 | id: ID
695+
11 | createdAt: DateTime
696+
12 | }
697+
`;
698+
699+
exports[`should sort by group when \`*\` is at the end 1`] = `
700+
#### ⌨️ Code
701+
702+
1 | type User {
703+
2 | firstName: Int
704+
3 | createdAt: DateTime
705+
4 | author: Int
706+
5 | wagon: Int
707+
6 | id: ID
708+
7 | foo: Int
709+
8 | updatedAt: DateTime
710+
9 | bar: Int
711+
10 | nachos: Int
712+
11 | guild: Int
713+
12 | }
714+
715+
#### ⚙️ Options
716+
717+
{
718+
"fields": [
719+
"ObjectTypeDefinition"
720+
],
721+
"groups": [
722+
"updatedAt",
723+
"id",
724+
"createdAt",
725+
"*"
726+
]
727+
}
728+
729+
#### ❌ Error 1/4
730+
731+
2 | firstName: Int
732+
> 3 | createdAt: DateTime
733+
| ^^^^^^^^^ \`createdAt\` should be before \`firstName\`.
734+
4 | author: Int
735+
736+
#### ❌ Error 2/4
737+
738+
5 | wagon: Int
739+
> 6 | id: ID
740+
| ^^ \`id\` should be before \`wagon\`.
741+
7 | foo: Int
742+
743+
#### ❌ Error 3/4
744+
745+
7 | foo: Int
746+
> 8 | updatedAt: DateTime
747+
| ^^^^^^^^^ \`updatedAt\` should be before \`foo\`.
748+
9 | bar: Int
749+
750+
#### ❌ Error 4/4
751+
752+
10 | nachos: Int
753+
> 11 | guild: Int
754+
| ^^^^^ \`guild\` should be before \`nachos\`.
755+
12 | }
756+
757+
#### 🔧 Autofix output
758+
759+
1 | type User {
760+
2 | updatedAt: DateTime
761+
3 | id: ID
762+
4 | createdAt: DateTime
763+
5 | author: Int
764+
6 | bar: Int
765+
7 | firstName: Int
766+
8 | foo: Int
767+
9 | guild: Int
768+
10 | nachos: Int
769+
11 | wagon: Int
770+
12 | }
771+
`;
772+
773+
exports[`should sort by group when \`*\` is between 1`] = `
774+
#### ⌨️ Code
775+
776+
1 | type User {
777+
2 | firstName: Int
778+
3 | createdAt: DateTime
779+
4 | author: Int
780+
5 | wagon: Int
781+
6 | id: ID
782+
7 | foo: Int
783+
8 | updatedAt: DateTime
784+
9 | bar: Int
785+
10 | nachos: Int
786+
11 | guild: Int
787+
12 | }
788+
789+
#### ⚙️ Options
790+
791+
{
792+
"fields": [
793+
"ObjectTypeDefinition"
794+
],
795+
"groups": [
796+
"id",
797+
"*",
798+
"createdAt",
799+
"updatedAt"
800+
]
801+
}
802+
803+
#### ❌ Error 1/4
804+
805+
3 | createdAt: DateTime
806+
> 4 | author: Int
807+
| ^^^^^^ \`author\` should be before \`createdAt\`.
808+
5 | wagon: Int
809+
810+
#### ❌ Error 2/4
811+
812+
5 | wagon: Int
813+
> 6 | id: ID
814+
| ^^ \`id\` should be before \`wagon\`.
815+
7 | foo: Int
816+
817+
#### ❌ Error 3/4
818+
819+
8 | updatedAt: DateTime
820+
> 9 | bar: Int
821+
| ^^^ \`bar\` should be before \`updatedAt\`.
822+
10 | nachos: Int
823+
824+
#### ❌ Error 4/4
825+
826+
10 | nachos: Int
827+
> 11 | guild: Int
828+
| ^^^^^ \`guild\` should be before \`nachos\`.
829+
12 | }
830+
831+
#### 🔧 Autofix output
832+
833+
1 | type User {
834+
2 | id: ID
835+
3 | author: Int
836+
4 | bar: Int
837+
5 | firstName: Int
838+
6 | foo: Int
839+
7 | guild: Int
840+
8 | nachos: Int
841+
9 | wagon: Int
842+
10 | createdAt: DateTime
843+
11 | updatedAt: DateTime
844+
12 | }
845+
`;
846+
625847
exports[`should sort definitions 1`] = `
626848
#### ⌨️ Code
627849

packages/plugin/tests/alphabetize.spec.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,21 @@ import { rule, RuleOptions } from '../src/rules/alphabetize';
33

44
const ruleTester = new GraphQLRuleTester();
55

6+
const GROUP_ORDER_TEST = /* GraphQL */ `
7+
type User {
8+
firstName: Int
9+
createdAt: DateTime
10+
author: Int
11+
wagon: Int
12+
id: ID
13+
foo: Int
14+
updatedAt: DateTime
15+
bar: Int
16+
nachos: Int
17+
guild: Int
18+
}
19+
`
20+
621
ruleTester.runGraphQLTests<RuleOptions>('alphabetize', rule, {
722
valid: [
823
{
@@ -364,5 +379,53 @@ ruleTester.runGraphQLTests<RuleOptions>('alphabetize', rule, {
364379
{ message: '`firsName` should be before `fullName`.' },
365380
],
366381
},
382+
{
383+
name: 'should sort by group when `*` is between',
384+
options: [
385+
{
386+
fields: ['ObjectTypeDefinition'],
387+
groups: ['id', '*', 'createdAt', 'updatedAt'],
388+
},
389+
],
390+
code: GROUP_ORDER_TEST,
391+
errors: [
392+
{ message: '`author` should be before `createdAt`.' },
393+
{ message: '`id` should be before `wagon`.' },
394+
{ message: '`bar` should be before `updatedAt`.' },
395+
{ message: '`guild` should be before `nachos`.' },
396+
],
397+
},
398+
{
399+
name: 'should sort by group when `*` is at the end',
400+
options: [
401+
{
402+
fields: ['ObjectTypeDefinition'],
403+
groups: ['updatedAt', 'id', 'createdAt', '*'],
404+
},
405+
],
406+
code: GROUP_ORDER_TEST,
407+
errors: [
408+
{ message: '`createdAt` should be before `firstName`.' },
409+
{ message: '`id` should be before `wagon`.' },
410+
{ message: '`updatedAt` should be before `foo`.' },
411+
{ message: '`guild` should be before `nachos`.' },
412+
],
413+
},
414+
{
415+
name: 'should sort by group when `*` at the start',
416+
options: [
417+
{
418+
fields: ['ObjectTypeDefinition'],
419+
groups: ['*', 'updatedAt', 'id', 'createdAt'],
420+
},
421+
],
422+
code: GROUP_ORDER_TEST,
423+
errors: [
424+
{ message: '`author` should be before `createdAt`.' },
425+
{ message: '`foo` should be before `id`.' },
426+
{ message: '`bar` should be before `updatedAt`.' },
427+
{ message: '`guild` should be before `nachos`.' },
428+
],
429+
},
367430
],
368431
});

0 commit comments

Comments
 (0)