graphql 16.13.2 → 16.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/index.d.ts +1 -0
  2. package/language/ast.d.ts +10 -1
  3. package/language/ast.js +8 -1
  4. package/language/ast.mjs +8 -1
  5. package/language/directiveLocation.d.ts +1 -0
  6. package/language/directiveLocation.js +1 -0
  7. package/language/directiveLocation.mjs +1 -0
  8. package/language/index.d.ts +1 -0
  9. package/language/kinds.d.ts +1 -0
  10. package/language/kinds.js +1 -0
  11. package/language/kinds.mjs +1 -0
  12. package/language/parser.d.ts +14 -0
  13. package/language/parser.js +33 -0
  14. package/language/parser.mjs +33 -0
  15. package/language/predicates.js +3 -1
  16. package/language/predicates.mjs +5 -1
  17. package/language/printer.js +13 -1
  18. package/language/printer.mjs +13 -1
  19. package/package.json +1 -1
  20. package/type/directives.d.ts +9 -1
  21. package/type/directives.js +10 -1
  22. package/type/directives.mjs +10 -1
  23. package/type/introspection.js +24 -1
  24. package/type/introspection.mjs +24 -1
  25. package/utilities/buildASTSchema.js +4 -0
  26. package/utilities/buildASTSchema.mjs +4 -0
  27. package/utilities/buildClientSchema.js +1 -0
  28. package/utilities/buildClientSchema.mjs +1 -0
  29. package/utilities/extendSchema.js +58 -3
  30. package/utilities/extendSchema.mjs +58 -3
  31. package/utilities/getIntrospectionQuery.d.ts +16 -0
  32. package/utilities/getIntrospectionQuery.js +31 -38
  33. package/utilities/getIntrospectionQuery.mjs +31 -38
  34. package/utilities/introspectionFromSchema.js +1 -0
  35. package/utilities/introspectionFromSchema.mjs +1 -0
  36. package/utilities/printSchema.js +1 -0
  37. package/utilities/printSchema.mjs +1 -0
  38. package/utilities/valueFromAST.js +12 -2
  39. package/utilities/valueFromAST.mjs +12 -2
  40. package/validation/rules/KnownDirectivesRule.js +4 -0
  41. package/validation/rules/KnownDirectivesRule.mjs +4 -0
  42. package/validation/rules/UniqueDirectivesPerLocationRule.js +12 -0
  43. package/validation/rules/UniqueDirectivesPerLocationRule.mjs +12 -0
  44. package/version.js +3 -3
  45. package/version.mjs +3 -3
@@ -87,6 +87,10 @@ export function buildSchema(source, options) {
87
87
  options === null || options === void 0
88
88
  ? void 0
89
89
  : options.allowLegacyFragmentVariables,
90
+ experimentalDirectivesOnDirectiveDefinitions:
91
+ options === null || options === void 0
92
+ ? void 0
93
+ : options.experimentalDirectivesOnDirectiveDefinitions,
90
94
  });
91
95
  return buildASTSchema(document, {
92
96
  assumeValidSDL:
@@ -380,6 +380,7 @@ function buildClientSchema(introspection, options) {
380
380
  name: directiveIntrospection.name,
381
381
  description: directiveIntrospection.description,
382
382
  isRepeatable: directiveIntrospection.isRepeatable,
383
+ deprecationReason: directiveIntrospection.deprecationReason,
383
384
  locations: directiveIntrospection.locations.slice(),
384
385
  args: buildInputValueDefMap(directiveIntrospection.args),
385
386
  });
@@ -357,6 +357,7 @@ export function buildClientSchema(introspection, options) {
357
357
  name: directiveIntrospection.name,
358
358
  description: directiveIntrospection.description,
359
359
  isRepeatable: directiveIntrospection.isRepeatable,
360
+ deprecationReason: directiveIntrospection.deprecationReason,
360
361
  locations: directiveIntrospection.locations.slice(),
361
362
  args: buildInputValueDefMap(directiveIntrospection.args),
362
363
  });
@@ -78,7 +78,8 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
78
78
 
79
79
  // Collect the type definitions and extensions found in the document.
80
80
  const typeDefs = [];
81
- const typeExtensionsMap = Object.create(null); // New directives and types are separate because a directives and types can
81
+ const typeExtensionsMap = Object.create(null);
82
+ const directiveExtensionsMap = Object.create(null); // New directives and types are separate because a directives and types can
82
83
  // have the same name. For example, a type named "skip".
