@apollo/federation-internals 2.0.0-alpha.6 → 2.0.0-preview.10

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 (127) hide show
  1. package/CHANGELOG.md +43 -3
  2. package/dist/buildSchema.d.ts +7 -3
  3. package/dist/buildSchema.d.ts.map +1 -1
  4. package/dist/buildSchema.js +94 -61
  5. package/dist/buildSchema.js.map +1 -1
  6. package/dist/coreSpec.d.ts +39 -9
  7. package/dist/coreSpec.d.ts.map +1 -1
  8. package/dist/coreSpec.js +232 -42
  9. package/dist/coreSpec.js.map +1 -1
  10. package/dist/definitions.d.ts +71 -51
  11. package/dist/definitions.d.ts.map +1 -1
  12. package/dist/definitions.js +326 -231
  13. package/dist/definitions.js.map +1 -1
  14. package/dist/directiveAndTypeSpecification.d.ts +48 -0
  15. package/dist/directiveAndTypeSpecification.d.ts.map +1 -0
  16. package/dist/directiveAndTypeSpecification.js +253 -0
  17. package/dist/directiveAndTypeSpecification.js.map +1 -0
  18. package/dist/error.d.ts +21 -1
  19. package/dist/error.d.ts.map +1 -1
  20. package/dist/error.js +63 -3
  21. package/dist/error.js.map +1 -1
  22. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  23. package/dist/extractSubgraphsFromSupergraph.js +42 -97
  24. package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
  25. package/dist/federation.d.ts +102 -46
  26. package/dist/federation.d.ts.map +1 -1
  27. package/dist/federation.js +762 -234
  28. package/dist/federation.js.map +1 -1
  29. package/dist/federationSpec.d.ts +23 -0
  30. package/dist/federationSpec.d.ts.map +1 -0
  31. package/dist/federationSpec.js +117 -0
  32. package/dist/federationSpec.js.map +1 -0
  33. package/dist/inaccessibleSpec.d.ts +5 -1
  34. package/dist/inaccessibleSpec.d.ts.map +1 -1
  35. package/dist/inaccessibleSpec.js +31 -3
  36. package/dist/inaccessibleSpec.js.map +1 -1
  37. package/dist/index.d.ts +4 -0
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +9 -1
  40. package/dist/index.js.map +1 -1
  41. package/dist/introspection.d.ts.map +1 -1
  42. package/dist/introspection.js +8 -3
  43. package/dist/introspection.js.map +1 -1
  44. package/dist/joinSpec.d.ts +6 -1
  45. package/dist/joinSpec.d.ts.map +1 -1
  46. package/dist/joinSpec.js +22 -0
  47. package/dist/joinSpec.js.map +1 -1
  48. package/dist/knownCoreFeatures.d.ts +4 -0
  49. package/dist/knownCoreFeatures.d.ts.map +1 -0
  50. package/dist/knownCoreFeatures.js +16 -0
  51. package/dist/knownCoreFeatures.js.map +1 -0
  52. package/dist/operations.d.ts +9 -1
  53. package/dist/operations.d.ts.map +1 -1
  54. package/dist/operations.js +27 -5
  55. package/dist/operations.js.map +1 -1
  56. package/dist/precompute.d.ts +3 -0
  57. package/dist/precompute.d.ts.map +1 -0
  58. package/dist/precompute.js +51 -0
  59. package/dist/precompute.js.map +1 -0
  60. package/dist/print.d.ts +11 -9
  61. package/dist/print.d.ts.map +1 -1
  62. package/dist/print.js +32 -22
  63. package/dist/print.js.map +1 -1
  64. package/dist/schemaUpgrader.d.ts +108 -0
  65. package/dist/schemaUpgrader.d.ts.map +1 -0
  66. package/dist/schemaUpgrader.js +497 -0
  67. package/dist/schemaUpgrader.js.map +1 -0
  68. package/dist/suggestions.d.ts +1 -1
  69. package/dist/suggestions.d.ts.map +1 -1
  70. package/dist/suggestions.js.map +1 -1
  71. package/dist/supergraphs.d.ts.map +1 -1
  72. package/dist/supergraphs.js +3 -3
  73. package/dist/supergraphs.js.map +1 -1
  74. package/dist/tagSpec.d.ts +7 -2
  75. package/dist/tagSpec.d.ts.map +1 -1
  76. package/dist/tagSpec.js +36 -16
  77. package/dist/tagSpec.js.map +1 -1
  78. package/dist/utils.d.ts +7 -0
  79. package/dist/utils.d.ts.map +1 -1
  80. package/dist/utils.js +34 -1
  81. package/dist/utils.js.map +1 -1
  82. package/dist/validate.d.ts.map +1 -1
  83. package/dist/validate.js +19 -11
  84. package/dist/validate.js.map +1 -1
  85. package/dist/validation/KnownTypeNamesInFederationRule.d.ts.map +1 -1
  86. package/dist/validation/KnownTypeNamesInFederationRule.js +1 -2
  87. package/dist/validation/KnownTypeNamesInFederationRule.js.map +1 -1
  88. package/dist/values.d.ts +1 -0
  89. package/dist/values.d.ts.map +1 -1
  90. package/dist/values.js +3 -2
  91. package/dist/values.js.map +1 -1
  92. package/package.json +4 -4
  93. package/src/__tests__/coreSpec.test.ts +100 -0
  94. package/src/__tests__/definitions.test.ts +98 -17
  95. package/src/__tests__/extractSubgraphsFromSupergraph.test.ts +64 -0
  96. package/src/__tests__/federation.test.ts +31 -0
  97. package/src/__tests__/operations.test.ts +2 -3
  98. package/src/__tests__/removeInaccessibleElements.test.ts +59 -6
  99. package/src/__tests__/schemaUpgrader.test.ts +169 -0
  100. package/src/__tests__/subgraphValidation.test.ts +422 -21
  101. package/src/__tests__/values.test.ts +2 -4
  102. package/src/buildSchema.ts +154 -84
  103. package/src/coreSpec.ts +294 -55
  104. package/src/definitions.ts +415 -275
  105. package/src/directiveAndTypeSpecification.ts +353 -0
  106. package/src/error.ts +143 -5
  107. package/src/extractSubgraphsFromSupergraph.ts +56 -122
  108. package/src/federation.ts +991 -302
  109. package/src/federationSpec.ts +146 -0
  110. package/src/inaccessibleSpec.ts +39 -11
  111. package/src/index.ts +4 -0
  112. package/src/introspection.ts +8 -3
  113. package/src/joinSpec.ts +35 -4
  114. package/src/knownCoreFeatures.ts +13 -0
  115. package/src/operations.ts +37 -7
  116. package/src/precompute.ts +65 -0
  117. package/src/print.ts +63 -48
  118. package/src/schemaUpgrader.ts +653 -0
  119. package/src/suggestions.ts +1 -1
  120. package/src/supergraphs.ts +4 -3
  121. package/src/tagSpec.ts +50 -18
  122. package/src/utils.ts +63 -0
  123. package/src/validate.ts +27 -16
  124. package/src/validation/KnownTypeNamesInFederationRule.ts +1 -7
  125. package/src/values.ts +7 -3
  126. package/tsconfig.test.tsbuildinfo +1 -1
  127. package/tsconfig.tsbuildinfo +1 -1
@@ -1,48 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ExternalTester = exports.addSubgraphToError = exports.addSubgraphToASTNode = exports.Subgraph = exports.Subgraphs = exports.subgraphsFromServiceList = exports.parseFieldSetArgument = exports.buildSubgraph = exports.isEntityType = exports.isFederationDirective = exports.isFederationField = exports.isFederationTypeName = exports.isFederationType = exports.isFederationSubgraphSchema = exports.federationBuiltIns = exports.FederationBuiltIns = exports.FEDERATION_RESERVED_SUBGRAPH_NAME = exports.entitiesFieldName = exports.serviceFieldName = exports.tagDirectiveName = exports.providesDirectiveName = exports.requiresDirectiveName = exports.externalDirectiveName = exports.extendsDirectiveName = exports.keyDirectiveName = exports.fieldSetTypeName = exports.anyTypeName = exports.serviceTypeName = exports.entityTypeName = void 0;
3
+ exports.removeInactiveProvidesAndRequires = exports.addSubgraphToError = exports.addSubgraphToASTNode = exports.Subgraph = exports.FEDERATION_OPERATION_FIELDS = exports.entitiesFieldName = exports.serviceFieldName = exports.FEDERATION_OPERATION_TYPES = exports.entityTypeSpec = exports.serviceTypeSpec = exports.anyTypeSpec = exports.Subgraphs = exports.subgraphsFromServiceList = exports.collectTargetFields = exports.parseFieldSetArgument = exports.newEmptyFederation2Schema = exports.buildSubgraph = exports.isEntityType = exports.isFederationField = exports.isFederationSubgraphSchema = exports.federationMetadata = exports.printSubgraphNames = exports.asFed2SubgraphDocument = exports.FEDERATION2_LINK_WTH_FULL_IMPORTS = exports.setSchemaAsFed2Subgraph = exports.FederationBlueprint = exports.FederationMetadata = exports.collectUsedFields = exports.FEDERATION_RESERVED_SUBGRAPH_NAME = void 0;
4
4
  const definitions_1 = require("./definitions");
5
5
  const utils_1 = require("./utils");
6
6
  const specifiedRules_1 = require("graphql/validation/specifiedRules");
7
7
  const graphql_1 = require("graphql");
