@theguild/federation-composition 0.11.3 → 0.11.4-alpha-20240626075710-a99d3f0
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/validation/validate-state.js +1 -1
- package/cjs/supergraph/validation/rules/interface-subtype-rule.js +115 -0
- package/cjs/supergraph/validation/validate-supergraph.js +2 -0
- package/esm/graphql/contains-supergraph-spec.js +1 -1
- package/esm/subgraph/validation/validate-state.js +1 -1
- package/esm/supergraph/validation/rules/interface-subtype-rule.js +110 -0
- package/esm/supergraph/validation/validate-supergraph.js +2 -0
- package/package.json +1 -1
- package/typings/supergraph/validation/rules/interface-subtype-rule.d.cts +6 -0
- package/typings/supergraph/validation/rules/interface-subtype-rule.d.ts +6 -0
|
@@ -344,7 +344,7 @@ function validateTypeImplementsInterface(state, implementationsMap, reportError,
|
|
|
344
344
|
}
|
|
345
345
|
if (!isTypeSubTypeOf(state, implementationsMap, typeField.type, ifaceField.type)) {
|
|
346
346
|
reportError(`Interface field ${interfaceType.name}.${fieldName} expects type ` +
|
|
347
|
-
`${ifaceField.type} but ${type.name}.${fieldName}
|
|
347
|
+
`${ifaceField.type} but ${type.name}.${fieldName} of type ${typeField.type} is not a proper subtype.`);
|
|
348
348
|
}
|
|
349
349
|
for (const ifaceArg of ifaceField.args.values()) {
|
|
350
350
|
const argName = ifaceArg.name;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTypeSubTypeOf = exports.InterfaceSubtypeRule = void 0;
|
|
4
|
+
const graphql_1 = require("graphql");
|
|
5
|
+
const state_js_1 = require("../../../utils/state.js");
|
|
6
|
+
function InterfaceSubtypeRule(context, supergraph) {
|
|
7
|
+
const implementationsMap = new Map();
|
|
8
|
+
for (const type of supergraph.interfaceTypes.values()) {
|
|
9
|
+
for (const iface of type.interfaces) {
|
|
10
|
+
const interfaceType = getTypeFromSupergraph(supergraph, iface);
|
|
11
|
+
if (interfaceType && isInterfaceType(interfaceType)) {
|
|
12
|
+
let implementations = implementationsMap.get(iface);
|
|
13
|
+
if (implementations === undefined) {
|
|
14
|
+
implementationsMap.set(iface, new Set([type.name]));
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
implementations.add(type.name);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
for (const type of supergraph.objectTypes.values()) {
|
|
23
|
+
for (const iface of type.interfaces) {
|
|
24
|
+
const interfaceType = getTypeFromSupergraph(supergraph, iface);
|
|
25
|
+
if (interfaceType && isInterfaceType(interfaceType)) {
|
|
26
|
+
let implementations = implementationsMap.get(iface);
|
|
27
|
+
if (implementations === undefined) {
|
|
28
|
+
implementationsMap.set(iface, new Set([type.name]));
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
implementations.add(type.name);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
ObjectTypeField(objectTypeState, fieldState) {
|
|
38
|
+
if (objectTypeState.interfaces.size === 0) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const interfaceNames = Array.from(objectTypeState.interfaces.values());
|
|
42
|
+
for (const interfaceName of interfaceNames) {
|
|
43
|
+
const interfaceState = supergraph.interfaceTypes.get(interfaceName);
|
|
44
|
+
if (!interfaceState) {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const interfaceField = interfaceState.fields.get(fieldState.name);
|
|
48
|
+
if (!interfaceField) {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (!isTypeSubTypeOf(supergraph, implementationsMap, fieldState.type, interfaceField.type)) {
|
|
52
|
+
context.reportError(new graphql_1.GraphQLError(`Interface field ${interfaceName}.${interfaceField.name} expects type ${interfaceField.type} but ${objectTypeState.name}.${fieldState.name} of type ${fieldState.type} is not a proper subtype.`, {
|
|
53
|
+
extensions: {
|
|
54
|
+
code: 'INVALID_GRAPHQL',
|
|
55
|
+
},
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
exports.InterfaceSubtypeRule = InterfaceSubtypeRule;
|
|
63
|
+
function isTypeSubTypeOf(state, implementationsMap, maybeSubTypeName, superTypeName) {
|
|
64
|
+
if (maybeSubTypeName === superTypeName) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if ((0, state_js_1.isNonNull)(superTypeName)) {
|
|
68
|
+
if ((0, state_js_1.isNonNull)(maybeSubTypeName)) {
|
|
69
|
+
return isTypeSubTypeOf(state, implementationsMap, (0, state_js_1.stripNonNull)(maybeSubTypeName), (0, state_js_1.stripNonNull)(superTypeName));
|
|
70
|
+
}
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if ((0, state_js_1.isNonNull)(maybeSubTypeName)) {
|
|
74
|
+
return isTypeSubTypeOf(state, implementationsMap, (0, state_js_1.stripNonNull)(maybeSubTypeName), superTypeName);
|
|
75
|
+
}
|
|
76
|
+
if ((0, state_js_1.isList)(superTypeName)) {
|
|
77
|
+
if ((0, state_js_1.isList)(maybeSubTypeName)) {
|
|
78
|
+
return isTypeSubTypeOf(state, implementationsMap, (0, state_js_1.stripList)(maybeSubTypeName), (0, state_js_1.stripList)(superTypeName));
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
if ((0, state_js_1.isList)(maybeSubTypeName)) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
const superType = getTypeFromSupergraph(state, superTypeName);
|
|
86
|
+
const maybeSubType = getTypeFromSupergraph(state, maybeSubTypeName);
|
|
87
|
+
if (!superType || !maybeSubType) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
return (isAbstractType(superType) &&
|
|
91
|
+
(isInterfaceType(maybeSubType) || isObjectType(maybeSubType)) &&
|
|
92
|
+
isSubType(implementationsMap, superType, maybeSubType));
|
|
93
|
+
}
|
|
94
|
+
exports.isTypeSubTypeOf = isTypeSubTypeOf;
|
|
95
|
+
function getTypeFromSupergraph(state, name) {
|
|
96
|
+
return (state.objectTypes.get(name) ?? state.interfaceTypes.get(name) ?? state.unionTypes.get(name));
|
|
97
|
+
}
|
|
98
|
+
function isSubType(implementationsMap, abstractType, maybeSubType) {
|
|
99
|
+
if (isUnionType(abstractType)) {
|
|
100
|
+
return abstractType.members.has(maybeSubType.name);
|
|
101
|
+
}
|
|
102
|
+
return implementationsMap.get(abstractType.name)?.has(maybeSubType.name) ?? false;
|
|
103
|
+
}
|
|
104
|
+
function isAbstractType(type) {
|
|
105
|
+
return isInterfaceType(type) || isUnionType(type);
|
|
106
|
+
}
|
|
107
|
+
function isObjectType(type) {
|
|
108
|
+
return type.kind === 'object';
|
|
109
|
+
}
|
|
110
|
+
function isInterfaceType(type) {
|
|
111
|
+
return type.kind === 'interface';
|
|
112
|
+
}
|
|
113
|
+
function isUnionType(type) {
|
|
114
|
+
return type.kind === 'union';
|
|
115
|
+
}
|
|
@@ -16,6 +16,7 @@ const input_field_default_mismatch_rule_js_1 = require("./rules/input-field-defa
|
|
|
16
16
|
const input_object_values_rule_js_1 = require("./rules/input-object-values-rule.js");
|
|
17
17
|
const interface_key_missing_implementation_type_js_1 = require("./rules/interface-key-missing-implementation-type.js");
|
|
18
18
|
const interface_object_usage_error_js_1 = require("./rules/interface-object-usage-error.js");
|
|
19
|
+
const interface_subtype_rule_js_1 = require("./rules/interface-subtype-rule.js");
|
|
19
20
|
const invalid_field_sharing_rule_js_1 = require("./rules/invalid-field-sharing-rule.js");
|
|
20
21
|
const only_inaccessible_children_rule_js_1 = require("./rules/only-inaccessible-children-rule.js");
|
|
21
22
|
const override_source_has_override_js_1 = require("./rules/override-source-has-override.js");
|
|
@@ -68,6 +69,7 @@ function validateSupergraph(subgraphStates, state, __internal) {
|
|
|
68
69
|
satisfiablity_rule_js_1.SatisfiabilityRule,
|
|
69
70
|
subgraph_name_rule_js_1.SubgraphNameRule,
|
|
70
71
|
required_argument_or_field_is_not_inaccessible_rule_js_1.RequiredArgumentOrFieldIsNotInaccessibleRule,
|
|
72
|
+
interface_subtype_rule_js_1.InterfaceSubtypeRule,
|
|
71
73
|
];
|
|
72
74
|
const supergraph = state.getSupergraphState();
|
|
73
75
|
(0, visitor_js_1.visitSupergraphState)(supergraph, postSupergraphRules.map(rule => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { federationDirectives, federationEnums, federationScalars } from
|
|
1
|
+
import { federationDirectives, federationEnums, federationScalars, } from './transform-supergraph-to-public-schema.js';
|
|
2
2
|
const supergraphSpecDetectionRegex = new RegExp(Array.from(federationScalars)
|
|
3
3
|
.concat(Array.from(federationEnums))
|
|
4
4
|
.map(name => [`\\[${name}`, `\\s${name}`])
|
|
@@ -340,7 +340,7 @@ function validateTypeImplementsInterface(state, implementationsMap, reportError,
|
|
|
340
340
|
}
|
|
341
341
|
if (!isTypeSubTypeOf(state, implementationsMap, typeField.type, ifaceField.type)) {
|
|
342
342
|
reportError(`Interface field ${interfaceType.name}.${fieldName} expects type ` +
|
|
343
|
-
`${ifaceField.type} but ${type.name}.${fieldName}
|
|
343
|
+
`${ifaceField.type} but ${type.name}.${fieldName} of type ${typeField.type} is not a proper subtype.`);
|
|
344
344
|
}
|
|
345
345
|
for (const ifaceArg of ifaceField.args.values()) {
|
|
346
346
|
const argName = ifaceArg.name;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { GraphQLError } from 'graphql';
|
|
2
|
+
import { isList, isNonNull, stripList, stripNonNull } from '../../../utils/state.js';
|
|
3
|
+
export function InterfaceSubtypeRule(context, supergraph) {
|
|
4
|
+
const implementationsMap = new Map();
|
|
5
|
+
for (const type of supergraph.interfaceTypes.values()) {
|
|
6
|
+
for (const iface of type.interfaces) {
|
|
7
|
+
const interfaceType = getTypeFromSupergraph(supergraph, iface);
|
|
8
|
+
if (interfaceType && isInterfaceType(interfaceType)) {
|
|
9
|
+
let implementations = implementationsMap.get(iface);
|
|
10
|
+
if (implementations === undefined) {
|
|
11
|
+
implementationsMap.set(iface, new Set([type.name]));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
implementations.add(type.name);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
for (const type of supergraph.objectTypes.values()) {
|
|
20
|
+
for (const iface of type.interfaces) {
|
|
21
|
+
const interfaceType = getTypeFromSupergraph(supergraph, iface);
|
|
22
|
+
if (interfaceType && isInterfaceType(interfaceType)) {
|
|
23
|
+
let implementations = implementationsMap.get(iface);
|
|
24
|
+
if (implementations === undefined) {
|
|
25
|
+
implementationsMap.set(iface, new Set([type.name]));
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
implementations.add(type.name);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
ObjectTypeField(objectTypeState, fieldState) {
|
|
35
|
+
if (objectTypeState.interfaces.size === 0) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const interfaceNames = Array.from(objectTypeState.interfaces.values());
|
|
39
|
+
for (const interfaceName of interfaceNames) {
|
|
40
|
+
const interfaceState = supergraph.interfaceTypes.get(interfaceName);
|
|
41
|
+
if (!interfaceState) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
const interfaceField = interfaceState.fields.get(fieldState.name);
|
|
45
|
+
if (!interfaceField) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
if (!isTypeSubTypeOf(supergraph, implementationsMap, fieldState.type, interfaceField.type)) {
|
|
49
|
+
context.reportError(new GraphQLError(`Interface field ${interfaceName}.${interfaceField.name} expects type ${interfaceField.type} but ${objectTypeState.name}.${fieldState.name} of type ${fieldState.type} is not a proper subtype.`, {
|
|
50
|
+
extensions: {
|
|
51
|
+
code: 'INVALID_GRAPHQL',
|
|
52
|
+
},
|
|
53
|
+
}));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
export function isTypeSubTypeOf(state, implementationsMap, maybeSubTypeName, superTypeName) {
|
|
60
|
+
if (maybeSubTypeName === superTypeName) {
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
if (isNonNull(superTypeName)) {
|
|
64
|
+
if (isNonNull(maybeSubTypeName)) {
|
|
65
|
+
return isTypeSubTypeOf(state, implementationsMap, stripNonNull(maybeSubTypeName), stripNonNull(superTypeName));
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
if (isNonNull(maybeSubTypeName)) {
|
|
70
|
+
return isTypeSubTypeOf(state, implementationsMap, stripNonNull(maybeSubTypeName), superTypeName);
|
|
71
|
+
}
|
|
72
|
+
if (isList(superTypeName)) {
|
|
73
|
+
if (isList(maybeSubTypeName)) {
|
|
74
|
+
return isTypeSubTypeOf(state, implementationsMap, stripList(maybeSubTypeName), stripList(superTypeName));
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (isList(maybeSubTypeName)) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
const superType = getTypeFromSupergraph(state, superTypeName);
|
|
82
|
+
const maybeSubType = getTypeFromSupergraph(state, maybeSubTypeName);
|
|
83
|
+
if (!superType || !maybeSubType) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
return (isAbstractType(superType) &&
|
|
87
|
+
(isInterfaceType(maybeSubType) || isObjectType(maybeSubType)) &&
|
|
88
|
+
isSubType(implementationsMap, superType, maybeSubType));
|
|
89
|
+
}
|
|
90
|
+
function getTypeFromSupergraph(state, name) {
|
|
91
|
+
return (state.objectTypes.get(name) ?? state.interfaceTypes.get(name) ?? state.unionTypes.get(name));
|
|
92
|
+
}
|
|
93
|
+
function isSubType(implementationsMap, abstractType, maybeSubType) {
|
|
94
|
+
if (isUnionType(abstractType)) {
|
|
95
|
+
return abstractType.members.has(maybeSubType.name);
|
|
96
|
+
}
|
|
97
|
+
return implementationsMap.get(abstractType.name)?.has(maybeSubType.name) ?? false;
|
|
98
|
+
}
|
|
99
|
+
function isAbstractType(type) {
|
|
100
|
+
return isInterfaceType(type) || isUnionType(type);
|
|
101
|
+
}
|
|
102
|
+
function isObjectType(type) {
|
|
103
|
+
return type.kind === 'object';
|
|
104
|
+
}
|
|
105
|
+
function isInterfaceType(type) {
|
|
106
|
+
return type.kind === 'interface';
|
|
107
|
+
}
|
|
108
|
+
function isUnionType(type) {
|
|
109
|
+
return type.kind === 'union';
|
|
110
|
+
}
|
|
@@ -13,6 +13,7 @@ import { InputFieldDefaultMismatchRule } from './rules/input-field-default-misma
|
|
|
13
13
|
import { InputObjectValuesRule } from './rules/input-object-values-rule.js';
|
|
14
14
|
import { InterfaceKeyMissingImplementationTypeRule } from './rules/interface-key-missing-implementation-type.js';
|
|
15
15
|
import { InterfaceObjectUsageErrorRule } from './rules/interface-object-usage-error.js';
|
|
16
|
+
import { InterfaceSubtypeRule } from './rules/interface-subtype-rule.js';
|
|
16
17
|
import { InvalidFieldSharingRule } from './rules/invalid-field-sharing-rule.js';
|
|
17
18
|
import { OnlyInaccessibleChildrenRule } from './rules/only-inaccessible-children-rule.js';
|
|
18
19
|
import { OverrideSourceHasOverrideRule } from './rules/override-source-has-override.js';
|
|
@@ -65,6 +66,7 @@ export function validateSupergraph(subgraphStates, state, __internal) {
|
|
|
65
66
|
SatisfiabilityRule,
|
|
66
67
|
SubgraphNameRule,
|
|
67
68
|
RequiredArgumentOrFieldIsNotInaccessibleRule,
|
|
69
|
+
InterfaceSubtypeRule,
|
|
68
70
|
];
|
|
69
71
|
const supergraph = state.getSupergraphState();
|
|
70
72
|
visitSupergraphState(supergraph, postSupergraphRules.map(rule => {
|
package/package.json
CHANGED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SupergraphVisitorMap } from '../../composition/visitor.cjs';
|
|
2
|
+
import { SupergraphState } from '../../state.cjs';
|
|
3
|
+
import { SupergraphValidationContext } from '../validation-context.cjs';
|
|
4
|
+
export declare function InterfaceSubtypeRule(context: SupergraphValidationContext, supergraph: SupergraphState): SupergraphVisitorMap;
|
|
5
|
+
export declare function isTypeSubTypeOf(state: SupergraphState, implementationsMap: Map<string, Set<string>>, maybeSubTypeName: string, superTypeName: string): boolean;
|
|
6
|
+
//# sourceMappingURL=interface-subtype-rule.d.ts.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { SupergraphVisitorMap } from '../../composition/visitor.js';
|
|
2
|
+
import { SupergraphState } from '../../state.js';
|
|
3
|
+
import { SupergraphValidationContext } from '../validation-context.js';
|
|
4
|
+
export declare function InterfaceSubtypeRule(context: SupergraphValidationContext, supergraph: SupergraphState): SupergraphVisitorMap;
|
|
5
|
+
export declare function isTypeSubTypeOf(state: SupergraphState, implementationsMap: Map<string, Set<string>>, maybeSubTypeName: string, superTypeName: string): boolean;
|
|
6
|
+
//# sourceMappingURL=interface-subtype-rule.d.ts.map
|