Skip to content

Commit 3ee2e6a

Browse files
committed
fixes
1 parent bbff5e5 commit 3ee2e6a

File tree

4 files changed

+71
-29
lines changed

4 files changed

+71
-29
lines changed

example/.eslintrc.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
},
66
"plugins": ["@graphql-eslint"],
77
"rules": {
8-
"@graphql-eslint/require-id-when-available": "error",
8+
"@graphql-eslint/require-id-when-available": ["error", {
9+
"fieldName": "_id"
10+
}],
911
"@graphql-eslint/validate-against-schema": "error",
1012
"@graphql-eslint/no-anonymous-operations": "warn",
1113
"@graphql-eslint/no-operation-name-suffix": "error",

example/query.graphql

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
query test {
22
user {
3+
id
34
name
5+
... on User {
6+
name
7+
}
48
}
59
}

packages/plugin/src/rules/require-id-when-available.ts

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,74 @@
1-
import { GraphQLESLintRule } from "@graphql-eslint/types";
1+
import { GraphQLESLintRule, getBaseType } from "@graphql-eslint/types";
22
import { GraphQLInterfaceType, GraphQLObjectType } from "graphql";
33

44
const REQUIRE_ID_WHEN_AVAILABLE = "REQUIRE_ID_WHEN_AVAILABLE";
5-
const ID_FIELD_NAME = "id";
5+
const DEFAULT_ID_FIELD_NAME = "id";
66

7-
const rule: GraphQLESLintRule<any, true> = {
7+
type RequireIdWhenAvailableRuleConfig = { fieldName: string };
8+
9+
const rule: GraphQLESLintRule<RequireIdWhenAvailableRuleConfig, true> = {
810
meta: {
911
messages: {
10-
[REQUIRE_ID_WHEN_AVAILABLE]: `Field "id" must be selected when it's available on a type. Please make sure to include it in your selection set!`,
12+
[REQUIRE_ID_WHEN_AVAILABLE]: `Field "{{ fieldName }}" must be selected when it's available on a type. Please make sure to include it in your selection set!`,
13+
},
14+
schema: {
15+
type: "array",
16+
additionalItems: false,
17+
minItems: 0,
18+
maxItems: 1,
19+
items: {
20+
type: "object",
21+
properties: {
22+
fieldName: {
23+
type: "string",
24+
default: DEFAULT_ID_FIELD_NAME,
25+
},
26+
},
27+
},
1128
},
1229
},
1330
create(context) {
1431
return {
1532
SelectionSet(node) {
16-
if (!node.selections || node.selections.length > 0) {
33+
const fieldName =
34+
(context.options[0] || {}).fieldName || DEFAULT_ID_FIELD_NAME;
35+
36+
if (!node.selections || node.selections.length === 0) {
1737
return;
1838
}
1939

2040
if (node.typeInfo && node.typeInfo.gqlType) {
41+
const rawType = getBaseType(node.typeInfo.gqlType);
2142
if (
22-
node.typeInfo.gqlType instanceof GraphQLObjectType ||
23-
node.typeInfo.gqlType instanceof GraphQLInterfaceType
43+
rawType instanceof GraphQLObjectType ||
44+
rawType instanceof GraphQLInterfaceType
2445
) {
25-
const fields = node.typeInfo.gqlType.getFields();
26-
const hasIdFieldInType = !!fields[ID_FIELD_NAME];
27-
const hasIdFieldInSelectionSet = !!node.selections.find(
28-
(s) => s.kind === "Field" && s.name.value === ID_FIELD_NAME
29-
);
30-
31-
if (hasIdFieldInType && !hasIdFieldInSelectionSet) {
32-
context.report({
33-
loc: {
34-
start: {
35-
line: node.loc.start.line,
36-
column: node.loc.start.column - 1,
46+
const fields = rawType.getFields();
47+
const hasIdFieldInType = !!fields[fieldName];
48+
49+
if (hasIdFieldInType) {
50+
const hasIdFieldInSelectionSet = !!node.selections.find(
51+
(s) => s.kind === "Field" && s.name.value === fieldName
52+
);
53+
54+
if (!hasIdFieldInSelectionSet) {
55+
context.report({
56+
loc: {
57+
start: {
58+
line: node.loc.start.line,
59+
column: node.loc.start.column - 1,
60+
},
61+
end: {
62+
line: node.loc.end.line,
63+
column: node.loc.end.column - 1,
64+
},
3765
},
38-
end: {
39-
line: node.loc.end.line,
40-
column: node.loc.end.column - 1,
66+
messageId: REQUIRE_ID_WHEN_AVAILABLE,
67+
data: {
68+
fieldName,
4169
},
42-
},
43-
messageId: REQUIRE_ID_WHEN_AVAILABLE,
44-
data: {
45-
nodeType: node.kind,
46-
},
47-
});
70+
});
71+
}
4872
}
4973
}
5074
}

packages/types/src/utils.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ import {
1313
ObjectValueNode,
1414
VariableNode,
1515
TokenKind,
16+
GraphQLOutputType,
17+
GraphQLNamedType,
18+
isNonNullType,
19+
isListType,
1620
} from "graphql";
1721
import { SourceLocation, Comment } from "estree";
1822
import { GraphQLESTreeNode } from "./estree-ast";
@@ -77,6 +81,14 @@ export function valueFromNode(
7781
}
7882
}
7983

84+
export function getBaseType(type: GraphQLOutputType): GraphQLNamedType {
85+
if (isNonNullType(type) || isListType(type)) {
86+
return getBaseType(type.ofType);
87+
}
88+
89+
return type;
90+
}
91+
8092
export function convertRange(gqlLocation: Location): [number, number] {
8193
return [gqlLocation.start, gqlLocation.end];
8294
}

0 commit comments

Comments
 (0)