@wundergraph/composition 0.17.1 → 0.18.1

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 (56) hide show
  1. package/dist/ast/ast.d.ts +2 -9
  2. package/dist/ast/ast.js +4 -32
  3. package/dist/ast/ast.js.map +1 -1
  4. package/dist/ast/utils.d.ts +1 -2
  5. package/dist/ast/utils.js.map +1 -1
  6. package/dist/errors/errors.d.ts +8 -12
  7. package/dist/errors/errors.js +27 -29
  8. package/dist/errors/errors.js.map +1 -1
  9. package/dist/federation/federation-factory.d.ts +7 -6
  10. package/dist/federation/federation-factory.js +38 -20
  11. package/dist/federation/federation-factory.js.map +1 -1
  12. package/dist/federation/utils.d.ts +4 -4
  13. package/dist/federation/utils.js +2 -2
  14. package/dist/federation/utils.js.map +1 -1
  15. package/dist/index.d.ts +8 -1
  16. package/dist/index.js +8 -1
  17. package/dist/index.js.map +1 -1
  18. package/dist/normalization/normalization-factory.d.ts +24 -27
  19. package/dist/normalization/normalization-factory.js +256 -961
  20. package/dist/normalization/normalization-factory.js.map +1 -1
  21. package/dist/normalization/utils.d.ts +6 -126
  22. package/dist/normalization/utils.js +71 -166
  23. package/dist/normalization/utils.js.map +1 -1
  24. package/dist/normalization/walkers.d.ts +5 -0
  25. package/dist/normalization/walkers.js +593 -0
  26. package/dist/normalization/walkers.js.map +1 -0
  27. package/dist/schema-building/ast.d.ts +104 -0
  28. package/dist/schema-building/ast.js +156 -0
  29. package/dist/schema-building/ast.js.map +1 -0
  30. package/dist/schema-building/type-definition-data.d.ts +108 -0
  31. package/dist/schema-building/type-definition-data.js +3 -0
  32. package/dist/schema-building/type-definition-data.js.map +1 -0
  33. package/dist/schema-building/type-extension-data.d.ts +45 -0
  34. package/dist/schema-building/type-extension-data.js +3 -0
  35. package/dist/schema-building/type-extension-data.js.map +1 -0
  36. package/dist/{type-merging → schema-building}/type-merging.js +5 -4
  37. package/dist/schema-building/type-merging.js.map +1 -0
  38. package/dist/schema-building/utils.d.ts +42 -0
  39. package/dist/schema-building/utils.js +600 -0
  40. package/dist/schema-building/utils.js.map +1 -0
  41. package/dist/subgraph/subgraph.d.ts +4 -5
  42. package/dist/subgraph/subgraph.js +2 -65
  43. package/dist/subgraph/subgraph.js.map +1 -1
  44. package/dist/tsconfig.tsbuildinfo +1 -1
  45. package/dist/utils/constants.d.ts +4 -2
  46. package/dist/utils/constants.js +383 -359
  47. package/dist/utils/constants.js.map +1 -1
  48. package/dist/utils/string-constants.d.ts +4 -0
  49. package/dist/utils/string-constants.js +6 -2
  50. package/dist/utils/string-constants.js.map +1 -1
  51. package/dist/utils/utils.d.ts +8 -6
  52. package/dist/utils/utils.js +72 -30
  53. package/dist/utils/utils.js.map +1 -1
  54. package/package.json +2 -2
  55. package/dist/type-merging/type-merging.js.map +0 -1
  56. /package/dist/{type-merging → schema-building}/type-merging.d.ts +0 -0
@@ -5,7 +5,7 @@ const graphql_1 = require("graphql");
5
5
  const utils_1 = require("../ast/utils");
6
6
  const utils_2 = require("./utils");
7
7
  const constants_1 = require("../utils/constants");
8
- const type_merging_1 = require("../type-merging/type-merging");
8
+ const type_merging_1 = require("../schema-building/type-merging");
9
9
  const utils_3 = require("../utils/utils");
10
10
  const errors_1 = require("../errors/errors");
11
11
  const string_constants_1 = require("../utils/string-constants");
@@ -14,6 +14,8 @@ const merge_1 = require("@graphql-tools/merge");
14
14
  const ast_1 = require("../ast/ast");
15
15
  const subgraph_1 = require("../subgraph/subgraph");
16
16
  const warnings_1 = require("../warnings/warnings");
