forked from graphql-hive/graphql-eslint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
no-duplicate-fields.ts
116 lines (112 loc) · 2.98 KB
/
no-duplicate-fields.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import { Kind, NameNode } from 'graphql';
import type { GraphQLESLintRule } from '../types';
import type { GraphQLESTreeNode } from '../estree-converter';
const RULE_ID = 'no-duplicate-fields';
const rule: GraphQLESLintRule = {
meta: {
type: 'suggestion',
hasSuggestions: true,
docs: {
description:
'Checks for duplicate fields in selection set, variables in operation definition, or in arguments set of a field.',
category: 'Operations',
url: `https://github.com/B2o5T/graphql-eslint/blob/master/docs/rules/${RULE_ID}.md`,
recommended: true,
examples: [
{
title: 'Incorrect',
code: /* GraphQL */ `
query {
user {
name
email
name # duplicate field
}
}
`,
},
{
title: 'Incorrect',
code: /* GraphQL */ `
query {
users(
first: 100
skip: 50
after: "cji629tngfgou0b73kt7vi5jo"
first: 100 # duplicate argument
) {
id
}
}
`,
},
{
title: 'Incorrect',
code: /* GraphQL */ `
query (
$first: Int!
$first: Int! # duplicate variable
) {
users(first: $first, skip: 50) {
id
}
}
`,
},
],
},
messages: {
[RULE_ID]: '{{ type }} `{{ fieldName }}` defined multiple times.',
},
schema: [],
},
create(context) {
function checkNode(usedFields: Set<string>, node: GraphQLESTreeNode<NameNode>): void {
const fieldName = node.value;
if (usedFields.has(fieldName)) {
const { parent } = node;
context.report({
node,
messageId: RULE_ID,
data: {
type: parent.type,
fieldName,
},
suggest: [
{
desc: `Remove \`${fieldName}\` ${parent.type.toLowerCase()}`,
fix(fixer) {
return fixer.remove((parent.type === Kind.VARIABLE ? parent.parent : parent) as any);
},
},
],
});
} else {
usedFields.add(fieldName);
}
}
return {
OperationDefinition(node) {
const set = new Set<string>();
for (const varDef of node.variableDefinitions) {
checkNode(set, varDef.variable.name);
}
},
Field(node) {
const set = new Set<string>();
for (const arg of node.arguments) {
checkNode(set, arg.name);
}
},
SelectionSet(node) {
const set = new Set<string>();
for (const selection of node.selections) {
if (selection.kind === Kind.FIELD) {
checkNode(set, selection.alias || selection.name);
}
}
},
};
},
};
export default rule;