@wundergraph/composition 0.37.0 → 0.37.1
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 +41 -48
- package/dist/ast/utils.js +2 -2
- package/dist/ast/utils.js.map +1 -1
- package/dist/errors/errors.d.ts +9 -12
- package/dist/errors/errors.js +71 -68
- package/dist/errors/errors.js.map +1 -1
- package/dist/federation/types.d.ts +2 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/normalization/normalization.d.ts +3 -1
- package/dist/normalization/normalization.js +8 -0
- package/dist/normalization/normalization.js.map +1 -1
- package/dist/normalization/types.d.ts +2 -2
- package/dist/resolvability-graph/graph-nodes.d.ts +1 -1
- package/dist/resolvability-graph/graph-nodes.js.map +1 -1
- package/dist/resolvability-graph/graph.d.ts +1 -2
- package/dist/resolvability-graph/graph.js.map +1 -1
- package/dist/resolvability-graph/utils.d.ts +1 -1
- package/dist/resolvability-graph/utils.js.map +1 -1
- package/dist/router-configuration/{router-configuration.d.ts → types.d.ts} +3 -4
- package/dist/router-configuration/types.js +3 -0
- package/dist/router-configuration/types.js.map +1 -0
- package/dist/router-configuration/utils.d.ts +3 -0
- package/dist/router-configuration/{router-configuration.js → utils.js} +9 -1
- package/dist/router-configuration/utils.js.map +1 -0
- package/dist/schema-building/types.d.ts +23 -7
- package/dist/schema-building/types.js.map +1 -1
- package/dist/schema-building/utils.d.ts +3 -6
- package/dist/schema-building/utils.js +11 -8
- package/dist/schema-building/utils.js.map +1 -1
- package/dist/subgraph/types.d.ts +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/utils/composition-version.js +1 -1
- package/dist/utils/string-constants.d.ts +3 -2
- package/dist/utils/string-constants.js +5 -4
- package/dist/utils/string-constants.js.map +1 -1
- package/dist/utils/types.d.ts +38 -0
- package/dist/utils/utils.d.ts +0 -48
- package/dist/utils/utils.js +0 -10
- package/dist/utils/utils.js.map +1 -1
- package/dist/v1/federation/federation-factory.d.ts +4 -4
- package/dist/v1/federation/federation-factory.js +46 -35
- package/dist/v1/federation/federation-factory.js.map +1 -1
- package/dist/v1/federation/utils.d.ts +7 -8
- package/dist/v1/federation/utils.js +22 -20
- package/dist/v1/federation/utils.js.map +1 -1
- package/dist/v1/normalization/normalization-factory.d.ts +19 -22
- package/dist/v1/normalization/normalization-factory.js +568 -70
- package/dist/v1/normalization/normalization-factory.js.map +1 -1
- package/dist/v1/normalization/types.d.ts +49 -0
- package/dist/v1/normalization/types.js +3 -0
- package/dist/v1/normalization/types.js.map +1 -0
- package/dist/v1/normalization/utils.d.ts +7 -42
- package/dist/v1/normalization/utils.js +59 -382
- package/dist/v1/normalization/utils.js.map +1 -1
- package/dist/v1/normalization/walkers.js +36 -23
- package/dist/v1/normalization/walkers.js.map +1 -1
- package/dist/v1/utils/utils.d.ts +15 -12
- package/dist/v1/utils/utils.js +53 -47
- package/dist/v1/utils/utils.js.map +1 -1
- package/dist/v1/warnings/warnings.d.ts +4 -3
- package/dist/v1/warnings/warnings.js +47 -17
- package/dist/v1/warnings/warnings.js.map +1 -1
- package/dist/warnings/{warnings.js → types.js} +1 -1
- package/dist/warnings/types.js.map +1 -0
- package/package.json +2 -2
- package/dist/router-configuration/router-configuration.js.map +0 -1
- package/dist/warnings/warnings.js.map +0 -1
- /package/dist/warnings/{warnings.d.ts → types.d.ts} +0 -0
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.newKeyFieldSetData = newKeyFieldSetData;
|
|
4
3
|
exports.newFieldSetData = newFieldSetData;
|
|
5
|
-
exports.addFieldNamesToConfigurationData = addFieldNamesToConfigurationData;
|
|
6
4
|
exports.extractFieldSetValue = extractFieldSetValue;
|
|
7
5
|
exports.getNormalizedFieldSet = getNormalizedFieldSet;
|
|
6
|
+
exports.getInitialFieldCoordsPath = getInitialFieldCoordsPath;
|
|
8
7
|
exports.validateKeyFieldSets = validateKeyFieldSets;
|
|
9
|
-
exports.
|
|
8
|
+
exports.getConditionalFieldSetDirectiveName = getConditionalFieldSetDirectiveName;
|
|
10
9
|
exports.isNodeQuery = isNodeQuery;
|
|
11
10
|
exports.validateArgumentTemplateReferences = validateArgumentTemplateReferences;
|
|
12
11
|
exports.initializeDirectiveDefinitionDatas = initializeDirectiveDefinitionDatas;
|
|
@@ -14,43 +13,16 @@ const graphql_1 = require("graphql");
|
|
|
14
13
|
const utils_1 = require("../../ast/utils");
|
|
15
14
|
const errors_1 = require("../../errors/errors");
|
|
16
15
|
const constants_1 = require("../utils/constants");
|
|
17
|
-
const router_configuration_1 = require("../../router-configuration/router-configuration");
|
|
18
16
|
const ast_1 = require("../../schema-building/ast");
|
|
19
|
-
const utils_2 = require("../../schema-building/utils");
|
|
20
|
-
const warnings_1 = require("../warnings/warnings");
|
|
21
17
|
const directive_definition_data_1 = require("./directive-definition-data");
|
|
22
18
|
const string_constants_1 = require("../../utils/string-constants");
|
|
23
|
-
const
|
|
24
|
-
function newKeyFieldSetData() {
|
|
25
|
-
return {
|
|
26
|
-
isUnresolvableByKeyFieldSet: new Map(),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
19
|
+
const utils_2 = require("../../utils/utils");
|
|
29
20
|
function newFieldSetData() {
|
|
30
21
|
return {
|
|
31
22
|
provides: new Map(),
|
|
32
23
|
requires: new Map(),
|
|
33
24
|
};
|
|
34
25
|
}
|
|
35
|
-
function addFieldNamesToConfigurationData(fieldDataByFieldName, configurationData) {
|
|
36
|
-
const externalFieldNames = new Set();
|
|
37
|
-
for (const [fieldName, fieldContainer] of fieldDataByFieldName) {
|
|
38
|
-
if (fieldContainer.directivesByDirectiveName.has(string_constants_1.EXTERNAL)) {
|
|
39
|
-
if (configurationData.externalFieldNames) {
|
|
40
|
-
configurationData.externalFieldNames.add(fieldName);
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
externalFieldNames.add(fieldName);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
configurationData.fieldNames.add(fieldName);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (externalFieldNames.size > 0) {
|
|
51
|
-
configurationData.externalFieldNames = externalFieldNames;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
26
|
function extractFieldSetValue(name, map, directives) {
|
|
55
27
|
// ALl directive validation errors are accounted for later
|
|
56
28
|
// Requires and provides should not be repeatable, so the length should be no more than 1
|
|
@@ -78,249 +50,28 @@ function getNormalizedFieldSet(documentNode) {
|
|
|
78
50
|
*/
|
|
79
51
|
return (0, graphql_1.print)((0, utils_1.lexicographicallySortDocumentNode)(documentNode)).replaceAll(/\s+/g, ' ').slice(2, -2);
|
|
80
52
|
}
|
|
81
|
-
function
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
return [`${directiveParentTypeName}.${directiveFieldName}`];
|
|
85
|
-
default:
|
|
86
|
-
return [];
|
|
53
|
+
function getInitialFieldCoordsPath(isProvides, directiveCoords) {
|
|
54
|
+
if (isProvides) {
|
|
55
|
+
return [directiveCoords];
|
|
87
56
|
}
|
|
57
|
+
return [];
|
|
88
58
|
}
|
|
89
|
-
function
|
|
90
|
-
|
|
91
|
-
const { error, documentNode } = (0, utils_1.safeParse)('{' + fieldSet + '}');
|
|
92
|
-
if (error || !documentNode) {
|
|
93
|
-
return { errorMessage: (0, errors_1.unparsableFieldSetErrorMessage)(fieldSet, error) };
|
|
94
|
-
}
|
|
95
|
-
const parentDatas = [selectionSetParentData];
|
|
96
|
-
const definedFields = [];
|
|
97
|
-
const fieldCoordinatesPath = getInitialFieldCoordinatesPath(fieldSetDirective, directiveParentTypeName, directiveFieldName);
|
|
98
|
-
const fieldPath = [directiveFieldName];
|
|
99
|
-
const externalAncestors = new Set();
|
|
100
|
-
let errorMessage;
|
|
101
|
-
let currentDepth = -1;
|
|
102
|
-
let shouldDefineSelectionSet = true;
|
|
103
|
-
let lastFieldName = directiveFieldName;
|
|
104
|
-
(0, graphql_1.visit)(documentNode, {
|
|
105
|
-
Argument: {
|
|
106
|
-
enter() {
|
|
107
|
-
return false;
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
Field: {
|
|
111
|
-
enter(node) {
|
|
112
|
-
const parentData = parentDatas[currentDepth];
|
|
113
|
-
const parentTypeName = parentData.name;
|
|
114
|
-
if (parentData.kind === graphql_1.Kind.UNION_TYPE_DEFINITION) {
|
|
115
|
-
errorMessage = (0, errors_1.invalidSelectionOnUnionErrorMessage)(fieldSet, fieldCoordinatesPath, parentTypeName);
|
|
116
|
-
return graphql_1.BREAK;
|
|
117
|
-
}
|
|
118
|
-
const fieldName = node.name.value;
|
|
119
|
-
const currentFieldCoords = `${parentTypeName}.${fieldName}`;
|
|
120
|
-
nf.unvalidatedExternalFieldCoords.delete(currentFieldCoords);
|
|
121
|
-
// If an object-like was just visited, a selection set should have been entered
|
|
122
|
-
if (shouldDefineSelectionSet) {
|
|
123
|
-
errorMessage = (0, errors_1.invalidSelectionSetErrorMessage)(fieldSet, fieldCoordinatesPath, parentTypeName, (0, utils_3.kindToTypeString)(parentData.kind));
|
|
124
|
-
return graphql_1.BREAK;
|
|
125
|
-
}
|
|
126
|
-
fieldCoordinatesPath.push(currentFieldCoords);
|
|
127
|
-
fieldPath.push(fieldName);
|
|
128
|
-
lastFieldName = fieldName;
|
|
129
|
-
const fieldData = parentData.fieldDataByFieldName.get(fieldName);
|
|
130
|
-
// undefined if the field does not exist on the parent
|
|
131
|
-
if (!fieldData) {
|
|
132
|
-
errorMessage = (0, errors_1.undefinedFieldInFieldSetErrorMessage)(fieldSet, parentTypeName, fieldName);
|
|
133
|
-
return graphql_1.BREAK;
|
|
134
|
-
}
|
|
135
|
-
if (definedFields[currentDepth].has(fieldName)) {
|
|
136
|
-
errorMessage = (0, errors_1.duplicateFieldInFieldSetErrorMessage)(fieldSet, currentFieldCoords);
|
|
137
|
-
return graphql_1.BREAK;
|
|
138
|
-
}
|
|
139
|
-
definedFields[currentDepth].add(fieldName);
|
|
140
|
-
const isExternal = fieldData.isExternalBySubgraphName.get(nf.subgraphName);
|
|
141
|
-
const namedTypeName = (0, ast_1.getTypeNodeNamedTypeName)(fieldData.node.type);
|
|
142
|
-
// The child could itself be a parent
|
|
143
|
-
const namedTypeData = nf.parentDefinitionDataByTypeName.get(namedTypeName);
|
|
144
|
-
// The base scalars are not in the parents map
|
|
145
|
-
if (constants_1.BASE_SCALARS.has(namedTypeName) ||
|
|
146
|
-
namedTypeData?.kind === graphql_1.Kind.SCALAR_TYPE_DEFINITION ||
|
|
147
|
-
namedTypeData?.kind === graphql_1.Kind.ENUM_TYPE_DEFINITION) {
|
|
148
|
-
if (externalAncestors.size < 1 && !isExternal) {
|
|
149
|
-
if (nf.isSubgraphVersionTwo) {
|
|
150
|
-
nf.errors.push((0, errors_1.nonExternalConditionalFieldError)(`${directiveParentTypeName}.${directiveFieldName}`, nf.subgraphName, currentFieldCoords, fieldSet, fieldSetDirective));
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
/* In V1, @requires and @provides do not need to declare any part of the field set @external.
|
|
154
|
-
* It would appear that any such non-external fields are treated as if they are non-conditionally provided.
|
|
155
|
-
* */
|
|
156
|
-
nf.warnings.push((0, warnings_1.nonExternalConditionalFieldWarning)(`${directiveParentTypeName}.${directiveFieldName}`, nf.subgraphName, currentFieldCoords, fieldSet, fieldSetDirective));
|
|
157
|
-
}
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
const conditionalFieldData = (0, utils_3.getValueOrDefault)(nf.conditionalFieldDataByCoordinates, currentFieldCoords, utils_2.newConditionalFieldData);
|
|
161
|
-
const fieldSetCondition = (0, router_configuration_1.newFieldSetConditionData)({
|
|
162
|
-
fieldCoordinatesPath: [...fieldCoordinatesPath],
|
|
163
|
-
fieldPath: [...fieldPath],
|
|
164
|
-
});
|
|
165
|
-
fieldSetDirective === utils_2.FieldSetDirective.PROVIDES
|
|
166
|
-
? conditionalFieldData.providedBy.push(fieldSetCondition)
|
|
167
|
-
: conditionalFieldData.requiredBy.push(fieldSetCondition);
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
if (!namedTypeData) {
|
|
171
|
-
// Should not be possible to receive this error
|
|
172
|
-
errorMessage = (0, errors_1.unknownTypeInFieldSetErrorMessage)(fieldSet, currentFieldCoords, namedTypeName);
|
|
173
|
-
return graphql_1.BREAK;
|
|
174
|
-
}
|
|
175
|
-
if (isExternal) {
|
|
176
|
-
const data = (0, utils_3.getValueOrDefault)(nf.conditionalFieldDataByCoordinates, currentFieldCoords, utils_2.newConditionalFieldData);
|
|
177
|
-
switch (fieldSetDirective) {
|
|
178
|
-
case utils_2.FieldSetDirective.PROVIDES:
|
|
179
|
-
data.providedBy.push((0, router_configuration_1.newFieldSetConditionData)({
|
|
180
|
-
fieldCoordinatesPath: [...fieldCoordinatesPath],
|
|
181
|
-
fieldPath: [...fieldPath],
|
|
182
|
-
}));
|
|
183
|
-
break;
|
|
184
|
-
default:
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
externalAncestors.add(currentFieldCoords);
|
|
188
|
-
}
|
|
189
|
-
if (namedTypeData.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION ||
|
|
190
|
-
namedTypeData.kind === graphql_1.Kind.INTERFACE_TYPE_DEFINITION ||
|
|
191
|
-
namedTypeData.kind === graphql_1.Kind.UNION_TYPE_DEFINITION) {
|
|
192
|
-
shouldDefineSelectionSet = true;
|
|
193
|
-
parentDatas.push(namedTypeData);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
},
|
|
197
|
-
leave() {
|
|
198
|
-
externalAncestors.delete(fieldCoordinatesPath.pop() || '');
|
|
199
|
-
fieldPath.pop();
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
InlineFragment: {
|
|
203
|
-
enter(node) {
|
|
204
|
-
const parentData = parentDatas[currentDepth];
|
|
205
|
-
const parentTypeName = parentData.name;
|
|
206
|
-
const fieldCoordinates = fieldCoordinatesPath.length < 1
|
|
207
|
-
? selectionSetParentData.name
|
|
208
|
-
: fieldCoordinatesPath[fieldCoordinatesPath.length - 1];
|
|
209
|
-
if (!node.typeCondition) {
|
|
210
|
-
errorMessage = (0, errors_1.inlineFragmentWithoutTypeConditionErrorMessage)(fieldSet, fieldCoordinates);
|
|
211
|
-
return graphql_1.BREAK;
|
|
212
|
-
}
|
|
213
|
-
const typeConditionName = node.typeCondition.name.value;
|
|
214
|
-
// It's possible to infinitely define fragments
|
|
215
|
-
if (typeConditionName === parentTypeName) {
|
|
216
|
-
parentDatas.push(parentData);
|
|
217
|
-
shouldDefineSelectionSet = true;
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
if (!(0, utils_1.isKindAbstract)(parentData.kind)) {
|
|
221
|
-
errorMessage = (0, errors_1.invalidInlineFragmentTypeErrorMessage)(fieldSet, fieldCoordinatesPath, typeConditionName, parentTypeName);
|
|
222
|
-
return graphql_1.BREAK;
|
|
223
|
-
}
|
|
224
|
-
const fragmentNamedTypeData = nf.parentDefinitionDataByTypeName.get(typeConditionName);
|
|
225
|
-
if (!fragmentNamedTypeData) {
|
|
226
|
-
errorMessage = (0, errors_1.unknownInlineFragmentTypeConditionErrorMessage)(fieldSet, fieldCoordinatesPath, parentTypeName, typeConditionName);
|
|
227
|
-
return graphql_1.BREAK;
|
|
228
|
-
}
|
|
229
|
-
shouldDefineSelectionSet = true;
|
|
230
|
-
switch (fragmentNamedTypeData.kind) {
|
|
231
|
-
case graphql_1.Kind.INTERFACE_TYPE_DEFINITION: {
|
|
232
|
-
if (!fragmentNamedTypeData.implementedInterfaceTypeNames.has(parentTypeName)) {
|
|
233
|
-
break;
|
|
234
|
-
}
|
|
235
|
-
parentDatas.push(fragmentNamedTypeData);
|
|
236
|
-
return;
|
|
237
|
-
}
|
|
238
|
-
case graphql_1.Kind.OBJECT_TYPE_DEFINITION: {
|
|
239
|
-
const concreteTypeNames = nf.concreteTypeNamesByAbstractTypeName.get(parentTypeName);
|
|
240
|
-
if (!concreteTypeNames || !concreteTypeNames.has(typeConditionName)) {
|
|
241
|
-
break;
|
|
242
|
-
}
|
|
243
|
-
parentDatas.push(fragmentNamedTypeData);
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
case graphql_1.Kind.UNION_TYPE_DEFINITION: {
|
|
247
|
-
parentDatas.push(fragmentNamedTypeData);
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
default: {
|
|
251
|
-
errorMessage = (0, errors_1.invalidInlineFragmentTypeConditionTypeErrorMessage)(fieldSet, fieldCoordinatesPath, parentTypeName, typeConditionName, (0, utils_3.kindToTypeString)(fragmentNamedTypeData.kind));
|
|
252
|
-
return graphql_1.BREAK;
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
errorMessage = (0, errors_1.invalidInlineFragmentTypeConditionErrorMessage)(fieldSet, fieldCoordinatesPath, typeConditionName, (0, utils_3.kindToTypeString)(parentData.kind), parentTypeName);
|
|
256
|
-
return graphql_1.BREAK;
|
|
257
|
-
},
|
|
258
|
-
},
|
|
259
|
-
SelectionSet: {
|
|
260
|
-
enter() {
|
|
261
|
-
if (!shouldDefineSelectionSet) {
|
|
262
|
-
const parentData = parentDatas[currentDepth];
|
|
263
|
-
if (parentData.kind === graphql_1.Kind.UNION_TYPE_DEFINITION) {
|
|
264
|
-
// Should never happen
|
|
265
|
-
errorMessage = (0, errors_1.unparsableFieldSetSelectionErrorMessage)(fieldSet, lastFieldName);
|
|
266
|
-
return graphql_1.BREAK;
|
|
267
|
-
}
|
|
268
|
-
const fieldData = parentData.fieldDataByFieldName.get(lastFieldName);
|
|
269
|
-
if (!fieldData) {
|
|
270
|
-
errorMessage = (0, errors_1.undefinedFieldInFieldSetErrorMessage)(fieldSet, parentData.name, lastFieldName);
|
|
271
|
-
return graphql_1.BREAK;
|
|
272
|
-
}
|
|
273
|
-
const fieldNamedTypeName = (0, ast_1.getTypeNodeNamedTypeName)(fieldData.node.type);
|
|
274
|
-
// If the child is not found, it's a base scalar. Undefined types would have already been handled.
|
|
275
|
-
const namedTypeData = nf.parentDefinitionDataByTypeName.get(fieldNamedTypeName);
|
|
276
|
-
const childKind = namedTypeData ? namedTypeData.kind : graphql_1.Kind.SCALAR_TYPE_DEFINITION;
|
|
277
|
-
errorMessage = (0, errors_1.invalidSelectionSetDefinitionErrorMessage)(fieldSet, fieldCoordinatesPath, fieldNamedTypeName, (0, utils_3.kindToTypeString)(childKind));
|
|
278
|
-
return graphql_1.BREAK;
|
|
279
|
-
}
|
|
280
|
-
currentDepth += 1;
|
|
281
|
-
shouldDefineSelectionSet = false;
|
|
282
|
-
if (currentDepth < 0 || currentDepth >= parentDatas.length) {
|
|
283
|
-
errorMessage = (0, errors_1.unparsableFieldSetSelectionErrorMessage)(fieldSet, lastFieldName);
|
|
284
|
-
return graphql_1.BREAK;
|
|
285
|
-
}
|
|
286
|
-
definedFields.push(new Set());
|
|
287
|
-
},
|
|
288
|
-
leave() {
|
|
289
|
-
if (shouldDefineSelectionSet) {
|
|
290
|
-
const parentData = parentDatas[currentDepth + 1];
|
|
291
|
-
errorMessage = (0, errors_1.invalidSelectionSetErrorMessage)(fieldSet, fieldCoordinatesPath, parentData.name, (0, utils_3.kindToTypeString)(parentData.kind));
|
|
292
|
-
shouldDefineSelectionSet = false;
|
|
293
|
-
}
|
|
294
|
-
// Empty selection sets would be a parse error, so it is unnecessary to handle them
|
|
295
|
-
currentDepth -= 1;
|
|
296
|
-
parentDatas.pop();
|
|
297
|
-
definedFields.pop();
|
|
298
|
-
},
|
|
299
|
-
},
|
|
300
|
-
});
|
|
301
|
-
if (errorMessage) {
|
|
302
|
-
return { errorMessage };
|
|
303
|
-
}
|
|
304
|
-
return { configuration: { fieldName: directiveFieldName, selectionSet: getNormalizedFieldSet(documentNode) } };
|
|
305
|
-
}
|
|
306
|
-
function validateKeyFieldSets(nf, entityParentData, nonResolvableByKeyFieldSet, fieldNames) {
|
|
307
|
-
const isEntityInterface = nf.entityInterfaceDataByTypeName.has(entityParentData.name);
|
|
59
|
+
function validateKeyFieldSets(nf, entityParentData, keyFieldSetDataByFieldSet, fieldNames) {
|
|
60
|
+
const entityInterfaceData = nf.entityInterfaceDataByTypeName.get(entityParentData.name);
|
|
308
61
|
const entityTypeName = entityParentData.name;
|
|
309
|
-
const errorMessages = [];
|
|
310
62
|
const configurations = [];
|
|
311
|
-
const keyFieldNames = new Set();
|
|
312
63
|
const allKeyFieldSetPaths = [];
|
|
313
64
|
// If the key is on an entity interface/interface object, an entity data node should not be propagated
|
|
314
|
-
const entityDataNode =
|
|
65
|
+
const entityDataNode = entityInterfaceData ? undefined : nf.internalGraph.addEntityDataNode(entityParentData.name);
|
|
315
66
|
const graphNode = nf.internalGraph.addOrUpdateNode(entityParentData.name);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
errorMessages.push((0, errors_1.unparsableFieldSetErrorMessage)(fieldSet, error));
|
|
321
|
-
continue;
|
|
67
|
+
let keyNumber = 0;
|
|
68
|
+
for (const [fieldSet, { documentNode, isUnresolvable, rawFieldSet }] of keyFieldSetDataByFieldSet) {
|
|
69
|
+
if (entityInterfaceData) {
|
|
70
|
+
entityInterfaceData.resolvable ||= !isUnresolvable;
|
|
322
71
|
}
|
|
323
|
-
|
|
72
|
+
keyNumber += 1;
|
|
73
|
+
const errorMessages = [];
|
|
74
|
+
const parentDatas = [entityParentData];
|
|
324
75
|
const definedFields = [];
|
|
325
76
|
const currentPath = [];
|
|
326
77
|
const keyFieldSetPaths = new Set();
|
|
@@ -332,59 +83,52 @@ function validateKeyFieldSets(nf, entityParentData, nonResolvableByKeyFieldSet,
|
|
|
332
83
|
enter(node) {
|
|
333
84
|
// Fields that define arguments are never allowed in a key FieldSet
|
|
334
85
|
// However, at this stage, it actually means the argument is undefined on the field
|
|
335
|
-
errorMessages.push((0, errors_1.unexpectedArgumentErrorMessage)(
|
|
86
|
+
errorMessages.push((0, errors_1.unexpectedArgumentErrorMessage)(rawFieldSet, `${parentDatas[currentDepth].name}.${lastFieldName}`, node.name.value));
|
|
336
87
|
return graphql_1.BREAK;
|
|
337
88
|
},
|
|
338
89
|
},
|
|
339
90
|
Field: {
|
|
340
91
|
enter(node) {
|
|
341
|
-
const
|
|
342
|
-
const parentData = parentWithFieldsDatas[currentDepth];
|
|
92
|
+
const parentData = parentDatas[currentDepth];
|
|
343
93
|
const parentTypeName = parentData.name;
|
|
344
|
-
|
|
345
|
-
const fieldCoords = `${parentTypeName}.${fieldName}`;
|
|
346
|
-
nf.unvalidatedExternalFieldCoords.delete(fieldCoords);
|
|
347
|
-
// If an object-like was just visited, a selection set should have been entered
|
|
94
|
+
// If a composite type was just visited, a selection set should have been entered
|
|
348
95
|
if (shouldDefineSelectionSet) {
|
|
349
|
-
|
|
96
|
+
const lastFieldCoords = `${parentTypeName}.${lastFieldName}`;
|
|
97
|
+
const lastFieldData = parentData.fieldDataByFieldName.get(lastFieldName);
|
|
98
|
+
if (!lastFieldData) {
|
|
99
|
+
errorMessages.push((0, errors_1.undefinedFieldInFieldSetErrorMessage)(rawFieldSet, lastFieldCoords, lastFieldName));
|
|
100
|
+
return graphql_1.BREAK;
|
|
101
|
+
}
|
|
102
|
+
const lastFieldNamedTypeName = (0, ast_1.getTypeNodeNamedTypeName)(lastFieldData.node.type);
|
|
103
|
+
// If the child is not found, it's a base scalar. Undefined types would have already been handled.
|
|
104
|
+
const namedTypeData = nf.parentDefinitionDataByTypeName.get(lastFieldNamedTypeName);
|
|
105
|
+
const namedTypeKind = namedTypeData ? namedTypeData.kind : graphql_1.Kind.SCALAR_TYPE_DEFINITION;
|
|
106
|
+
errorMessages.push((0, errors_1.invalidSelectionSetErrorMessage)(rawFieldSet, [lastFieldCoords], lastFieldNamedTypeName, (0, utils_2.kindToTypeString)(namedTypeKind)));
|
|
350
107
|
return graphql_1.BREAK;
|
|
351
108
|
}
|
|
109
|
+
const fieldName = node.name.value;
|
|
110
|
+
const fieldCoords = `${parentTypeName}.${fieldName}`;
|
|
352
111
|
lastFieldName = fieldName;
|
|
353
112
|
const fieldData = parentData.fieldDataByFieldName.get(fieldName);
|
|
354
113
|
// undefined if the field does not exist on the parent
|
|
355
114
|
if (!fieldData) {
|
|
356
|
-
errorMessages.push((0, errors_1.undefinedFieldInFieldSetErrorMessage)(
|
|
115
|
+
errorMessages.push((0, errors_1.undefinedFieldInFieldSetErrorMessage)(rawFieldSet, parentTypeName, fieldName));
|
|
357
116
|
return graphql_1.BREAK;
|
|
358
117
|
}
|
|
359
118
|
// TODO navigate already provided keys
|
|
360
119
|
if (fieldData.argumentDataByArgumentName.size) {
|
|
361
|
-
errorMessages.push((0, errors_1.argumentsInKeyFieldSetErrorMessage)(
|
|
120
|
+
errorMessages.push((0, errors_1.argumentsInKeyFieldSetErrorMessage)(rawFieldSet, fieldCoords));
|
|
362
121
|
return graphql_1.BREAK;
|
|
363
122
|
}
|
|
364
123
|
if (definedFields[currentDepth].has(fieldName)) {
|
|
365
|
-
errorMessages.push((0, errors_1.duplicateFieldInFieldSetErrorMessage)(
|
|
124
|
+
errorMessages.push((0, errors_1.duplicateFieldInFieldSetErrorMessage)(rawFieldSet, fieldCoords));
|
|
366
125
|
return graphql_1.BREAK;
|
|
367
126
|
}
|
|
368
127
|
currentPath.push(fieldName);
|
|
369
128
|
// Fields that form part of an entity key are intrinsically shareable
|
|
370
129
|
fieldData.isShareableBySubgraphName.set(nf.subgraphName, true);
|
|
371
130
|
definedFields[currentDepth].add(fieldName);
|
|
372
|
-
|
|
373
|
-
* If a field is external, but it's part of a key FieldSet, it should be included in its respective
|
|
374
|
-
* root or child node */
|
|
375
|
-
if (currentDepth === 0) {
|
|
376
|
-
keyFieldNames.add(fieldName);
|
|
377
|
-
fieldNames.add(fieldName);
|
|
378
|
-
}
|
|
379
|
-
else {
|
|
380
|
-
const nestedConfigurationData = nf.configurationDataByParentTypeName.get(parentTypeName);
|
|
381
|
-
if (!nestedConfigurationData) {
|
|
382
|
-
errorMessages.push((0, errors_1.invalidConfigurationDataErrorMessage)(parentTypeName, fieldName, fieldSet));
|
|
383
|
-
return graphql_1.BREAK;
|
|
384
|
-
}
|
|
385
|
-
nestedConfigurationData.fieldNames.add(fieldName);
|
|
386
|
-
}
|
|
387
|
-
(0, utils_3.getValueOrDefault)(nf.keyFieldNamesByParentTypeName, parentTypeName, () => new Set()).add(fieldName);
|
|
131
|
+
(0, utils_2.getValueOrDefault)(nf.keyFieldNamesByParentTypeName, parentTypeName, () => new Set()).add(fieldName);
|
|
388
132
|
const namedTypeName = (0, ast_1.getTypeNodeNamedTypeName)(fieldData.node.type);
|
|
389
133
|
// The base scalars are not in the parents map
|
|
390
134
|
if (constants_1.BASE_SCALARS.has(namedTypeName)) {
|
|
@@ -396,17 +140,17 @@ function validateKeyFieldSets(nf, entityParentData, nonResolvableByKeyFieldSet,
|
|
|
396
140
|
const namedTypeData = nf.parentDefinitionDataByTypeName.get(namedTypeName);
|
|
397
141
|
if (!namedTypeData) {
|
|
398
142
|
// Should not be possible to receive this error
|
|
399
|
-
errorMessages.push((0, errors_1.unknownTypeInFieldSetErrorMessage)(
|
|
143
|
+
errorMessages.push((0, errors_1.unknownTypeInFieldSetErrorMessage)(rawFieldSet, fieldCoords, namedTypeName));
|
|
400
144
|
return graphql_1.BREAK;
|
|
401
145
|
}
|
|
402
146
|
if (namedTypeData.kind === graphql_1.Kind.OBJECT_TYPE_DEFINITION) {
|
|
403
147
|
shouldDefineSelectionSet = true;
|
|
404
|
-
|
|
148
|
+
parentDatas.push(namedTypeData);
|
|
405
149
|
return;
|
|
406
150
|
}
|
|
407
151
|
// interfaces and unions are invalid in a key directive
|
|
408
152
|
if ((0, utils_1.isKindAbstract)(namedTypeData.kind)) {
|
|
409
|
-
errorMessages.push((0, errors_1.abstractTypeInKeyFieldSetErrorMessage)(
|
|
153
|
+
errorMessages.push((0, errors_1.abstractTypeInKeyFieldSetErrorMessage)(rawFieldSet, fieldCoords, namedTypeName, (0, utils_2.kindToTypeString)(namedTypeData.kind)));
|
|
410
154
|
return graphql_1.BREAK;
|
|
411
155
|
}
|
|
412
156
|
keyFieldSetPaths.add(currentPath.join(string_constants_1.PERIOD));
|
|
@@ -422,140 +166,73 @@ function validateKeyFieldSets(nf, entityParentData, nonResolvableByKeyFieldSet,
|
|
|
422
166
|
SelectionSet: {
|
|
423
167
|
enter() {
|
|
424
168
|
if (!shouldDefineSelectionSet) {
|
|
425
|
-
const parentData =
|
|
169
|
+
const parentData = parentDatas[currentDepth];
|
|
426
170
|
const parentTypeName = parentData.name;
|
|
427
171
|
const fieldCoordinates = `${parentTypeName}.${lastFieldName}`;
|
|
428
172
|
// If the last field is not an object-like
|
|
429
173
|
const fieldData = parentData.fieldDataByFieldName.get(lastFieldName);
|
|
430
174
|
if (!fieldData) {
|
|
431
|
-
errorMessages.push((0, errors_1.undefinedFieldInFieldSetErrorMessage)(
|
|
175
|
+
errorMessages.push((0, errors_1.undefinedFieldInFieldSetErrorMessage)(rawFieldSet, fieldCoordinates, lastFieldName));
|
|
432
176
|
return graphql_1.BREAK;
|
|
433
177
|
}
|
|
434
178
|
const fieldNamedTypeName = (0, ast_1.getTypeNodeNamedTypeName)(fieldData.node.type);
|
|
435
179
|
// If the child is not found, it's a base scalar. Undefined types would have already been handled.
|
|
436
180
|
const namedTypeData = nf.parentDefinitionDataByTypeName.get(fieldNamedTypeName);
|
|
437
181
|
const namedTypeKind = namedTypeData ? namedTypeData.kind : graphql_1.Kind.SCALAR_TYPE_DEFINITION;
|
|
438
|
-
errorMessages.push((0, errors_1.invalidSelectionSetDefinitionErrorMessage)(
|
|
182
|
+
errorMessages.push((0, errors_1.invalidSelectionSetDefinitionErrorMessage)(rawFieldSet, [fieldCoordinates], fieldNamedTypeName, (0, utils_2.kindToTypeString)(namedTypeKind)));
|
|
439
183
|
return graphql_1.BREAK;
|
|
440
184
|
}
|
|
441
185
|
currentDepth += 1;
|
|
442
186
|
shouldDefineSelectionSet = false;
|
|
443
|
-
if (currentDepth < 0 || currentDepth >=
|
|
444
|
-
errorMessages.push((0, errors_1.unparsableFieldSetSelectionErrorMessage)(
|
|
187
|
+
if (currentDepth < 0 || currentDepth >= parentDatas.length) {
|
|
188
|
+
errorMessages.push((0, errors_1.unparsableFieldSetSelectionErrorMessage)(rawFieldSet, lastFieldName));
|
|
445
189
|
return graphql_1.BREAK;
|
|
446
190
|
}
|
|
447
191
|
definedFields.push(new Set());
|
|
448
192
|
},
|
|
449
193
|
leave() {
|
|
450
194
|
if (shouldDefineSelectionSet) {
|
|
451
|
-
const grandparentData =
|
|
195
|
+
const grandparentData = parentDatas[currentDepth];
|
|
452
196
|
const grandparentTypeName = grandparentData.name;
|
|
453
|
-
const parentData =
|
|
197
|
+
const parentData = parentDatas[currentDepth + 1];
|
|
454
198
|
const fieldCoordinates = `${grandparentTypeName}.${lastFieldName}`;
|
|
455
|
-
errorMessages.push((0, errors_1.invalidSelectionSetErrorMessage)(
|
|
199
|
+
errorMessages.push((0, errors_1.invalidSelectionSetErrorMessage)(rawFieldSet, [fieldCoordinates], parentData.name, (0, utils_2.kindToTypeString)(parentData.kind)));
|
|
456
200
|
shouldDefineSelectionSet = false;
|
|
457
201
|
}
|
|
458
202
|
// Empty selection sets would be a parse error, so it is unnecessary to handle them
|
|
459
203
|
currentDepth -= 1;
|
|
460
|
-
|
|
204
|
+
parentDatas.pop();
|
|
461
205
|
definedFields.pop();
|
|
462
206
|
},
|
|
463
207
|
},
|
|
464
208
|
});
|
|
465
209
|
if (errorMessages.length > 0) {
|
|
210
|
+
nf.errors.push((0, errors_1.invalidDirectiveError)(string_constants_1.KEY, entityTypeName, (0, utils_2.numberToOrdinal)(keyNumber), errorMessages));
|
|
466
211
|
continue;
|
|
467
212
|
}
|
|
468
|
-
const normalizedFieldSet = getNormalizedFieldSet(documentNode);
|
|
469
213
|
configurations.push({
|
|
470
214
|
fieldName: '',
|
|
471
|
-
selectionSet:
|
|
472
|
-
...(
|
|
215
|
+
selectionSet: fieldSet,
|
|
216
|
+
...(isUnresolvable ? { disableEntityResolver: true } : {}),
|
|
473
217
|
});
|
|
474
|
-
graphNode.satisfiedFieldSets.add(
|
|
475
|
-
if (
|
|
218
|
+
graphNode.satisfiedFieldSets.add(fieldSet);
|
|
219
|
+
if (isUnresolvable) {
|
|
476
220
|
continue;
|
|
477
221
|
}
|
|
478
|
-
entityDataNode?.addTargetSubgraphByFieldSet(
|
|
222
|
+
entityDataNode?.addTargetSubgraphByFieldSet(fieldSet, nf.subgraphName);
|
|
479
223
|
allKeyFieldSetPaths.push(keyFieldSetPaths);
|
|
480
224
|
}
|
|
481
|
-
if (errorMessages.length) {
|
|
482
|
-
nf.errors.push((0, errors_1.invalidKeyDirectivesError)(entityTypeName, errorMessages));
|
|
483
|
-
return;
|
|
484
|
-
}
|
|
485
225
|
// todo
|
|
486
226
|
// nf.internalGraph.addEntityNode(entityTypeName, allKeyFieldSetPaths);
|
|
487
|
-
if (configurations.length) {
|
|
488
|
-
return configurations;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
function getFieldSetParent(factory, fieldSetDirective, parentData, fieldName, parentTypeName) {
|
|
492
|
-
if (fieldSetDirective !== utils_2.FieldSetDirective.PROVIDES) {
|
|
493
|
-
return { fieldSetParentData: parentData };
|
|
494
|
-
}
|
|
495
|
-
const fieldData = (0, utils_3.getOrThrowError)(parentData.fieldDataByFieldName, fieldName, `${parentTypeName}.fieldDataByFieldName`);
|
|
496
|
-
const fieldNamedTypeName = (0, ast_1.getTypeNodeNamedTypeName)(fieldData.node.type);
|
|
497
|
-
const namedTypeData = factory.parentDefinitionDataByTypeName.get(fieldNamedTypeName);
|
|
498
|
-
// This error should never happen
|
|
499
|
-
if (!namedTypeData) {
|
|
500
|
-
return {
|
|
501
|
-
errorString: (0, errors_1.unknownNamedTypeErrorMessage)(`${parentTypeName}.${fieldName}`, fieldNamedTypeName),
|
|
502
|
-
};
|
|
503
|
-
}
|
|
504
|
-
if (namedTypeData.kind !== graphql_1.Kind.INTERFACE_TYPE_DEFINITION && namedTypeData.kind !== graphql_1.Kind.OBJECT_TYPE_DEFINITION) {
|
|
505
|
-
return {
|
|
506
|
-
errorString: (0, errors_1.incompatibleTypeWithProvidesErrorMessage)(`${parentTypeName}.${fieldName}`, fieldNamedTypeName),
|
|
507
|
-
};
|
|
508
|
-
}
|
|
509
|
-
return { fieldSetParentData: namedTypeData };
|
|
510
|
-
}
|
|
511
|
-
function validateProvidesOrRequires(nf, parentData, fieldSetByFieldName, fieldSetDirective) {
|
|
512
|
-
const errorMessages = [];
|
|
513
|
-
const configurations = [];
|
|
514
|
-
const parentTypeName = (0, utils_2.getParentTypeName)(parentData);
|
|
515
|
-
for (const [fieldName, fieldSet] of fieldSetByFieldName) {
|
|
516
|
-
/* It is possible to encounter a field before encountering the type definition.
|
|
517
|
-
Consequently, at that time, it is unknown whether the named type is an entity.
|
|
518
|
-
If it isn't, the @provides directive does not make sense and can be ignored.
|
|
519
|
-
*/
|
|
520
|
-
const { fieldSetParentData, errorString } = getFieldSetParent(nf, fieldSetDirective, parentData, fieldName, parentTypeName);
|
|
521
|
-
const fieldCoords = `${parentTypeName}.${fieldName}`;
|
|
522
|
-
if (errorString) {
|
|
523
|
-
errorMessages.push(errorString);
|
|
524
|
-
continue;
|
|
525
|
-
}
|
|
526
|
-
if (!fieldSetParentData) {
|
|
527
|
-
continue;
|
|
528
|
-
}
|
|
529
|
-
const { errorMessage, configuration } = validateNonRepeatableFieldSet(nf, fieldSetParentData, fieldSet, fieldName, fieldSetDirective, parentTypeName);
|
|
530
|
-
if (errorMessage) {
|
|
531
|
-
errorMessages.push(` On "${fieldCoords}" —` + errorMessage);
|
|
532
|
-
continue;
|
|
533
|
-
}
|
|
534
|
-
if (configuration) {
|
|
535
|
-
configurations.push(configuration);
|
|
536
|
-
continue;
|
|
537
|
-
}
|
|
538
|
-
// Should never happen
|
|
539
|
-
throw (0, errors_1.invalidConfigurationResultFatalError)(fieldCoords);
|
|
540
|
-
}
|
|
541
|
-
if (errorMessages.length > 0) {
|
|
542
|
-
nf.errors.push((0, errors_1.invalidProvidesOrRequiresDirectivesError)(fieldSetDirective, errorMessages));
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
227
|
if (configurations.length > 0) {
|
|
546
228
|
return configurations;
|
|
547
229
|
}
|
|
548
230
|
}
|
|
549
|
-
function
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
if (provides) {
|
|
553
|
-
configurationData.provides = provides;
|
|
554
|
-
}
|
|
555
|
-
const requires = validateProvidesOrRequires(nf, parentData, fieldSetData.requires, utils_2.FieldSetDirective.REQUIRES);
|
|
556
|
-
if (requires) {
|
|
557
|
-
configurationData.requires = requires;
|
|
231
|
+
function getConditionalFieldSetDirectiveName(isProvides) {
|
|
232
|
+
if (isProvides) {
|
|
233
|
+
return string_constants_1.PROVIDES;
|
|
558
234
|
}
|
|
235
|
+
return string_constants_1.REQUIRES;
|
|
559
236
|
}
|
|
560
237
|
function isNodeQuery(typeName, operationTypeNode) {
|
|
561
238
|
return typeName === string_constants_1.QUERY || operationTypeNode === graphql_1.OperationTypeNode.QUERY;
|