@apollo/federation-internals 2.0.0-alpha.2 → 2.0.0-alpha.6

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 (66) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/buildSchema.d.ts.map +1 -1
  3. package/dist/buildSchema.js +3 -3
  4. package/dist/buildSchema.js.map +1 -1
  5. package/dist/debug.d.ts.map +1 -1
  6. package/dist/debug.js +2 -18
  7. package/dist/debug.js.map +1 -1
  8. package/dist/definitions.d.ts +18 -7
  9. package/dist/definitions.d.ts.map +1 -1
  10. package/dist/definitions.js +80 -26
  11. package/dist/definitions.js.map +1 -1
  12. package/dist/error.d.ts +88 -3
  13. package/dist/error.d.ts.map +1 -1
  14. package/dist/error.js +145 -5
  15. package/dist/error.js.map +1 -1
  16. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  17. package/dist/extractSubgraphsFromSupergraph.js +41 -4
  18. package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
  19. package/dist/federation.d.ts +4 -1
  20. package/dist/federation.d.ts.map +1 -1
  21. package/dist/federation.js +231 -58
  22. package/dist/federation.js.map +1 -1
  23. package/dist/genErrorCodeDoc.d.ts +2 -0
  24. package/dist/genErrorCodeDoc.d.ts.map +1 -0
  25. package/dist/genErrorCodeDoc.js +55 -0
  26. package/dist/genErrorCodeDoc.js.map +1 -0
  27. package/dist/inaccessibleSpec.d.ts.map +1 -1
  28. package/dist/inaccessibleSpec.js +1 -1
  29. package/dist/inaccessibleSpec.js.map +1 -1
  30. package/dist/joinSpec.d.ts.map +1 -1
  31. package/dist/joinSpec.js +6 -5
  32. package/dist/joinSpec.js.map +1 -1
  33. package/dist/operations.d.ts.map +1 -1
  34. package/dist/operations.js +15 -15
  35. package/dist/operations.js.map +1 -1
  36. package/dist/tagSpec.d.ts +2 -2
  37. package/dist/tagSpec.d.ts.map +1 -1
  38. package/dist/tagSpec.js +10 -2
  39. package/dist/tagSpec.js.map +1 -1
  40. package/dist/utils.d.ts +2 -0
  41. package/dist/utils.d.ts.map +1 -1
  42. package/dist/utils.js +34 -1
  43. package/dist/utils.js.map +1 -1
  44. package/dist/values.d.ts +2 -1
  45. package/dist/values.d.ts.map +1 -1
  46. package/dist/values.js +27 -1
  47. package/dist/values.js.map +1 -1
  48. package/jest.config.js +5 -1
  49. package/package.json +3 -6
  50. package/src/__tests__/extractSubgraphsFromSupergraph.test.ts +535 -0
  51. package/src/__tests__/subgraphValidation.test.ts +480 -0
  52. package/src/buildSchema.ts +7 -6
  53. package/src/debug.ts +2 -19
  54. package/src/definitions.ts +151 -40
  55. package/src/error.ts +340 -7
  56. package/src/extractSubgraphsFromSupergraph.ts +50 -5
  57. package/src/federation.ts +297 -92
  58. package/src/genErrorCodeDoc.ts +69 -0
  59. package/src/inaccessibleSpec.ts +7 -2
  60. package/src/joinSpec.ts +11 -5
  61. package/src/operations.ts +20 -18
  62. package/src/tagSpec.ts +11 -6
  63. package/src/utils.ts +49 -0
  64. package/src/values.ts +47 -5
  65. package/tsconfig.test.tsbuildinfo +1 -1
  66. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,480 @@
