@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.
- package/CHANGELOG.md +43 -3
- package/dist/buildSchema.d.ts +7 -3
- package/dist/buildSchema.d.ts.map +1 -1
- package/dist/buildSchema.js +94 -61
- package/dist/buildSchema.js.map +1 -1
- package/dist/coreSpec.d.ts +39 -9
- package/dist/coreSpec.d.ts.map +1 -1
- package/dist/coreSpec.js +232 -42
- package/dist/coreSpec.js.map +1 -1
- package/dist/definitions.d.ts +71 -51
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +326 -231
- package/dist/definitions.js.map +1 -1
- package/dist/directiveAndTypeSpecification.d.ts +48 -0
- package/dist/directiveAndTypeSpecification.d.ts.map +1 -0
- package/dist/directiveAndTypeSpecification.js +253 -0
- package/dist/directiveAndTypeSpecification.js.map +1 -0
- package/dist/error.d.ts +21 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +63 -3
- package/dist/error.js.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
- package/dist/extractSubgraphsFromSupergraph.js +42 -97
- package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
- package/dist/federation.d.ts +102 -46
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +762 -234
- package/dist/federation.js.map +1 -1
- package/dist/federationSpec.d.ts +23 -0
- package/dist/federationSpec.d.ts.map +1 -0
- package/dist/federationSpec.js +117 -0
- package/dist/federationSpec.js.map +1 -0
- package/dist/inaccessibleSpec.d.ts +5 -1
- package/dist/inaccessibleSpec.d.ts.map +1 -1
- package/dist/inaccessibleSpec.js +31 -3
- package/dist/inaccessibleSpec.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/introspection.d.ts.map +1 -1
- package/dist/introspection.js +8 -3
- package/dist/introspection.js.map +1 -1
- package/dist/joinSpec.d.ts +6 -1
- package/dist/joinSpec.d.ts.map +1 -1
- package/dist/joinSpec.js +22 -0
- package/dist/joinSpec.js.map +1 -1
- package/dist/knownCoreFeatures.d.ts +4 -0
- package/dist/knownCoreFeatures.d.ts.map +1 -0
- package/dist/knownCoreFeatures.js +16 -0
- package/dist/knownCoreFeatures.js.map +1 -0
- package/dist/operations.d.ts +9 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +27 -5
- package/dist/operations.js.map +1 -1
- package/dist/precompute.d.ts +3 -0
- package/dist/precompute.d.ts.map +1 -0
- package/dist/precompute.js +51 -0
- package/dist/precompute.js.map +1 -0
- package/dist/print.d.ts +11 -9
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +32 -22
- 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 +497 -0
- package/dist/schemaUpgrader.js.map +1 -0
- package/dist/suggestions.d.ts +1 -1
- package/dist/suggestions.d.ts.map +1 -1
- package/dist/suggestions.js.map +1 -1
- package/dist/supergraphs.d.ts.map +1 -1
- package/dist/supergraphs.js +3 -3
- package/dist/supergraphs.js.map +1 -1
- package/dist/tagSpec.d.ts +7 -2
- package/dist/tagSpec.d.ts.map +1 -1
- package/dist/tagSpec.js +36 -16
- 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 +19 -11
- 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 +4 -4
- package/src/__tests__/coreSpec.test.ts +100 -0
- package/src/__tests__/definitions.test.ts +98 -17
- package/src/__tests__/extractSubgraphsFromSupergraph.test.ts +64 -0
- package/src/__tests__/federation.test.ts +31 -0
- package/src/__tests__/operations.test.ts +2 -3
- package/src/__tests__/removeInaccessibleElements.test.ts +59 -6
- package/src/__tests__/schemaUpgrader.test.ts +169 -0
- package/src/__tests__/subgraphValidation.test.ts +422 -21
- package/src/__tests__/values.test.ts +2 -4
- package/src/buildSchema.ts +154 -84
- package/src/coreSpec.ts +294 -55
- package/src/definitions.ts +415 -275
- package/src/directiveAndTypeSpecification.ts +353 -0
- package/src/error.ts +143 -5
- package/src/extractSubgraphsFromSupergraph.ts +56 -122
- package/src/federation.ts +991 -302
- package/src/federationSpec.ts +146 -0
- package/src/inaccessibleSpec.ts +39 -11
- package/src/index.ts +4 -0
- package/src/introspection.ts +8 -3
- package/src/joinSpec.ts +35 -4
- package/src/knownCoreFeatures.ts +13 -0
- package/src/operations.ts +37 -7
- package/src/precompute.ts +65 -0
- package/src/print.ts +63 -48
- package/src/schemaUpgrader.ts +653 -0
- package/src/suggestions.ts +1 -1
- package/src/supergraphs.ts +4 -3
- package/src/tagSpec.ts +50 -18
- package/src/utils.ts +63 -0
- package/src/validate.ts +27 -16
- 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,26 @@
|
|
|
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.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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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,
|
|
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 =
|
|
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 (
|
|
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 @${
|
|
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 @${
|
|
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 &&
|
|
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,
|
|
72
|
+
validateFieldSetSelections(directiveName, selection.selectionSet, newHasExternalInParents, federationMetadata, allowOnNonExternalLeafFields);
|
|
98
73
|
}
|
|
99
74
|
}
|
|
100
75
|
else {
|
|
101
|
-
validateFieldSetSelections(directiveName, selection.selectionSet, hasExternalInParents,
|
|
76
|
+
validateFieldSetSelections(directiveName, selection.selectionSet, hasExternalInParents, federationMetadata, allowOnNonExternalLeafFields);
|
|
102
77
|
}
|
|
103
78
|
}
|
|
104
79
|
}
|
|
105
|
-
function validateFieldSet(type, directive,
|
|
80
|
+
function validateFieldSet(type, directive, federationMetadata, allowOnNonExternalLeafFields, onFields) {
|
|
106
81
|
var _a;
|
|
107
82
|
try {
|
|
108
|
-
const
|
|
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,
|
|
92
|
+
const selectionSet = parseFieldSetArgument({ parentType: type, directive, fieldAccessor });
|
|
118
93
|
try {
|
|
119
|
-
validateFieldSetSelections(directive.name, selectionSet, false,
|
|
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,
|
|
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,
|
|
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
|
|
179
|
-
|
|
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 (!
|
|
195
|
+
if (!metadata.isFieldExternal(field) || metadata.isFieldUsed(field)) {
|
|
185
196
|
continue;
|
|
186
197
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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 (
|
|
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
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
this.
|
|
238
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
294
|
-
|
|
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
|
-
|
|
297
|
-
|
|
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
|
|
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
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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(
|
|
332
|
-
validateAllFieldSet(
|
|
333
|
-
if (
|
|
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,
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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.
|
|
354
|
-
validateInterfaceRuntimeImplementationFieldsTypes(itf,
|
|
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
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
|
|
371
|
-
|
|
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
|
-
|
|
374
|
-
|
|
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
|
-
|
|
377
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
const
|
|
382
|
-
|
|
383
|
-
|
|
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
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
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.
|
|
397
|
-
exports.
|
|
398
|
-
function
|
|
399
|
-
|
|
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.
|
|
402
|
-
function
|
|
403
|
-
return
|
|
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.
|
|
406
|
-
function
|
|
407
|
-
return
|
|
626
|
+
exports.federationMetadata = federationMetadata;
|
|
627
|
+
function isFederationSubgraphSchema(schema) {
|
|
628
|
+
return !!federationMetadata(schema);
|
|
408
629
|
}
|
|
409
|
-
exports.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
429
|
-
? (0, buildSchema_1.buildSchema)(new graphql_1.Source(source, name),
|
|
430
|
-
: (0, buildSchema_1.buildSchemaFromAST)(source,
|
|
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
|
|
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
|
-
|
|
446
|
-
|
|
447
|
-
|
|
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 ===
|
|
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(
|
|
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` });
|
|
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
|
-
|
|
536
|
-
|
|
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
|
|
913
|
+
constructor(name, url, schema) {
|
|
565
914
|
this.name = name;
|
|
566
915
|
this.url = url;
|
|
567
916
|
this.schema = schema;
|
|
568
|
-
if (
|
|
569
|
-
|
|
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
|
-
|
|
573
|
-
|
|
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
|
|
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
|
|
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
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
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
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
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(
|
|
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
|