diff --git a/.changeset/lovely-emus-shake.md b/.changeset/lovely-emus-shake.md new file mode 100644 index 00000000000..5ef9f51ae96 --- /dev/null +++ b/.changeset/lovely-emus-shake.md @@ -0,0 +1,6 @@ +--- +'@graphql-eslint/eslint-plugin': major +--- + +Add new config option `ignoredFieldSelectors` to `no-unused-fields` rule to ignore all the relay +pagination fields for every connection exposed in schema for example diff --git a/packages/plugin/src/rules/no-unused-fields/index.test.ts b/packages/plugin/src/rules/no-unused-fields/index.test.ts index 59815616764..fd05baa7c81 100644 --- a/packages/plugin/src/rules/no-unused-fields/index.test.ts +++ b/packages/plugin/src/rules/no-unused-fields/index.test.ts @@ -50,6 +50,9 @@ const ruleTester = new RuleTester({ }, }); +const example = rule.meta.docs!.examples!.find(example => example.title.includes('ignoring')); +const [RELAY_SCHEMA, RELAY_QUERY] = example!.code.split('### 2️⃣ YOUR QUERY'); + ruleTester.run('no-unused-fields', rule, { valid: [ { @@ -95,6 +98,17 @@ ruleTester.run('no-unused-fields', rule, { }, }, }, + { + name: 'should do not report unused fields for Relay', + options: example!.usage, + code: RELAY_SCHEMA, + parserOptions: { + graphQLConfig: { + documents: RELAY_QUERY, + schema: RELAY_SCHEMA, + }, + }, + }, ], invalid: [ { diff --git a/packages/plugin/src/rules/no-unused-fields/index.ts b/packages/plugin/src/rules/no-unused-fields/index.ts index f2d0a7d895c..670c9d761b9 100644 --- a/packages/plugin/src/rules/no-unused-fields/index.ts +++ b/packages/plugin/src/rules/no-unused-fields/index.ts @@ -1,12 +1,109 @@ -import { GraphQLSchema, TypeInfo, visit, visitWithTypeInfo } from 'graphql'; +import { FieldDefinitionNode, GraphQLSchema, TypeInfo, visit, visitWithTypeInfo } from 'graphql'; import { GraphQLProjectConfig } from 'graphql-config'; +import { FromSchema } from 'json-schema-to-ts'; import { ModuleCache } from '../../cache.js'; import { SiblingOperations } from '../../siblings.js'; -import { GraphQLESLintRule } from '../../types.js'; +import { GraphQLESLintRule, GraphQLESTreeNode } from '../../types.js'; import { requireGraphQLSchemaFromContext, requireSiblingsOperations } from '../../utils.js'; const RULE_ID = 'no-unused-fields'; +const RELAY_SCHEMA = /* GraphQL */ ` + # Root Query Type + type Query { + user: User + } + + # User Type + type User { + id: ID! + name: String! + friends(first: Int, after: String): FriendConnection! + } + + # FriendConnection Type (Relay Connection) + type FriendConnection { + edges: [FriendEdge] + pageInfo: PageInfo! + } + + # FriendEdge Type + type FriendEdge { + cursor: String! + node: Friend! + } + + # Friend Type + type Friend { + id: ID! + name: String! + } + + # PageInfo Type (Relay Pagination) + type PageInfo { + hasPreviousPage: Boolean! + hasNextPage: Boolean! + startCursor: String + endCursor: String + } +`; + +const RELAY_QUERY = /* GraphQL */ ` + query { + user { + id + name + friends(first: 10) { + edges { + node { + id + name + } + } + } + } + } +`; + +const RELAY_DEFAULT_IGNORED_FIELD_SELECTORS = [ + '[parent.name.value=PageInfo][name.value=/(endCursor|startCursor|hasNextPage|hasPreviousPage)/]', + '[parent.name.value=/Edge$/][name.value=cursor]', + '[parent.name.value=/Connection$/][name.value=pageInfo]', +]; + +const schema = { + type: 'array', + maxItems: 1, + items: { + type: 'object', + additionalProperties: false, + properties: { + ignoredFieldSelectors: { + type: 'array', + uniqueItems: true, + minItems: 1, + description: [ + 'Fields that will be ignored and are allowed to be unused.', + '', + 'E.g. The following selector will ignore all the relay pagination fields for every connection exposed in the schema:', + '```json', + JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2), + '```', + '', + '> These fields are defined by ESLint [`selectors`](https://eslint.org/docs/developer-guide/selectors).', + '> Paste or drop code into the editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your selector.', + ].join('\n'), + items: { + type: 'string', + pattern: '^\\[(.+)]$', + }, + }, + }, + }, +} as const; + +export type RuleOptions = FromSchema; + type UsedFields = Record>; const usedFieldsCache = new ModuleCache(); @@ -44,7 +141,7 @@ function getUsedFields(schema: GraphQLSchema, operations: SiblingOperations): Us return usedFields; } -export const rule: GraphQLESLintRule = { +export const rule: GraphQLESLintRule = { meta: { messages: { [RULE_ID]: 'Field "{{fieldName}}" is unused', @@ -99,23 +196,37 @@ export const rule: GraphQLESLintRule = { } `, }, + { + title: 'Correct (ignoring fields)', + usage: [{ ignoredFieldSelectors: RELAY_DEFAULT_IGNORED_FIELD_SELECTORS }], + code: /* GraphQL */ ` + ### 1️⃣ YOUR SCHEMA + ${RELAY_SCHEMA} + + ### 2️⃣ YOUR QUERY + ${RELAY_QUERY} + `, + }, ], }, type: 'suggestion', - schema: [], + schema, hasSuggestions: true, }, create(context) { const schema = requireGraphQLSchemaFromContext(RULE_ID, context); const siblingsOperations = requireSiblingsOperations(RULE_ID, context); const usedFields = getUsedFields(schema, siblingsOperations); - + const { ignoredFieldSelectors } = context.options[0] || {}; + const selector = (ignoredFieldSelectors || []).reduce( + (acc, selector) => `${acc}:not(${selector})`, + 'FieldDefinition', + ); return { - FieldDefinition(node) { + [selector](node: GraphQLESTreeNode) { const fieldName = node.name.value; const parentTypeName = node.parent.name.value; const isUsed = usedFields[parentTypeName]?.has(fieldName); - if (isUsed) { return; } diff --git a/scripts/generate-docs.ts b/scripts/generate-docs.ts index af243cbb893..2e20745b3a3 100644 --- a/scripts/generate-docs.ts +++ b/scripts/generate-docs.ts @@ -55,9 +55,12 @@ async function generateDocs(): Promise { const prettierConfigTs = await prettier.resolveConfig('./_meta.ts'); const result = Object.entries(rules).map(async ([ruleName, rule]) => { + const frontMatterDescription = rule.meta + .docs!.description!.replace(/\n.*/g, '') + .replace(MARKDOWN_LINK_RE, '$1'); const blocks: string[] = [ '---', - `description: ${JSON.stringify(rule.meta.docs!.description!.replace(/\n.*/g, '').replace(MARKDOWN_LINK_RE, '$1'))}`, + `description: ${JSON.stringify(frontMatterDescription)}`, '---', `# \`${ruleName}\``, ]; @@ -98,7 +101,7 @@ async function generateDocs(): Promise { `- Requires GraphQL Schema: \`${requiresSchema}\` [ℹ️](/docs/getting-started#extended-linting-rules-with-graphql-schema)`, `- Requires GraphQL Operations: \`${requiresSiblings}\` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations)`, BR, - docs.description, + docs.description === frontMatterDescription ? '{frontMatter.description}' : docs.description, ); if (docs.examples?.length > 0) { @@ -153,7 +156,7 @@ async function generateDocs(): Promise { ); } return { - path: resolve(RULES_PATH, `${ruleName}.md`), + path: resolve(RULES_PATH, `${ruleName}.mdx`), content: blocks.join('\n'), }; }); diff --git a/website/src/pages/rules/alphabetize.md b/website/src/pages/rules/alphabetize.mdx similarity index 94% rename from website/src/pages/rules/alphabetize.md rename to website/src/pages/rules/alphabetize.mdx index d54d0a60b66..b39e3446c8e 100644 --- a/website/src/pages/rules/alphabetize.md +++ b/website/src/pages/rules/alphabetize.mdx @@ -17,8 +17,7 @@ fix some of the problems reported by this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation -selections and more. +{frontMatter.description} ## Usage Examples @@ -165,12 +164,12 @@ Definitions – `type`, `interface`, `enum`, `scalar`, `input`, `union` and `dir ### `groups` (array) -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` The object is an array with all elements of the type `string`. diff --git a/website/src/pages/rules/description-style.md b/website/src/pages/rules/description-style.mdx similarity index 95% rename from website/src/pages/rules/description-style.md rename to website/src/pages/rules/description-style.mdx index 48773901253..eec430ea7e2 100644 --- a/website/src/pages/rules/description-style.md +++ b/website/src/pages/rules/description-style.mdx @@ -17,7 +17,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require all comments to follow the same style (either block or inline). +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/executable-definitions.md b/website/src/pages/rules/executable-definitions.mdx similarity index 100% rename from website/src/pages/rules/executable-definitions.md rename to website/src/pages/rules/executable-definitions.mdx diff --git a/website/src/pages/rules/fields-on-correct-type.md b/website/src/pages/rules/fields-on-correct-type.mdx similarity index 100% rename from website/src/pages/rules/fields-on-correct-type.md rename to website/src/pages/rules/fields-on-correct-type.mdx diff --git a/website/src/pages/rules/fragments-on-composite-type.md b/website/src/pages/rules/fragments-on-composite-type.mdx similarity index 100% rename from website/src/pages/rules/fragments-on-composite-type.md rename to website/src/pages/rules/fragments-on-composite-type.mdx diff --git a/website/src/pages/rules/input-name.md b/website/src/pages/rules/input-name.mdx similarity index 100% rename from website/src/pages/rules/input-name.md rename to website/src/pages/rules/input-name.mdx diff --git a/website/src/pages/rules/known-argument-names.md b/website/src/pages/rules/known-argument-names.mdx similarity index 100% rename from website/src/pages/rules/known-argument-names.md rename to website/src/pages/rules/known-argument-names.mdx diff --git a/website/src/pages/rules/known-directives.md b/website/src/pages/rules/known-directives.mdx similarity index 100% rename from website/src/pages/rules/known-directives.md rename to website/src/pages/rules/known-directives.mdx diff --git a/website/src/pages/rules/known-fragment-names.md b/website/src/pages/rules/known-fragment-names.mdx similarity index 100% rename from website/src/pages/rules/known-fragment-names.md rename to website/src/pages/rules/known-fragment-names.mdx diff --git a/website/src/pages/rules/known-type-names.md b/website/src/pages/rules/known-type-names.mdx similarity index 100% rename from website/src/pages/rules/known-type-names.md rename to website/src/pages/rules/known-type-names.mdx diff --git a/website/src/pages/rules/lone-anonymous-operation.md b/website/src/pages/rules/lone-anonymous-operation.mdx similarity index 100% rename from website/src/pages/rules/lone-anonymous-operation.md rename to website/src/pages/rules/lone-anonymous-operation.mdx diff --git a/website/src/pages/rules/lone-executable-definition.md b/website/src/pages/rules/lone-executable-definition.mdx similarity index 93% rename from website/src/pages/rules/lone-executable-definition.md rename to website/src/pages/rules/lone-executable-definition.mdx index 9adc43efb7f..611e473646d 100644 --- a/website/src/pages/rules/lone-executable-definition.md +++ b/website/src/pages/rules/lone-executable-definition.mdx @@ -12,7 +12,7 @@ description: - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require queries, mutations, subscriptions or fragments to be located in separate files. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/lone-schema-definition.md b/website/src/pages/rules/lone-schema-definition.mdx similarity index 100% rename from website/src/pages/rules/lone-schema-definition.md rename to website/src/pages/rules/lone-schema-definition.mdx diff --git a/website/src/pages/rules/match-document-filename.md b/website/src/pages/rules/match-document-filename.mdx similarity index 97% rename from website/src/pages/rules/match-document-filename.md rename to website/src/pages/rules/match-document-filename.mdx index 8bbc44c4200..e47ace42f07 100644 --- a/website/src/pages/rules/match-document-filename.md +++ b/website/src/pages/rules/match-document-filename.mdx @@ -11,7 +11,7 @@ description: 'This rule allows you to enforce that the file name should match th - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -This rule allows you to enforce that the file name should match the operation name. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/naming-convention.md b/website/src/pages/rules/naming-convention.mdx similarity index 99% rename from website/src/pages/rules/naming-convention.md rename to website/src/pages/rules/naming-convention.mdx index 5f3e27c11d7..15b800b545b 100644 --- a/website/src/pages/rules/naming-convention.md +++ b/website/src/pages/rules/naming-convention.mdx @@ -18,7 +18,7 @@ rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require names to follow specified conventions. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-anonymous-operations.md b/website/src/pages/rules/no-anonymous-operations.mdx similarity index 89% rename from website/src/pages/rules/no-anonymous-operations.md rename to website/src/pages/rules/no-anonymous-operations.mdx index f0484b64204..f8b590417d4 100644 --- a/website/src/pages/rules/no-anonymous-operations.md +++ b/website/src/pages/rules/no-anonymous-operations.mdx @@ -19,8 +19,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require name for your GraphQL operations. This is useful since most GraphQL client libraries are -using the operation name for caching purposes. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-deprecated.md b/website/src/pages/rules/no-deprecated.mdx similarity index 96% rename from website/src/pages/rules/no-deprecated.md rename to website/src/pages/rules/no-deprecated.mdx index ff87b91e008..054cc4ac32f 100644 --- a/website/src/pages/rules/no-deprecated.md +++ b/website/src/pages/rules/no-deprecated.mdx @@ -17,7 +17,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforce that deprecated fields or enum values are not in use by operations. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-duplicate-fields.md b/website/src/pages/rules/no-duplicate-fields.mdx similarity index 93% rename from website/src/pages/rules/no-duplicate-fields.md rename to website/src/pages/rules/no-duplicate-fields.mdx index af74cccf68e..12ad6fa1449 100644 --- a/website/src/pages/rules/no-duplicate-fields.md +++ b/website/src/pages/rules/no-duplicate-fields.mdx @@ -19,8 +19,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Checks for duplicate fields in selection set, variables in operation definition, or in arguments set -of a field. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-fragment-cycles.md b/website/src/pages/rules/no-fragment-cycles.mdx similarity index 100% rename from website/src/pages/rules/no-fragment-cycles.md rename to website/src/pages/rules/no-fragment-cycles.mdx diff --git a/website/src/pages/rules/no-hashtag-description.md b/website/src/pages/rules/no-hashtag-description.mdx similarity index 100% rename from website/src/pages/rules/no-hashtag-description.md rename to website/src/pages/rules/no-hashtag-description.mdx diff --git a/website/src/pages/rules/no-one-place-fragments.md b/website/src/pages/rules/no-one-place-fragments.mdx similarity index 95% rename from website/src/pages/rules/no-one-place-fragments.md rename to website/src/pages/rules/no-one-place-fragments.mdx index 0c167b4d83a..c6b400cabbc 100644 --- a/website/src/pages/rules/no-one-place-fragments.md +++ b/website/src/pages/rules/no-one-place-fragments.mdx @@ -11,7 +11,7 @@ description: 'Disallow fragments that are used only in one place.' - Requires GraphQL Operations: `true` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Disallow fragments that are used only in one place. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-root-type.md b/website/src/pages/rules/no-root-type.mdx similarity index 95% rename from website/src/pages/rules/no-root-type.md rename to website/src/pages/rules/no-root-type.mdx index 5b1f1995cea..f360576d8f2 100644 --- a/website/src/pages/rules/no-root-type.md +++ b/website/src/pages/rules/no-root-type.mdx @@ -14,7 +14,7 @@ description: 'Disallow using root types `mutation` and/or `subscription`.' - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Disallow using root types `mutation` and/or `subscription`. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-scalar-result-type-on-mutation.md b/website/src/pages/rules/no-scalar-result-type-on-mutation.mdx similarity index 93% rename from website/src/pages/rules/no-scalar-result-type-on-mutation.md rename to website/src/pages/rules/no-scalar-result-type-on-mutation.mdx index 2180185ac88..702bdadf3aa 100644 --- a/website/src/pages/rules/no-scalar-result-type-on-mutation.md +++ b/website/src/pages/rules/no-scalar-result-type-on-mutation.mdx @@ -14,7 +14,7 @@ description: 'Avoid scalar result type on mutation type to make sure to return a - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Avoid scalar result type on mutation type to make sure to return a valid state. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-typename-prefix.md b/website/src/pages/rules/no-typename-prefix.mdx similarity index 93% rename from website/src/pages/rules/no-typename-prefix.md rename to website/src/pages/rules/no-typename-prefix.mdx index 379dc3e707e..c39208ca460 100644 --- a/website/src/pages/rules/no-typename-prefix.md +++ b/website/src/pages/rules/no-typename-prefix.mdx @@ -18,7 +18,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforces users to avoid using the type name in a field name while defining your schema. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-undefined-variables.md b/website/src/pages/rules/no-undefined-variables.mdx similarity index 100% rename from website/src/pages/rules/no-undefined-variables.md rename to website/src/pages/rules/no-undefined-variables.mdx diff --git a/website/src/pages/rules/no-unreachable-types.md b/website/src/pages/rules/no-unreachable-types.mdx similarity index 94% rename from website/src/pages/rules/no-unreachable-types.md rename to website/src/pages/rules/no-unreachable-types.mdx index 8921fde6b0b..7a453455cd1 100644 --- a/website/src/pages/rules/no-unreachable-types.md +++ b/website/src/pages/rules/no-unreachable-types.mdx @@ -17,7 +17,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Requires all types to be reachable at some level by root level fields. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/no-unused-fields.md b/website/src/pages/rules/no-unused-fields.md deleted file mode 100644 index 2bc33a3acea..00000000000 --- a/website/src/pages/rules/no-unused-fields.md +++ /dev/null @@ -1,69 +0,0 @@ ---- -description: 'Requires all fields to be used at some level by siblings operations.' ---- - -# `no-unused-fields` - -💡 This rule provides -[suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions) - -- Category: `Schema` -- Rule name: `@graphql-eslint/no-unused-fields` -- Requires GraphQL Schema: `true` - [ℹ️](/docs/getting-started#extended-linting-rules-with-graphql-schema) -- Requires GraphQL Operations: `true` - [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) - -Requires all fields to be used at some level by siblings operations. - -## Usage Examples - -### Incorrect - -```graphql -# eslint @graphql-eslint/no-unused-fields: 'error' - -type User { - id: ID! - name: String - someUnusedField: String -} - -type Query { - me: User -} - -query { - me { - id - name - } -} -``` - -### Correct - -```graphql -# eslint @graphql-eslint/no-unused-fields: 'error' - -type User { - id: ID! - name: String -} - -type Query { - me: User -} - -query { - me { - id - name - } -} -``` - -## Resources - -- [Rule source](https://github.com/B2o5T/graphql-eslint/tree/master/packages/plugin/src/rules/no-unused-fields.ts) -- [Test source](https://github.com/B2o5T/graphql-eslint/tree/master/packages/plugin/__tests__/no-unused-fields.spec.ts) diff --git a/website/src/pages/rules/no-unused-fields.mdx b/website/src/pages/rules/no-unused-fields.mdx new file mode 100644 index 00000000000..9c114492d3d --- /dev/null +++ b/website/src/pages/rules/no-unused-fields.mdx @@ -0,0 +1,163 @@ +--- +description: 'Requires all fields to be used at some level by siblings operations.' +--- + +# `no-unused-fields` + +💡 This rule provides +[suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions) + +- Category: `Schema` +- Rule name: `@graphql-eslint/no-unused-fields` +- Requires GraphQL Schema: `true` + [ℹ️](/docs/getting-started#extended-linting-rules-with-graphql-schema) +- Requires GraphQL Operations: `true` + [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) + +{frontMatter.description} + +## Usage Examples + +### Incorrect + +```graphql +# eslint @graphql-eslint/no-unused-fields: 'error' + +type User { + id: ID! + name: String + someUnusedField: String +} + +type Query { + me: User +} + +query { + me { + id + name + } +} +``` + +### Correct + +```graphql +# eslint @graphql-eslint/no-unused-fields: 'error' + +type User { + id: ID! + name: String +} + +type Query { + me: User +} + +query { + me { + id + name + } +} +``` + +### Correct (ignoring fields) + +```graphql +# eslint @graphql-eslint/no-unused-fields: ['error', { ignoredFieldSelectors: ['[parent.name.value=PageInfo][name.value=/(endCursor|startCursor|hasNextPage|hasPreviousPage)/]', '[parent.name.value=/Edge$/][name.value=cursor]', '[parent.name.value=/Connection$/][name.value=pageInfo]'] }] + +### 1️⃣ YOUR SCHEMA + +# Root Query Type +type Query { + user: User +} + +# User Type +type User { + id: ID! + name: String! + friends(first: Int, after: String): FriendConnection! +} + +# FriendConnection Type (Relay Connection) +type FriendConnection { + edges: [FriendEdge] + pageInfo: PageInfo! +} + +# FriendEdge Type +type FriendEdge { + cursor: String! + node: Friend! +} + +# Friend Type +type Friend { + id: ID! + name: String! +} + +# PageInfo Type (Relay Pagination) +type PageInfo { + hasPreviousPage: Boolean! + hasNextPage: Boolean! + startCursor: String + endCursor: String +} + +### 2️⃣ YOUR QUERY + +query { + user { + id + name + friends(first: 10) { + edges { + node { + id + name + } + } + } + } +} +``` + +## Config Schema + +The schema defines the following properties: + +### `ignoredFieldSelectors` (array) + +Fields that will be ignored and are allowed to be unused. + +E.g. The following selector will ignore all the relay pagination fields for every connection exposed +in the schema: + +```json +[ + "[parent.name.value=PageInfo][name.value=/(endCursor|startCursor|hasNextPage|hasPreviousPage)/]", + "[parent.name.value=/Edge$/][name.value=cursor]", + "[parent.name.value=/Connection$/][name.value=pageInfo]" +] +``` + +> These fields are defined by ESLint +> [`selectors`](https://eslint.org/docs/developer-guide/selectors). Paste or drop code into the +> editor in [ASTExplorer](https://astexplorer.net) and inspect the generated AST to compose your +> selector. + +The object is an array with all elements of the type `string`. + +Additional restrictions: + +- Minimum items: `1` +- Unique items: `true` + +## Resources + +- [Rule source](https://github.com/B2o5T/graphql-eslint/tree/master/packages/plugin/src/rules/no-unused-fields.ts) +- [Test source](https://github.com/B2o5T/graphql-eslint/tree/master/packages/plugin/__tests__/no-unused-fields.spec.ts) diff --git a/website/src/pages/rules/no-unused-fragments.md b/website/src/pages/rules/no-unused-fragments.mdx similarity index 100% rename from website/src/pages/rules/no-unused-fragments.md rename to website/src/pages/rules/no-unused-fragments.mdx diff --git a/website/src/pages/rules/no-unused-variables.md b/website/src/pages/rules/no-unused-variables.mdx similarity index 100% rename from website/src/pages/rules/no-unused-variables.md rename to website/src/pages/rules/no-unused-variables.mdx diff --git a/website/src/pages/rules/one-field-subscriptions.md b/website/src/pages/rules/one-field-subscriptions.mdx similarity index 100% rename from website/src/pages/rules/one-field-subscriptions.md rename to website/src/pages/rules/one-field-subscriptions.mdx diff --git a/website/src/pages/rules/overlapping-fields-can-be-merged.md b/website/src/pages/rules/overlapping-fields-can-be-merged.mdx similarity index 100% rename from website/src/pages/rules/overlapping-fields-can-be-merged.md rename to website/src/pages/rules/overlapping-fields-can-be-merged.mdx diff --git a/website/src/pages/rules/possible-fragment-spread.md b/website/src/pages/rules/possible-fragment-spread.mdx similarity index 100% rename from website/src/pages/rules/possible-fragment-spread.md rename to website/src/pages/rules/possible-fragment-spread.mdx diff --git a/website/src/pages/rules/possible-type-extension.md b/website/src/pages/rules/possible-type-extension.mdx similarity index 100% rename from website/src/pages/rules/possible-type-extension.md rename to website/src/pages/rules/possible-type-extension.mdx diff --git a/website/src/pages/rules/provided-required-arguments.md b/website/src/pages/rules/provided-required-arguments.mdx similarity index 100% rename from website/src/pages/rules/provided-required-arguments.md rename to website/src/pages/rules/provided-required-arguments.mdx diff --git a/website/src/pages/rules/relay-arguments.md b/website/src/pages/rules/relay-arguments.mdx similarity index 100% rename from website/src/pages/rules/relay-arguments.md rename to website/src/pages/rules/relay-arguments.mdx diff --git a/website/src/pages/rules/relay-connection-types.md b/website/src/pages/rules/relay-connection-types.mdx similarity index 100% rename from website/src/pages/rules/relay-connection-types.md rename to website/src/pages/rules/relay-connection-types.mdx diff --git a/website/src/pages/rules/relay-edge-types.md b/website/src/pages/rules/relay-edge-types.mdx similarity index 100% rename from website/src/pages/rules/relay-edge-types.md rename to website/src/pages/rules/relay-edge-types.mdx diff --git a/website/src/pages/rules/relay-page-info.md b/website/src/pages/rules/relay-page-info.mdx similarity index 100% rename from website/src/pages/rules/relay-page-info.md rename to website/src/pages/rules/relay-page-info.mdx diff --git a/website/src/pages/rules/require-deprecation-date.md b/website/src/pages/rules/require-deprecation-date.mdx similarity index 93% rename from website/src/pages/rules/require-deprecation-date.md rename to website/src/pages/rules/require-deprecation-date.mdx index 6bf60d96517..9052d8c0755 100644 --- a/website/src/pages/rules/require-deprecation-date.md +++ b/website/src/pages/rules/require-deprecation-date.mdx @@ -16,8 +16,7 @@ description: - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require deletion date on `@deprecated` directive. Suggest removing deprecated things after -deprecated date. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/require-deprecation-reason.md b/website/src/pages/rules/require-deprecation-reason.mdx similarity index 95% rename from website/src/pages/rules/require-deprecation-reason.md rename to website/src/pages/rules/require-deprecation-reason.mdx index b7a96b42de4..5ff0ab85116 100644 --- a/website/src/pages/rules/require-deprecation-reason.md +++ b/website/src/pages/rules/require-deprecation-reason.mdx @@ -14,7 +14,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require all deprecation directives to specify a reason. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/require-description.md b/website/src/pages/rules/require-description.mdx similarity index 98% rename from website/src/pages/rules/require-description.md rename to website/src/pages/rules/require-description.mdx index d90cbaafe88..281a33a55d4 100644 --- a/website/src/pages/rules/require-description.md +++ b/website/src/pages/rules/require-description.mdx @@ -14,7 +14,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforce descriptions in type definitions and operations. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/require-field-of-type-query-in-mutation-result.md b/website/src/pages/rules/require-field-of-type-query-in-mutation-result.mdx similarity index 100% rename from website/src/pages/rules/require-field-of-type-query-in-mutation-result.md rename to website/src/pages/rules/require-field-of-type-query-in-mutation-result.mdx diff --git a/website/src/pages/rules/require-import-fragment.md b/website/src/pages/rules/require-import-fragment.mdx similarity index 96% rename from website/src/pages/rules/require-import-fragment.md rename to website/src/pages/rules/require-import-fragment.mdx index 568ff5c7d75..b4a432e6699 100644 --- a/website/src/pages/rules/require-import-fragment.md +++ b/website/src/pages/rules/require-import-fragment.mdx @@ -14,7 +14,7 @@ description: 'Require fragments to be imported via an import expression.' - Requires GraphQL Operations: `true` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require fragments to be imported via an import expression. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/require-nullable-fields-with-oneof.md b/website/src/pages/rules/require-nullable-fields-with-oneof.mdx similarity index 93% rename from website/src/pages/rules/require-nullable-fields-with-oneof.md rename to website/src/pages/rules/require-nullable-fields-with-oneof.mdx index d2351fc61a2..a112f05d2d8 100644 --- a/website/src/pages/rules/require-nullable-fields-with-oneof.md +++ b/website/src/pages/rules/require-nullable-fields-with-oneof.mdx @@ -11,7 +11,7 @@ description: 'Require `input` or `type` fields to be non-nullable with `@oneOf` - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require `input` or `type` fields to be non-nullable with `@oneOf` directive. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/require-nullable-result-in-root.md b/website/src/pages/rules/require-nullable-result-in-root.mdx similarity index 96% rename from website/src/pages/rules/require-nullable-result-in-root.md rename to website/src/pages/rules/require-nullable-result-in-root.mdx index 1a75de64bf3..5ff8d399d9c 100644 --- a/website/src/pages/rules/require-nullable-result-in-root.md +++ b/website/src/pages/rules/require-nullable-result-in-root.mdx @@ -14,7 +14,7 @@ description: 'Require nullable fields in root types.' - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Require nullable fields in root types. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/require-selections.md b/website/src/pages/rules/require-selections.mdx similarity index 95% rename from website/src/pages/rules/require-selections.md rename to website/src/pages/rules/require-selections.mdx index 7c1624e19d4..67c32a7f88a 100644 --- a/website/src/pages/rules/require-selections.md +++ b/website/src/pages/rules/require-selections.mdx @@ -17,7 +17,7 @@ enables this rule. - Requires GraphQL Operations: `true` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforce selecting specific fields when they are available on the GraphQL type. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/require-type-pattern-with-oneof.md b/website/src/pages/rules/require-type-pattern-with-oneof.mdx similarity index 93% rename from website/src/pages/rules/require-type-pattern-with-oneof.md rename to website/src/pages/rules/require-type-pattern-with-oneof.mdx index bf6ee7a31a6..480f1252b2a 100644 --- a/website/src/pages/rules/require-type-pattern-with-oneof.md +++ b/website/src/pages/rules/require-type-pattern-with-oneof.mdx @@ -11,7 +11,7 @@ description: 'Enforce types with `@oneOf` directive have `error` and `ok` fields - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforce types with `@oneOf` directive have `error` and `ok` fields. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/scalar-leafs.md b/website/src/pages/rules/scalar-leafs.mdx similarity index 100% rename from website/src/pages/rules/scalar-leafs.md rename to website/src/pages/rules/scalar-leafs.mdx diff --git a/website/src/pages/rules/selection-set-depth.md b/website/src/pages/rules/selection-set-depth.mdx similarity index 100% rename from website/src/pages/rules/selection-set-depth.md rename to website/src/pages/rules/selection-set-depth.mdx diff --git a/website/src/pages/rules/strict-id-in-types.md b/website/src/pages/rules/strict-id-in-types.mdx similarity index 94% rename from website/src/pages/rules/strict-id-in-types.md rename to website/src/pages/rules/strict-id-in-types.mdx index f9fa64a5e47..c98ad29a416 100644 --- a/website/src/pages/rules/strict-id-in-types.md +++ b/website/src/pages/rules/strict-id-in-types.mdx @@ -16,8 +16,7 @@ enables this rule. - Requires GraphQL Operations: `false` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Requires output types to have one unique identifier unless they do not have a logical one. -Exceptions can be used to ignore output types that do not have unique identifiers. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/unique-argument-names.md b/website/src/pages/rules/unique-argument-names.mdx similarity index 100% rename from website/src/pages/rules/unique-argument-names.md rename to website/src/pages/rules/unique-argument-names.mdx diff --git a/website/src/pages/rules/unique-directive-names-per-location.md b/website/src/pages/rules/unique-directive-names-per-location.mdx similarity index 100% rename from website/src/pages/rules/unique-directive-names-per-location.md rename to website/src/pages/rules/unique-directive-names-per-location.mdx diff --git a/website/src/pages/rules/unique-directive-names.md b/website/src/pages/rules/unique-directive-names.mdx similarity index 100% rename from website/src/pages/rules/unique-directive-names.md rename to website/src/pages/rules/unique-directive-names.mdx diff --git a/website/src/pages/rules/unique-enum-value-names.md b/website/src/pages/rules/unique-enum-value-names.mdx similarity index 100% rename from website/src/pages/rules/unique-enum-value-names.md rename to website/src/pages/rules/unique-enum-value-names.mdx diff --git a/website/src/pages/rules/unique-field-definition-names.md b/website/src/pages/rules/unique-field-definition-names.mdx similarity index 100% rename from website/src/pages/rules/unique-field-definition-names.md rename to website/src/pages/rules/unique-field-definition-names.mdx diff --git a/website/src/pages/rules/unique-fragment-name.md b/website/src/pages/rules/unique-fragment-name.mdx similarity index 96% rename from website/src/pages/rules/unique-fragment-name.md rename to website/src/pages/rules/unique-fragment-name.mdx index 0a619093df6..738cafb9afb 100644 --- a/website/src/pages/rules/unique-fragment-name.md +++ b/website/src/pages/rules/unique-fragment-name.mdx @@ -14,7 +14,7 @@ enables this rule. - Requires GraphQL Operations: `true` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforce unique fragment names across your project. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/unique-input-field-names.md b/website/src/pages/rules/unique-input-field-names.mdx similarity index 100% rename from website/src/pages/rules/unique-input-field-names.md rename to website/src/pages/rules/unique-input-field-names.mdx diff --git a/website/src/pages/rules/unique-operation-name.md b/website/src/pages/rules/unique-operation-name.mdx similarity index 95% rename from website/src/pages/rules/unique-operation-name.md rename to website/src/pages/rules/unique-operation-name.mdx index 074f9e8fe3c..794f016330c 100644 --- a/website/src/pages/rules/unique-operation-name.md +++ b/website/src/pages/rules/unique-operation-name.mdx @@ -14,7 +14,7 @@ enables this rule. - Requires GraphQL Operations: `true` [ℹ️](/docs/getting-started#extended-linting-rules-with-siblings-operations) -Enforce unique operation names across your project. +{frontMatter.description} ## Usage Examples diff --git a/website/src/pages/rules/unique-operation-types.md b/website/src/pages/rules/unique-operation-types.mdx similarity index 100% rename from website/src/pages/rules/unique-operation-types.md rename to website/src/pages/rules/unique-operation-types.mdx diff --git a/website/src/pages/rules/unique-type-names.md b/website/src/pages/rules/unique-type-names.mdx similarity index 100% rename from website/src/pages/rules/unique-type-names.md rename to website/src/pages/rules/unique-type-names.mdx diff --git a/website/src/pages/rules/unique-variable-names.md b/website/src/pages/rules/unique-variable-names.mdx similarity index 100% rename from website/src/pages/rules/unique-variable-names.md rename to website/src/pages/rules/unique-variable-names.mdx diff --git a/website/src/pages/rules/value-literals-of-correct-type.md b/website/src/pages/rules/value-literals-of-correct-type.mdx similarity index 100% rename from website/src/pages/rules/value-literals-of-correct-type.md rename to website/src/pages/rules/value-literals-of-correct-type.mdx diff --git a/website/src/pages/rules/variables-are-input-types.md b/website/src/pages/rules/variables-are-input-types.mdx similarity index 100% rename from website/src/pages/rules/variables-are-input-types.md rename to website/src/pages/rules/variables-are-input-types.mdx diff --git a/website/src/pages/rules/variables-in-allowed-position.md b/website/src/pages/rules/variables-in-allowed-position.mdx similarity index 100% rename from website/src/pages/rules/variables-in-allowed-position.md rename to website/src/pages/rules/variables-in-allowed-position.mdx