1
+ import { DocumentNode } from 'graphql';
2
+ import gql from 'graphql-tag';
3
+ import { errorCauses } from '..';
4
+ import { buildSubgraph } from "../federation"
5
+
6
+ // Builds the provided subgraph (using name 'S' for the subgraph) and, if the
7
+ // subgraph is invalid/has errors, return those errors as a list of [code, message].
8
+ // If the subgraph is valid, return undefined.
9
+ function buildForErrors(subgraphDefs: DocumentNode, subgraphName: string = 'S'): [string, string][] | undefined {
10
+ try {
11
+ buildSubgraph(subgraphName, subgraphDefs);
12
+ return undefined;
13
+ } catch (e) {
14
+ const causes = errorCauses(e);
15
+ if (!causes) {
16
+ throw e;
17
+ }
18
+ return causes.map((err) => [err.extensions.code as string, err.message]);
19
+ }
20
+ }
21
+
22
+ describe('fieldset-based directives', () => {
23
+ it('rejects field defined with arguments in @key', () => {
24
+ const subgraph = gql`
25
+ type Query {
26
+ t: T
27
+ }
28
+
29
+ type T @key(fields: "f") {
30
+ f(x: Int): Int
31
+ }
32
+ `
33
+ expect(buildForErrors(subgraph)).toStrictEqual([
34
+ ['KEY_FIELDS_HAS_ARGS', '[S] On type "T", for @key(fields: "f"): field T.f cannot be included because it has arguments (fields with argument are not allowed in @key)']
35
+ ]);
36
+ });
37
+
38
+ it('rejects field defined with arguments in @provides', () => {
39
+ const subgraph = gql`
40
+ type Query {
41
+ t: T @provides(fields: "f")
42
+ }
43
+
44
+ type T {
45
+ f(x: Int): Int @external
46
+ }
47
+ `
48
+ expect(buildForErrors(subgraph)).toStrictEqual([
49
+ ['PROVIDES_FIELDS_HAS_ARGS', '[S] On field "Query.t", for @provides(fields: "f"): field T.f cannot be included because it has arguments (fields with argument are not allowed in @provides)']
50
+ ]);
51
+ });
52
+
53
+ it('rejects field defined with arguments in @requires', () => {
54
+ const subgraph = gql`
55
+ type Query {
56
+ t: T
57
+ }
58
+
59
+ type T {
60
+ f(x: Int): Int @external
61
+ g: Int @requires(fields: "f")
62
+ }
63
+ `
64
+ expect(buildForErrors(subgraph)).toStrictEqual([
65
+ ['REQUIRES_FIELDS_HAS_ARGS', '[S] On field "T.g", for @requires(fields: "f"): field T.f cannot be included because it has arguments (fields with argument are not allowed in @requires)']
66
+ ]);
67
+ });
68
+
69
+ it('rejects @provides on non-external fields', () => {
70
+ const subgraph = gql`
71
+ type Query {
72
+ t: T @provides(fields: "f")
73
+ }
74
+
75
+ type T {
76
+ f: Int
77
+ }
78
+ `
79
+ expect(buildForErrors(subgraph)).toStrictEqual([
80
+ ['PROVIDES_FIELDS_MISSING_EXTERNAL', '[S] On field "Query.t", for @provides(fields: "f"): field "T.f" should not be part of a @provides since it is already provided by this subgraph (it is not marked @external)']
81
+ ]);
82
+ });
83
+
84
+ it('rejects @requires on non-external fields', () => {
85
+ const subgraph = gql`
86
+ type Query {
87
+ t: T
88
+ }
89
+
90
+ type T {
91
+ f: Int
92
+ g: Int @requires(fields: "f")
93
+ }
94
+ `
95
+ expect(buildForErrors(subgraph)).toStrictEqual([
96
+ ['REQUIRES_FIELDS_MISSING_EXTERNAL', '[S] On field "T.g", for @requires(fields: "f"): field "T.f" should not be part of a @requires since it is already provided by this subgraph (it is not marked @external)']
97
+ ]);
98
+ });
99
+
100
+ it('rejects @key on interfaces', () => {
101
+ const subgraph = gql`
102
+ type Query {
103
+ t: T
104
+ }
105
+
106
+ interface T @key(fields: "f") {
107
+ f: Int
108
+ }
109
+ `
110
+ expect(buildForErrors(subgraph)).toStrictEqual([
111
+ ['KEY_UNSUPPORTED_ON_INTERFACE', '[S] Cannot use @key on interface "T": @key is not yet supported on interfaces'],
112
+ ]);
113
+ });
114
+
115
+ it('rejects @provides on interfaces', () => {
116
+ const subgraph = gql`
117
+ type Query {
118
+ t: T
119
+ }
120
+
121
+ interface T {
122
+ f: U @provides(fields: "g")
123
+ }
124
+
125
+ type U {
126
+ g: Int @external
127
+ }
128
+ `
129
+ expect(buildForErrors(subgraph)).toStrictEqual([
130
+ ['PROVIDES_UNSUPPORTED_ON_INTERFACE', '[S] Cannot use @provides on field "T.f" of parent type "T": @provides is not yet supported within interfaces'],
131
+ ]);
132
+ });
133
+
134
+ it('rejects @requires on interfaces', () => {
135
+ const subgraph = gql`
136
+ type Query {
137
+ t: T
138
+ }
139
+
140
+ interface T {
141
+ f: Int @external
142
+ g: Int @requires(fields: "f")
143
+ }
144
+ `
145
+ expect(buildForErrors(subgraph)).toStrictEqual([
146
+ ['REQUIRES_UNSUPPORTED_ON_INTERFACE', '[S] Cannot use @requires on field "T.g" of parent type "T": @requires is not yet supported within interfaces' ],
147
+ ]);
148
+ });
149
+
150
+ it('rejects unused @external', () => {
151
+ const subgraph = gql`
152
+ type Query {
153
+ t: T
154
+ }
155
+
156
+ type T {
157
+ f: Int @external
158
+ }
159
+ `
160
+ expect(buildForErrors(subgraph)).toStrictEqual([
161
+ ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).'],
162
+ ]);
163
+ });
164
+
165
+ it('rejects @provides on non-object fields', () => {
166
+ const subgraph = gql`
167
+ type Query {
168
+ t: Int @provides(fields: "f")
169
+ }
170
+
171
+ type T {
172
+ f: Int
173
+ }
174
+ `
175
+ expect(buildForErrors(subgraph)).toStrictEqual([
176
+ ['PROVIDES_ON_NON_OBJECT_FIELD', '[S] Invalid @provides directive on field "Query.t": field has type "Int" which is not a Composite Type'],
177
+ ]);
178
+ });
179
+
180
+ it('rejects a non-string argument to @key', () => {
181
+ const subgraph = gql`
182
+ type Query {
183
+ t: T
184
+ }
185
+
186
+ type T @key(fields: ["f"]) {
187
+ f: Int
188
+ }
189
+ `
190
+ expect(buildForErrors(subgraph)).toStrictEqual([
191
+ ['KEY_INVALID_FIELDS_TYPE', '[S] On type "T", for @key(fields: ["f"]): Invalid value for argument "fields": must be a string.'],
192
+ ]);
193
+ });
194
+
195
+ it('rejects a non-string argument to @provides', () => {
196
+ const subgraph = gql`
197
+ type Query {
198
+ t: T @provides(fields: ["f"])
199
+ }
200
+
201
+ type T {
202
+ f: Int @external
203
+ }
204
+ `
205
+ // Note: since the error here is that we cannot parse the key `fields`, this also mean that @external on
206
+ // `f` will appear unused and we get an error for it. It's kind of hard to avoid cleanly and hopefully
207
+ // not a big deal (having errors dependencies is not exactly unheard of).
208
+ expect(buildForErrors(subgraph)).toStrictEqual([
209
+ ['PROVIDES_INVALID_FIELDS_TYPE', '[S] On field "Query.t", for @provides(fields: ["f"]): Invalid value for argument "fields": must be a string.'],
210
+ ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).' ],
211
+ ]);
212
+ });
213
+
214
+ it('rejects a non-string argument to @requires', () => {
215
+ const subgraph = gql`
216
+ type Query {
217
+ t: T
218
+ }
219
+
220
+ type T {
221
+ f: Int @external
222
+ g: Int @requires(fields: ["f"])
223
+ }
224
+ `
225
+ // Note: since the error here is that we cannot parse the key `fields`, this also mean that @external on
226
+ // `f` will appear unused and we get an error for it. It's kind of hard to avoid cleanly and hopefully
227
+ // not a big deal (having errors dependencies is not exactly unheard of).
228
+ expect(buildForErrors(subgraph)).toStrictEqual([
229
+ ['REQUIRES_INVALID_FIELDS_TYPE', '[S] On field "T.g", for @requires(fields: ["f"]): Invalid value for argument "fields": must be a string.'],
230
+ ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).' ],
231
+ ]);
232
+ });
233
+
234
+ // Special case of non-string argument, specialized because it hits a different
235
+ // code-path due to enum values being parsed as string and requiring special care.
236
+ it('rejects an enum-like argument to @key', () => {
237
+ const subgraph = gql`
238
+ type Query {
239
+ t: T
240
+ }
241
+
242
+ type T @key(fields: f) {
243
+ f: Int
244
+ }
245
+ `
246
+ expect(buildForErrors(subgraph)).toStrictEqual([
247
+ ['KEY_INVALID_FIELDS_TYPE', '[S] On type "T", for @key(fields: f): Invalid value for argument "fields": must be a string.'],
248
+ ]);
249
+ });
250
+
251
+ // Special case of non-string argument, specialized because it hits a different
252
+ // code-path due to enum values being parsed as string and requiring special care.
253
+ it('rejects an enum-lik argument to @provides', () => {
254
+ const subgraph = gql`
255
+ type Query {
256
+ t: T @provides(fields: f)
257
+ }
258
+
259
+ type T {
260
+ f: Int @external
261
+ }
262
+ `
263
+ // Note: since the error here is that we cannot parse the key `fields`, this also mean that @external on
264
+ // `f` will appear unused and we get an error for it. It's kind of hard to avoid cleanly and hopefully
265
+ // not a big deal (having errors dependencies is not exactly unheard of).
266
+ expect(buildForErrors(subgraph)).toStrictEqual([
267
+ ['PROVIDES_INVALID_FIELDS_TYPE', '[S] On field "Query.t", for @provides(fields: f): Invalid value for argument "fields": must be a string.'],
268
+ ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).' ],
269
+ ]);
270
+ });
271
+
272
+ // Special case of non-string argument, specialized because it hits a different
273
+ // code-path due to enum values being parsed as string and requiring special care.
274
+ it('rejects an enum-like argument to @requires', () => {
275
+ const subgraph = gql`
276
+ type Query {
277
+ t: T
278
+ }
279
+
280
+ type T {
281
+ f: Int @external
282
+ g: Int @requires(fields: f)
283
+ }
284
+ `
285
+ // Note: since the error here is that we cannot parse the key `fields`, this also mean that @external on
286
+ // `f` will appear unused and we get an error for it. It's kind of hard to avoid cleanly and hopefully
287
+ // not a big deal (having errors dependencies is not exactly unheard of).
288
+ expect(buildForErrors(subgraph)).toStrictEqual([
289
+ ['REQUIRES_INVALID_FIELDS_TYPE', '[S] On field "T.g", for @requires(fields: f): Invalid value for argument "fields": must be a string.'],
290
+ ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).' ],
291
+ ]);
292
+ });
293
+
294
+ it('rejects an invalid `fields` argument to @key', () => {
295
+ const subgraph = gql`
296
+ type Query {
297
+ t: T
298
+ }
299
+
300
+ type T @key(fields: ":f") {
301
+ f: Int
302
+ }
303
+ `
304
+ expect(buildForErrors(subgraph)).toStrictEqual([
305
+ ['KEY_INVALID_FIELDS', '[S] On type "T", for @key(fields: ":f"): Syntax Error: Expected Name, found ":".'],
306
+ ]);
307
+ });
308
+
309
+ it('rejects an invalid `fields` argument to @provides', () => {
310
+ const subgraph = gql`
311
+ type Query {
312
+ t: T @provides(fields: "{{f}}")
313
+ }
314
+
315
+ type T {
316
+ f: Int @external
317
+ }
318
+ `
319
+ expect(buildForErrors(subgraph)).toStrictEqual([
320
+ ['PROVIDES_INVALID_FIELDS', '[S] On field "Query.t", for @provides(fields: "{{f}}"): Syntax Error: Expected Name, found "{".'],
321
+ ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).' ],
322
+ ]);
323
+ });
324
+
325
+ it('rejects an invalid `fields` argument to @requires', () => {
326
+ const subgraph = gql`
327
+ type Query {
328
+ t: T
329
+ }
330
+
331
+ type T {
332
+ f: Int @external
333
+ g: Int @requires(fields: "f b")
334
+ }
335
+ `
336
+ expect(buildForErrors(subgraph)).toStrictEqual([
337
+ ['REQUIRES_INVALID_FIELDS', '[S] On field "T.g", for @requires(fields: "f b"): Cannot query field "b" on type "T" (if the field is defined in another subgraph, you need to add it to this subgraph with @external).'],
338
+ ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).' ],
339
+ ]);
340
+ });
341
+
342
+ it('rejects @key on a list field', () => {
343
+ const subgraph = gql`
344
+ type Query {
345
+ t: T
346
+ }
347
+
348
+ type T @key(fields: "f") {
349
+ f: [Int]
350
+ }
351
+ `
352
+ expect(buildForErrors(subgraph)).toStrictEqual([
353
+ ['KEY_FIELDS_SELECT_INVALID_TYPE', '[S] On type "T", for @key(fields: "f"): field "T.f" is a List type which is not allowed in @key'],
354
+ ]);
355
+ });
356
+
357
+ it('rejects @key on an interface field', () => {
358
+ const subgraph = gql`
359
+ type Query {
360
+ t: T
361
+ }
362
+
363
+ type T @key(fields: "f") {
364
+ f: I
365
+ }
366
+
367
+ interface I {
368
+ i: Int
369
+ }
370
+ `
371
+ expect(buildForErrors(subgraph)).toStrictEqual([
372
+ ['KEY_FIELDS_SELECT_INVALID_TYPE', '[S] On type "T", for @key(fields: "f"): field "T.f" is a Interface type which is not allowed in @key'],
373
+ ]);
374
+ });
375
+
376
+ it('rejects @key on an union field', () => {
377
+ const subgraph = gql`
378
+ type Query {
379
+ t: T
380
+ }
381
+
382
+ type T @key(fields: "f") {
383
+ f: U
384
+ }
385
+
386
+ union U = Query | T
387
+ `
388
+ expect(buildForErrors(subgraph)).toStrictEqual([
389
+ ['KEY_FIELDS_SELECT_INVALID_TYPE', '[S] On type "T", for @key(fields: "f"): field "T.f" is a Union type which is not allowed in @key'],
390
+ ]);
391
+ });
392
+ });
393
+
394
+ describe('root types', () => {
395
+ it('rejects using Query as type name if not the query root', () => {
396
+ const subgraph = gql`
397
+ schema {
398
+ query: MyQuery
399
+ }
400
+
401
+ type MyQuery {
402
+ f: Int
403
+ }
404
+
405
+ type Query {
406
+ g: Int
407
+ }
408
+ `
409
+ expect(buildForErrors(subgraph)).toStrictEqual([
410
+ ['ROOT_QUERY_USED', '[S] The schema has a type named "Query" but it is not set as the query root type ("MyQuery" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name.'],
411
+ ]);
412
+ });
413
+
414
+ it('rejects using Mutation as type name if not the mutation root', () => {
415
+ const subgraph = gql`
416
+ schema {
417
+ mutation: MyMutation
418
+ }
419
+
420
+ type MyMutation {
421
+ f: Int
422
+ }
423
+
424
+ type Mutation {
425
+ g: Int
426
+ }
427
+ `
428
+ expect(buildForErrors(subgraph)).toStrictEqual([
429
+ ['ROOT_MUTATION_USED', '[S] The schema has a type named "Mutation" but it is not set as the mutation root type ("MyMutation" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name.'],
430
+ ]);
431
+ });
432
+
433
+ it('rejects using Subscription as type name if not the subscription root', () => {
434
+ const subgraph = gql`
435
+ schema {
436
+ subscription: MySubscription
437
+ }
438
+
439
+ type MySubscription {
440
+ f: Int
441
+ }
442
+
443
+ type Subscription {
444
+ g: Int
445
+ }
446
+ `
447
+ expect(buildForErrors(subgraph)).toStrictEqual([
448
+ ['ROOT_SUBSCRIPTION_USED', '[S] The schema has a type named "Subscription" but it is not set as the subscription root type ("MySubscription" is instead): this is not supported by federation. If a root type does not use its default name, there should be no other type with that default name.'],
449
+ ]);
450
+ });
451
+ });
452
+
453
+
454
+ it('validates all implementations of interface field have same type if any has @external', () => {
455
+ const subgraph = gql`
456
+ type Query {
457
+ is: [I!]!
458
+ }
459
+
460
+ interface I {
461
+ f: Int
462
+ }
463
+
464
+ type T1 implements I {
465
+ f: Int
466
+ }
467
+
468
+ type T2 implements I {
469
+ f: Int!
470
+ }
471
+
472
+ type T3 implements I {
473
+ id: ID!
474
+ f: Int @external
475
+ }
476
+ `;
477
+ expect(buildForErrors(subgraph)).toStrictEqual([
478
+ ['INTERFACE_FIELD_IMPLEM_TYPE_MISMATCH', '[S] Some of the runtime implementations of interface field "I.f" are marked @external or have a @require ("T3.f") so all the implementations should use the same type (a current limitation of federation; see https://github.com/apollographql/federation/issues/1257), but "T1.f" and "T3.f" have type "Int" while "T2.f" has type "Int!".'],
479
+ ]);
480
+ })
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DefinitionNode,
3
3
  DirectiveDefinitionNode,
