From 0688ed0a4cb334a30c063e6b3e1b36371c15c53f Mon Sep 17 00:00:00 2001 From: deathemperor Date: Fri, 14 Jun 2024 14:08:14 +0700 Subject: [PATCH 1/8] feat: add option to short relationships last in OperationDefinition with tests --- .../__snapshots__/alphabetize.spec.md | 344 ++++++++++++++++++ packages/plugin/__tests__/alphabetize.spec.ts | 123 +++++++ packages/plugin/src/rules/alphabetize.ts | 20 +- website/src/pages/rules/_meta.ts | 4 +- website/src/pages/rules/alphabetize.md | 4 + 5 files changed, 489 insertions(+), 6 deletions(-) diff --git a/packages/plugin/__tests__/__snapshots__/alphabetize.spec.md b/packages/plugin/__tests__/__snapshots__/alphabetize.spec.md index 287c08f5962..106b4406aa4 100644 --- a/packages/plugin/__tests__/__snapshots__/alphabetize.spec.md +++ b/packages/plugin/__tests__/__snapshots__/alphabetize.spec.md @@ -614,6 +614,153 @@ exports[`alphabetize > invalid > should move comment 1`] = ` 14 | } # } character `; +exports[`alphabetize > invalid > should sort between group relationships 1`] = ` +#### ⌨️ Code + + 1 | { + 2 | aa + 3 | id + 4 | zz + 5 | aab { + 6 | id + 7 | } + 8 | user { + 9 | id + 10 | } + 11 | updatedAt + 12 | } + +#### ⚙️ Options + + { + "selections": [ + "OperationDefinition" + ], + "groups": [ + "id", + "*", + "createdAt", + "updatedAt", + "user", + "aab" + ], + "relationships_last": true + } + +#### ❌ Error 1/3 + + 2 | aa + > 3 | id + | ^^ field "id" should be before field "aa" + 4 | zz + +#### ❌ Error 2/3 + + 7 | } + > 8 | user { + | ^^^^ field "user" should be before field "aab" + 9 | id + +#### ❌ Error 3/3 + + 10 | } + > 11 | updatedAt + | ^^^^^^^^^ field "updatedAt" should be before field "user" + 12 | } + +#### 🔧 Autofix output + + 1 | { + 2 | id + 3 | aa + 4 | zz + 5 | updatedAt + 6 | user { + 7 | id + 8 | } + 9 | aab { + 10 | id + 11 | } + 12 | } +`; + +exports[`alphabetize > invalid > should sort between relationships 1`] = ` +#### ⌨️ Code + + 1 | { + 2 | zz + 3 | updatedAt + 4 | createdAt + 5 | aa + 6 | user { + 7 | id + 8 | } + 9 | aab { + 10 | id + 11 | } + 12 | updatedAt + 13 | } + +#### ⚙️ Options + + { + "selections": [ + "OperationDefinition" + ], + "groups": [ + "id", + "*", + "createdAt", + "updatedAt" + ], + "relationships_last": true + } + +#### ❌ Error 1/4 + + 3 | updatedAt + > 4 | createdAt + | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" + 5 | aa + +#### ❌ Error 2/4 + + 4 | createdAt + > 5 | aa + | ^^ field "aa" should be before field "createdAt" + 6 | user { + +#### ❌ Error 3/4 + + 8 | } + > 9 | aab { + | ^^^ field "aab" should be before field "user" + 10 | id + +#### ❌ Error 4/4 + + 11 | } + > 12 | updatedAt + | ^^^^^^^^^ field "updatedAt" should be before field "aab" + 13 | } + +#### 🔧 Autofix output + + 1 | { + 2 | aa + 3 | zz + 4 | createdAt + 5 | updatedAt + 6 | updatedAt + 7 | aab { + 8 | id + 9 | } + 10 | user { + 11 | id + 12 | } + 13 | } +`; + exports[`alphabetize > invalid > should sort by group when \`*\` at the start 1`] = ` #### ⌨️ Code @@ -1031,6 +1178,203 @@ exports[`alphabetize > invalid > should sort definitions 1`] = ` 59 | # END `; +exports[`alphabetize > invalid > should sort relationships 1`] = ` +#### ⌨️ Code + + 1 | { + 2 | zz + 3 | updatedAt + 4 | createdAt + 5 | z + 6 | yyy { + 7 | id + 8 | } + 9 | } + +#### ⚙️ Options + + { + "selections": [ + "OperationDefinition" + ], + "relationships_last": false + } + +#### ❌ Error 1/3 + + 2 | zz + > 3 | updatedAt + | ^^^^^^^^^ field "updatedAt" should be before field "zz" + 4 | createdAt + +#### ❌ Error 2/3 + + 3 | updatedAt + > 4 | createdAt + | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" + 5 | z + +#### ❌ Error 3/3 + + 5 | z + > 6 | yyy { + | ^^^ field "yyy" should be before field "z" + 7 | id + +#### 🔧 Autofix output + + 1 | { + 2 | createdAt + 3 | updatedAt + 4 | yyy { + 5 | id + 6 | } + 7 | z + 8 | zz + 9 | } +`; + +exports[`alphabetize > invalid > should sort relationships last 1`] = ` +#### ⌨️ Code + + 1 | { + 2 | zz + 3 | updatedAt + 4 | createdAt + 5 | aab { + 6 | id + 7 | } + 8 | aa + 9 | user { + 10 | id + 11 | } + 12 | id + 13 | } + +#### ⚙️ Options + + { + "selections": [ + "OperationDefinition" + ], + "relationships_last": true + } + +#### ❌ Error 1/4 + + 2 | zz + > 3 | updatedAt + | ^^^^^^^^^ field "updatedAt" should be before field "zz" + 4 | createdAt + +#### ❌ Error 2/4 + + 3 | updatedAt + > 4 | createdAt + | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" + 5 | aab { + +#### ❌ Error 3/4 + + 7 | } + > 8 | aa + | ^^ field "aa" should be before field "aab" + 9 | user { + +#### ❌ Error 4/4 + + 11 | } + > 12 | id + | ^^ field "id" should be before field "user" + 13 | } + +#### 🔧 Autofix output + + 1 | { + 2 | aa + 3 | createdAt + 4 | id + 5 | updatedAt + 6 | zz + 7 | aab { + 8 | id + 9 | } + 10 | user { + 11 | id + 12 | } + 13 | } +`; + +exports[`alphabetize > invalid > should sort relationships last with group 1`] = ` +#### ⌨️ Code + + 1 | { + 2 | zz + 3 | updatedAt + 4 | createdAt + 5 | aab { + 6 | id + 7 | } + 8 | aa + 9 | user { + 10 | id + 11 | } + 12 | updatedAt + 13 | } + +#### ⚙️ Options + + { + "selections": [ + "OperationDefinition" + ], + "groups": [ + "id", + "*", + "createdAt", + "updatedAt" + ], + "relationships_last": true + } + +#### ❌ Error 1/3 + + 3 | updatedAt + > 4 | createdAt + | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" + 5 | aab { + +#### ❌ Error 2/3 + + 7 | } + > 8 | aa + | ^^ field "aa" should be before field "aab" + 9 | user { + +#### ❌ Error 3/3 + + 11 | } + > 12 | updatedAt + | ^^^^^^^^^ field "updatedAt" should be before field "user" + 13 | } + +#### 🔧 Autofix output + + 1 | { + 2 | aa + 3 | zz + 4 | createdAt + 5 | updatedAt + 6 | updatedAt + 7 | aab { + 8 | id + 9 | } + 10 | user { + 11 | id + 12 | } + 13 | } +`; + exports[`alphabetize > invalid > should sort selections by group when \`*\` is between 1`] = ` #### ⌨️ Code diff --git a/packages/plugin/__tests__/alphabetize.spec.ts b/packages/plugin/__tests__/alphabetize.spec.ts index 6cb77b78c14..fdddf9d9d2a 100644 --- a/packages/plugin/__tests__/alphabetize.spec.ts +++ b/packages/plugin/__tests__/alphabetize.spec.ts @@ -444,5 +444,128 @@ ruleTester.run('alphabetize', rule, { `, errors: 3, }, + { + name: 'should sort relationships', + options: [ + { + selections: ['OperationDefinition'], + relationships_last: false + }, + ], + code: /* GraphQL */ ` + { + zz + updatedAt + createdAt + z + yyy { + id + } + } + `, + errors: 3, + }, + { + name: 'should sort relationships last', + options: [ + { + selections: ['OperationDefinition'], + relationships_last: true + }, + ], + code: /* GraphQL */ ` + { + zz + updatedAt + createdAt + aab { + id + } + aa + user { + id + } + id + } + `, + errors: 4, + }, + { + name: 'should sort relationships last with group', + options: [ + { + selections: ['OperationDefinition'], + groups: ['id', '*', 'createdAt', 'updatedAt'], + relationships_last: true + }, + ], + code: /* GraphQL */ ` + { + zz + updatedAt + createdAt + aab { + id + } + aa + user { + id + } + updatedAt + } + `, + errors: 3, + }, + { + name: 'should sort between relationships', + options: [ + { + selections: ['OperationDefinition'], + groups: ['id', '*', 'createdAt', 'updatedAt'], + relationships_last: true + }, + ], + code: /* GraphQL */ ` + { + zz + updatedAt + createdAt + aa + user { + id + } + aab { + id + } + updatedAt + } + `, + errors: 4, + }, + { + name: 'should sort between group relationships', + options: [ + { + selections: ['OperationDefinition'], + groups: ['id', '*', 'createdAt', 'updatedAt', 'user', 'aab'], + relationships_last: true + }, + ], + code: /* GraphQL */ ` + { + aa + id + zz + aab { + id + } + user { + id + } + updatedAt + } + `, + errors: 3, + }, ], }); diff --git a/packages/plugin/src/rules/alphabetize.ts b/packages/plugin/src/rules/alphabetize.ts index f61fe91ed65..59f40c425f2 100644 --- a/packages/plugin/src/rules/alphabetize.ts +++ b/packages/plugin/src/rules/alphabetize.ts @@ -96,6 +96,10 @@ const schema = { description: "Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt']` where `*` says for everything else.", }, + relationships_last: { + type: 'boolean', + description: 'Sort nodes last', + }, }, }, } as const; @@ -260,6 +264,7 @@ export const rule: GraphQLESLintRule = { // Starts from 1, ignore nodes.length <= 1 for (let i = 1; i < nodes.length; i += 1) { const currNode = nodes[i]; + const isCurrNodeObject = 'selectionSet' in currNode && currNode.selectionSet != null; const currName = ('alias' in currNode && currNode.alias?.value) || ('name' in currNode && currNode.name?.value); @@ -269,15 +274,22 @@ export const rule: GraphQLESLintRule = { } const prevNode = nodes[i - 1]; + const isPrevNodeObject = 'selectionSet' in prevNode && prevNode.selectionSet != null; const prevName = ('alias' in prevNode && prevNode.alias?.value) || ('name' in prevNode && prevNode.name?.value); if (prevName) { + const { groups, relationships_last } = opts; + if (relationships_last && isCurrNodeObject && !isPrevNodeObject) { + continue; + } // Compare with lexicographic order - const compareResult = prevName.localeCompare(currName); - - const { groups } = opts; + let compareResult = prevName.localeCompare(currName); let shouldSortByGroup = false; + const shouldSortNodes = relationships_last && !isCurrNodeObject && isPrevNodeObject + if (shouldSortNodes) { + compareResult = 1; + } if (groups?.length) { if (!groups.includes('*')) { @@ -288,7 +300,7 @@ export const rule: GraphQLESLintRule = { let indexForCurr = groups.indexOf(currName); if (indexForCurr === -1) indexForCurr = groups.indexOf('*'); shouldSortByGroup = indexForPrev - indexForCurr > 0; - if (indexForPrev < indexForCurr) { + if (indexForPrev < indexForCurr && !shouldSortNodes) { continue; } } diff --git a/website/src/pages/rules/_meta.ts b/website/src/pages/rules/_meta.ts index e61f8f57070..32bd27eaddd 100644 --- a/website/src/pages/rules/_meta.ts +++ b/website/src/pages/rules/_meta.ts @@ -68,5 +68,5 @@ export default { 'unique-variable-names': '', 'value-literals-of-correct-type': '', 'variables-are-input-types': '', - 'variables-in-allowed-position': '', -}; + 'variables-in-allowed-position': '' +} diff --git a/website/src/pages/rules/alphabetize.md b/website/src/pages/rules/alphabetize.md index b0cab34300b..cade961d15d 100644 --- a/website/src/pages/rules/alphabetize.md +++ b/website/src/pages/rules/alphabetize.md @@ -169,6 +169,10 @@ Additional restrictions: - Minimum items: `2` - Unique items: `true` +### `relationships_last` (boolean) + +Sort relationships last + ## Resources - [Rule source](https://github.com/B2o5T/graphql-eslint/tree/master/packages/plugin/src/rules/alphabetize.ts) From 859e211b5153709fe298a7b4b119bc76475e77fd Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 16 Nov 2024 09:43:02 +0700 Subject: [PATCH 2/8] upd --- .../src/rules/alphabetize/index.test.ts | 104 +----- .../plugin/src/rules/alphabetize/snapshot.md | 346 ++---------------- 2 files changed, 42 insertions(+), 408 deletions(-) diff --git a/packages/plugin/src/rules/alphabetize/index.test.ts b/packages/plugin/src/rules/alphabetize/index.test.ts index 2486458a3bb..a4372ea590b 100644 --- a/packages/plugin/src/rules/alphabetize/index.test.ts +++ b/packages/plugin/src/rules/alphabetize/index.test.ts @@ -505,123 +505,27 @@ ruleTester.run('alphabetize', rule, { errors: 4, }, { - name: 'should sort relationships', + name: 'should sort selection set', options: [ { selections: ['OperationDefinition'], - relationships_last: false + groups: ['id', '*', 'createdAt', 'updatedAt', '{'], }, ], code: /* GraphQL */ ` { zz updatedAt - createdAt - z - yyy { - id - } - } - `, - errors: 3, - }, - { - name: 'should sort relationships last', - options: [ - { - selections: ['OperationDefinition'], - relationships_last: true - }, - ], - code: /* GraphQL */ ` - { - zz - updatedAt - createdAt - aab { - id + createdAt { + __typename } aa user { id } - id - } - `, - errors: 4, - }, - { - name: 'should sort relationships last with group', - options: [ - { - selections: ['OperationDefinition'], - groups: ['id', '*', 'createdAt', 'updatedAt'], - relationships_last: true - }, - ], - code: /* GraphQL */ ` - { - zz - updatedAt - createdAt aab { id } - aa - user { - id - } - updatedAt - } - `, - errors: 3, - }, - { - name: 'should sort between relationships', - options: [ - { - selections: ['OperationDefinition'], - groups: ['id', '*', 'createdAt', 'updatedAt'], - relationships_last: true - }, - ], - code: /* GraphQL */ ` - { - zz - updatedAt - createdAt - aa - user { - id - } - aab { - id - } - updatedAt - } - `, - errors: 4, - }, - { - name: 'should sort between group relationships', - options: [ - { - selections: ['OperationDefinition'], - groups: ['id', '*', 'createdAt', 'updatedAt', 'user', 'aab'], - relationships_last: true - }, - ], - code: /* GraphQL */ ` - { - aa - id - zz - aab { - id - } - user { - id - } updatedAt } `, diff --git a/packages/plugin/src/rules/alphabetize/snapshot.md b/packages/plugin/src/rules/alphabetize/snapshot.md index a1da493225b..13f94256f65 100644 --- a/packages/plugin/src/rules/alphabetize/snapshot.md +++ b/packages/plugin/src/rules/alphabetize/snapshot.md @@ -614,153 +614,6 @@ exports[`alphabetize > invalid > should move comment 1`] = ` 14 | } # } character `; -exports[`alphabetize > invalid > should sort between group relationships 1`] = ` -#### ⌨️ Code - - 1 | { - 2 | aa - 3 | id - 4 | zz - 5 | aab { - 6 | id - 7 | } - 8 | user { - 9 | id - 10 | } - 11 | updatedAt - 12 | } - -#### ⚙️ Options - - { - "selections": [ - "OperationDefinition" - ], - "groups": [ - "id", - "*", - "createdAt", - "updatedAt", - "user", - "aab" - ], - "relationships_last": true - } - -#### ❌ Error 1/3 - - 2 | aa - > 3 | id - | ^^ field "id" should be before field "aa" - 4 | zz - -#### ❌ Error 2/3 - - 7 | } - > 8 | user { - | ^^^^ field "user" should be before field "aab" - 9 | id - -#### ❌ Error 3/3 - - 10 | } - > 11 | updatedAt - | ^^^^^^^^^ field "updatedAt" should be before field "user" - 12 | } - -#### 🔧 Autofix output - - 1 | { - 2 | id - 3 | aa - 4 | zz - 5 | updatedAt - 6 | user { - 7 | id - 8 | } - 9 | aab { - 10 | id - 11 | } - 12 | } -`; - -exports[`alphabetize > invalid > should sort between relationships 1`] = ` -#### ⌨️ Code - - 1 | { - 2 | zz - 3 | updatedAt - 4 | createdAt - 5 | aa - 6 | user { - 7 | id - 8 | } - 9 | aab { - 10 | id - 11 | } - 12 | updatedAt - 13 | } - -#### ⚙️ Options - - { - "selections": [ - "OperationDefinition" - ], - "groups": [ - "id", - "*", - "createdAt", - "updatedAt" - ], - "relationships_last": true - } - -#### ❌ Error 1/4 - - 3 | updatedAt - > 4 | createdAt - | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" - 5 | aa - -#### ❌ Error 2/4 - - 4 | createdAt - > 5 | aa - | ^^ field "aa" should be before field "createdAt" - 6 | user { - -#### ❌ Error 3/4 - - 8 | } - > 9 | aab { - | ^^^ field "aab" should be before field "user" - 10 | id - -#### ❌ Error 4/4 - - 11 | } - > 12 | updatedAt - | ^^^^^^^^^ field "updatedAt" should be before field "aab" - 13 | } - -#### 🔧 Autofix output - - 1 | { - 2 | aa - 3 | zz - 4 | createdAt - 5 | updatedAt - 6 | updatedAt - 7 | aab { - 8 | id - 9 | } - 10 | user { - 11 | id - 12 | } - 13 | } -`; - exports[`alphabetize > invalid > should sort by group when \`*\` at the start 1`] = ` #### ⌨️ Code @@ -1178,149 +1031,24 @@ exports[`alphabetize > invalid > should sort definitions 1`] = ` 59 | # END `; -exports[`alphabetize > invalid > should sort relationships 1`] = ` -#### ⌨️ Code - - 1 | { - 2 | zz - 3 | updatedAt - 4 | createdAt - 5 | z - 6 | yyy { - 7 | id - 8 | } - 9 | } - -#### ⚙️ Options - - { - "selections": [ - "OperationDefinition" - ], - "relationships_last": false - } - -#### ❌ Error 1/3 - - 2 | zz - > 3 | updatedAt - | ^^^^^^^^^ field "updatedAt" should be before field "zz" - 4 | createdAt - -#### ❌ Error 2/3 - - 3 | updatedAt - > 4 | createdAt - | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" - 5 | z - -#### ❌ Error 3/3 - - 5 | z - > 6 | yyy { - | ^^^ field "yyy" should be before field "z" - 7 | id - -#### 🔧 Autofix output - - 1 | { - 2 | createdAt - 3 | updatedAt - 4 | yyy { - 5 | id - 6 | } - 7 | z - 8 | zz - 9 | } -`; - -exports[`alphabetize > invalid > should sort relationships last 1`] = ` +exports[`alphabetize > invalid > should sort selection set 1`] = ` #### ⌨️ Code 1 | { 2 | zz 3 | updatedAt - 4 | createdAt - 5 | aab { - 6 | id - 7 | } - 8 | aa - 9 | user { - 10 | id - 11 | } - 12 | id - 13 | } - -#### ⚙️ Options - - { - "selections": [ - "OperationDefinition" - ], - "relationships_last": true - } - -#### ❌ Error 1/4 - - 2 | zz - > 3 | updatedAt - | ^^^^^^^^^ field "updatedAt" should be before field "zz" - 4 | createdAt - -#### ❌ Error 2/4 - - 3 | updatedAt - > 4 | createdAt - | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" - 5 | aab { - -#### ❌ Error 3/4 - - 7 | } - > 8 | aa - | ^^ field "aa" should be before field "aab" - 9 | user { - -#### ❌ Error 4/4 - - 11 | } - > 12 | id - | ^^ field "id" should be before field "user" - 13 | } - -#### 🔧 Autofix output - - 1 | { - 2 | aa - 3 | createdAt - 4 | id - 5 | updatedAt - 6 | zz - 7 | aab { - 8 | id - 9 | } - 10 | user { - 11 | id - 12 | } - 13 | } -`; - -exports[`alphabetize > invalid > should sort relationships last with group 1`] = ` -#### ⌨️ Code - - 1 | { - 2 | zz - 3 | updatedAt - 4 | createdAt - 5 | aab { - 6 | id - 7 | } - 8 | aa - 9 | user { - 10 | id - 11 | } - 12 | updatedAt - 13 | } + 4 | createdAt { + 5 | __typename + 6 | } + 7 | aa + 8 | user { + 9 | id + 10 | } + 11 | aab { + 12 | id + 13 | } + 14 | updatedAt + 15 | } #### ⚙️ Options @@ -1332,47 +1060,49 @@ exports[`alphabetize > invalid > should sort relationships last with group 1`] = "id", "*", "createdAt", - "updatedAt" - ], - "relationships_last": true + "updatedAt", + "{" + ] } #### ❌ Error 1/3 3 | updatedAt - > 4 | createdAt + > 4 | createdAt { | ^^^^^^^^^ field "createdAt" should be before field "updatedAt" - 5 | aab { + 5 | __typename #### ❌ Error 2/3 - 7 | } - > 8 | aa - | ^^ field "aa" should be before field "aab" - 9 | user { + 6 | } + > 7 | aa + | ^^ field "aa" should be before field "createdAt" + 8 | user { #### ❌ Error 3/3 - 11 | } - > 12 | updatedAt - | ^^^^^^^^^ field "updatedAt" should be before field "user" - 13 | } + 10 | } + > 11 | aab { + | ^^^ field "aab" should be before field "user" + 12 | id #### 🔧 Autofix output 1 | { 2 | aa - 3 | zz - 4 | createdAt - 5 | updatedAt - 6 | updatedAt - 7 | aab { - 8 | id - 9 | } - 10 | user { - 11 | id + 3 | aab { + 4 | id + 5 | } + 6 | user { + 7 | id + 8 | } + 9 | zz + 10 | createdAt { + 11 | __typename 12 | } - 13 | } + 13 | updatedAt + 14 | updatedAt + 15 | } `; exports[`alphabetize > invalid > should sort selections by group when \`*\` is between 1`] = ` From b876480004e44073be5ee074aa72a1fef276eece Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 16 Nov 2024 09:58:12 +0700 Subject: [PATCH 3/8] upd --- .../src/rules/alphabetize/index.test.ts | 29 ++- .../plugin/src/rules/alphabetize/index.ts | 11 +- .../plugin/src/rules/alphabetize/snapshot.md | 165 +++++++++++++++--- 3 files changed, 175 insertions(+), 30 deletions(-) diff --git a/packages/plugin/src/rules/alphabetize/index.test.ts b/packages/plugin/src/rules/alphabetize/index.test.ts index a4372ea590b..17665e817d0 100644 --- a/packages/plugin/src/rules/alphabetize/index.test.ts +++ b/packages/plugin/src/rules/alphabetize/index.test.ts @@ -505,11 +505,11 @@ ruleTester.run('alphabetize', rule, { errors: 4, }, { - name: 'should sort selection set', + name: 'should sort selection set at the end', options: [ { selections: ['OperationDefinition'], - groups: ['id', '*', 'createdAt', 'updatedAt', '{'], + groups: ['id', '*', 'updatedAt', '{'], }, ], code: /* GraphQL */ ` @@ -526,7 +526,32 @@ ruleTester.run('alphabetize', rule, { aab { id } + } + `, + errors: 2, + }, + { + name: 'should sort selection set at the start', + options: [ + { + selections: ['OperationDefinition'], + groups: ['{', 'id', '*', 'updatedAt'], + }, + ], + code: /* GraphQL */ ` + { + zz updatedAt + createdAt { + __typename + } + aa + user { + id + } + aab { + id + } } `, errors: 3, diff --git a/packages/plugin/src/rules/alphabetize/index.ts b/packages/plugin/src/rules/alphabetize/index.ts index d7533417dab..754a72c2d18 100644 --- a/packages/plugin/src/rules/alphabetize/index.ts +++ b/packages/plugin/src/rules/alphabetize/index.ts @@ -417,16 +417,11 @@ function getIndex({ }): number { // Try an exact match let index = groups.indexOf(getName(node)); - + if (index === -1 && 'selectionSet' in node && node.selectionSet) index = groups.indexOf('{'); // Check for the fragment spread group - if (index === -1 && node.kind === Kind.FRAGMENT_SPREAD) { - index = groups.indexOf('...'); - } - + if (index === -1 && node.kind === Kind.FRAGMENT_SPREAD) index = groups.indexOf('...'); // Check for the catch-all group - if (index === -1) { - index = groups.indexOf('*'); - } + if (index === -1) index = groups.indexOf('*'); return index; } diff --git a/packages/plugin/src/rules/alphabetize/snapshot.md b/packages/plugin/src/rules/alphabetize/snapshot.md index 13f94256f65..dd0a29990e7 100644 --- a/packages/plugin/src/rules/alphabetize/snapshot.md +++ b/packages/plugin/src/rules/alphabetize/snapshot.md @@ -1047,8 +1047,7 @@ exports[`alphabetize > invalid > should sort selection set 1`] = ` 11 | aab { 12 | id 13 | } - 14 | updatedAt - 15 | } + 14 | } #### ⚙️ Options @@ -1059,12 +1058,139 @@ exports[`alphabetize > invalid > should sort selection set 1`] = ` "groups": [ "id", "*", - "createdAt", "updatedAt", "{" ] } +#### ❌ Error 1/2 + + 6 | } + > 7 | aa + | ^^ field "aa" should be before field "createdAt" + 8 | user { + +#### ❌ Error 2/2 + + 10 | } + > 11 | aab { + | ^^^ field "aab" should be before field "user" + 12 | id + +#### 🔧 Autofix output + + 1 | { + 2 | aa + 3 | zz + 4 | updatedAt + 5 | aab { + 6 | id + 7 | } + 8 | createdAt { + 9 | __typename + 10 | } + 11 | user { + 12 | id + 13 | } + 14 | } +`; + +exports[`alphabetize > invalid > should sort selection set at the end 1`] = ` +#### ⌨️ Code + + 1 | { + 2 | zz + 3 | updatedAt + 4 | createdAt { + 5 | __typename + 6 | } + 7 | aa + 8 | user { + 9 | id + 10 | } + 11 | aab { + 12 | id + 13 | } + 14 | } + +#### ⚙️ Options + + { + "selections": [ + "OperationDefinition" + ], + "groups": [ + "id", + "*", + "updatedAt", + "{" + ] + } + +#### ❌ Error 1/2 + + 6 | } + > 7 | aa + | ^^ field "aa" should be before field "createdAt" + 8 | user { + +#### ❌ Error 2/2 + + 10 | } + > 11 | aab { + | ^^^ field "aab" should be before field "user" + 12 | id + +#### 🔧 Autofix output + + 1 | { + 2 | aa + 3 | zz + 4 | updatedAt + 5 | aab { + 6 | id + 7 | } + 8 | createdAt { + 9 | __typename + 10 | } + 11 | user { + 12 | id + 13 | } + 14 | } +`; + +exports[`alphabetize > invalid > should sort selection set at the start 1`] = ` +#### ⌨️ Code + + 1 | { + 2 | zz + 3 | updatedAt + 4 | createdAt { + 5 | __typename + 6 | } + 7 | aa + 8 | user { + 9 | id + 10 | } + 11 | aab { + 12 | id + 13 | } + 14 | } + +#### ⚙️ Options + + { + "selections": [ + "OperationDefinition" + ], + "groups": [ + "{", + "id", + "*", + "updatedAt" + ] + } + #### ❌ Error 1/3 3 | updatedAt @@ -1074,10 +1200,10 @@ exports[`alphabetize > invalid > should sort selection set 1`] = ` #### ❌ Error 2/3 - 6 | } - > 7 | aa - | ^^ field "aa" should be before field "createdAt" - 8 | user { + 7 | aa + > 8 | user { + | ^^^^ field "user" should be before field "aa" + 9 | id #### ❌ Error 3/3 @@ -1089,20 +1215,19 @@ exports[`alphabetize > invalid > should sort selection set 1`] = ` #### 🔧 Autofix output 1 | { - 2 | aa - 3 | aab { - 4 | id - 5 | } - 6 | user { - 7 | id - 8 | } - 9 | zz - 10 | createdAt { - 11 | __typename - 12 | } + 2 | aab { + 3 | id + 4 | } + 5 | createdAt { + 6 | __typename + 7 | } + 8 | user { + 9 | id + 10 | } + 11 | aa + 12 | zz 13 | updatedAt - 14 | updatedAt - 15 | } + 14 | } `; exports[`alphabetize > invalid > should sort selections by group when \`*\` is between 1`] = ` From 7ca2a448f39610c96939a37bf157770b0df13468 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 16 Nov 2024 10:05:24 +0700 Subject: [PATCH 4/8] upd --- packages/plugin/src/rules/alphabetize/index.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/plugin/src/rules/alphabetize/index.ts b/packages/plugin/src/rules/alphabetize/index.ts index 754a72c2d18..3a36c6f81a4 100644 --- a/packages/plugin/src/rules/alphabetize/index.ts +++ b/packages/plugin/src/rules/alphabetize/index.ts @@ -94,7 +94,13 @@ const schema = { ...ARRAY_DEFAULT_OPTIONS, minItems: 2, description: - "Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt', '...']` where `...` stands for fragment spreads, and `*` stands for everything else.", + [ + "Custom order group. Example: `['...', 'id', '*', '{']` where:", + "- `...` stands for fragment spreads", + "- `id` stands for field with name `id`", + "- `*` stands for everything else", + "- `{` stands for field `selection set`" + ].join('\n'), }, }, }, @@ -194,7 +200,7 @@ export const rule: GraphQLESLintRule = { fields: fieldsEnum, values: true, arguments: argumentsEnum, - groups: ['id', '*', 'createdAt', 'updatedAt'], + groups: ['id', '*', '{'], }, ], operations: [ @@ -203,7 +209,7 @@ export const rule: GraphQLESLintRule = { selections: selectionsEnum, variables: true, arguments: [Kind.FIELD, Kind.DIRECTIVE], - groups: ['...', 'id', '*', 'createdAt', 'updatedAt'], + groups: ['...', 'id', '*', '{'], }, ], }, From a4439c9e2888b738f8c36cf94eb170dae4d157d7 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 16 Nov 2024 10:08:18 +0700 Subject: [PATCH 5/8] upd --- packages/plugin/src/configs/operations-all.ts | 2 +- packages/plugin/src/rules/alphabetize/index.ts | 6 +++--- website/src/pages/rules/alphabetize.md | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/plugin/src/configs/operations-all.ts b/packages/plugin/src/configs/operations-all.ts index d132ea0daec..593e7d4d863 100644 --- a/packages/plugin/src/configs/operations-all.ts +++ b/packages/plugin/src/configs/operations-all.ts @@ -13,7 +13,7 @@ export = { selections: ['OperationDefinition', 'FragmentDefinition'], variables: true, arguments: ['Field', 'Directive'], - groups: ['...', 'id', '*', 'createdAt', 'updatedAt'], + groups: ['...', 'id', '*', '{'], }, ], '@graphql-eslint/lone-executable-definition': 'error', diff --git a/packages/plugin/src/rules/alphabetize/index.ts b/packages/plugin/src/rules/alphabetize/index.ts index 3a36c6f81a4..73595bbd221 100644 --- a/packages/plugin/src/rules/alphabetize/index.ts +++ b/packages/plugin/src/rules/alphabetize/index.ts @@ -95,11 +95,11 @@ const schema = { minItems: 2, description: [ - "Custom order group. Example: `['...', 'id', '*', '{']` where:", + "Order group. Example: `['...', 'id', '*', '{']` where:", "- `...` stands for fragment spreads", "- `id` stands for field with name `id`", "- `*` stands for everything else", - "- `{` stands for field `selection set`" + "- `{` stands for fields `selection set`" ].join('\n'), }, }, @@ -200,7 +200,7 @@ export const rule: GraphQLESLintRule = { fields: fieldsEnum, values: true, arguments: argumentsEnum, - groups: ['id', '*', '{'], + groups: ['id', '*', 'createdAt', 'updatedAt'], }, ], operations: [ diff --git a/website/src/pages/rules/alphabetize.md b/website/src/pages/rules/alphabetize.md index 7e39a5c4273..d54d0a60b66 100644 --- a/website/src/pages/rules/alphabetize.md +++ b/website/src/pages/rules/alphabetize.md @@ -165,8 +165,12 @@ Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `dir ### `groups` (array) -Custom order group. Example: `['id', '*', 'createdAt', 'updatedAt', '...']` where `...` stands for -fragment spreads, and `*` stands for everything else. +Custom order group. Example: `['...', 'id', '*', '{']` where: + +- `...` stands for fragment spreads +- `id` stands for field with name `id` +- `*` stands for everything else +- `{` stands for field `selection set` The object is an array with all elements of the type `string`. @@ -175,10 +179,6 @@ Additional restrictions: - Minimum items: `2` - Unique items: `true` -### `relationships_last` (boolean) - -Sort relationships last - ## Resources - [Rule source](https://github.com/B2o5T/graphql-eslint/tree/master/packages/plugin/src/rules/alphabetize.ts) From 6eda241a39d251d5bd40b5b9a4d21f6a5c936bde Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 16 Nov 2024 10:08:43 +0700 Subject: [PATCH 6/8] prettier --- packages/plugin/src/rules/alphabetize/index.ts | 15 +++++++-------- website/src/pages/rules/_meta.ts | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/plugin/src/rules/alphabetize/index.ts b/packages/plugin/src/rules/alphabetize/index.ts index 73595bbd221..7437c4d87cd 100644 --- a/packages/plugin/src/rules/alphabetize/index.ts +++ b/packages/plugin/src/rules/alphabetize/index.ts @@ -93,14 +93,13 @@ const schema = { groups: { ...ARRAY_DEFAULT_OPTIONS, minItems: 2, - description: - [ - "Order group. Example: `['...', 'id', '*', '{']` where:", - "- `...` stands for fragment spreads", - "- `id` stands for field with name `id`", - "- `*` stands for everything else", - "- `{` stands for fields `selection set`" - ].join('\n'), + description: [ + "Order group. Example: `['...', 'id', '*', '{']` where:", + '- `...` stands for fragment spreads', + '- `id` stands for field with name `id`', + '- `*` stands for everything else', + '- `{` stands for fields `selection set`', + ].join('\n'), }, }, }, diff --git a/website/src/pages/rules/_meta.ts b/website/src/pages/rules/_meta.ts index 32bd27eaddd..e61f8f57070 100644 --- a/website/src/pages/rules/_meta.ts +++ b/website/src/pages/rules/_meta.ts @@ -68,5 +68,5 @@ export default { 'unique-variable-names': '', 'value-literals-of-correct-type': '', 'variables-are-input-types': '', - 'variables-in-allowed-position': '' -} + 'variables-in-allowed-position': '', +}; From fc6dfb32e3e0e6d09eede5c4bc01ea1545765087 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 16 Nov 2024 10:10:45 +0700 Subject: [PATCH 7/8] Create empty-singers-develop.md --- .changeset/empty-singers-develop.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/empty-singers-develop.md diff --git a/.changeset/empty-singers-develop.md b/.changeset/empty-singers-develop.md new file mode 100644 index 00000000000..34b679e87dd --- /dev/null +++ b/.changeset/empty-singers-develop.md @@ -0,0 +1,5 @@ +--- +"@graphql-eslint/eslint-plugin": feat +--- + +feat: add a new option `{` for alphabetize rule to sort fields `selection set` From dfec4ae18f4b810903b0697f602ec35710a3c40f Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Sat, 16 Nov 2024 10:13:23 +0700 Subject: [PATCH 8/8] upd --- .../plugin/src/rules/alphabetize/snapshot.md | 64 ------------------- 1 file changed, 64 deletions(-) diff --git a/packages/plugin/src/rules/alphabetize/snapshot.md b/packages/plugin/src/rules/alphabetize/snapshot.md index dd0a29990e7..a912d4c5141 100644 --- a/packages/plugin/src/rules/alphabetize/snapshot.md +++ b/packages/plugin/src/rules/alphabetize/snapshot.md @@ -1031,70 +1031,6 @@ exports[`alphabetize > invalid > should sort definitions 1`] = ` 59 | # END `; -exports[`alphabetize > invalid > should sort selection set 1`] = ` -#### ⌨️ Code - - 1 | { - 2 | zz - 3 | updatedAt - 4 | createdAt { - 5 | __typename - 6 | } - 7 | aa - 8 | user { - 9 | id - 10 | } - 11 | aab { - 12 | id - 13 | } - 14 | } - -#### ⚙️ Options - - { - "selections": [ - "OperationDefinition" - ], - "groups": [ - "id", - "*", - "updatedAt", - "{" - ] - } - -#### ❌ Error 1/2 - - 6 | } - > 7 | aa - | ^^ field "aa" should be before field "createdAt" - 8 | user { - -#### ❌ Error 2/2 - - 10 | } - > 11 | aab { - | ^^^ field "aab" should be before field "user" - 12 | id - -#### 🔧 Autofix output - - 1 | { - 2 | aa - 3 | zz - 4 | updatedAt - 5 | aab { - 6 | id - 7 | } - 8 | createdAt { - 9 | __typename - 10 | } - 11 | user { - 12 | id - 13 | } - 14 | } -`; - exports[`alphabetize > invalid > should sort selection set at the end 1`] = ` #### ⌨️ Code