17
+ const walkers_1 = require("./walkers");
18
+ const utils_4 = require("../schema-building/utils");
17
19
  function normalizeSubgraphFromString(subgraphSDL) {
18
20
  const { error, documentNode } = (0, utils_1.safeParse)(subgraphSDL);
19
21
  if (error || !documentNode) {
@@ -30,7 +32,7 @@ function normalizeSubgraph(document, subgraphName) {
30
32
  exports.normalizeSubgraph = normalizeSubgraph;
31
33
  class NormalizationFactory {
32
34
  abstractToConcreteTypeNames = new Map();
33
- allDirectiveDefinitions = new Map();
35
+ directiveDefinitionByDirectiveName = new Map();
34
36
  argumentName = '';
35
37
  authorizationDataByParentTypeName = new Map();
36
38
  childName = '';
@@ -39,36 +41,38 @@ class NormalizationFactory {
39
41
  errors = [];
40
42
  entityContainerByTypeName = new Map();
41
43
  entityInterfaces = new Map();
42
- extensionContainerByTypeName = new Map();
44
+ parentExtensionDataByTypeName = new Map();
45
+ interfaceTypeNamesWithAuthorizationDirectives = new Set();
43
46
  isCurrentParentExtension = false;
44
- isCurrentParentRootType = false;
45
47
  isSubgraphVersionTwo = false;
46
48
  fieldSetContainerByTypeName = new Map();
49
+ heirFieldAuthorizationDataByTypeName = new Map();
47
50
  handledRepeatedDirectivesByHostPath = new Map();
48
51
  lastParentNodeKind = graphql_1.Kind.NULL;
49
52
  lastChildNodeKind = graphql_1.Kind.NULL;
50
53
  leafTypeNamesWithAuthorizationDirectives = new Set();
51
54
  keyFieldNamesByParentTypeName = new Map();
52
55
  operationTypeNames = new Map();
53
- parentContainerByTypeName = new Map();
56
+ parentDefinitionDataByTypeName = new Map();
54
57
  parentTypeName = '';
55
58
  parentsWithChildArguments = new Set();
56
59
  eventsConfigurations = new Map();
57
60
  overridesByTargetSubgraphName = new Map();
61
+ invalidOrScopesHostPaths = new Set();
58
62
  schemaDefinition;
59
- referencedDirectives = new Set();
63
+ referencedDirectiveNames = new Set();
60
64
  referencedTypeNames = new Set();
61
65
  warnings = [];
62
66
  subgraphName;
63
67
  constructor(subgraphName) {
64
- for (const baseDirectiveDefinition of constants_1.BASE_DIRECTIVE_DEFINITIONS) {
65
- this.allDirectiveDefinitions.set(baseDirectiveDefinition.name.value, baseDirectiveDefinition);
68
+ for (const [baseDirectiveName, baseDirectiveDefinition] of constants_1.BASE_DIRECTIVE_DEFINITION_BY_DIRECTIVE_NAME) {
69
+ this.directiveDefinitionByDirectiveName.set(baseDirectiveName, baseDirectiveDefinition);
66
70
  }
67
71
  this.subgraphName = subgraphName;
68
72
  this.schemaDefinition = {
69
- directives: new Map(),
73
+ directivesByDirectiveName: new Map(),
70
74
  kind: graphql_1.Kind.SCHEMA_DEFINITION,
71
- name: (0, utils_1.stringToNameNode)(string_constants_1.SCHEMA),
75
+ typeName: string_constants_1.SCHEMA,
72
76
  operationTypes: new Map(),
73
77
  };
74
78
  }
@@ -76,7 +80,7 @@ class NormalizationFactory {
76
80
  if (constants_1.BASE_SCALARS.has(namedType)) {
77
81
  return { hasUnhandledError: false, typeString: '' };
78
82
  }
79
- const parentContainer = this.parentContainerByTypeName.get(namedType);
83
+ const parentContainer = this.parentDefinitionDataByTypeName.get(namedType);
80
84
  if (!parentContainer) {
81
85
  this.errors.push((0, errors_1.undefinedTypeError)(namedType));
82
86
  return { hasUnhandledError: false, typeString: '' };
@@ -90,28 +94,28 @@ class NormalizationFactory {
90
94
  return { hasUnhandledError: true, typeString: (0, utils_3.kindToTypeString)(parentContainer.kind) };
91
95
  }
92
96
  }
93
- extractArguments(node, argumentByName, fieldPath) {
97
+ extractArguments(node, argumentDataByArgumentName, fieldPath) {
94
98
  if (!node.arguments) {
95
- return argumentByName;
99
+ return argumentDataByArgumentName;
96
100
  }
97
101
  this.parentsWithChildArguments.add(this.parentTypeName);
98
102
  const duplicatedArguments = new Set();
99
103
  for (const argumentNode of node.arguments) {
100
104
  const argumentName = argumentNode.name.value;
101
- if (argumentByName.has(argumentName)) {
105
+ if (argumentDataByArgumentName.has(argumentName)) {
102
106
  duplicatedArguments.add(argumentName);
103
107
  continue;
104
108
  }
105
- argumentByName.set(argumentName, (0, ast_1.inputValueDefinitionNodeToMutable)(argumentNode, this.parentTypeName));
109
+ argumentDataByArgumentName.set(argumentName, (0, ast_1.inputValueDefinitionNodeToMutable)(argumentNode, this.parentTypeName));
106
110
  }
107
111
  if (duplicatedArguments.size > 0) {
108
112
  this.errors.push((0, errors_1.duplicateArgumentsError)(fieldPath, [...duplicatedArguments]));
109
113
  }
110
- return argumentByName;
114
+ return argumentDataByArgumentName;
111
115
  }
112
- validateArguments(fieldContainer, fieldPath) {
116
+ validateArguments(fieldData, fieldPath) {
113
117
  const invalidArguments = [];
114
- for (const [argumentName, argumentNode] of fieldContainer.arguments) {
118
+ for (const [argumentName, argumentNode] of fieldData.argumentDataByArgumentName) {
115
119
  const namedType = (0, type_merging_1.getNamedTypeForChild)(fieldPath + `(${argumentName}...)`, argumentNode.type);
116
120
  const { hasUnhandledError, typeString } = this.validateInputNamedType(namedType);
117
121
  if (hasUnhandledError) {
@@ -122,51 +126,118 @@ class NormalizationFactory {
122
126
  this.errors.push((0, errors_1.invalidArgumentsError)(fieldPath, invalidArguments));
123
127
  }
124
128
  }
125
- extractDirectives(node, map) {
129
+ // Note that directive validation errors are handled elsewhere
130
+ getAuthorizationData(node) {
131
+ let authorizationData = this.authorizationDataByParentTypeName.get(this.parentTypeName);
132
+ (0, utils_3.resetAuthorizationData)(authorizationData);
126
133
  if (!node.directives) {
127
- return map;
134
+ return authorizationData;
128
135
  }
129
- for (const directive of node.directives) {
130
- const directiveName = directive.name.value;
131
- if (directiveName === string_constants_1.EXTENDS) {
136
+ let requiresAuthentication = false;
137
+ const requiresScopes = [];
138
+ for (const directiveNode of node.directives) {
139
+ const directiveName = directiveNode.name.value;
140
+ if (directiveName === string_constants_1.AUTHENTICATED) {
141
+ // @authenticated is not repeatable
142
+ if (requiresAuthentication) {
143
+ return;
144
+ }
145
+ requiresAuthentication = true;
132
146
  continue;
133
147
  }
134
- const existingDirectives = map.get(directiveName);
135
- if (existingDirectives) {
136
- existingDirectives.push(directive);
148
+ if (directiveName !== string_constants_1.REQUIRES_SCOPES) {
137
149
  continue;
138
150
  }
139
- map.set(directiveName, [directive]);
151
+ // @requiresScopes is not repeatable
152
+ if (requiresScopes.length > 0) {
153
+ return;
154
+ }
155
+ requiresScopes.push(directiveNode);
140
156
  }
141
- return map;
157
+ if (!requiresAuthentication && requiresScopes.length < 1) {
158
+ return authorizationData;
159
+ }
160
+ if ((0, utils_3.isNodeKindInterface)(node.kind)) {
161
+ this.interfaceTypeNamesWithAuthorizationDirectives.add(this.parentTypeName);
162
+ }
163
+ if (!authorizationData) {
164
+ authorizationData = (0, utils_3.setAndGetValue)(this.authorizationDataByParentTypeName, this.parentTypeName, (0, utils_3.newAuthorizationData)(this.parentTypeName));
165
+ }
166
+ authorizationData.hasParentLevelAuthorization = true;
167
+ authorizationData.requiresAuthentication = requiresAuthentication;
168
+ if (requiresScopes.length !== 1) {
169
+ return authorizationData;
170
+ }
171
+ const directiveNode = requiresScopes[0];
172
+ if (!directiveNode.arguments || directiveNode.arguments.length !== 1) {
173
+ return;
174
+ }
175
+ const scopesArgument = directiveNode.arguments[0];
176
+ if (scopesArgument.name.value !== string_constants_1.SCOPES || scopesArgument.value.kind !== graphql_1.Kind.LIST) {
177
+ return;
178
+ }
179
+ const orScopes = scopesArgument.value.values;
180
+ if (orScopes.length < 1) {
181
+ return authorizationData;
182
+ }
183
+ if (orScopes.length > utils_3.maxOrScopes) {
184
+ this.invalidOrScopesHostPaths.add(this.parentTypeName);
185
+ return;
186
+ }
187
+ for (const scopes of orScopes) {
188
+ if (scopes.kind !== graphql_1.Kind.LIST) {
189
+ return;
190
+ }
191
+ const andScopes = new Set();
192
+ for (const scope of scopes.values) {
193
+ if (scope.kind !== graphql_1.Kind.STRING) {
194
+ return;
195
+ }
196
+ andScopes.add(scope.value);
197
+ }
198
+ if (andScopes.size) {
199
+ authorizationData.requiredScopes.push(andScopes);
200
+ }
201
+ }
202
+ return authorizationData;
142
203
  }
143
- extractDirectivesAndAuthorization(node, map) {
204
+ extractDirectivesAndAuthorization(node, directivesByDirectiveName) {
144
205
  if (!node.directives) {
145
- return map;
206
+ return directivesByDirectiveName;
146
207
  }
208
+ const hostPath = this.childName ? `${this.parentTypeName}.${this.childName}` : this.parentTypeName;
147
209
  const authorizationDirectives = [];
148
- for (const directive of node.directives) {
149
- const directiveName = directive.name.value;
210
+ for (const directiveNode of node.directives) {
211
+ const errorMessages = (0, utils_4.getDirectiveValidationErrors)(directiveNode, node.kind, directivesByDirectiveName, this.directiveDefinitionByDirectiveName, this.handledRepeatedDirectivesByHostPath, hostPath);
212
+ const directiveName = directiveNode.name.value;
213
+ if (errorMessages.length > 0) {
214
+ this.errors.push((0, errors_1.invalidDirectiveError)(directiveName, hostPath, errorMessages));
215
+ continue;
216
+ }
150
217
  if (directiveName === string_constants_1.EXTENDS) {
151
218
  continue;
152
219
  }
220
+ if (directiveName === string_constants_1.OVERRIDE) {
221
+ this.handleOverrideDeclaration(directiveNode, hostPath, errorMessages);
222
+ if (errorMessages.length > 0) {
223
+ this.errors.push((0, errors_1.invalidDirectiveError)(directiveName, hostPath, errorMessages));
224
+ }
225
+ continue;
226
+ }
153
227
  if (directiveName === string_constants_1.AUTHENTICATED || directiveName === string_constants_1.REQUIRES_SCOPES) {
154
- authorizationDirectives.push(directive);
228
+ authorizationDirectives.push(directiveNode);
229
+ continue;
155
230
  }
156
- const existingDirectives = map.get(directiveName);
231
+ const existingDirectives = directivesByDirectiveName.get(directiveName);
157
232
  if (existingDirectives) {
158
- existingDirectives.push(directive);
159
- continue;
233
+ existingDirectives.push(directiveNode);
160
234
  }
161
- map.set(directiveName, [directive]);
235
+ directivesByDirectiveName.set(directiveName, [directiveNode]);
162
236
  }
163
237
  if (authorizationDirectives.length < 1) {
164
- return map;
238
+ return directivesByDirectiveName;
165
239
  }
166
- if (node.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION ||
167
- node.kind === graphql_1.Kind.ENUM_TYPE_EXTENSION ||
168
- node.kind === graphql_1.Kind.SCALAR_TYPE_DEFINITION ||
169
- node.kind === graphql_1.Kind.SCALAR_TYPE_EXTENSION) {
240
+ if (node.kind !== graphql_1.Kind.FIELD_DEFINITION) {
170
241
  this.leafTypeNamesWithAuthorizationDirectives.add(this.parentTypeName);
171
242
  }
172
243
  const parentAuthorizationData = (0, utils_3.getValueOrDefault)(this.authorizationDataByParentTypeName, this.parentTypeName, () => (0, utils_3.newAuthorizationData)(this.parentTypeName));
@@ -177,29 +248,14 @@ class NormalizationFactory {
177
248
  authorizationData.requiresAuthentication = true;
178
249
  continue;
179
250
  }
180
- if (!directiveNode.arguments || directiveNode.arguments.length !== 1) {
181
- break;
182
- }
183
- const scopesArgument = directiveNode.arguments[0];
184
- if (scopesArgument.name.value !== string_constants_1.SCOPES) {
185
- break;
186
- }
187
- if (scopesArgument.value.kind !== graphql_1.Kind.LIST) {
188
- break;
189
- }
190
- const orScopes = scopesArgument.value.values;
191
- if (orScopes.length < 1) {
251
+ const orScopes = directiveNode.arguments[0].value.values;
252
+ if (orScopes.length > utils_3.maxOrScopes) {
253
+ this.invalidOrScopesHostPaths.add(hostPath);
192
254
  continue;
193
255
  }
194
256
  for (const scopes of orScopes) {
195
- if (scopes.kind !== graphql_1.Kind.LIST) {
196
- return map;
197
- }
198
257
  const andScopes = new Set();
199
258
  for (const scope of scopes.values) {
200
- if (scope.kind !== graphql_1.Kind.STRING) {
201
- return map;
202
- }
203
259
  andScopes.add(scope.value);
204
260
  }
205
261
  if (andScopes.size) {
@@ -207,21 +263,7 @@ class NormalizationFactory {
207
263
  }
208
264
  }
209
265
  }
210
- return map;
211
- }
212
- extractUniqueUnionMembers(members, map) {
213
- for (const member of members) {
214
- const name = member.name.value;
215
- if (map.has(name)) {
216
- this.errors.push(new Error(`Member "${name} can only be defined on union "${this.parentTypeName}" once.`));
217
- continue;
218
- }
219
- if (!constants_1.BASE_SCALARS.has(name)) {
220
- this.referencedTypeNames.add(name);
221
- }
222
- map.set(name, member);
223
- }
224
- return map;
266
+ return directivesByDirectiveName;
225
267
  }
226
268
  mergeUniqueInterfaces(extensionInterfaces, interfaces, typeName) {
227
269
  for (const interfaceName of extensionInterfaces) {
@@ -232,109 +274,6 @@ class NormalizationFactory {
232
274
  this.errors.push((0, errors_1.duplicateInterfaceExtensionError)(interfaceName, typeName));
233
275
  }
234
276
  }
235
- mergeUniqueUnionMembers(baseUnion, extensionUnion) {
236
- if (!extensionUnion) {
237
- return;
238
- }
239
- const extensionMembers = extensionUnion.types;
240
- const members = baseUnion.types;
241
- const typeName = baseUnion.name.value;
242
- for (const [memberName, namedTypeNode] of extensionMembers) {
243
- if (!members.has(memberName)) {
244
- members.set(memberName, namedTypeNode);
245
- continue;
246
- }
247
- this.errors.push((0, errors_1.duplicateUnionMemberError)(memberName, typeName));
248
- }
249
- }
250
- mergeDirectives(baseTypeDirectives, extension) {
251
- if (!extension) {
252
- return;
253
- }
254
- for (const [directiveName, directives] of extension.directives) {
255
- const existingDirectives = baseTypeDirectives.get(directiveName);
256
- if (existingDirectives) {
257
- existingDirectives.push(...directives);
258
- continue;
259
- }
260
- baseTypeDirectives.set(directiveName, [...directives]);
261
- }
262
- }
263
- getValidatedAndNormalizedParentDirectives(parent) {
264
- const parentTypeName = parent.name.value;
265
- const normalizedDirectives = [];
266
- for (const [directiveName, directives] of parent.directives) {
267
- const definition = this.allDirectiveDefinitions.get(directiveName);
268
- if (!definition) {
269
- this.errors.push((0, errors_1.undefinedDirectiveError)(directiveName, parentTypeName));
270
- continue;
271
- }
272
- const allArguments = new Set();
273
- const requiredArguments = new Set();
274
- (0, utils_2.getDirectiveDefinitionArgumentSets)(definition.arguments || [], allArguments, requiredArguments);
275
- const entityKeys = new Set();
276
- const errorMessages = [];
277
- for (const directive of directives) {
278
- if (!(0, utils_2.areNodeKindAndDirectiveLocationCompatible)(parent.kind, definition)) {
279
- errorMessages.push((0, errors_1.invalidDirectiveLocationErrorMessage)(parentTypeName, parent.kind, directiveName));
280
- }
281
- if (!definition.repeatable && directives.length > 1) {
282
- errorMessages.push((0, errors_1.invalidRepeatedDirectiveErrorMessage)(directiveName, parentTypeName));
283
- }
284
- if (!definition.arguments || definition.arguments.length < 1) {
285
- if (directive.arguments && directive.arguments.length > 0) {
286
- errorMessages.push((0, errors_1.unexpectedDirectiveArgumentsErrorMessage)(directive, parentTypeName));
287
- }
288
- else {
289
- normalizedDirectives.push(directive);
290
- }
291
- continue;
292
- }
293
- if (!directive.arguments || directive.arguments.length < 1) {
294
- if (requiredArguments.size > 0) {
295
- errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, parentTypeName, [...requiredArguments]));
296
- }
297
- else {
298
- normalizedDirectives.push(directive);
299
- }
300
- continue;
301
- }
302
- const definedArguments = (0, utils_2.getDefinedArgumentsForDirective)(directive.arguments, allArguments, directiveName, parentTypeName, errorMessages);
303
- const missingRequiredArguments = (0, utils_3.getEntriesNotInHashSet)(requiredArguments, definedArguments);
304
- if (missingRequiredArguments.length > 0) {
305
- errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, parentTypeName, [...requiredArguments], missingRequiredArguments));
306
- }
307
- // Only add unique entity keys
308
- if (directiveName === string_constants_1.KEY) {
309
- const directiveKind = directive.arguments[0].value.kind;
310
- if (directiveKind !== graphql_1.Kind.STRING) {
311
- errorMessages.push((0, errors_1.invalidKeyDirectiveArgumentErrorMessage)(directiveKind));
312
- continue;
313
- }
314
- const entityKey = directive.arguments[0].value.value;
315
- if (entityKeys.has(entityKey)) {
316
- continue;
317
- }
318
- entityKeys.add(entityKey);
319
- }
320
- normalizedDirectives.push(directive);
321
- }
322
- if (errorMessages.length > 0) {
323
- this.errors.push((0, errors_1.invalidDirectiveError)(directiveName, parentTypeName, errorMessages));
324
- }
325
- }
326
- return normalizedDirectives;
327
- }
328
- convertKindForExtension(node) {
329
- switch (node.kind) {
330
- case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
331
- return graphql_1.Kind.INTERFACE_TYPE_EXTENSION;
332
- case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
333
- return graphql_1.Kind.OBJECT_TYPE_EXTENSION;
334
- default:
335
- return node.kind;
336
- }
337
- }
338
277
  handleInterfaceObject(node) {
339
278
  if (!(0, utils_1.isNodeInterfaceObject)(node)) {
340
279
  return;
@@ -351,28 +290,22 @@ class NormalizationFactory {
351
290
  typeName: name,
352
291
  });
353
292
  }
354
- handleObjectLikeExtension(node) {
293
+ handleExtensionWithFields(node) {
355
294
  this.isCurrentParentExtension = true;
356
- const extension = this.extensionContainerByTypeName.get(this.parentTypeName);
357
- const convertedKind = this.convertKindForExtension(node);
295
+ const extension = this.parentExtensionDataByTypeName.get(this.parentTypeName);
296
+ const convertedKind = (0, utils_4.convertKindForExtension)(node);
358
297
  if (extension) {
359
298
  if (extension.kind !== convertedKind) {
360
299
  this.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
361
300
  return false;
362
301
  }
363
- this.extractDirectivesAndAuthorization(node, extension.directives);
364
- (0, utils_1.extractInterfaces)(node, extension.interfaces, this.errors);
302
+ (0, utils_4.extractDirectives)(node, extension.directivesByDirectiveName, this.errors, this.directiveDefinitionByDirectiveName, this.handledRepeatedDirectivesByHostPath, this.parentTypeName);
303
+ (0, utils_1.extractInterfaces)(node, extension.implementedInterfaceTypeNames, this.errors);
365
304
  return;
366
305
  }
367
306
  const isEntity = (0, utils_1.isObjectLikeNodeEntity)(node);
368
- this.extensionContainerByTypeName.set(this.parentTypeName, {
369
- directives: this.extractDirectivesAndAuthorization(node, new Map()),
370
- fields: new Map(),
371
- interfaces: (0, utils_1.extractInterfaces)(node, new Set(), this.errors),
372
- isEntity,
373
- kind: convertedKind,
374
- name: node.name,
375
- });
307
+ (0, utils_4.upsertExtensionWithFieldsDataByNode)(this.parentExtensionDataByTypeName, node, this.errors, this.directiveDefinitionByDirectiveName, this.handledRepeatedDirectivesByHostPath, isEntity);
308
+ // TODO re-assess this line
376
309
  if (node.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION || node.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION || !isEntity) {
377
310
  return;
378
311
  }
@@ -384,48 +317,6 @@ class NormalizationFactory {
384
317
  ...(this.subgraphName ? { subgraphNames: [this.subgraphName] } : {}),
385
318
  });
386
319
  }
387
- validateChildDirectives(child, hostPath) {
388
- const childKind = child.node.kind;
389
- for (const [directiveName, directives] of child.directives) {
390
- const definition = this.allDirectiveDefinitions.get(directiveName);
391
- if (!definition) {
392
- this.errors.push((0, errors_1.undefinedDirectiveError)(directiveName, hostPath));
393
- continue;
394
- }
395
- const allArguments = new Set();
396
- const requiredArguments = new Set();
397
- (0, utils_2.getDirectiveDefinitionArgumentSets)(definition.arguments || [], allArguments, requiredArguments);
398
- const errorMessages = [];
399
- for (const directive of directives) {
400
- if (!(0, utils_2.areNodeKindAndDirectiveLocationCompatible)(childKind, definition)) {
401
- errorMessages.push((0, errors_1.invalidDirectiveLocationErrorMessage)(hostPath, childKind, directiveName));
402
- }
403
- if (!definition.repeatable && directives.length > 1) {
404
- errorMessages.push((0, errors_1.invalidRepeatedDirectiveErrorMessage)(directiveName, hostPath));
405
- }
406
- if (!definition.arguments || definition.arguments.length < 1) {
407
- if (directive.arguments && directive.arguments.length > 0) {
408
- errorMessages.push((0, errors_1.unexpectedDirectiveArgumentsErrorMessage)(directive, hostPath));
409
- }
410
- continue;
411
- }
412
- if (!directive.arguments || directive.arguments.length < 1) {
413
- if (requiredArguments.size > 0) {
414
- errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, hostPath, [...requiredArguments]));
415
- }
416
- continue;
417
- }
418
- const definedArguments = (0, utils_2.getDefinedArgumentsForDirective)(directive.arguments, allArguments, directiveName, hostPath, errorMessages);
419
- const missingRequiredArguments = (0, utils_3.getEntriesNotInHashSet)(requiredArguments, definedArguments);
420
- if (missingRequiredArguments.length > 0) {
421
- errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(directiveName, hostPath, [...requiredArguments], missingRequiredArguments));
422
- }
423
- }
424
- if (errorMessages.length > 0) {
425
- this.errors.push((0, errors_1.invalidDirectiveError)(directiveName, hostPath, errorMessages));
426
- }
427
- }
428
- }
429
320
  isTypeValidImplementation(originalType, implementationType) {
430
321
  if (originalType.kind === graphql_1.Kind.NON_NULL_TYPE) {
431
322
  if (implementationType.kind !== graphql_1.Kind.NON_NULL_TYPE) {
@@ -458,18 +349,6 @@ class NormalizationFactory {
458
349
  return false;
459
350
  }
460
351
  }
461
- canContainEventDirectives() {
462
- if (!this.isCurrentParentRootType) {
463
- return false;
464
- }
465
- const operationTypeNode = this.operationTypeNames.get(this.parentTypeName);
466
- if (!operationTypeNode) {
467
- return string_constants_1.ROOT_TYPES.has(this.parentTypeName);
468
- }
469
- return (operationTypeNode === graphql_1.OperationTypeNode.QUERY ||
470
- operationTypeNode === graphql_1.OperationTypeNode.MUTATION ||
471
- operationTypeNode === graphql_1.OperationTypeNode.SUBSCRIPTION);
472
- }
473
352
  extractKeyFieldSets(node, fieldSetContainer) {
474
353
  const rawFieldSets = fieldSetContainer.keys;
475
354
  const parentTypeName = node.name.value;
@@ -511,12 +390,12 @@ class NormalizationFactory {
511
390
  }
512
391
  }
513
392
  validateInterfaceImplementations(container) {
514
- if (container.interfaces.size < 1) {
393
+ if (container.implementedInterfaceTypeNames.size < 1) {
515
394
  return;
516
395
  }
517
396
  const implementationErrorsMap = new Map();
518
- for (const interfaceName of container.interfaces) {
519
- const interfaceContainer = (0, utils_3.getOrThrowError)(this.parentContainerByTypeName, interfaceName, string_constants_1.PARENTS);
397
+ for (const interfaceName of container.implementedInterfaceTypeNames) {
398
+ const interfaceContainer = (0, utils_3.getOrThrowError)(this.parentDefinitionDataByTypeName, interfaceName, string_constants_1.PARENTS);
520
399
  if (interfaceContainer.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION) {
521
400
  throw (0, errors_1.incompatibleParentKindFatalError)(interfaceName, graphql_1.Kind.INTERFACE_TYPE_DEFINITION, interfaceContainer.kind);
522
401
  }
@@ -525,9 +404,9 @@ class NormalizationFactory {
525
404
  unimplementedFields: [],
526
405
  };
527
406
  let hasErrors = false;
528
- for (const [fieldName, interfaceField] of interfaceContainer.fields) {
407
+ for (const [fieldName, interfaceField] of interfaceContainer.fieldDataByFieldName) {
529
408
  let hasNestedErrors = false;
530
- const containerField = container.fields.get(fieldName);
409
+ const containerField = container.fieldDataByFieldName.get(fieldName);
531
410
  if (!containerField) {
532
411
  hasErrors = true;
533
412
  implementationErrors.unimplementedFields.push(fieldName);
@@ -546,9 +425,9 @@ class NormalizationFactory {
546
425
  invalidFieldImplementation.implementedResponseType = (0, merge_1.printTypeNode)(containerField.node.type);
547
426
  }
548
427
  const handledArguments = new Set();
549
- for (const [argumentName, interfaceArgument] of interfaceField.arguments) {
428
+ for (const [argumentName, interfaceArgument] of interfaceField.argumentDataByArgumentName) {
550
429
  handledArguments.add(argumentName);
551
- const containerArgument = containerField.arguments.get(argumentName);
430
+ const containerArgument = containerField.argumentDataByArgumentName.get(argumentName);
552
431
  // The type implementing the interface must include all arguments with no variation for that argument
553
432
  if (!containerArgument) {
554
433
  hasErrors = true;
@@ -566,11 +445,11 @@ class NormalizationFactory {
566
445
  }
567
446
  }
568
447
  // Additional arguments must be optional (nullable)
569
- for (const [argumentName, argumentNode] of containerField.arguments) {
448
+ for (const [argumentName, argumentData] of containerField.argumentDataByArgumentName) {
570
449
  if (handledArguments.has(argumentName)) {
571
450
  continue;
572
451
  }
573
- if (argumentNode.type.kind !== graphql_1.Kind.NON_NULL_TYPE) {
452
+ if (argumentData.type.kind !== graphql_1.Kind.NON_NULL_TYPE) {
574
453
  continue;
575
454
  }
576
455
  hasErrors = true;
@@ -586,81 +465,25 @@ class NormalizationFactory {
586
465
  }
587
466
  }
588
467
  if (implementationErrorsMap.size) {
589
- this.errors.push((0, errors_1.unimplementedInterfaceFieldsError)(container.name.value, (0, utils_3.kindToTypeString)(container.kind), implementationErrorsMap));
468
+ this.errors.push((0, errors_1.unimplementedInterfaceFieldsError)(container.typeName, (0, utils_3.kindToTypeString)(container.kind), implementationErrorsMap));
590
469
  }
591
470
  }
592
- handleOverride(node) {
593
- if (node.name.value !== string_constants_1.OVERRIDE) {
471
+ handleOverrideDeclaration(node, hostPath, errorMessages) {
472
+ const argumentNode = node.arguments[0];
473
+ if (argumentNode.value.kind !== graphql_1.Kind.STRING) {
474
+ errorMessages.push((0, errors_1.invalidDirectiveArgumentTypeErrorMessage)(true, string_constants_1.FROM, graphql_1.Kind.STRING, argumentNode.value.kind));
594
475
  return;
595
476
  }
596
- const errorMessages = [];
597
- let hostPath = `${this.parentTypeName}.${this.childName}`;
598
- let kind = this.lastChildNodeKind === graphql_1.Kind.NULL ? this.lastParentNodeKind : this.lastChildNodeKind;
599
- if (this.argumentName) {
600
- hostPath += `(${this.argumentName}: ...)`;
601
- kind = graphql_1.Kind.ARGUMENT;
602
- }
603
- if (kind !== graphql_1.Kind.FIELD_DEFINITION) {
604
- errorMessages.push((0, errors_1.invalidDirectiveLocationErrorMessage)(hostPath, kind, string_constants_1.OVERRIDE));
605
- }
606
- let targetSubgraphName = '';
607
- if (node.arguments && node.arguments.length > 0) {
608
- const observedArguments = new Set();
609
- const handledDuplicateArguments = new Set();
610
- for (const argumentNode of node.arguments) {
611
- const argumentName = argumentNode.name.value;
612
- if (argumentName !== string_constants_1.FROM && !observedArguments.has(argumentName)) {
613
- observedArguments.add(argumentName);
614
- errorMessages.push((0, errors_1.unexpectedDirectiveArgumentErrorMessage)(string_constants_1.OVERRIDE, argumentName));
615
- continue;
616
- }
617
- // If an argument is observed more than once, it is a duplication error.
618
- // However, the error should only propagate once.
619
- if (observedArguments.has(argumentName)) {
620
- if (!handledDuplicateArguments.has(argumentName)) {
621
- errorMessages.push((0, errors_1.duplicateDirectiveArgumentDefinitionErrorMessage)(string_constants_1.OVERRIDE, hostPath, argumentName));
622
- }
623
- continue;
624
- }
625
- if (argumentNode.value.kind !== graphql_1.Kind.STRING) {
626
- errorMessages.push((0, errors_1.invalidDirectiveArgumentTypeErrorMessage)(true, string_constants_1.FROM, graphql_1.Kind.STRING, argumentNode.value.kind));
627
- }
628
- else {
629
- observedArguments.add(string_constants_1.FROM);
630
- targetSubgraphName = argumentNode.value.value;
631
- if (targetSubgraphName === this.subgraphName) {
632
- this.errors.push((0, errors_1.equivalentSourceAndTargetOverrideError)(targetSubgraphName, hostPath));
633
- }
634
- }
635
- }
636
- if (!observedArguments.has(string_constants_1.FROM)) {
637
- errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(string_constants_1.OVERRIDE, hostPath, [string_constants_1.FROM], [string_constants_1.FROM]));
638
- }
639
- }
640
- else {
641
- errorMessages.push((0, errors_1.undefinedRequiredArgumentsErrorMessage)(string_constants_1.OVERRIDE, hostPath, [string_constants_1.FROM], []));
642
- }
643
- if (errorMessages.length > 0) {
644
- this.errors.push((0, errors_1.invalidDirectiveError)(string_constants_1.OVERRIDE, hostPath, errorMessages));
477
+ const targetSubgraphName = argumentNode.value.value;
478
+ if (targetSubgraphName === this.subgraphName) {
479
+ errorMessages.push((0, errors_1.equivalentSourceAndTargetOverrideErrorMessage)(targetSubgraphName, hostPath));
645
480
  return;
646
481
  }
647
482
  const overrideDataForSubgraph = (0, utils_3.getValueOrDefault)(this.overridesByTargetSubgraphName, targetSubgraphName, () => new Map());
648
483
  const overriddenFieldNamesForParent = (0, utils_3.getValueOrDefault)(overrideDataForSubgraph, this.parentTypeName, () => new Set());
649
- if (overriddenFieldNamesForParent.has(this.childName)) {
650
- const handledRepeatedDirectives = this.handledRepeatedDirectivesByHostPath.get(hostPath);
651
- // If the directive name exists as a value on the host path key, the repeatable error has been handled
652
- if (handledRepeatedDirectives && handledRepeatedDirectives.has(string_constants_1.OVERRIDE)) {
653
- return;
654
- }
655
- // Add the directive name to the existing set (if other invalid repeated directives exist) or a new set
656
- (0, utils_3.getValueOrDefault)(this.handledRepeatedDirectivesByHostPath, hostPath, () => new Set()).add(string_constants_1.OVERRIDE);
657
- // The invalid repeated directive error should propagate only once per directive per host path
658
- this.errors.push((0, errors_1.invalidDirectiveError)(string_constants_1.OVERRIDE, hostPath, [(0, errors_1.invalidRepeatedDirectiveErrorMessage)(string_constants_1.OVERRIDE, hostPath)]));
659
- return;
660
- }
661
484
  overriddenFieldNamesForParent.add(this.childName);
662
485
  }
663
- extractEventDirectives(node) {
486
+ extractEventDirectivesToConfiguration(node) {
664
487
  if (!node.directives) {
665
488
  return;
666
489
  }
@@ -726,584 +549,52 @@ class NormalizationFactory {
726
549
  }
727
550
  }
728
551
  normalize(document) {
729
- const factory = this;
730
552
  /* factory.allDirectiveDefinitions is initialized with v1 directive definitions, and v2 definitions are only added
731
553
  after the visitor has visited the entire schema and the subgraph is known to be a V2 graph. Consequently,
732
554
  allDirectiveDefinitions cannot be used to check for duplicate definitions, and another set (below) is required */
733
- const definedDirectives = new Set();
734
- const handledRootTypes = new Set();
735
555
  // Collect any renamed root types
736
- (0, graphql_1.visit)(document, {
737
- OperationTypeDefinition: {
738
- enter(node) {
739
- const operationType = node.operation;
740
- const operationPath = `${factory.parentTypeName}.${operationType}`;
741
- const definitionNode = factory.schemaDefinition.operationTypes.get(operationType);
742
- const newTypeName = (0, type_merging_1.getNamedTypeForChild)(operationPath, node.type);
743
- if (definitionNode) {
744
- (0, errors_1.duplicateOperationTypeDefinitionError)(operationType, newTypeName, (0, type_merging_1.getNamedTypeForChild)(operationPath, definitionNode.type));
745
- return false;
746
- }
747
- const existingOperationType = factory.operationTypeNames.get(newTypeName);
748
- if (existingOperationType) {
749
- factory.errors.push((0, errors_1.invalidOperationTypeDefinitionError)(existingOperationType, newTypeName, operationType));
750
- }
751
- else {
752
- handledRootTypes.add(operationType);
753
- factory.operationTypeNames.set(newTypeName, operationType);
754
- factory.schemaDefinition.operationTypes.set(operationType, node);
755
- }
756
- return false;
757
- },
758
- },
759
- SchemaDefinition: {
760
- enter(node) {
761
- factory.extractDirectives(node, factory.schemaDefinition.directives);
762
- factory.schemaDefinition.description = node.description;
763
- },
764
- },
765
- SchemaExtension: {
766
- enter(node) {
767
- factory.extractDirectives(node, factory.schemaDefinition.directives);
768
- },
769
- },
770
- });
771
- (0, graphql_1.visit)(document, {
772
- DirectiveDefinition: {
773
- enter(node) {
774
- const name = node.name.value;
775
- if (definedDirectives.has(name)) {
776
- factory.errors.push((0, errors_1.duplicateDirectiveDefinitionError)(name));
777
- return false;
778
- }
779
- else {
780
- definedDirectives.add(name);
781
- }
782
- // Normalize federation directives by replacing them with predefined definitions
783
- if (constants_1.VERSION_TWO_DIRECTIVES.has(name)) {
784
- factory.isSubgraphVersionTwo = true;
785
- return false;
786
- }
787
- // The V1 directives are always injected
788
- if (constants_1.VERSION_ONE_DIRECTIVES.has(name)) {
789
- return false;
790
- }
791
- factory.allDirectiveDefinitions.set(name, node);
792
- factory.customDirectiveDefinitions.set(name, node);
793
- return false;
794
- },
795
- },
796
- Directive: {
797
- enter(node) {
798
- const name = node.name.value;
799
- factory.handleOverride(node);
800
- if (constants_1.VERSION_TWO_DIRECTIVES.has(name)) {
801
- factory.isSubgraphVersionTwo = true;
802
- return false;
803
- }
804
- if (constants_1.VERSION_ONE_DIRECTIVES.has(name)) {
805
- return false;
806
- }
807
- factory.referencedDirectives.add(name);
808
- },
809
- },
810
- EnumTypeDefinition: {
811
- enter(node) {
812
- const typeName = node.name.value;
813
- if (factory.parentContainerByTypeName.has(typeName)) {
814
- factory.errors.push((0, errors_1.duplicateTypeDefinitionError)((0, utils_3.kindToTypeString)(node.kind), typeName));
815
- return false;
816
- }
817
- factory.parentTypeName = typeName;
818
- factory.lastParentNodeKind = node.kind;
819
- const directives = factory.extractDirectivesAndAuthorization(node, new Map());
820
- factory.parentContainerByTypeName.set(typeName, {
821
- description: (0, utils_1.formatDescription)(node.description),
822
- directives,
823
- kind: node.kind,
824
- name: node.name,
825
- values: new Map(),
826
- });
827
- },
828
- leave() {
829
- factory.parentTypeName = '';
830
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
831
- },
832
- },
833
- EnumTypeExtension: {
834
- enter(node) {
835
- const name = node.name.value;
836
- factory.parentTypeName = name;
837
- factory.lastParentNodeKind = node.kind;
838
- factory.isCurrentParentExtension = true;
839
- const extension = factory.extensionContainerByTypeName.get(factory.parentTypeName);
840
- if (extension) {
841
- if (extension.kind !== graphql_1.Kind.ENUM_TYPE_EXTENSION) {
842
- factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
843
- return false;
844
- }
845
- factory.extractDirectivesAndAuthorization(node, extension.directives);
846
- return;
847
- }
848
- factory.extensionContainerByTypeName.set(name, {
849
- directives: factory.extractDirectivesAndAuthorization(node, new Map()),
850
- kind: node.kind,
851
- name: node.name,
852
- values: new Map(),
853
- });
854
- },
855
- leave() {
856
- factory.parentTypeName = '';
857
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
858
- factory.isCurrentParentExtension = false;
859
- },
860
- },
861
- EnumValueDefinition: {
862
- enter(node) {
863
- const name = node.name.value;
864
- factory.childName = name;
865
- factory.lastChildNodeKind = node.kind;
866
- const parent = factory.isCurrentParentExtension
867
- ? (0, utils_3.getOrThrowError)(factory.extensionContainerByTypeName, factory.parentTypeName, string_constants_1.EXTENSIONS)
868
- : (0, utils_3.getOrThrowError)(factory.parentContainerByTypeName, factory.parentTypeName, string_constants_1.PARENTS);
869
- if (parent.kind !== graphql_1.Kind.ENUM_TYPE_DEFINITION && parent.kind !== graphql_1.Kind.ENUM_TYPE_EXTENSION) {
870
- throw (0, errors_1.unexpectedKindFatalError)(name);
871
- }
872
- if (parent.values.has(name)) {
873
- const error = factory.isCurrentParentExtension
874
- ? (0, errors_1.duplicateValueExtensionError)('enum', factory.parentTypeName, name)
875
- : (0, errors_1.duplicateEnumValueDefinitionError)(name, factory.parentTypeName);
876
- factory.errors.push(error);
877
- return;
878
- }
879
- parent.values.set(name, {
880
- directives: factory.extractDirectives(node, new Map()),
881
- name,
882
- node: { ...node, description: (0, utils_1.formatDescription)(node.description) },
883
- });
884
- },
885
- leave() {
886
- factory.childName = '';
887
- factory.lastChildNodeKind = graphql_1.Kind.NULL;
888
- },
889
- },
890
- FieldDefinition: {
891
- enter(node) {
892
- const fieldName = node.name.value;
893
- if (factory.isCurrentParentRootType && (fieldName === string_constants_1.SERVICE_FIELD || fieldName === string_constants_1.ENTITIES_FIELD)) {
894
- return false;
895
- }
896
- factory.childName = fieldName;
897
- factory.lastChildNodeKind = node.kind;
898
- if (factory.canContainEventDirectives()) {
899
- factory.extractEventDirectives(node);
900
- }
901
- const fieldPath = `${factory.parentTypeName}.${fieldName}`;
902
- factory.lastChildNodeKind = node.kind;
903
- const fieldNamedTypeName = (0, type_merging_1.getNamedTypeForChild)(fieldPath, node.type);
904
- if (!constants_1.BASE_SCALARS.has(fieldNamedTypeName)) {
905
- factory.referencedTypeNames.add(fieldNamedTypeName);
906
- }
907
- const parent = factory.isCurrentParentExtension
908
- ? (0, utils_3.getOrThrowError)(factory.extensionContainerByTypeName, factory.parentTypeName, string_constants_1.EXTENSIONS)
909
- : (0, utils_3.getOrThrowError)(factory.parentContainerByTypeName, factory.parentTypeName, string_constants_1.PARENTS);
910
- if (parent.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
911
- parent.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION &&
912
- parent.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION &&
913
- parent.kind !== graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
914
- throw (0, errors_1.unexpectedKindFatalError)(factory.parentTypeName);
915
- }
916
- if (parent.fields.has(fieldName)) {
917
- factory.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName, factory.parentTypeName));
918
- return;
919
- }
920
- // recreate the node so the argument descriptions are updated
921
- const fieldContainer = {
922
- arguments: factory.extractArguments(node, new Map(), fieldPath),
923
- directives: factory.extractDirectivesAndAuthorization(node, new Map()),
924
- name: fieldName,
925
- node: {
926
- ...node,
927
- arguments: node.arguments?.map((arg) => ({
928
- ...arg,
929
- description: (0, utils_1.formatDescription)(arg.description),
930
- })),
931
- },
932
- };
933
- parent.fields.set(fieldName, fieldContainer);
934
- const entityContainer = factory.entityContainerByTypeName.get(factory.parentTypeName);
935
- if (entityContainer) {
936
- entityContainer.fieldNames.add(fieldName);
937
- // Only entities will have an existing FieldSet
938
- const existingFieldSet = factory.fieldSetContainerByTypeName.get(factory.parentTypeName);
939
- if (existingFieldSet) {
940
- // @requires should only be defined on a field whose parent is an entity
941
- // If there is existingFieldSet, it's an entity
942
- (0, utils_2.extractFieldSetValue)(fieldName, existingFieldSet.requires, fieldContainer.directives.get(string_constants_1.REQUIRES));
943
- // @provides only makes sense on entities, but the field can be encountered before the type definition
944
- // When the FieldSet is evaluated, it will be checked whether the field is an entity.
945
- (0, utils_2.extractFieldSetValue)(fieldName, existingFieldSet.provides, fieldContainer.directives.get(string_constants_1.PROVIDES));
946
- return;
947
- }
948
- }
949
- const providesDirectives = fieldContainer.directives.get(string_constants_1.PROVIDES);
950
- // Check whether the directive exists to avoid creating unnecessary fieldSet configurations
951
- if (!providesDirectives) {
952
- return;
953
- }
954
- const fieldSetContainer = (0, utils_3.getValueOrDefault)(factory.fieldSetContainerByTypeName, factory.parentTypeName, utils_2.newFieldSetContainer);
955
- // @provides only makes sense on entities, but the field can be encountered before the type definition
956
- // When the FieldSet is evaluated, it will be checked whether the field is an entity.
957
- (0, utils_2.extractFieldSetValue)(fieldName, fieldSetContainer.provides, providesDirectives);
958
- },
959
- leave() {
960
- factory.childName = '';
961
- factory.lastChildNodeKind = graphql_1.Kind.NULL;
962
- },
963
- },
964
- InputObjectTypeDefinition: {
965
- enter(node) {
966
- const name = node.name.value;
967
- if (factory.parentContainerByTypeName.has(name)) {
968
- factory.errors.push((0, errors_1.duplicateTypeDefinitionError)((0, utils_3.kindToTypeString)(node.kind), name));
969
- return false;
970
- }
971
- factory.lastParentNodeKind = node.kind;
972
- factory.parentTypeName = name;
973
- factory.parentContainerByTypeName.set(name, {
974
- description: (0, utils_1.formatDescription)(node.description),
975
- directives: factory.extractDirectives(node, new Map()),
976
- fields: new Map(),
977
- kind: node.kind,
978
- name: node.name,
979
- });
980
- },
981
- leave() {
982
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
983
- factory.parentTypeName = '';
984
- },
985
- },
986
- InputObjectTypeExtension: {
987
- enter(node) {
988
- const name = node.name.value;
989
- factory.parentTypeName = name;
990
- factory.lastParentNodeKind = node.kind;
991
- factory.isCurrentParentExtension = true;
992
- const extension = factory.extensionContainerByTypeName.get(factory.parentTypeName);
993
- if (extension) {
994
- if (extension.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION) {
995
- factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
996
- return false;
997
- }
998
- factory.extractDirectives(node, extension.directives);
999
- return;
1000
- }
1001
- factory.extensionContainerByTypeName.set(name, {
1002
- directives: factory.extractDirectives(node, new Map()),
1003
- fields: new Map(),
1004
- kind: node.kind,
1005
- name: node.name,
1006
- });
1007
- },
1008
- leave() {
1009
- factory.parentTypeName = '';
1010
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1011
- factory.isCurrentParentExtension = false;
1012
- },
1013
- },
1014
- InputValueDefinition: {
1015
- enter(node) {
1016
- const name = node.name.value;
1017
- // If the parent is not an object type definition/extension, this node is an argument
1018
- if (factory.lastParentNodeKind !== graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION &&
1019
- factory.lastParentNodeKind !== graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION) {
1020
- factory.argumentName = name;
1021
- return;
1022
- }
1023
- factory.childName = name;
1024
- factory.lastChildNodeKind = node.kind;
1025
- const valueRootTypeName = (0, type_merging_1.getNamedTypeForChild)(`${factory.parentTypeName}.${name}`, node.type);
1026
- if (!constants_1.BASE_SCALARS.has(valueRootTypeName)) {
1027
- factory.referencedTypeNames.add(valueRootTypeName);
1028
- }
1029
- const parent = factory.isCurrentParentExtension
1030
- ? (0, utils_3.getOrThrowError)(factory.extensionContainerByTypeName, factory.parentTypeName, string_constants_1.EXTENSIONS)
1031
- : (0, utils_3.getOrThrowError)(factory.parentContainerByTypeName, factory.parentTypeName, string_constants_1.PARENTS);
1032
- if (parent.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION && parent.kind !== graphql_1.Kind.INPUT_OBJECT_TYPE_EXTENSION) {
1033
- throw (0, errors_1.unexpectedKindFatalError)(factory.parentTypeName);
1034
- }
1035
- if (parent.fields.has(name)) {
1036
- factory.errors.push((0, errors_1.duplicateValueExtensionError)('input', factory.parentTypeName, name));
1037
- return;
1038
- }
1039
- parent.fields.set(name, {
1040
- directives: factory.extractDirectives(node, new Map()),
1041
- name,
1042
- node: { ...node, description: (0, utils_1.formatDescription)(node.description) },
1043
- });
1044
- },
1045
- leave() {
1046
- factory.argumentName = '';
1047
- // Only reset childName and lastNodeKind if this input value was NOT an argument
1048
- if (factory.lastChildNodeKind === graphql_1.Kind.INPUT_VALUE_DEFINITION) {
1049
- factory.childName = '';
1050
- factory.lastChildNodeKind = graphql_1.Kind.NULL;
1051
- }
1052
- },
1053
- },
1054
- InterfaceTypeDefinition: {
1055
- enter(node) {
1056
- const name = node.name.value;
1057
- factory.parentTypeName = name;
1058
- factory.lastParentNodeKind = node.kind;
1059
- if ((0, utils_1.isNodeExtension)(node)) {
1060
- return factory.handleObjectLikeExtension(node);
1061
- }
1062
- if (factory.parentContainerByTypeName.has(name)) {
1063
- factory.errors.push((0, errors_1.duplicateTypeDefinitionError)((0, utils_3.kindToTypeString)(node.kind), name));
1064
- return false;
1065
- }
1066
- const isEntity = (0, utils_1.isObjectLikeNodeEntity)(node);
1067
- factory.parentContainerByTypeName.set(name, {
1068
- description: (0, utils_1.formatDescription)(node.description),
1069
- directives: factory.extractDirectivesAndAuthorization(node, new Map()),
1070
- fields: new Map(),
1071
- interfaces: (0, utils_1.extractInterfaces)(node, new Set(), factory.errors),
1072
- isEntity,
1073
- kind: node.kind,
1074
- name: node.name,
1075
- });
1076
- if (!isEntity) {
1077
- return;
1078
- }
1079
- factory.entityInterfaces.set(name, {
1080
- concreteTypeNames: new Set(),
1081
- interfaceFieldNames: new Set(node.fields?.map((field) => field.name.value)),
1082
- interfaceObjectFieldNames: new Set(),
1083
- isInterfaceObject: false,
1084
- typeName: name,
1085
- });
1086
- (0, utils_3.upsertEntityContainerProperties)(factory.entityContainerByTypeName, {
1087
- typeName: factory.parentTypeName,
1088
- ...(factory.subgraphName ? { subgraphNames: [factory.subgraphName] } : {}),
1089
- });
1090
- const fieldSetContainer = (0, utils_3.getValueOrDefault)(factory.fieldSetContainerByTypeName, name, utils_2.newFieldSetContainer);
1091
- factory.extractKeyFieldSets(node, fieldSetContainer);
1092
- },
1093
- leave() {
1094
- factory.parentTypeName = '';
1095
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1096
- factory.isCurrentParentExtension = false;
1097
- },
1098
- },
1099
- InterfaceTypeExtension: {
1100
- enter(node) {
1101
- factory.parentTypeName = node.name.value;
1102
- factory.lastParentNodeKind = node.kind;
1103
- return factory.handleObjectLikeExtension(node);
1104
- },
1105
- leave() {
1106
- factory.isCurrentParentExtension = false;
1107
- factory.parentTypeName = '';
1108
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1109
- },
1110
- },
1111
- ObjectTypeDefinition: {
1112
- enter(node) {
1113
- const typeName = node.name.value;
1114
- if (typeName === string_constants_1.SERVICE_OBJECT) {
1115
- return false;
1116
- }
1117
- factory.isCurrentParentRootType = string_constants_1.ROOT_TYPES.has(typeName) || factory.operationTypeNames.has(typeName);
1118
- factory.parentTypeName = typeName;
1119
- factory.lastParentNodeKind = node.kind;
1120
- (0, utils_1.addConcreteTypesForImplementedInterfaces)(node, factory.abstractToConcreteTypeNames);
1121
- factory.handleInterfaceObject(node);
1122
- // handling for @extends directive
1123
- if ((0, utils_1.isNodeExtension)(node)) {
1124
- return factory.handleObjectLikeExtension(node);
1125
- }
1126
- if (factory.parentContainerByTypeName.has(typeName)) {
1127
- factory.errors.push((0, errors_1.duplicateTypeDefinitionError)((0, utils_3.kindToTypeString)(node.kind), typeName));
1128
- return false;
1129
- }
1130
- const isEntity = (0, utils_1.isObjectLikeNodeEntity)(node);
1131
- factory.parentContainerByTypeName.set(typeName, {
1132
- description: (0, utils_1.formatDescription)(node.description),
1133
- directives: factory.extractDirectivesAndAuthorization(node, new Map()),
1134
- fields: new Map(),
1135
- interfaces: (0, utils_1.extractInterfaces)(node, new Set(), factory.errors),
1136
- isEntity,
1137
- kind: node.kind,
1138
- name: node.name,
1139
- });
1140
- if (!isEntity) {
1141
- return;
1142
- }
1143
- const fieldSetContainer = (0, utils_3.getValueOrDefault)(factory.fieldSetContainerByTypeName, typeName, utils_2.newFieldSetContainer);
1144
- factory.extractKeyFieldSets(node, fieldSetContainer);
1145
- (0, utils_3.upsertEntityContainerProperties)(factory.entityContainerByTypeName, {
1146
- typeName: factory.parentTypeName,
1147
- keyFieldSets: fieldSetContainer.keys,
1148
- ...(factory.subgraphName ? { subgraphNames: [factory.subgraphName] } : {}),
1149
- });
1150
- },
1151
- leave() {
1152
- factory.isCurrentParentRootType = false;
1153
- factory.isCurrentParentExtension = false;
1154
- factory.parentTypeName = '';
1155
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1156
- },
1157
- },
1158
- ObjectTypeExtension: {
1159
- enter(node) {
1160
- const name = node.name.value;
1161
- if (name === string_constants_1.SERVICE_OBJECT) {
1162
- return false;
1163
- }
1164
- factory.isCurrentParentRootType = string_constants_1.ROOT_TYPES.has(name) || factory.operationTypeNames.has(name);
1165
- factory.parentTypeName = name;
1166
- factory.lastParentNodeKind = node.kind;
1167
- (0, utils_1.addConcreteTypesForImplementedInterfaces)(node, factory.abstractToConcreteTypeNames);
1168
- return factory.handleObjectLikeExtension(node);
1169
- },
1170
- leave() {
1171
- factory.isCurrentParentRootType = false;
1172
- factory.isCurrentParentExtension = false;
1173
- factory.parentTypeName = '';
1174
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1175
- },
1176
- },
1177
- ScalarTypeDefinition: {
1178
- enter(node) {
1179
- const name = node.name.value;
1180
- if (name === string_constants_1.ANY_SCALAR) {
1181
- return false;
1182
- }
1183
- const parent = factory.parentContainerByTypeName.get(name);
1184
- if (parent) {
1185
- factory.errors.push((0, errors_1.duplicateTypeDefinitionError)((0, utils_3.kindToTypeString)(node.kind), name));
1186
- return false;
1187
- }
1188
- factory.parentTypeName = name;
1189
- factory.lastParentNodeKind = node.kind;
1190
- factory.parentContainerByTypeName.set(name, {
1191
- description: (0, utils_1.formatDescription)(node.description),
1192
- directives: factory.extractDirectivesAndAuthorization(node, new Map()),
1193
- kind: graphql_1.Kind.SCALAR_TYPE_DEFINITION,
1194
- name: node.name,
1195
- });
1196
- },
1197
- leave() {
1198
- factory.parentTypeName = '';
1199
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1200
- },
1201
- },
1202
- ScalarTypeExtension: {
1203
- enter(node) {
1204
- const name = node.name.value;
1205
- if (name === string_constants_1.ANY_SCALAR) {
1206
- return false;
1207
- }
1208
- const extension = factory.extensionContainerByTypeName.get(name);
1209
- if (extension) {
1210
- if (extension.kind !== graphql_1.Kind.SCALAR_TYPE_EXTENSION) {
1211
- factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
1212
- return false;
1213
- }
1214
- factory.extractDirectivesAndAuthorization(node, extension.directives);
1215
- }
1216
- else {
1217
- factory.parentTypeName = name;
1218
- factory.lastParentNodeKind = node.kind;
1219
- factory.extensionContainerByTypeName.set(name, {
1220
- directives: factory.extractDirectivesAndAuthorization(node, new Map()),
1221
- kind: node.kind,
1222
- name: node.name,
1223
- });
1224
- }
1225
- return false;
1226
- },
1227
- leave() {
1228
- factory.parentTypeName = '';
1229
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1230
- },
1231
- },
1232
- UnionTypeDefinition: {
1233
- enter(node) {
1234
- const name = node.name.value;
1235
- if (name === string_constants_1.ENTITY_UNION) {
1236
- return false;
1237
- }
1238
- factory.parentTypeName = name;
1239
- const parent = factory.parentContainerByTypeName.get(name);
1240
- if (parent) {
1241
- factory.errors.push((0, errors_1.duplicateTypeDefinitionError)((0, utils_3.kindToTypeString)(node.kind), name));
1242
- return false;
1243
- }
1244
- if (!node.types) {
1245
- factory.errors.push((0, errors_1.noDefinedUnionMembersError)(name));
1246
- return false;
1247
- }
1248
- factory.lastParentNodeKind = node.kind;
1249
- (0, utils_1.addConcreteTypesForUnion)(node, factory.abstractToConcreteTypeNames);
1250
- factory.parentContainerByTypeName.set(name, {
1251
- description: (0, utils_1.formatDescription)(node.description),
1252
- directives: factory.extractDirectives(node, new Map()),
1253
- kind: node.kind,
1254
- name: node.name,
1255
- types: factory.extractUniqueUnionMembers([...node.types], new Map()),
1256
- });
1257
- },
1258
- leave() {
1259
- factory.parentTypeName = '';
1260
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1261
- },
1262
- },
1263
- UnionTypeExtension: {
1264
- enter(node) {
1265
- const name = node.name.value;
1266
- if (name === string_constants_1.ENTITY_UNION) {
1267
- return false;
1268
- }
1269
- const extension = factory.extensionContainerByTypeName.get(name);
1270
- if (!node.types) {
1271
- factory.errors.push();
1272
- return false;
1273
- }
1274
- factory.lastParentNodeKind = node.kind;
1275
- (0, utils_1.addConcreteTypesForUnion)(node, factory.abstractToConcreteTypeNames);
1276
- if (extension) {
1277
- if (extension.kind !== graphql_1.Kind.UNION_TYPE_EXTENSION) {
1278
- factory.errors.push((0, errors_1.incompatibleExtensionKindsError)(node, extension.kind));
1279
- return false;
1280
- }
1281
- factory.extractDirectives(node, extension.directives);
1282
- }
1283
- else {
1284
- factory.extensionContainerByTypeName.set(name, {
1285
- directives: factory.extractDirectives(node, new Map()),
1286
- kind: node.kind,
1287
- name: node.name,
1288
- types: factory.extractUniqueUnionMembers([...node.types], new Map()),
1289
- });
556
+ (0, walkers_1.upsertDirectiveAndSchemaDefinitions)(this, document);
557
+ (0, walkers_1.upsertParentsAndChildren)(this, document);
558
+ (0, walkers_1.consolidateAuthorizationDirectives)(this, document);
559
+ for (const interfaceTypeName of this.interfaceTypeNamesWithAuthorizationDirectives) {
560
+ const interfaceAuthorizationData = this.authorizationDataByParentTypeName.get(interfaceTypeName);
561
+ if (!interfaceAuthorizationData) {
562
+ continue;
563
+ }
564
+ const concreteTypeNames = this.abstractToConcreteTypeNames.get(interfaceTypeName);
565
+ for (const concreteTypeName of concreteTypeNames || []) {
566
+ const concreteAuthorizationData = (0, utils_3.getValueOrDefault)(this.authorizationDataByParentTypeName, concreteTypeName, () => (0, utils_3.newAuthorizationData)(concreteTypeName));
567
+ for (const [fieldName, interfaceFieldAuthorizationData,] of interfaceAuthorizationData.fieldAuthorizationDataByFieldName) {
568
+ if (!(0, utils_3.upsertFieldAuthorizationData)(concreteAuthorizationData.fieldAuthorizationDataByFieldName, interfaceFieldAuthorizationData)) {
569
+ this.invalidOrScopesHostPaths.add(`${concreteTypeName}.${fieldName}`);
1290
570
  }
1291
- return false;
1292
- },
1293
- leave() {
1294
- factory.lastParentNodeKind = graphql_1.Kind.NULL;
1295
- },
1296
- },
1297
- });
571
+ }
572
+ }
573
+ }
574
+ // Apply inherited leaf authorization that was not applied to interface fields of that type earlier
575
+ for (const [typeName, fieldAuthorizationDatas] of this.heirFieldAuthorizationDataByTypeName) {
576
+ const authorizationData = this.authorizationDataByParentTypeName.get(typeName);
577
+ if (!authorizationData) {
578
+ continue;
579
+ }
580
+ for (const fieldAuthorizationData of fieldAuthorizationDatas) {
581
+ if (!(0, utils_3.mergeAuthorizationDataByAND)(authorizationData, fieldAuthorizationData)) {
582
+ this.invalidOrScopesHostPaths.add(`${typeName}.${fieldAuthorizationData.fieldName}`);
583
+ }
584
+ }
585
+ }
586
+ if (this.invalidOrScopesHostPaths.size > 0) {
587
+ this.errors.push((0, errors_1.orScopesLimitError)(utils_3.maxOrScopes, [...this.invalidOrScopesHostPaths]));
588
+ }
1298
589
  const definitions = [];
1299
590
  for (const directiveDefinition of constants_1.BASE_DIRECTIVE_DEFINITIONS) {
1300
591
  definitions.push(directiveDefinition);
1301
592
  }
1302
593
  definitions.push(constants_1.FIELD_SET_SCALAR_DEFINITION);
1303
- if (factory.isSubgraphVersionTwo) {
594
+ if (this.isSubgraphVersionTwo) {
1304
595
  for (const directiveDefinition of constants_1.VERSION_TWO_DIRECTIVE_DEFINITIONS) {
1305
596
  definitions.push(directiveDefinition);
1306
- this.allDirectiveDefinitions.set(directiveDefinition.name.value, directiveDefinition);
597
+ this.directiveDefinitionByDirectiveName.set(directiveDefinition.name.value, directiveDefinition);
1307
598
  }
1308
599
  definitions.push(constants_1.SCOPE_SCALAR_DEFINITION);
1309
600
  }
@@ -1311,11 +602,11 @@ class NormalizationFactory {
1311
602
  definitions.push(directiveDefinition);
1312
603
  }
1313
604
  if (this.schemaDefinition.operationTypes.size > 0) {
1314
- definitions.push((0, utils_2.schemaContainerToNode)(this, this.schemaDefinition));
605
+ definitions.push((0, utils_4.getSchemaNodeByData)(this.schemaDefinition, this.errors, this.directiveDefinitionByDirectiveName));
1315
606
  }
1316
607
  const validExtensionOrphans = new Set();
1317
608
  const parentsToIgnore = new Set();
1318
- for (const [extensionTypeName, extensionContainer] of this.extensionContainerByTypeName) {
609
+ for (const [extensionTypeName, parentExtensionData] of this.parentExtensionDataByTypeName) {
1319
610
  const isEntity = this.entityContainerByTypeName.has(extensionTypeName);
1320
611
  const configurationData = {
1321
612
  fieldNames: new Set(),
@@ -1323,91 +614,91 @@ class NormalizationFactory {
1323
614
  typeName: extensionTypeName,
1324
615
  };
1325
616
  this.configurationDataMap.set(extensionTypeName, configurationData);
1326
- if (extensionContainer.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
617
+ if (parentExtensionData.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
1327
618
  if (this.operationTypeNames.has(extensionTypeName)) {
1328
- extensionContainer.fields.delete(string_constants_1.SERVICE_FIELD);
1329
- extensionContainer.fields.delete(string_constants_1.ENTITIES_FIELD);
619
+ parentExtensionData.fieldDataByFieldName.delete(string_constants_1.SERVICE_FIELD);
620
+ parentExtensionData.fieldDataByFieldName.delete(string_constants_1.ENTITIES_FIELD);
1330
621
  }
1331
- (0, utils_2.addNonExternalFieldsToSet)(extensionContainer.fields, configurationData.fieldNames);
622
+ (0, utils_2.addNonExternalFieldsToSet)(parentExtensionData.fieldDataByFieldName, configurationData.fieldNames);
1332
623
  }
1333
- const baseType = this.parentContainerByTypeName.get(extensionTypeName);
1334
- if (!baseType) {
1335
- if (extensionContainer.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
624
+ const parentDefinitionData = this.parentDefinitionDataByTypeName.get(extensionTypeName);
625
+ if (!parentDefinitionData) {
626
+ if (parentExtensionData.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
1336
627
  this.errors.push((0, errors_1.noBaseTypeExtensionError)(extensionTypeName));
1337
628
  }
1338
629
  else {
1339
- this.validateInterfaceImplementations(extensionContainer);
630
+ this.validateInterfaceImplementations(parentExtensionData);
1340
631
  validExtensionOrphans.add(extensionTypeName);
1341
- definitions.push((0, utils_2.objectLikeContainerToNode)(this, extensionContainer));
632
+ definitions.push((0, utils_4.getParentWithFieldsNodeByData)(parentExtensionData, this.errors, this.directiveDefinitionByDirectiveName, this.authorizationDataByParentTypeName));
1342
633
  }
1343
634
  continue;
1344
635
  }
1345
- if (!(0, utils_1.areBaseAndExtensionKindsCompatible)(baseType.kind, extensionContainer.kind, extensionTypeName)) {
1346
- this.errors.push((0, errors_1.incompatibleExtensionError)(extensionTypeName, baseType.kind, extensionContainer.kind));
636
+ if (!(0, utils_1.areBaseAndExtensionKindsCompatible)(parentDefinitionData.kind, parentExtensionData.kind, extensionTypeName)) {
637
+ this.errors.push((0, errors_1.incompatibleExtensionError)(extensionTypeName, parentDefinitionData.kind, parentExtensionData.kind));
1347
638
  continue;
1348
639
  }
1349
- switch (baseType.kind) {
640
+ switch (parentDefinitionData.kind) {
1350
641
  case graphql_1.Kind.ENUM_TYPE_DEFINITION:
1351
- const enumExtension = extensionContainer;
1352
- for (const [valueName, enumValueDefinitionNode] of enumExtension.values) {
1353
- if (!baseType.values.has(valueName)) {
1354
- baseType.values.set(valueName, enumValueDefinitionNode);
642
+ const enumExtensionData = parentExtensionData;
643
+ for (const [valueName, enumValueDefinitionNode] of enumExtensionData.enumValueDataByValueName) {
644
+ if (!parentDefinitionData.enumValueDataByValueName.has(valueName)) {
645
+ parentDefinitionData.enumValueDataByValueName.set(valueName, enumValueDefinitionNode);
1355
646
  continue;
1356
647
  }
1357
648
  this.errors.push((0, errors_1.duplicateEnumValueDefinitionError)(valueName, extensionTypeName));
1358
649
  }
1359
- definitions.push((0, utils_2.enumContainerToNode)(this, baseType, enumExtension));
650
+ definitions.push((0, utils_4.getEnumNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, this.authorizationDataByParentTypeName, enumExtensionData));
1360
651
  break;
1361
652
  case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
1362
- const inputExtension = extensionContainer;
1363
- for (const [fieldName, inputValueDefinitionNode] of inputExtension.fields) {
1364
- if (!baseType.fields.has(fieldName)) {
1365
- baseType.fields.set(fieldName, inputValueDefinitionNode);
653
+ const inputObjectExtensionData = parentExtensionData;
654
+ for (const [fieldName, inputValueDefinitionNode] of inputObjectExtensionData.inputValueDataByValueName) {
655
+ if (!parentDefinitionData.inputValueDataByValueName.has(fieldName)) {
656
+ parentDefinitionData.inputValueDataByValueName.set(fieldName, inputValueDefinitionNode);
1366
657
  continue;
1367
658
  }
1368
659
  this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName, extensionTypeName));
1369
660
  }
1370
- definitions.push((0, utils_2.inputObjectContainerToNode)(this, baseType, inputExtension));
661
+ definitions.push((0, utils_4.getInputObjectNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, this.authorizationDataByParentTypeName, inputObjectExtensionData));
1371
662
  break;
1372
663
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
1373
664
  // intentional fallthrough
1374
665
  case graphql_1.Kind.OBJECT_TYPE_DEFINITION:
1375
- const objectLikeExtension = extensionContainer;
666
+ const extensionWithFieldsData = parentExtensionData;
1376
667
  const operationTypeNode = this.operationTypeNames.get(extensionTypeName);
1377
668
  if (operationTypeNode) {
1378
- objectLikeExtension.fields.delete(string_constants_1.SERVICE_FIELD);
1379
- objectLikeExtension.fields.delete(string_constants_1.ENTITIES_FIELD);
669
+ extensionWithFieldsData.fieldDataByFieldName.delete(string_constants_1.SERVICE_FIELD);
670
+ extensionWithFieldsData.fieldDataByFieldName.delete(string_constants_1.ENTITIES_FIELD);
1380
671
  }
1381
- for (const [fieldName, fieldContainer] of objectLikeExtension.fields) {
1382
- if (fieldContainer.arguments.size > 0) {
672
+ for (const [fieldName, fieldData] of extensionWithFieldsData.fieldDataByFieldName) {
673
+ if (fieldData.argumentDataByArgumentName.size > 0) {
1383
674
  // Arguments can only be fully validated once all parents types are known
1384
- this.validateArguments(fieldContainer, `${extensionTypeName}.${fieldName}`);
675
+ this.validateArguments(fieldData, `${extensionTypeName}.${fieldName}`);
1385
676
  }
1386
- if (baseType.fields.has(fieldName)) {
677
+ if (parentDefinitionData.fieldDataByFieldName.has(fieldName)) {
1387
678
  this.errors.push((0, errors_1.duplicateFieldDefinitionError)(fieldName, extensionTypeName));
1388
679
  continue;
1389
680
  }
1390
- baseType.fields.set(fieldName, fieldContainer);
1391
- if (!fieldContainer.arguments.has(string_constants_1.EXTERNAL)) {
681
+ parentDefinitionData.fieldDataByFieldName.set(fieldName, fieldData);
682
+ if (!fieldData.argumentDataByArgumentName.has(string_constants_1.EXTERNAL)) {
1392
683
  configurationData.fieldNames.add(fieldName);
1393
684
  }
1394
685
  }
1395
- this.mergeUniqueInterfaces(objectLikeExtension.interfaces, baseType.interfaces, extensionTypeName);
1396
- this.validateInterfaceImplementations(baseType);
1397
- definitions.push((0, utils_2.objectLikeContainerToNode)(this, baseType, objectLikeExtension));
686
+ this.mergeUniqueInterfaces(extensionWithFieldsData.implementedInterfaceTypeNames, parentDefinitionData.implementedInterfaceTypeNames, extensionTypeName);
687
+ this.validateInterfaceImplementations(parentDefinitionData);
688
+ definitions.push((0, utils_4.getParentWithFieldsNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, this.authorizationDataByParentTypeName, extensionWithFieldsData));
1398
689
  // Interfaces and objects must define at least one field
1399
- if (baseType.fields.size < 1 && !(0, utils_2.isNodeQuery)(extensionTypeName, operationTypeNode)) {
1400
- this.errors.push((0, errors_1.noFieldDefinitionsError)((0, utils_3.kindToTypeString)(baseType.kind), extensionTypeName));
690
+ if (parentDefinitionData.fieldDataByFieldName.size < 1 &&
691
+ !(0, utils_2.isNodeQuery)(extensionTypeName, operationTypeNode)) {
692
+ this.errors.push((0, errors_1.noFieldDefinitionsError)((0, utils_3.kindToTypeString)(parentDefinitionData.kind), extensionTypeName));
1401
693
  }
1402
694
  // Add the non-external base type field names to the configuration data
1403
- (0, utils_2.addNonExternalFieldsToSet)(baseType.fields, configurationData.fieldNames);
695
+ (0, utils_2.addNonExternalFieldsToSet)(parentDefinitionData.fieldDataByFieldName, configurationData.fieldNames);
1404
696
  break;
1405
697
  case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
1406
- definitions.push((0, utils_2.scalarContainerToNode)(this, baseType, extensionContainer));
698
+ definitions.push((0, utils_4.getScalarNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, parentExtensionData));
1407
699
  break;
1408
700
  case graphql_1.Kind.UNION_TYPE_DEFINITION:
1409
- const unionExtension = extensionContainer;
1410
- definitions.push((0, utils_2.unionContainerToNode)(this, baseType, unionExtension));
701
+ definitions.push((0, utils_4.getUnionNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, parentExtensionData));
1411
702
  break;
1412
703
  default:
1413
704
  throw (0, errors_1.unexpectedKindFatalError)(extensionTypeName);
@@ -1415,16 +706,16 @@ class NormalizationFactory {
1415
706
  // At this point, the base type has been dealt with, so it doesn't need to be dealt with again
1416
707
  parentsToIgnore.add(extensionTypeName);
1417
708
  }
1418
- for (const [parentTypeName, parentContainer] of this.parentContainerByTypeName) {
709
+ for (const [parentTypeName, parentDefinitionData] of this.parentDefinitionDataByTypeName) {
1419
710
  if (parentsToIgnore.has(parentTypeName)) {
1420
711
  continue;
1421
712
  }
1422
- switch (parentContainer.kind) {
713
+ switch (parentDefinitionData.kind) {
1423
714
  case graphql_1.Kind.ENUM_TYPE_DEFINITION:
1424
- definitions.push((0, utils_2.enumContainerToNode)(this, parentContainer));
715
+ definitions.push((0, utils_4.getEnumNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, this.authorizationDataByParentTypeName));
1425
716
  break;
1426
717
  case graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION:
1427
- definitions.push((0, utils_2.inputObjectContainerToNode)(this, parentContainer));
718
+ definitions.push((0, utils_4.getInputObjectNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, this.authorizationDataByParentTypeName));
1428
719
  break;
1429
720
  case graphql_1.Kind.INTERFACE_TYPE_DEFINITION:
1430
721
  // intentional fallthrough
@@ -1432,15 +723,15 @@ class NormalizationFactory {
1432
723
  const isEntity = this.entityContainerByTypeName.has(parentTypeName);
1433
724
  const operationTypeNode = this.operationTypeNames.get(parentTypeName);
1434
725
  if (operationTypeNode) {
1435
- parentContainer.fields.delete(string_constants_1.SERVICE_FIELD);
1436
- parentContainer.fields.delete(string_constants_1.ENTITIES_FIELD);
726
+ parentDefinitionData.fieldDataByFieldName.delete(string_constants_1.SERVICE_FIELD);
727
+ parentDefinitionData.fieldDataByFieldName.delete(string_constants_1.ENTITIES_FIELD);
1437
728
  }
1438
729
  if (this.parentsWithChildArguments.has(parentTypeName)) {
1439
- if (parentContainer.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
1440
- parentContainer.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION) {
730
+ if (parentDefinitionData.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
731
+ parentDefinitionData.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION) {
1441
732
  continue;
1442
733
  }
1443
- for (const [fieldName, fieldContainer] of parentContainer.fields) {
734
+ for (const [fieldName, fieldContainer] of parentDefinitionData.fieldDataByFieldName) {
1444
735
  // Arguments can only be fully validated once all parents types are known
1445
736
  this.validateArguments(fieldContainer, `${parentTypeName}.${fieldName}`);
1446
737
  }
@@ -1462,19 +753,19 @@ class NormalizationFactory {
1462
753
  configurationData.events = events;
1463
754
  }
1464
755
  this.configurationDataMap.set(parentTypeName, configurationData);
1465
- (0, utils_2.addNonExternalFieldsToSet)(parentContainer.fields, configurationData.fieldNames);
1466
- this.validateInterfaceImplementations(parentContainer);
1467
- definitions.push((0, utils_2.objectLikeContainerToNode)(this, parentContainer));
756
+ (0, utils_2.addNonExternalFieldsToSet)(parentDefinitionData.fieldDataByFieldName, configurationData.fieldNames);
757
+ this.validateInterfaceImplementations(parentDefinitionData);
758
+ definitions.push((0, utils_4.getParentWithFieldsNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName, this.authorizationDataByParentTypeName));
1468
759
  // interfaces and objects must define at least one field
1469
- if (parentContainer.fields.size < 1 && !(0, utils_2.isNodeQuery)(parentTypeName, operationTypeNode)) {
1470
- this.errors.push((0, errors_1.noFieldDefinitionsError)((0, utils_3.kindToTypeString)(parentContainer.kind), parentTypeName));
760
+ if (parentDefinitionData.fieldDataByFieldName.size < 1 && !(0, utils_2.isNodeQuery)(parentTypeName, operationTypeNode)) {
761
+ this.errors.push((0, errors_1.noFieldDefinitionsError)((0, utils_3.kindToTypeString)(parentDefinitionData.kind), parentTypeName));
1471
762
  }
1472
763
  break;
1473
764
  case graphql_1.Kind.SCALAR_TYPE_DEFINITION:
1474
- definitions.push((0, utils_2.scalarContainerToNode)(this, parentContainer));
765
+ definitions.push((0, utils_4.getScalarNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName));
1475
766
  break;
1476
767
  case graphql_1.Kind.UNION_TYPE_DEFINITION:
1477
- definitions.push((0, utils_2.unionContainerToNode)(this, parentContainer));
768
+ definitions.push((0, utils_4.getUnionNodeByData)(parentDefinitionData, this.errors, this.directiveDefinitionByDirectiveName));
1478
769
  break;
1479
770
  default:
1480
771
  throw (0, errors_1.unexpectedKindFatalError)(parentTypeName);
@@ -1488,12 +779,13 @@ class NormalizationFactory {
1488
779
  const operationTypeName = node ? (0, type_merging_1.getNamedTypeForChild)(`schema.${operationType}`, node.type) : defaultTypeName;
1489
780
  // If a custom type is used, the default type should not be defined
1490
781
  if (operationTypeName !== defaultTypeName &&
1491
- (this.parentContainerByTypeName.has(defaultTypeName) || this.extensionContainerByTypeName.has(defaultTypeName))) {
782
+ (this.parentDefinitionDataByTypeName.has(defaultTypeName) ||
783
+ this.parentExtensionDataByTypeName.has(defaultTypeName))) {
1492
784
  this.errors.push((0, errors_1.invalidRootTypeDefinitionError)(operationType, operationTypeName, defaultTypeName));
1493
785
  continue;
1494
786
  }
1495
- const object = this.parentContainerByTypeName.get(operationTypeName);
1496
- const extension = this.extensionContainerByTypeName.get(operationTypeName);
787
+ const object = this.parentDefinitionDataByTypeName.get(operationTypeName);
788
+ const extension = this.parentExtensionDataByTypeName.get(operationTypeName);
1497
789
  // Node is truthy if an operation type was explicitly declared
1498
790
  if (node) {
1499
791
  // If the type is not defined in the schema, it's always an error
@@ -1523,12 +815,11 @@ class NormalizationFactory {
1523
815
  }
1524
816
  // Root types fields whose response type is an extension orphan could be valid through a federated graph
1525
817
  // However, the field would have to be shareable to ever be valid TODO
1526
- for (const fieldContainer of container.fields.values()) {
1527
- const fieldName = fieldContainer.name;
818
+ for (const [fieldName, fieldData] of container.fieldDataByFieldName) {
1528
819
  const fieldPath = `${operationTypeName}.${fieldName}`;
1529
- const fieldTypeName = (0, type_merging_1.getNamedTypeForChild)(fieldPath, fieldContainer.node.type);
820
+ const fieldTypeName = (0, type_merging_1.getNamedTypeForChild)(fieldPath, fieldData.node.type);
1530
821
  if (!constants_1.BASE_SCALARS.has(fieldTypeName) &&
1531
- !this.parentContainerByTypeName.has(fieldTypeName) &&
822
+ !this.parentDefinitionDataByTypeName.has(fieldTypeName) &&
1532
823
  !validExtensionOrphans.has(fieldTypeName)) {
1533
824
  this.errors.push((0, errors_1.undefinedTypeError)(fieldTypeName));
1534
825
  }
@@ -1536,17 +827,18 @@ class NormalizationFactory {
1536
827
  }
1537
828
  }
1538
829
  for (const referencedTypeName of this.referencedTypeNames) {
1539
- if (this.parentContainerByTypeName.has(referencedTypeName) ||
830
+ if (this.parentDefinitionDataByTypeName.has(referencedTypeName) ||
1540
831
  this.entityContainerByTypeName.has(referencedTypeName)) {
1541
832
  continue;
1542
833
  }
1543
- const extension = this.extensionContainerByTypeName.get(referencedTypeName);
834
+ const extension = this.parentExtensionDataByTypeName.get(referencedTypeName);
1544
835
  if (!extension || extension.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
1545
836
  this.errors.push((0, errors_1.undefinedTypeError)(referencedTypeName));
1546
837
  }
1547
838
  }
1548
839
  for (const [parentTypeName, fieldSetContainers] of this.fieldSetContainerByTypeName) {
1549
- const parentContainer = this.parentContainerByTypeName.get(parentTypeName) || this.extensionContainerByTypeName.get(parentTypeName);
840
+ const parentContainer = this.parentDefinitionDataByTypeName.get(parentTypeName) ||
841
+ this.parentExtensionDataByTypeName.get(parentTypeName);
1550
842
  if (!parentContainer ||
1551
843
  (parentContainer.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION &&
1552
844
  parentContainer.kind != graphql_1.Kind.OBJECT_TYPE_EXTENSION &&
@@ -1565,7 +857,6 @@ class NormalizationFactory {
1565
857
  kind: graphql_1.Kind.DOCUMENT,
1566
858
  definitions,
1567
859
  };
1568
- (0, subgraph_1.walkSubgraphToApplyFieldAuthorization)(factory, newAST);
1569
860
  return {
1570
861
  normalizationResult: {
1571
862
  authorizationDataByParentTypeName: this.authorizationDataByParentTypeName,
@@ -1574,12 +865,12 @@ class NormalizationFactory {
1574
865
  configurationDataMap: this.configurationDataMap,
1575
866
  entityContainerByTypeName: this.entityContainerByTypeName,
1576
867
  entityInterfaces: this.entityInterfaces,
1577
- extensionContainerByTypeName: this.extensionContainerByTypeName,
868
+ parentExtensionDataByTypeName: this.parentExtensionDataByTypeName,
1578
869
  isVersionTwo: this.isSubgraphVersionTwo,
1579
870
  keyFieldNamesByParentTypeName: this.keyFieldNamesByParentTypeName,
1580
871
  operationTypes: this.operationTypeNames,
1581
872
  overridesByTargetSubgraphName: this.overridesByTargetSubgraphName,
1582
- parentContainerByTypeName: this.parentContainerByTypeName,
873
+ parentDataByTypeName: this.parentDefinitionDataByTypeName,
1583
874
  subgraphAST: newAST,
1584
875
  subgraphString: (0, graphql_1.print)(newAST),
1585
876
  schema: (0, buildASTSchema_1.buildASTSchema)(newAST, { assumeValid: true }),
@@ -1595,10 +886,11 @@ function batchNormalize(subgraphs) {
1595
886
  const allOverridesByTargetSubgraphName = new Map();
1596
887
  const overrideSourceSubgraphNamesByFieldPath = new Map();
1597
888
  const duplicateOverriddenFieldPaths = new Set();
1598
- const parentContainerMapsBySubgraphName = new Map();
889
+ const parentDefinitionDataMapsBySubgraphName = new Map();
1599
890
  const subgraphNames = new Set();
1600
891
  const nonUniqueSubgraphNames = new Set();
1601
892
  const invalidNameErrorMessages = [];
893
+ const invalidOrScopesHostPaths = new Set();
1602
894
  const warnings = [];
1603
895
  const validationErrors = [];
1604
896
  // Record the subgraph names first, so that subgraph references can be validated
@@ -1622,9 +914,9 @@ function batchNormalize(subgraphs) {
1622
914
  validationErrors.push((0, errors_1.subgraphValidationError)(subgraphName, [errors_1.subgraphValidationFailureError]));
1623
915
  continue;
1624
916
  }
1625
- parentContainerMapsBySubgraphName.set(subgraphName, normalizationResult.parentContainerByTypeName);
917
+ parentDefinitionDataMapsBySubgraphName.set(subgraphName, normalizationResult.parentDataByTypeName);
1626
918
  for (const authorizationData of normalizationResult.authorizationDataByParentTypeName.values()) {
1627
- (0, utils_3.upsertAuthorizationData)(authorizationDataByParentTypeName, authorizationData);
919
+ (0, utils_3.upsertAuthorizationData)(authorizationDataByParentTypeName, authorizationData, invalidOrScopesHostPaths);
1628
920
  }
1629
921
  for (const entityContainer of normalizationResult.entityContainerByTypeName.values()) {
1630
922
  (0, utils_3.upsertEntityContainer)(entityContainerByTypeName, entityContainer);
@@ -1634,13 +926,13 @@ function batchNormalize(subgraphs) {
1634
926
  configurationDataMap: normalizationResult.configurationDataMap,
1635
927
  definitions: normalizationResult.subgraphAST,
1636
928
  entityInterfaces: normalizationResult.entityInterfaces,
1637
- extensionContainerByTypeName: normalizationResult.extensionContainerByTypeName,
929
+ parentExtensionDataByTypeName: normalizationResult.parentExtensionDataByTypeName,
1638
930
  keyFieldNamesByParentTypeName: normalizationResult.keyFieldNamesByParentTypeName,
1639
931
  isVersionTwo: normalizationResult.isVersionTwo,
1640
932
  name: subgraphName,
1641
933
  operationTypes: normalizationResult.operationTypes,
1642
934
  overriddenFieldNamesByParentTypeName: new Map(),
1643
- parentContainerByTypeName: normalizationResult.parentContainerByTypeName,
935
+ parentDataByTypeName: normalizationResult.parentDataByTypeName,
1644
936
  schema: normalizationResult.schema,
1645
937
  url: subgraph.url,
1646
938
  });
@@ -1673,6 +965,9 @@ function batchNormalize(subgraphs) {
1673
965
  }
1674
966
  }
1675
967
  const allErrors = [];
968
+ if (invalidOrScopesHostPaths.size > 0) {
969
+ allErrors.push((0, errors_1.orScopesLimitError)(utils_3.maxOrScopes, [...invalidOrScopesHostPaths]));
970
+ }
1676
971
  if (invalidNameErrorMessages.length > 0 || nonUniqueSubgraphNames.size > 0) {
1677
972
  allErrors.push((0, errors_1.invalidSubgraphNamesError)([...nonUniqueSubgraphNames], invalidNameErrorMessages));
1678
973
  }