4
- DirectiveLocationEnum,
4
+ DirectiveLocation,
5
5
  DirectiveNode,
6
6
  DocumentNode,
7
7
  FieldDefinitionNode,
@@ -18,7 +18,8 @@ import {
18
18
  StringValueNode,
19
19
  ASTNode,
20
20
  SchemaExtensionNode,
21
- parseType
21
+ parseType,
22
+ Kind,
22
23
  } from "graphql";
23
24
  import { Maybe } from "graphql/jsutils/Maybe";
24
25
  import {
@@ -332,11 +333,11 @@ export function builtTypeReference(encodedType: string, schema: Schema): Type {
332
333
 
333
334
  function buildTypeReferenceFromAST(typeNode: TypeNode, schema: Schema): Type {
334
335
  switch (typeNode.kind) {
335
- case 'ListType':
336
+ case Kind.LIST_TYPE:
336
337
  return new ListType(buildTypeReferenceFromAST(typeNode.type, schema));
337
- case 'NonNullType':
338
+ case Kind.NON_NULL_TYPE:
338
339
  const wrapped = buildTypeReferenceFromAST(typeNode.type, schema);
339
- if (wrapped.kind == 'NonNullType') {
340
+ if (wrapped.kind == Kind.NON_NULL_TYPE) {
340
341
  throw new GraphQLError(`Cannot apply the non-null operator (!) twice to the same type`, typeNode);
341
342
  }
342
343
  return new NonNullType(wrapped);
@@ -368,7 +369,7 @@ function buildDirectiveDefinitionInner(directiveNode: DirectiveDefinitionNode, d
368
369
  buildArgumentDefinitionInner(inputValueDef, directive.addArgument(inputValueDef.name.value));
369
370
  }
370
371
  directive.repeatable = directiveNode.repeatable;
371
- const locations = directiveNode.locations.map(({ value }) => value as DirectiveLocationEnum);
372
+ const locations = directiveNode.locations.map(({ value }) => value as DirectiveLocation);
372
373
  directive.addLocations(...locations);
373
374
  directive.description = directiveNode.description?.value;
374
375
  directive.sourceAST = directiveNode;
package/src/debug.ts CHANGED
@@ -1,24 +1,7 @@
1
1
  // Simple debugging facility.
2
2
 
3
3
  import chalk from 'chalk';
4
-
5
- function stringIsBoolean(str?: string) : boolean | undefined {
6
- if (!str) {
7
- return false;
8
- }
9
- switch (str.toLocaleLowerCase()) {
10
- case "true":
11
- case "yes":
12
- case "1":
13
- return true;
14
- case "false":
15
- case "no":
16
- case "0":
17
- return false;
18
- default:
19
- return undefined;
20
- }
21
- }
4
+ import { validateStringContainsBoolean } from './utils';
22
5
 
23
6
  function indentString(indentLevel: number) : string {
24
7
  let str = "";
@@ -30,7 +13,7 @@ function indentString(indentLevel: number) : string {
30
13
 
31
14
  function isEnabled(name: string): boolean {
32
15
  const v = process.env.APOLLO_FEDERATION_DEBUG;
33
- const bool = stringIsBoolean(v);
16
+ const bool = validateStringContainsBoolean(v);
34
17
  if (bool !== undefined) {
35
18
  return bool;
36
19
  }