8
- const print_1 = require("./print");
9
8
  const KnownTypeNamesInFederationRule_1 = require("./validation/KnownTypeNamesInFederationRule");
10
9
  const buildSchema_1 = require("./buildSchema");
11
10
  const operations_1 = require("./operations");
12
11
  const tagSpec_1 = require("./tagSpec");
13
12
  const error_1 = require("./error");
14
- exports.entityTypeName = '_Entity';
15
- exports.serviceTypeName = '_Service';
16
- exports.anyTypeName = '_Any';
17
- exports.fieldSetTypeName = '_FieldSet';
18
- exports.keyDirectiveName = 'key';
19
- exports.extendsDirectiveName = 'extends';
20
- exports.externalDirectiveName = 'external';
21
- exports.requiresDirectiveName = 'requires';
22
- exports.providesDirectiveName = 'provides';
23
- exports.tagDirectiveName = 'tag';
24
- exports.serviceFieldName = '_service';
25
- exports.entitiesFieldName = '_entities';
13
+ const precompute_1 = require("./precompute");
14
+ const coreSpec_1 = require("./coreSpec");
15
+ const federationSpec_1 = require("./federationSpec");
16
+ const print_1 = require("./print");
17
+ const directiveAndTypeSpecification_1 = require("./directiveAndTypeSpecification");
18
+ const suggestions_1 = require("./suggestions");
19
+ const inaccessibleSpec_1 = require("./inaccessibleSpec");
20
+ const linkSpec = coreSpec_1.LINK_VERSIONS.latest();
26
21
  const tagSpec = tagSpec_1.TAG_VERSIONS.latest();
22
+ const federationSpec = federationSpec_1.FEDERATION_VERSIONS.latest();
27
23
  exports.FEDERATION_RESERVED_SUBGRAPH_NAME = '_';