83
84
 
84
85
  const directiveDefs = [];
@@ -101,6 +102,14 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
101
102
  : [def];
102
103
  } else if (def.kind === _kinds.Kind.DIRECTIVE_DEFINITION) {
103
104
  directiveDefs.push(def);
105
+ } else if (def.kind === _kinds.Kind.DIRECTIVE_EXTENSION) {
106
+ const extendedDirectiveName = def.name.value;
107
+ const existingDirectiveExtensions =
108
+ directiveExtensionsMap[extendedDirectiveName];
109
+ directiveExtensionsMap[extendedDirectiveName] =
110
+ existingDirectiveExtensions
111
+ ? existingDirectiveExtensions.concat([def])
112
+ : [def];
104
113
  }
105
114
  } // If this document contains no new types, extensions, or directives then
106
115
  // return the same unmodified GraphQLSchema instance.
@@ -108,6 +117,7 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
108
117
  if (
109
118
  Object.keys(typeExtensionsMap).length === 0 &&
110
119
  typeDefs.length === 0 &&
120
+ Object.keys(directiveExtensionsMap).length === 0 &&
111
121
  directiveDefs.length === 0 &&
112
122
  schemaExtensions.length === 0 &&
113
123
  schemaDef == null
@@ -132,6 +142,12 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
132
142
  : buildType(typeNode);
133
143
  }
134
144
 
145
+ const directiveMap = Object.create(null);
146
+
147
+ for (const existingDirective of schemaConfig.directives) {
148
+ directiveMap[existingDirective.name] = extendDirective(existingDirective);
149
+ }
150
+
135
151
  const operationTypes = {
136
152
  // Get the extended root operation types.
137
153
  query: schemaConfig.query && replaceNamedType(schemaConfig.query),
@@ -143,6 +159,8 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
143
159
  ...getOperationTypes(schemaExtensions),
144
160
  }; // Then produce and return a Schema config with these types.
145
161
 
162
+ const directives = Object.values(directiveMap); // will be `Array<GraphQLDirective>`
163
+
146
164
  return {
147
165
  description:
148
166
  (_schemaDef = schemaDef) === null || _schemaDef === void 0
@@ -154,7 +172,7 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
154
172
  ...operationTypes,
155
173
  types: Object.values(typeMap),
156
174
  directives: [
157
- ...schemaConfig.directives.map(replaceDirective),
175
+ ...directives.map(replaceDirective),
158
176
  ...directiveDefs.map(buildDirective),
159
177
  ],
160
178
  extensions: Object.create(null),
@@ -413,6 +431,29 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
413
431
  return opTypes;
414
432
  }
415
433
 
434
+ function extendDirective(directive) {
435
+ var _directiveExtensionsM, _config$deprecationRe;
436
+
437
+ const config = directive.toConfig();
438
+ const extensions =
439
+ (_directiveExtensionsM = directiveExtensionsMap[config.name]) !== null &&
440
+ _directiveExtensionsM !== void 0
441
+ ? _directiveExtensionsM
442
+ : [];
443
+ const deprecationReason =
444
+ (_config$deprecationRe = config.deprecationReason) !== null &&
445
+ _config$deprecationRe !== void 0
446
+ ? _config$deprecationRe
447
+ : extensions
448
+ .map((ext) => getDeprecationReason(ext))
449
+ .find((reason) => reason != null);
450
+ return new _directives.GraphQLDirective({
451
+ ...config,
452
+ deprecationReason,
453
+ extensionASTNodes: config.extensionASTNodes.concat(extensions),
454
+ });
455
+ }
456
+
416
457
  function getNamedType(node) {
417
458
  var _stdTypeMap$name2;
418
459
 
@@ -443,8 +484,20 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
443
484
  }
444
485
 
