Skip to content

Commit af22d9d

Browse files
authored
chore: clarify report message for require-description rule (#928)
1 parent 411ebe9 commit af22d9d

File tree

5 files changed

+129
-160
lines changed

5 files changed

+129
-160
lines changed

.changeset/fuzzy-chairs-tease.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@graphql-eslint/eslint-plugin': patch
3+
---
4+
5+
chore: clarify report message for `require-description` rule

packages/plugin/src/rules/require-description.ts

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { ASTKindToNode, Kind, TokenKind } from 'graphql';
1+
import { ASTKindToNode, Kind, NameNode, TokenKind } from 'graphql';
22
import { GraphQLESLintRule, ValueOf } from '../types';
33
import { getLocation, TYPES_KINDS } from '../utils';
44
import { GraphQLESTreeNode } from '../estree-parser/estree-ast';
@@ -7,22 +7,53 @@ const RULE_ID = 'require-description';
77

88
const ALLOWED_KINDS = [
99
...TYPES_KINDS,
10+
Kind.DIRECTIVE_DEFINITION,
1011
Kind.FIELD_DEFINITION,
1112
Kind.INPUT_VALUE_DEFINITION,
1213
Kind.ENUM_VALUE_DEFINITION,
13-
Kind.DIRECTIVE_DEFINITION,
1414
Kind.OPERATION_DEFINITION,
1515
] as const;
1616

1717
type AllowedKind = typeof ALLOWED_KINDS[number];
1818
type AllowedKindToNode = Pick<ASTKindToNode, AllowedKind>;
19+
type SelectorNode = GraphQLESTreeNode<ValueOf<AllowedKindToNode>> & { parent: { name: NameNode } };
1920

2021
export type RequireDescriptionRuleConfig = {
2122
types?: boolean;
2223
} & {
2324
[key in AllowedKind]?: boolean;
2425
};
2526

27+
function getNodeName(node: SelectorNode) {
28+
const DisplayNodeNameMap = {
29+
[Kind.OBJECT_TYPE_DEFINITION]: 'type',
30+
[Kind.INTERFACE_TYPE_DEFINITION]: 'interface',
31+
[Kind.ENUM_TYPE_DEFINITION]: 'enum',
32+
[Kind.SCALAR_TYPE_DEFINITION]: 'scalar',
33+
[Kind.INPUT_OBJECT_TYPE_DEFINITION]: 'input',
34+
[Kind.UNION_TYPE_DEFINITION]: 'union',
35+
[Kind.DIRECTIVE_DEFINITION]: 'directive',
36+
} as const;
37+
38+
switch (node.kind) {
39+
case Kind.OBJECT_TYPE_DEFINITION:
40+
case Kind.INTERFACE_TYPE_DEFINITION:
41+
case Kind.ENUM_TYPE_DEFINITION:
42+
case Kind.SCALAR_TYPE_DEFINITION:
43+
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
44+
case Kind.UNION_TYPE_DEFINITION:
45+
return `${DisplayNodeNameMap[node.kind]} ${node.name.value}`;
46+
case Kind.DIRECTIVE_DEFINITION:
47+
return `${DisplayNodeNameMap[node.kind]} @${node.name.value}`;
48+
case Kind.FIELD_DEFINITION:
49+
case Kind.INPUT_VALUE_DEFINITION:
50+
case Kind.ENUM_VALUE_DEFINITION:
51+
return `${node.parent.name.value}.${node.name.value}`;
52+
case Kind.OPERATION_DEFINITION:
53+
return node.name ? `${node.operation} ${node.name.value}` : node.operation;
54+
}
55+
}
56+
2657
const rule: GraphQLESLintRule<[RequireDescriptionRuleConfig]> = {
2758
meta: {
2859
docs: {
@@ -75,7 +106,7 @@ const rule: GraphQLESLintRule<[RequireDescriptionRuleConfig]> = {
75106
},
76107
type: 'suggestion',
77108
messages: {
78-
[RULE_ID]: 'Description is required for nodes of type "{{ nodeType }}"',
109+
[RULE_ID]: 'Description is required for `{{ nodeName }}`.',
79110
},
80111
schema: {
81112
type: 'array',
@@ -118,7 +149,7 @@ const rule: GraphQLESLintRule<[RequireDescriptionRuleConfig]> = {
118149
const selector = [...kinds].join(',');
119150

120151
return {
121-
[selector](node: GraphQLESTreeNode<ValueOf<AllowedKindToNode>>) {
152+
[selector](node: SelectorNode) {
122153
let description = '';
123154
const isOperation = node.kind === Kind.OPERATION_DEFINITION;
124155
if (isOperation) {
@@ -140,7 +171,7 @@ const rule: GraphQLESLintRule<[RequireDescriptionRuleConfig]> = {
140171
loc: isOperation ? getLocation(node.loc, node.operation) : getLocation(node.name.loc, node.name.value),
141172
messageId: RULE_ID,
142173
data: {
143-
nodeType: node.kind,
174+
nodeName: getNodeName(node),
144175
},
145176
});
146177
}

packages/plugin/tests/__snapshots__/examples.spec.ts.snap

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ Array [
3535
filePath: examples/basic/schema.graphql,
3636
messages: Array [
3737
Object {
38-
message: Description is required for nodes of type "FieldDefinition",
38+
message: Description is required for \`Query.user\`.,
3939
ruleId: @graphql-eslint/require-description,
4040
},
4141
Object {
42-
message: Description is required for nodes of type "FieldDefinition",
42+
message: Description is required for \`User.id\`.,
4343
ruleId: @graphql-eslint/require-description,
4444
},
4545
Object {
46-
message: Description is required for nodes of type "FieldDefinition",
46+
message: Description is required for \`User.name\`.,
4747
ruleId: @graphql-eslint/require-description,
4848
},
4949
],

packages/plugin/tests/__snapshots__/require-description.spec.ts.snap

Lines changed: 29 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -1,148 +1,60 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

33
exports[` 1`] = `
4-
1 |
5-
2 | input SalaryDecimalOperatorsFilterUpdateOneUserInput {
6-
> 3 | gt: BSONDecimal
7-
| ^^ Description is required for nodes of type "InputValueDefinition"
8-
4 | gte: BSONDecimal
9-
5 | lt: BSONDecimal
10-
6 | lte: BSONDecimal
11-
7 | ne: BSONDecimal
12-
8 | in: [BSONDecimal]
13-
9 | nin: [BSONDecimal]
14-
10 | }
15-
11 |
4+
> 1 | type User { id: ID }
5+
| ^^^^ Description is required for \`type User\`.
166
`;
177

188
exports[` 2`] = `
19-
1 |
20-
2 | input SalaryDecimalOperatorsFilterUpdateOneUserInput {
21-
3 | gt: BSONDecimal
22-
> 4 | gte: BSONDecimal
23-
| ^^^ Description is required for nodes of type "InputValueDefinition"
24-
5 | lt: BSONDecimal
25-
6 | lte: BSONDecimal
26-
7 | ne: BSONDecimal
27-
8 | in: [BSONDecimal]
28-
9 | nin: [BSONDecimal]
29-
10 | }
30-
11 |
9+
> 1 | interface Node { id: ID! }
10+
| ^^^^ Description is required for \`interface Node\`.
3111
`;
3212

3313
exports[` 3`] = `
34-
1 |
35-
2 | input SalaryDecimalOperatorsFilterUpdateOneUserInput {
36-
3 | gt: BSONDecimal
37-
4 | gte: BSONDecimal
38-
> 5 | lt: BSONDecimal
39-
| ^^ Description is required for nodes of type "InputValueDefinition"
40-
6 | lte: BSONDecimal
41-
7 | ne: BSONDecimal
42-
8 | in: [BSONDecimal]
43-
9 | nin: [BSONDecimal]
44-
10 | }
45-
11 |
14+
> 1 | enum Role { ADMIN }
15+
| ^^^^ Description is required for \`enum Role\`.
4616
`;
4717

4818
exports[` 4`] = `
49-
1 |
50-
2 | input SalaryDecimalOperatorsFilterUpdateOneUserInput {
51-
3 | gt: BSONDecimal
52-
4 | gte: BSONDecimal
53-
5 | lt: BSONDecimal
54-
> 6 | lte: BSONDecimal
55-
| ^^^ Description is required for nodes of type "InputValueDefinition"
56-
7 | ne: BSONDecimal
57-
8 | in: [BSONDecimal]
58-
9 | nin: [BSONDecimal]
59-
10 | }
60-
11 |
19+
> 1 | scalar Email
20+
| ^^^^^ Description is required for \`scalar Email\`.
6121
`;
6222

6323
exports[` 5`] = `
64-
1 |
65-
2 | input SalaryDecimalOperatorsFilterUpdateOneUserInput {
66-
3 | gt: BSONDecimal
67-
4 | gte: BSONDecimal
68-
5 | lt: BSONDecimal
69-
6 | lte: BSONDecimal
70-
> 7 | ne: BSONDecimal
71-
| ^^ Description is required for nodes of type "InputValueDefinition"
72-
8 | in: [BSONDecimal]
73-
9 | nin: [BSONDecimal]
74-
10 | }
75-
11 |
24+
> 1 | input CreateUserInput { email: Email! }
25+
| ^^^^^^^^^^^^^^^ Description is required for \`input CreateUserInput\`.
7626
`;
7727

7828
exports[` 6`] = `
79-
1 |
80-
2 | input SalaryDecimalOperatorsFilterUpdateOneUserInput {
81-
3 | gt: BSONDecimal
82-
4 | gte: BSONDecimal
83-
5 | lt: BSONDecimal
84-
6 | lte: BSONDecimal
85-
7 | ne: BSONDecimal
86-
> 8 | in: [BSONDecimal]
87-
| ^^ Description is required for nodes of type "InputValueDefinition"
88-
9 | nin: [BSONDecimal]
89-
10 | }
90-
11 |
29+
> 1 | union Media = Book | Movie
30+
| ^^^^^ Description is required for \`union Media\`.
9131
`;
9232

9333
exports[` 7`] = `
94-
1 |
95-
2 | input SalaryDecimalOperatorsFilterUpdateOneUserInput {
96-
3 | gt: BSONDecimal
97-
4 | gte: BSONDecimal
98-
5 | lt: BSONDecimal
99-
6 | lte: BSONDecimal
100-
7 | ne: BSONDecimal
101-
8 | in: [BSONDecimal]
102-
> 9 | nin: [BSONDecimal]
103-
| ^^^ Description is required for nodes of type "InputValueDefinition"
104-
10 | }
105-
11 |
34+
> 1 | directive @auth(requires: Role!) on FIELD_DEFINITION
35+
| ^^^^ Description is required for \`directive @auth\`.
10636
`;
10737

10838
exports[` 8`] = `
109-
1 |
110-
2 | enum EnumUserLanguagesSkill {
111-
> 3 | basic
112-
| ^^^^^ Description is required for nodes of type "EnumValueDefinition"
113-
4 | fluent
114-
5 | native
115-
6 | }
116-
7 |
39+
> 1 | type User { email: Email! }
40+
| ^^^^^ Description is required for \`User.email\`.
11741
`;
11842

11943
exports[` 9`] = `
120-
1 |
121-
2 | enum EnumUserLanguagesSkill {
122-
3 | basic
123-
> 4 | fluent
124-
| ^^^^^^ Description is required for nodes of type "EnumValueDefinition"
125-
5 | native
126-
6 | }
127-
7 |
44+
> 1 | input CreateUserInput { email: Email! }
45+
| ^^^^^ Description is required for \`CreateUserInput.email\`.
12846
`;
12947

13048
exports[` 10`] = `
131-
1 |
132-
2 | enum EnumUserLanguagesSkill {
133-
3 | basic
134-
4 | fluent
135-
> 5 | native
136-
| ^^^^^^ Description is required for nodes of type "EnumValueDefinition"
137-
6 | }
138-
7 |
49+
> 1 | enum Role { ADMIN }
50+
| ^^^^^ Description is required for \`Role.ADMIN\`.
13951
`;
14052

14153
exports[` 11`] = `
14254
1 |
14355
2 | type CreateOneUserPayload {
14456
> 3 | recordId: MongoID
145-
| ^^^^^^^^ Description is required for nodes of type "FieldDefinition"
57+
| ^^^^^^^^ Description is required for \`CreateOneUserPayload.recordId\`.
14658
4 | record: User
14759
5 | }
14860
6 |
@@ -153,7 +65,7 @@ exports[` 12`] = `
15365
2 | type CreateOneUserPayload {
15466
3 | recordId: MongoID
15567
> 4 | record: User
156-
| ^^^^^^ Description is required for nodes of type "FieldDefinition"
68+
| ^^^^^^ Description is required for \`CreateOneUserPayload.record\`.
15769
5 | }
15870
6 |
15971
`;
@@ -163,27 +75,27 @@ exports[` 13`] = `
16375
2 | # linesBefore !== 1
16476
3 |
16577
> 4 | query {
166-
| ^^^^^ Description is required for nodes of type "OperationDefinition"
78+
| ^^^^^ Description is required for \`query\`.
16779
5 | foo
16880
6 | }
16981
7 |
17082
`;
17183
17284
exports[` 14`] = `
173-
> 1 | mutation { test }
174-
| ^^^^^^^^ Description is required for nodes of type "OperationDefinition"
85+
> 1 | mutation createUser { foo }
86+
| ^^^^^^^^ Description is required for \`mutation createUser\`.
17587
`;
17688
17789
exports[` 15`] = `
178-
> 1 | subscription { test }
179-
| ^^^^^^^^^^^^ Description is required for nodes of type "OperationDefinition"
90+
> 1 | subscription commentAdded { foo }
91+
| ^^^^^^^^^^^^ Description is required for \`subscription commentAdded\`.
18092
`;
18193
18294
exports[` 16`] = `
18395
1 |
18496
2 | # eslint-disable-next-line semi
18597
> 3 | query {
186-
| ^^^^^ Description is required for nodes of type "OperationDefinition"
98+
| ^^^^^ Description is required for \`query\`.
18799
4 | foo
188100
5 | }
189101
6 |
@@ -197,7 +109,7 @@ exports[` 17`] = `
197109
5 | }
198110
6 |
199111
> 7 | query {
200-
| ^^^^^ Description is required for nodes of type "OperationDefinition"
112+
| ^^^^^ Description is required for \`query\`.
201113
8 | user {
202114
9 | ...UserFields
203115
10 | }

0 commit comments

Comments
 (0)