@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.
@@ -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} is type ${typeField.type}.`);
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 "./transform-supergraph-to-public-schema.js";
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} is type ${typeField.type}.`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theguild/federation-composition",
3
- "version": "0.11.3",
3
+ "version": "0.11.4-alpha-20240626075710-a99d3f0",
4
4
  "description": "Open Source Composition library for Apollo Federation",
5
5
  "peerDependencies": {
6
6
  "graphql": "^16.0.0"
@@ -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