28
- const FEDERATION_TYPES = [
29
- exports.entityTypeName,
30
- exports.serviceTypeName,
31
- exports.anyTypeName,
32
- exports.fieldSetTypeName
33
- ];
34
- const FEDERATION_DIRECTIVES = [
35
- exports.keyDirectiveName,
36
- exports.extendsDirectiveName,
37
- exports.externalDirectiveName,
38
- exports.requiresDirectiveName,
39
- exports.providesDirectiveName,
40
- exports.tagDirectiveName
41
- ];
42
- const FEDERATION_ROOT_FIELDS = [
43
- exports.serviceFieldName,
44
- exports.entitiesFieldName
45
- ];
46
24
  const FEDERATION_OMITTED_VALIDATION_RULES = [
47
25
  graphql_1.PossibleTypeExtensionsRule,
48
26
  graphql_1.KnownTypeNamesRule
@@ -51,14 +29,11 @@ const FEDERATION_SPECIFIC_VALIDATION_RULES = [
51
29
  KnownTypeNamesInFederationRule_1.KnownTypeNamesInFederationRule
52
30
  ];
53
31
  const FEDERATION_VALIDATION_RULES = specifiedRules_1.specifiedSDLRules.filter(rule => !FEDERATION_OMITTED_VALIDATION_RULES.includes(rule)).concat(FEDERATION_SPECIFIC_VALIDATION_RULES);
54
- function validateFieldSetSelections(directiveName, selectionSet, hasExternalInParents, externalTester, externalFieldCoordinatesCollector, allowOnNonExternalLeafFields) {
32
+ function validateFieldSetSelections(directiveName, selectionSet, hasExternalInParents, federationMetadata, allowOnNonExternalLeafFields) {
55
33
  for (const selection of selectionSet.selections()) {
56
34
  if (selection.kind === 'FieldSelection') {
57
35
  const field = selection.element().definition;
58
- const isExternal = externalTester.isExternal(field);
59
- if (isExternal) {
60
- externalFieldCoordinatesCollector.push(field.coordinate);
61
- }
36
+ const isExternal = federationMetadata.isFieldExternal(field);
62
37
  if (field.hasArguments()) {
63
38
  throw error_1.ERROR_CATEGORIES.FIELDS_HAS_ARGS.get(directiveName).err({
64
39
  message: `field ${field.coordinate} cannot be included because it has arguments (fields with argument are not allowed in @${directiveName})`,
@@ -68,16 +43,16 @@ function validateFieldSetSelections(directiveName, selectionSet, hasExternalInPa
68
43
  const mustBeExternal = !selection.selectionSet && !allowOnNonExternalLeafFields && !hasExternalInParents;
69
44
  if (!isExternal && mustBeExternal) {
70
45
  const errorCode = error_1.ERROR_CATEGORIES.DIRECTIVE_FIELDS_MISSING_EXTERNAL.get(directiveName);
71
- if (externalTester.isFakeExternal(field)) {
46
+ if (federationMetadata.isFieldFakeExternal(field)) {
72
47
  throw errorCode.err({
73
48
  message: `field "${field.coordinate}" should not be part of a @${directiveName} since it is already "effectively" provided by this subgraph `
74
- + `(while it is marked @${exports.externalDirectiveName}, it is a @${exports.keyDirectiveName} field of an extension type, which are not internally considered external for historical/backward compatibility reasons)`,
49
+ + `(while it is marked @${federationSpec_1.externalDirectiveSpec.name}, it is a @${federationSpec_1.keyDirectiveSpec.name} field of an extension type, which are not internally considered external for historical/backward compatibility reasons)`,
75
50
  nodes: field.sourceAST
76
51
  });
77
52
  }
78
53
  else {
79
54
  throw errorCode.err({
80
- message: `field "${field.coordinate}" should not be part of a @${directiveName} since it is already provided by this subgraph (it is not marked @${exports.externalDirectiveName})`,
55
+ message: `field "${field.coordinate}" should not be part of a @${directiveName} since it is already provided by this subgraph (it is not marked @${federationSpec_1.externalDirectiveSpec.name})`,
81
56
  nodes: field.sourceAST
82
57
  });
83
58
  }
@@ -88,24 +63,24 @@ function validateFieldSetSelections(directiveName, selectionSet, hasExternalInPa
88
63
  if (!newHasExternalInParents && (0, definitions_1.isInterfaceType)(parentType)) {
89
64
  for (const implem of parentType.possibleRuntimeTypes()) {
90
65
  const fieldInImplem = implem.field(field.name);
91
- if (fieldInImplem && externalTester.isExternal(fieldInImplem)) {
66
+ if (fieldInImplem && federationMetadata.isFieldExternal(fieldInImplem)) {
92
67
  newHasExternalInParents = true;
93
68
  break;
94
69
  }
95
70
  }
96
71
  }
97
- validateFieldSetSelections(directiveName, selection.selectionSet, newHasExternalInParents, externalTester, externalFieldCoordinatesCollector, allowOnNonExternalLeafFields);
72
+ validateFieldSetSelections(directiveName, selection.selectionSet, newHasExternalInParents, federationMetadata, allowOnNonExternalLeafFields);
98
73
  }
99
74
  }
100
75
  else {
101
- validateFieldSetSelections(directiveName, selection.selectionSet, hasExternalInParents, externalTester, externalFieldCoordinatesCollector, allowOnNonExternalLeafFields);
76
+ validateFieldSetSelections(directiveName, selection.selectionSet, hasExternalInParents, federationMetadata, allowOnNonExternalLeafFields);
102
77
  }
103
78
  }
104
79
  }
105
- function validateFieldSet(type, directive, externalTester, externalFieldCoordinatesCollector, allowOnNonExternalLeafFields, onFields) {
80
+ function validateFieldSet(type, directive, federationMetadata, allowOnNonExternalLeafFields, onFields) {
106
81
  var _a;
107
82
  try {
108
- const fieldAcessor = onFields
83
+ const fieldAccessor = onFields
109
84
  ? (type, fieldName) => {
110
85
  const field = type.field(fieldName);
111
86
  if (field) {
@@ -114,9 +89,9 @@ function validateFieldSet(type, directive, externalTester, externalFieldCoordina
114
89
  return field;
115
90
  }
116
91
  : undefined;
117
- const selectionSet = parseFieldSetArgument(type, directive, fieldAcessor);
92
+ const selectionSet = parseFieldSetArgument({ parentType: type, directive, fieldAccessor });
118
93
  try {
119
- validateFieldSetSelections(directive.name, selectionSet, false, externalTester, externalFieldCoordinatesCollector, allowOnNonExternalLeafFields);
94
+ validateFieldSetSelections(directive.name, selectionSet, false, federationMetadata, allowOnNonExternalLeafFields);
120
95
  return undefined;
121
96
  }
122
97
  catch (e) {
@@ -155,7 +130,7 @@ function fieldSetTargetDescription(directive) {
155
130
  const targetKind = directive.parent instanceof definitions_1.FieldDefinition ? "field" : "type";
156
131
  return `${targetKind} "${(_a = directive.parent) === null || _a === void 0 ? void 0 : _a.coordinate}"`;
157
132
  }
158
- function validateAllFieldSet(definition, targetTypeExtractor, errorCollector, externalTester, externalFieldCoordinatesCollector, isOnParentType, allowOnNonExternalLeafFields, onFields) {
133
+ function validateAllFieldSet(definition, targetTypeExtractor, errorCollector, federationMetadata, isOnParentType, allowOnNonExternalLeafFields, onFields) {
159
134
  for (const application of definition.applications()) {
160
135
  const elt = application.parent;
161
136
  const type = targetTypeExtractor(elt);
@@ -169,35 +144,81 @@ function validateAllFieldSet(definition, targetTypeExtractor, errorCollector, ex
169
144
  nodes: (0, definitions_1.sourceASTs)(application).concat(isOnParentType ? [] : (0, definitions_1.sourceASTs)(type)),
170
145
  }));
171
146
  }
172
- const error = validateFieldSet(type, application, externalTester, externalFieldCoordinatesCollector, allowOnNonExternalLeafFields, onFields);
147
+ const error = validateFieldSet(type, application, federationMetadata, allowOnNonExternalLeafFields, onFields);
173
148
  if (error) {
174
149
  errorCollector.push(error);
175
150
  }
176
151
  }
177
152
  }
178
- function validateAllExternalFieldsUsed(schema, externalTester, allExternalFieldsUsedInFederationDirectivesCoordinates, errorCollector) {
179
- for (const type of schema.types()) {
153
+ function collectUsedFields(metadata) {
154
+ const usedFields = new Set();
155
+ collectUsedFieldsForDirective(metadata.keyDirective(), type => type, usedFields);
156
+ collectUsedFieldsForDirective(metadata.requiresDirective(), field => field.parent, usedFields);
157
+ collectUsedFieldsForDirective(metadata.providesDirective(), field => {
158
+ const type = (0, definitions_1.baseType)(field.type);
159
+ return (0, definitions_1.isCompositeType)(type) ? type : undefined;
160
+ }, usedFields);
161
+ for (const itfType of metadata.schema.interfaceTypes()) {
162
+ const runtimeTypes = itfType.possibleRuntimeTypes();
163
+ for (const field of itfType.fields()) {
164
+ for (const runtimeType of runtimeTypes) {
165
+ const implemField = runtimeType.field(field.name);
166
+ if (implemField) {
167
+ usedFields.add(implemField);
168
+ }
169
+ }
170
+ }
171
+ }
172
+ return usedFields;
173
+ }
174
+ exports.collectUsedFields = collectUsedFields;
175
+ function collectUsedFieldsForDirective(definition, targetTypeExtractor, usedFieldDefs) {
176
+ for (const application of definition.applications()) {
177
+ const type = targetTypeExtractor(application.parent);
178
+ if (!type) {
179
+ continue;
180
+ }
181
+ collectTargetFields({
182
+ parentType: type,
183
+ directive: application,
184
+ includeInterfaceFieldsImplementations: true,
185
+ validate: false,
186
+ }).forEach((field) => usedFieldDefs.add(field));
187
+ }
188
+ }
189
+ function validateAllExternalFieldsUsed(metadata, errorCollector) {
190
+ for (const type of metadata.schema.types()) {
180
191
  if (!(0, definitions_1.isObjectType)(type) && !(0, definitions_1.isInterfaceType)(type)) {
181
192
  continue;
182
193
  }
183
194
  for (const field of type.fields()) {
184
- if (!externalTester.isExternal(field) || allExternalFieldsUsedInFederationDirectivesCoordinates.includes(field.coordinate)) {
195
+ if (!metadata.isFieldExternal(field) || metadata.isFieldUsed(field)) {
185
196
  continue;
186
197
  }
187
- if (!isFieldSatisfyingInterface(field)) {
188
- errorCollector.push(error_1.ERRORS.EXTERNAL_UNUSED.err({
189
- message: `Field "${field.coordinate}" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface;`
190
- + ' the field declaration has no use and should be removed (or the field should not be @external).',
198
+ errorCollector.push(error_1.ERRORS.EXTERNAL_UNUSED.err({
199
+ message: `Field "${field.coordinate}" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface;`
200
+ + ' the field declaration has no use and should be removed (or the field should not be @external).',
201
+ nodes: field.sourceAST,
202
+ }));
203
+ }
204
+ }
205
+ }
206
+ function validateNoExternalOnInterfaceFields(metadata, errorCollector) {
207
+ for (const itf of metadata.schema.interfaceTypes()) {
208
+ for (const field of itf.fields()) {
209
+ if (metadata.isFieldExternal(field)) {
210
+ errorCollector.push(error_1.ERRORS.EXTERNAL_ON_INTERFACE.err({
211
+ message: `Interface type field "${field.coordinate}" is marked @external but @external is not allowed on interface fields (it is nonsensical).`,
191
212
  nodes: field.sourceAST,
192
213
  }));
193
214
  }
194
215
  }
195
216
  }
196
217
  }
197
- function isFieldSatisfyingInterface(field) {
198
- return field.parent.interfaces().some(itf => itf.field(field.name));
199
- }
200
- function validateInterfaceRuntimeImplementationFieldsTypes(itf, externalTester, errorCollector) {
218
+ function validateInterfaceRuntimeImplementationFieldsTypes(itf, metadata, errorCollector) {
219
+ var _a;
220
+ const requiresDirective = (_a = federationMetadata(itf.schema())) === null || _a === void 0 ? void 0 : _a.requiresDirective();
221
+ (0, utils_1.assert)(requiresDirective, 'Schema should be a federation subgraph, but @requires directive not found');
201
222
  const runtimeTypes = itf.possibleRuntimeTypes();
202
223
  for (const field of itf.fields()) {
203
224
  const withExternalOrRequires = [];
@@ -210,7 +231,7 @@ function validateInterfaceRuntimeImplementationFieldsTypes(itf, externalTester,
210
231
  if (implemField.sourceAST) {
211
232
  nodes.push(implemField.sourceAST);
212
233
  }
213
- if (externalTester.isExternal(implemField) || implemField.hasAppliedDirective(exports.requiresDirectiveName)) {
234
+ if (metadata.isFieldExternal(implemField) || implemField.hasAppliedDirective(requiresDirective)) {
214
235
  withExternalOrRequires.push(implemField);
215
236
  }
216
237
  const returnType = implemField.type;
@@ -229,77 +250,209 @@ const printFieldCoordinate = (f) => `"${f.coordinate}"`;
229
250
  function formatFieldsToReturnType([type, implems]) {
230
251
  return `${(0, utils_1.joinStrings)(implems.map(printFieldCoordinate))} ${implems.length == 1 ? 'has' : 'have'} type "${type}"`;
231
252
  }
232
- class FederationBuiltIns extends definitions_1.BuiltIns {
233
- addBuiltInTypes(schema) {
234
- super.addBuiltInTypes(schema);
235
- this.addBuiltInUnion(schema, exports.entityTypeName);
236
- this.addBuiltInObject(schema, exports.serviceTypeName).addField('sdl', schema.stringType());
237
- this.addBuiltInScalar(schema, exports.anyTypeName);
238
- this.addBuiltInScalar(schema, exports.fieldSetTypeName);
239
- }
240
- addBuiltInDirectives(schema) {
241
- super.addBuiltInDirectives(schema);
242
- const fieldSetType = new definitions_1.NonNullType(schema.type(exports.fieldSetTypeName));
243
- const keyDirective = this.addBuiltInDirective(schema, exports.keyDirectiveName)
244
- .addLocations(graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE);
245
- keyDirective.repeatable = true;
246
- keyDirective.addArgument('fields', fieldSetType);
247
- this.addBuiltInDirective(schema, exports.extendsDirectiveName)
248
- .addLocations(graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.INTERFACE);
249
- this.addBuiltInDirective(schema, exports.externalDirectiveName)
250
- .addLocations(graphql_1.DirectiveLocation.OBJECT, graphql_1.DirectiveLocation.FIELD_DEFINITION);
251
- for (const name of [exports.requiresDirectiveName, exports.providesDirectiveName]) {
252
- this.addBuiltInDirective(schema, name)
253
- .addLocations(graphql_1.DirectiveLocation.FIELD_DEFINITION)
254
- .addArgument('fields', fieldSetType);
255
- }
256
- const directive = this.addBuiltInDirective(schema, 'tag').addLocations(...tagSpec_1.tagLocations);
257
- directive.addArgument("name", new definitions_1.NonNullType(schema.stringType()));
258
- }
259
- prepareValidation(schema) {
260
- super.prepareValidation(schema);
261
- let entityType = schema.type(exports.entityTypeName);
262
- if (!entityType.isBuiltIn) {
263
- if (entityType.membersCount() === 0) {
264
- entityType.remove();
265
- }
266
- entityType = schema.builtInTypes('UnionType', true).find(u => u.name === exports.entityTypeName);
267
- }
268
- entityType.clearTypes();
269
- for (const objectType of schema.types("ObjectType")) {
270
- if (isEntityType(objectType)) {
271
- entityType.addType(objectType);
272
- }
273
- }
274
- const hasEntities = entityType.membersCount() > 0;
275
- if (!hasEntities) {
276
- entityType.remove();
277
- }
278
- const queryRoot = schema.schemaDefinition.root("query");
279
- const queryType = queryRoot ? queryRoot.type : schema.addType(new definitions_1.ObjectType("Query"));
280
- const entityField = queryType.field(exports.entitiesFieldName);
281
- if (hasEntities) {
282
- const anyType = schema.type(exports.anyTypeName);
283
- (0, utils_1.assert)(anyType, `The schema should have the _Any type`);
284
- const entityFieldType = new definitions_1.NonNullType(new definitions_1.ListType(entityType));
285
- if (!entityField) {
286
- this.addBuiltInField(queryType, exports.entitiesFieldName, entityFieldType)
287
- .addArgument('representations', new definitions_1.NonNullType(new definitions_1.ListType(new definitions_1.NonNullType(anyType))));
288
- }
289
- else if (!entityField.type) {
290
- entityField.type = entityType;
253
+ class FederationMetadata {
254
+ constructor(schema) {
255
+ this.schema = schema;
256
+ }
257
+ onInvalidate() {
258
+ this._externalTester = undefined;
259
+ this._sharingPredicate = undefined;
260
+ this._isFed2Schema = undefined;
261
+ this._fieldUsedPredicate = undefined;
262
+ }
263
+ isFed2Schema() {
264
+ if (!this._isFed2Schema) {
265
+ const feature = this.federationFeature();
266
+ this._isFed2Schema = !!feature && feature.url.version.satisfies(new coreSpec_1.FeatureVersion(2, 0));
267
+ }
268
+ return this._isFed2Schema;
269
+ }
270
+ federationFeature() {
271
+ var _a;
272
+ return (_a = this.schema.coreFeatures) === null || _a === void 0 ? void 0 : _a.getByIdentity(federationSpec.identity);
273
+ }
274
+ externalTester() {
275
+ if (!this._externalTester) {
276
+ this._externalTester = new ExternalTester(this.schema);
277
+ }
278
+ return this._externalTester;
279
+ }
280
+ sharingPredicate() {
281
+ if (!this._sharingPredicate) {
282
+ this._sharingPredicate = (0, precompute_1.computeShareables)(this.schema);
283
+ }
284
+ return this._sharingPredicate;
285
+ }
286
+ fieldUsedPredicate() {
287
+ if (!this._fieldUsedPredicate) {
288
+ const usedFields = collectUsedFields(this);
289
+ this._fieldUsedPredicate = (field) => !!usedFields.has(field);
290
+ }
291
+ return this._fieldUsedPredicate;
292
+ }
293
+ isFieldUsed(field) {
294
+ return this.fieldUsedPredicate()(field);
295
+ }
296
+ isFieldExternal(field) {
297
+ return this.externalTester().isExternal(field);
298
+ }
299
+ isFieldPartiallyExternal(field) {
300
+ return this.externalTester().isPartiallyExternal(field);
301
+ }
302
+ isFieldFullyExternal(field) {
303
+ return this.externalTester().isFullyExternal(field);
304
+ }
305
+ isFieldFakeExternal(field) {
306
+ return this.externalTester().isFakeExternal(field);
307
+ }
308
+ selectionSelectsAnyExternalField(selectionSet) {
309
+ return this.externalTester().selectsAnyExternalField(selectionSet);
310
+ }
311
+ isFieldShareable(field) {
312
+ return this.sharingPredicate()(field);
313
+ }
314
+ federationDirectiveNameInSchema(name) {
315
+ if (this.isFed2Schema()) {
316
+ const coreFeatures = this.schema.coreFeatures;
317
+ (0, utils_1.assert)(coreFeatures, 'Schema should be a core schema');
318
+ const federationFeature = coreFeatures.getByIdentity(federationSpec.identity);
319
+ (0, utils_1.assert)(federationFeature, 'Schema should have the federation feature');
320
+ return federationFeature.directiveNameInSchema(name);
321
+ }
322
+ else {
323
+ return name;
324
+ }
325
+ }
326
+ federationTypeNameInSchema(name) {
327
+ if (name.charAt(0) === '_') {
328
+ return name;
329
+ }
330
+ if (this.isFed2Schema()) {
331
+ const coreFeatures = this.schema.coreFeatures;
332
+ (0, utils_1.assert)(coreFeatures, 'Schema should be a core schema');
333
+ const federationFeature = coreFeatures.getByIdentity(federationSpec.identity);
334
+ (0, utils_1.assert)(federationFeature, 'Schema should have the federation feature');
335
+ return federationFeature.typeNameInSchema(name);
336
+ }
337
+ else {
338
+ return '_' + name;
339
+ }
340
+ }
341
+ getFederationDirective(name) {
342
+ const directive = this.schema.directive(this.federationDirectiveNameInSchema(name));
343
+ (0, utils_1.assert)(directive, `The provided schema does not have federation directive @${name}`);
344
+ return directive;
345
+ }
346
+ keyDirective() {
347
+ return this.getFederationDirective(federationSpec_1.keyDirectiveSpec.name);
348
+ }
349
+ overrideDirective() {
350
+ return this.getFederationDirective(federationSpec_1.overrideDirectiveSpec.name);
351
+ }
352
+ extendsDirective() {
353
+ return this.getFederationDirective(federationSpec_1.extendsDirectiveSpec.name);
354
+ }
355
+ externalDirective() {
356
+ return this.getFederationDirective(federationSpec_1.externalDirectiveSpec.name);
357
+ }
358
+ requiresDirective() {
359
+ return this.getFederationDirective(federationSpec_1.requiresDirectiveSpec.name);
360
+ }
361
+ providesDirective() {
362
+ return this.getFederationDirective(federationSpec_1.providesDirectiveSpec.name);
363
+ }
364
+ shareableDirective() {
365
+ return this.getFederationDirective(federationSpec_1.shareableDirectiveSpec.name);
366
+ }
367
+ tagDirective() {
368
+ return this.getFederationDirective(tagSpec.tagDirectiveSpec.name);
369
+ }
370
+ inaccessibleDirective() {
371
+ return this.getFederationDirective(inaccessibleSpec_1.inaccessibleDirectiveSpec.name);
372
+ }
373
+ allFederationDirectives() {
374
+ const baseDirectives = [
375
+ this.keyDirective(),
376
+ this.externalDirective(),
377
+ this.requiresDirective(),
378
+ this.providesDirective(),
379
+ this.tagDirective(),
380
+ this.extendsDirective(),
381
+ ];
382
+ return this.isFed2Schema()
383
+ ? baseDirectives.concat(this.shareableDirective(), this.inaccessibleDirective(), this.overrideDirective())
384
+ : baseDirectives;
385
+ }
386
+ entityType() {
387
+ return this.schema.type(this.federationTypeNameInSchema(exports.entityTypeSpec.name));
388
+ }
389
+ anyType() {
390
+ return this.schema.type(this.federationTypeNameInSchema(exports.anyTypeSpec.name));
391
+ }
392
+ serviceType() {
393
+ return this.schema.type(this.federationTypeNameInSchema(exports.serviceTypeSpec.name));
394
+ }
395
+ fieldSetType() {
396
+ return this.schema.type(this.federationTypeNameInSchema(federationSpec_1.fieldSetTypeSpec.name));
397
+ }
398
+ allFederationTypes() {
399
+ const baseTypes = [
400
+ this.anyType(),
401
+ this.serviceType(),
402
+ this.fieldSetType(),
403
+ ];
404
+ const entityType = this.entityType();
405
+ if (entityType) {
406
+ baseTypes.push(entityType);
407
+ }
408
+ return baseTypes;
409
+ }
410
+ }
411
+ exports.FederationMetadata = FederationMetadata;
412
+ class FederationBlueprint extends definitions_1.SchemaBlueprint {
413
+ onAddedCoreFeature(schema, feature) {
414
+ super.onAddedCoreFeature(schema, feature);
415
+ if (feature.url.identity === federationSpec_1.federationIdentity) {
416
+ const spec = federationSpec_1.FEDERATION_VERSIONS.find(feature.url.version);
417
+ if (spec) {
418
+ spec.addElementsToSchema(schema);
291
419
  }
292
420
  }
293
- else if (entityField) {
294
- entityField.remove();
421
+ }
422
+ onMissingDirectiveDefinition(schema, name, args) {
423
+ if (name === coreSpec_1.linkDirectiveDefaultName) {
424
+ const url = args && args['url'];
425
+ const as = url && url.startsWith(linkSpec.identity) ? args['as'] : undefined;
426
+ const errors = linkSpec.addDefinitionsToSchema(schema, as);
427
+ return errors.length > 0 ? errors : schema.directive(name);
295
428
  }
296
- if (!queryType.field(exports.serviceFieldName)) {
297
- this.addBuiltInField(queryType, exports.serviceFieldName, schema.type(exports.serviceTypeName));
429
+ return super.onMissingDirectiveDefinition(schema, name, args);
430
+ }
431
+ ignoreParsedField(type, fieldName) {
432
+ if (!exports.FEDERATION_OPERATION_FIELDS.includes(fieldName)) {
433
+ return false;
298
434
  }
435
+ const metadata = federationMetadata(type.schema());
436
+ return !!metadata && !metadata.isFed2Schema();
437
+ }
438
+ onConstructed(schema) {
439
+ const existing = federationMetadata(schema);
440
+ if (!existing) {
441
+ schema['_federationMetadata'] = new FederationMetadata(schema);
442
+ }
443
+ }
444
+ onDirectiveDefinitionAndSchemaParsed(schema) {
445
+ return completeSubgraphSchema(schema);
446
+ }
447
+ onInvalidation(schema) {
448
+ super.onInvalidation(schema);
449
+ const metadata = federationMetadata(schema);
450
+ (0, utils_1.assert)(metadata, 'Federation schema should have had its metadata set on construction');
451
+ FederationMetadata.prototype['onInvalidate'].call(metadata);
299
452
  }
300
453
  onValidation(schema) {
301
454
  var _a;
302
- const errors = super.onValidation(schema, [exports.tagDirectiveName]);
455
+ const errors = super.onValidation(schema);
303
456
  for (const k of definitions_1.allSchemaRootKinds) {
304
457
  const type = (_a = schema.schemaDefinition.root(k)) === null || _a === void 0 ? void 0 : _a.type;
305
458
  const defaultName = (0, definitions_1.defaultRootName)(k);
@@ -316,21 +469,25 @@ class FederationBuiltIns extends definitions_1.BuiltIns {
316
469
  type.rename(defaultName);
317
470
  }
318
471
  }
319
- const externalTester = new ExternalTester(schema);
320
- const externalFieldsInFedDirectivesCoordinates = [];
321
- const keyDirective = this.keyDirective(schema);
322
- validateAllFieldSet(keyDirective, type => type, errors, externalTester, externalFieldsInFedDirectivesCoordinates, true, true, field => {
323
- if ((0, definitions_1.isListType)(field.type) || (0, definitions_1.isUnionType)(field.type) || (0, definitions_1.isInterfaceType)(field.type)) {
324
- let kind = field.type.kind;
472
+ const metadata = federationMetadata(schema);
473
+ (0, utils_1.assert)(metadata, 'Federation schema should have had its metadata set on construction');
474
+ if (!metadata.isFed2Schema()) {
475
+ return errors;
476
+ }
477
+ const keyDirective = metadata.keyDirective();
478
+ validateAllFieldSet(keyDirective, type => type, errors, metadata, true, true, field => {
479
+ const type = (0, definitions_1.baseType)(field.type);
480
+ if ((0, definitions_1.isUnionType)(type) || (0, definitions_1.isInterfaceType)(type)) {
481
+ let kind = type.kind;
325
482
  kind = kind.slice(0, kind.length - 'Type'.length);
326
483
  throw error_1.ERRORS.KEY_FIELDS_SELECT_INVALID_TYPE.err({
327
484
  message: `field "${field.coordinate}" is a ${kind} type which is not allowed in @key`
328
485
  });
329
486
  }
330
487
  });
331
- validateAllFieldSet(this.requiresDirective(schema), field => field.parent, errors, externalTester, externalFieldsInFedDirectivesCoordinates, false, false);
332
- validateAllFieldSet(this.providesDirective(schema), field => {
333
- if (externalTester.isExternal(field)) {
488
+ validateAllFieldSet(metadata.requiresDirective(), field => field.parent, errors, metadata, false, false);
489
+ validateAllFieldSet(metadata.providesDirective(), field => {
490
+ if (metadata.isFieldExternal(field)) {
334
491
  throw new graphql_1.GraphQLError(`Cannot have both @provides and @external on field "${field.coordinate}"`, field.sourceAST);
335
492
  }
336
493
  const type = (0, definitions_1.baseType)(field.type);
@@ -341,93 +498,163 @@ class FederationBuiltIns extends definitions_1.BuiltIns {
341
498
  });
342
499
  }
343
500
  return type;
344
- }, errors, externalTester, externalFieldsInFedDirectivesCoordinates, false, false);
345
- validateAllExternalFieldsUsed(schema, externalTester, externalFieldsInFedDirectivesCoordinates, errors);
346
- const tagDirective = this.tagDirective(schema);
347
- if (!tagDirective.isBuiltIn) {
501
+ }, errors, metadata, false, false);
502
+ validateNoExternalOnInterfaceFields(metadata, errors);
503
+ validateAllExternalFieldsUsed(metadata, errors);
504
+ const tagDirective = metadata.tagDirective();
505
+ if (tagDirective) {
348
506
  const error = tagSpec.checkCompatibleDirective(tagDirective);
349
507
  if (error) {
350
508
  errors.push(error);
351
509
  }
352
510
  }
353
- for (const itf of schema.types('InterfaceType')) {
354
- validateInterfaceRuntimeImplementationFieldsTypes(itf, externalTester, errors);
511
+ for (const itf of schema.interfaceTypes()) {
512
+ validateInterfaceRuntimeImplementationFieldsTypes(itf, metadata, errors);
355
513
  }
356
514
  return errors;
357
515
  }
358
516
  validationRules() {
359
517
  return FEDERATION_VALIDATION_RULES;
360
518
  }
361
- keyDirective(schema) {
362
- return this.getTypedDirective(schema, exports.keyDirectiveName);
363
- }
364
- extendsDirective(schema) {
365
- return this.getTypedDirective(schema, exports.extendsDirectiveName);
366
- }
367
- externalDirective(schema) {
368
- return this.getTypedDirective(schema, exports.externalDirectiveName);
519
+ onUnknownDirectiveValidationError(schema, unknownDirectiveName, error) {
520
+ const metadata = federationMetadata(schema);
521
+ (0, utils_1.assert)(metadata, `This method should only have been called on a subgraph schema`);
522
+ if (federationSpec_1.ALL_FEDERATION_DIRECTIVES_DEFAULT_NAMES.includes(unknownDirectiveName)) {
523
+ if (metadata.isFed2Schema()) {
524
+ const federationFeature = metadata.federationFeature();
525
+ (0, utils_1.assert)(federationFeature, 'Fed2 subgraph _must_ link to the federation feature');
526
+ const directiveNameInSchema = federationFeature.directiveNameInSchema(unknownDirectiveName);
527
+ if (directiveNameInSchema.startsWith(federationFeature.nameInSchema + '__')) {
528
+ return (0, error_1.withModifiedErrorMessage)(error, `${error.message} If you meant the "@${unknownDirectiveName}" federation directive, you should use fully-qualified name "@${directiveNameInSchema}" or add "@${unknownDirectiveName}" to the \`import\` argument of the @link to the federation specification.`);
529
+ }
530
+ else {
531
+ return (0, error_1.withModifiedErrorMessage)(error, `${error.message} If you meant the "@${unknownDirectiveName}" federation directive, you should use "@${directiveNameInSchema}" as it is imported under that name in the @link to the federation specification of this schema.`);
532
+ }
533
+ }
534
+ else {
535
+ return (0, error_1.withModifiedErrorMessage)(error, `${error.message} If you meant the "@${unknownDirectiveName}" federation 2 directive, note that this schema is a federation 1 schema. To be a federation 2 schema, it needs to @link to the federation specifcation v2.`);
536
+ }
537
+ }
538
+ else if (!metadata.isFed2Schema()) {
539
+ const suggestions = (0, suggestions_1.suggestionList)(unknownDirectiveName, federationSpec_1.FEDERATION2_ONLY_SPEC_DIRECTIVES.map((spec) => spec.name));
540
+ if (suggestions.length > 0) {
541
+ return (0, error_1.withModifiedErrorMessage)(error, `${error.message}${(0, suggestions_1.didYouMean)(suggestions.map((s) => '@' + s))} If so, note that ${suggestions.length === 1 ? 'it is a federation 2 directive' : 'they are federation 2 directives'} but this schema is a federation 1 one. To be a federation 2 schema, it needs to @link to the federation specifcation v2.`);
542
+ }
543
+ }
544
+ return error;
369
545
  }
370
- requiresDirective(schema) {
371
- return this.getTypedDirective(schema, exports.requiresDirectiveName);
546
+ }
547
+ exports.FederationBlueprint = FederationBlueprint;
548
+ const federationBlueprint = new FederationBlueprint();
549
+ function findUnusedNamedForLinkDirective(schema) {
550
+ if (!schema.directive(linkSpec.url.name)) {
551
+ return undefined;
372
552
  }
373
- providesDirective(schema) {
374
- return this.getTypedDirective(schema, exports.providesDirectiveName);
553
+ const baseName = linkSpec.url.name;
554
+ let n = 1;
555
+ for (;;) {
556
+ const candidate = baseName + n;
557
+ if (!schema.directive(candidate)) {
558
+ return candidate;
559
+ }
375
560
  }
376
- tagDirective(schema) {
377
- return this.getTypedDirective(schema, exports.tagDirectiveName);
561
+ }
562
+ function setSchemaAsFed2Subgraph(schema) {
563
+ let core = schema.coreFeatures;
564
+ let spec;
565
+ if (core) {
566
+ spec = core.coreDefinition;
567
+ (0, utils_1.assert)(spec.url.version.satisfies(linkSpec.version), `Fed2 schema must use @link with version >= 1.0, but schema uses ${spec.url}`);
378
568
  }
379
- maybeUpdateSubgraphDocument(schema, document) {
380
- document = super.maybeUpdateSubgraphDocument(schema, document);
381
- const definitions = document.definitions.concat();
382
- for (const directiveName of FEDERATION_DIRECTIVES) {
383
- const directive = schema.directive(directiveName);
384
- (0, utils_1.assert)(directive, 'This method should only have been called on a schema with federation built-ins');
385
- if (directive.isBuiltIn) {
386
- definitions.push((0, graphql_1.parse)((0, print_1.printDirectiveDefinition)(directive, print_1.defaultPrintOptions)).definitions[0]);
387
- }
569
+ else {
570
+ const alias = findUnusedNamedForLinkDirective(schema);
571
+ const errors = linkSpec.addToSchema(schema, alias);
572
+ if (errors.length > 0) {
573
+ throw (0, definitions_1.ErrGraphQLValidationFailed)(errors);
388
574
  }
389
- return {
390
- kind: graphql_1.Kind.DOCUMENT,
391
- loc: document.loc,
392
- definitions
393
- };
575
+ spec = linkSpec;
576
+ core = schema.coreFeatures;
577
+ (0, utils_1.assert)(core, 'Schema should now be a core schema');
578
+ }
579
+ (0, utils_1.assert)(!core.getByIdentity(federationSpec.identity), 'Schema already set as a federation subgraph');
580
+ schema.schemaDefinition.applyDirective(core.coreItself.nameInSchema, {
581
+ url: federationSpec.url.toString(),
582
+ import: federationSpec_1.FEDERATION2_SPEC_DIRECTIVES.map((spec) => `@${spec.name}`),
583
+ });
584
+ const errors = completeSubgraphSchema(schema);
585
+ if (errors.length > 0) {
586
+ throw (0, definitions_1.ErrGraphQLValidationFailed)(errors);
394
587
  }
395
588
  }
396
- exports.FederationBuiltIns = FederationBuiltIns;
397
- exports.federationBuiltIns = new FederationBuiltIns();
398
- function isFederationSubgraphSchema(schema) {
399
- return schema.builtIns instanceof FederationBuiltIns;
589
+ exports.setSchemaAsFed2Subgraph = setSchemaAsFed2Subgraph;
590
+ exports.FEDERATION2_LINK_WTH_FULL_IMPORTS = '@link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@requires", "@provides", "@external", "@tag", "@extends", "@shareable", "@inaccessible", "@override"])';
591
+ function asFed2SubgraphDocument(document) {
592
+ const fed2LinkExtension = {
593
+ kind: graphql_1.Kind.SCHEMA_EXTENSION,
594
+ directives: [{
595
+ kind: graphql_1.Kind.DIRECTIVE,
596
+ name: { kind: graphql_1.Kind.NAME, value: coreSpec_1.linkDirectiveDefaultName },
597
+ arguments: [{
598
+ kind: graphql_1.Kind.ARGUMENT,
599
+ name: { kind: graphql_1.Kind.NAME, value: 'url' },
600
+ value: { kind: graphql_1.Kind.STRING, value: federationSpec.url.toString() }
601
+ },
602
+ {
603
+ kind: graphql_1.Kind.ARGUMENT,
604
+ name: { kind: graphql_1.Kind.NAME, value: 'import' },
605
+ value: { kind: graphql_1.Kind.LIST, values: federationSpec_1.FEDERATION2_SPEC_DIRECTIVES.map((spec) => ({ kind: graphql_1.Kind.STRING, value: `@${spec.name}` })) }
606
+ }]
607
+ }]
608
+ };
609
+ return {
610
+ kind: graphql_1.Kind.DOCUMENT,
611
+ loc: document.loc,
612
+ definitions: document.definitions.concat(fed2LinkExtension)
613
+ };
400
614
  }
401
- exports.isFederationSubgraphSchema = isFederationSubgraphSchema;
402
- function isFederationType(type) {
403
- return isFederationTypeName(type.name);
615
+ exports.asFed2SubgraphDocument = asFed2SubgraphDocument;
616
+ function printSubgraphNames(names) {
617
+ return (0, utils_1.printHumanReadableList)(names.map(n => `"${n}"`), {
618
+ prefix: 'subgraph',
619
+ prefixPlural: 'subgraphs',
620
+ });
621
+ }
622
+ exports.printSubgraphNames = printSubgraphNames;
623
+ function federationMetadata(schema) {
624
+ return schema['_federationMetadata'];
404
625
  }
405
- exports.isFederationType = isFederationType;
406
- function isFederationTypeName(typeName) {
407
- return FEDERATION_TYPES.includes(typeName);
626
+ exports.federationMetadata = federationMetadata;
627
+ function isFederationSubgraphSchema(schema) {
628
+ return !!federationMetadata(schema);
408
629
  }
409
- exports.isFederationTypeName = isFederationTypeName;
630
+ exports.isFederationSubgraphSchema = isFederationSubgraphSchema;
410
631
  function isFederationField(field) {
411
632
  var _a;
412
633
  if (field.parent === ((_a = field.schema().schemaDefinition.root("query")) === null || _a === void 0 ? void 0 : _a.type)) {
413
- return FEDERATION_ROOT_FIELDS.includes(field.name);
634
+ return exports.FEDERATION_OPERATION_FIELDS.includes(field.name);
414
635
  }
415
636
  return false;
416
637
  }
417
638
  exports.isFederationField = isFederationField;
418
- function isFederationDirective(directive) {
419
- return FEDERATION_DIRECTIVES.includes(directive.name);
420
- }
421
- exports.isFederationDirective = isFederationDirective;
422
639
  function isEntityType(type) {
423
- return type.kind == "ObjectType" && type.hasAppliedDirective(exports.keyDirectiveName);
640
+ if (type.kind !== "ObjectType") {
641
+ return false;
642
+ }
643
+ const metadata = federationMetadata(type.schema());
644
+ return !!metadata && type.hasAppliedDirective(metadata.keyDirective());
424
645
  }
425
646
  exports.isEntityType = isEntityType;
426
- function buildSubgraph(name, source) {
647
+ function buildSubgraph(name, url, source) {
648
+ const buildOptions = {
649
+ blueprint: federationBlueprint,
650
+ validate: false,
651
+ };
652
+ let subgraph;
427
653
  try {
428
- return typeof source === 'string'
429
- ? (0, buildSchema_1.buildSchema)(new graphql_1.Source(source, name), exports.federationBuiltIns)
430
- : (0, buildSchema_1.buildSchemaFromAST)(source, exports.federationBuiltIns);
654
+ const schema = typeof source === 'string'
655
+ ? (0, buildSchema_1.buildSchema)(new graphql_1.Source(source, name), buildOptions)
656
+ : (0, buildSchema_1.buildSchemaFromAST)(source, buildOptions);
657
+ subgraph = new Subgraph(name, url, schema);
431
658
  }
432
659
  catch (e) {
433
660
  if (e instanceof graphql_1.GraphQLError) {
@@ -437,14 +664,78 @@ function buildSubgraph(name, source) {
437
664
  throw e;
438
665
  }
439
666
  }
667
+ return subgraph.validate();
440
668
  }
441
669
  exports.buildSubgraph = buildSubgraph;
442
- function parseFieldSetArgument(parentType, directive, fieldAccessor = (type, name) => type.field(name)) {
670
+ function newEmptyFederation2Schema() {
671
+ const schema = new definitions_1.Schema(federationBlueprint);
672
+ setSchemaAsFed2Subgraph(schema);
673
+ return schema;
674
+ }
675
+ exports.newEmptyFederation2Schema = newEmptyFederation2Schema;
676
+ function completeSubgraphSchema(schema) {
677
+ const coreFeatures = schema.coreFeatures;
678
+ if (coreFeatures) {
679
+ const fedFeature = coreFeatures.getByIdentity(federationSpec_1.federationIdentity);
680
+ if (fedFeature) {
681
+ return completeFed2SubgraphSchema(schema);
682
+ }
683
+ else {
684
+ return completeFed1SubgraphSchema(schema);
685
+ }
686
+ }
687
+ else {
688
+ const fedLink = schema.schemaDefinition.appliedDirectivesOf(coreSpec_1.linkDirectiveDefaultName).find(isFedSpecLinkDirective);
689
+ if (fedLink) {
690
+ const errors = linkSpec.addToSchema(schema);
691
+ if (errors.length > 0) {
692
+ return errors;
693
+ }
694
+ return completeFed2SubgraphSchema(schema);
695
+ }
696
+ else {
697
+ return completeFed1SubgraphSchema(schema);
698
+ }
699
+ }
700
+ }
701
+ function isFedSpecLinkDirective(directive) {
702
+ const args = directive.arguments();
703
+ return directive.name === coreSpec_1.linkDirectiveDefaultName && args['url'] && args['url'].startsWith(federationSpec_1.federationIdentity);
704
+ }
705
+ function completeFed1SubgraphSchema(schema) {
706
+ return [
707
+ federationSpec_1.fieldSetTypeSpec.checkOrAdd(schema, '_' + federationSpec_1.fieldSetTypeSpec.name),
708
+ federationSpec_1.keyDirectiveSpec.checkOrAdd(schema),
709
+ federationSpec_1.requiresDirectiveSpec.checkOrAdd(schema),
710
+ federationSpec_1.providesDirectiveSpec.checkOrAdd(schema),
711
+ federationSpec_1.extendsDirectiveSpec.checkOrAdd(schema),
712
+ federationSpec_1.externalDirectiveSpec.checkOrAdd(schema),
713
+ tagSpec.tagDirectiveSpec.checkOrAdd(schema),
714
+ ].flat();
715
+ }
716
+ function completeFed2SubgraphSchema(schema) {
717
+ const coreFeatures = schema.coreFeatures;
718
+ (0, utils_1.assert)(coreFeatures, 'This method should not have been called on a non-core schema');
719
+ const fedFeature = coreFeatures.getByIdentity(federationSpec_1.federationIdentity);
720
+ (0, utils_1.assert)(fedFeature, 'This method should not have been called on a schema with no @link for federation');
721
+ const spec = federationSpec_1.FEDERATION_VERSIONS.find(fedFeature.url.version);
722
+ if (!spec) {
723
+ return [error_1.ERRORS.UNKNOWN_FEDERATION_LINK_VERSION.err({
724
+ message: `Invalid version ${fedFeature.url.version} for the federation feature in @link direction on schema`,
725
+ nodes: fedFeature.directive.sourceAST
726
+ })];
727
+ }
728
+ return spec.addElementsToSchema(schema);
729
+ }
730
+ function parseFieldSetArgument({ parentType, directive, fieldAccessor, validate, }) {
443
731
  var _a;
444
732
  try {
445
- const selectionSet = (0, operations_1.parseSelectionSet)(parentType, validateFieldSetValue(directive), new definitions_1.VariableDefinitions(), undefined, fieldAccessor);
446
- selectionSet.validate();
447
- return selectionSet;
733
+ return (0, operations_1.parseSelectionSet)({
734
+ parentType,
735
+ source: validateFieldSetValue(directive),
736
+ fieldAccessor,
737
+ validate,
738
+ });
448
739
  }
449
740
  catch (e) {
450
741
  if (!(e instanceof graphql_1.GraphQLError)) {
@@ -459,7 +750,7 @@ function parseFieldSetArgument(parentType, directive, fieldAccessor = (type, nam
459
750
  if (msg.endsWith('.')) {
460
751
  msg = msg.slice(0, msg.length - 1);
461
752
  }
462
- if (directive.name === exports.keyDirectiveName) {
753
+ if (directive.name === federationSpec_1.keyDirectiveSpec.name) {
463
754
  msg = msg + ' (the field should be either be added to this subgraph or, if it should not be resolved by this subgraph, you need to add it to this subgraph with @external).';
464
755
  }
465
756
  else {
@@ -475,6 +766,39 @@ function parseFieldSetArgument(parentType, directive, fieldAccessor = (type, nam
475
766
  }
476
767
  }
477
768
  exports.parseFieldSetArgument = parseFieldSetArgument;
769
+ function collectTargetFields({ parentType, directive, includeInterfaceFieldsImplementations, validate = true, }) {
770
+ const fields = [];
771
+ try {
772
+ parseFieldSetArgument({
773
+ parentType,
774
+ directive,
775
+ fieldAccessor: (t, f) => {
776
+ const field = t.field(f);
777
+ if (field) {
778
+ fields.push(field);
779
+ if (includeInterfaceFieldsImplementations && (0, definitions_1.isInterfaceType)(t)) {
780
+ for (const implType of t.possibleRuntimeTypes()) {
781
+ const implField = implType.field(f);
782
+ if (implField) {
783
+ fields.push(implField);
784
+ }
785
+ }
786
+ }
787
+ }
788
+ return field;
789
+ },
790
+ validate,
791
+ });
792
+ }
793
+ catch (e) {
794
+ const isGraphQLError = (0, definitions_1.errorCauses)(e) !== undefined;
795
+ if (!isGraphQLError || validate) {
796
+ throw e;
797
+ }
798
+ }
799
+ return fields;
800
+ }
801
+ exports.collectTargetFields = collectTargetFields;
478
802
  function validateFieldSetValue(directive) {
479
803
  var _a;
480
804
  const fields = directive.arguments().fields;
@@ -506,7 +830,7 @@ function subgraphsFromServiceList(serviceList) {
506
830
  const subgraphs = new Subgraphs();
507
831
  for (const service of serviceList) {
508
832
  try {
509
- subgraphs.add(service.name, (_a = service.url) !== null && _a !== void 0 ? _a : '', service.typeDefs);
833
+ subgraphs.add(buildSubgraph(service.name, (_a = service.url) !== null && _a !== void 0 ? _a : '', service.typeDefs));
510
834
  }
511
835
  catch (e) {
512
836
  const causes = (0, definitions_1.errorCauses)(e);
@@ -525,18 +849,12 @@ class Subgraphs {
525
849
  constructor() {
526
850
  this.subgraphs = new utils_1.OrderedMap();
527
851
  }
528
- add(subgraphOrName, url, schema) {
529
- const toAdd = typeof subgraphOrName === 'string'
530
- ? new Subgraph(subgraphOrName, url, schema instanceof definitions_1.Schema ? schema : buildSubgraph(subgraphOrName, schema))
531
- : subgraphOrName;
532
- if (toAdd.name === exports.FEDERATION_RESERVED_SUBGRAPH_NAME) {
533
- throw error_1.ERRORS.INVALID_SUBGRAPH_NAME.err({ message: `Invalid name ${exports.FEDERATION_RESERVED_SUBGRAPH_NAME} for a subgraph: this name is reserved` });
852
+ add(subgraph) {
853
+ if (this.subgraphs.has(subgraph.name)) {
854
+ throw new Error(`A subgraph named ${subgraph.name} already exists` + (subgraph.url ? ` (with url '${subgraph.url}')` : ''));
534
855
  }
535
- if (this.subgraphs.has(toAdd.name)) {
536
- throw new Error(`A subgraph named ${toAdd.name} already exists` + (toAdd.url ? ` (with url '${toAdd.url}')` : ''));
537
- }
538
- this.subgraphs.add(toAdd.name, toAdd);
539
- return toAdd;
856
+ this.subgraphs.add(subgraph.name, subgraph);
857
+ return subgraph;
540
858
  }
541
859
  get(name) {
542
860
  return this.subgraphs.get(name);
@@ -555,22 +873,123 @@ class Subgraphs {
555
873
  yield subgraph;
556
874
  }
557
875
  }
876
+ validate() {
877
+ let errors = [];
878
+ for (const subgraph of this.values()) {
879
+ try {
880
+ subgraph.validate();
881
+ }
882
+ catch (e) {
883
+ const causes = (0, definitions_1.errorCauses)(e);
884
+ if (!causes) {
885
+ throw e;
886
+ }
887
+ errors = errors.concat(causes);
888
+ }
889
+ }
890
+ return errors.length === 0 ? undefined : errors;
891
+ }
558
892
  toString() {
559
893
  return '[' + this.subgraphs.keys().join(', ') + ']';
560
894
  }
561
895
  }
562
896
  exports.Subgraphs = Subgraphs;
897
+ exports.anyTypeSpec = (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: '_Any' });
898
+ exports.serviceTypeSpec = (0, directiveAndTypeSpecification_1.createObjectTypeSpecification)({
899
+ name: '_Service',
900
+ fieldsFct: (schema) => [{ name: 'sdl', type: schema.stringType() }],
901
+ });
902
+ exports.entityTypeSpec = (0, directiveAndTypeSpecification_1.createUnionTypeSpecification)({
903
+ name: '_Entity',
904
+ membersFct: (schema) => {
905
+ return schema.objectTypes().filter(isEntityType).map((t) => t.name);
906
+ },
907
+ });
908
+ exports.FEDERATION_OPERATION_TYPES = [exports.anyTypeSpec, exports.serviceTypeSpec, exports.entityTypeSpec];
909
+ exports.serviceFieldName = '_service';
910
+ exports.entitiesFieldName = '_entities';
911
+ exports.FEDERATION_OPERATION_FIELDS = [exports.serviceFieldName, exports.entitiesFieldName];
563
912
  class Subgraph {
564
- constructor(name, url, schema, validateSchema = true) {
913
+ constructor(name, url, schema) {
565
914
  this.name = name;
566
915
  this.url = url;
567
916
  this.schema = schema;
568
- if (validateSchema) {
569
- schema.validate();
917
+ if (name === exports.FEDERATION_RESERVED_SUBGRAPH_NAME) {
918
+ throw error_1.ERRORS.INVALID_SUBGRAPH_NAME.err({ message: `Invalid name ${exports.FEDERATION_RESERVED_SUBGRAPH_NAME} for a subgraph: this name is reserved` });
570
919
  }
571
920
  }
572
- toString() {
573
- return `${this.name} (${this.url})`;
921
+ metadata() {
922
+ const metadata = federationMetadata(this.schema);
923
+ (0, utils_1.assert)(metadata, 'The subgraph schema should have built with the federation built-ins.');
924
+ return metadata;
925
+ }
926
+ isFed2Subgraph() {
927
+ return this.metadata().isFed2Schema();
928
+ }
929
+ addFederationOperations() {
930
+ const metadata = this.metadata();
931
+ for (const type of exports.FEDERATION_OPERATION_TYPES) {
932
+ type.checkOrAdd(this.schema);
933
+ }
934
+ const queryRoot = this.schema.schemaDefinition.root("query");
935
+ const queryType = queryRoot ? queryRoot.type : this.schema.addType(new definitions_1.ObjectType("Query"));
936
+ const entityField = queryType.field(exports.entitiesFieldName);
937
+ const entityType = metadata.entityType();
938
+ if (entityType) {
939
+ const entityFieldType = new definitions_1.NonNullType(new definitions_1.ListType(entityType));
940
+ if (!entityField) {
941
+ queryType.addField(exports.entitiesFieldName, entityFieldType)
942
+ .addArgument('representations', new definitions_1.NonNullType(new definitions_1.ListType(new definitions_1.NonNullType(metadata.anyType()))));
943
+ }
944
+ else if (!entityField.type) {
945
+ entityField.type = entityType;
946
+ }
947
+ }
948
+ else if (entityField) {
949
+ entityField.remove();
950
+ }
951
+ if (!queryType.field(exports.serviceFieldName)) {
952
+ queryType.addField(exports.serviceFieldName, metadata.serviceType());
953
+ }
954
+ }
955
+ validate() {
956
+ try {
957
+ this.addFederationOperations();
958
+ this.schema.validate();
959
+ return this;
960
+ }
961
+ catch (e) {
962
+ if (e instanceof graphql_1.GraphQLError) {
963
+ throw addSubgraphToError(e, this.name, error_1.ERRORS.INVALID_GRAPHQL);
964
+ }
965
+ else {
966
+ throw e;
967
+ }
968
+ }
969
+ }
970
+ isPrintedDirective(d) {
971
+ var _a;
972
+ if (this.metadata().allFederationDirectives().includes(d)) {
973
+ return false;
974
+ }
975
+ const core = this.schema.coreFeatures;
976
+ return !core || ((_a = core.sourceFeature(d)) === null || _a === void 0 ? void 0 : _a.url.identity) !== coreSpec_1.linkIdentity;
977
+ }
978
+ isPrintedType(t) {
979
+ var _a;
980
+ if (this.metadata().allFederationTypes().includes(t)) {
981
+ return false;
982
+ }
983
+ const core = this.schema.coreFeatures;
984
+ return !core || ((_a = core.sourceFeature(t)) === null || _a === void 0 ? void 0 : _a.url.identity) !== coreSpec_1.linkIdentity;
985
+ }
986
+ toString(basePrintOptions = print_1.defaultPrintOptions) {
987
+ return (0, print_1.printSchema)(this.schema, {
988
+ ...basePrintOptions,
989
+ directiveDefinitionFilter: (d) => this.isPrintedDirective(d),
990
+ typeFilter: (t) => this.isPrintedType(t),
991
+ fieldFilter: (f) => !isFederationField(f),
992
+ });
574
993
  }
575
994
  }
576
995
  exports.Subgraph = Subgraph;
@@ -596,48 +1015,61 @@ function addSubgraphToError(e, subgraphName, errorCode) {
596
1015
  source: cause.source,
597
1016
  positions: cause.positions,
598
1017
  path: cause.path,
599
- originalError: cause.originalError,
1018
+ originalError: cause,
600
1019
  extensions: cause.extensions,
601
1020
  });
602
1021
  }
603
1022
  else {
604
- return new graphql_1.GraphQLError(message, nodes, cause.source, cause.positions, cause.path, cause.originalError, cause.extensions);
1023
+ return new graphql_1.GraphQLError(message, nodes, cause.source, cause.positions, cause.path, cause, cause.extensions);
605
1024
  }
606
1025
  });
607
- return (0, definitions_1.ErrGraphQLValidationFailed)(updatedCauses);
1026
+ return updatedCauses.length === 1 ? updatedCauses[0] : (0, definitions_1.ErrGraphQLValidationFailed)(updatedCauses);
608
1027
  }
609
1028
  exports.addSubgraphToError = addSubgraphToError;
610
1029
  class ExternalTester {
611
1030
  constructor(schema) {
612
1031
  this.schema = schema;
613
1032
  this.fakeExternalFields = new Set();
1033
+ this.providedFields = new Set();
1034
+ this.externalDirective = this.metadata().externalDirective();
614
1035
  this.collectFakeExternals();
1036
+ this.collectProvidedFields();
1037
+ }
1038
+ metadata() {
1039
+ const metadata = federationMetadata(this.schema);
1040
+ (0, utils_1.assert)(metadata, 'Schema should be a subgraphs schema');
1041
+ return metadata;
615
1042
  }
616
1043
  collectFakeExternals() {
617
- const keyDirective = exports.federationBuiltIns.keyDirective(this.schema);
618
- if (!keyDirective) {
619
- return;
620
- }
621
- for (const key of keyDirective.applications()) {
622
- const parent = key.parent;
623
- if (!(key.ofExtension() || parent.hasAppliedDirective(exports.extendsDirectiveName))) {
1044
+ const metadata = this.metadata();
1045
+ const extendsDirective = metadata.extendsDirective();
1046
+ for (const key of metadata.keyDirective().applications()) {
1047
+ const parentType = key.parent;
1048
+ if (!(key.ofExtension() || parentType.hasAppliedDirective(extendsDirective))) {
624
1049
  continue;
625
1050
  }
626
- try {
627
- parseFieldSetArgument(parent, key, (parentType, fieldName) => {
628
- const field = parentType.field(fieldName);
629
- if (field && field.hasAppliedDirective(exports.externalDirectiveName)) {
630
- this.fakeExternalFields.add(field.coordinate);
631
- }
632
- return field;
633
- });
634
- }
635
- catch (e) {
636
- }
1051
+ collectTargetFields({
1052
+ parentType,
1053
+ directive: key,
1054
+ includeInterfaceFieldsImplementations: false,
1055
+ validate: false,
1056
+ }).filter((field) => field.hasAppliedDirective(this.externalDirective))
1057
+ .forEach((field) => this.fakeExternalFields.add(field.coordinate));
1058
+ }
1059
+ }
1060
+ collectProvidedFields() {
1061
+ for (const provides of this.metadata().providesDirective().applications()) {
1062
+ const parent = provides.parent;
1063
+ collectTargetFields({
1064
+ parentType: (0, definitions_1.baseType)(parent.type),
1065
+ directive: provides,
1066
+ includeInterfaceFieldsImplementations: true,
1067
+ validate: false,
1068
+ }).forEach((f) => this.providedFields.add(f.coordinate));
637
1069
  }
638
1070
  }
639
1071
  isExternal(field) {
640
- return field.hasAppliedDirective(exports.externalDirectiveName) && !this.isFakeExternal(field);
1072
+ return field.hasAppliedDirective(this.externalDirective) && !this.isFakeExternal(field);
641
1073
  }
642
1074
  isFakeExternal(field) {
643
1075
  return this.fakeExternalFields.has(field.coordinate);
@@ -655,6 +1087,102 @@ class ExternalTester {
655
1087
  }
656
1088
  return false;
657
1089
  }
1090
+ isPartiallyExternal(field) {
1091
+ return this.isExternal(field) && this.providedFields.has(field.coordinate);
1092
+ }
1093
+ isFullyExternal(field) {
1094
+ return this.isExternal(field) && !this.providedFields.has(field.coordinate);
1095
+ }
1096
+ }
1097
+ function removeInactiveProvidesAndRequires(schema, onModified = () => { }) {
1098
+ const metadata = federationMetadata(schema);
1099
+ if (!metadata) {
1100
+ return;
1101
+ }
1102
+ const providesDirective = metadata.providesDirective();
1103
+ const requiresDirective = metadata.requiresDirective();
1104
+ for (const type of schema.types()) {
1105
+ if (!(0, definitions_1.isObjectType)(type) && !(0, definitions_1.isInterfaceType)(type)) {
1106
+ continue;
1107
+ }
1108
+ for (const field of type.fields()) {
1109
+ const fieldBaseType = (0, definitions_1.baseType)(field.type);
1110
+ removeInactiveApplications(providesDirective, field, fieldBaseType, onModified);
1111
+ removeInactiveApplications(requiresDirective, field, type, onModified);
1112
+ }
1113
+ }
1114
+ }
1115
+ exports.removeInactiveProvidesAndRequires = removeInactiveProvidesAndRequires;
1116
+ function removeInactiveApplications(directiveDefinition, field, parentType, onModified) {
1117
+ for (const application of field.appliedDirectivesOf(directiveDefinition)) {
1118
+ let selection;
1119
+ try {
1120
+ selection = parseFieldSetArgument({ parentType, directive: application });
1121
+ }
1122
+ catch (e) {
1123
+ continue;
1124
+ }
1125
+ if (selectsNonExternalLeafField(selection)) {
1126
+ application.remove();
1127
+ const updated = withoutNonExternalLeafFields(selection);
1128
+ if (!updated.isEmpty()) {
1129
+ const updatedDirective = field.applyDirective(directiveDefinition, { fields: updated.toString(true, false) });
1130
+ onModified(field, application, updatedDirective);
1131
+ }
1132
+ else {
1133
+ onModified(field, application);
1134
+ }
1135
+ }
1136
+ }
1137
+ }
1138
+ function isExternalOrHasExternalImplementations(field) {
1139
+ const metadata = federationMetadata(field.schema());
1140
+ if (!metadata) {
1141
+ return false;
1142
+ }
1143
+ if (field.hasAppliedDirective(metadata.externalDirective())) {
1144
+ return true;
1145
+ }
1146
+ const parentType = field.parent;
1147
+ if ((0, definitions_1.isInterfaceType)(parentType)) {
1148
+ for (const implem of parentType.possibleRuntimeTypes()) {
1149
+ const fieldInImplem = implem.field(field.name);
1150
+ if (fieldInImplem && fieldInImplem.hasAppliedDirective(metadata.externalDirective())) {
1151
+ return true;
1152
+ }
1153
+ }
1154
+ }
1155
+ return false;
1156
+ }
1157
+ function selectsNonExternalLeafField(selection) {
1158
+ return selection.selections().some(s => {
1159
+ if (s.kind === 'FieldSelection') {
1160
+ if (isExternalOrHasExternalImplementations(s.field.definition)) {
1161
+ return false;
1162
+ }
1163
+ return !s.selectionSet || selectsNonExternalLeafField(s.selectionSet);
1164
+ }
1165
+ else {
1166
+ return selectsNonExternalLeafField(s.selectionSet);
1167
+ }
1168
+ });
1169
+ }
1170
+ function withoutNonExternalLeafFields(selectionSet) {
1171
+ const newSelectionSet = new operations_1.SelectionSet(selectionSet.parentType);
1172
+ for (const selection of selectionSet.selections()) {
1173
+ if (selection.kind === 'FieldSelection') {
1174
+ if (isExternalOrHasExternalImplementations(selection.field.definition)) {
1175
+ newSelectionSet.add(selection);
1176
+ continue;
1177
+ }
1178
+ }
1179
+ if (selection.selectionSet) {
1180
+ const updated = withoutNonExternalLeafFields(selection.selectionSet);
1181
+ if (!updated.isEmpty()) {
1182
+ newSelectionSet.add((0, operations_1.selectionOfElement)(selection.element(), updated));
1183
+ }
1184
+ }
1185
+ }
1186
+ return newSelectionSet;
658
1187
  }
659
- exports.ExternalTester = ExternalTester;
660
1188
  //# sourceMappingURL=federation.js.map