-
Notifications
You must be signed in to change notification settings - Fork 2k
/
KnownTypeNamesRule.ts
77 lines (67 loc) · 2.32 KB
/
KnownTypeNamesRule.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
import { didYouMean } from '../../jsutils/didYouMean.js';
import { suggestionList } from '../../jsutils/suggestionList.js';
import { GraphQLError } from '../../error/GraphQLError.js';
import type { ASTNode } from '../../language/ast.js';
import {
isTypeDefinitionNode,
isTypeSystemDefinitionNode,
isTypeSystemExtensionNode,
} from '../../language/predicates.js';
import type { ASTVisitor } from '../../language/visitor.js';
import { introspectionTypes } from '../../type/introspection.js';
import { specifiedScalarTypes } from '../../type/scalars.js';
import type {
SDLValidationContext,
ValidationContext,
} from '../ValidationContext.js';
/**
* Known type names
*
* A GraphQL document is only valid if referenced types (specifically
* variable definitions and fragment conditions) are defined by the type schema.
*
* See https://spec.graphql.org/draft/#sec-Fragment-Spread-Type-Existence
*/
export function KnownTypeNamesRule(
context: ValidationContext | SDLValidationContext,
): ASTVisitor {
const { definitions } = context.getDocument();
const existingTypesMap = context.getSchema()?.getTypeMap() ?? {};
const typeNames = new Set([
...Object.keys(existingTypesMap),
...definitions.filter(isTypeDefinitionNode).map((def) => def.name.value),
]);
return {
NamedType(node, _1, parent, _2, ancestors) {
const typeName = node.name.value;
if (!typeNames.has(typeName)) {
const definitionNode = ancestors[2] ?? parent;
const isSDL = definitionNode != null && isSDLNode(definitionNode);
if (isSDL && standardTypeNames.has(typeName)) {
return;
}
const suggestedTypes = context.hideSuggestions
? []
: suggestionList(
typeName,
isSDL ? [...standardTypeNames, ...typeNames] : [...typeNames],
);
context.reportError(
new GraphQLError(
`Unknown type "${typeName}".` + didYouMean(suggestedTypes),
{ nodes: node },
),
);
}
},
};
}
const standardTypeNames = new Set<string>(
[...specifiedScalarTypes, ...introspectionTypes].map((type) => type.name),
);
function isSDLNode(value: ASTNode | ReadonlyArray<ASTNode>): boolean {
return (
'kind' in value &&
(isTypeSystemDefinitionNode(value) || isTypeSystemExtensionNode(value))
);
}