@theguild/federation-composition 0.6.1 → 0.6.2-rc-20231219171219-079169e
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/cjs/subgraph/helpers.js +4 -2
- package/cjs/subgraph/validation/rules/elements/key.js +5 -1
- package/cjs/subgraph/validation/rules/elements/provides.js +7 -1
- package/cjs/subgraph/validation/rules/elements/requires.js +7 -1
- package/cjs/subgraph/validation/validation-context.js +19 -2
- package/cjs/supergraph/validation/rules/external-argument-missing-rule.js +21 -20
- package/esm/subgraph/helpers.js +4 -2
- package/esm/subgraph/validation/rules/elements/key.js +5 -1
- package/esm/subgraph/validation/rules/elements/provides.js +7 -1
- package/esm/subgraph/validation/rules/elements/requires.js +7 -1
- package/esm/subgraph/validation/validation-context.js +19 -2
- package/esm/supergraph/validation/rules/external-argument-missing-rule.js +21 -20
- package/package.json +1 -1
package/cjs/subgraph/helpers.js
CHANGED
|
@@ -38,13 +38,15 @@ function validateDirectiveAgainstOriginal(providedDirectiveNode, directiveName,
|
|
|
38
38
|
const isNonNullableString = providedType === 'String!';
|
|
39
39
|
const allowedFieldSetTypes = isFederationV2
|
|
40
40
|
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!']
|
|
41
|
-
: ['_FieldSet!', 'String'];
|
|
41
|
+
: ['_FieldSet!', 'String', 'String!'];
|
|
42
42
|
const fieldSetTypesInSpec = isFederationV2
|
|
43
43
|
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!']
|
|
44
44
|
: ['_FieldSet!', 'FieldSet!', 'String'];
|
|
45
45
|
const expectsFieldSet = fieldSetTypesInSpec.includes(expectedType);
|
|
46
46
|
if (!isNonNullableString && expectsFieldSet) {
|
|
47
|
-
const isOneOfExpected = allowedFieldSetTypes
|
|
47
|
+
const isOneOfExpected = allowedFieldSetTypes
|
|
48
|
+
.concat(allowedFieldSetTypes.map(f => `[${f}]!`))
|
|
49
|
+
.includes(providedType);
|
|
48
50
|
if (!isOneOfExpected) {
|
|
49
51
|
errors.push(new graphql_1.GraphQLError(`Invalid definition for directive "@${directiveName}": argument "${argName}" should have type "${expectedType}" but found type "${providedType}"`, {
|
|
50
52
|
nodes: providedDirectiveNode,
|
|
@@ -69,10 +69,14 @@ function KeyRules(context) {
|
|
|
69
69
|
const knownObjectsAndInterfaces = context.getSubgraphObjectOrInterfaceTypes();
|
|
70
70
|
let isValid = true;
|
|
71
71
|
const fieldsUsedInKey = new Set();
|
|
72
|
+
const mergedTypeDef = context.getSubgraphObjectOrInterfaceTypes().get(typeDef.name.value);
|
|
73
|
+
if (!mergedTypeDef) {
|
|
74
|
+
throw new Error(`Could not find type "${typeDef.name.value}"`);
|
|
75
|
+
}
|
|
72
76
|
(0, helpers_js_1.visitFields)({
|
|
73
77
|
context,
|
|
74
78
|
selectionSet,
|
|
75
|
-
typeDefinition:
|
|
79
|
+
typeDefinition: mergedTypeDef,
|
|
76
80
|
interceptField(info) {
|
|
77
81
|
if (info.typeDefinition.name.value === typeDef.name.value) {
|
|
78
82
|
fieldsUsedInKey.add(info.fieldName);
|
|
@@ -129,11 +129,17 @@ function ProvidesRules(context) {
|
|
|
129
129
|
const fieldsArg = keyDirective.arguments?.find(arg => arg.name.value === 'fields' && arg.value.kind === graphql_1.Kind.STRING);
|
|
130
130
|
if (fieldsArg) {
|
|
131
131
|
const keyFields = (0, helpers_js_1.parseFields)(fieldsArg.value.value);
|
|
132
|
+
const mergedTypeDef = context
|
|
133
|
+
.getSubgraphObjectOrInterfaceTypes()
|
|
134
|
+
.get(info.typeDefinition.name.value);
|
|
135
|
+
if (!mergedTypeDef) {
|
|
136
|
+
throw new Error(`Could not find type "${info.typeDefinition.name.value}"`);
|
|
137
|
+
}
|
|
132
138
|
if (keyFields) {
|
|
133
139
|
(0, helpers_js_1.visitFields)({
|
|
134
140
|
context,
|
|
135
141
|
selectionSet: keyFields,
|
|
136
|
-
typeDefinition:
|
|
142
|
+
typeDefinition: mergedTypeDef,
|
|
137
143
|
interceptField(keyFieldInfo) {
|
|
138
144
|
if (keyFieldInfo.typeDefinition.name.value === info.typeDefinition.name.value &&
|
|
139
145
|
keyFieldInfo.fieldName === info.fieldName) {
|
|
@@ -68,10 +68,16 @@ function RequiresRules(context) {
|
|
|
68
68
|
annotatedType.kind !== graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
69
69
|
return;
|
|
70
70
|
}
|
|
71
|
+
const mergedTypeDef = context
|
|
72
|
+
.getSubgraphObjectOrInterfaceTypes()
|
|
73
|
+
.get(annotatedType.name.value);
|
|
74
|
+
if (!mergedTypeDef) {
|
|
75
|
+
throw new Error(`Could not find type "${annotatedType.name.value}"`);
|
|
76
|
+
}
|
|
71
77
|
(0, helpers_js_1.visitFields)({
|
|
72
78
|
context,
|
|
73
79
|
selectionSet,
|
|
74
|
-
typeDefinition:
|
|
80
|
+
typeDefinition: mergedTypeDef,
|
|
75
81
|
interceptField(info) {
|
|
76
82
|
if (info.typeDefinition.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
77
83
|
info.typeDefinition.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
@@ -65,10 +65,27 @@ function createSubgraphValidationContext(subgraph, federation, typeNodeInfo, sta
|
|
|
65
65
|
const { version, imports } = federation;
|
|
66
66
|
const availableSpec = (0, federation_js_1.createSpecSchema)(version, imports);
|
|
67
67
|
const knownSpec = (0, federation_js_1.createSpecSchema)(version);
|
|
68
|
-
const knownSubgraphEntities = new Map(
|
|
68
|
+
const knownSubgraphEntities = new Map();
|
|
69
|
+
for (const def of subgraph.typeDefs.definitions.filter(def => def.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
69
70
|
def.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION ||
|
|
70
71
|
def.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
|
|
71
|
-
def.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION)
|
|
72
|
+
def.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION)) {
|
|
73
|
+
const found = knownSubgraphEntities.get(def.name.value);
|
|
74
|
+
if (!found) {
|
|
75
|
+
knownSubgraphEntities.set(def.name.value, { ...def });
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
found.fields = (found.fields ?? []).concat(def.fields ?? []);
|
|
79
|
+
found.interfaces = (found.interfaces ?? []).concat(def.interfaces ?? []);
|
|
80
|
+
found.directives = (found.directives ?? []).concat(def.directives ?? []);
|
|
81
|
+
if (def.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION && found.kind === graphql_1.Kind.OBJECT_TYPE_EXTENSION) {
|
|
82
|
+
found.kind = graphql_1.Kind.OBJECT_TYPE_DEFINITION;
|
|
83
|
+
}
|
|
84
|
+
else if (def.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION &&
|
|
85
|
+
found.kind === graphql_1.Kind.INTERFACE_TYPE_EXTENSION) {
|
|
86
|
+
found.kind = graphql_1.Kind.INTERFACE_TYPE_DEFINITION;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
72
89
|
const knownSubgraphDirectiveDefinitions = new Map(subgraph.typeDefs.definitions.filter(def => def.kind === graphql_1.Kind.DIRECTIVE_DEFINITION).map(def => [def.name.value, def]));
|
|
73
90
|
const leafTypeNames = new Set(graphql_1.specifiedScalarTypes.map(type => type.name));
|
|
74
91
|
for (const def of subgraph.typeDefs.definitions) {
|
|
@@ -5,27 +5,28 @@ const graphql_1 = require("graphql");
|
|
|
5
5
|
function ExternalArgumentMissingRule(context) {
|
|
6
6
|
return {
|
|
7
7
|
ObjectTypeFieldArg(objectState, fieldState, argState) {
|
|
8
|
-
if (argState.
|
|
9
|
-
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
if (fieldState.byGraph.size === argState.byGraph.size) {
|
|
13
|
-
return;
|
|
14
|
-
}
|
|
15
|
-
const graphsWithRequiredArg = Array.from(argState.byGraph)
|
|
16
|
-
.filter(([graph, arg]) => arg.type.endsWith('!') && fieldState.byGraph.get(graph)?.external !== true)
|
|
17
|
-
.map(([graph]) => graph);
|
|
18
|
-
const externalGraphsWithoutArg = Array.from(fieldState.byGraph.keys()).filter(graph => !argState.byGraph.has(graph) && fieldState.byGraph.get(graph)?.external === true);
|
|
19
|
-
const requiredIn = `subgraph${graphsWithRequiredArg.length > 1 ? 's' : ''} "${graphsWithRequiredArg.map(context.graphIdToName).join('", "')}"`;
|
|
20
|
-
const missingIn = `subgraph${externalGraphsWithoutArg.length > 1 ? 's' : ''} "${externalGraphsWithoutArg.map(context.graphIdToName).join('", "')}"`;
|
|
21
|
-
const fieldCoordinate = `${objectState.name}.${fieldState.name}`;
|
|
22
|
-
const argCoordinate = `${objectState.name}.${fieldState.name}(${argState.name}:)`;
|
|
23
|
-
context.reportError(new graphql_1.GraphQLError(`Field "${fieldCoordinate}" is missing argument "${argCoordinate}" in some subgraphs where it is marked @external: argument "${argCoordinate}" is declared in ${requiredIn} but not in ${missingIn} (where "${fieldCoordinate}" is @external)`, {
|
|
24
|
-
extensions: {
|
|
25
|
-
code: 'EXTERNAL_ARGUMENT_MISSING',
|
|
26
|
-
},
|
|
27
|
-
}));
|
|
8
|
+
if (argState.byGraph.size === 1 && fieldState.byGraph.size === argState.byGraph.size) {
|
|
9
|
+
return;
|
|
28
10
|
}
|
|
11
|
+
if (fieldState.byGraph.size === argState.byGraph.size) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const graphsWithRequiredArg = Array.from(argState.byGraph)
|
|
15
|
+
.filter(([graph, arg]) => fieldState.byGraph.get(graph)?.external !== true)
|
|
16
|
+
.map(([graph]) => graph);
|
|
17
|
+
const externalGraphsWithoutArg = Array.from(fieldState.byGraph.keys()).filter(graph => !argState.byGraph.has(graph) && fieldState.byGraph.get(graph)?.external === true);
|
|
18
|
+
if (!externalGraphsWithoutArg.length) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const requiredIn = `subgraph${graphsWithRequiredArg.length > 1 ? 's' : ''} "${graphsWithRequiredArg.map(context.graphIdToName).join('", "')}"`;
|
|
22
|
+
const missingIn = `subgraph${externalGraphsWithoutArg.length > 1 ? 's' : ''} "${externalGraphsWithoutArg.map(context.graphIdToName).join('", "')}"`;
|
|
23
|
+
const fieldCoordinate = `${objectState.name}.${fieldState.name}`;
|
|
24
|
+
const argCoordinate = `${objectState.name}.${fieldState.name}(${argState.name}:)`;
|
|
25
|
+
context.reportError(new graphql_1.GraphQLError(`Field "${fieldCoordinate}" is missing argument "${argCoordinate}" in some subgraphs where it is marked @external: argument "${argCoordinate}" is declared in ${requiredIn} but not in ${missingIn} (where "${fieldCoordinate}" is @external)`, {
|
|
26
|
+
extensions: {
|
|
27
|
+
code: 'EXTERNAL_ARGUMENT_MISSING',
|
|
28
|
+
},
|
|
29
|
+
}));
|
|
29
30
|
},
|
|
30
31
|
};
|
|
31
32
|
}
|
package/esm/subgraph/helpers.js
CHANGED
|
@@ -35,13 +35,15 @@ export function validateDirectiveAgainstOriginal(providedDirectiveNode, directiv
|
|
|
35
35
|
const isNonNullableString = providedType === 'String!';
|
|
36
36
|
const allowedFieldSetTypes = isFederationV2
|
|
37
37
|
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!']
|
|
38
|
-
: ['_FieldSet!', 'String'];
|
|
38
|
+
: ['_FieldSet!', 'String', 'String!'];
|
|
39
39
|
const fieldSetTypesInSpec = isFederationV2
|
|
40
40
|
? ['FieldSet!', 'federation__FieldSet!', '_FieldSet!']
|
|
41
41
|
: ['_FieldSet!', 'FieldSet!', 'String'];
|
|
42
42
|
const expectsFieldSet = fieldSetTypesInSpec.includes(expectedType);
|
|
43
43
|
if (!isNonNullableString && expectsFieldSet) {
|
|
44
|
-
const isOneOfExpected = allowedFieldSetTypes
|
|
44
|
+
const isOneOfExpected = allowedFieldSetTypes
|
|
45
|
+
.concat(allowedFieldSetTypes.map(f => `[${f}]!`))
|
|
46
|
+
.includes(providedType);
|
|
45
47
|
if (!isOneOfExpected) {
|
|
46
48
|
errors.push(new GraphQLError(`Invalid definition for directive "@${directiveName}": argument "${argName}" should have type "${expectedType}" but found type "${providedType}"`, {
|
|
47
49
|
nodes: providedDirectiveNode,
|
|
@@ -66,10 +66,14 @@ export function KeyRules(context) {
|
|
|
66
66
|
const knownObjectsAndInterfaces = context.getSubgraphObjectOrInterfaceTypes();
|
|
67
67
|
let isValid = true;
|
|
68
68
|
const fieldsUsedInKey = new Set();
|
|
69
|
+
const mergedTypeDef = context.getSubgraphObjectOrInterfaceTypes().get(typeDef.name.value);
|
|
70
|
+
if (!mergedTypeDef) {
|
|
71
|
+
throw new Error(`Could not find type "${typeDef.name.value}"`);
|
|
72
|
+
}
|
|
69
73
|
visitFields({
|
|
70
74
|
context,
|
|
71
75
|
selectionSet,
|
|
72
|
-
typeDefinition:
|
|
76
|
+
typeDefinition: mergedTypeDef,
|
|
73
77
|
interceptField(info) {
|
|
74
78
|
if (info.typeDefinition.name.value === typeDef.name.value) {
|
|
75
79
|
fieldsUsedInKey.add(info.fieldName);
|
|
@@ -126,11 +126,17 @@ export function ProvidesRules(context) {
|
|
|
126
126
|
const fieldsArg = keyDirective.arguments?.find(arg => arg.name.value === 'fields' && arg.value.kind === Kind.STRING);
|
|
127
127
|
if (fieldsArg) {
|
|
128
128
|
const keyFields = parseFields(fieldsArg.value.value);
|
|
129
|
+
const mergedTypeDef = context
|
|
130
|
+
.getSubgraphObjectOrInterfaceTypes()
|
|
131
|
+
.get(info.typeDefinition.name.value);
|
|
132
|
+
if (!mergedTypeDef) {
|
|
133
|
+
throw new Error(`Could not find type "${info.typeDefinition.name.value}"`);
|
|
134
|
+
}
|
|
129
135
|
if (keyFields) {
|
|
130
136
|
visitFields({
|
|
131
137
|
context,
|
|
132
138
|
selectionSet: keyFields,
|
|
133
|
-
typeDefinition:
|
|
139
|
+
typeDefinition: mergedTypeDef,
|
|
134
140
|
interceptField(keyFieldInfo) {
|
|
135
141
|
if (keyFieldInfo.typeDefinition.name.value === info.typeDefinition.name.value &&
|
|
136
142
|
keyFieldInfo.fieldName === info.fieldName) {
|
|
@@ -65,10 +65,16 @@ export function RequiresRules(context) {
|
|
|
65
65
|
annotatedType.kind !== Kind.OBJECT_TYPE_EXTENSION) {
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
|
+
const mergedTypeDef = context
|
|
69
|
+
.getSubgraphObjectOrInterfaceTypes()
|
|
70
|
+
.get(annotatedType.name.value);
|
|
71
|
+
if (!mergedTypeDef) {
|
|
72
|
+
throw new Error(`Could not find type "${annotatedType.name.value}"`);
|
|
73
|
+
}
|
|
68
74
|
visitFields({
|
|
69
75
|
context,
|
|
70
76
|
selectionSet,
|
|
71
|
-
typeDefinition:
|
|
77
|
+
typeDefinition: mergedTypeDef,
|
|
72
78
|
interceptField(info) {
|
|
73
79
|
if (info.typeDefinition.kind === Kind.OBJECT_TYPE_DEFINITION ||
|
|
74
80
|
info.typeDefinition.kind === Kind.OBJECT_TYPE_EXTENSION) {
|
|
@@ -61,10 +61,27 @@ export function createSubgraphValidationContext(subgraph, federation, typeNodeIn
|
|
|
61
61
|
const { version, imports } = federation;
|
|
62
62
|
const availableSpec = createSpecSchema(version, imports);
|
|
63
63
|
const knownSpec = createSpecSchema(version);
|
|
64
|
-
const knownSubgraphEntities = new Map(
|
|
64
|
+
const knownSubgraphEntities = new Map();
|
|
65
|
+
for (const def of subgraph.typeDefs.definitions.filter(def => def.kind === Kind.OBJECT_TYPE_DEFINITION ||
|
|
65
66
|
def.kind === Kind.OBJECT_TYPE_EXTENSION ||
|
|
66
67
|
def.kind === Kind.INTERFACE_TYPE_DEFINITION ||
|
|
67
|
-
def.kind === Kind.INTERFACE_TYPE_EXTENSION)
|
|
68
|
+
def.kind === Kind.INTERFACE_TYPE_EXTENSION)) {
|
|
69
|
+
const found = knownSubgraphEntities.get(def.name.value);
|
|
70
|
+
if (!found) {
|
|
71
|
+
knownSubgraphEntities.set(def.name.value, { ...def });
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
found.fields = (found.fields ?? []).concat(def.fields ?? []);
|
|
75
|
+
found.interfaces = (found.interfaces ?? []).concat(def.interfaces ?? []);
|
|
76
|
+
found.directives = (found.directives ?? []).concat(def.directives ?? []);
|
|
77
|
+
if (def.kind === Kind.OBJECT_TYPE_DEFINITION && found.kind === Kind.OBJECT_TYPE_EXTENSION) {
|
|
78
|
+
found.kind = Kind.OBJECT_TYPE_DEFINITION;
|
|
79
|
+
}
|
|
80
|
+
else if (def.kind === Kind.INTERFACE_TYPE_DEFINITION &&
|
|
81
|
+
found.kind === Kind.INTERFACE_TYPE_EXTENSION) {
|
|
82
|
+
found.kind = Kind.INTERFACE_TYPE_DEFINITION;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
68
85
|
const knownSubgraphDirectiveDefinitions = new Map(subgraph.typeDefs.definitions.filter(def => def.kind === Kind.DIRECTIVE_DEFINITION).map(def => [def.name.value, def]));
|
|
69
86
|
const leafTypeNames = new Set(specifiedScalarTypes.map(type => type.name));
|
|
70
87
|
for (const def of subgraph.typeDefs.definitions) {
|
|
@@ -2,27 +2,28 @@ import { GraphQLError } from 'graphql';
|
|
|
2
2
|
export function ExternalArgumentMissingRule(context) {
|
|
3
3
|
return {
|
|
4
4
|
ObjectTypeFieldArg(objectState, fieldState, argState) {
|
|
5
|
-
if (argState.
|
|
6
|
-
|
|
7
|
-
return;
|
|
8
|
-
}
|
|
9
|
-
if (fieldState.byGraph.size === argState.byGraph.size) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
const graphsWithRequiredArg = Array.from(argState.byGraph)
|
|
13
|
-
.filter(([graph, arg]) => arg.type.endsWith('!') && fieldState.byGraph.get(graph)?.external !== true)
|
|
14
|
-
.map(([graph]) => graph);
|
|
15
|
-
const externalGraphsWithoutArg = Array.from(fieldState.byGraph.keys()).filter(graph => !argState.byGraph.has(graph) && fieldState.byGraph.get(graph)?.external === true);
|
|
16
|
-
const requiredIn = `subgraph${graphsWithRequiredArg.length > 1 ? 's' : ''} "${graphsWithRequiredArg.map(context.graphIdToName).join('", "')}"`;
|
|
17
|
-
const missingIn = `subgraph${externalGraphsWithoutArg.length > 1 ? 's' : ''} "${externalGraphsWithoutArg.map(context.graphIdToName).join('", "')}"`;
|
|
18
|
-
const fieldCoordinate = `${objectState.name}.${fieldState.name}`;
|
|
19
|
-
const argCoordinate = `${objectState.name}.${fieldState.name}(${argState.name}:)`;
|
|
20
|
-
context.reportError(new GraphQLError(`Field "${fieldCoordinate}" is missing argument "${argCoordinate}" in some subgraphs where it is marked @external: argument "${argCoordinate}" is declared in ${requiredIn} but not in ${missingIn} (where "${fieldCoordinate}" is @external)`, {
|
|
21
|
-
extensions: {
|
|
22
|
-
code: 'EXTERNAL_ARGUMENT_MISSING',
|
|
23
|
-
},
|
|
24
|
-
}));
|
|
5
|
+
if (argState.byGraph.size === 1 && fieldState.byGraph.size === argState.byGraph.size) {
|
|
6
|
+
return;
|
|
25
7
|
}
|
|
8
|
+
if (fieldState.byGraph.size === argState.byGraph.size) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const graphsWithRequiredArg = Array.from(argState.byGraph)
|
|
12
|
+
.filter(([graph, arg]) => fieldState.byGraph.get(graph)?.external !== true)
|
|
13
|
+
.map(([graph]) => graph);
|
|
14
|
+
const externalGraphsWithoutArg = Array.from(fieldState.byGraph.keys()).filter(graph => !argState.byGraph.has(graph) && fieldState.byGraph.get(graph)?.external === true);
|
|
15
|
+
if (!externalGraphsWithoutArg.length) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const requiredIn = `subgraph${graphsWithRequiredArg.length > 1 ? 's' : ''} "${graphsWithRequiredArg.map(context.graphIdToName).join('", "')}"`;
|
|
19
|
+
const missingIn = `subgraph${externalGraphsWithoutArg.length > 1 ? 's' : ''} "${externalGraphsWithoutArg.map(context.graphIdToName).join('", "')}"`;
|
|
20
|
+
const fieldCoordinate = `${objectState.name}.${fieldState.name}`;
|
|
21
|
+
const argCoordinate = `${objectState.name}.${fieldState.name}(${argState.name}:)`;
|
|
22
|
+
context.reportError(new GraphQLError(`Field "${fieldCoordinate}" is missing argument "${argCoordinate}" in some subgraphs where it is marked @external: argument "${argCoordinate}" is declared in ${requiredIn} but not in ${missingIn} (where "${fieldCoordinate}" is @external)`, {
|
|
23
|
+
extensions: {
|
|
24
|
+
code: 'EXTERNAL_ARGUMENT_MISSING',
|
|
25
|
+
},
|
|
26
|
+
}));
|
|
26
27
|
},
|
|
27
28
|
};
|
|
28
29
|
}
|