@theguild/federation-composition 0.11.4 → 0.12.0-alpha-20240708141320-c066c07

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 CHANGED
@@ -182,10 +182,10 @@ Your feedback and bug reports are welcome and appreciated.
182
182
  - ✅ `INTERFACE_OBJECT_USAGE_ERROR`
183
183
  - ✅ `REQUIRED_INACCESSIBLE`
184
184
  - ✅ `SATISFIABILITY_ERROR`
185
+ - ✅ `INTERFACE_FIELD_NO_IMPLEM`
185
186
 
186
187
  ### TODOs
187
188
 
188
- - [ ] `INTERFACE_FIELD_NO_IMPLEM`
189
189
  - [ ] `DISALLOWED_INACCESSIBLE`
190
190
  - [ ] `EXTERNAL_ARGUMENT_DEFAULT_MISMATCH`
191
191
  - [ ] `EXTERNAL_ARGUMENT_TYPE_MISMATCH`
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InterfaceFieldNoImplementationRule = void 0;
4
+ const graphql_1 = require("graphql");
5
+ function InterfaceFieldNoImplementationRule(context, supergraph) {
6
+ return {
7
+ ObjectType(objectTypeState) {
8
+ if (objectTypeState.interfaces.size === 0) {
9
+ return;
10
+ }
11
+ for (const interfaceName of objectTypeState.interfaces) {
12
+ const interfaceTypeState = getTypeFromSupergraph(supergraph, interfaceName);
13
+ if (!interfaceTypeState) {
14
+ throw new Error(`Expected an interface to exist in supergraph state`);
15
+ }
16
+ if (interfaceTypeState.kind !== 'interface') {
17
+ throw new Error('Expected interface, got ' + interfaceTypeState.kind);
18
+ }
19
+ const nonRequiredFields = [];
20
+ for (const [graph, interfaceStateInGraph] of interfaceTypeState.byGraph) {
21
+ if (!interfaceStateInGraph.isInterfaceObject) {
22
+ continue;
23
+ }
24
+ for (const [fieldName, interfaceFieldState] of interfaceTypeState.fields) {
25
+ const interfaceFieldStateInGraph = interfaceFieldState.byGraph.get(graph);
26
+ if (!interfaceFieldStateInGraph) {
27
+ continue;
28
+ }
29
+ if (interfaceFieldStateInGraph.external) {
30
+ continue;
31
+ }
32
+ nonRequiredFields.push(fieldName);
33
+ }
34
+ }
35
+ for (const [fieldName, interfaceFieldState] of interfaceTypeState.fields) {
36
+ if (nonRequiredFields.includes(fieldName)) {
37
+ continue;
38
+ }
39
+ if (objectTypeState.fields.has(fieldName) && objectTypeState.isEntity) {
40
+ continue;
41
+ }
42
+ for (const [graph, objectTypeInGraph] of objectTypeState.byGraph) {
43
+ if (!objectTypeInGraph.interfaces.has(interfaceName)) {
44
+ continue;
45
+ }
46
+ const objectFieldState = objectTypeState.fields.get(fieldName);
47
+ if (!objectFieldState) {
48
+ const interfaceFieldDefinedInGraphs = Array.from(interfaceFieldState.byGraph.keys()).map(context.graphIdToName);
49
+ const declaredIn = interfaceFieldDefinedInGraphs.length === 1
50
+ ? `subgraph "${interfaceFieldDefinedInGraphs[0]}"`
51
+ : `subgraphs ${interfaceFieldDefinedInGraphs.map(g => `"${g}"`).join(', ')}`;
52
+ context.reportError(new graphql_1.GraphQLError(`Interface field "${interfaceName}.${fieldName}" is declared in ${declaredIn} but type "${objectTypeState.name}", which implements "${interfaceName}" in subgraph "${context.graphIdToName(graph)}" does not have field "${fieldName}".`, {
53
+ extensions: {
54
+ code: 'INTERFACE_FIELD_NO_IMPLEM',
55
+ },
56
+ }));
57
+ }
58
+ }
59
+ }
60
+ }
61
+ },
62
+ };
63
+ }
64
+ exports.InterfaceFieldNoImplementationRule = InterfaceFieldNoImplementationRule;
65
+ function getTypeFromSupergraph(state, name) {
66
+ return (state.objectTypes.get(name) ?? state.interfaceTypes.get(name) ?? state.unionTypes.get(name));
67
+ }
@@ -27,6 +27,7 @@ const required_input_field_missing_in_some_subgraph_rule_js_1 = require("./rules
27
27
  const required_query_rule_js_1 = require("./rules/required-query-rule.js");
28
28
  const satisfiablity_rule_js_1 = require("./rules/satisfiablity-rule.js");
29
29
  const subgraph_name_rule_js_1 = require("./rules/subgraph-name-rule.js");
30
+ const interface_field_no_implementation_rule_js_1 = require("./rules/interface-field-no-implementation-rule.js");
30
31
  const types_of_the_same_kind_rule_js_1 = require("./rules/types-of-the-same-kind-rule.js");
31
32
  const validation_context_js_1 = require("./validation-context.js");
32
33
  function validateSupergraph(subgraphStates, state, __internal) {
@@ -46,6 +47,7 @@ function validateSupergraph(subgraphStates, state, __internal) {
46
47
  state.visitSubgraphState(subgraphState);
47
48
  }
48
49
  const postSupergraphRules = [
50
+ interface_field_no_implementation_rule_js_1.InterfaceFieldNoImplementationRule,
49
51
  extension_with_base_js_1.ExtensionWithBaseRule,
50
52
  fields_of_the_same_type_rule_js_1.FieldsOfTheSameTypeRule,
51
53
  field_arguments_of_the_same_type_rule_js_1.FieldArgumentsOfTheSameTypeRule,
@@ -0,0 +1,63 @@
1
+ import { GraphQLError } from 'graphql';
2
+ export function InterfaceFieldNoImplementationRule(context, supergraph) {
3
+ return {
4
+ ObjectType(objectTypeState) {
5
+ if (objectTypeState.interfaces.size === 0) {
6
+ return;
7
+ }
8
+ for (const interfaceName of objectTypeState.interfaces) {
9
+ const interfaceTypeState = getTypeFromSupergraph(supergraph, interfaceName);
10
+ if (!interfaceTypeState) {
11
+ throw new Error(`Expected an interface to exist in supergraph state`);
12
+ }
13
+ if (interfaceTypeState.kind !== 'interface') {
14
+ throw new Error('Expected interface, got ' + interfaceTypeState.kind);
15
+ }
16
+ const nonRequiredFields = [];
17
+ for (const [graph, interfaceStateInGraph] of interfaceTypeState.byGraph) {
18
+ if (!interfaceStateInGraph.isInterfaceObject) {
19
+ continue;
20
+ }
21
+ for (const [fieldName, interfaceFieldState] of interfaceTypeState.fields) {
22
+ const interfaceFieldStateInGraph = interfaceFieldState.byGraph.get(graph);
23
+ if (!interfaceFieldStateInGraph) {
24
+ continue;
25
+ }
26
+ if (interfaceFieldStateInGraph.external) {
27
+ continue;
28
+ }
29
+ nonRequiredFields.push(fieldName);
30
+ }
31
+ }
32
+ for (const [fieldName, interfaceFieldState] of interfaceTypeState.fields) {
33
+ if (nonRequiredFields.includes(fieldName)) {
34
+ continue;
35
+ }
36
+ if (objectTypeState.fields.has(fieldName) && objectTypeState.isEntity) {
37
+ continue;
38
+ }
39
+ for (const [graph, objectTypeInGraph] of objectTypeState.byGraph) {
40
+ if (!objectTypeInGraph.interfaces.has(interfaceName)) {
41
+ continue;
42
+ }
43
+ const objectFieldState = objectTypeState.fields.get(fieldName);
44
+ if (!objectFieldState) {
45
+ const interfaceFieldDefinedInGraphs = Array.from(interfaceFieldState.byGraph.keys()).map(context.graphIdToName);
46
+ const declaredIn = interfaceFieldDefinedInGraphs.length === 1
47
+ ? `subgraph "${interfaceFieldDefinedInGraphs[0]}"`
48
+ : `subgraphs ${interfaceFieldDefinedInGraphs.map(g => `"${g}"`).join(', ')}`;
49
+ context.reportError(new GraphQLError(`Interface field "${interfaceName}.${fieldName}" is declared in ${declaredIn} but type "${objectTypeState.name}", which implements "${interfaceName}" in subgraph "${context.graphIdToName(graph)}" does not have field "${fieldName}".`, {
50
+ extensions: {
51
+ code: 'INTERFACE_FIELD_NO_IMPLEM',
52
+ },
53
+ }));
54
+ }
55
+ }
56
+ }
57
+ }
58
+ },
59
+ };
60
+ }
61
+ function getTypeFromSupergraph(state, name) {
62
+ return (state.objectTypes.get(name) ?? state.interfaceTypes.get(name) ?? state.unionTypes.get(name));
63
+ }
@@ -24,6 +24,7 @@ import { RequiredInputFieldMissingInSomeSubgraphRule } from './rules/required-in
24
24
  import { RequiredQueryRule } from './rules/required-query-rule.js';
25
25
  import { SatisfiabilityRule } from './rules/satisfiablity-rule.js';
26
26
  import { SubgraphNameRule } from './rules/subgraph-name-rule.js';
27
+ import { InterfaceFieldNoImplementationRule } from './rules/interface-field-no-implementation-rule.js';
27
28
  import { TypesOfTheSameKindRule } from './rules/types-of-the-same-kind-rule.js';
28
29
  import { createSupergraphValidationContext } from './validation-context.js';
29
30
  export function validateSupergraph(subgraphStates, state, __internal) {
@@ -43,6 +44,7 @@ export function validateSupergraph(subgraphStates, state, __internal) {
43
44
  state.visitSubgraphState(subgraphState);
44
45
  }
45
46
  const postSupergraphRules = [
47
+ InterfaceFieldNoImplementationRule,
46
48
  ExtensionWithBaseRule,
47
49
  FieldsOfTheSameTypeRule,
48
50
  FieldArgumentsOfTheSameTypeRule,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@theguild/federation-composition",
3
- "version": "0.11.4",
3
+ "version": "0.12.0-alpha-20240708141320-c066c07",
4
4
  "description": "Open Source Composition library for Apollo Federation",
5
5
  "peerDependencies": {
6
6
  "graphql": "^16.0.0"
@@ -0,0 +1,5 @@
1
+ import { SupergraphVisitorMap } from '../../composition/visitor.cjs';
2
+ import { SupergraphState } from '../../state.cjs';
3
+ import { SupergraphValidationContext } from '../validation-context.cjs';
4
+ export declare function InterfaceFieldNoImplementationRule(context: SupergraphValidationContext, supergraph: SupergraphState): SupergraphVisitorMap;
5
+ //# sourceMappingURL=interface-field-no-implementation-rule.d.ts.map
@@ -0,0 +1,5 @@
1
+ import { SupergraphVisitorMap } from '../../composition/visitor.js';
2
+ import { SupergraphState } from '../../state.js';
3
+ import { SupergraphValidationContext } from '../validation-context.js';
4
+ export declare function InterfaceFieldNoImplementationRule(context: SupergraphValidationContext, supergraph: SupergraphState): SupergraphVisitorMap;
5
+ //# sourceMappingURL=interface-field-no-implementation-rule.d.ts.map