diff --git a/.changeset/happy-bottles-warn.md b/.changeset/happy-bottles-warn.md index e1f077b8bd8..49f4ad67890 100644 --- a/.changeset/happy-bottles-warn.md +++ b/.changeset/happy-bottles-warn.md @@ -2,5 +2,5 @@ '@graphql-eslint/eslint-plugin': minor --- -introduce `forbiddenPattern` and `requiredPattern` options for `naming-convention` rule and +introduce `forbiddenPatterns` and `requiredPatterns` options for `naming-convention` rule and deprecate `forbiddenPrefixes`, `forbiddenSuffixes` and `requiredPrefixes` and `requiredSuffixes` diff --git a/.changeset/long-chicken-press.md b/.changeset/long-chicken-press.md new file mode 100644 index 00000000000..cb7832d5916 --- /dev/null +++ b/.changeset/long-chicken-press.md @@ -0,0 +1,6 @@ +--- +'@graphql-eslint/eslint-plugin': minor +--- + +add new option `ignoredSelectors` for `require-description` rule, to ignore eslint selectors, e.g. +types which ends with `Connection` or `Edge` diff --git a/packages/plugin/src/rules/naming-convention/index.test.ts b/packages/plugin/src/rules/naming-convention/index.test.ts index a605d20dac9..9622374a441 100644 --- a/packages/plugin/src/rules/naming-convention/index.test.ts +++ b/packages/plugin/src/rules/naming-convention/index.test.ts @@ -527,19 +527,19 @@ ruleTester.run('naming-convention', rule, { errors: 2, }, { - name: 'forbiddenPattern', + name: 'forbiddenPatterns', code: 'query queryFoo { foo } query getBar { bar }', - options: [{ OperationDefinition: { forbiddenPattern: [/^(get|query)/] } }], + options: [{ OperationDefinition: { forbiddenPatterns: [/^(get|query)/] } }], errors: 2, }, { - name: 'requiredPattern', + name: 'requiredPatterns', code: 'type Test { enabled: Boolean! }', options: [ { 'FieldDefinition[gqlType.gqlType.name.value=Boolean]': { style: 'camelCase', - requiredPattern: [/^(is|has)/], + requiredPatterns: [/^(is|has)/], }, }, ], diff --git a/packages/plugin/src/rules/naming-convention/index.ts b/packages/plugin/src/rules/naming-convention/index.ts index 5d2068d3f2f..bf0514a32b3 100644 --- a/packages/plugin/src/rules/naming-convention/index.ts +++ b/packages/plugin/src/rules/naming-convention/index.ts @@ -48,7 +48,7 @@ const schemaOption = { oneOf: [{ $ref: '#/definitions/asString' }, { $ref: '#/definitions/asObject' }], } as const; -const descriptionPrefixesSuffixes = (name: 'forbiddenPattern' | 'requiredPattern') => +const descriptionPrefixesSuffixes = (name: 'forbiddenPatterns' | 'requiredPatterns') => `> [!WARNING] > > This option is deprecated and will be removed in the next major release. Use [\`${name}\`](#${name.toLowerCase()}-array) instead.`; @@ -66,14 +66,14 @@ const schema = { style: { enum: ALLOWED_STYLES }, prefix: { type: 'string' }, suffix: { type: 'string' }, - forbiddenPattern: { + forbiddenPatterns: { ...ARRAY_DEFAULT_OPTIONS, items: { type: 'object', }, description: 'Should be of instance of `RegEx`', }, - requiredPattern: { + requiredPatterns: { ...ARRAY_DEFAULT_OPTIONS, items: { type: 'object', @@ -82,19 +82,19 @@ const schema = { }, forbiddenPrefixes: { ...ARRAY_DEFAULT_OPTIONS, - description: descriptionPrefixesSuffixes('forbiddenPattern'), + description: descriptionPrefixesSuffixes('forbiddenPatterns'), }, forbiddenSuffixes: { ...ARRAY_DEFAULT_OPTIONS, - description: descriptionPrefixesSuffixes('forbiddenPattern'), + description: descriptionPrefixesSuffixes('forbiddenPatterns'), }, requiredPrefixes: { ...ARRAY_DEFAULT_OPTIONS, - description: descriptionPrefixesSuffixes('requiredPattern'), + description: descriptionPrefixesSuffixes('requiredPatterns'), }, requiredSuffixes: { ...ARRAY_DEFAULT_OPTIONS, - description: descriptionPrefixesSuffixes('requiredPattern'), + description: descriptionPrefixesSuffixes('requiredPatterns'), }, ignorePattern: { type: 'string', @@ -118,7 +118,9 @@ const schema = { kind, { ...schemaOption, - description: `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`, + description: `> [!NOTE] +> +> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`, }, ]), ), @@ -150,8 +152,8 @@ type PropertySchema = { style?: AllowedStyle; suffix?: string; prefix?: string; - forbiddenPattern?: RegExp[]; - requiredPattern?: RegExp[]; + forbiddenPatterns?: RegExp[]; + requiredPatterns?: RegExp[]; forbiddenPrefixes?: string[]; forbiddenSuffixes?: string[]; requiredPrefixes?: string[]; @@ -375,8 +377,8 @@ export const rule: GraphQLESLintRule = { ignorePattern, requiredPrefixes, requiredSuffixes, - forbiddenPattern, - requiredPattern, + forbiddenPatterns, + requiredPatterns, } = normalisePropertyOption(selector); const nodeName = node.value; const error = getError(); @@ -415,16 +417,16 @@ export const rule: GraphQLESLintRule = { renameToNames: [name + suffix], }; } - const forbidden = forbiddenPattern?.find(pattern => pattern.test(name)); + const forbidden = forbiddenPatterns?.find(pattern => pattern.test(name)); if (forbidden) { return { errorMessage: `not contain the forbidden pattern "${forbidden}"`, renameToNames: [name.replace(forbidden, '')], }; } - if (requiredPattern && !requiredPattern.some(pattern => pattern.test(name))) { + if (requiredPatterns && !requiredPatterns.some(pattern => pattern.test(name))) { return { - errorMessage: `contain the required pattern: ${englishJoinWords(requiredPattern.map(re => re.source))}`, + errorMessage: `contain the required pattern: ${englishJoinWords(requiredPatterns.map(re => re.source))}`, renameToNames: [], }; } diff --git a/packages/plugin/src/rules/naming-convention/snapshot.md b/packages/plugin/src/rules/naming-convention/snapshot.md index 13075e5ba5f..12750ad44fc 100644 --- a/packages/plugin/src/rules/naming-convention/snapshot.md +++ b/packages/plugin/src/rules/naming-convention/snapshot.md @@ -375,7 +375,7 @@ exports[`naming-convention > invalid > Invalid #10 1`] = ` 1 | query Foo { foo } query Bar { bar } `; -exports[`naming-convention > invalid > forbiddenPattern 1`] = ` +exports[`naming-convention > invalid > forbiddenPatterns 1`] = ` #### ⌨️ Code 1 | query queryFoo { foo } query getBar { bar } @@ -384,7 +384,7 @@ exports[`naming-convention > invalid > forbiddenPattern 1`] = ` { "OperationDefinition": { - "forbiddenPattern": [ + "forbiddenPatterns": [ "/^(get|query)/" ] } @@ -1973,7 +1973,7 @@ exports[`naming-convention > invalid > operations-recommended config 1`] = ` 13 | fragment Test on Test { id } `; -exports[`naming-convention > invalid > requiredPattern 1`] = ` +exports[`naming-convention > invalid > requiredPatterns 1`] = ` #### ⌨️ Code 1 | type Test { enabled: Boolean! } @@ -1983,7 +1983,7 @@ exports[`naming-convention > invalid > requiredPattern 1`] = ` { "FieldDefinition[gqlType.gqlType.name.value=Boolean]": { "style": "camelCase", - "requiredPattern": [ + "requiredPatterns": [ "/^(is|has)/" ] } diff --git a/packages/plugin/src/rules/no-unused-fields/index.ts b/packages/plugin/src/rules/no-unused-fields/index.ts index d0bff8c891d..b29571608fa 100644 --- a/packages/plugin/src/rules/no-unused-fields/index.ts +++ b/packages/plugin/src/rules/no-unused-fields/index.ts @@ -4,7 +4,7 @@ import { FromSchema } from 'json-schema-to-ts'; import { ModuleCache } from '../../cache.js'; import { SiblingOperations } from '../../siblings.js'; import { GraphQLESLintRule, GraphQLESTreeNode } from '../../types.js'; -import { requireGraphQLOperations, requireGraphQLSchema } from '../../utils.js'; +import { eslintSelectorsTip, requireGraphQLOperations, requireGraphQLSchema } from '../../utils.js'; const RULE_ID = 'no-unused-fields'; @@ -89,9 +89,7 @@ const 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.', + eslintSelectorsTip, ].join('\n'), items: { type: 'string', diff --git a/packages/plugin/src/rules/require-description/index.test.ts b/packages/plugin/src/rules/require-description/index.test.ts index dec194889c4..f3e432771f4 100644 --- a/packages/plugin/src/rules/require-description/index.test.ts +++ b/packages/plugin/src/rules/require-description/index.test.ts @@ -228,6 +228,47 @@ ruleTester.run('require-description', rule, { options: [{ rootField: true }], errors: [{ messageId: RULE_ID }], }, + { + name: 'ignoredSelectors', + options: [ + { + types: true, + ignoredSelectors: [ + '[type=ObjectTypeDefinition][name.value=PageInfo]', + '[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]', + ], + }, + ], + code: /* GraphQL */ ` + type Query { + user: User + } + type User { + id: ID! + name: String! + friends(first: Int, after: String): FriendConnection! + } + type FriendConnection { + edges: [FriendEdge] + pageInfo: PageInfo! + } + type FriendEdge { + cursor: String! + node: Friend! + } + type Friend { + id: ID! + name: String! + } + type PageInfo { + hasPreviousPage: Boolean! + hasNextPage: Boolean! + startCursor: String + endCursor: String + } + `, + errors: 3, + }, ], }); diff --git a/packages/plugin/src/rules/require-description/index.ts b/packages/plugin/src/rules/require-description/index.ts index bfed1965f73..bdcb4a8d2d6 100644 --- a/packages/plugin/src/rules/require-description/index.ts +++ b/packages/plugin/src/rules/require-description/index.ts @@ -2,7 +2,14 @@ import { ASTKindToNode, Kind, TokenKind } from 'graphql'; import { getRootTypeNames } from '@graphql-tools/utils'; import { GraphQLESTreeNode } from '../../estree-converter/index.js'; import { GraphQLESLintRule, ValueOf } from '../../types.js'; -import { getLocation, getNodeName, requireGraphQLSchema, TYPES_KINDS } from '../../utils.js'; +import { + ARRAY_DEFAULT_OPTIONS, + eslintSelectorsTip, + getLocation, + getNodeName, + requireGraphQLSchema, + TYPES_KINDS, +} from '../../utils.js'; export const RULE_ID = 'require-description'; @@ -30,18 +37,31 @@ const schema = { properties: { types: { type: 'boolean', + enum: [true], description: `Includes:\n${TYPES_KINDS.map(kind => `- \`${kind}\``).join('\n')}`, }, rootField: { type: 'boolean', + enum: [true], description: 'Definitions within `Query`, `Mutation`, and `Subscription` root types.', }, + ignoredSelectors: { + ...ARRAY_DEFAULT_OPTIONS, + description: ['Ignore specific selectors', eslintSelectorsTip].join('\n'), + }, ...Object.fromEntries( [...ALLOWED_KINDS].sort().map(kind => { - let description = `Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`; + let description = `> [!NOTE] +> +> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`; if (kind === Kind.OPERATION_DEFINITION) { - description += - '\n> You must use only comment syntax `#` and not description syntax `"""` or `"`.'; + description += [ + '', + '', + '> [!WARNING]', + '>', + '> You must use only comment syntax `#` and not description syntax `"""` or `"`.', + ].join('\n'); } return [kind, { type: 'boolean', description }]; }), @@ -55,8 +75,9 @@ export type RuleOptions = [ { [key in AllowedKind]?: boolean; } & { - types?: boolean; - rootField?: boolean; + types?: true; + rootField?: true; + ignoredSelectors?: string[]; }, ]; @@ -115,6 +136,33 @@ export const rule: GraphQLESLintRule = { } `, }, + { + title: 'Correct', + usage: [ + { + ignoredSelectors: [ + '[type=ObjectTypeDefinition][name.value=PageInfo]', + '[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]', + ], + }, + ], + code: /* GraphQL */ ` + type FriendConnection { + edges: [FriendEdge] + pageInfo: PageInfo! + } + type FriendEdge { + cursor: String! + node: Friend! + } + type PageInfo { + hasPreviousPage: Boolean! + hasNextPage: Boolean! + startCursor: String + endCursor: String + } + `, + }, ], configOptions: [ { @@ -132,7 +180,7 @@ export const rule: GraphQLESLintRule = { schema, }, create(context) { - const { types, rootField, ...restOptions } = context.options[0] || {}; + const { types, rootField, ignoredSelectors = [], ...restOptions } = context.options[0] || {}; const kinds = new Set(types ? TYPES_KINDS : []); for (const [kind, isEnabled] of Object.entries(restOptions)) { @@ -152,13 +200,10 @@ export const rule: GraphQLESLintRule = { ].join(',')})$/] > FieldDefinition`, ); } - - if (!kinds.size) { - throw new Error('At least one kind must be enabled'); + let selector = `:matches(${[...kinds]})`; + for (const str of ignoredSelectors) { + selector += `:not(${str})`; } - - const selector = [...kinds].join(','); - return { [selector](node: SelectorNode) { let description = ''; diff --git a/packages/plugin/src/rules/require-description/snapshot.md b/packages/plugin/src/rules/require-description/snapshot.md index 817e48a1637..9fca130f783 100644 --- a/packages/plugin/src/rules/require-description/snapshot.md +++ b/packages/plugin/src/rules/require-description/snapshot.md @@ -228,6 +228,67 @@ exports[`require-description > invalid > Invalid #19 1`] = ` 3 | } `; +exports[`require-description > invalid > ignoredSelectors 1`] = ` +#### ⌨️ Code + + 1 | type Query { + 2 | user: User + 3 | } + 4 | type User { + 5 | id: ID! + 6 | name: String! + 7 | friends(first: Int, after: String): FriendConnection! + 8 | } + 9 | type FriendConnection { + 10 | edges: [FriendEdge] + 11 | pageInfo: PageInfo! + 12 | } + 13 | type FriendEdge { + 14 | cursor: String! + 15 | node: Friend! + 16 | } + 17 | type Friend { + 18 | id: ID! + 19 | name: String! + 20 | } + 21 | type PageInfo { + 22 | hasPreviousPage: Boolean! + 23 | hasNextPage: Boolean! + 24 | startCursor: String + 25 | endCursor: String + 26 | } + +#### ⚙️ Options + + { + "types": true, + "ignoredSelectors": [ + "[type=ObjectTypeDefinition][name.value=PageInfo]", + "[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]" + ] + } + +#### ❌ Error 1/3 + + > 1 | type Query { + | ^^^^^ Description is required for type "Query" + 2 | user: User + +#### ❌ Error 2/3 + + 3 | } + > 4 | type User { + | ^^^^ Description is required for type "User" + 5 | id: ID! + +#### ❌ Error 3/3 + + 16 | } + > 17 | type Friend { + | ^^^^^^ Description is required for type "Friend" + 18 | id: ID! +`; + exports[`require-description > invalid > should disable description for ObjectTypeDefinition 1`] = ` #### ⌨️ Code diff --git a/packages/plugin/src/utils.ts b/packages/plugin/src/utils.ts index 396b755dbaf..c78afe3abd7 100644 --- a/packages/plugin/src/utils.ts +++ b/packages/plugin/src/utils.ts @@ -200,3 +200,8 @@ export function getNodeName(node: GraphQLESTreeNode): string { } return ''; } + +export const eslintSelectorsTip = `> [!TIP] +> +> 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.`; diff --git a/packages/rule-tester/src/index.ts b/packages/rule-tester/src/index.ts index bb315a22240..07e9c72b29b 100644 --- a/packages/rule-tester/src/index.ts +++ b/packages/rule-tester/src/index.ts @@ -26,8 +26,8 @@ function applyFix(code: string, { range, text }: Rule.Fix): string { } // @ts-expect-error -- Extend RegExp with a custom toJSON method -RegExp.prototype.toJSON = function() { - return `/${this.source}/${this.flags}` +RegExp.prototype.toJSON = function () { + return `/${this.source}/${this.flags}`; }; export class RuleTester extends ESLintRuleTester { diff --git a/website/content/docs/index.mdx b/website/content/docs/index.mdx index ff1b7ae5b65..837e4c75cef 100644 --- a/website/content/docs/index.mdx +++ b/website/content/docs/index.mdx @@ -6,11 +6,12 @@ description: What's GraphQL-ESLint, key features and helpful resources. This project integrates GraphQL and ESLint, for a better developer experience. - - -

Demo GraphQL-ESLint in VSCode

+
+ +
Demo GraphQL-ESLint in VSCode
+
## Features @@ -22,7 +23,7 @@ This project integrates GraphQL and ESLint, for a better developer experience. - Easily extendable - supports custom rules based on GraphQL's AST and ESLint API - Validates, lints, prettifies and checks for best practices across GraphQL schema and GraphQL operations -- Integrates with [`graphql-config`](https://the-guild.dev/graphql/config) +- Integrates with [GraphQL Config](https://the-guild.dev/graphql/config) - Integrates and visualizes lint issues in popular IDEs (VSCode / WebStorm) ## Resources diff --git a/website/content/docs/usage/index.mdx b/website/content/docs/usage/index.mdx index 0f94ab5ed01..31e2cb37f7d 100644 --- a/website/content/docs/usage/index.mdx +++ b/website/content/docs/usage/index.mdx @@ -63,8 +63,8 @@ export default [ ### Lint GraphQL Definitions in Code Files _(Optional)_[#lint-in-code-files] -If you're defining GraphQL schemas or operations directly within code files[^1], check out -[the usage with `.js`/`.jsx`](./usage/js) files. +If you're defining GraphQL schemas or operations directly within code files (e.g., `.js`, `.jsx`, +`.ts`, `.tsx` files), check out [the usage with `.js`/`.jsx`](./usage/js) files. ### Providing GraphQL Schema _(Optional)_[#providing-schema] @@ -75,13 +75,13 @@ through root-level fields. To enable these rules, you need to inform ESLint how to identify and load your complete schema. The GraphQL ESLint plugin integrates seamlessly with -[GraphQL Config](https://the-guild.dev/graphql/config) which it uses to automatically load your +[GraphQL Config](https://the-guild.dev/graphql/config), which it uses to automatically load your schema. > [!TIP] > > GraphQL Config uses [`GraphQL Tools`](https://the-guild.dev/graphql/tools) and its loaders under -> the hood to handle the schema loading. GraphQL Config +> the hood to handle the schema loading. It also > [supports multiple ways to specify your schema](https://the-guild.dev/graphql/config/docs/user/schema), > including: > @@ -160,8 +160,15 @@ results, due the missing information. To workaround that, we allow you to provide additional information on your GraphQL operations, making it available for rules while doing the actual linting. -To provide that, we are using `graphql-tools` loaders to load your sibling operations and fragments, -just specify a glob expression(s) that points to your code[^1] and/or `.graphql` files: +The GraphQL ESLint plugin integrates seamlessly with +[GraphQL Config](https://the-guild.dev/graphql/config), which it uses to automatically load your +sibling operations and fragments. + +> [!TIP] +> +> GraphQL Config uses [`GraphQL Tools`](https://the-guild.dev/graphql/tools) and its loaders under +> the hood to handle the loading of operations and fragments. It also +> [supports multiple ways to specify them](https://the-guild.dev/graphql/config/docs/user/documents). @@ -234,5 +241,3 @@ export default [ PrettierIcon }} /> - -[^1]: Code files (e.g., `.js`, `.jsx`, `.ts`, `.tsx` files) diff --git a/website/content/rules/naming-convention.mdx b/website/content/rules/naming-convention.mdx index e63bfbc6ef6..9011f499497 100644 --- a/website/content/rules/naming-convention.mdx +++ b/website/content/rules/naming-convention.mdx @@ -149,7 +149,9 @@ The object must be one of the following types: ### `Argument` -Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#Argument). +> [!NOTE] +> +> Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#Argument). The object must be one of the following types: @@ -158,8 +160,10 @@ The object must be one of the following types: ### `DirectiveDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#DirectiveDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#DirectiveDefinition). The object must be one of the following types: @@ -168,8 +172,10 @@ The object must be one of the following types: ### `EnumTypeDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#EnumTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#EnumTypeDefinition). The object must be one of the following types: @@ -178,8 +184,10 @@ The object must be one of the following types: ### `EnumValueDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#EnumValueDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#EnumValueDefinition). The object must be one of the following types: @@ -188,8 +196,10 @@ The object must be one of the following types: ### `FieldDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#FieldDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#FieldDefinition). The object must be one of the following types: @@ -198,8 +208,10 @@ The object must be one of the following types: ### `FragmentDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#FragmentDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#FragmentDefinition). The object must be one of the following types: @@ -208,8 +220,10 @@ The object must be one of the following types: ### `InputObjectTypeDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#InputObjectTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#InputObjectTypeDefinition). The object must be one of the following types: @@ -218,8 +232,10 @@ The object must be one of the following types: ### `InputValueDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#InputValueDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#InputValueDefinition). The object must be one of the following types: @@ -228,8 +244,10 @@ The object must be one of the following types: ### `InterfaceTypeDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#InterfaceTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#InterfaceTypeDefinition). The object must be one of the following types: @@ -238,8 +256,10 @@ The object must be one of the following types: ### `ObjectTypeDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#ObjectTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#ObjectTypeDefinition). The object must be one of the following types: @@ -248,8 +268,10 @@ The object must be one of the following types: ### `OperationDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#OperationDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#OperationDefinition). The object must be one of the following types: @@ -258,8 +280,10 @@ The object must be one of the following types: ### `ScalarTypeDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#ScalarTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#ScalarTypeDefinition). The object must be one of the following types: @@ -268,8 +292,10 @@ The object must be one of the following types: ### `UnionTypeDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#UnionTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#UnionTypeDefinition). The object must be one of the following types: @@ -278,8 +304,10 @@ The object must be one of the following types: ### `VariableDefinition` -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#VariableDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#VariableDefinition). The object must be one of the following types: @@ -321,7 +349,7 @@ This element must be one of the following enum values: ### `suffix` (string) -### `forbiddenPattern` (array) +### `forbiddenPatterns` (array) Should be of instance of `RegEx` @@ -334,7 +362,7 @@ Additional restrictions: - Minimum items: `1` - Unique items: `true` -### `requiredPattern` (array) +### `requiredPatterns` (array) Should be of instance of `RegEx` @@ -352,7 +380,7 @@ Additional restrictions: > [!WARNING] > > This option is deprecated and will be removed in the next major release. Use -> [`forbiddenPattern`](#forbiddenpattern-array) instead. +> [`forbiddenPatterns`](#forbiddenpatterns-array) instead. The object is an array with all elements of the type `string`. @@ -366,7 +394,7 @@ Additional restrictions: > [!WARNING] > > This option is deprecated and will be removed in the next major release. Use -> [`forbiddenPattern`](#forbiddenpattern-array) instead. +> [`forbiddenPatterns`](#forbiddenpatterns-array) instead. The object is an array with all elements of the type `string`. @@ -380,7 +408,7 @@ Additional restrictions: > [!WARNING] > > This option is deprecated and will be removed in the next major release. Use -> [`requiredPattern`](#requiredpattern-array) instead. +> [`requiredPatterns`](#requiredpatterns-array) instead. The object is an array with all elements of the type `string`. @@ -394,7 +422,7 @@ Additional restrictions: > [!WARNING] > > This option is deprecated and will be removed in the next major release. Use -> [`requiredPattern`](#requiredpattern-array) instead. +> [`requiredPatterns`](#requiredpatterns-array) instead. The object is an array with all elements of the type `string`. diff --git a/website/content/rules/no-unused-fields.mdx b/website/content/rules/no-unused-fields.mdx index 7b386958e50..d8da4326c43 100644 --- a/website/content/rules/no-unused-fields.mdx +++ b/website/content/rules/no-unused-fields.mdx @@ -145,6 +145,8 @@ in the schema: ] ``` +> [!TIP] +> > 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 diff --git a/website/content/rules/require-description.mdx b/website/content/rules/require-description.mdx index aeb29a45aad..ef19c96cc4f 100644 --- a/website/content/rules/require-description.mdx +++ b/website/content/rules/require-description.mdx @@ -70,11 +70,32 @@ type User { } ``` +### Correct + +```graphql +# eslint @graphql-eslint/require-description: ['error', { ignoredSelectors: ['[type=ObjectTypeDefinition][name.value=PageInfo]', '[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]'] }] + +type FriendConnection { + edges: [FriendEdge] + pageInfo: PageInfo! +} +type FriendEdge { + cursor: String! + node: Friend! +} +type PageInfo { + hasPreviousPage: Boolean! + hasNextPage: Boolean! + startCursor: String + endCursor: String +} +``` + ## Config Schema The schema defines the following properties: -### `types` (boolean) +### `types` (boolean, enum) Includes: @@ -85,66 +106,116 @@ Includes: - `InputObjectTypeDefinition` - `UnionTypeDefinition` -### `rootField` (boolean) +This element must be one of the following enum values: + +- `true` + +### `rootField` (boolean, enum) Definitions within `Query`, `Mutation`, and `Subscription` root types. +This element must be one of the following enum values: + +- `true` + +### `ignoredSelectors` (array) + +Ignore specific selectors + +> [!TIP] +> +> 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` + ### `DirectiveDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#DirectiveDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#DirectiveDefinition). ### `EnumTypeDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#EnumTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#EnumTypeDefinition). ### `EnumValueDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#EnumValueDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#EnumValueDefinition). ### `FieldDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#FieldDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#FieldDefinition). ### `InputObjectTypeDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#InputObjectTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#InputObjectTypeDefinition). ### `InputValueDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#InputValueDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#InputValueDefinition). ### `InterfaceTypeDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#InterfaceTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#InterfaceTypeDefinition). ### `ObjectTypeDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#ObjectTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#ObjectTypeDefinition). ### `OperationDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#OperationDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#OperationDefinition). +> [!WARNING] +> > You must use only comment syntax `#` and not description syntax `"""` or `"`. ### `ScalarTypeDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#ScalarTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#ScalarTypeDefinition). ### `UnionTypeDefinition` (boolean) -Read more about this kind on -[spec.graphql.org](https://spec.graphql.org/October2021/#UnionTypeDefinition). +> [!NOTE] +> +> Read more about this kind on +> [spec.graphql.org](https://spec.graphql.org/October2021/#UnionTypeDefinition). ## Resources diff --git a/website/tailwind.config.ts b/website/tailwind.config.ts index becc9ab65ae..9e9cbbbcf35 100644 --- a/website/tailwind.config.ts +++ b/website/tailwind.config.ts @@ -3,6 +3,8 @@ import tailwindConfig from '@theguild/tailwind-config'; export default { ...tailwindConfig, + // todo: add to shared config + content: [...tailwindConfig.content, './content/**/*.{md,mdx}'], // @ts-expect-error -- fixme plugins: [tailwindRadix()], };