7
7
* @flow strict
8
8
*/
9
9
10
- import type { ValidationContext } from '../ValidationContext' ;
10
+ import type {
11
+ ValidationContext ,
12
+ SDLValidationContext ,
13
+ } from '../ValidationContext' ;
11
14
import { GraphQLError } from '../../error/GraphQLError' ;
15
+ import { Kind } from '../../language/kinds' ;
12
16
import inspect from '../../jsutils/inspect' ;
13
17
import keyMap from '../../jsutils/keyMap' ;
14
18
import { isRequiredArgument } from '../../type/definition' ;
15
19
import type { ASTVisitor } from '../../language/visitor' ;
20
+ import { specifiedDirectives } from '../../type/directives' ;
16
21
17
22
export function missingFieldArgMessage (
18
23
fieldName : string ,
@@ -28,12 +33,13 @@ export function missingFieldArgMessage(
28
33
export function missingDirectiveArgMessage (
29
34
directiveName : string ,
30
35
argName : string ,
31
- type : string ,
36
+ type ?: ? string ,
32
37
) : string {
33
- return (
34
- `Directive "@${ directiveName } " argument "${ argName } " of type ` +
35
- `"${ type } " is required but not provided.`
36
- ) ;
38
+ let msg = `Directive "@${ directiveName } " argument "${ argName } "` ;
39
+ if ( type ) {
40
+ msg += ' of type ' + type ;
41
+ }
42
+ return msg + ' is required but not provided.' ;
37
43
}
38
44
39
45
/**
@@ -46,12 +52,13 @@ export function ProvidedRequiredArguments(
46
52
context : ValidationContext ,
47
53
) : ASTVisitor {
48
54
return {
55
+ ...ProvidedRequiredArgumentsOnDirectives ( context ) ,
49
56
Field : {
50
57
// Validate on leave to allow for deeper errors to appear first.
51
58
leave ( node ) {
52
59
const fieldDef = context . getFieldDef ( ) ;
53
60
if ( ! fieldDef ) {
54
- return false ;
61
+ return ;
55
62
}
56
63
const argNodes = node . arguments || [ ] ;
57
64
@@ -73,33 +80,69 @@ export function ProvidedRequiredArguments(
73
80
}
74
81
} ,
75
82
} ,
83
+ } ;
84
+ }
76
85
86
+ // @internal
87
+ export function ProvidedRequiredArgumentsOnDirectives (
88
+ context : ValidationContext | SDLValidationContext ,
89
+ ) : ASTVisitor {
90
+ const requiredArgsMap = Object . create ( null ) ;
91
+
92
+ const schema = context . getSchema ( ) ;
93
+ const definedDirectives = schema
94
+ ? schema . getDirectives ( )
95
+ : specifiedDirectives ;
96
+ for ( const directive of definedDirectives ) {
97
+ requiredArgsMap [ directive . name ] = directive . args
98
+ . filter ( isRequiredArgument )
99
+ . map ( arg => arg . name ) ;
100
+ }
101
+
102
+ const astDefinitions = context . getDocument ( ) . definitions ;
103
+ for ( const def of astDefinitions ) {
104
+ if ( def . kind === Kind . DIRECTIVE_DEFINITION ) {
105
+ const args = def . arguments ;
106
+ requiredArgsMap [ def . name . value ] = args
107
+ ? args . filter ( isRequiredArgumentNode ) . map ( arg => arg . name . value )
108
+ : [ ] ;
109
+ }
110
+ }
111
+
112
+ return {
77
113
Directive : {
78
114
// Validate on leave to allow for deeper errors to appear first.
79
115
leave ( node ) {
80
- const directiveDef = context . getDirective ( ) ;
81
- if ( ! directiveDef ) {
82
- return false ;
83
- }
84
- const argNodes = node . arguments || [ ] ;
116
+ const directiveName = node . name . value ;
117
+ const requiredArgs = requiredArgsMap [ directiveName ] ;
118
+ if ( requiredArgs ) {
119
+ const argNodes = node . arguments || [ ] ;
120
+ const argNodeMap = keyMap ( argNodes , arg => arg . name . value ) ;
121
+ for ( const argName of requiredArgs ) {
122
+ if ( ! argNodeMap [ argName ] ) {
123
+ const directiveDef = schema && schema . getDirective ( directiveName ) ;
124
+ const argDef =
125
+ directiveDef &&
126
+ directiveDef . args . find ( arg => arg . name === argName ) ;
85
127
86
- const argNodeMap = keyMap ( argNodes , arg => arg . name . value ) ;
87
- for ( const argDef of directiveDef . args ) {
88
- const argNode = argNodeMap [ argDef . name ] ;
89
- if ( ! argNode && isRequiredArgument ( argDef ) ) {
90
- context . reportError (
91
- new GraphQLError (
92
- missingDirectiveArgMessage (
93
- node . name . value ,
94
- argDef . name ,
95
- inspect ( argDef . type ) ,
128
+ context . reportError (
129
+ new GraphQLError (
130
+ missingDirectiveArgMessage (
131
+ directiveName ,
132
+ argName ,
133
+ argDef && inspect ( argDef . type ) ,
134
+ ) ,
135
+ [ node ] ,
96
136
) ,
97
- [ node ] ,
98
- ) ,
99
- ) ;
137
+ ) ;
138
+ }
100
139
}
101
140
}
102
141
} ,
103
142
} ,
104
143
} ;
105
144
}
145
+
146
+ function isRequiredArgumentNode ( arg ) {
147
+ return arg . type . kind === Kind . NON_NULL_TYPE && arg . defaultValue == null ;
148
+ }
0 commit comments