From 803626af0fca8482ed395af83467afd99270b702 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 29 Nov 2024 15:06:47 +0700 Subject: [PATCH 1/7] more --- .../src/rules/naming-convention/index.ts | 4 +- .../src/rules/no-unused-fields/index.ts | 6 +- .../rules/require-description/index.test.ts | 39 +++++++++ .../src/rules/require-description/snapshot.md | 61 ++++++++++++++ packages/plugin/src/utils.ts | 5 ++ website/content/rules/naming-convention.mdx | 82 +++++++++++++------ website/content/rules/require-description.mdx | 60 +++++++++----- 7 files changed, 205 insertions(+), 52 deletions(-) diff --git a/packages/plugin/src/rules/naming-convention/index.ts b/packages/plugin/src/rules/naming-convention/index.ts index 5d2068d3f2f..29ab877725f 100644 --- a/packages/plugin/src/rules/naming-convention/index.ts +++ b/packages/plugin/src/rules/naming-convention/index.ts @@ -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}).`, }, ]), ), diff --git a/packages/plugin/src/rules/no-unused-fields/index.ts b/packages/plugin/src/rules/no-unused-fields/index.ts index d0bff8c891d..8d070615ca3 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..faf5ddcb612 100644 --- a/packages/plugin/src/rules/require-description/index.test.ts +++ b/packages/plugin/src/rules/require-description/index.test.ts @@ -228,6 +228,45 @@ ruleTester.run('require-description', rule, { options: [{ rootField: true }], errors: [{ messageId: RULE_ID }], }, + { + only: true, + 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/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..86bacd02f71 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/website/content/rules/naming-convention.mdx b/website/content/rules/naming-convention.mdx index e63bfbc6ef6..b83ed070038 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: diff --git a/website/content/rules/require-description.mdx b/website/content/rules/require-description.mdx index aeb29a45aad..ac060ef7626 100644 --- a/website/content/rules/require-description.mdx +++ b/website/content/rules/require-description.mdx @@ -91,43 +91,59 @@ Definitions within `Query`, `Mutation`, and `Subscription` root types. ### `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) @@ -138,13 +154,17 @@ Read more about this kind on ### `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 From f9d97f94acf5c34327d754b2e4db13c19b86e313 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 29 Nov 2024 15:11:54 +0700 Subject: [PATCH 2/7] more --- .../src/rules/require-description/index.ts | 37 +++++++++++------- website/content/rules/no-unused-fields.mdx | 2 + website/content/rules/require-description.mdx | 38 +++++++++++++++++-- 3 files changed, 60 insertions(+), 17 deletions(-) diff --git a/packages/plugin/src/rules/require-description/index.ts b/packages/plugin/src/rules/require-description/index.ts index bfed1965f73..d62352ce61a 100644 --- a/packages/plugin/src/rules/require-description/index.ts +++ b/packages/plugin/src/rules/require-description/index.ts @@ -2,7 +2,13 @@ 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 +36,25 @@ 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 +68,9 @@ export type RuleOptions = [ { [key in AllowedKind]?: boolean; } & { - types?: boolean; - rootField?: boolean; + types?: true; + rootField?: true; + ignoredSelectors?: string[]; }, ]; @@ -132,7 +146,7 @@ export const rule: GraphQLESLintRule = { schema, }, create(context) { - const { types, rootField, ...restOptions } = context.options[0] || {}; + let { types, rootField, ignoredSelectors = [], ...restOptions } = context.options[0] || {}; const kinds = new Set(types ? TYPES_KINDS : []); for (const [kind, isEnabled] of Object.entries(restOptions)) { @@ -152,13 +166,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/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 ac060ef7626..f3e88f28c80 100644 --- a/website/content/rules/require-description.mdx +++ b/website/content/rules/require-description.mdx @@ -74,7 +74,7 @@ type User { The schema defines the following properties: -### `types` (boolean) +### `types` (boolean, enum) Includes: @@ -85,10 +85,36 @@ 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) > [!NOTE] @@ -147,9 +173,13 @@ Definitions within `Query`, `Mutation`, and `Subscription` root types. ### `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) From df4bb52259f099e7dee39421fabf56793c72beb8 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 29 Nov 2024 15:16:11 +0700 Subject: [PATCH 3/7] more --- .changeset/long-chicken-press.md | 5 ++ .../src/rules/no-unused-fields/index.ts | 4 +- .../rules/require-description/index.test.ts | 18 ++++---- .../src/rules/require-description/index.ts | 46 ++++++++++++++++--- packages/plugin/src/utils.ts | 2 +- packages/rule-tester/src/index.ts | 4 +- 6 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 .changeset/long-chicken-press.md diff --git a/.changeset/long-chicken-press.md b/.changeset/long-chicken-press.md new file mode 100644 index 00000000000..5cc1855550b --- /dev/null +++ b/.changeset/long-chicken-press.md @@ -0,0 +1,5 @@ +--- +'@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/no-unused-fields/index.ts b/packages/plugin/src/rules/no-unused-fields/index.ts index 8d070615ca3..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 { eslintSelectorsTip, requireGraphQLOperations, requireGraphQLSchema } from "../../utils.js"; +import { eslintSelectorsTip, requireGraphQLOperations, requireGraphQLSchema } from '../../utils.js'; const RULE_ID = 'no-unused-fields'; @@ -89,7 +89,7 @@ const schema = { '```json', JSON.stringify(RELAY_DEFAULT_IGNORED_FIELD_SELECTORS, null, 2), '```', - eslintSelectorsTip + 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 faf5ddcb612..f3e432771f4 100644 --- a/packages/plugin/src/rules/require-description/index.test.ts +++ b/packages/plugin/src/rules/require-description/index.test.ts @@ -229,14 +229,16 @@ ruleTester.run('require-description', rule, { errors: [{ messageId: RULE_ID }], }, { - only: true, name: 'ignoredSelectors', - options: [{ types: true, - ignoredSelectors: [ - '[type=ObjectTypeDefinition][name.value=PageInfo]', - '[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]', - ] - }], + options: [ + { + types: true, + ignoredSelectors: [ + '[type=ObjectTypeDefinition][name.value=PageInfo]', + '[type=ObjectTypeDefinition][name.value=/(Connection|Edge)$/]', + ], + }, + ], code: /* GraphQL */ ` type Query { user: User @@ -266,7 +268,7 @@ ruleTester.run('require-description', rule, { } `, errors: 3, - } + }, ], }); diff --git a/packages/plugin/src/rules/require-description/index.ts b/packages/plugin/src/rules/require-description/index.ts index d62352ce61a..515ba7d7940 100644 --- a/packages/plugin/src/rules/require-description/index.ts +++ b/packages/plugin/src/rules/require-description/index.ts @@ -3,12 +3,13 @@ import { getRootTypeNames } from '@graphql-tools/utils'; import { GraphQLESTreeNode } from '../../estree-converter/index.js'; import { GraphQLESLintRule, ValueOf } from '../../types.js'; import { - ARRAY_DEFAULT_OPTIONS, eslintSelectorsTip, + ARRAY_DEFAULT_OPTIONS, + eslintSelectorsTip, getLocation, getNodeName, requireGraphQLSchema, - TYPES_KINDS -} from "../../utils.js"; + TYPES_KINDS, +} from '../../utils.js'; export const RULE_ID = 'require-description'; @@ -46,7 +47,7 @@ const schema = { }, ignoredSelectors: { ...ARRAY_DEFAULT_OPTIONS, - description: ['Ignore specific selectors', eslintSelectorsTip].join('\n') + description: ['Ignore specific selectors', eslintSelectorsTip].join('\n'), }, ...Object.fromEntries( [...ALLOWED_KINDS].sort().map(kind => { @@ -54,7 +55,13 @@ const schema = { > > Read more about this kind on [spec.graphql.org](https://spec.graphql.org/October2021/#${kind}).`; if (kind === Kind.OPERATION_DEFINITION) { - description += ['','','> [!WARNING]', '>', '> You must use only comment syntax `#` and not description syntax `"""` or `"`.'].join('\n') + description += [ + '', + '', + '> [!WARNING]', + '>', + '> You must use only comment syntax `#` and not description syntax `"""` or `"`.', + ].join('\n'); } return [kind, { type: 'boolean', description }]; }), @@ -129,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: [ { @@ -168,7 +202,7 @@ export const rule: GraphQLESLintRule = { } let selector = `:matches(${[...kinds]})`; for (const str of ignoredSelectors) { - selector += `:not(${str})` + selector += `:not(${str})`; } return { [selector](node: SelectorNode) { diff --git a/packages/plugin/src/utils.ts b/packages/plugin/src/utils.ts index 86bacd02f71..c78afe3abd7 100644 --- a/packages/plugin/src/utils.ts +++ b/packages/plugin/src/utils.ts @@ -204,4 +204,4 @@ export function getNodeName(node: GraphQLESTreeNode): string { 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.` +> 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 { From 16935a388eefce8f769dbc335390cd1ec180a816 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 29 Nov 2024 15:19:31 +0700 Subject: [PATCH 4/7] more --- .changeset/happy-bottles-warn.md | 2 +- .changeset/long-chicken-press.md | 3 +- .../src/rules/naming-convention/index.test.ts | 8 +-- .../src/rules/naming-convention/index.ts | 28 +++++----- .../src/rules/naming-convention/snapshot.md | 56 +++++++++++++++++++ website/content/rules/naming-convention.mdx | 12 ++-- website/content/rules/require-description.mdx | 21 +++++++ 7 files changed, 104 insertions(+), 26 deletions(-) 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 index 5cc1855550b..cb7832d5916 100644 --- a/.changeset/long-chicken-press.md +++ b/.changeset/long-chicken-press.md @@ -2,4 +2,5 @@ '@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` +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 29ab877725f..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', @@ -152,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[]; @@ -377,8 +377,8 @@ export const rule: GraphQLESLintRule = { ignorePattern, requiredPrefixes, requiredSuffixes, - forbiddenPattern, - requiredPattern, + forbiddenPatterns, + requiredPatterns, } = normalisePropertyOption(selector); const nodeName = node.value; const error = getError(); @@ -417,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..78d6d27fb92 100644 --- a/packages/plugin/src/rules/naming-convention/snapshot.md +++ b/packages/plugin/src/rules/naming-convention/snapshot.md @@ -409,6 +409,40 @@ exports[`naming-convention > invalid > forbiddenPattern 1`] = ` 1 | query queryFoo { foo } query Bar { bar } `; +exports[`naming-convention > invalid > forbiddenPatterns 1`] = ` +#### ⌨️ Code + + 1 | query queryFoo { foo } query getBar { bar } + +#### ⚙️ Options + + { + "OperationDefinition": { + "forbiddenPatterns": [ + "/^(get|query)/" + ] + } + } + +#### ❌ Error 1/2 + + > 1 | query queryFoo { foo } query getBar { bar } + | ^^^^^^^^ Query "queryFoo" should not contain the forbidden pattern "/^(get|query)/" + +#### 💡 Suggestion: Rename to \`Foo\` + + 1 | query Foo { foo } query getBar { bar } + +#### ❌ Error 2/2 + + > 1 | query queryFoo { foo } query getBar { bar } + | ^^^^^^ Query "getBar" should not contain the forbidden pattern "/^(get|query)/" + +#### 💡 Suggestion: Rename to \`Bar\` + + 1 | query queryFoo { foo } query Bar { bar } +`; + exports[`naming-convention > invalid > large graphql file 1`] = ` #### ⌨️ Code @@ -1995,6 +2029,28 @@ exports[`naming-convention > invalid > requiredPattern 1`] = ` | ^^^^^^^ Field "enabled" should contain the required pattern: ^(is|has) `; +exports[`naming-convention > invalid > requiredPatterns 1`] = ` +#### ⌨️ Code + + 1 | type Test { enabled: Boolean! } + +#### ⚙️ Options + + { + "FieldDefinition[gqlType.gqlType.name.value=Boolean]": { + "style": "camelCase", + "requiredPatterns": [ + "/^(is|has)/" + ] + } + } + +#### ❌ Error + + > 1 | type Test { enabled: Boolean! } + | ^^^^^^^ Field "enabled" should contain the required pattern: ^(is|has) +`; + exports[`naming-convention > invalid > schema-recommended config 1`] = ` #### ⌨️ Code diff --git a/website/content/rules/naming-convention.mdx b/website/content/rules/naming-convention.mdx index b83ed070038..9011f499497 100644 --- a/website/content/rules/naming-convention.mdx +++ b/website/content/rules/naming-convention.mdx @@ -349,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` @@ -362,7 +362,7 @@ Additional restrictions: - Minimum items: `1` - Unique items: `true` -### `requiredPattern` (array) +### `requiredPatterns` (array) Should be of instance of `RegEx` @@ -380,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`. @@ -394,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`. @@ -408,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`. @@ -422,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/require-description.mdx b/website/content/rules/require-description.mdx index f3e88f28c80..ef19c96cc4f 100644 --- a/website/content/rules/require-description.mdx +++ b/website/content/rules/require-description.mdx @@ -70,6 +70,27 @@ 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: From 137773e2da031621a4bbb9323212b09179e1076a Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 29 Nov 2024 15:20:02 +0700 Subject: [PATCH 5/7] more --- .../src/rules/naming-convention/snapshot.md | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/packages/plugin/src/rules/naming-convention/snapshot.md b/packages/plugin/src/rules/naming-convention/snapshot.md index 78d6d27fb92..12750ad44fc 100644 --- a/packages/plugin/src/rules/naming-convention/snapshot.md +++ b/packages/plugin/src/rules/naming-convention/snapshot.md @@ -375,40 +375,6 @@ exports[`naming-convention > invalid > Invalid #10 1`] = ` 1 | query Foo { foo } query Bar { bar } `; -exports[`naming-convention > invalid > forbiddenPattern 1`] = ` -#### ⌨️ Code - - 1 | query queryFoo { foo } query getBar { bar } - -#### ⚙️ Options - - { - "OperationDefinition": { - "forbiddenPattern": [ - "/^(get|query)/" - ] - } - } - -#### ❌ Error 1/2 - - > 1 | query queryFoo { foo } query getBar { bar } - | ^^^^^^^^ Query "queryFoo" should not contain the forbidden pattern "/^(get|query)/" - -#### 💡 Suggestion: Rename to \`Foo\` - - 1 | query Foo { foo } query getBar { bar } - -#### ❌ Error 2/2 - - > 1 | query queryFoo { foo } query getBar { bar } - | ^^^^^^ Query "getBar" should not contain the forbidden pattern "/^(get|query)/" - -#### 💡 Suggestion: Rename to \`Bar\` - - 1 | query queryFoo { foo } query Bar { bar } -`; - exports[`naming-convention > invalid > forbiddenPatterns 1`] = ` #### ⌨️ Code @@ -2007,28 +1973,6 @@ exports[`naming-convention > invalid > operations-recommended config 1`] = ` 13 | fragment Test on Test { id } `; -exports[`naming-convention > invalid > requiredPattern 1`] = ` -#### ⌨️ Code - - 1 | type Test { enabled: Boolean! } - -#### ⚙️ Options - - { - "FieldDefinition[gqlType.gqlType.name.value=Boolean]": { - "style": "camelCase", - "requiredPattern": [ - "/^(is|has)/" - ] - } - } - -#### ❌ Error - - > 1 | type Test { enabled: Boolean! } - | ^^^^^^^ Field "enabled" should contain the required pattern: ^(is|has) -`; - exports[`naming-convention > invalid > requiredPatterns 1`] = ` #### ⌨️ Code From 114d57ed0844b9b0b559ca8117db51bed4e2dbb1 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 29 Nov 2024 15:45:53 +0700 Subject: [PATCH 6/7] more --- .../src/rules/require-description/index.ts | 2 +- website/content/docs/index.mdx | 13 +++++++------ website/content/docs/usage/index.mdx | 18 +++++++++++------- website/tailwind.config.ts | 4 ++++ 4 files changed, 23 insertions(+), 14 deletions(-) diff --git a/packages/plugin/src/rules/require-description/index.ts b/packages/plugin/src/rules/require-description/index.ts index 515ba7d7940..bdcb4a8d2d6 100644 --- a/packages/plugin/src/rules/require-description/index.ts +++ b/packages/plugin/src/rules/require-description/index.ts @@ -180,7 +180,7 @@ export const rule: GraphQLESLintRule = { schema, }, create(context) { - let { types, rootField, ignoredSelectors = [], ...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)) { diff --git a/website/content/docs/index.mdx b/website/content/docs/index.mdx index ff1b7ae5b65..3df8a12efbe 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..9495f395123 100644 --- a/website/content/docs/usage/index.mdx +++ b/website/content/docs/usage/index.mdx @@ -63,7 +63,7 @@ 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 +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,14 @@ 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 +240,3 @@ export default [ PrettierIcon }} /> - -[^1]: Code files (e.g., `.js`, `.jsx`, `.ts`, `.tsx` files) diff --git a/website/tailwind.config.ts b/website/tailwind.config.ts index becc9ab65ae..95324a9152c 100644 --- a/website/tailwind.config.ts +++ b/website/tailwind.config.ts @@ -3,6 +3,10 @@ import tailwindConfig from '@theguild/tailwind-config'; export default { ...tailwindConfig, + content: [ + ...tailwindConfig.content, + './content/**/*.{md,mdx}' + ], // @ts-expect-error -- fixme plugins: [tailwindRadix()], }; From 436164c7c2041bfc29ccb7abed9a3c3fb4db5520 Mon Sep 17 00:00:00 2001 From: Dimitri POSTOLOV Date: Fri, 29 Nov 2024 15:46:28 +0700 Subject: [PATCH 7/7] more --- website/content/docs/index.mdx | 2 +- website/content/docs/usage/index.mdx | 7 ++++--- website/tailwind.config.ts | 6 ++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/website/content/docs/index.mdx b/website/content/docs/index.mdx index 3df8a12efbe..837e4c75cef 100644 --- a/website/content/docs/index.mdx +++ b/website/content/docs/index.mdx @@ -10,7 +10,7 @@ This project integrates GraphQL and ESLint, for a better developer experience. -
Demo GraphQL-ESLint in VSCode
+
Demo GraphQL-ESLint in VSCode
## Features diff --git a/website/content/docs/usage/index.mdx b/website/content/docs/usage/index.mdx index 9495f395123..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 (e.g., `.js`, `.jsx`, `.ts`, `.tsx` files), 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] @@ -161,7 +161,8 @@ To workaround that, we allow you to provide additional information on your Graph making it available for rules while doing the actual linting. 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. +[GraphQL Config](https://the-guild.dev/graphql/config), which it uses to automatically load your +sibling operations and fragments. > [!TIP] > diff --git a/website/tailwind.config.ts b/website/tailwind.config.ts index 95324a9152c..9e9cbbbcf35 100644 --- a/website/tailwind.config.ts +++ b/website/tailwind.config.ts @@ -3,10 +3,8 @@ import tailwindConfig from '@theguild/tailwind-config'; export default { ...tailwindConfig, - content: [ - ...tailwindConfig.content, - './content/**/*.{md,mdx}' - ], + // todo: add to shared config + content: [...tailwindConfig.content, './content/**/*.{md,mdx}'], // @ts-expect-error -- fixme plugins: [tailwindRadix()], };