445
486
  function buildDirective(node) {
446
- var _node$description;
487
+ var _directiveExtensionsM2, _getDeprecationReason, _node$description;
447
488
 
489
+ const extensions =
490
+ (_directiveExtensionsM2 = directiveExtensionsMap[node.name.value]) !==
491
+ null && _directiveExtensionsM2 !== void 0
492
+ ? _directiveExtensionsM2
493
+ : [];
494
+ const deprecationReason =
495
+ (_getDeprecationReason = getDeprecationReason(node)) !== null &&
496
+ _getDeprecationReason !== void 0
497
+ ? _getDeprecationReason
498
+ : extensions
499
+ .map((ext) => getDeprecationReason(ext))
500
+ .find((reason) => reason != null);
448
501
  return new _directives.GraphQLDirective({
449
502
  name: node.name.value,
450
503
  description:
@@ -456,7 +509,9 @@ function extendSchemaImpl(schemaConfig, documentAST, options) {
456
509
  locations: node.locations.map(({ value }) => value),
457
510
  isRepeatable: node.repeatable,
458
511
  args: buildArgumentMap(node.arguments),
512
+ deprecationReason,
459
513
  astNode: node,
514
+ extensionASTNodes: extensions,
460
515
  });
461
516
  }
462
517
 
@@ -87,7 +87,8 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
87
87
 
88
88
  // Collect the type definitions and extensions found in the document.
89
89
  const typeDefs = [];
90
- const typeExtensionsMap = Object.create(null); // New directives and types are separate because a directives and types can
90
+ const typeExtensionsMap = Object.create(null);
91
+ const directiveExtensionsMap = Object.create(null); // New directives and types are separate because a directives and types can
91
92
  // have the same name. For example, a type named "skip".
92
93
 
93
94
  const directiveDefs = [];
@@ -110,6 +111,14 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
110
111
  : [def];
111
112
  } else if (def.kind === Kind.DIRECTIVE_DEFINITION) {
112
113
  directiveDefs.push(def);
114
+ } else if (def.kind === Kind.DIRECTIVE_EXTENSION) {
115
+ const extendedDirectiveName = def.name.value;
116
+ const existingDirectiveExtensions =
117
+ directiveExtensionsMap[extendedDirectiveName];
118
+ directiveExtensionsMap[extendedDirectiveName] =
119
+ existingDirectiveExtensions
120
+ ? existingDirectiveExtensions.concat([def])
121
+ : [def];
113
122
  }
114
123
  } // If this document contains no new types, extensions, or directives then
115
124
  // return the same unmodified GraphQLSchema instance.
@@ -117,6 +126,7 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
117
126
  if (
118
127
  Object.keys(typeExtensionsMap).length === 0 &&
119
128
  typeDefs.length === 0 &&
129
+ Object.keys(directiveExtensionsMap).length === 0 &&
120
130
  directiveDefs.length === 0 &&
121
131
  schemaExtensions.length === 0 &&
122
132
  schemaDef == null
@@ -141,6 +151,12 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
141
151
  : buildType(typeNode);
142
152
  }
143
153
 
154
+ const directiveMap = Object.create(null);
155
+
156
+ for (const existingDirective of schemaConfig.directives) {
157
+ directiveMap[existingDirective.name] = extendDirective(existingDirective);
158
+ }
159
+
144
160
  const operationTypes = {
145
161
  // Get the extended root operation types.
146
162
  query: schemaConfig.query && replaceNamedType(schemaConfig.query),
@@ -152,6 +168,8 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
152
168
  ...getOperationTypes(schemaExtensions),
153
169
  }; // Then produce and return a Schema config with these types.
154
170
 
171
+ const directives = Object.values(directiveMap); // will be `Array<GraphQLDirective>`
172
+
155
173
  return {
156
174
  description:
157
175
  (_schemaDef = schemaDef) === null || _schemaDef === void 0
@@ -163,7 +181,7 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
163
181
  ...operationTypes,
164
182
  types: Object.values(typeMap),
165
183
  directives: [
166
- ...schemaConfig.directives.map(replaceDirective),
184
+ ...directives.map(replaceDirective),
167
185
  ...directiveDefs.map(buildDirective),
168
186
  ],
169
187
  extensions: Object.create(null),
@@ -415,6 +433,29 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
415
433
  return opTypes;
416
434
  }
417
435
 
