@theguild/federation-composition 0.9.0 → 0.10.0
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/README.md +2 -1
- package/cjs/specifications/link.js +40 -5
- package/cjs/subgraph/helpers.js +2 -2
- package/cjs/subgraph/state.js +8 -0
- package/cjs/subgraph/validation/rules/elements/provides.js +8 -6
- package/cjs/subgraph/validation/rules/elements/requires.js +9 -7
- package/cjs/subgraph/validation/validate-state.js +9 -3
- package/cjs/subgraph/validation/validate-subgraph.js +4 -2
- package/cjs/subgraph/validation/validation-context.js +10 -0
- package/cjs/supergraph/composition/directive.js +3 -0
- package/cjs/supergraph/composition/enum-type.js +3 -0
- package/cjs/supergraph/composition/input-object-type.js +3 -0
- package/cjs/supergraph/composition/interface-type.js +4 -0
- package/cjs/supergraph/composition/object-type.js +18 -20
- package/cjs/supergraph/composition/scalar-type.js +2 -0
- package/cjs/supergraph/composition/union-type.js +2 -0
- package/cjs/supergraph/state.js +24 -26
- package/cjs/supergraph/validation/rules/fields-of-the-same-type-rule.js +35 -0
- package/cjs/supergraph/validation/rules/invalid-field-sharing-rule.js +4 -1
- package/cjs/supergraph/validation/rules/satisfiablity/constants.js +4 -0
- package/cjs/supergraph/validation/rules/satisfiablity/edge.js +64 -0
- package/cjs/supergraph/validation/rules/satisfiablity/errors.js +44 -0
- package/cjs/supergraph/validation/rules/satisfiablity/fields.js +147 -0
- package/cjs/supergraph/validation/rules/satisfiablity/finder.js +267 -0
- package/cjs/supergraph/validation/rules/satisfiablity/graph.js +675 -0
- package/cjs/supergraph/validation/rules/satisfiablity/helpers.js +41 -0
- package/cjs/supergraph/validation/rules/satisfiablity/move-validator.js +337 -0
- package/cjs/supergraph/validation/rules/satisfiablity/moves.js +52 -0
- package/cjs/supergraph/validation/rules/satisfiablity/node.js +89 -0
- package/cjs/supergraph/validation/rules/satisfiablity/operation-path.js +70 -0
- package/cjs/supergraph/validation/rules/satisfiablity/supergraph.js +37 -0
- package/cjs/supergraph/validation/rules/satisfiablity/walker.js +306 -0
- package/cjs/supergraph/validation/rules/satisfiablity-rule.js +45 -1081
- package/cjs/supergraph/validation/validate-supergraph.js +1 -1
- package/cjs/utils/logger.js +127 -0
- package/esm/specifications/link.js +40 -5
- package/esm/subgraph/helpers.js +2 -2
- package/esm/subgraph/state.js +8 -0
- package/esm/subgraph/validation/rules/elements/provides.js +8 -6
- package/esm/subgraph/validation/rules/elements/requires.js +9 -7
- package/esm/subgraph/validation/validate-state.js +9 -3
- package/esm/subgraph/validation/validate-subgraph.js +4 -2
- package/esm/subgraph/validation/validation-context.js +11 -1
- package/esm/supergraph/composition/directive.js +3 -0
- package/esm/supergraph/composition/enum-type.js +3 -0
- package/esm/supergraph/composition/input-object-type.js +3 -0
- package/esm/supergraph/composition/interface-type.js +4 -0
- package/esm/supergraph/composition/object-type.js +18 -20
- package/esm/supergraph/composition/scalar-type.js +2 -0
- package/esm/supergraph/composition/union-type.js +2 -0
- package/esm/supergraph/state.js +24 -26
- package/esm/supergraph/validation/rules/fields-of-the-same-type-rule.js +35 -0
- package/esm/supergraph/validation/rules/invalid-field-sharing-rule.js +4 -1
- package/esm/supergraph/validation/rules/satisfiablity/constants.js +1 -0
- package/esm/supergraph/validation/rules/satisfiablity/edge.js +54 -0
- package/esm/supergraph/validation/rules/satisfiablity/errors.js +40 -0
- package/esm/supergraph/validation/rules/satisfiablity/fields.js +142 -0
- package/esm/supergraph/validation/rules/satisfiablity/finder.js +261 -0
- package/esm/supergraph/validation/rules/satisfiablity/graph.js +671 -0
- package/esm/supergraph/validation/rules/satisfiablity/helpers.js +35 -0
- package/esm/supergraph/validation/rules/satisfiablity/move-validator.js +333 -0
- package/esm/supergraph/validation/rules/satisfiablity/moves.js +46 -0
- package/esm/supergraph/validation/rules/satisfiablity/node.js +85 -0
- package/esm/supergraph/validation/rules/satisfiablity/operation-path.js +66 -0
- package/esm/supergraph/validation/rules/satisfiablity/supergraph.js +33 -0
- package/esm/supergraph/validation/rules/satisfiablity/walker.js +301 -0
- package/esm/supergraph/validation/rules/satisfiablity-rule.js +40 -1076
- package/esm/supergraph/validation/validate-supergraph.js +1 -1
- package/esm/utils/logger.js +119 -0
- package/package.json +2 -1
- package/typings/subgraph/state.d.cts +2 -0
- package/typings/subgraph/state.d.ts +2 -0
- package/typings/subgraph/validation/validate-state.d.cts +2 -1
- package/typings/subgraph/validation/validate-state.d.ts +2 -1
- package/typings/subgraph/validation/validation-context.d.cts +3 -0
- package/typings/subgraph/validation/validation-context.d.ts +3 -0
- package/typings/supergraph/composition/common.d.cts +2 -1
- package/typings/supergraph/composition/common.d.ts +2 -1
- package/typings/supergraph/composition/directive.d.cts +4 -0
- package/typings/supergraph/composition/directive.d.ts +4 -0
- package/typings/supergraph/composition/enum-type.d.cts +4 -0
- package/typings/supergraph/composition/enum-type.d.ts +4 -0
- package/typings/supergraph/composition/input-object-type.d.cts +4 -0
- package/typings/supergraph/composition/input-object-type.d.ts +4 -0
- package/typings/supergraph/composition/interface-type.d.cts +5 -0
- package/typings/supergraph/composition/interface-type.d.ts +5 -0
- package/typings/supergraph/composition/object-type.d.cts +5 -0
- package/typings/supergraph/composition/object-type.d.ts +5 -0
- package/typings/supergraph/composition/scalar-type.d.cts +3 -0
- package/typings/supergraph/composition/scalar-type.d.ts +3 -0
- package/typings/supergraph/composition/union-type.d.cts +3 -0
- package/typings/supergraph/composition/union-type.d.ts +3 -0
- package/typings/supergraph/state.d.cts +4 -4
- package/typings/supergraph/state.d.ts +4 -4
- package/typings/supergraph/validation/rules/satisfiablity/constants.d.cts +2 -0
- package/typings/supergraph/validation/rules/satisfiablity/constants.d.ts +2 -0
- package/typings/supergraph/validation/rules/satisfiablity/edge.d.cts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/edge.d.ts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/errors.d.cts +17 -0
- package/typings/supergraph/validation/rules/satisfiablity/errors.d.ts +17 -0
- package/typings/supergraph/validation/rules/satisfiablity/fields.d.cts +33 -0
- package/typings/supergraph/validation/rules/satisfiablity/fields.d.ts +33 -0
- package/typings/supergraph/validation/rules/satisfiablity/finder.d.cts +28 -0
- package/typings/supergraph/validation/rules/satisfiablity/finder.d.ts +28 -0
- package/typings/supergraph/validation/rules/satisfiablity/graph.d.cts +63 -0
- package/typings/supergraph/validation/rules/satisfiablity/graph.d.ts +63 -0
- package/typings/supergraph/validation/rules/satisfiablity/helpers.d.cts +7 -0
- package/typings/supergraph/validation/rules/satisfiablity/helpers.d.ts +7 -0
- package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.cts +25 -0
- package/typings/supergraph/validation/rules/satisfiablity/move-validator.d.ts +25 -0
- package/typings/supergraph/validation/rules/satisfiablity/moves.d.cts +24 -0
- package/typings/supergraph/validation/rules/satisfiablity/moves.d.ts +24 -0
- package/typings/supergraph/validation/rules/satisfiablity/node.d.cts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/node.d.ts +31 -0
- package/typings/supergraph/validation/rules/satisfiablity/operation-path.d.cts +29 -0
- package/typings/supergraph/validation/rules/satisfiablity/operation-path.d.ts +29 -0
- package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.cts +14 -0
- package/typings/supergraph/validation/rules/satisfiablity/supergraph.d.ts +14 -0
- package/typings/supergraph/validation/rules/satisfiablity/walker.d.cts +35 -0
- package/typings/supergraph/validation/rules/satisfiablity/walker.d.ts +35 -0
- package/typings/utils/logger.d.cts +33 -0
- package/typings/utils/logger.d.ts +33 -0
- package/cjs/utils/dependency-graph.js +0 -227
- package/esm/utils/dependency-graph.js +0 -222
- package/typings/utils/dependency-graph.d.cts +0 -31
- package/typings/utils/dependency-graph.d.ts +0 -31
package/README.md
CHANGED
|
@@ -12,7 +12,8 @@ Supports all Federation versions. Drop-in replacement for `@apollo/composition`.
|
|
|
12
12
|
- produces Supergraph SDL (can be used with Apollo Router and every tool that supports Supergraph
|
|
13
13
|
SDL)
|
|
14
14
|
- does not support Hints
|
|
15
|
-
-
|
|
15
|
+
- 5x faster when composing and validating small to medium schemas (a bit slower for huge schemas)
|
|
16
|
+
- 2x less memory usage
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -34,10 +34,41 @@ function printLink(link) {
|
|
|
34
34
|
},
|
|
35
35
|
value: {
|
|
36
36
|
kind: graphql_1.Kind.LIST,
|
|
37
|
-
values: link.imports.map(im =>
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
values: link.imports.map(im => {
|
|
38
|
+
if (!im.alias) {
|
|
39
|
+
return {
|
|
40
|
+
kind: graphql_1.Kind.STRING,
|
|
41
|
+
value: im.name,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
kind: graphql_1.Kind.OBJECT,
|
|
46
|
+
fields: [
|
|
47
|
+
{
|
|
48
|
+
kind: graphql_1.Kind.OBJECT_FIELD,
|
|
49
|
+
name: {
|
|
50
|
+
kind: graphql_1.Kind.NAME,
|
|
51
|
+
value: 'name',
|
|
52
|
+
},
|
|
53
|
+
value: {
|
|
54
|
+
kind: graphql_1.Kind.STRING,
|
|
55
|
+
value: im.name,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
kind: graphql_1.Kind.OBJECT_FIELD,
|
|
60
|
+
name: {
|
|
61
|
+
kind: graphql_1.Kind.NAME,
|
|
62
|
+
value: 'as',
|
|
63
|
+
},
|
|
64
|
+
value: {
|
|
65
|
+
kind: graphql_1.Kind.STRING,
|
|
66
|
+
value: im.alias,
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}),
|
|
41
72
|
},
|
|
42
73
|
},
|
|
43
74
|
],
|
|
@@ -162,7 +193,11 @@ function mergeLinks(links) {
|
|
|
162
193
|
return Array.from(groupByIdentity.entries()).map(([identity, link]) => ({
|
|
163
194
|
identity,
|
|
164
195
|
version: link.highestVersion,
|
|
165
|
-
imports: Array.from(link.imports).map(link => ({
|
|
196
|
+
imports: Array.from(link.imports).map(link => ({
|
|
197
|
+
kind: link.kind,
|
|
198
|
+
name: link.name,
|
|
199
|
+
alias: link.alias,
|
|
200
|
+
})),
|
|
166
201
|
name: link.name,
|
|
167
202
|
}));
|
|
168
203
|
}
|
package/cjs/subgraph/helpers.js
CHANGED
|
@@ -37,10 +37,10 @@ function validateDirectiveAgainstOriginal(providedDirectiveNode, directiveName,
|
|
|
37
37
|
if (expectedType !== providedType) {
|
|
38
38
|
const isNonNullableString = providedType === 'String!';
|
|
39
39
|
const allowedFieldSetTypes = isFederationV2
|
|
40
|
-
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!']
|
|
40
|
+
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!', '[String!]!']
|
|
41
41
|
: ['_FieldSet!', 'String', 'String!'];
|
|
42
42
|
const fieldSetTypesInSpec = isFederationV2
|
|
43
|
-
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!']
|
|
43
|
+
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!', '[String!]!']
|
|
44
44
|
: ['_FieldSet!', 'FieldSet!', 'String'];
|
|
45
45
|
const expectsFieldSet = fieldSetTypesInSpec.includes(expectedType);
|
|
46
46
|
if (!isNonNullableString && expectsFieldSet) {
|
package/cjs/subgraph/state.js
CHANGED
|
@@ -104,6 +104,9 @@ function createSubgraphStateBuilder(graph, typeDefs, version, links) {
|
|
|
104
104
|
throw new Error(`Expected to find an object type`);
|
|
105
105
|
}
|
|
106
106
|
objectTypeBuilder.field.setType(typeDef.name.value, node.name.value, (0, helpers_js_1.printOutputType)(node.type));
|
|
107
|
+
if (typeDef.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
108
|
+
objectTypeBuilder.field.setExtension(typeDef.name.value, node.name.value);
|
|
109
|
+
}
|
|
107
110
|
if (version === 'v1.0' &&
|
|
108
111
|
(typeDef.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
109
112
|
typeDef.name.value === expectedQueryTypeName ||
|
|
@@ -596,6 +599,9 @@ function objectTypeFactory(state, renameObject) {
|
|
|
596
599
|
setType(typeName, fieldName, fieldType) {
|
|
597
600
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).type = fieldType;
|
|
598
601
|
},
|
|
602
|
+
setExtension(typeName, fieldName) {
|
|
603
|
+
getOrCreateObjectField(state, renameObject, typeName, fieldName).extension = true;
|
|
604
|
+
},
|
|
599
605
|
setDirective(typeName, fieldName, directive) {
|
|
600
606
|
getOrCreateObjectField(state, renameObject, typeName, fieldName).ast.directives.push(directive);
|
|
601
607
|
},
|
|
@@ -1108,6 +1114,7 @@ function getOrCreateObjectField(state, renameObject, typeName, fieldName) {
|
|
|
1108
1114
|
external: false,
|
|
1109
1115
|
inaccessible: false,
|
|
1110
1116
|
authenticated: false,
|
|
1117
|
+
extension: false,
|
|
1111
1118
|
policies: [],
|
|
1112
1119
|
scopes: [],
|
|
1113
1120
|
used: false,
|
|
@@ -1147,6 +1154,7 @@ function getOrCreateInterfaceField(state, typeName, fieldName) {
|
|
|
1147
1154
|
required: false,
|
|
1148
1155
|
provided: false,
|
|
1149
1156
|
shareable: false,
|
|
1157
|
+
extension: false,
|
|
1150
1158
|
tags: new Set(),
|
|
1151
1159
|
args: new Map(),
|
|
1152
1160
|
ast: {
|
|
@@ -106,12 +106,14 @@ function ProvidesRules(context) {
|
|
|
106
106
|
context.reportError(new graphql_1.GraphQLError(`On field "${fieldCoordinate}", for @provides(fields: ${printedFieldsValue}): field ${info.typeDefinition.name.value}.${info.fieldName} cannot be included because it has arguments (fields with argument are not allowed in @provides)`, { nodes: directiveNode, extensions: { code: 'PROVIDES_FIELDS_HAS_ARGS' } }));
|
|
107
107
|
},
|
|
108
108
|
interceptNonExternalField(info) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
if (context.satisfiesVersionRange('> v1.0')) {
|
|
110
|
+
isValid = false;
|
|
111
|
+
context.reportError(new graphql_1.GraphQLError(`On field "${fieldCoordinate}", for @provides(fields: ${printedFieldsValue}): field "${info.typeDefinition.name.value}.${info.fieldName}" should not be part of a @provides since it is already provided by this subgraph (it is not marked @external)`, {
|
|
112
|
+
extensions: {
|
|
113
|
+
code: 'PROVIDES_FIELDS_MISSING_EXTERNAL',
|
|
114
|
+
},
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
115
117
|
},
|
|
116
118
|
interceptExternalField(info) {
|
|
117
119
|
const keyDirectives = info.typeDefinition.directives?.filter(directive => context.isAvailableFederationDirective('key', directive));
|
|
@@ -33,7 +33,7 @@ function RequiresRules(context) {
|
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
const printedFieldsValue = (0, printer_js_1.print)(fieldsArg.value);
|
|
36
|
-
if (fieldsArg.value.kind !== graphql_1.Kind.STRING) {
|
|
36
|
+
if (fieldsArg.value.kind !== graphql_1.Kind.STRING && fieldsArg.value.kind !== graphql_1.Kind.ENUM) {
|
|
37
37
|
context.reportError(new graphql_1.GraphQLError(`On field "${fieldCoordinate}", for @requires(fields: ${printedFieldsValue}): Invalid value for argument "fields": must be a string.`, {
|
|
38
38
|
nodes: directiveNode,
|
|
39
39
|
extensions: {
|
|
@@ -106,12 +106,14 @@ function RequiresRules(context) {
|
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
interceptNonExternalField(info) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
109
|
+
if (context.satisfiesVersionRange('> v1.0')) {
|
|
110
|
+
isValid = false;
|
|
111
|
+
context.reportError(new graphql_1.GraphQLError(`On field "${fieldCoordinate}", for @requires(fields: ${printedFieldsValue}): field "${info.typeDefinition.name.value}.${info.fieldName}" should not be part of a @requires since it is already provided by this subgraph (it is not marked @external)`, {
|
|
112
|
+
extensions: {
|
|
113
|
+
code: 'REQUIRES_FIELDS_MISSING_EXTERNAL',
|
|
114
|
+
},
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
115
117
|
},
|
|
116
118
|
});
|
|
117
119
|
if (isValid) {
|
|
@@ -6,7 +6,7 @@ const format_js_1 = require("../../utils/format.js");
|
|
|
6
6
|
const state_js_1 = require("../../utils/state.js");
|
|
7
7
|
const state_js_2 = require("../state.js");
|
|
8
8
|
const specifiedScalars = new Set(graphql_1.specifiedScalarTypes.map(t => t.name));
|
|
9
|
-
function validateSubgraphState(state) {
|
|
9
|
+
function validateSubgraphState(state, context) {
|
|
10
10
|
const errors = [];
|
|
11
11
|
function reportError(message) {
|
|
12
12
|
errors.push(new graphql_1.GraphQLError(message, {
|
|
@@ -16,7 +16,7 @@ function validateSubgraphState(state) {
|
|
|
16
16
|
}));
|
|
17
17
|
}
|
|
18
18
|
validateRootTypes(state, reportError);
|
|
19
|
-
validateDirectives(state, reportError);
|
|
19
|
+
validateDirectives(state, reportError, context);
|
|
20
20
|
validateTypes(state, reportError);
|
|
21
21
|
return errors;
|
|
22
22
|
}
|
|
@@ -58,13 +58,19 @@ function validateRootTypes(state, reportError) {
|
|
|
58
58
|
function capitalize(str) {
|
|
59
59
|
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
60
60
|
}
|
|
61
|
-
function validateDirectives(state, reportError) {
|
|
61
|
+
function validateDirectives(state, reportError, context) {
|
|
62
62
|
for (const directive of state.types.values()) {
|
|
63
63
|
if (isDirective(directive)) {
|
|
64
|
+
if (context.isLinkSpecDirective(directive.name)) {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
64
67
|
validateName(reportError, directive.name);
|
|
65
68
|
for (const [argName, arg] of directive.args) {
|
|
66
69
|
validateName(reportError, argName);
|
|
67
70
|
const argInputTypeName = (0, state_js_1.stripTypeModifiers)(arg.type);
|
|
71
|
+
if (context.isLinkSpecType(argInputTypeName)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
68
74
|
if (!isInputType(state, argInputTypeName)) {
|
|
69
75
|
reportError(`The type of @${directive.name}(${arg.name}:) must be Input Type ` +
|
|
70
76
|
`but got: ${arg.type}.`);
|
|
@@ -162,7 +162,7 @@ function validateSubgraph(subgraph, stateBuilder, federation, __internal) {
|
|
|
162
162
|
: null,
|
|
163
163
|
subgraph.typeDefs,
|
|
164
164
|
].filter(onlyDocumentNode));
|
|
165
|
-
const subgraphStateErrors = (0, validate_state_js_1.validateSubgraphState)(stateBuilder.state);
|
|
165
|
+
const subgraphStateErrors = (0, validate_state_js_1.validateSubgraphState)(stateBuilder.state, validationContext);
|
|
166
166
|
const simpleValidationContext = (0, validation_context_js_1.createSimpleValidationContext)(fullTypeDefs, typeNodeInfo);
|
|
167
167
|
(0, graphql_1.visit)(fullTypeDefs, (0, graphql_1.visitInParallel)(graphqlRules.map(rule => {
|
|
168
168
|
if (rulesToSkip.includes(rule.name)) {
|
|
@@ -322,7 +322,9 @@ function cleanSubgraphTypeDefsFromSubgraphSpec(typeDefs) {
|
|
|
322
322
|
const queryTypeName = schemaDef?.operationTypes?.find(op => op.operation === graphql_1.OperationTypeNode.QUERY)?.type.name
|
|
323
323
|
.value ?? 'Query';
|
|
324
324
|
typeDefs.definitions = typeDefs.definitions.filter(def => {
|
|
325
|
-
if (def.kind === graphql_1.Kind.SCALAR_TYPE_DEFINITION
|
|
325
|
+
if ((def.kind === graphql_1.Kind.SCALAR_TYPE_DEFINITION ||
|
|
326
|
+
def.kind === graphql_1.Kind.INPUT_OBJECT_TYPE_DEFINITION) &&
|
|
327
|
+
def.name.value === '_Any') {
|
|
326
328
|
return false;
|
|
327
329
|
}
|
|
328
330
|
if (def.kind === graphql_1.Kind.UNION_TYPE_DEFINITION && def.name.value === '_Entity') {
|
|
@@ -3,8 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.createSubgraphValidationContext = exports.createSimpleValidationContext = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
5
|
const federation_js_1 = require("../../specifications/federation.js");
|
|
6
|
+
const link_js_1 = require("../../specifications/link.js");
|
|
6
7
|
const state_js_1 = require("../../utils/state.js");
|
|
7
8
|
const state_js_2 = require("../state.js");
|
|
9
|
+
const linkSpec = (0, graphql_1.parse)(link_js_1.sdl);
|
|
10
|
+
const linkSpecDirectives = linkSpec.definitions.filter((def) => def.kind === graphql_1.Kind.DIRECTIVE_DEFINITION);
|
|
11
|
+
const linkSpecTypes = linkSpec.definitions.filter(graphql_1.isTypeDefinitionNode);
|
|
8
12
|
function createSimpleValidationContext(typeDefs, typeNodeInfo) {
|
|
9
13
|
let reportedErrors = [];
|
|
10
14
|
const directiveDefinitionMap = new Map();
|
|
@@ -155,6 +159,12 @@ function createSubgraphValidationContext(subgraph, federation, typeNodeInfo, sta
|
|
|
155
159
|
}
|
|
156
160
|
return {
|
|
157
161
|
stateBuilder,
|
|
162
|
+
isLinkSpecDirective(name) {
|
|
163
|
+
return linkSpecDirectives.some(d => d.name.value === name);
|
|
164
|
+
},
|
|
165
|
+
isLinkSpecType(name) {
|
|
166
|
+
return linkSpecTypes.some(t => t.name.value === name);
|
|
167
|
+
},
|
|
158
168
|
isAvailableFederationType(name) {
|
|
159
169
|
const alternativeNames = typeAlternativeNamesMap.get(name);
|
|
160
170
|
if (alternativeNames) {
|
|
@@ -31,11 +31,13 @@ function directiveBuilder() {
|
|
|
31
31
|
argState.byGraph.set(graph.id, {
|
|
32
32
|
type: arg.type,
|
|
33
33
|
defaultValue: arg.defaultValue,
|
|
34
|
+
version: graph.version,
|
|
34
35
|
});
|
|
35
36
|
}
|
|
36
37
|
directiveState.byGraph.set(graph.id, {
|
|
37
38
|
locations: directive.locations,
|
|
38
39
|
repeatable: directive.repeatable,
|
|
40
|
+
version: graph.version,
|
|
39
41
|
});
|
|
40
42
|
},
|
|
41
43
|
composeSupergraphNode(directive) {
|
|
@@ -64,6 +66,7 @@ function getOrCreateDirective(state, directiveName) {
|
|
|
64
66
|
return existing;
|
|
65
67
|
}
|
|
66
68
|
const def = {
|
|
69
|
+
kind: 'directive',
|
|
67
70
|
name: directiveName,
|
|
68
71
|
locations: new Set(),
|
|
69
72
|
byGraph: new Map(),
|
|
@@ -39,6 +39,7 @@ function enumTypeBuilder() {
|
|
|
39
39
|
}
|
|
40
40
|
enumTypeState.byGraph.set(graph.id, {
|
|
41
41
|
inaccessible: type.inaccessible,
|
|
42
|
+
version: graph.version,
|
|
42
43
|
});
|
|
43
44
|
for (const value of type.values.values()) {
|
|
44
45
|
const valueState = getOrCreateEnumValue(enumTypeState, value.name);
|
|
@@ -54,6 +55,7 @@ function enumTypeBuilder() {
|
|
|
54
55
|
}
|
|
55
56
|
valueState.byGraph.set(graph.id, {
|
|
56
57
|
inaccessible: value.inaccessible,
|
|
58
|
+
version: graph.version,
|
|
57
59
|
});
|
|
58
60
|
}
|
|
59
61
|
},
|
|
@@ -114,6 +116,7 @@ function getOrCreateEnumType(state, typeName) {
|
|
|
114
116
|
return existing;
|
|
115
117
|
}
|
|
116
118
|
const def = {
|
|
119
|
+
kind: 'enum',
|
|
117
120
|
name: typeName,
|
|
118
121
|
values: new Map(),
|
|
119
122
|
tags: new Set(),
|
|
@@ -19,6 +19,7 @@ function inputObjectTypeBuilder() {
|
|
|
19
19
|
}
|
|
20
20
|
inputObjectTypeState.byGraph.set(graph.id, {
|
|
21
21
|
inaccessible: type.inaccessible,
|
|
22
|
+
version: graph.version,
|
|
22
23
|
});
|
|
23
24
|
for (const field of type.fields.values()) {
|
|
24
25
|
const fieldState = getOrCreateField(inputObjectTypeState, field.name, field.type);
|
|
@@ -42,6 +43,7 @@ function inputObjectTypeBuilder() {
|
|
|
42
43
|
type: field.type,
|
|
43
44
|
inaccessible: field.inaccessible,
|
|
44
45
|
defaultValue: field.defaultValue,
|
|
46
|
+
version: graph.version,
|
|
45
47
|
});
|
|
46
48
|
}
|
|
47
49
|
},
|
|
@@ -95,6 +97,7 @@ function getOrCreateInputObjectType(state, typeName) {
|
|
|
95
97
|
return existing;
|
|
96
98
|
}
|
|
97
99
|
const def = {
|
|
100
|
+
kind: 'input',
|
|
98
101
|
name: typeName,
|
|
99
102
|
tags: new Set(),
|
|
100
103
|
hasDefinition: false,
|
|
@@ -36,6 +36,7 @@ function interfaceTypeBuilder() {
|
|
|
36
36
|
keys: type.keys,
|
|
37
37
|
interfaces: type.interfaces,
|
|
38
38
|
implementedBy: type.implementedBy,
|
|
39
|
+
version: graph.version,
|
|
39
40
|
});
|
|
40
41
|
for (const field of type.fields.values()) {
|
|
41
42
|
const fieldState = getOrCreateInterfaceField(interfaceTypeState, field.name, field.type);
|
|
@@ -69,6 +70,7 @@ function interfaceTypeBuilder() {
|
|
|
69
70
|
override: field.override,
|
|
70
71
|
provides: field.provides,
|
|
71
72
|
requires: field.requires,
|
|
73
|
+
version: graph.version,
|
|
72
74
|
});
|
|
73
75
|
for (const arg of field.args.values()) {
|
|
74
76
|
const argState = getOrCreateArg(fieldState, arg.name, arg.type);
|
|
@@ -91,6 +93,7 @@ function interfaceTypeBuilder() {
|
|
|
91
93
|
argState.byGraph.set(graph.id, {
|
|
92
94
|
type: arg.type,
|
|
93
95
|
defaultValue: arg.defaultValue,
|
|
96
|
+
version: graph.version,
|
|
94
97
|
});
|
|
95
98
|
}
|
|
96
99
|
}
|
|
@@ -197,6 +200,7 @@ function getOrCreateInterfaceType(state, typeName) {
|
|
|
197
200
|
return existing;
|
|
198
201
|
}
|
|
199
202
|
const def = {
|
|
203
|
+
kind: 'interface',
|
|
200
204
|
name: typeName,
|
|
201
205
|
tags: new Set(),
|
|
202
206
|
inaccessible: false,
|
|
@@ -63,6 +63,7 @@ function objectTypeBuilder() {
|
|
|
63
63
|
inaccessible: type.inaccessible,
|
|
64
64
|
shareable: type.shareable,
|
|
65
65
|
interfaces: type.interfaces,
|
|
66
|
+
version: graph.version,
|
|
66
67
|
});
|
|
67
68
|
const typeInGraph = objectTypeState.byGraph.get(graph.id);
|
|
68
69
|
for (const field of type.fields.values()) {
|
|
@@ -120,8 +121,10 @@ function objectTypeBuilder() {
|
|
|
120
121
|
provided: field.provided,
|
|
121
122
|
required: field.required,
|
|
122
123
|
shareable: field.shareable,
|
|
124
|
+
extension: field.extension,
|
|
123
125
|
used: field.used,
|
|
124
126
|
usedAsKey,
|
|
127
|
+
version: graph.version,
|
|
125
128
|
});
|
|
126
129
|
for (const arg of field.args.values()) {
|
|
127
130
|
const argState = getOrCreateArg(fieldState, arg.name, arg.type);
|
|
@@ -148,6 +151,7 @@ function objectTypeBuilder() {
|
|
|
148
151
|
type: arg.type,
|
|
149
152
|
inaccessible: arg.inaccessible,
|
|
150
153
|
defaultValue: arg.defaultValue,
|
|
154
|
+
version: graph.version,
|
|
151
155
|
});
|
|
152
156
|
}
|
|
153
157
|
}
|
|
@@ -157,7 +161,7 @@ function objectTypeBuilder() {
|
|
|
157
161
|
const joinTypes = isQuery
|
|
158
162
|
?
|
|
159
163
|
Array.from(graphs.values()).map(graph => ({
|
|
160
|
-
graph: graph.id,
|
|
164
|
+
graph: graph.graph.id,
|
|
161
165
|
}))
|
|
162
166
|
:
|
|
163
167
|
Array.from(objectType.byGraph.entries())
|
|
@@ -220,12 +224,12 @@ function objectTypeBuilder() {
|
|
|
220
224
|
}
|
|
221
225
|
return true;
|
|
222
226
|
}
|
|
223
|
-
function createJoinFields(fieldInGraphs, field, { hasDifferentOutputType,
|
|
227
|
+
function createJoinFields(fieldInGraphs, field, { hasDifferentOutputType, }) {
|
|
224
228
|
return fieldInGraphs
|
|
225
229
|
.map(([graphId, meta]) => {
|
|
226
230
|
const type = hasDifferentOutputType ? meta.type : undefined;
|
|
227
231
|
const override = meta.override ?? undefined;
|
|
228
|
-
const usedOverridden = provideUsedOverriddenValue(field
|
|
232
|
+
const usedOverridden = provideUsedOverriddenValue(field, meta, fieldNamesOfImplementedInterfaces, graphId, graphNameToId);
|
|
229
233
|
const external = shouldSetExternalOnJoinField(meta, graphId, field);
|
|
230
234
|
const provides = meta.provides ?? undefined;
|
|
231
235
|
const requires = meta.requires ?? undefined;
|
|
@@ -261,7 +265,6 @@ function objectTypeBuilder() {
|
|
|
261
265
|
const hasDifferentOutputType = fieldInGraphs.some(([_, meta]) => meta.type !== field.type);
|
|
262
266
|
const isDefinedEverywhere = field.byGraph.size === (isQuery ? graphs.size : objectType.byGraph.size);
|
|
263
267
|
let joinFields = [];
|
|
264
|
-
const overridesMap = {};
|
|
265
268
|
const differencesBetweenGraphs = {
|
|
266
269
|
override: false,
|
|
267
270
|
type: false,
|
|
@@ -277,10 +280,6 @@ function objectTypeBuilder() {
|
|
|
277
280
|
}
|
|
278
281
|
if (meta.override !== null) {
|
|
279
282
|
differencesBetweenGraphs.override = true;
|
|
280
|
-
const originalGraphId = graphNameToId(meta.override);
|
|
281
|
-
if (originalGraphId) {
|
|
282
|
-
overridesMap[originalGraphId] = graphId;
|
|
283
|
-
}
|
|
284
283
|
}
|
|
285
284
|
if (meta.provides !== null) {
|
|
286
285
|
differencesBetweenGraphs.provides = true;
|
|
@@ -299,7 +298,7 @@ function objectTypeBuilder() {
|
|
|
299
298
|
!fieldInGraph.usedAsKey &&
|
|
300
299
|
!fieldInGraph.required &&
|
|
301
300
|
!fieldInGraph.provided &&
|
|
302
|
-
!provideUsedOverriddenValue(field
|
|
301
|
+
!provideUsedOverriddenValue(field, fieldInGraph, fieldNamesOfImplementedInterfaces, graphId, graphNameToId) &&
|
|
303
302
|
graphs.get(graphId).version === 'v1.0') {
|
|
304
303
|
return null;
|
|
305
304
|
}
|
|
@@ -315,7 +314,7 @@ function objectTypeBuilder() {
|
|
|
315
314
|
joinFields = graphsWithOverride.map(([graphId, meta]) => ({
|
|
316
315
|
graph: graphId,
|
|
317
316
|
override: meta.override ?? undefined,
|
|
318
|
-
usedOverridden: provideUsedOverriddenValue(field
|
|
317
|
+
usedOverridden: provideUsedOverriddenValue(field, meta, fieldNamesOfImplementedInterfaces, graphId, graphNameToId),
|
|
319
318
|
type: differencesBetweenGraphs.type ? meta.type : undefined,
|
|
320
319
|
external: meta.external ?? undefined,
|
|
321
320
|
provides: meta.provides ?? undefined,
|
|
@@ -343,7 +342,7 @@ function objectTypeBuilder() {
|
|
|
343
342
|
const graphsToEmit = fieldInGraphs.filter(([graphId, f]) => {
|
|
344
343
|
const isExternal = f.external === true;
|
|
345
344
|
const isOverridden = overriddenGraphs.includes(graphId);
|
|
346
|
-
const needsToPrintUsedOverridden = provideUsedOverriddenValue(field
|
|
345
|
+
const needsToPrintUsedOverridden = provideUsedOverriddenValue(field, f, fieldNamesOfImplementedInterfaces, graphId, graphNameToId);
|
|
347
346
|
const isRequired = f.required === true;
|
|
348
347
|
return (isExternal && isRequired) || needsToPrintUsedOverridden || !isOverridden;
|
|
349
348
|
});
|
|
@@ -353,7 +352,7 @@ function objectTypeBuilder() {
|
|
|
353
352
|
joinFields = graphsToEmit.map(([graphId, meta]) => ({
|
|
354
353
|
graph: graphId,
|
|
355
354
|
override: meta.override ?? undefined,
|
|
356
|
-
usedOverridden: provideUsedOverriddenValue(field
|
|
355
|
+
usedOverridden: provideUsedOverriddenValue(field, meta, fieldNamesOfImplementedInterfaces, graphId, graphNameToId),
|
|
357
356
|
type: differencesBetweenGraphs.type ? meta.type : undefined,
|
|
358
357
|
external: meta.external ?? undefined,
|
|
359
358
|
provides: meta.provides ?? undefined,
|
|
@@ -364,7 +363,6 @@ function objectTypeBuilder() {
|
|
|
364
363
|
else if (hasDifferencesBetweenGraphs) {
|
|
365
364
|
joinFields = createJoinFields(fieldInGraphs, field, {
|
|
366
365
|
hasDifferentOutputType,
|
|
367
|
-
overridesMap,
|
|
368
366
|
});
|
|
369
367
|
}
|
|
370
368
|
}
|
|
@@ -376,11 +374,11 @@ function objectTypeBuilder() {
|
|
|
376
374
|
const graphsToPrintJoinField = fieldInGraphs.filter(([graphId, meta]) => meta.override !== null ||
|
|
377
375
|
meta.external === true ||
|
|
378
376
|
(meta.shareable && !overriddenGraphs.includes(graphId)) ||
|
|
379
|
-
provideUsedOverriddenValue(field
|
|
377
|
+
provideUsedOverriddenValue(field, meta, fieldNamesOfImplementedInterfaces, graphId, graphNameToId));
|
|
380
378
|
joinFields = graphsToPrintJoinField.map(([graphId, meta]) => ({
|
|
381
379
|
graph: graphId,
|
|
382
380
|
override: meta.override ?? undefined,
|
|
383
|
-
usedOverridden: provideUsedOverriddenValue(field
|
|
381
|
+
usedOverridden: provideUsedOverriddenValue(field, meta, fieldNamesOfImplementedInterfaces, graphId, graphNameToId),
|
|
384
382
|
type: differencesBetweenGraphs.type ? meta.type : undefined,
|
|
385
383
|
external: meta.external ?? undefined,
|
|
386
384
|
provides: meta.provides ?? undefined,
|
|
@@ -390,7 +388,6 @@ function objectTypeBuilder() {
|
|
|
390
388
|
else {
|
|
391
389
|
joinFields = createJoinFields(fieldInGraphs, field, {
|
|
392
390
|
hasDifferentOutputType,
|
|
393
|
-
overridesMap,
|
|
394
391
|
});
|
|
395
392
|
}
|
|
396
393
|
}
|
|
@@ -470,12 +467,12 @@ function objectTypeBuilder() {
|
|
|
470
467
|
};
|
|
471
468
|
}
|
|
472
469
|
exports.objectTypeBuilder = objectTypeBuilder;
|
|
473
|
-
function provideUsedOverriddenValue(
|
|
474
|
-
const inGraphs = fieldNamesOfImplementedInterfaces[
|
|
470
|
+
function provideUsedOverriddenValue(field, fieldStateInGraph, fieldNamesOfImplementedInterfaces, graphId, graphNameToId) {
|
|
471
|
+
const inGraphs = fieldNamesOfImplementedInterfaces[field.name];
|
|
475
472
|
const hasMatchingInterfaceFieldInGraph = inGraphs && inGraphs.has(graphId);
|
|
476
473
|
const isUsedAsNonExternalKey = fieldStateInGraph.usedAsKey && !fieldStateInGraph.external;
|
|
477
|
-
const
|
|
478
|
-
if (
|
|
474
|
+
const isOverridden = field.override && graphNameToId(field.override) === graphId;
|
|
475
|
+
if (isOverridden && (isUsedAsNonExternalKey || hasMatchingInterfaceFieldInGraph)) {
|
|
479
476
|
return true;
|
|
480
477
|
}
|
|
481
478
|
return false;
|
|
@@ -486,6 +483,7 @@ function getOrCreateObjectType(state, typeName) {
|
|
|
486
483
|
return existing;
|
|
487
484
|
}
|
|
488
485
|
const def = {
|
|
486
|
+
kind: 'object',
|
|
489
487
|
name: typeName,
|
|
490
488
|
tags: new Set(),
|
|
491
489
|
hasDefinition: false,
|
|
@@ -31,6 +31,7 @@ function scalarTypeBuilder() {
|
|
|
31
31
|
});
|
|
32
32
|
scalarTypeState.byGraph.set(graph.id, {
|
|
33
33
|
inaccessible: type.inaccessible,
|
|
34
|
+
version: graph.version,
|
|
34
35
|
});
|
|
35
36
|
},
|
|
36
37
|
composeSupergraphNode(scalarType) {
|
|
@@ -62,6 +63,7 @@ function getOrCreateScalarType(state, typeName) {
|
|
|
62
63
|
return existing;
|
|
63
64
|
}
|
|
64
65
|
const def = {
|
|
66
|
+
kind: 'scalar',
|
|
65
67
|
name: typeName,
|
|
66
68
|
tags: new Set(),
|
|
67
69
|
inaccessible: false,
|
|
@@ -18,6 +18,7 @@ function unionTypeBuilder() {
|
|
|
18
18
|
}
|
|
19
19
|
unionTypeState.byGraph.set(graph.id, {
|
|
20
20
|
members: type.members,
|
|
21
|
+
version: graph.version,
|
|
21
22
|
});
|
|
22
23
|
for (const member of type.members) {
|
|
23
24
|
unionTypeState.members.add(member);
|
|
@@ -52,6 +53,7 @@ function getOrCreateUnionType(state, typeName) {
|
|
|
52
53
|
return existing;
|
|
53
54
|
}
|
|
54
55
|
const def = {
|
|
56
|
+
kind: 'union',
|
|
55
57
|
name: typeName,
|
|
56
58
|
members: new Set(),
|
|
57
59
|
tags: new Set(),
|