-
Notifications
You must be signed in to change notification settings - Fork 2k
/
Copy pathvalidate.ts
136 lines (122 loc) · 4.09 KB
/
validate.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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import type { Maybe } from '../jsutils/Maybe.js';
import { GraphQLError } from '../error/GraphQLError.js';
import type { DocumentNode } from '../language/ast.js';
import { visit, visitInParallel } from '../language/visitor.js';
import type { GraphQLSchema } from '../type/schema.js';
import { assertValidSchema } from '../type/validate.js';
import { TypeInfo, visitWithTypeInfo } from '../utilities/TypeInfo.js';
import { specifiedRules, specifiedSDLRules } from './specifiedRules.js';
import type { SDLValidationRule, ValidationRule } from './ValidationContext.js';
import {
SDLValidationContext,
ValidationContext,
} from './ValidationContext.js';
/**
* Implements the "Validation" section of the spec.
*
* Validation runs synchronously, returning an array of encountered errors, or
* an empty array if no errors were encountered and the document is valid.
*
* A list of specific validation rules may be provided. If not provided, the
* default list of rules defined by the GraphQL specification will be used.
*
* Each validation rules is a function which returns a visitor
* (see the language/visitor API). Visitor methods are expected to return
* GraphQLErrors, or Arrays of GraphQLErrors when invalid.
*
* Validate will stop validation after a `maxErrors` limit has been reached.
* Attackers can send pathologically invalid queries to induce a DoS attack,
* so by default `maxErrors` set to 100 errors.
*
* Optionally a custom TypeInfo instance may be provided. If not provided, one
* will be created from the provided schema.
*/
export function validate(
schema: GraphQLSchema,
documentAST: DocumentNode,
rules: ReadonlyArray<ValidationRule> = specifiedRules,
options?: { maxErrors?: number; hideSuggestions?: Maybe<boolean> },
): ReadonlyArray<GraphQLError> {
const maxErrors = options?.maxErrors ?? 100;
const hideSuggestions = options?.hideSuggestions ?? false;
// If the schema used for validation is invalid, throw an error.
assertValidSchema(schema);
const abortError = new GraphQLError(
'Too many validation errors, error limit reached. Validation aborted.',
);
const errors: Array<GraphQLError> = [];
const typeInfo = new TypeInfo(schema);
const context = new ValidationContext(
schema,
documentAST,
typeInfo,
(error) => {
if (errors.length >= maxErrors) {
throw abortError;
}
errors.push(error);
},
hideSuggestions,
);
// This uses a specialized visitor which runs multiple visitors in parallel,
// while maintaining the visitor skip and break API.
const visitor = visitInParallel(rules.map((rule) => rule(context)));
// Visit the whole document with each instance of all provided rules.
try {
visit(documentAST, visitWithTypeInfo(typeInfo, visitor));
} catch (e: unknown) {
if (e === abortError) {
errors.push(abortError);
} else {
throw e;
}
}
return errors;
}
/**
* @internal
*/
export function validateSDL(
documentAST: DocumentNode,
schemaToExtend?: Maybe<GraphQLSchema>,
rules: ReadonlyArray<SDLValidationRule> = specifiedSDLRules,
): ReadonlyArray<GraphQLError> {
const errors: Array<GraphQLError> = [];
const context = new SDLValidationContext(
documentAST,
schemaToExtend,
(error) => {
errors.push(error);
},
);
const visitors = rules.map((rule) => rule(context));
visit(documentAST, visitInParallel(visitors));
return errors;
}
/**
* Utility function which asserts a SDL document is valid by throwing an error
* if it is invalid.
*
* @internal
*/
export function assertValidSDL(documentAST: DocumentNode): void {
const errors = validateSDL(documentAST);
if (errors.length !== 0) {
throw new Error(errors.map((error) => error.message).join('\n\n'));
}
}
/**
* Utility function which asserts a SDL document is valid by throwing an error
* if it is invalid.
*
* @internal
*/
export function assertValidSDLExtension(
documentAST: DocumentNode,
schema: GraphQLSchema,
): void {
const errors = validateSDL(documentAST, schema);
if (errors.length !== 0) {
throw new Error(errors.map((error) => error.message).join('\n\n'));
}
}