@apollo/federation-internals 2.0.0-alpha.6 → 2.0.0-preview.2
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.
- package/CHANGELOG.md +12 -0
- package/dist/buildSchema.d.ts +7 -3
- package/dist/buildSchema.d.ts.map +1 -1
- package/dist/buildSchema.js +41 -22
- package/dist/buildSchema.js.map +1 -1
- package/dist/coreSpec.d.ts +26 -4
- package/dist/coreSpec.d.ts.map +1 -1
- package/dist/coreSpec.js +86 -25
- package/dist/coreSpec.js.map +1 -1
- package/dist/definitions.d.ts +50 -43
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +201 -217
- package/dist/definitions.js.map +1 -1
- package/dist/directiveAndTypeSpecification.d.ts +38 -0
- package/dist/directiveAndTypeSpecification.d.ts.map +1 -0
- package/dist/directiveAndTypeSpecification.js +196 -0
- package/dist/directiveAndTypeSpecification.js.map +1 -0
- package/dist/error.d.ts +9 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +20 -2
- package/dist/error.js.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.js +28 -93
- package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
- package/dist/federation.d.ts +88 -46
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +706 -228
- package/dist/federation.js.map +1 -1
- package/dist/federationSpec.d.ts +19 -0
- package/dist/federationSpec.d.ts.map +1 -0
- package/dist/federationSpec.js +91 -0
- package/dist/federationSpec.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/index.js.map +1 -1
- package/dist/joinSpec.d.ts +1 -0
- package/dist/joinSpec.d.ts.map +1 -1
- package/dist/joinSpec.js +1 -0
- package/dist/joinSpec.js.map +1 -1
- package/dist/operations.d.ts +8 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +11 -4
- package/dist/operations.js.map +1 -1
- package/dist/print.d.ts +11 -9
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +21 -11
- package/dist/print.js.map +1 -1
- package/dist/schemaUpgrader.d.ts +108 -0
- package/dist/schemaUpgrader.d.ts.map +1 -0
- package/dist/schemaUpgrader.js +498 -0
- package/dist/schemaUpgrader.js.map +1 -0
- package/dist/sharing.d.ts +3 -0
- package/dist/sharing.d.ts.map +1 -0
- package/dist/sharing.js +51 -0
- package/dist/sharing.js.map +1 -0
- package/dist/supergraphs.d.ts.map +1 -1
- package/dist/supergraphs.js +2 -3
- package/dist/supergraphs.js.map +1 -1
- package/dist/tagSpec.d.ts.map +1 -1
- package/dist/tagSpec.js +1 -3
- package/dist/tagSpec.js.map +1 -1
- package/dist/utils.d.ts +7 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +34 -1
- package/dist/utils.js.map +1 -1
- package/dist/validate.d.ts.map +1 -1
- package/dist/validate.js +9 -4
- package/dist/validate.js.map +1 -1
- package/dist/validation/KnownTypeNamesInFederationRule.d.ts.map +1 -1
- package/dist/validation/KnownTypeNamesInFederationRule.js +1 -2
- package/dist/validation/KnownTypeNamesInFederationRule.js.map +1 -1
- package/dist/values.d.ts +1 -0
- package/dist/values.d.ts.map +1 -1
- package/dist/values.js +3 -2
- package/dist/values.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/definitions.test.ts +19 -17
- package/src/__tests__/federation.test.ts +31 -0
- package/src/__tests__/operations.test.ts +2 -3
- package/src/__tests__/schemaUpgrader.test.ts +168 -0
- package/src/__tests__/subgraphValidation.test.ts +5 -19
- package/src/__tests__/values.test.ts +2 -4
- package/src/buildSchema.ts +55 -36
- package/src/coreSpec.ts +112 -31
- package/src/definitions.ts +247 -260
- package/src/directiveAndTypeSpecification.ts +276 -0
- package/src/error.ts +55 -5
- package/src/extractSubgraphsFromSupergraph.ts +34 -118
- package/src/federation.ts +912 -295
- package/src/federationSpec.ts +113 -0
- package/src/index.ts +2 -0
- package/src/joinSpec.ts +2 -1
- package/src/operations.ts +22 -7
- package/src/print.ts +51 -38
- package/src/schemaUpgrader.ts +657 -0
- package/src/sharing.ts +68 -0
- package/src/supergraphs.ts +3 -3
- package/src/tagSpec.ts +1 -3
- package/src/utils.ts +63 -0
- package/src/validate.ts +13 -7
- package/src/validation/KnownTypeNamesInFederationRule.ts +1 -7
- package/src/values.ts +7 -3
- package/tsconfig.test.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/dist/federation.js
CHANGED
|
@@ -1,48 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
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.setSchemaAsFed2Subgraph = exports.FederationBlueprint = exports.FederationMetadata = exports.collectUsedExternalFieldsCoordinates = 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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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 sharing_1 = require("./sharing");
|
|
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 linkSpec = coreSpec_1.LINK_VERSIONS.latest();
|
|
26
19
|
const tagSpec = tagSpec_1.TAG_VERSIONS.latest();
|
|
20
|
+
const federationSpec = federationSpec_1.FEDERATION_VERSIONS.latest();
|
|
27
21
|
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
22
|
const FEDERATION_OMITTED_VALIDATION_RULES = [
|
|
47
23
|
graphql_1.PossibleTypeExtensionsRule,
|
|
48
24
|
graphql_1.KnownTypeNamesRule
|
|
@@ -51,14 +27,11 @@ const FEDERATION_SPECIFIC_VALIDATION_RULES = [
|
|
|
51
27
|
KnownTypeNamesInFederationRule_1.KnownTypeNamesInFederationRule
|
|
52
28
|
];
|
|
53
29
|
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,
|
|
30
|
+
function validateFieldSetSelections(directiveName, selectionSet, hasExternalInParents, federationMetadata, allowOnNonExternalLeafFields) {
|
|
55
31
|
for (const selection of selectionSet.selections()) {
|
|
56
32
|
if (selection.kind === 'FieldSelection') {
|
|
57
33
|
const field = selection.element().definition;
|
|
58
|
-
const isExternal =
|
|
59
|
-
if (isExternal) {
|
|
60
|
-
externalFieldCoordinatesCollector.push(field.coordinate);
|
|
61
|
-
}
|
|
34
|
+
const isExternal = federationMetadata.isFieldExternal(field);
|
|
62
35
|
if (field.hasArguments()) {
|
|
63
36
|
throw error_1.ERROR_CATEGORIES.FIELDS_HAS_ARGS.get(directiveName).err({
|
|
64
37
|
message: `field ${field.coordinate} cannot be included because it has arguments (fields with argument are not allowed in @${directiveName})`,
|
|
@@ -68,16 +41,16 @@ function validateFieldSetSelections(directiveName, selectionSet, hasExternalInPa
|
|
|
68
41
|
const mustBeExternal = !selection.selectionSet && !allowOnNonExternalLeafFields && !hasExternalInParents;
|
|
69
42
|
if (!isExternal && mustBeExternal) {
|
|
70
43
|
const errorCode = error_1.ERROR_CATEGORIES.DIRECTIVE_FIELDS_MISSING_EXTERNAL.get(directiveName);
|
|
71
|
-
if (
|
|
44
|
+
if (federationMetadata.isFieldFakeExternal(field)) {
|
|
72
45
|
throw errorCode.err({
|
|
73
46
|
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 @${
|
|
47
|
+
+ `(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
48
|
nodes: field.sourceAST
|
|
76
49
|
});
|
|
77
50
|
}
|
|
78
51
|
else {
|
|
79
52
|
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 @${
|
|
53
|
+
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
54
|
nodes: field.sourceAST
|
|
82
55
|
});
|
|
83
56
|
}
|
|
@@ -88,24 +61,24 @@ function validateFieldSetSelections(directiveName, selectionSet, hasExternalInPa
|
|
|
88
61
|
if (!newHasExternalInParents && (0, definitions_1.isInterfaceType)(parentType)) {
|
|
89
62
|
for (const implem of parentType.possibleRuntimeTypes()) {
|
|
90
63
|
const fieldInImplem = implem.field(field.name);
|
|
91
|
-
if (fieldInImplem &&
|
|
64
|
+
if (fieldInImplem && federationMetadata.isFieldExternal(fieldInImplem)) {
|
|
92
65
|
newHasExternalInParents = true;
|
|
93
66
|
break;
|
|
94
67
|
}
|
|
95
68
|
}
|
|
96
69
|
}
|
|
97
|
-
validateFieldSetSelections(directiveName, selection.selectionSet, newHasExternalInParents,
|
|
70
|
+
validateFieldSetSelections(directiveName, selection.selectionSet, newHasExternalInParents, federationMetadata, allowOnNonExternalLeafFields);
|
|
98
71
|
}
|
|
99
72
|
}
|
|
100
73
|
else {
|
|
101
|
-
validateFieldSetSelections(directiveName, selection.selectionSet, hasExternalInParents,
|
|
74
|
+
validateFieldSetSelections(directiveName, selection.selectionSet, hasExternalInParents, federationMetadata, allowOnNonExternalLeafFields);
|
|
102
75
|
}
|
|
103
76
|
}
|
|
104
77
|
}
|
|
105
|
-
function validateFieldSet(type, directive,
|
|
78
|
+
function validateFieldSet(type, directive, federationMetadata, allowOnNonExternalLeafFields, onFields) {
|
|
106
79
|
var _a;
|
|
107
80
|
try {
|
|
108
|
-
const
|
|
81
|
+
const fieldAccessor = onFields
|
|
109
82
|
? (type, fieldName) => {
|
|
110
83
|
const field = type.field(fieldName);
|
|
111
84
|
if (field) {
|
|
@@ -114,9 +87,9 @@ function validateFieldSet(type, directive, externalTester, externalFieldCoordina
|
|
|
114
87
|
return field;
|
|
115
88
|
}
|
|
116
89
|
: undefined;
|
|
117
|
-
const selectionSet = parseFieldSetArgument(type, directive,
|
|
90
|
+
const selectionSet = parseFieldSetArgument({ parentType: type, directive, fieldAccessor });
|
|
118
91
|
try {
|
|
119
|
-
validateFieldSetSelections(directive.name, selectionSet, false,
|
|
92
|
+
validateFieldSetSelections(directive.name, selectionSet, false, federationMetadata, allowOnNonExternalLeafFields);
|
|
120
93
|
return undefined;
|
|
121
94
|
}
|
|
122
95
|
catch (e) {
|
|
@@ -155,7 +128,7 @@ function fieldSetTargetDescription(directive) {
|
|
|
155
128
|
const targetKind = directive.parent instanceof definitions_1.FieldDefinition ? "field" : "type";
|
|
156
129
|
return `${targetKind} "${(_a = directive.parent) === null || _a === void 0 ? void 0 : _a.coordinate}"`;
|
|
157
130
|
}
|
|
158
|
-
function validateAllFieldSet(definition, targetTypeExtractor, errorCollector,
|
|
131
|
+
function validateAllFieldSet(definition, targetTypeExtractor, errorCollector, federationMetadata, isOnParentType, allowOnNonExternalLeafFields, onFields) {
|
|
159
132
|
for (const application of definition.applications()) {
|
|
160
133
|
const elt = application.parent;
|
|
161
134
|
const type = targetTypeExtractor(elt);
|
|
@@ -169,19 +142,57 @@ function validateAllFieldSet(definition, targetTypeExtractor, errorCollector, ex
|
|
|
169
142
|
nodes: (0, definitions_1.sourceASTs)(application).concat(isOnParentType ? [] : (0, definitions_1.sourceASTs)(type)),
|
|
170
143
|
}));
|
|
171
144
|
}
|
|
172
|
-
const error = validateFieldSet(type, application,
|
|
145
|
+
const error = validateFieldSet(type, application, federationMetadata, allowOnNonExternalLeafFields, onFields);
|
|
173
146
|
if (error) {
|
|
174
147
|
errorCollector.push(error);
|
|
175
148
|
}
|
|
176
149
|
}
|
|
177
150
|
}
|
|
178
|
-
function
|
|
179
|
-
|
|
151
|
+
function collectUsedExternalFieldsCoordinates(metadata) {
|
|
152
|
+
const usedExternalCoordinates = new Set();
|
|
153
|
+
collectUsedExternaFieldsForDirective(metadata, metadata.keyDirective(), type => type, usedExternalCoordinates);
|
|
154
|
+
collectUsedExternaFieldsForDirective(metadata, metadata.requiresDirective(), field => field.parent, usedExternalCoordinates);
|
|
155
|
+
collectUsedExternaFieldsForDirective(metadata, metadata.providesDirective(), field => {
|
|
156
|
+
const type = (0, definitions_1.baseType)(field.type);
|
|
157
|
+
return (0, definitions_1.isCompositeType)(type) ? type : undefined;
|
|
158
|
+
}, usedExternalCoordinates);
|
|
159
|
+
for (const itfType of metadata.schema.types('InterfaceType')) {
|
|
160
|
+
const runtimeTypes = itfType.possibleRuntimeTypes();
|
|
161
|
+
for (const field of itfType.fields()) {
|
|
162
|
+
for (const runtimeType of runtimeTypes) {
|
|
163
|
+
const implemField = runtimeType.field(field.name);
|
|
164
|
+
if (implemField && metadata.isFieldExternal(implemField)) {
|
|
165
|
+
usedExternalCoordinates.add(implemField.coordinate);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return usedExternalCoordinates;
|
|
171
|
+
}
|
|
172
|
+
exports.collectUsedExternalFieldsCoordinates = collectUsedExternalFieldsCoordinates;
|
|
173
|
+
function collectUsedExternaFieldsForDirective(metadata, definition, targetTypeExtractor, usedExternalCoordinates) {
|
|
174
|
+
for (const application of definition.applications()) {
|
|
175
|
+
const type = targetTypeExtractor(application.parent);
|
|
176
|
+
if (!type) {
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
collectTargetFields({
|
|
180
|
+
parentType: type,
|
|
181
|
+
directive: application,
|
|
182
|
+
includeInterfaceFieldsImplementations: true,
|
|
183
|
+
validate: false,
|
|
184
|
+
}).filter((field) => metadata.isFieldExternal(field))
|
|
185
|
+
.forEach((field) => usedExternalCoordinates.add(field.coordinate));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function validateAllExternalFieldsUsed(metadata, errorCollector) {
|
|
189
|
+
const allUsedExternals = collectUsedExternalFieldsCoordinates(metadata);
|
|
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 (!
|
|
195
|
+
if (!metadata.isFieldExternal(field) || allUsedExternals.has(field.coordinate)) {
|
|
185
196
|
continue;
|
|
186
197
|
}
|
|
187
198
|
if (!isFieldSatisfyingInterface(field)) {
|
|
@@ -194,10 +205,25 @@ function validateAllExternalFieldsUsed(schema, externalTester, allExternalFields
|
|
|
194
205
|
}
|
|
195
206
|
}
|
|
196
207
|
}
|
|
208
|
+
function validateNoExternalOnInterfaceFields(metadata, errorCollector) {
|
|
209
|
+
for (const itf of metadata.schema.types('InterfaceType')) {
|
|
210
|
+
for (const field of itf.fields()) {
|
|
211
|
+
if (metadata.isFieldExternal(field)) {
|
|
212
|
+
errorCollector.push(error_1.ERRORS.EXTERNAL_ON_INTERFACE.err({
|
|
213
|
+
message: `Interface type field "${field.coordinate}" is marked @external but @external is not allowed on interface fields (it is nonsensical).`,
|
|
214
|
+
nodes: field.sourceAST,
|
|
215
|
+
}));
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
197
220
|
function isFieldSatisfyingInterface(field) {
|
|
198
221
|
return field.parent.interfaces().some(itf => itf.field(field.name));
|
|
199
222
|
}
|
|
200
|
-
function validateInterfaceRuntimeImplementationFieldsTypes(itf,
|
|
223
|
+
function validateInterfaceRuntimeImplementationFieldsTypes(itf, metadata, errorCollector) {
|
|
224
|
+
var _a;
|
|
225
|
+
const requiresDirective = (_a = federationMetadata(itf.schema())) === null || _a === void 0 ? void 0 : _a.requiresDirective();
|
|
226
|
+
(0, utils_1.assert)(requiresDirective, 'Schema should be a federation subgraph, but @requires directive not found');
|
|
201
227
|
const runtimeTypes = itf.possibleRuntimeTypes();
|
|
202
228
|
for (const field of itf.fields()) {
|
|
203
229
|
const withExternalOrRequires = [];
|
|
@@ -210,7 +236,7 @@ function validateInterfaceRuntimeImplementationFieldsTypes(itf, externalTester,
|
|
|
210
236
|
if (implemField.sourceAST) {
|
|
211
237
|
nodes.push(implemField.sourceAST);
|
|
212
238
|
}
|
|
213
|
-
if (
|
|
239
|
+
if (metadata.isFieldExternal(implemField) || implemField.hasAppliedDirective(requiresDirective)) {
|
|
214
240
|
withExternalOrRequires.push(implemField);
|
|
215
241
|
}
|
|
216
242
|
const returnType = implemField.type;
|
|
@@ -229,77 +255,193 @@ const printFieldCoordinate = (f) => `"${f.coordinate}"`;
|
|
|
229
255
|
function formatFieldsToReturnType([type, implems]) {
|
|
230
256
|
return `${(0, utils_1.joinStrings)(implems.map(printFieldCoordinate))} ${implems.length == 1 ? 'has' : 'have'} type "${type}"`;
|
|
231
257
|
}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
this.
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
if (!
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
258
|
+
function checkIfFed2Schema(schema) {
|
|
259
|
+
const core = schema.coreFeatures;
|
|
260
|
+
if (!core) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
const federationFeature = core.getByIdentity(federationSpec.identity);
|
|
264
|
+
return !!federationFeature && federationFeature.url.version.satisfies(new coreSpec_1.FeatureVersion(2, 0));
|
|
265
|
+
}
|
|
266
|
+
class FederationMetadata {
|
|
267
|
+
constructor(schema) {
|
|
268
|
+
this.schema = schema;
|
|
269
|
+
}
|
|
270
|
+
onInvalidate() {
|
|
271
|
+
this._externalTester = undefined;
|
|
272
|
+
this._sharingPredicate = undefined;
|
|
273
|
+
this._isFed2Schema = undefined;
|
|
274
|
+
}
|
|
275
|
+
isFed2Schema() {
|
|
276
|
+
if (!this._isFed2Schema) {
|
|
277
|
+
this._isFed2Schema = checkIfFed2Schema(this.schema);
|
|
278
|
+
}
|
|
279
|
+
return this._isFed2Schema;
|
|
280
|
+
}
|
|
281
|
+
externalTester() {
|
|
282
|
+
if (!this._externalTester) {
|
|
283
|
+
this._externalTester = new ExternalTester(this.schema);
|
|
284
|
+
}
|
|
285
|
+
return this._externalTester;
|
|
286
|
+
}
|
|
287
|
+
sharingPredicate() {
|
|
288
|
+
if (!this._sharingPredicate) {
|
|
289
|
+
this._sharingPredicate = (0, sharing_1.computeShareables)(this.schema);
|
|
290
|
+
}
|
|
291
|
+
return this._sharingPredicate;
|
|
292
|
+
}
|
|
293
|
+
isFieldExternal(field) {
|
|
294
|
+
return this.externalTester().isExternal(field);
|
|
295
|
+
}
|
|
296
|
+
isFieldPartiallyExternal(field) {
|
|
297
|
+
return this.externalTester().isPartiallyExternal(field);
|
|
298
|
+
}
|
|
299
|
+
isFieldFullyExternal(field) {
|
|
300
|
+
return this.externalTester().isFullyExternal(field);
|
|
301
|
+
}
|
|
302
|
+
isFieldFakeExternal(field) {
|
|
303
|
+
return this.externalTester().isFakeExternal(field);
|
|
304
|
+
}
|
|
305
|
+
selectionSelectsAnyExternalField(selectionSet) {
|
|
306
|
+
return this.externalTester().selectsAnyExternalField(selectionSet);
|
|
307
|
+
}
|
|
308
|
+
isFieldShareable(field) {
|
|
309
|
+
return this.sharingPredicate()(field);
|
|
310
|
+
}
|
|
311
|
+
federationDirectiveNameInSchema(name) {
|
|
312
|
+
if (this.isFed2Schema()) {
|
|
313
|
+
const coreFeatures = this.schema.coreFeatures;
|
|
314
|
+
(0, utils_1.assert)(coreFeatures, 'Schema should be a core schema');
|
|
315
|
+
const federationFeature = coreFeatures.getByIdentity(federationSpec.identity);
|
|
316
|
+
(0, utils_1.assert)(federationFeature, 'Schema should have the federation feature');
|
|
317
|
+
return federationFeature.directiveNameInSchema(name);
|
|
318
|
+
}
|
|
319
|
+
else {
|
|
320
|
+
return name;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
federationTypeNameInSchema(name) {
|
|
324
|
+
if (name.charAt(0) === '_') {
|
|
325
|
+
return name;
|
|
326
|
+
}
|
|
327
|
+
if (this.isFed2Schema()) {
|
|
328
|
+
const coreFeatures = this.schema.coreFeatures;
|
|
329
|
+
(0, utils_1.assert)(coreFeatures, 'Schema should be a core schema');
|
|
330
|
+
const federationFeature = coreFeatures.getByIdentity(federationSpec.identity);
|
|
331
|
+
(0, utils_1.assert)(federationFeature, 'Schema should have the federation feature');
|
|
332
|
+
return federationFeature.typeNameInSchema(name);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
return '_' + name;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
getFederationDirective(name) {
|
|
339
|
+
const directive = this.schema.directive(this.federationDirectiveNameInSchema(name));
|
|
340
|
+
(0, utils_1.assert)(directive, `The provided schema does not have federation directive @${name}`);
|
|
341
|
+
return directive;
|
|
342
|
+
}
|
|
343
|
+
keyDirective() {
|
|
344
|
+
return this.getFederationDirective(federationSpec_1.keyDirectiveSpec.name);
|
|
345
|
+
}
|
|
346
|
+
extendsDirective() {
|
|
347
|
+
return this.getFederationDirective(federationSpec_1.extendsDirectiveSpec.name);
|
|
348
|
+
}
|
|
349
|
+
externalDirective() {
|
|
350
|
+
return this.getFederationDirective(federationSpec_1.externalDirectiveSpec.name);
|
|
351
|
+
}
|
|
352
|
+
requiresDirective() {
|
|
353
|
+
return this.getFederationDirective(federationSpec_1.requiresDirectiveSpec.name);
|
|
354
|
+
}
|
|
355
|
+
providesDirective() {
|
|
356
|
+
return this.getFederationDirective(federationSpec_1.providesDirectiveSpec.name);
|
|
357
|
+
}
|
|
358
|
+
shareableDirective() {
|
|
359
|
+
return this.getFederationDirective(federationSpec_1.shareableDirectiveSpec.name);
|
|
360
|
+
}
|
|
361
|
+
tagDirective() {
|
|
362
|
+
return this.getFederationDirective(federationSpec_1.tagDirectiveSpec.name);
|
|
363
|
+
}
|
|
364
|
+
allFederationDirectives() {
|
|
365
|
+
const baseDirectives = [
|
|
366
|
+
this.keyDirective(),
|
|
367
|
+
this.externalDirective(),
|
|
368
|
+
this.requiresDirective(),
|
|
369
|
+
this.providesDirective(),
|
|
370
|
+
this.tagDirective(),
|
|
371
|
+
this.extendsDirective(),
|
|
372
|
+
];
|
|
373
|
+
return this.isFed2Schema()
|
|
374
|
+
? baseDirectives.concat(this.shareableDirective())
|
|
375
|
+
: baseDirectives;
|
|
376
|
+
}
|
|
377
|
+
entityType() {
|
|
378
|
+
return this.schema.type(this.federationTypeNameInSchema(exports.entityTypeSpec.name));
|
|
379
|
+
}
|
|
380
|
+
anyType() {
|
|
381
|
+
return this.schema.type(this.federationTypeNameInSchema(exports.anyTypeSpec.name));
|
|
382
|
+
}
|
|
383
|
+
serviceType() {
|
|
384
|
+
return this.schema.type(this.federationTypeNameInSchema(exports.serviceTypeSpec.name));
|
|
385
|
+
}
|
|
386
|
+
fieldSetType() {
|
|
387
|
+
return this.schema.type(this.federationTypeNameInSchema(federationSpec_1.fieldSetTypeSpec.name));
|
|
388
|
+
}
|
|
389
|
+
allFederationTypes() {
|
|
390
|
+
const baseTypes = [
|
|
391
|
+
this.anyType(),
|
|
392
|
+
this.serviceType(),
|
|
393
|
+
this.fieldSetType(),
|
|
394
|
+
];
|
|
395
|
+
const entityType = this.entityType();
|
|
396
|
+
if (entityType) {
|
|
397
|
+
baseTypes.push(entityType);
|
|
398
|
+
}
|
|
399
|
+
return baseTypes;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
exports.FederationMetadata = FederationMetadata;
|
|
403
|
+
class FederationBlueprint extends definitions_1.SchemaBlueprint {
|
|
404
|
+
onAddedCoreFeature(schema, feature) {
|
|
405
|
+
super.onAddedCoreFeature(schema, feature);
|
|
406
|
+
if (feature.url.identity === federationSpec_1.federationIdentity) {
|
|
407
|
+
const spec = federationSpec_1.FEDERATION_VERSIONS.find(feature.url.version);
|
|
408
|
+
if (spec) {
|
|
409
|
+
spec.addElementsToSchema(schema);
|
|
291
410
|
}
|
|
292
411
|
}
|
|
293
|
-
|
|
294
|
-
|
|
412
|
+
}
|
|
413
|
+
onMissingDirectiveDefinition(schema, name) {
|
|
414
|
+
if (name === coreSpec_1.linkDirectiveDefaultName) {
|
|
415
|
+
linkSpec.addToSchema(schema);
|
|
416
|
+
return schema.directive(name);
|
|
295
417
|
}
|
|
296
|
-
|
|
297
|
-
|
|
418
|
+
return super.onMissingDirectiveDefinition(schema, name);
|
|
419
|
+
}
|
|
420
|
+
ignoreParsedField(type, fieldName) {
|
|
421
|
+
if (!exports.FEDERATION_OPERATION_FIELDS.includes(fieldName)) {
|
|
422
|
+
return false;
|
|
423
|
+
}
|
|
424
|
+
const metadata = federationMetadata(type.schema());
|
|
425
|
+
return !!metadata && !metadata.isFed2Schema();
|
|
426
|
+
}
|
|
427
|
+
onConstructed(schema) {
|
|
428
|
+
const existing = federationMetadata(schema);
|
|
429
|
+
if (!existing) {
|
|
430
|
+
schema['_federationMetadata'] = new FederationMetadata(schema);
|
|
298
431
|
}
|
|
299
432
|
}
|
|
433
|
+
onDirectiveDefinitionAndSchemaParsed(schema) {
|
|
434
|
+
completeSubgraphSchema(schema);
|
|
435
|
+
}
|
|
436
|
+
onInvalidation(schema) {
|
|
437
|
+
super.onInvalidation(schema);
|
|
438
|
+
const metadata = federationMetadata(schema);
|
|
439
|
+
(0, utils_1.assert)(metadata, 'Federation schema should have had its metadata set on construction');
|
|
440
|
+
FederationMetadata.prototype['onInvalidate'].call(metadata);
|
|
441
|
+
}
|
|
300
442
|
onValidation(schema) {
|
|
301
443
|
var _a;
|
|
302
|
-
const errors = super.onValidation(schema
|
|
444
|
+
const errors = super.onValidation(schema);
|
|
303
445
|
for (const k of definitions_1.allSchemaRootKinds) {
|
|
304
446
|
const type = (_a = schema.schemaDefinition.root(k)) === null || _a === void 0 ? void 0 : _a.type;
|
|
305
447
|
const defaultName = (0, definitions_1.defaultRootName)(k);
|
|
@@ -316,21 +458,25 @@ class FederationBuiltIns extends definitions_1.BuiltIns {
|
|
|
316
458
|
type.rename(defaultName);
|
|
317
459
|
}
|
|
318
460
|
}
|
|
319
|
-
const
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
461
|
+
const metadata = federationMetadata(schema);
|
|
462
|
+
(0, utils_1.assert)(metadata, 'Federation schema should have had its metadata set on construction');
|
|
463
|
+
if (!metadata.isFed2Schema()) {
|
|
464
|
+
return errors;
|
|
465
|
+
}
|
|
466
|
+
const keyDirective = metadata.keyDirective();
|
|
467
|
+
validateAllFieldSet(keyDirective, type => type, errors, metadata, true, true, field => {
|
|
468
|
+
const type = (0, definitions_1.baseType)(field.type);
|
|
469
|
+
if ((0, definitions_1.isUnionType)(type) || (0, definitions_1.isInterfaceType)(type)) {
|
|
470
|
+
let kind = type.kind;
|
|
325
471
|
kind = kind.slice(0, kind.length - 'Type'.length);
|
|
326
472
|
throw error_1.ERRORS.KEY_FIELDS_SELECT_INVALID_TYPE.err({
|
|
327
473
|
message: `field "${field.coordinate}" is a ${kind} type which is not allowed in @key`
|
|
328
474
|
});
|
|
329
475
|
}
|
|
330
476
|
});
|
|
331
|
-
validateAllFieldSet(
|
|
332
|
-
validateAllFieldSet(
|
|
333
|
-
if (
|
|
477
|
+
validateAllFieldSet(metadata.requiresDirective(), field => field.parent, errors, metadata, false, false);
|
|
478
|
+
validateAllFieldSet(metadata.providesDirective(), field => {
|
|
479
|
+
if (metadata.isFieldExternal(field)) {
|
|
334
480
|
throw new graphql_1.GraphQLError(`Cannot have both @provides and @external on field "${field.coordinate}"`, field.sourceAST);
|
|
335
481
|
}
|
|
336
482
|
const type = (0, definitions_1.baseType)(field.type);
|
|
@@ -341,93 +487,129 @@ class FederationBuiltIns extends definitions_1.BuiltIns {
|
|
|
341
487
|
});
|
|
342
488
|
}
|
|
343
489
|
return type;
|
|
344
|
-
}, errors,
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
490
|
+
}, errors, metadata, false, false);
|
|
491
|
+
validateNoExternalOnInterfaceFields(metadata, errors);
|
|
492
|
+
validateAllExternalFieldsUsed(metadata, errors);
|
|
493
|
+
const tagDirective = metadata.tagDirective();
|
|
494
|
+
if (tagDirective) {
|
|
348
495
|
const error = tagSpec.checkCompatibleDirective(tagDirective);
|
|
349
496
|
if (error) {
|
|
350
497
|
errors.push(error);
|
|
351
498
|
}
|
|
352
499
|
}
|
|
353
500
|
for (const itf of schema.types('InterfaceType')) {
|
|
354
|
-
validateInterfaceRuntimeImplementationFieldsTypes(itf,
|
|
501
|
+
validateInterfaceRuntimeImplementationFieldsTypes(itf, metadata, errors);
|
|
355
502
|
}
|
|
356
503
|
return errors;
|
|
357
504
|
}
|
|
358
505
|
validationRules() {
|
|
359
506
|
return FEDERATION_VALIDATION_RULES;
|
|
360
507
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
externalDirective(schema) {
|
|
368
|
-
return this.getTypedDirective(schema, exports.externalDirectiveName);
|
|
369
|
-
}
|
|
370
|
-
requiresDirective(schema) {
|
|
371
|
-
return this.getTypedDirective(schema, exports.requiresDirectiveName);
|
|
508
|
+
}
|
|
509
|
+
exports.FederationBlueprint = FederationBlueprint;
|
|
510
|
+
const federationBlueprint = new FederationBlueprint();
|
|
511
|
+
function findUnusedNamedForLinkDirective(schema) {
|
|
512
|
+
if (!schema.directive(linkSpec.url.name)) {
|
|
513
|
+
return undefined;
|
|
372
514
|
}
|
|
373
|
-
|
|
374
|
-
|
|
515
|
+
const baseName = linkSpec.url.name;
|
|
516
|
+
let n = 1;
|
|
517
|
+
for (;;) {
|
|
518
|
+
const candidate = baseName + n;
|
|
519
|
+
if (!schema.directive(candidate)) {
|
|
520
|
+
return candidate;
|
|
521
|
+
}
|
|
375
522
|
}
|
|
376
|
-
|
|
377
|
-
|
|
523
|
+
}
|
|
524
|
+
function setSchemaAsFed2Subgraph(schema) {
|
|
525
|
+
let core = schema.coreFeatures;
|
|
526
|
+
let spec;
|
|
527
|
+
if (core) {
|
|
528
|
+
spec = core.coreDefinition;
|
|
529
|
+
(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
530
|
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
if (directive.isBuiltIn) {
|
|
386
|
-
definitions.push((0, graphql_1.parse)((0, print_1.printDirectiveDefinition)(directive, print_1.defaultPrintOptions)).definitions[0]);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
return {
|
|
390
|
-
kind: graphql_1.Kind.DOCUMENT,
|
|
391
|
-
loc: document.loc,
|
|
392
|
-
definitions
|
|
393
|
-
};
|
|
531
|
+
else {
|
|
532
|
+
const alias = findUnusedNamedForLinkDirective(schema);
|
|
533
|
+
linkSpec.addToSchema(schema, alias);
|
|
534
|
+
spec = linkSpec;
|
|
535
|
+
core = schema.coreFeatures;
|
|
536
|
+
(0, utils_1.assert)(core, 'Schema should now be a core schema');
|
|
394
537
|
}
|
|
538
|
+
(0, utils_1.assert)(!core.getByIdentity(federationSpec.identity), 'Schema already set as a federation subgraph');
|
|
539
|
+
schema.schemaDefinition.applyDirective(core.coreItself.nameInSchema, {
|
|
540
|
+
url: federationSpec.url.toString(),
|
|
541
|
+
import: federationSpec_1.FEDERATION2_SPEC_DIRECTIVES.map((spec) => `@${spec.name}`),
|
|
542
|
+
});
|
|
543
|
+
completeSubgraphSchema(schema);
|
|
395
544
|
}
|
|
396
|
-
exports.
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
545
|
+
exports.setSchemaAsFed2Subgraph = setSchemaAsFed2Subgraph;
|
|
546
|
+
function asFed2SubgraphDocument(document) {
|
|
547
|
+
const fed2LinkExtension = {
|
|
548
|
+
kind: graphql_1.Kind.SCHEMA_EXTENSION,
|
|
549
|
+
directives: [{
|
|
550
|
+
kind: graphql_1.Kind.DIRECTIVE,
|
|
551
|
+
name: { kind: graphql_1.Kind.NAME, value: coreSpec_1.linkDirectiveDefaultName },
|
|
552
|
+
arguments: [{
|
|
553
|
+
kind: graphql_1.Kind.ARGUMENT,
|
|
554
|
+
name: { kind: graphql_1.Kind.NAME, value: 'url' },
|
|
555
|
+
value: { kind: graphql_1.Kind.STRING, value: federationSpec.url.toString() }
|
|
556
|
+
},
|
|
557
|
+
{
|
|
558
|
+
kind: graphql_1.Kind.ARGUMENT,
|
|
559
|
+
name: { kind: graphql_1.Kind.NAME, value: 'import' },
|
|
560
|
+
value: { kind: graphql_1.Kind.LIST, values: federationSpec_1.FEDERATION2_SPEC_DIRECTIVES.map((spec) => ({ kind: graphql_1.Kind.STRING, value: `@${spec.name}` })) }
|
|
561
|
+
}]
|
|
562
|
+
}]
|
|
563
|
+
};
|
|
564
|
+
return {
|
|
565
|
+
kind: graphql_1.Kind.DOCUMENT,
|
|
566
|
+
loc: document.loc,
|
|
567
|
+
definitions: document.definitions.concat(fed2LinkExtension)
|
|
568
|
+
};
|
|
400
569
|
}
|
|
401
|
-
exports.
|
|
402
|
-
function
|
|
403
|
-
return
|
|
570
|
+
exports.asFed2SubgraphDocument = asFed2SubgraphDocument;
|
|
571
|
+
function printSubgraphNames(names) {
|
|
572
|
+
return (0, utils_1.printHumanReadableList)(names.map(n => `"${n}"`), {
|
|
573
|
+
prefix: 'subgraph',
|
|
574
|
+
prefixPlural: 'subgraphs',
|
|
575
|
+
});
|
|
404
576
|
}
|
|
405
|
-
exports.
|
|
406
|
-
function
|
|
407
|
-
return
|
|
577
|
+
exports.printSubgraphNames = printSubgraphNames;
|
|
578
|
+
function federationMetadata(schema) {
|
|
579
|
+
return schema['_federationMetadata'];
|
|
408
580
|
}
|
|
409
|
-
exports.
|
|
581
|
+
exports.federationMetadata = federationMetadata;
|
|
582
|
+
function isFederationSubgraphSchema(schema) {
|
|
583
|
+
return !!federationMetadata(schema);
|
|
584
|
+
}
|
|
585
|
+
exports.isFederationSubgraphSchema = isFederationSubgraphSchema;
|
|
410
586
|
function isFederationField(field) {
|
|
411
587
|
var _a;
|
|
412
588
|
if (field.parent === ((_a = field.schema().schemaDefinition.root("query")) === null || _a === void 0 ? void 0 : _a.type)) {
|
|
413
|
-
return
|
|
589
|
+
return exports.FEDERATION_OPERATION_FIELDS.includes(field.name);
|
|
414
590
|
}
|
|
415
591
|
return false;
|
|
416
592
|
}
|
|
417
593
|
exports.isFederationField = isFederationField;
|
|
418
|
-
function isFederationDirective(directive) {
|
|
419
|
-
return FEDERATION_DIRECTIVES.includes(directive.name);
|
|
420
|
-
}
|
|
421
|
-
exports.isFederationDirective = isFederationDirective;
|
|
422
594
|
function isEntityType(type) {
|
|
423
|
-
|
|
595
|
+
if (type.kind !== "ObjectType") {
|
|
596
|
+
return false;
|
|
597
|
+
}
|
|
598
|
+
const metadata = federationMetadata(type.schema());
|
|
599
|
+
return !!metadata && type.hasAppliedDirective(metadata.keyDirective());
|
|
424
600
|
}
|
|
425
601
|
exports.isEntityType = isEntityType;
|
|
426
|
-
function buildSubgraph(name, source) {
|
|
602
|
+
function buildSubgraph(name, url, source) {
|
|
603
|
+
const buildOptions = {
|
|
604
|
+
blueprint: federationBlueprint,
|
|
605
|
+
validate: false,
|
|
606
|
+
};
|
|
607
|
+
let subgraph;
|
|
427
608
|
try {
|
|
428
|
-
|
|
429
|
-
? (0, buildSchema_1.buildSchema)(new graphql_1.Source(source, name),
|
|
430
|
-
: (0, buildSchema_1.buildSchemaFromAST)(source,
|
|
609
|
+
const schema = typeof source === 'string'
|
|
610
|
+
? (0, buildSchema_1.buildSchema)(new graphql_1.Source(source, name), buildOptions)
|
|
611
|
+
: (0, buildSchema_1.buildSchemaFromAST)(source, buildOptions);
|
|
612
|
+
subgraph = new Subgraph(name, url, schema);
|
|
431
613
|
}
|
|
432
614
|
catch (e) {
|
|
433
615
|
if (e instanceof graphql_1.GraphQLError) {
|
|
@@ -437,14 +619,73 @@ function buildSubgraph(name, source) {
|
|
|
437
619
|
throw e;
|
|
438
620
|
}
|
|
439
621
|
}
|
|
622
|
+
return subgraph.validate();
|
|
440
623
|
}
|
|
441
624
|
exports.buildSubgraph = buildSubgraph;
|
|
442
|
-
function
|
|
625
|
+
function newEmptyFederation2Schema() {
|
|
626
|
+
const schema = new definitions_1.Schema(federationBlueprint);
|
|
627
|
+
setSchemaAsFed2Subgraph(schema);
|
|
628
|
+
return schema;
|
|
629
|
+
}
|
|
630
|
+
exports.newEmptyFederation2Schema = newEmptyFederation2Schema;
|
|
631
|
+
function completeSubgraphSchema(schema) {
|
|
632
|
+
const coreFeatures = schema.coreFeatures;
|
|
633
|
+
if (coreFeatures) {
|
|
634
|
+
const fedFeature = coreFeatures.getByIdentity(federationSpec_1.federationIdentity);
|
|
635
|
+
if (fedFeature) {
|
|
636
|
+
completeFed2SubgraphSchema(schema);
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
completeFed1SubgraphSchema(schema);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
else {
|
|
643
|
+
const fedLink = schema.schemaDefinition.appliedDirectivesOf(coreSpec_1.linkDirectiveDefaultName).find(isFedSpecLinkDirective);
|
|
644
|
+
if (fedLink) {
|
|
645
|
+
linkSpec.addToSchema(schema);
|
|
646
|
+
completeFed2SubgraphSchema(schema);
|
|
647
|
+
}
|
|
648
|
+
else {
|
|
649
|
+
completeFed1SubgraphSchema(schema);
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
function isFedSpecLinkDirective(directive) {
|
|
654
|
+
const args = directive.arguments();
|
|
655
|
+
return directive.name === coreSpec_1.linkDirectiveDefaultName && args['url'] && args['url'].startsWith(federationSpec_1.federationIdentity);
|
|
656
|
+
}
|
|
657
|
+
function completeFed1SubgraphSchema(schema) {
|
|
658
|
+
federationSpec_1.fieldSetTypeSpec.checkOrAdd(schema, '_' + federationSpec_1.fieldSetTypeSpec.name);
|
|
659
|
+
federationSpec_1.keyDirectiveSpec.checkOrAdd(schema);
|
|
660
|
+
federationSpec_1.requiresDirectiveSpec.checkOrAdd(schema);
|
|
661
|
+
federationSpec_1.providesDirectiveSpec.checkOrAdd(schema);
|
|
662
|
+
federationSpec_1.extendsDirectiveSpec.checkOrAdd(schema);
|
|
663
|
+
federationSpec_1.externalDirectiveSpec.checkOrAdd(schema);
|
|
664
|
+
federationSpec_1.tagDirectiveSpec.checkOrAdd(schema);
|
|
665
|
+
}
|
|
666
|
+
function completeFed2SubgraphSchema(schema) {
|
|
667
|
+
const coreFeatures = schema.coreFeatures;
|
|
668
|
+
(0, utils_1.assert)(coreFeatures, 'This method should not have been called on a non-core schema');
|
|
669
|
+
const fedFeature = coreFeatures.getByIdentity(federationSpec_1.federationIdentity);
|
|
670
|
+
(0, utils_1.assert)(fedFeature, 'This method should not have been called on a schema with no @link for federation');
|
|
671
|
+
const spec = federationSpec_1.FEDERATION_VERSIONS.find(fedFeature.url.version);
|
|
672
|
+
if (!spec) {
|
|
673
|
+
throw error_1.ERRORS.UNKNOWN_FEDERATION_LINK_VERSION.err({
|
|
674
|
+
message: `Invalid version ${fedFeature.url.version} for the federation feature in @link direction on schema`,
|
|
675
|
+
nodes: fedFeature.directive.sourceAST
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
spec.addElementsToSchema(schema);
|
|
679
|
+
}
|
|
680
|
+
function parseFieldSetArgument({ parentType, directive, fieldAccessor, validate, }) {
|
|
443
681
|
var _a;
|
|
444
682
|
try {
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
683
|
+
return (0, operations_1.parseSelectionSet)({
|
|
684
|
+
parentType,
|
|
685
|
+
source: validateFieldSetValue(directive),
|
|
686
|
+
fieldAccessor,
|
|
687
|
+
validate,
|
|
688
|
+
});
|
|
448
689
|
}
|
|
449
690
|
catch (e) {
|
|
450
691
|
if (!(e instanceof graphql_1.GraphQLError)) {
|
|
@@ -459,7 +700,7 @@ function parseFieldSetArgument(parentType, directive, fieldAccessor = (type, nam
|
|
|
459
700
|
if (msg.endsWith('.')) {
|
|
460
701
|
msg = msg.slice(0, msg.length - 1);
|
|
461
702
|
}
|
|
462
|
-
if (directive.name ===
|
|
703
|
+
if (directive.name === federationSpec_1.keyDirectiveSpec.name) {
|
|
463
704
|
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
705
|
}
|
|
465
706
|
else {
|
|
@@ -475,6 +716,39 @@ function parseFieldSetArgument(parentType, directive, fieldAccessor = (type, nam
|
|
|
475
716
|
}
|
|
476
717
|
}
|
|
477
718
|
exports.parseFieldSetArgument = parseFieldSetArgument;
|
|
719
|
+
function collectTargetFields({ parentType, directive, includeInterfaceFieldsImplementations, validate = true, }) {
|
|
720
|
+
const fields = [];
|
|
721
|
+
try {
|
|
722
|
+
parseFieldSetArgument({
|
|
723
|
+
parentType,
|
|
724
|
+
directive,
|
|
725
|
+
fieldAccessor: (t, f) => {
|
|
726
|
+
const field = t.field(f);
|
|
727
|
+
if (field) {
|
|
728
|
+
fields.push(field);
|
|
729
|
+
if (includeInterfaceFieldsImplementations && (0, definitions_1.isInterfaceType)(t)) {
|
|
730
|
+
for (const implType of t.possibleRuntimeTypes()) {
|
|
731
|
+
const implField = implType.field(f);
|
|
732
|
+
if (implField) {
|
|
733
|
+
fields.push(implField);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return field;
|
|
739
|
+
},
|
|
740
|
+
validate,
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
catch (e) {
|
|
744
|
+
const isGraphQLError = (0, definitions_1.errorCauses)(e) !== undefined;
|
|
745
|
+
if (!isGraphQLError || validate) {
|
|
746
|
+
throw e;
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return fields;
|
|
750
|
+
}
|
|
751
|
+
exports.collectTargetFields = collectTargetFields;
|
|
478
752
|
function validateFieldSetValue(directive) {
|
|
479
753
|
var _a;
|
|
480
754
|
const fields = directive.arguments().fields;
|
|
@@ -506,7 +780,7 @@ function subgraphsFromServiceList(serviceList) {
|
|
|
506
780
|
const subgraphs = new Subgraphs();
|
|
507
781
|
for (const service of serviceList) {
|
|
508
782
|
try {
|
|
509
|
-
subgraphs.add(service.name, (_a = service.url) !== null && _a !== void 0 ? _a : '', service.typeDefs);
|
|
783
|
+
subgraphs.add(buildSubgraph(service.name, (_a = service.url) !== null && _a !== void 0 ? _a : '', service.typeDefs));
|
|
510
784
|
}
|
|
511
785
|
catch (e) {
|
|
512
786
|
const causes = (0, definitions_1.errorCauses)(e);
|
|
@@ -525,18 +799,12 @@ class Subgraphs {
|
|
|
525
799
|
constructor() {
|
|
526
800
|
this.subgraphs = new utils_1.OrderedMap();
|
|
527
801
|
}
|
|
528
|
-
add(
|
|
529
|
-
|
|
530
|
-
|
|
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` });
|
|
534
|
-
}
|
|
535
|
-
if (this.subgraphs.has(toAdd.name)) {
|
|
536
|
-
throw new Error(`A subgraph named ${toAdd.name} already exists` + (toAdd.url ? ` (with url '${toAdd.url}')` : ''));
|
|
802
|
+
add(subgraph) {
|
|
803
|
+
if (this.subgraphs.has(subgraph.name)) {
|
|
804
|
+
throw new Error(`A subgraph named ${subgraph.name} already exists` + (subgraph.url ? ` (with url '${subgraph.url}')` : ''));
|
|
537
805
|
}
|
|
538
|
-
this.subgraphs.add(
|
|
539
|
-
return
|
|
806
|
+
this.subgraphs.add(subgraph.name, subgraph);
|
|
807
|
+
return subgraph;
|
|
540
808
|
}
|
|
541
809
|
get(name) {
|
|
542
810
|
return this.subgraphs.get(name);
|
|
@@ -555,22 +823,123 @@ class Subgraphs {
|
|
|
555
823
|
yield subgraph;
|
|
556
824
|
}
|
|
557
825
|
}
|
|
826
|
+
validate() {
|
|
827
|
+
let errors = [];
|
|
828
|
+
for (const subgraph of this.values()) {
|
|
829
|
+
try {
|
|
830
|
+
subgraph.validate();
|
|
831
|
+
}
|
|
832
|
+
catch (e) {
|
|
833
|
+
const causes = (0, definitions_1.errorCauses)(e);
|
|
834
|
+
if (!causes) {
|
|
835
|
+
throw e;
|
|
836
|
+
}
|
|
837
|
+
errors = errors.concat(causes);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return errors.length === 0 ? undefined : errors;
|
|
841
|
+
}
|
|
558
842
|
toString() {
|
|
559
843
|
return '[' + this.subgraphs.keys().join(', ') + ']';
|
|
560
844
|
}
|
|
561
845
|
}
|
|
562
846
|
exports.Subgraphs = Subgraphs;
|
|
847
|
+
exports.anyTypeSpec = (0, directiveAndTypeSpecification_1.createScalarTypeSpecification)({ name: '_Any' });
|
|
848
|
+
exports.serviceTypeSpec = (0, directiveAndTypeSpecification_1.createObjectTypeSpecification)({
|
|
849
|
+
name: '_Service',
|
|
850
|
+
fieldsFct: (schema) => [{ name: 'sdl', type: schema.stringType() }],
|
|
851
|
+
});
|
|
852
|
+
exports.entityTypeSpec = (0, directiveAndTypeSpecification_1.createUnionTypeSpecification)({
|
|
853
|
+
name: '_Entity',
|
|
854
|
+
membersFct: (schema) => {
|
|
855
|
+
return schema.types("ObjectType").filter(isEntityType).map((t) => t.name);
|
|
856
|
+
},
|
|
857
|
+
});
|
|
858
|
+
exports.FEDERATION_OPERATION_TYPES = [exports.anyTypeSpec, exports.serviceTypeSpec, exports.entityTypeSpec];
|
|
859
|
+
exports.serviceFieldName = '_service';
|
|
860
|
+
exports.entitiesFieldName = '_entities';
|
|
861
|
+
exports.FEDERATION_OPERATION_FIELDS = [exports.serviceFieldName, exports.entitiesFieldName];
|
|
563
862
|
class Subgraph {
|
|
564
|
-
constructor(name, url, schema
|
|
863
|
+
constructor(name, url, schema) {
|
|
565
864
|
this.name = name;
|
|
566
865
|
this.url = url;
|
|
567
866
|
this.schema = schema;
|
|
568
|
-
if (
|
|
569
|
-
|
|
867
|
+
if (name === exports.FEDERATION_RESERVED_SUBGRAPH_NAME) {
|
|
868
|
+
throw error_1.ERRORS.INVALID_SUBGRAPH_NAME.err({ message: `Invalid name ${exports.FEDERATION_RESERVED_SUBGRAPH_NAME} for a subgraph: this name is reserved` });
|
|
570
869
|
}
|
|
571
870
|
}
|
|
572
|
-
|
|
573
|
-
|
|
871
|
+
metadata() {
|
|
872
|
+
const metadata = federationMetadata(this.schema);
|
|
873
|
+
(0, utils_1.assert)(metadata, 'The subgraph schema should have built with the federation built-ins.');
|
|
874
|
+
return metadata;
|
|
875
|
+
}
|
|
876
|
+
isFed2Subgraph() {
|
|
877
|
+
return this.metadata().isFed2Schema();
|
|
878
|
+
}
|
|
879
|
+
addFederationOperations() {
|
|
880
|
+
const metadata = this.metadata();
|
|
881
|
+
for (const type of exports.FEDERATION_OPERATION_TYPES) {
|
|
882
|
+
type.checkOrAdd(this.schema);
|
|
883
|
+
}
|
|
884
|
+
const queryRoot = this.schema.schemaDefinition.root("query");
|
|
885
|
+
const queryType = queryRoot ? queryRoot.type : this.schema.addType(new definitions_1.ObjectType("Query"));
|
|
886
|
+
const entityField = queryType.field(exports.entitiesFieldName);
|
|
887
|
+
const entityType = metadata.entityType();
|
|
888
|
+
if (entityType) {
|
|
889
|
+
const entityFieldType = new definitions_1.NonNullType(new definitions_1.ListType(entityType));
|
|
890
|
+
if (!entityField) {
|
|
891
|
+
queryType.addField(exports.entitiesFieldName, entityFieldType)
|
|
892
|
+
.addArgument('representations', new definitions_1.NonNullType(new definitions_1.ListType(new definitions_1.NonNullType(metadata.anyType()))));
|
|
893
|
+
}
|
|
894
|
+
else if (!entityField.type) {
|
|
895
|
+
entityField.type = entityType;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
else if (entityField) {
|
|
899
|
+
entityField.remove();
|
|
900
|
+
}
|
|
901
|
+
if (!queryType.field(exports.serviceFieldName)) {
|
|
902
|
+
queryType.addField(exports.serviceFieldName, metadata.serviceType());
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
validate() {
|
|
906
|
+
try {
|
|
907
|
+
this.addFederationOperations();
|
|
908
|
+
this.schema.validate();
|
|
909
|
+
return this;
|
|
910
|
+
}
|
|
911
|
+
catch (e) {
|
|
912
|
+
if (e instanceof graphql_1.GraphQLError) {
|
|
913
|
+
throw addSubgraphToError(e, this.name, error_1.ERRORS.INVALID_GRAPHQL);
|
|
914
|
+
}
|
|
915
|
+
else {
|
|
916
|
+
throw e;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
isPrintedDirective(d) {
|
|
921
|
+
var _a;
|
|
922
|
+
if (this.metadata().allFederationDirectives().includes(d)) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
const core = this.schema.coreFeatures;
|
|
926
|
+
return !core || ((_a = core.sourceFeature(d)) === null || _a === void 0 ? void 0 : _a.url.identity) !== coreSpec_1.linkIdentity;
|
|
927
|
+
}
|
|
928
|
+
isPrintedType(t) {
|
|
929
|
+
var _a;
|
|
930
|
+
if (this.metadata().allFederationTypes().includes(t)) {
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
const core = this.schema.coreFeatures;
|
|
934
|
+
return !core || ((_a = core.sourceFeature(t)) === null || _a === void 0 ? void 0 : _a.url.identity) !== coreSpec_1.linkIdentity;
|
|
935
|
+
}
|
|
936
|
+
toString(basePrintOptions = print_1.defaultPrintOptions) {
|
|
937
|
+
return (0, print_1.printSchema)(this.schema, {
|
|
938
|
+
...basePrintOptions,
|
|
939
|
+
directiveDefinitionFilter: (d) => this.isPrintedDirective(d),
|
|
940
|
+
typeFilter: (t) => this.isPrintedType(t),
|
|
941
|
+
fieldFilter: (f) => !isFederationField(f),
|
|
942
|
+
});
|
|
574
943
|
}
|
|
575
944
|
}
|
|
576
945
|
exports.Subgraph = Subgraph;
|
|
@@ -596,48 +965,61 @@ function addSubgraphToError(e, subgraphName, errorCode) {
|
|
|
596
965
|
source: cause.source,
|
|
597
966
|
positions: cause.positions,
|
|
598
967
|
path: cause.path,
|
|
599
|
-
originalError: cause
|
|
968
|
+
originalError: cause,
|
|
600
969
|
extensions: cause.extensions,
|
|
601
970
|
});
|
|
602
971
|
}
|
|
603
972
|
else {
|
|
604
|
-
return new graphql_1.GraphQLError(message, nodes, cause.source, cause.positions, cause.path, cause
|
|
973
|
+
return new graphql_1.GraphQLError(message, nodes, cause.source, cause.positions, cause.path, cause, cause.extensions);
|
|
605
974
|
}
|
|
606
975
|
});
|
|
607
|
-
return (0, definitions_1.ErrGraphQLValidationFailed)(updatedCauses);
|
|
976
|
+
return updatedCauses.length === 1 ? updatedCauses[0] : (0, definitions_1.ErrGraphQLValidationFailed)(updatedCauses);
|
|
608
977
|
}
|
|
609
978
|
exports.addSubgraphToError = addSubgraphToError;
|
|
610
979
|
class ExternalTester {
|
|
611
980
|
constructor(schema) {
|
|
612
981
|
this.schema = schema;
|
|
613
982
|
this.fakeExternalFields = new Set();
|
|
983
|
+
this.providedFields = new Set();
|
|
984
|
+
this.externalDirective = this.metadata().externalDirective();
|
|
614
985
|
this.collectFakeExternals();
|
|
986
|
+
this.collectProvidedFields();
|
|
987
|
+
}
|
|
988
|
+
metadata() {
|
|
989
|
+
const metadata = federationMetadata(this.schema);
|
|
990
|
+
(0, utils_1.assert)(metadata, 'Schema should be a subgraphs schema');
|
|
991
|
+
return metadata;
|
|
615
992
|
}
|
|
616
993
|
collectFakeExternals() {
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
const parent = key.parent;
|
|
623
|
-
if (!(key.ofExtension() || parent.hasAppliedDirective(exports.extendsDirectiveName))) {
|
|
994
|
+
const metadata = this.metadata();
|
|
995
|
+
const extendsDirective = metadata.extendsDirective();
|
|
996
|
+
for (const key of metadata.keyDirective().applications()) {
|
|
997
|
+
const parentType = key.parent;
|
|
998
|
+
if (!(key.ofExtension() || parentType.hasAppliedDirective(extendsDirective))) {
|
|
624
999
|
continue;
|
|
625
1000
|
}
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
1001
|
+
collectTargetFields({
|
|
1002
|
+
parentType,
|
|
1003
|
+
directive: key,
|
|
1004
|
+
includeInterfaceFieldsImplementations: false,
|
|
1005
|
+
validate: false,
|
|
1006
|
+
}).filter((field) => field.hasAppliedDirective(this.externalDirective))
|
|
1007
|
+
.forEach((field) => this.fakeExternalFields.add(field.coordinate));
|
|
1008
|
+
}
|
|
1009
|
+
}
|
|
1010
|
+
collectProvidedFields() {
|
|
1011
|
+
for (const provides of this.metadata().providesDirective().applications()) {
|
|
1012
|
+
const parent = provides.parent;
|
|
1013
|
+
collectTargetFields({
|
|
1014
|
+
parentType: (0, definitions_1.baseType)(parent.type),
|
|
1015
|
+
directive: provides,
|
|
1016
|
+
includeInterfaceFieldsImplementations: true,
|
|
1017
|
+
validate: false,
|
|
1018
|
+
}).forEach((f) => this.providedFields.add(f.coordinate));
|
|
637
1019
|
}
|
|
638
1020
|
}
|
|
639
1021
|
isExternal(field) {
|
|
640
|
-
return field.hasAppliedDirective(
|
|
1022
|
+
return field.hasAppliedDirective(this.externalDirective) && !this.isFakeExternal(field);
|
|
641
1023
|
}
|
|
642
1024
|
isFakeExternal(field) {
|
|
643
1025
|
return this.fakeExternalFields.has(field.coordinate);
|
|
@@ -655,6 +1037,102 @@ class ExternalTester {
|
|
|
655
1037
|
}
|
|
656
1038
|
return false;
|
|
657
1039
|
}
|
|
1040
|
+
isPartiallyExternal(field) {
|
|
1041
|
+
return this.isExternal(field) && this.providedFields.has(field.coordinate);
|
|
1042
|
+
}
|
|
1043
|
+
isFullyExternal(field) {
|
|
1044
|
+
return this.isExternal(field) && !this.providedFields.has(field.coordinate);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
function removeInactiveProvidesAndRequires(schema, onModified = () => { }) {
|
|
1048
|
+
const metadata = federationMetadata(schema);
|
|
1049
|
+
if (!metadata) {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
const providesDirective = metadata.providesDirective();
|
|
1053
|
+
const requiresDirective = metadata.requiresDirective();
|
|
1054
|
+
for (const type of schema.types()) {
|
|
1055
|
+
if (!(0, definitions_1.isObjectType)(type) && !(0, definitions_1.isInterfaceType)(type)) {
|
|
1056
|
+
continue;
|
|
1057
|
+
}
|
|
1058
|
+
for (const field of type.fields()) {
|
|
1059
|
+
const fieldBaseType = (0, definitions_1.baseType)(field.type);
|
|
1060
|
+
removeInactiveApplications(providesDirective, field, fieldBaseType, onModified);
|
|
1061
|
+
removeInactiveApplications(requiresDirective, field, type, onModified);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
exports.removeInactiveProvidesAndRequires = removeInactiveProvidesAndRequires;
|
|
1066
|
+
function removeInactiveApplications(directiveDefinition, field, parentType, onModified) {
|
|
1067
|
+
for (const application of field.appliedDirectivesOf(directiveDefinition)) {
|
|
1068
|
+
let selection;
|
|
1069
|
+
try {
|
|
1070
|
+
selection = parseFieldSetArgument({ parentType, directive: application });
|
|
1071
|
+
}
|
|
1072
|
+
catch (e) {
|
|
1073
|
+
continue;
|
|
1074
|
+
}
|
|
1075
|
+
if (selectsNonExternalLeafField(selection)) {
|
|
1076
|
+
application.remove();
|
|
1077
|
+
const updated = withoutNonExternalLeafFields(selection);
|
|
1078
|
+
if (!updated.isEmpty()) {
|
|
1079
|
+
const updatedDirective = field.applyDirective(directiveDefinition, { fields: updated.toString(true, false) });
|
|
1080
|
+
onModified(field, application, updatedDirective);
|
|
1081
|
+
}
|
|
1082
|
+
else {
|
|
1083
|
+
onModified(field, application);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
function isExternalOrHasExternalImplementations(field) {
|
|
1089
|
+
const metadata = federationMetadata(field.schema());
|
|
1090
|
+
if (!metadata) {
|
|
1091
|
+
return false;
|
|
1092
|
+
}
|
|
1093
|
+
if (field.hasAppliedDirective(metadata.externalDirective())) {
|
|
1094
|
+
return true;
|
|
1095
|
+
}
|
|
1096
|
+
const parentType = field.parent;
|
|
1097
|
+
if ((0, definitions_1.isInterfaceType)(parentType)) {
|
|
1098
|
+
for (const implem of parentType.possibleRuntimeTypes()) {
|
|
1099
|
+
const fieldInImplem = implem.field(field.name);
|
|
1100
|
+
if (fieldInImplem && fieldInImplem.hasAppliedDirective(metadata.externalDirective())) {
|
|
1101
|
+
return true;
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return false;
|
|
1106
|
+
}
|
|
1107
|
+
function selectsNonExternalLeafField(selection) {
|
|
1108
|
+
return selection.selections().some(s => {
|
|
1109
|
+
if (s.kind === 'FieldSelection') {
|
|
1110
|
+
if (isExternalOrHasExternalImplementations(s.field.definition)) {
|
|
1111
|
+
return false;
|
|
1112
|
+
}
|
|
1113
|
+
return !s.selectionSet || selectsNonExternalLeafField(s.selectionSet);
|
|
1114
|
+
}
|
|
1115
|
+
else {
|
|
1116
|
+
return selectsNonExternalLeafField(s.selectionSet);
|
|
1117
|
+
}
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
function withoutNonExternalLeafFields(selectionSet) {
|
|
1121
|
+
const newSelectionSet = new operations_1.SelectionSet(selectionSet.parentType);
|
|
1122
|
+
for (const selection of selectionSet.selections()) {
|
|
1123
|
+
if (selection.kind === 'FieldSelection') {
|
|
1124
|
+
if (isExternalOrHasExternalImplementations(selection.field.definition)) {
|
|
1125
|
+
newSelectionSet.add(selection);
|
|
1126
|
+
continue;
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
if (selection.selectionSet) {
|
|
1130
|
+
const updated = withoutNonExternalLeafFields(selection.selectionSet);
|
|
1131
|
+
if (!updated.isEmpty()) {
|
|
1132
|
+
newSelectionSet.add((0, operations_1.selectionOfElement)(selection.element(), updated));
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
return newSelectionSet;
|
|
658
1137
|
}
|
|
659
|
-
exports.ExternalTester = ExternalTester;
|
|
660
1138
|
//# sourceMappingURL=federation.js.map
|