@graphql-eslint/eslint-plugin 3.14.4-alpha-20230111223410-a558ee8 → 3.14.4-alpha-20230111225020-02d9c28
Sign up to get free protection for your applications and to get access to all the features.
- package/README.md +5 -288
- package/cjs/documents.js +2 -105
- package/cjs/graphql-config.js +1 -1
- package/cjs/parser.js +9 -3
- package/cjs/rules/alphabetize.js +1 -1
- package/cjs/rules/description-style.js +1 -1
- package/cjs/rules/graphql-js-validation.js +1 -1
- package/cjs/rules/input-name.js +4 -4
- package/cjs/rules/lone-executable-definition.js +1 -1
- package/cjs/rules/match-document-filename.js +2 -3
- package/cjs/rules/naming-convention.js +1 -1
- package/cjs/rules/no-anonymous-operations.js +1 -1
- package/cjs/rules/no-case-insensitive-enum-values-duplicates.js +1 -1
- package/cjs/rules/no-deprecated.js +1 -1
- package/cjs/rules/no-duplicate-fields.js +1 -1
- package/cjs/rules/no-hashtag-description.js +1 -1
- package/cjs/rules/no-one-place-fragments.js +1 -1
- package/cjs/rules/no-root-type.js +1 -1
- package/cjs/rules/no-scalar-result-type-on-mutation.js +1 -1
- package/cjs/rules/no-typename-prefix.js +1 -1
- package/cjs/rules/no-unreachable-types.js +1 -1
- package/cjs/rules/no-unused-fields.js +1 -1
- package/cjs/rules/relay-arguments.js +1 -1
- package/cjs/rules/relay-connection-types.js +1 -1
- package/cjs/rules/relay-edge-types.js +1 -1
- package/cjs/rules/relay-page-info.js +1 -1
- package/cjs/rules/require-deprecation-date.js +1 -1
- package/cjs/rules/require-deprecation-reason.js +1 -1
- package/cjs/rules/require-description.js +1 -1
- package/cjs/rules/require-field-of-type-query-in-mutation-result.js +1 -1
- package/cjs/rules/require-id-when-available.js +1 -1
- package/cjs/rules/require-nullable-fields-with-oneof.js +1 -1
- package/cjs/rules/require-type-pattern-with-oneof.js +1 -1
- package/cjs/rules/selection-set-depth.js +1 -1
- package/cjs/rules/strict-id-in-types.js +1 -1
- package/cjs/rules/unique-fragment-name.js +1 -1
- package/cjs/rules/unique-operation-name.js +1 -1
- package/cjs/siblings.js +113 -0
- package/cjs/utils.js +2 -1
- package/docs/README.md +1 -85
- package/docs/custom-rules.md +1 -184
- package/docs/deprecated-rules.md +1 -24
- package/docs/parser-options.md +1 -107
- package/docs/parser.md +1 -67
- package/esm/documents.js +2 -105
- package/esm/graphql-config.js +1 -1
- package/esm/parser.js +10 -4
- package/esm/rules/alphabetize.js +1 -1
- package/esm/rules/description-style.js +1 -1
- package/esm/rules/graphql-js-validation.js +1 -1
- package/esm/rules/input-name.js +4 -4
- package/esm/rules/lone-executable-definition.js +1 -1
- package/esm/rules/match-document-filename.js +3 -4
- package/esm/rules/naming-convention.js +1 -1
- package/esm/rules/no-anonymous-operations.js +1 -1
- package/esm/rules/no-case-insensitive-enum-values-duplicates.js +1 -1
- package/esm/rules/no-deprecated.js +1 -1
- package/esm/rules/no-duplicate-fields.js +1 -1
- package/esm/rules/no-hashtag-description.js +1 -1
- package/esm/rules/no-one-place-fragments.js +1 -1
- package/esm/rules/no-root-type.js +1 -1
- package/esm/rules/no-scalar-result-type-on-mutation.js +1 -1
- package/esm/rules/no-typename-prefix.js +1 -1
- package/esm/rules/no-unreachable-types.js +1 -1
- package/esm/rules/no-unused-fields.js +1 -1
- package/esm/rules/relay-arguments.js +1 -1
- package/esm/rules/relay-connection-types.js +1 -1
- package/esm/rules/relay-edge-types.js +1 -1
- package/esm/rules/relay-page-info.js +1 -1
- package/esm/rules/require-deprecation-date.js +1 -1
- package/esm/rules/require-deprecation-reason.js +1 -1
- package/esm/rules/require-description.js +1 -1
- package/esm/rules/require-field-of-type-query-in-mutation-result.js +1 -1
- package/esm/rules/require-id-when-available.js +1 -1
- package/esm/rules/require-nullable-fields-with-oneof.js +1 -1
- package/esm/rules/require-type-pattern-with-oneof.js +1 -1
- package/esm/rules/selection-set-depth.js +1 -1
- package/esm/rules/strict-id-in-types.js +1 -1
- package/esm/rules/unique-fragment-name.js +1 -1
- package/esm/rules/unique-operation-name.js +1 -1
- package/esm/siblings.js +109 -0
- package/esm/utils.js +1 -0
- package/package.json +1 -1
- package/typings/documents.d.cts +2 -20
- package/typings/documents.d.ts +2 -20
- package/typings/rules/input-name.d.cts +1 -1
- package/typings/rules/input-name.d.ts +1 -1
- package/typings/siblings.d.cts +22 -0
- package/typings/siblings.d.ts +22 -0
- package/typings/types.d.cts +3 -2
- package/typings/types.d.ts +3 -2
- package/typings/utils.d.cts +2 -1
- package/typings/utils.d.ts +2 -1
- package/docs/rules/alphabetize.md +0 -194
- package/docs/rules/description-style.md +0 -57
- package/docs/rules/executable-definitions.md +0 -20
- package/docs/rules/fields-on-correct-type.md +0 -23
- package/docs/rules/fragments-on-composite-type.md +0 -20
- package/docs/rules/input-name.md +0 -80
- package/docs/rules/known-argument-names.md +0 -23
- package/docs/rules/known-directives.md +0 -48
- package/docs/rules/known-fragment-names.md +0 -72
- package/docs/rules/known-type-names.md +0 -24
- package/docs/rules/lone-anonymous-operation.md +0 -20
- package/docs/rules/lone-executable-definition.md +0 -59
- package/docs/rules/lone-schema-definition.md +0 -19
- package/docs/rules/match-document-filename.md +0 -181
- package/docs/rules/naming-convention.md +0 -320
- package/docs/rules/no-anonymous-operations.md +0 -43
- package/docs/rules/no-case-insensitive-enum-values-duplicates.md +0 -46
- package/docs/rules/no-deprecated.md +0 -88
- package/docs/rules/no-duplicate-fields.md +0 -69
- package/docs/rules/no-fragment-cycles.md +0 -19
- package/docs/rules/no-hashtag-description.md +0 -62
- package/docs/rules/no-one-place-fragments.md +0 -51
- package/docs/rules/no-root-type.md +0 -55
- package/docs/rules/no-scalar-result-type-on-mutation.md +0 -39
- package/docs/rules/no-typename-prefix.md +0 -42
- package/docs/rules/no-undefined-variables.md +0 -20
- package/docs/rules/no-unreachable-types.md +0 -52
- package/docs/rules/no-unused-fields.md +0 -64
- package/docs/rules/no-unused-fragments.md +0 -20
- package/docs/rules/no-unused-variables.md +0 -20
- package/docs/rules/one-field-subscriptions.md +0 -19
- package/docs/rules/overlapping-fields-can-be-merged.md +0 -20
- package/docs/rules/possible-fragment-spread.md +0 -21
- package/docs/rules/possible-type-extension.md +0 -19
- package/docs/rules/provided-required-arguments.md +0 -21
- package/docs/rules/relay-arguments.md +0 -59
- package/docs/rules/relay-connection-types.md +0 -43
- package/docs/rules/relay-edge-types.md +0 -60
- package/docs/rules/relay-page-info.md +0 -34
- package/docs/rules/require-deprecation-date.md +0 -59
- package/docs/rules/require-deprecation-reason.md +0 -49
- package/docs/rules/require-description.md +0 -147
- package/docs/rules/require-field-of-type-query-in-mutation-result.md +0 -50
- package/docs/rules/require-id-when-available.md +0 -91
- package/docs/rules/require-nullable-fields-with-oneof.md +0 -38
- package/docs/rules/require-type-pattern-with-oneof.md +0 -39
- package/docs/rules/scalar-leafs.md +0 -23
- package/docs/rules/selection-set-depth.md +0 -86
- package/docs/rules/strict-id-in-types.md +0 -129
- package/docs/rules/unique-argument-names.md +0 -19
- package/docs/rules/unique-directive-names-per-location.md +0 -21
- package/docs/rules/unique-directive-names.md +0 -19
- package/docs/rules/unique-enum-value-names.md +0 -16
- package/docs/rules/unique-field-definition-names.md +0 -19
- package/docs/rules/unique-fragment-name.md +0 -52
- package/docs/rules/unique-input-field-names.md +0 -19
- package/docs/rules/unique-operation-name.md +0 -56
- package/docs/rules/unique-operation-types.md +0 -19
- package/docs/rules/unique-type-names.md +0 -19
- package/docs/rules/unique-variable-names.md +0 -19
- package/docs/rules/value-literals-of-correct-type.md +0 -22
- package/docs/rules/variables-are-input-types.md +0 -20
- package/docs/rules/variables-in-allowed-position.md +0 -19
@@ -27,7 +27,7 @@ exports.rule = {
|
|
27
27
|
docs: {
|
28
28
|
category: 'Schema',
|
29
29
|
description: 'Disallow using root types `mutation` and/or `subscription`.',
|
30
|
-
url: 'https://
|
30
|
+
url: 'https://the-guild.dev/graphql/eslint/rules/no-root-type',
|
31
31
|
requiresSchema: true,
|
32
32
|
isDisabledForAllConfig: true,
|
33
33
|
examples: [
|
@@ -11,7 +11,7 @@ exports.rule = {
|
|
11
11
|
docs: {
|
12
12
|
category: 'Schema',
|
13
13
|
description: 'Avoid scalar result type on mutation type to make sure to return a valid state.',
|
14
|
-
url: `https://
|
14
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
15
15
|
requiresSchema: true,
|
16
16
|
examples: [
|
17
17
|
{
|
@@ -10,7 +10,7 @@ exports.rule = {
|
|
10
10
|
category: 'Schema',
|
11
11
|
description: 'Enforces users to avoid using the type name in a field name while defining your schema.',
|
12
12
|
recommended: true,
|
13
|
-
url: 'https://
|
13
|
+
url: 'https://the-guild.dev/graphql/eslint/rules/no-typename-prefix',
|
14
14
|
examples: [
|
15
15
|
{
|
16
16
|
title: 'Incorrect',
|
@@ -93,7 +93,7 @@ exports.rule = {
|
|
93
93
|
docs: {
|
94
94
|
description: 'Requires all types to be reachable at some level by root level fields.',
|
95
95
|
category: 'Schema',
|
96
|
-
url: `https://
|
96
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
97
97
|
requiresSchema: true,
|
98
98
|
examples: [
|
99
99
|
{
|
@@ -42,7 +42,7 @@ exports.rule = {
|
|
42
42
|
docs: {
|
43
43
|
description: 'Requires all fields to be used at some level by siblings operations.',
|
44
44
|
category: 'Schema',
|
45
|
-
url: `https://
|
45
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
46
46
|
requiresSiblings: true,
|
47
47
|
requiresSchema: true,
|
48
48
|
isDisabledForAllConfig: true,
|
@@ -41,7 +41,7 @@ exports.rule = {
|
|
41
41
|
'- `last` takes a non-negative integer',
|
42
42
|
'- `before` takes the Cursor type',
|
43
43
|
].join('\n'),
|
44
|
-
url: `https://
|
44
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
45
45
|
examples: [
|
46
46
|
{
|
47
47
|
title: 'Incorrect',
|
@@ -35,7 +35,7 @@ exports.rule = {
|
|
35
35
|
'- Connection type must contain a field `edges` that return a list type that wraps an edge type',
|
36
36
|
'- Connection type must contain a field `pageInfo` that return a non-null `PageInfo` Object type',
|
37
37
|
].join('\n'),
|
38
|
-
url: 'https://
|
38
|
+
url: 'https://the-guild.dev/graphql/eslint/rules/relay-connection-types',
|
39
39
|
isDisabledForAllConfig: true,
|
40
40
|
examples: [
|
41
41
|
{
|
@@ -82,7 +82,7 @@ exports.rule = {
|
|
82
82
|
"- Edge type's field `node` must implement `Node` interface _(optional)_",
|
83
83
|
'- A list type should only wrap an edge type _(optional)_',
|
84
84
|
].join('\n'),
|
85
|
-
url: `https://
|
85
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
86
86
|
isDisabledForAllConfig: true,
|
87
87
|
requiresSchema: true,
|
88
88
|
examples: [
|
@@ -21,7 +21,7 @@ exports.rule = {
|
|
21
21
|
'- `PageInfo` must contain fields `hasPreviousPage` and `hasNextPage`, that return non-null Boolean',
|
22
22
|
'- `PageInfo` must contain fields `startCursor` and `endCursor`, that return either String or Scalar, which can be null if there are no results',
|
23
23
|
].join('\n'),
|
24
|
-
url: `https://
|
24
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
25
25
|
examples: [
|
26
26
|
{
|
27
27
|
title: 'Correct',
|
@@ -28,7 +28,7 @@ exports.rule = {
|
|
28
28
|
docs: {
|
29
29
|
category: 'Schema',
|
30
30
|
description: 'Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.',
|
31
|
-
url: 'https://
|
31
|
+
url: 'https://the-guild.dev/graphql/eslint/rules/require-deprecation-date',
|
32
32
|
examples: [
|
33
33
|
{
|
34
34
|
title: 'Incorrect',
|
@@ -7,7 +7,7 @@ exports.rule = {
|
|
7
7
|
docs: {
|
8
8
|
description: 'Require all deprecation directives to specify a reason.',
|
9
9
|
category: 'Schema',
|
10
|
-
url: 'https://
|
10
|
+
url: 'https://the-guild.dev/graphql/eslint/rules/require-deprecation-reason',
|
11
11
|
recommended: true,
|
12
12
|
examples: [
|
13
13
|
{
|
@@ -74,7 +74,7 @@ exports.rule = {
|
|
74
74
|
docs: {
|
75
75
|
category: 'Schema',
|
76
76
|
description: 'Enforce descriptions in type definitions and operations.',
|
77
|
-
url: `https://
|
77
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
78
78
|
examples: [
|
79
79
|
{
|
80
80
|
title: 'Incorrect',
|
@@ -10,7 +10,7 @@ exports.rule = {
|
|
10
10
|
docs: {
|
11
11
|
category: 'Schema',
|
12
12
|
description: 'Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.\n> Currently, no errors are reported for result type `union`, `interface` and `scalar`.',
|
13
|
-
url: `https://
|
13
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
14
14
|
requiresSchema: true,
|
15
15
|
examples: [
|
16
16
|
{
|
@@ -34,7 +34,7 @@ exports.rule = {
|
|
34
34
|
docs: {
|
35
35
|
category: 'Operations',
|
36
36
|
description: 'Enforce selecting specific fields when they are available on the GraphQL type.',
|
37
|
-
url: `https://
|
37
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
38
38
|
requiresSchema: true,
|
39
39
|
requiresSiblings: true,
|
40
40
|
examples: [
|
@@ -9,7 +9,7 @@ exports.rule = {
|
|
9
9
|
docs: {
|
10
10
|
category: 'Schema',
|
11
11
|
description: 'Require `input` or `type` fields to be non-nullable with `@oneOf` directive.',
|
12
|
-
url: `https://
|
12
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
13
13
|
examples: [
|
14
14
|
{
|
15
15
|
title: 'Incorrect',
|
@@ -8,7 +8,7 @@ exports.rule = {
|
|
8
8
|
docs: {
|
9
9
|
category: 'Schema',
|
10
10
|
description: 'Enforce types with `@oneOf` directive have `error` and `ok` fields.',
|
11
|
-
url: `https://
|
11
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
12
12
|
examples: [
|
13
13
|
{
|
14
14
|
title: 'Correct',
|
@@ -29,7 +29,7 @@ exports.rule = {
|
|
29
29
|
docs: {
|
30
30
|
category: 'Operations',
|
31
31
|
description: 'Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://npmjs.com/package/graphql-depth-limit).',
|
32
|
-
url: `https://
|
32
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
33
33
|
requiresSiblings: true,
|
34
34
|
examples: [
|
35
35
|
{
|
@@ -43,7 +43,7 @@ exports.rule = {
|
|
43
43
|
description: '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.',
|
44
44
|
category: 'Schema',
|
45
45
|
recommended: true,
|
46
|
-
url: `https://
|
46
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
47
47
|
requiresSchema: true,
|
48
48
|
examples: [
|
49
49
|
{
|
@@ -39,7 +39,7 @@ exports.rule = {
|
|
39
39
|
docs: {
|
40
40
|
category: 'Operations',
|
41
41
|
description: 'Enforce unique fragment names across your project.',
|
42
|
-
url: `https://
|
42
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
43
43
|
requiresSiblings: true,
|
44
44
|
examples: [
|
45
45
|
{
|
@@ -9,7 +9,7 @@ exports.rule = {
|
|
9
9
|
docs: {
|
10
10
|
category: 'Operations',
|
11
11
|
description: 'Enforce unique operation names across your project.',
|
12
|
-
url: `https://
|
12
|
+
url: `https://the-guild.dev/graphql/eslint/rules/${RULE_ID}`,
|
13
13
|
requiresSiblings: true,
|
14
14
|
examples: [
|
15
15
|
{
|
package/cjs/siblings.js
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getSiblings = void 0;
|
4
|
+
const utils_1 = require("@graphql-tools/utils");
|
5
|
+
const graphql_1 = require("graphql");
|
6
|
+
const documents_js_1 = require("./documents.js");
|
7
|
+
const utils_js_1 = require("./utils.js");
|
8
|
+
const siblingOperationsCache = new Map();
|
9
|
+
function getSiblings(project, documents) {
|
10
|
+
const siblings = project
|
11
|
+
? (0, documents_js_1.getDocuments)(project)
|
12
|
+
: typeof documents === 'string'
|
13
|
+
? [(0, utils_1.parseGraphQLSDL)('operation.graphql', documents, { noLocation: true })]
|
14
|
+
: [];
|
15
|
+
if (siblings.length === 0) {
|
16
|
+
let printed = false;
|
17
|
+
const noopWarn = () => {
|
18
|
+
if (!printed) {
|
19
|
+
utils_js_1.logger.warn('getSiblingOperations was called without any operations. Make sure to set "parserOptions.operations" to make this feature available!');
|
20
|
+
printed = true;
|
21
|
+
}
|
22
|
+
return [];
|
23
|
+
};
|
24
|
+
return {
|
25
|
+
available: false,
|
26
|
+
getFragment: noopWarn,
|
27
|
+
getFragments: noopWarn,
|
28
|
+
getFragmentByType: noopWarn,
|
29
|
+
getFragmentsInUse: noopWarn,
|
30
|
+
getOperation: noopWarn,
|
31
|
+
getOperations: noopWarn,
|
32
|
+
getOperationByType: noopWarn,
|
33
|
+
};
|
34
|
+
}
|
35
|
+
// Since the siblings array is cached, we can use it as cache key.
|
36
|
+
// We should get the same array reference each time we get
|
37
|
+
// to this point for the same graphql project
|
38
|
+
const value = siblingOperationsCache.get(siblings);
|
39
|
+
if (value) {
|
40
|
+
return value;
|
41
|
+
}
|
42
|
+
let fragmentsCache = null;
|
43
|
+
const getFragments = () => {
|
44
|
+
var _a;
|
45
|
+
if (fragmentsCache === null) {
|
46
|
+
const result = [];
|
47
|
+
for (const source of siblings) {
|
48
|
+
for (const definition of ((_a = source.document) === null || _a === void 0 ? void 0 : _a.definitions) || []) {
|
49
|
+
if (definition.kind === graphql_1.Kind.FRAGMENT_DEFINITION) {
|
50
|
+
result.push({
|
51
|
+
filePath: source.location,
|
52
|
+
document: definition,
|
53
|
+
});
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
fragmentsCache = result;
|
58
|
+
}
|
59
|
+
return fragmentsCache;
|
60
|
+
};
|
61
|
+
let cachedOperations = null;
|
62
|
+
const getOperations = () => {
|
63
|
+
var _a;
|
64
|
+
if (cachedOperations === null) {
|
65
|
+
const result = [];
|
66
|
+
for (const source of siblings) {
|
67
|
+
for (const definition of ((_a = source.document) === null || _a === void 0 ? void 0 : _a.definitions) || []) {
|
68
|
+
if (definition.kind === graphql_1.Kind.OPERATION_DEFINITION) {
|
69
|
+
result.push({
|
70
|
+
filePath: source.location,
|
71
|
+
document: definition,
|
72
|
+
});
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
cachedOperations = result;
|
77
|
+
}
|
78
|
+
return cachedOperations;
|
79
|
+
};
|
80
|
+
const getFragment = (name) => getFragments().filter(f => { var _a; return ((_a = f.document.name) === null || _a === void 0 ? void 0 : _a.value) === name; });
|
81
|
+
const collectFragments = (selectable, recursive, collected = new Map()) => {
|
82
|
+
(0, graphql_1.visit)(selectable, {
|
83
|
+
FragmentSpread(spread) {
|
84
|
+
const fragmentName = spread.name.value;
|
85
|
+
const [fragment] = getFragment(fragmentName);
|
86
|
+
if (!fragment) {
|
87
|
+
utils_js_1.logger.warn(`Unable to locate fragment named "${fragmentName}", please make sure it's loaded using "parserOptions.operations"`);
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
if (!collected.has(fragmentName)) {
|
91
|
+
collected.set(fragmentName, fragment.document);
|
92
|
+
if (recursive) {
|
93
|
+
collectFragments(fragment.document, recursive, collected);
|
94
|
+
}
|
95
|
+
}
|
96
|
+
},
|
97
|
+
});
|
98
|
+
return collected;
|
99
|
+
};
|
100
|
+
const siblingOperations = {
|
101
|
+
available: true,
|
102
|
+
getFragment,
|
103
|
+
getFragments,
|
104
|
+
getFragmentByType: typeName => getFragments().filter(f => { var _a, _b; return ((_b = (_a = f.document.typeCondition) === null || _a === void 0 ? void 0 : _a.name) === null || _b === void 0 ? void 0 : _b.value) === typeName; }),
|
105
|
+
getFragmentsInUse: (selectable, recursive = true) => Array.from(collectFragments(selectable, recursive).values()),
|
106
|
+
getOperation: name => getOperations().filter(o => { var _a; return ((_a = o.document.name) === null || _a === void 0 ? void 0 : _a.value) === name; }),
|
107
|
+
getOperations,
|
108
|
+
getOperationByType: type => getOperations().filter(o => o.document.operation === type),
|
109
|
+
};
|
110
|
+
siblingOperationsCache.set(siblings, siblingOperations);
|
111
|
+
return siblingOperations;
|
112
|
+
}
|
113
|
+
exports.getSiblings = getSiblings;
|
package/cjs/utils.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.truthy = exports.englishJoinWords = exports.ARRAY_DEFAULT_OPTIONS = exports.REPORT_ON_FIRST_CHARACTER = exports.getLocation = exports.convertCase = exports.camelCase = exports.pascalCase = exports.TYPES_KINDS = exports.getTypeName = exports.CWD = exports.VIRTUAL_DOCUMENT_REGEX = exports.normalizePath = exports.logger = exports.requireGraphQLSchemaFromContext = exports.requireSiblingsOperations = void 0;
|
3
|
+
exports.truthy = exports.englishJoinWords = exports.ARRAY_DEFAULT_OPTIONS = exports.REPORT_ON_FIRST_CHARACTER = exports.getLocation = exports.convertCase = exports.camelCase = exports.pascalCase = exports.TYPES_KINDS = exports.getTypeName = exports.IS_BROWSER = exports.CWD = exports.VIRTUAL_DOCUMENT_REGEX = exports.normalizePath = exports.logger = exports.requireGraphQLSchemaFromContext = exports.requireSiblingsOperations = void 0;
|
4
4
|
const tslib_1 = require("tslib");
|
5
5
|
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
6
6
|
const graphql_1 = require("graphql");
|
@@ -36,6 +36,7 @@ const normalizePath = (path) => (path || '').replace(/\\/g, '/');
|
|
36
36
|
exports.normalizePath = normalizePath;
|
37
37
|
exports.VIRTUAL_DOCUMENT_REGEX = /\/\d+_document.graphql$/;
|
38
38
|
exports.CWD = process.cwd();
|
39
|
+
exports.IS_BROWSER = typeof window !== 'undefined';
|
39
40
|
const getTypeName = (node) => 'type' in node ? (0, exports.getTypeName)(node.type) : 'name' in node && node.name ? node.name.value : '';
|
40
41
|
exports.getTypeName = getTypeName;
|
41
42
|
exports.TYPES_KINDS = [
|
package/docs/README.md
CHANGED
@@ -1,85 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
Each rule has emojis denoting:
|
4
|
-
|
5
|
-
- 📄 if the rule applies to schema documents
|
6
|
-
- 📦 if the rule applies to operations
|
7
|
-
- 🚀 `graphql-eslint` rule
|
8
|
-
- 🔮 `graphql-js` rule
|
9
|
-
- 🔧 if some problems reported by the rule are automatically fixable by the `--fix`
|
10
|
-
[command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) option
|
11
|
-
- 💡 if some problems reported by the rule are manually fixable by editor
|
12
|
-
[suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions)
|
13
|
-
|
14
|
-
<!-- 🚨 IMPORTANT! Do not manually modify this table. Run: `yarn generate:docs` -->
|
15
|
-
<!-- prettier-ignore-start -->
|
16
|
-
Name |Description| Config |📄 / 📦|🚀 / 🔮|🔧 / 💡
|
17
|
-
-|-|:-:|:-:|:-:|:-:
|
18
|
-
[alphabetize](rules/alphabetize.md)|Enforce arrange in alphabetical order for type fields, enum values, input object fields, operation selections and more.|![all][]|📄 📦|🚀|🔧
|
19
|
-
[description-style](rules/description-style.md)|Require all comments to follow the same style (either block or inline).|![recommended][]|📄|🚀|💡
|
20
|
-
[executable-definitions](rules/executable-definitions.md)|A GraphQL document is only valid for execution if all definitions are either operation or fragment definitions.|![recommended][]|📦|🔮|
|
21
|
-
[fields-on-correct-type](rules/fields-on-correct-type.md)|A GraphQL document is only valid if all fields selected are defined by the parent type, or are an allowed meta field such as `__typename`.|![recommended][]|📦|🔮|💡
|
22
|
-
[fragments-on-composite-type](rules/fragments-on-composite-type.md)|Fragments use a type condition to determine if they apply, since fragments can only be spread into a composite type (object, interface, or union), the type condition must also be a composite type.|![recommended][]|📦|🔮|
|
23
|
-
[input-name](rules/input-name.md)|Require mutation argument to be always called "input" and input type to be called Mutation name + "Input".|![all][]|📄|🚀|💡
|
24
|
-
[known-argument-names](rules/known-argument-names.md)|A GraphQL field is only valid if all supplied arguments are defined by that field.|![recommended][]|📄 📦|🔮|💡
|
25
|
-
[known-directives](rules/known-directives.md)|A GraphQL document is only valid if all `@directive`s are known by the schema and legally positioned.|![recommended][]|📄 📦|🔮|
|
26
|
-
[known-fragment-names](rules/known-fragment-names.md)|A GraphQL document is only valid if all `...Fragment` fragment spreads refer to fragments defined in the same document.|![recommended][]|📦|🔮|
|
27
|
-
[known-type-names](rules/known-type-names.md)|A GraphQL document is only valid if referenced types (specifically variable definitions and fragment conditions) are defined by the type schema.|![recommended][]|📄 📦|🔮|💡
|
28
|
-
[lone-anonymous-operation](rules/lone-anonymous-operation.md)|A GraphQL document that contains an anonymous operation (the `query` short-hand) is only valid if it contains only that one operation definition.|![recommended][]|📦|🔮|
|
29
|
-
[lone-executable-definition](rules/lone-executable-definition.md)|Require queries, mutations, subscriptions or fragments to be located in separate files.|![all][]|📦|🚀|
|
30
|
-
[lone-schema-definition](rules/lone-schema-definition.md)|A GraphQL document is only valid if it contains only one schema definition.|![recommended][]|📄|🔮|
|
31
|
-
[match-document-filename](rules/match-document-filename.md)|This rule allows you to enforce that the file name should match the operation name.|![all][]|📦|🚀|
|
32
|
-
[naming-convention](rules/naming-convention.md)|Require names to follow specified conventions.|![recommended][]|📄 📦|🚀|💡
|
33
|
-
[no-anonymous-operations](rules/no-anonymous-operations.md)|Require name for your GraphQL operations. This is useful since most GraphQL client libraries are using the operation name for caching purposes.|![recommended][]|📦|🚀|💡
|
34
|
-
[no-case-insensitive-enum-values-duplicates](rules/no-case-insensitive-enum-values-duplicates.md)|Disallow case-insensitive enum values duplicates.|![recommended][]|📄|🚀|💡
|
35
|
-
[no-deprecated](rules/no-deprecated.md)|Enforce that deprecated fields or enum values are not in use by operations.|![recommended][]|📦|🚀|💡
|
36
|
-
[no-duplicate-fields](rules/no-duplicate-fields.md)|Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.|![recommended][]|📦|🚀|💡
|
37
|
-
[no-fragment-cycles](rules/no-fragment-cycles.md)|A GraphQL fragment is only valid when it does not have cycles in fragments usage.|![recommended][]|📦|🔮|
|
38
|
-
[no-hashtag-description](rules/no-hashtag-description.md)|Requires to use `"""` or `"` for adding a GraphQL description instead of `#`.|![recommended][]|📄|🚀|💡
|
39
|
-
[no-one-place-fragments](rules/no-one-place-fragments.md)|Disallow fragments that are used only in one place.|![all][]|📦|🚀|
|
40
|
-
[no-root-type](rules/no-root-type.md)|Disallow using root types `mutation` and/or `subscription`.||📄|🚀|💡
|
41
|
-
[no-scalar-result-type-on-mutation](rules/no-scalar-result-type-on-mutation.md)|Avoid scalar result type on mutation type to make sure to return a valid state.|![all][]|📄|🚀|💡
|
42
|
-
[no-typename-prefix](rules/no-typename-prefix.md)|Enforces users to avoid using the type name in a field name while defining your schema.|![recommended][]|📄|🚀|💡
|
43
|
-
[no-undefined-variables](rules/no-undefined-variables.md)|A GraphQL operation is only valid if all variables encountered, both directly and via fragment spreads, are defined by that operation.|![recommended][]|📦|🔮|
|
44
|
-
[no-unreachable-types](rules/no-unreachable-types.md)|Requires all types to be reachable at some level by root level fields.|![recommended][]|📄|🚀|💡
|
45
|
-
[no-unused-fields](rules/no-unused-fields.md)|Requires all fields to be used at some level by siblings operations.||📄|🚀|💡
|
46
|
-
[no-unused-fragments](rules/no-unused-fragments.md)|A GraphQL document is only valid if all fragment definitions are spread within operations, or spread within other fragments spread within operations.|![recommended][]|📦|🔮|
|
47
|
-
[no-unused-variables](rules/no-unused-variables.md)|A GraphQL operation is only valid if all variables defined by an operation are used, either directly or within a spread fragment.|![recommended][]|📦|🔮|
|
48
|
-
[one-field-subscriptions](rules/one-field-subscriptions.md)|A GraphQL subscription is valid only if it contains a single root field.|![recommended][]|📦|🔮|
|
49
|
-
[overlapping-fields-can-be-merged](rules/overlapping-fields-can-be-merged.md)|A selection set is only valid if all fields (including spreading any fragments) either correspond to distinct response names or can be merged without ambiguity.|![recommended][]|📦|🔮|
|
50
|
-
[possible-fragment-spread](rules/possible-fragment-spread.md)|A fragment spread is only valid if the type condition could ever possibly be true: if there is a non-empty intersection of the possible parent types, and possible types which pass the type condition.|![recommended][]|📦|🔮|
|
51
|
-
[possible-type-extension](rules/possible-type-extension.md)|A type extension is only valid if the type is defined and has the same kind.||📄|🔮|💡
|
52
|
-
[provided-required-arguments](rules/provided-required-arguments.md)|A field or directive is only valid if all required (non-null without a default value) field arguments have been provided.|![recommended][]|📄 📦|🔮|
|
53
|
-
[relay-arguments](rules/relay-arguments.md)|Set of rules to follow Relay specification for Arguments.|![relay][]|📄|🚀|
|
54
|
-
[relay-connection-types](rules/relay-connection-types.md)|Set of rules to follow Relay specification for Connection types.|![relay][]|📄|🚀|
|
55
|
-
[relay-edge-types](rules/relay-edge-types.md)|Set of rules to follow Relay specification for Edge types.|![relay][]|📄|🚀|
|
56
|
-
[relay-page-info](rules/relay-page-info.md)|Set of rules to follow Relay specification for `PageInfo` object.|![relay][]|📄|🚀|
|
57
|
-
[require-deprecation-date](rules/require-deprecation-date.md)|Require deletion date on `@deprecated` directive. Suggest removing deprecated things after deprecated date.|![all][]|📄|🚀|💡
|
58
|
-
[require-deprecation-reason](rules/require-deprecation-reason.md)|Require all deprecation directives to specify a reason.|![recommended][]|📄|🚀|
|
59
|
-
[require-description](rules/require-description.md)|Enforce descriptions in type definitions and operations.|![recommended][]|📄|🚀|
|
60
|
-
[require-field-of-type-query-in-mutation-result](rules/require-field-of-type-query-in-mutation-result.md)|Allow the client in one round-trip not only to call mutation but also to get a wagon of data to update their application.|![all][]|📄|🚀|
|
61
|
-
[require-id-when-available](rules/require-id-when-available.md)|Enforce selecting specific fields when they are available on the GraphQL type.|![recommended][]|📦|🚀|💡
|
62
|
-
[require-nullable-fields-with-oneof](rules/require-nullable-fields-with-oneof.md)|Require `input` or `type` fields to be non-nullable with `@oneOf` directive.|![all][]|📄|🚀|
|
63
|
-
[require-type-pattern-with-oneof](rules/require-type-pattern-with-oneof.md)|Enforce types with `@oneOf` directive have `error` and `ok` fields.|![all][]|📄|🚀|
|
64
|
-
[scalar-leafs](rules/scalar-leafs.md)|A GraphQL document is valid only if all leaf fields (fields without sub selections) are of scalar or enum types.|![recommended][]|📦|🔮|💡
|
65
|
-
[selection-set-depth](rules/selection-set-depth.md)|Limit the complexity of the GraphQL operations solely by their depth. Based on [graphql-depth-limit](https://npmjs.com/package/graphql-depth-limit).|![recommended][]|📦|🚀|💡
|
66
|
-
[strict-id-in-types](rules/strict-id-in-types.md)|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.|![recommended][]|📄|🚀|
|
67
|
-
[unique-argument-names](rules/unique-argument-names.md)|A GraphQL field or directive is only valid if all supplied arguments are uniquely named.|![recommended][]|📦|🔮|
|
68
|
-
[unique-directive-names](rules/unique-directive-names.md)|A GraphQL document is only valid if all defined directives have unique names.|![recommended][]|📄|🔮|
|
69
|
-
[unique-directive-names-per-location](rules/unique-directive-names-per-location.md)|A GraphQL document is only valid if all non-repeatable directives at a given location are uniquely named.|![recommended][]|📄 📦|🔮|
|
70
|
-
[unique-enum-value-names](rules/unique-enum-value-names.md)|A GraphQL enum type is only valid if all its values are uniquely named.||📄|🔮|
|
71
|
-
[unique-field-definition-names](rules/unique-field-definition-names.md)|A GraphQL complex type is only valid if all its fields are uniquely named.|![recommended][]|📄|🔮|
|
72
|
-
[unique-fragment-name](rules/unique-fragment-name.md)|Enforce unique fragment names across your project.|![all][]|📦|🚀|
|
73
|
-
[unique-input-field-names](rules/unique-input-field-names.md)|A GraphQL input object value is only valid if all supplied fields are uniquely named.|![recommended][]|📦|🔮|
|
74
|
-
[unique-operation-name](rules/unique-operation-name.md)|Enforce unique operation names across your project.|![all][]|📦|🚀|
|
75
|
-
[unique-operation-types](rules/unique-operation-types.md)|A GraphQL document is only valid if it has only one type per operation.|![recommended][]|📄|🔮|
|
76
|
-
[unique-type-names](rules/unique-type-names.md)|A GraphQL document is only valid if all defined types have unique names.|![recommended][]|📄|🔮|
|
77
|
-
[unique-variable-names](rules/unique-variable-names.md)|A GraphQL operation is only valid if all its variables are uniquely named.|![recommended][]|📦|🔮|
|
78
|
-
[value-literals-of-correct-type](rules/value-literals-of-correct-type.md)|A GraphQL document is only valid if all value literals are of the type expected at their position.|![recommended][]|📦|🔮|💡
|
79
|
-
[variables-are-input-types](rules/variables-are-input-types.md)|A GraphQL operation is only valid if all the variables it defines are of input types (scalar, enum, or input object).|![recommended][]|📦|🔮|
|
80
|
-
[variables-in-allowed-position](rules/variables-in-allowed-position.md)|Variables passed to field arguments conform to type.|![recommended][]|📦|🔮|
|
81
|
-
<!-- prettier-ignore-end -->
|
82
|
-
|
83
|
-
[recommended]: https://img.shields.io/badge/-recommended-green.svg
|
84
|
-
[all]: https://img.shields.io/badge/-all-blue.svg
|
85
|
-
[relay]: https://img.shields.io/badge/-relay-orange.svg
|
1
|
+
website/src/pages/rules/index.mdx
|
package/docs/custom-rules.md
CHANGED
@@ -1,184 +1 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
To get started with your own rules, start by understanding how
|
4
|
-
[ESLint custom rules works](https://eslint.org/docs/developer-guide/working-with-rules).
|
5
|
-
|
6
|
-
`graphql-eslint` converts the [GraphQL AST](https://graphql.org/graphql-js/language) into
|
7
|
-
[ESTree structure](https://github.com/estree/estree), so it allows you to easily travel the GraphQL
|
8
|
-
AST tree easily.
|
9
|
-
|
10
|
-
You can visit any GraphQL AST node in your custom rules, and report this as error. You don't need to
|
11
|
-
have special handlers for code-files, since `graphql-eslint` extracts usages of `gql` and magic
|
12
|
-
`/* GraphQL */` comments automatically, and runs it through the parser, and eventually it knows to
|
13
|
-
adjust errors location to fit in your code files original location.
|
14
|
-
|
15
|
-
You can explore the GraphQL AST for a given input on
|
16
|
-
[astexplorer.net](https://astexplorer.net/#/gist/e72aaccc1e57cbba41659d73cabbf75c/f10ee29317a31ff8012a21762a382c4a03c34d40).
|
17
|
-
|
18
|
-
## Getting Started
|
19
|
-
|
20
|
-
Start by creating a
|
21
|
-
[simple ESLint rule file](https://eslint.org/docs/developer-guide/working-with-rules), and choose
|
22
|
-
the AST nodes you wish to visit. It can either be a
|
23
|
-
[simple AST node `Kind`](https://github.com/graphql/graphql-js/blob/master/src/language/kinds.d.ts)
|
24
|
-
or a complex [ESLint selector](https://eslint.org/docs/developer-guide/selectors) that allows you to
|
25
|
-
travel and filter AST nodes.
|
26
|
-
|
27
|
-
We recommend you to read the [graphql-eslint parser documentation](parser.md) before getting
|
28
|
-
started, to understand the differences between the AST structures.
|
29
|
-
|
30
|
-
The `graphql-eslint` comes with a TypeScript wrapper for ESLint rules, and provides a testkit to
|
31
|
-
simplify testing process with GraphQL schemas, so you can use that by importing `GraphQLESLintRule`
|
32
|
-
type. But if you wish to use JavaScript - that's fine :)
|
33
|
-
|
34
|
-
Here's an example for a simple rule that reports on anonymous GraphQL operations:
|
35
|
-
|
36
|
-
```ts
|
37
|
-
import { GraphQLESLintRule } from '@graphql-eslint/eslint-plugin'
|
38
|
-
|
39
|
-
const rule: GraphQLESLintRule = {
|
40
|
-
create(context) {
|
41
|
-
return {
|
42
|
-
OperationDefinition(node) {
|
43
|
-
if (!node.name?.value) {
|
44
|
-
context.report({
|
45
|
-
node,
|
46
|
-
message: 'Oops, name is required!'
|
47
|
-
})
|
48
|
-
}
|
49
|
-
}
|
50
|
-
}
|
51
|
-
}
|
52
|
-
}
|
53
|
-
```
|
54
|
-
|
55
|
-
So what happens here?
|
56
|
-
|
57
|
-
1. `@graphql-eslint/eslint-plugin` handles the parsing process for your GraphQL content. It will
|
58
|
-
load the GraphQL files (either from code files or from `.graphql` files with SDL), parse it using
|
59
|
-
GraphQL parser, converts it to ESTree structure and let ESLint do the rest.
|
60
|
-
1. Your rule is being loaded by ESLint, and executes just like any other ESLint rule.
|
61
|
-
1. Our custom rule asks ESLint to run our function for every `OperationDefinition` found.
|
62
|
-
1. If the `OperationDefinition` node doesn't have a valid `name` - we report an error to ESLint.
|
63
|
-
|
64
|
-
#### More Examples
|
65
|
-
|
66
|
-
You can scan the `packages/plugin/src/rules` directory in this repo for references for implementing
|
67
|
-
rules. It coverts most of the use-cases and concepts of rules.
|
68
|
-
|
69
|
-
## Accessing original GraphQL AST nodes
|
70
|
-
|
71
|
-
Since our parser converts GraphQL AST to ESTree structure, there are some minor differences in the
|
72
|
-
structure of the objects. If you are using TypeScript, and you typed your rule with
|
73
|
-
`GraphQLESLintRule` - you'll see that each `node` is a bit different from the AST nodes of GraphQL
|
74
|
-
(you can read more about that in [graphql-eslint parser documentation](parser.md)).
|
75
|
-
|
76
|
-
If you need access to the original GraphQL AST `node`, you can use `.rawNode()` method on each node
|
77
|
-
you get from the AST structure of ESLint.
|
78
|
-
|
79
|
-
This is useful if you wish to use other GraphQL tools that works with the original GraphQL AST
|
80
|
-
objects.
|
81
|
-
|
82
|
-
Here's an example for using original `graphql-js` validate method to validate `OperationDefinition`:
|
83
|
-
|
84
|
-
```ts
|
85
|
-
import { requireGraphQLSchemaFromContext } from '@graphql-eslint/eslint-plugin'
|
86
|
-
import { validate } from 'graphql'
|
87
|
-
|
88
|
-
export const rule = {
|
89
|
-
create(context) {
|
90
|
-
return {
|
91
|
-
OperationDefinition(node) {
|
92
|
-
const schema = requireGraphQLSchemaFromContext(context)
|
93
|
-
|
94
|
-
validate(context, schema, {
|
95
|
-
kind: Kind.DOCUMENT,
|
96
|
-
definitions: [node.rawNode()]
|
97
|
-
})
|
98
|
-
}
|
99
|
-
}
|
100
|
-
}
|
101
|
-
}
|
102
|
-
```
|
103
|
-
|
104
|
-
## `TypeInfo` / `GraphQLSchema`
|
105
|
-
|
106
|
-
If you provide GraphQL schema in your ESLint configuration, it will get loaded automatically, and
|
107
|
-
become available in your rules in two ways:
|
108
|
-
|
109
|
-
1. You'll be able to access the loaded `GraphQLSchema` object.
|
110
|
-
2. In every visited node, you'll be able to use `.typeInfo()` method to get an object with complete
|
111
|
-
type information on your visited node (see
|
112
|
-
[TypeInfo documentation](https://graphql.org/graphql-js/utilities/#typeinfo)).
|
113
|
-
|
114
|
-
#### Getting `GraphQLSchema`
|
115
|
-
|
116
|
-
To mark your ESLint rules as a rule that needs access to GraphQL schema, start by running
|
117
|
-
`requireGraphQLSchemaFromContext` from the plugin package, it will make sure to return a schema, or
|
118
|
-
throw an error for the user about the missing schema.
|
119
|
-
|
120
|
-
```ts
|
121
|
-
const schema = requireGraphQLSchemaFromContext(context)
|
122
|
-
```
|
123
|
-
|
124
|
-
#### Accessing TypeInfo
|
125
|
-
|
126
|
-
If schema is provided and loaded successfully, the `typeInfo` will be available to use. Otherwise -
|
127
|
-
it will be `undefined`. If your plugin requires `typeInfo` in order to operate and run, make sure to
|
128
|
-
call `requireGraphQLSchemaFromContext` - it will validate that the schema is loaded.
|
129
|
-
|
130
|
-
`typeInfo` is provided on every node, based on the type of that node, for example, to access the
|
131
|
-
`GraphQLOutputType` while you are visiting a `SelectionSet` node, you can do:
|
132
|
-
|
133
|
-
```ts
|
134
|
-
import { requireGraphQLSchemaFromContext } from '@graphql-eslint/eslint-plugin'
|
135
|
-
|
136
|
-
export const rule = {
|
137
|
-
create(context) {
|
138
|
-
requireGraphQLSchemaFromContext('your-rule-name', context)
|
139
|
-
|
140
|
-
return {
|
141
|
-
SelectionSet(node) {
|
142
|
-
const typeInfo = node.typeInfo()
|
143
|
-
if (typeInfo.gqlType) {
|
144
|
-
console.log(`The GraphQLOutputType is: ${typeInfo.gqlType}`)
|
145
|
-
}
|
146
|
-
}
|
147
|
-
}
|
148
|
-
}
|
149
|
-
}
|
150
|
-
```
|
151
|
-
|
152
|
-
The structure of the return value of `.typeInfo()` is
|
153
|
-
[defined here](https://github.com/B2o5T/graphql-eslint/blob/master/packages/plugin/src/estree-converter/converter.ts#L32-L40).
|
154
|
-
So based on the `node` you are using, you'll get a different values on `.typeInfo()` result.
|
155
|
-
|
156
|
-
## Testing your rules
|
157
|
-
|
158
|
-
To test your rules, you can either use the wrapped `GraphQLRuleTester` from this library, or use the
|
159
|
-
built-it [`RuleTester`](https://eslint.org/docs/developer-guide/working-with-rules#rule-unit-tests)
|
160
|
-
of ESLint.
|
161
|
-
|
162
|
-
The wrapped `GraphQLRuleTester` provides built-in configured parser, and a schema loader, if you
|
163
|
-
need to test your rule with a loaded schema.
|
164
|
-
|
165
|
-
```ts
|
166
|
-
import { GraphQLRuleTester } from '@graphql-eslint/eslint-plugin'
|
167
|
-
import { rule } from './my-rule'
|
168
|
-
|
169
|
-
const ruleTester = new GraphQLRuleTester()
|
170
|
-
|
171
|
-
ruleTester.runGraphQLTests('my-rule', rule, {
|
172
|
-
valid: [
|
173
|
-
{
|
174
|
-
code: 'query something { foo }'
|
175
|
-
}
|
176
|
-
],
|
177
|
-
invalid: [
|
178
|
-
{
|
179
|
-
code: 'query invalid { foo }',
|
180
|
-
errors: [{ message: 'Your error message.' }]
|
181
|
-
}
|
182
|
-
]
|
183
|
-
})
|
184
|
-
```
|
1
|
+
website/src/pages/docs/custom-rules.mdx
|