Skip to content

Commit afa8b8a

Browse files
feat: add option to short relationships last in OperationDefinition (#2385)
* feat: add option to short relationships last in OperationDefinition with tests * upd * upd * upd * upd * prettier * Create empty-singers-develop.md * upd --------- Co-authored-by: Dimitri POSTOLOV <[email protected]>
1 parent b45bf4d commit afa8b8a

File tree

6 files changed

+210
-14
lines changed

6 files changed

+210
-14
lines changed

.changeset/empty-singers-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": feat
3+
---
4+
5+
feat: add a new option `{` for alphabetize rule to sort fields `selection set`

packages/plugin/src/configs/operations-all.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export = {
1313
selections: ['OperationDefinition', 'FragmentDefinition'],
1414
variables: true,
1515
arguments: ['Field', 'Directive'],
16-
groups: ['...', 'id', '*', 'createdAt', 'updatedAt'],
16+
groups: ['...', 'id', '*', '{'],
1717
},
1818
],
1919
'@graphql-eslint/lone-executable-definition': 'error',

packages/plugin/src/rules/alphabetize/index.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,5 +504,57 @@ ruleTester.run<RuleOptions>('alphabetize', rule, {
504504
`,
505505
errors: 4,
506506
},
507+
{
508+
name: 'should sort selection set at the end',
509+
options: [
510+
{
511+
selections: ['OperationDefinition'],
512+
groups: ['id', '*', 'updatedAt', '{'],
513+
},
514+
],
515+
code: /* GraphQL */ `
516+
{
517+
zz
518+
updatedAt
519+
createdAt {
520+
__typename
521+
}
522+
aa
523+
user {
524+
id
525+
}
526+
aab {
527+
id
528+
}
529+
}
530+
`,
531+
errors: 2,
532+
},
533+
{
534+
name: 'should sort selection set at the start',
535+
options: [
536+
{
537+
selections: ['OperationDefinition'],
538+
groups: ['{', 'id', '*', 'updatedAt'],
539+
},
540+
],
541+
code: /* GraphQL */ `
542+
{
543+
zz
544+
updatedAt
545+
createdAt {
546+
__typename
547+
}
548+
aa
549+
user {
550+
id
551+
}
552+
aab {
553+
id
554+
}
555+
}
556+
`,
557+
errors: 3,
558+
},
507559
],
508560
});

packages/plugin/src/rules/alphabetize/index.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,13 @@ const schema = {
9393
groups: {
9494
...ARRAY_DEFAULT_OPTIONS,
9595
minItems: 2,
96-
description:
97-
"Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt', '...']` where `...` stands for fragment spreads, and `*` stands for everything else.",
96+
description: [
97+
"Order group. Example: `['...', 'id', '*', '{']` where:",
98+
'- `...` stands for fragment spreads',
99+
'- `id` stands for field with name `id`',
100+
'- `*` stands for everything else',
101+
'- `{` stands for fields `selection set`',
102+
].join('\n'),
98103
},
99104
},
100105
},
@@ -203,7 +208,7 @@ export const rule: GraphQLESLintRule<RuleOptions> = {
203208
selections: selectionsEnum,
204209
variables: true,
205210
arguments: [Kind.FIELD, Kind.DIRECTIVE],
206-
groups: ['...', 'id', '*', 'createdAt', 'updatedAt'],
211+
groups: ['...', 'id', '*', '{'],
207212
},
208213
],
209214
},
@@ -417,16 +422,11 @@ function getIndex({
417422
}): number {
418423
// Try an exact match
419424
let index = groups.indexOf(getName(node));
420-
425+
if (index === -1 && 'selectionSet' in node && node.selectionSet) index = groups.indexOf('{');
421426
// Check for the fragment spread group
422-
if (index === -1 && node.kind === Kind.FRAGMENT_SPREAD) {
423-
index = groups.indexOf('...');
424-
}
425-
427+
if (index === -1 && node.kind === Kind.FRAGMENT_SPREAD) index = groups.indexOf('...');
426428
// Check for the catch-all group
427-
if (index === -1) {
428-
index = groups.indexOf('*');
429-
}
429+
if (index === -1) index = groups.indexOf('*');
430430
return index;
431431
}
432432

packages/plugin/src/rules/alphabetize/snapshot.md

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,141 @@ exports[`alphabetize > invalid > should sort definitions 1`] = `
10311031
59 | # END
10321032
`;
10331033

1034+
exports[`alphabetize > invalid > should sort selection set at the end 1`] = `
1035+
#### ⌨️ Code
1036+
1037+
1 | {
1038+
2 | zz
1039+
3 | updatedAt
1040+
4 | createdAt {
1041+
5 | __typename
1042+
6 | }
1043+
7 | aa
1044+
8 | user {
1045+
9 | id
1046+
10 | }
1047+
11 | aab {
1048+
12 | id
1049+
13 | }
1050+
14 | }
1051+
1052+
#### ⚙️ Options
1053+
1054+
{
1055+
"selections": [
1056+
"OperationDefinition"
1057+
],
1058+
"groups": [
1059+
"id",
1060+
"*",
1061+
"updatedAt",
1062+
"{"
1063+
]
1064+
}
1065+
1066+
#### ❌ Error 1/2
1067+
1068+
6 | }
1069+
> 7 | aa
1070+
| ^^ field "aa" should be before field "createdAt"
1071+
8 | user {
1072+
1073+
#### ❌ Error 2/2
1074+
1075+
10 | }
1076+
> 11 | aab {
1077+
| ^^^ field "aab" should be before field "user"
1078+
12 | id
1079+
1080+
#### 🔧 Autofix output
1081+
1082+
1 | {
1083+
2 | aa
1084+
3 | zz
1085+
4 | updatedAt
1086+
5 | aab {
1087+
6 | id
1088+
7 | }
1089+
8 | createdAt {
1090+
9 | __typename
1091+
10 | }
1092+
11 | user {
1093+
12 | id
1094+
13 | }
1095+
14 | }
1096+
`;
1097+
1098+
exports[`alphabetize > invalid > should sort selection set at the start 1`] = `
1099+
#### ⌨️ Code
1100+
1101+
1 | {
1102+
2 | zz
1103+
3 | updatedAt
1104+
4 | createdAt {
1105+
5 | __typename
1106+
6 | }
1107+
7 | aa
1108+
8 | user {
1109+
9 | id
1110+
10 | }
1111+
11 | aab {
1112+
12 | id
1113+
13 | }
1114+
14 | }
1115+
1116+
#### ⚙️ Options
1117+
1118+
{
1119+
"selections": [
1120+
"OperationDefinition"
1121+
],
1122+
"groups": [
1123+
"{",
1124+
"id",
1125+
"*",
1126+
"updatedAt"
1127+
]
1128+
}
1129+
1130+
#### ❌ Error 1/3
1131+
1132+
3 | updatedAt
1133+
> 4 | createdAt {
1134+
| ^^^^^^^^^ field "createdAt" should be before field "updatedAt"
1135+
5 | __typename
1136+
1137+
#### ❌ Error 2/3
1138+
1139+
7 | aa
1140+
> 8 | user {
1141+
| ^^^^ field "user" should be before field "aa"
1142+
9 | id
1143+
1144+
#### ❌ Error 3/3
1145+
1146+
10 | }
1147+
> 11 | aab {
1148+
| ^^^ field "aab" should be before field "user"
1149+
12 | id
1150+
1151+
#### 🔧 Autofix output
1152+
1153+
1 | {
1154+
2 | aab {
1155+
3 | id
1156+
4 | }
1157+
5 | createdAt {
1158+
6 | __typename
1159+
7 | }
1160+
8 | user {
1161+
9 | id
1162+
10 | }
1163+
11 | aa
1164+
12 | zz
1165+
13 | updatedAt
1166+
14 | }
1167+
`;
1168+
10341169
exports[`alphabetize > invalid > should sort selections by group when \`*\` is between 1`] = `
10351170
#### ⌨️ Code
10361171

website/src/pages/rules/alphabetize.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,12 @@ Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `dir
165165

166166
### `groups` (array)
167167

168-
Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt', '...']` where `...` stands for
169-
fragment spreads, and `*` stands for everything else.
168+
Custom order group. Example: `['...', 'id', '*', '{']` where:
169+
170+
- `...` stands for fragment spreads
171+
- `id` stands for field with name `id`
172+
- `*` stands for everything else
173+
- `{` stands for field `selection set`
170174

171175
The object is an array with all elements of the type `string`.
172176

0 commit comments

Comments
 (0)