436
+ function extendDirective(directive) {
437
+ var _directiveExtensionsM, _config$deprecationRe;
438
+
439
+ const config = directive.toConfig();
440
+ const extensions =
441
+ (_directiveExtensionsM = directiveExtensionsMap[config.name]) !== null &&
442
+ _directiveExtensionsM !== void 0
443
+ ? _directiveExtensionsM
444
+ : [];
445
+ const deprecationReason =
446
+ (_config$deprecationRe = config.deprecationReason) !== null &&
447
+ _config$deprecationRe !== void 0
448
+ ? _config$deprecationRe
449
+ : extensions
450
+ .map((ext) => getDeprecationReason(ext))
451
+ .find((reason) => reason != null);
452
+ return new GraphQLDirective({
453
+ ...config,
454
+ deprecationReason,
455
+ extensionASTNodes: config.extensionASTNodes.concat(extensions),
456
+ });
457
+ }
458
+
418
459
  function getNamedType(node) {
419
460
  var _stdTypeMap$name2;
420
461
 
@@ -445,8 +486,20 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
445
486
  }
446
487
 
447
488
  function buildDirective(node) {
448
- var _node$description;
489
+ var _directiveExtensionsM2, _getDeprecationReason, _node$description;
449
490
 
491
+ const extensions =
492
+ (_directiveExtensionsM2 = directiveExtensionsMap[node.name.value]) !==
493
+ null && _directiveExtensionsM2 !== void 0
494
+ ? _directiveExtensionsM2
495
+ : [];
496
+ const deprecationReason =
497
+ (_getDeprecationReason = getDeprecationReason(node)) !== null &&
498
+ _getDeprecationReason !== void 0
499
+ ? _getDeprecationReason
500
+ : extensions
501
+ .map((ext) => getDeprecationReason(ext))
502
+ .find((reason) => reason != null);
450
503
  return new GraphQLDirective({
451
504
  name: node.name.value,
452
505
  description:
@@ -458,7 +511,9 @@ export function extendSchemaImpl(schemaConfig, documentAST, options) {
458
511
  locations: node.locations.map(({ value }) => value),
459
512
  isRepeatable: node.repeatable,
460
513
  args: buildArgumentMap(node.arguments),
514
+ deprecationReason,
461
515
  astNode: node,
516
+ extensionASTNodes: extensions,
462
517
  });
463
518
  }
464
519
 
@@ -26,11 +26,25 @@ export interface IntrospectionOptions {
26
26
  * Default: false
27
27
  */
28
28
  inputValueDeprecation?: boolean;
29
+ /**
30
+ * Whether target GraphQL server supports deprecation of directives.
31
+ * Default: false
32
+ */
33
+ experimentalDirectiveDeprecation?: boolean;
29
34
  /**
30
35
  * Whether target GraphQL server supports `@oneOf` input objects.
31
36
  * Default: false
32
37
  */
33
38
  oneOf?: boolean;
39
+ /**
40
+ * How deep to recurse into nested types, larger values will result in more
41
+ * accurate results, but have a higher load on the server.
42
+ * Some servers might restrict the maximum query depth or complexity.
43
+ * If that's the case, try decreasing this value.
44
+ *
45
+ * Default: 9
46
+ */
47
+ typeDepth?: number;
34
48
  }
35
49
  /**
36
50
  * Produce the GraphQL query recommended for a full schema introspection.
@@ -183,6 +197,8 @@ export interface IntrospectionDirective {
183
197
  readonly name: string;
184
198
  readonly description?: Maybe<string>;
185
199
  readonly isRepeatable?: boolean;
200
+ readonly isDeprecated?: boolean;
201
+ readonly deprecationReason?: Maybe<string>;
186
202
  readonly locations: ReadonlyArray<DirectiveLocation>;
187
203
  readonly args: ReadonlyArray<IntrospectionInputValue>;
188
204
  }
@@ -16,7 +16,9 @@ function getIntrospectionQuery(options) {
16
16
  directiveIsRepeatable: false,
17
17
  schemaDescription: false,
18
18
  inputValueDeprecation: false,
19
+ experimentalDirectiveDeprecation: false,
19
20
  oneOf: false,
21
+ typeDepth: 9,
20
22
  ...options,
21
23
  };
22
24
  const descriptions = optionsWithDefault.descriptions ? 'description' : '';
@@ -34,7 +36,30 @@ function getIntrospectionQuery(options) {
34
36
  return optionsWithDefault.inputValueDeprecation ? str : '';
35
37
  }
36
38
 
39
+ function experimentalDirectiveDeprecation(str) {
40
+ return optionsWithDefault.experimentalDirectiveDeprecation ? str : '';
41
+ }
42
+
37
43
  const oneOf = optionsWithDefault.oneOf ? 'isOneOf' : '';
44
+
45
+ function ofType(level, indent) {
46
+ if (level <= 0) {
47
+ return '';
48
+ }
49
+
50
+ if (level > 100) {
51
+ throw new Error(
52
+ 'Please set typeDepth to a reasonable value between 0 and 100; the default is 9.',
53
+ );
54
+ }
55
+
56
+ return `
57
+ ${indent}ofType {
58
+ ${indent} name
59
+ ${indent} kind${ofType(level - 1, indent + ' ')}
60
+ ${indent}}`;
61
+ }
62
+
38
63
  return `
39
64
  query IntrospectionQuery {
40
65
  __schema {
@@ -45,10 +70,14 @@ function getIntrospectionQuery(options) {
45
70
  types {
46
71
  ...FullType
47
72
  }
48
- directives {
73
+ directives${experimentalDirectiveDeprecation(
74
+ '(includeDeprecated: true)',
75
+ )} {
49
76
  name
50
77
  ${descriptions}
51
78
  ${directiveIsRepeatable}
79
+ ${experimentalDirectiveDeprecation('isDeprecated')}
80
+ ${experimentalDirectiveDeprecation('deprecationReason')}
52
81
  locations
53
82
  args${inputDeprecation('(includeDeprecated: true)')} {
54
83
  ...InputValue
@@ -103,43 +132,7 @@ function getIntrospectionQuery(options) {
103
132
 
104
133
  fragment TypeRef on __Type {
105
134
  kind
106
- name
107
- ofType {
108
- kind
109
- name
110
- ofType {
111
- kind
112
- name
113
- ofType {
114
- kind
115
- name
116
- ofType {
117
- kind
118
- name
119
- ofType {
120
- kind
121
- name
122
- ofType {
123
- kind
124
- name
125
- ofType {
126
- kind
127
- name
128
- ofType {
129
- kind
130
- name
131
- ofType {
132
- kind
133
- name
134
- }
135
- }
136
- }
137
- }
138
- }
139
- }
140
- }
141
- }
142
- }
135
+ name${ofType(optionsWithDefault.typeDepth, ' ')}
143
136
  }
144
137
  `;
145
138
  }
@@ -9,7 +9,9 @@ export function getIntrospectionQuery(options) {
9
9
  directiveIsRepeatable: false,
10
10
  schemaDescription: false,
11
11
  inputValueDeprecation: false,
12
+ experimentalDirectiveDeprecation: false,
12
13
  oneOf: false,
14
+ typeDepth: 9,
13
15
  ...options,
14
16
  };
15
17
  const descriptions = optionsWithDefault.descriptions ? 'description' : '';
@@ -27,7 +29,30 @@ export function getIntrospectionQuery(options) {
27
29
  return optionsWithDefault.inputValueDeprecation ? str : '';
28
30
  }
29
31
 
32
+ function experimentalDirectiveDeprecation(str) {
33
+ return optionsWithDefault.experimentalDirectiveDeprecation ? str : '';
34
+ }
35
+
30
36
  const oneOf = optionsWithDefault.oneOf ? 'isOneOf' : '';
37
+
38
+ function ofType(level, indent) {
39
+ if (level <= 0) {
40
+ return '';
41
+ }
42
+
43
+ if (level > 100) {
44
+ throw new Error(
45
+ 'Please set typeDepth to a reasonable value between 0 and 100; the default is 9.',
46
+ );
47
+ }
48
+
49
+ return `
50
+ ${indent}ofType {
51
+ ${indent} name
52
+ ${indent} kind${ofType(level - 1, indent + ' ')}
53
+ ${indent}}`;
54
+ }
55
+
31
56
  return `
32
57
  query IntrospectionQuery {
33
58
  __schema {
@@ -38,10 +63,14 @@ export function getIntrospectionQuery(options) {
38
63
  types {
39
64
  ...FullType
40
65
  }
41
- directives {
66
+ directives${experimentalDirectiveDeprecation(
67
+ '(includeDeprecated: true)',
68
+ )} {
42
69
  name
43
70
  ${descriptions}
44
71
  ${directiveIsRepeatable}
72
+ ${experimentalDirectiveDeprecation('isDeprecated')}
73
+ ${experimentalDirectiveDeprecation('deprecationReason')}
45
74
  locations
46
75
  args${inputDeprecation('(includeDeprecated: true)')} {
47
76
  ...InputValue
@@ -96,43 +125,7 @@ export function getIntrospectionQuery(options) {
96
125
 
97
126
  fragment TypeRef on __Type {
98
127
  kind
99
- name
100
- ofType {
101
- kind
102
- name
103
- ofType {
104
- kind
105
- name
106
- ofType {
107
- kind
108
- name
109
- ofType {
110
- kind
111
- name
112
- ofType {
113
- kind
114
- name
115
- ofType {
116
- kind
117
- name
118
- ofType {
119
- kind
120
- name
121
- ofType {
122
- kind
123
- name
124
- ofType {
125
- kind
126
- name
127
- }
128
- }
129
- }
130
- }
131
- }
132
- }
133
- }
134
- }
135
- }
128
+ name${ofType(optionsWithDefault.typeDepth, ' ')}
136
129
  }
137
130
  `;
138
131
  }
@@ -28,6 +28,7 @@ function introspectionFromSchema(schema, options) {
28
28
  directiveIsRepeatable: true,
29
29
  schemaDescription: true,
30
30
  inputValueDeprecation: true,
31
+ experimentalDirectiveDeprecation: true,
31
32
  oneOf: true,
32
33
  ...options,
33
34
  };
@@ -18,6 +18,7 @@ export function introspectionFromSchema(schema, options) {
18
18
  directiveIsRepeatable: true,
19
19
  schemaDescription: true,
20
20
  inputValueDeprecation: true,
21
+ experimentalDirectiveDeprecation: true,
21
22
  oneOf: true,
22
23
  ...options,
23
24
  };
@@ -286,6 +286,7 @@ function printDirective(directive) {
286
286
  'directive @' +
287
287
  directive.name +
288
288
  printArgs(directive.args) +
289
+ printDeprecated(directive.deprecationReason) +
289
290
  (directive.isRepeatable ? ' repeatable' : '') +
290
291
  ' on ' +
291
292
  directive.locations.join(' | ')
@@ -262,6 +262,7 @@ function printDirective(directive) {
262
262
  'directive @' +
263
263
  directive.name +
264
264
  printArgs(directive.args) +
265
+ printDeprecated(directive.deprecationReason) +
265
266
  (directive.isRepeatable ? ' repeatable' : '') +
266
267
  ' on ' +
267
268
  directive.locations.join(' | ')
@@ -45,7 +45,11 @@ function valueFromAST(valueNode, type, variables) {
45
45
  if (valueNode.kind === _kinds.Kind.VARIABLE) {
46
46
  const variableName = valueNode.name.value;
47
47
 
48
- if (variables == null || variables[variableName] === undefined) {
48
+ if (
49
+ variables == null ||
50
+ variables[variableName] === undefined ||
51
+ !hasOwnProperty(variables, variableName)
52
+ ) {
49
53
  // No valid return value.
50
54
  return;
51
55
  }
@@ -192,6 +196,12 @@ function valueFromAST(valueNode, type, variables) {
192
196
  function isMissingVariable(valueNode, variables) {
193
197
  return (
194
198
  valueNode.kind === _kinds.Kind.VARIABLE &&
195
- (variables == null || variables[valueNode.name.value] === undefined)
199
+ (variables == null ||
200
+ variables[valueNode.name.value] === undefined ||
201
+ !hasOwnProperty(variables, valueNode.name.value))
196
202
  );
197
203
  }
204
+
205
+ function hasOwnProperty(obj, prop) {
206
+ return Object.prototype.hasOwnProperty.call(obj, prop);
207
+ }
@@ -39,7 +39,11 @@ export function valueFromAST(valueNode, type, variables) {
39
39
  if (valueNode.kind === Kind.VARIABLE) {
40
40
  const variableName = valueNode.name.value;
41
41
 
42
- if (variables == null || variables[variableName] === undefined) {
42
+ if (
43
+ variables == null ||
44
+ variables[variableName] === undefined ||
45
+ !hasOwnProperty(variables, variableName)
46
+ ) {
43
47
  // No valid return value.
44
48
  return;
45
49
  }
@@ -179,6 +183,12 @@ export function valueFromAST(valueNode, type, variables) {
179
183
  function isMissingVariable(valueNode, variables) {
180
184
  return (
181
185
  valueNode.kind === Kind.VARIABLE &&
182
- (variables == null || variables[valueNode.name.value] === undefined)
186
+ (variables == null ||
187
+ variables[valueNode.name.value] === undefined ||
188
+ !hasOwnProperty(variables, valueNode.name.value))
183
189
  );
184
190
  }
191
+
192
+ function hasOwnProperty(obj, prop) {
193
+ return Object.prototype.hasOwnProperty.call(obj, prop);
194
+ }
@@ -140,6 +140,10 @@ function getDirectiveLocationForASTPath(ancestors) {
140
140
  ? _directiveLocation.DirectiveLocation.INPUT_FIELD_DEFINITION
141
141
  : _directiveLocation.DirectiveLocation.ARGUMENT_DEFINITION;
142
142
  }
143
+
144
+ case _kinds.Kind.DIRECTIVE_DEFINITION:
145
+ case _kinds.Kind.DIRECTIVE_EXTENSION:
146
+ return _directiveLocation.DirectiveLocation.DIRECTIVE_DEFINITION;
143
147
  // Not reachable, all possible types have been considered.
144
148
 
145
149
  /* c8 ignore next */
@@ -127,6 +127,10 @@ function getDirectiveLocationForASTPath(ancestors) {
127
127
  ? DirectiveLocation.INPUT_FIELD_DEFINITION
128
128
  : DirectiveLocation.ARGUMENT_DEFINITION;
129
129
  }
130
+
131
+ case Kind.DIRECTIVE_DEFINITION:
132
+ case Kind.DIRECTIVE_EXTENSION:
133
+ return DirectiveLocation.DIRECTIVE_DEFINITION;
130
134
  // Not reachable, all possible types have been considered.
131
135
 
132
136
  /* c8 ignore next */
@@ -42,6 +42,7 @@ function UniqueDirectivesPerLocationRule(context) {
42
42
 
43
43
  const schemaDirectives = Object.create(null);
44
44
  const typeDirectivesMap = Object.create(null);
45
+ const directiveDirectivesMap = Object.create(null);
45
46
  return {
46
47
  // Many different AST nodes may contain directives. Rather than listing
47
48
  // them all, just listen for entering any node, and check to see if it
@@ -68,6 +69,17 @@ function UniqueDirectivesPerLocationRule(context) {
68
69
  if (seenDirectives === undefined) {
69
70
  typeDirectivesMap[typeName] = seenDirectives = Object.create(null);
70
71
  }
72
+ } else if (
73
+ node.kind === _kinds.Kind.DIRECTIVE_DEFINITION ||
74
+ node.kind === _kinds.Kind.DIRECTIVE_EXTENSION
75
+ ) {
76
+ const directiveName = node.name.value;
77
+ seenDirectives = directiveDirectivesMap[directiveName];
78
+
79
+ if (seenDirectives === undefined) {
80
+ directiveDirectivesMap[directiveName] = seenDirectives =
81
+ Object.create(null);
82
+ }
71
83
  } else {
72
84
  seenDirectives = Object.create(null);
73
85
  }
@@ -35,6 +35,7 @@ export function UniqueDirectivesPerLocationRule(context) {
35
35
 
36
36
  const schemaDirectives = Object.create(null);
37
37
  const typeDirectivesMap = Object.create(null);
38
+ const directiveDirectivesMap = Object.create(null);
38
39
  return {
39
40
  // Many different AST nodes may contain directives. Rather than listing
40
41
  // them all, just listen for entering any node, and check to see if it
@@ -58,6 +59,17 @@ export function UniqueDirectivesPerLocationRule(context) {
58
59
  if (seenDirectives === undefined) {
59
60
  typeDirectivesMap[typeName] = seenDirectives = Object.create(null);
60
61
  }
62
+ } else if (
63
+ node.kind === Kind.DIRECTIVE_DEFINITION ||
64
+ node.kind === Kind.DIRECTIVE_EXTENSION
65
+ ) {
66
+ const directiveName = node.name.value;
67
+ seenDirectives = directiveDirectivesMap[directiveName];
68
+
69
+ if (seenDirectives === undefined) {
70
+ directiveDirectivesMap[directiveName] = seenDirectives =
71
+ Object.create(null);
72
+ }
61
73
  } else {
62
74
  seenDirectives = Object.create(null);
63
75
  }