@apollo/federation-internals 2.0.0-alpha.0 → 2.0.0-alpha.4

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 (86) hide show
  1. package/CHANGELOG.md +18 -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/coreSpec.d.ts +1 -1
  6. package/dist/coreSpec.d.ts.map +1 -1
  7. package/dist/coreSpec.js +2 -0
  8. package/dist/coreSpec.js.map +1 -1
  9. package/dist/debug.d.ts.map +1 -1
  10. package/dist/debug.js +7 -23
  11. package/dist/debug.js.map +1 -1
  12. package/dist/definitions.d.ts +28 -13
  13. package/dist/definitions.d.ts.map +1 -1
  14. package/dist/definitions.js +132 -71
  15. package/dist/definitions.js.map +1 -1
  16. package/dist/error.d.ts +87 -3
  17. package/dist/error.d.ts.map +1 -1
  18. package/dist/error.js +143 -5
  19. package/dist/error.js.map +1 -1
  20. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  21. package/dist/extractSubgraphsFromSupergraph.js +60 -8
  22. package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
  23. package/dist/federation.d.ts +7 -6
  24. package/dist/federation.d.ts.map +1 -1
  25. package/dist/federation.js +227 -81
  26. package/dist/federation.js.map +1 -1
  27. package/dist/genErrorCodeDoc.d.ts +2 -0
  28. package/dist/genErrorCodeDoc.d.ts.map +1 -0
  29. package/dist/genErrorCodeDoc.js +55 -0
  30. package/dist/genErrorCodeDoc.js.map +1 -0
  31. package/dist/inaccessibleSpec.d.ts +1 -1
  32. package/dist/inaccessibleSpec.d.ts.map +1 -1
  33. package/dist/inaccessibleSpec.js +5 -5
  34. package/dist/inaccessibleSpec.js.map +1 -1
  35. package/dist/joinSpec.d.ts.map +1 -1
  36. package/dist/joinSpec.js +6 -5
  37. package/dist/joinSpec.js.map +1 -1
  38. package/dist/operations.d.ts.map +1 -1
  39. package/dist/operations.js +16 -16
  40. package/dist/operations.js.map +1 -1
  41. package/dist/print.d.ts +1 -1
  42. package/dist/print.d.ts.map +1 -1
  43. package/dist/print.js +4 -4
  44. package/dist/print.js.map +1 -1
  45. package/dist/suggestions.js +1 -1
  46. package/dist/suggestions.js.map +1 -1
  47. package/dist/tagSpec.d.ts +2 -2
  48. package/dist/tagSpec.d.ts.map +1 -1
  49. package/dist/tagSpec.js +10 -2
  50. package/dist/tagSpec.js.map +1 -1
  51. package/dist/utils.d.ts +16 -0
  52. package/dist/utils.d.ts.map +1 -1
  53. package/dist/utils.js +82 -1
  54. package/dist/utils.js.map +1 -1
  55. package/dist/validate.js.map +1 -1
  56. package/dist/values.d.ts +2 -1
  57. package/dist/values.d.ts.map +1 -1
  58. package/dist/values.js +29 -4
  59. package/dist/values.js.map +1 -1
  60. package/package.json +5 -6
  61. package/src/__tests__/definitions.test.ts +3 -3
  62. package/src/__tests__/extractSubgraphsFromSupergraph.test.ts +432 -0
  63. package/src/__tests__/matchers/toMatchString.ts +2 -2
  64. package/src/__tests__/removeInaccessibleElements.test.ts +8 -8
  65. package/src/__tests__/subgraphValidation.test.ts +452 -0
  66. package/src/__tests__/utils.test.ts +92 -0
  67. package/src/buildSchema.ts +12 -11
  68. package/src/coreSpec.ts +12 -10
  69. package/src/debug.ts +8 -25
  70. package/src/definitions.ts +249 -115
  71. package/src/error.ts +334 -7
  72. package/src/extractSubgraphsFromSupergraph.ts +80 -19
  73. package/src/federation.ts +299 -138
  74. package/src/genErrorCodeDoc.ts +69 -0
  75. package/src/inaccessibleSpec.ts +13 -8
  76. package/src/joinSpec.ts +11 -8
  77. package/src/operations.ts +40 -38
  78. package/src/print.ts +8 -8
  79. package/src/suggestions.ts +1 -1
  80. package/src/tagSpec.ts +12 -7
  81. package/src/types.ts +1 -1
  82. package/src/utils.ts +109 -0
  83. package/src/validate.ts +4 -4
  84. package/src/values.ts +51 -9
  85. package/tsconfig.test.tsbuildinfo +1 -1
  86. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,452 @@
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
+
@@ -0,0 +1,92 @@
1
+ import { OrderedMap } from '../utils';
2
+
3
+ describe('OrderedMap', () => {
4
+ it('updating value works', () => {
5
+ const orderedMap = new OrderedMap<string, number>();
6
+ orderedMap.add('one', 0);
7
+ expect(orderedMap.get('one')).toBe(0);
8
+ expect(orderedMap.size).toBe(1);
9
+
10
+ orderedMap.add('one', 1);
11
+ expect(orderedMap.get('one')).toBe(1);
12
+ expect(orderedMap.size).toBe(1);
13
+ expect(orderedMap.keys()).toEqual(['one']);
14
+ expect(orderedMap.values()).toEqual([1]);
15
+ });
16
+
17
+ it('test lexicographical sorting of map (default sorting algorithm)', () => {
18
+ const orderedMap = new OrderedMap<string, number>();
19
+ orderedMap.add('one', 1);
20
+ orderedMap.add('two', 2);
21
+ orderedMap.add('three', 3);
22
+ orderedMap.add('four', 4);
23
+ orderedMap.add('five', 5);
24
+ orderedMap.add('six', 6);
25
+ orderedMap.add('seven', 7);
26
+ orderedMap.add('eight', 8);
27
+ orderedMap.add('nine', 9);
28
+
29
+ // keys are in alphabetical order
30
+ expect(orderedMap.keys()).toEqual(['eight', 'five', 'four', 'nine', 'one', 'seven', 'six', 'three', 'two']);
31
+ const sortedArr = [8,5,4,9,1,7,6,3,2];
32
+ expect(orderedMap.values()).toEqual(sortedArr);
33
+
34
+ // test using spread operator to make sure iterator is performing correctly
35
+ expect([...orderedMap]).toEqual(sortedArr);
36
+
37
+ // testing get function
38
+ expect(orderedMap.get('one')).toBe(1);
39
+ expect(orderedMap.get('ten')).toBeUndefined();
40
+
41
+ // testing size function
42
+ expect(orderedMap.size).toBe(9);
43
+ orderedMap.add('one', 1);
44
+ expect(orderedMap.size).toBe(9);
45
+ expect(orderedMap.values()).toEqual(sortedArr);
46
+
47
+ // has function
48
+ expect(orderedMap.has('one')).toBe(true);
49
+ expect(orderedMap.has('fifty')).toBe(false);
50
+ });
51
+
52
+ it('sort by string length', () => {
53
+ const orderedMap = new OrderedMap<string, number>((a: string, b: string) => {
54
+ if (a.length < b.length) {
55
+ return -1;
56
+ } else if (b.length < a.length) {
57
+ return 1;
58
+ }
59
+ return 0;
60
+ });
61
+ orderedMap.add('eight', 8);
62
+ orderedMap.add('seventy', 70);
63
+ orderedMap.add('six', 6);
64
+ orderedMap.add('four', 4);
65
+
66
+ expect(orderedMap.keys()).toEqual(['six', 'four', 'eight', 'seventy']);
67
+ const sortedArr = [6,4,8,70];
68
+ expect(orderedMap.values()).toEqual(sortedArr);
69
+
70
+ // test using spread operator to make sure iterator is performing correctly
71
+ expect([...orderedMap]).toEqual(sortedArr);
72
+ });
73
+
74
+ it('sort numerically', () => {
75
+ const orderedMap = new OrderedMap<number, number>();
76
+ orderedMap.add(4, 40);
77
+ orderedMap.add(1, 10);
78
+ orderedMap.add(7, 70);
79
+ orderedMap.add(2, 20);
80
+ orderedMap.add(6, 60);
81
+ orderedMap.add(3, 30);
82
+ orderedMap.add(9, 90);
83
+ orderedMap.add(5, 50);
84
+ orderedMap.add(8, 80);
85
+
86
+ const keys = [1,2,3,4,5,6,7,8,9];
87
+ const values = [10,20,30,40,50,60,70,80,90];
88
+ expect(orderedMap.keys()).toEqual(keys);
89
+ expect(orderedMap.values()).toEqual(values);
90
+ expect([...orderedMap]).toEqual(values);
91
+ });
92
+ });
@@ -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 {
@@ -57,7 +58,7 @@ function buildValue(value?: ValueNode): any {
57
58
  // - for ID, which accepts strings and int, we don't get int converted to string.
58
59
  // - for floats, we get either int or float, we don't get int converted to float.
59
60
  // - we don't get any custom coercion (but neither is buildSchema in graphQL-js anyway).
60
- // 2) type validation.
61
+ // 2) type validation.
61
62
  return value ? valueFromASTUntyped(value) : undefined;
62
63
  }
63
64
 
@@ -91,7 +92,7 @@ export function buildSchemaFromAST(documentNode: DocumentNode, builtIns: BuiltIn
91
92
  case 'SchemaExtension':
92
93
  buildSchemaDefinitionInner(
93
94
  definitionNode,
94
- schema.schemaDefinition,
95
+ schema.schemaDefinition,
95
96
  schema.schemaDefinition.newExtension());
96
97
  break;
97
98
  case 'ScalarTypeDefinition':
@@ -300,7 +301,7 @@ function buildNamedTypeInner(
300
301
  }
301
302
 
302
303
  function buildFieldDefinitionInner(fieldNode: FieldDefinitionNode, field: FieldDefinition<any>) {
303
- const type = buildTypeReferenceFromAST(fieldNode.type, field.schema()!);
304
+ const type = buildTypeReferenceFromAST(fieldNode.type, field.schema());
304
305
  field.type = ensureOutputType(type, field.coordinate, fieldNode);
305
306
  for (const inputValueDef of fieldNode.arguments ?? []) {
306
307
  buildArgumentDefinitionInner(inputValueDef, field.addArgument(inputValueDef.name.value));
@@ -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);
@@ -346,7 +347,7 @@ function buildTypeReferenceFromAST(typeNode: TypeNode, schema: Schema): Type {
346
347
  }
347
348
 
348
349
  function buildArgumentDefinitionInner(inputNode: InputValueDefinitionNode, arg: ArgumentDefinition<any>) {
349
- const type = buildTypeReferenceFromAST(inputNode.type, arg.schema()!);
350
+ const type = buildTypeReferenceFromAST(inputNode.type, arg.schema());
350
351
  arg.type = ensureInputType(type, arg.coordinate, inputNode);
351
352
  arg.defaultValue = buildValue(inputNode.defaultValue);
352
353
  buildAppliedDirectives(inputNode, arg);
@@ -355,7 +356,7 @@ function buildArgumentDefinitionInner(inputNode: InputValueDefinitionNode, arg:
355
356
  }
356
357
 
357
358
  function buildInputFieldDefinitionInner(fieldNode: InputValueDefinitionNode, field: InputFieldDefinition) {
358
- const type = buildTypeReferenceFromAST(fieldNode.type, field.schema()!);
359
+ const type = buildTypeReferenceFromAST(fieldNode.type, field.schema());
359
360
  field.type = ensureInputType(type, field.coordinate, fieldNode);
360
361
  field.defaultValue = buildValue(fieldNode.defaultValue);
361
362
  buildAppliedDirectives(fieldNode, field);
@@ -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;