diff --git a/.cspell.json b/.cspell.json index dcb924f5..624073ff 100644 --- a/.cspell.json +++ b/.cspell.json @@ -30,6 +30,7 @@ ".yarn/", "__fixtures__/api.github.com/", "dist/", + "github.schema.gql", "patches/", "yarn.lock" ], diff --git a/.eslintignore b/.eslintignore index 394dfc79..91b0dae8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -25,6 +25,7 @@ yarn.lock !.cspell.json !.dprint.* !.github/ +!.graphqlrc.yml !.grease*.* !.lintstagedrc.json !.markdownlint.jsonc diff --git a/.eslintrc.base.cjs b/.eslintrc.base.cjs index 6371bfa4..80fe0cdb 100644 --- a/.eslintrc.base.cjs +++ b/.eslintrc.base.cjs @@ -59,6 +59,7 @@ const config = { 'promise', 'unicorn' ], + processor: '@graphql-eslint/graphql', rules: { '@typescript-eslint/adjacent-overload-signatures': 2, '@typescript-eslint/array-type': [ @@ -794,6 +795,7 @@ const config = { files: '**/*.d.+(cts|mts|ts)', rules: { '@typescript-eslint/ban-types': 0, + '@typescript-eslint/prefer-function-type': 0, '@typescript-eslint/triple-slash-reference': 0, 'jsdoc/no-undefined-types': 0, 'jsdoc/require-file-overview': 0, @@ -1181,12 +1183,6 @@ const config = { ] } }, - { - files: ['docker*.yml', '**/*.md/*.+(yaml|yml)'], - rules: { - 'yml/sort-keys': 0 - } - }, { files: ['.github/workflows/*.yml', '.yarnrc.yml', 'docker*.yml'], rules: { @@ -1218,6 +1214,35 @@ const config = { } ] } + }, + { + files: ['docker*.yml', '**/*.md/*.+(yaml|yml)'], + rules: { + 'yml/sort-keys': 0 + } + }, + { + extends: ['plugin:@graphql-eslint/operations-all'], + files: 'src/**/*.+(gql|graphql)', + parser: '@graphql-eslint/eslint-plugin', + plugins: ['@graphql-eslint'], + rules: { + '@graphql-eslint/alphabetize': [ + 2, + { + arguments: ['Field', 'Directive'], + definitions: true, + fields: [ + 'InputObjectTypeDefinition', + 'InterfaceTypeDefinition', + 'ObjectTypeDefinition' + ], + selections: ['OperationDefinition', 'FragmentDefinition'], + values: true, + variables: true + } + ] + } } ], plugins: [], diff --git a/.eslintrc.cjs b/.eslintrc.cjs index d63cfe32..69bdb274 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -10,7 +10,15 @@ */ const config = { extends: ['./.eslintrc.base.cjs'], - overrides: [...require('./.eslintrc.base.cjs').overrides], + overrides: [ + ...require('./.eslintrc.base.cjs').overrides, + { + files: 'github.schema.gql', + parser: '@graphql-eslint/eslint-plugin', + plugins: ['@graphql-eslint'], + rules: {} + } + ], root: true } diff --git a/.lintstagedrc.json b/.lintstagedrc.json index 23713d49..16900db0 100644 --- a/.lintstagedrc.json +++ b/.lintstagedrc.json @@ -1,7 +1,8 @@ { - "*": ["dprint check", "cspell lint --color --no-progress --relative $@"], - "**/*.{cjs,cts,gql,js,json,json5,jsonc,jsx,md,mjs,mts,ts,tsx,yaml,yml}": [ - "eslint --exit-on-fatal-error" + "*": [ + "dprint check", + "eslint --exit-on-fatal-error", + "cspell lint --color --no-progress --relative $@" ], "**/*.{cts,mts,ts}": "vitest run --changed --typecheck", "**/yarn.lock": "yarn dedupe --check", diff --git a/.vscode/settings.json b/.vscode/settings.json index af8a8332..98920b2d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -154,6 +154,8 @@ "extensions": [ "cjs", "cts", + "gql", + "graphql", "js", "json", "json5", @@ -171,8 +173,8 @@ "overrideConfigFile": ".eslintrc.cjs" }, "eslint.validate": [ - "graphql", "github-actions-workflow", + "graphql", "javascript", "json", "json5", diff --git a/__tests__/interfaces/index.ts b/__tests__/interfaces/index.ts index df90fc31..102a855a 100644 --- a/__tests__/interfaces/index.ts +++ b/__tests__/interfaces/index.ts @@ -1,5 +1,5 @@ /** - * @file Entry Point - Test Environment Interfaces + * @file Entry Point - Test Interfaces * @module tests/interfaces */ diff --git a/__tests__/interfaces/mock.ts b/__tests__/interfaces/mock.ts index 71a9cfea..de2dabb4 100644 --- a/__tests__/interfaces/mock.ts +++ b/__tests__/interfaces/mock.ts @@ -1,5 +1,5 @@ /** - * @file Test Environment Interfaces - Mock + * @file Test Interfaces - Mock * @module tests/interfaces/Mock */ diff --git a/__tests__/interfaces/spy.ts b/__tests__/interfaces/spy.ts index fc8e4f71..a5c652d5 100644 --- a/__tests__/interfaces/spy.ts +++ b/__tests__/interfaces/spy.ts @@ -1,5 +1,5 @@ /** - * @file Test Environment Interfaces - Spy + * @file Test Interfaces - Spy * @module tests/interfaces/Spy */ diff --git a/__tests__/setup/graphql/schema.ts b/__tests__/setup/graphql/schema.ts new file mode 100644 index 00000000..5e6945c2 --- /dev/null +++ b/__tests__/setup/graphql/schema.ts @@ -0,0 +1,27 @@ +/** + * @file Test Setup - schema + * @module tests/setup/graphql/schema + * @see https://mswjs.io/docs/recipes/mock-graphql-schema + */ + +import * as mlly from '@flex-development/mlly' +import pathe from '@flex-development/pathe' +import { buildSchema, type GraphQLSchema } from 'graphql' + +/** + * Absolute path to GraphQL schema file. + * + * @const {string} source + */ +const source: string = pathe.resolve('github.schema.gql') + +/** + * GraphQL schema object. + * + * @see {@linkcode GraphQLSchema} + * + * @const {GraphQLSchema} schema + */ +const schema: GraphQLSchema = buildSchema(await mlly.getSource(source)) + +export default schema diff --git a/__tests__/setup/server.ts b/__tests__/setup/server.ts index 7a107e7f..2c3fa53b 100644 --- a/__tests__/setup/server.ts +++ b/__tests__/setup/server.ts @@ -3,23 +3,33 @@ * @module tests/setup/server */ -import data from '#fixtures/api.github.com/graphql.json' assert { type: 'json' } +import root from '#fixtures/api.github.com/graphql.json' assert { type: 'json' } import CLIENT_MUTATION_ID from '#fixtures/client-mutation-id.fixture' import type { - CreateLabelCommand, - DeleteLabelCommand, - UpdateLabelCommand -} from '#src/labels/commands' -import type { Label } from '#src/labels/types' -import type { - GQLPayload, - MutationVariables, - QueryVariables -} from '#tests/types' + CreateLabelCommand as CreateLabelInput, + Label, + UpdateLabelCommand as UpdateLabelInput +} from '#src/labels' +import connection from '#tests/utils/connection' import gqh from '#tests/utils/gqh' -import GQLResponse from '#tests/utils/gql-response' -import { merge, pick, type Omit } from '@flex-development/tutils' +import { + assign, + includes, + pick, + select, + shake, + type Optional +} from '@flex-development/tutils' +import type { Connection } from '@octokit/graphql' +import type { RepositoryLabelsArgs } from '@octokit/graphql-schema' +import { + GraphQLError, + graphql as executeGraphql, + type ExecutionResult +} from 'graphql' +import { HttpResponse } from 'msw' import { setupServer, type SetupServer } from 'msw/node' +import schema from './graphql/schema' /** * Mock server. @@ -30,56 +40,122 @@ import { setupServer, type SetupServer } from 'msw/node' * @const {SetupServer} server */ const server: SetupServer = setupServer( - gqh.mutation< - GQLPayload<'label', Label>, - MutationVariables - >('CreateLabel', ({ variables: { input } }) => { - return GQLResponse.json({ - data: { - payload: { - label: