@theguild/federation-composition 0.5.0 → 0.5.1-rc-20231215091130-d3bef86
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 +15 -0
- package/cjs/graphql/helpers.js +20 -1
- package/cjs/supergraph/composition/object-type.js +18 -7
- package/cjs/validate.js +3 -2
- package/esm/graphql/helpers.js +18 -0
- package/esm/supergraph/composition/object-type.js +18 -7
- package/esm/validate.js +3 -2
- package/package.json +1 -1
- package/typings/graphql/helpers.d.cts +2 -1
- package/typings/graphql/helpers.d.ts +2 -1
- package/typings/supergraph/composition/object-type.d.cts +1 -0
- package/typings/supergraph/composition/object-type.d.ts +1 -0
package/README.md
CHANGED
|
@@ -98,6 +98,21 @@ pnpm test
|
|
|
98
98
|
- Look for `skipIf` or `skip` in the tests.
|
|
99
99
|
- Refactor code (piece by piece) if you feel like it.
|
|
100
100
|
|
|
101
|
+
### Compatibility
|
|
102
|
+
|
|
103
|
+
The lack of a publicly available specification for Apollo Federation, coupled with the non
|
|
104
|
+
open-source license of the Apollo Composition library, makes it difficult or even impossible to
|
|
105
|
+
assure complete compatibility of our open-source composition library.
|
|
106
|
+
|
|
107
|
+
Given that Apollo tools utilize their composition library, there is a potential for conflicting
|
|
108
|
+
results between our composition library and Apollo's. This may lead to variations in the supergraph,
|
|
109
|
+
differing composition errors, or, in some cases, conflicting composition outcomes.
|
|
110
|
+
|
|
111
|
+
We are working to ensure that our composition library is as compatible as possible with Apollo's and
|
|
112
|
+
will continue to do so as we learn more about the Federation specification.
|
|
113
|
+
|
|
114
|
+
Your feedback and bug reports are welcome and appreciated.
|
|
115
|
+
|
|
101
116
|
## Supergraph SDL Composition
|
|
102
117
|
|
|
103
118
|
✅ Done
|
package/cjs/graphql/helpers.js
CHANGED
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isDirectiveDefinition = void 0;
|
|
3
|
+
exports.moveSchemaAndDirectiveDefinitionsToTop = exports.isDirectiveDefinition = void 0;
|
|
4
4
|
const graphql_1 = require("graphql");
|
|
5
5
|
function isDirectiveDefinition(node) {
|
|
6
6
|
return node.kind === graphql_1.Kind.DIRECTIVE_DEFINITION;
|
|
7
7
|
}
|
|
8
8
|
exports.isDirectiveDefinition = isDirectiveDefinition;
|
|
9
|
+
const kindOrderWeightMap = {
|
|
10
|
+
[graphql_1.Kind.SCHEMA_DEFINITION]: 0,
|
|
11
|
+
[graphql_1.Kind.SCHEMA_EXTENSION]: 1,
|
|
12
|
+
[graphql_1.Kind.DIRECTIVE_DEFINITION]: 2,
|
|
13
|
+
};
|
|
14
|
+
function moveSchemaAndDirectiveDefinitionsToTop(ast) {
|
|
15
|
+
return {
|
|
16
|
+
kind: graphql_1.Kind.DOCUMENT,
|
|
17
|
+
definitions: ast.definitions.slice().sort((a, b) => {
|
|
18
|
+
const aWeight = kindOrderWeightMap[a.kind] ?? 3;
|
|
19
|
+
const bWeight = kindOrderWeightMap[b.kind] ?? 3;
|
|
20
|
+
if (aWeight === bWeight) {
|
|
21
|
+
return 0;
|
|
22
|
+
}
|
|
23
|
+
return aWeight < bWeight ? -1 : 1;
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
exports.moveSchemaAndDirectiveDefinitionsToTop = moveSchemaAndDirectiveDefinitionsToTop;
|
|
@@ -4,11 +4,20 @@ exports.objectTypeBuilder = exports.isRealExtension = void 0;
|
|
|
4
4
|
const ast_js_1 = require("./ast.js");
|
|
5
5
|
const common_js_1 = require("./common.js");
|
|
6
6
|
function isRealExtension(meta, version) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
const hasExtendsDirective = meta.extensionType === '@extends';
|
|
8
|
+
if (meta.extension) {
|
|
9
|
+
if (version === 'v1.0' && !hasExtendsDirective) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
if (hasExtendsDirective) {
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
if (meta.hasDefinition) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
return false;
|
|
12
21
|
}
|
|
13
22
|
exports.isRealExtension = isRealExtension;
|
|
14
23
|
function objectTypeBuilder() {
|
|
@@ -42,6 +51,7 @@ function objectTypeBuilder() {
|
|
|
42
51
|
}
|
|
43
52
|
type.interfaces.forEach(interfaceName => objectTypeState.interfaces.add(interfaceName));
|
|
44
53
|
objectTypeState.byGraph.set(graph.id, {
|
|
54
|
+
hasDefinition: isDefinition,
|
|
45
55
|
extension: type.extension,
|
|
46
56
|
extensionType: type.extensionType,
|
|
47
57
|
external: type.external,
|
|
@@ -50,6 +60,7 @@ function objectTypeBuilder() {
|
|
|
50
60
|
shareable: type.shareable,
|
|
51
61
|
interfaces: type.interfaces,
|
|
52
62
|
});
|
|
63
|
+
const typeInGraph = objectTypeState.byGraph.get(graph.id);
|
|
53
64
|
for (const field of type.fields.values()) {
|
|
54
65
|
const fieldState = getOrCreateField(objectTypeState, field.name, field.type);
|
|
55
66
|
field.tags.forEach(tag => fieldState.tags.add(tag));
|
|
@@ -58,7 +69,7 @@ function objectTypeBuilder() {
|
|
|
58
69
|
fieldState.usedAsKey = true;
|
|
59
70
|
}
|
|
60
71
|
const isExternal = graph.version === 'v1.0'
|
|
61
|
-
? field.external && isRealExtension(
|
|
72
|
+
? field.external && isRealExtension(typeInGraph, graph.version)
|
|
62
73
|
: field.external;
|
|
63
74
|
const shouldForceType = !usedAsKey && !isExternal && !fieldState.internal.seenNonExternal;
|
|
64
75
|
const shouldChangeType = shouldForceType ||
|
|
@@ -117,7 +128,7 @@ function objectTypeBuilder() {
|
|
|
117
128
|
if (arg.inaccessible) {
|
|
118
129
|
argState.inaccessible = true;
|
|
119
130
|
}
|
|
120
|
-
if (!
|
|
131
|
+
if (arg.description && !argState.description) {
|
|
121
132
|
argState.description = arg.description;
|
|
122
133
|
}
|
|
123
134
|
if (arg.deprecated && !argState.deprecated) {
|
package/cjs/validate.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.validate = exports.validateSubgraph = void 0;
|
|
4
4
|
const constant_case_1 = require("constant-case");
|
|
5
|
+
const helpers_js_1 = require("./graphql/helpers.js");
|
|
5
6
|
const federation_js_1 = require("./specifications/federation.js");
|
|
6
7
|
const state_js_1 = require("./subgraph/state.js");
|
|
7
8
|
const validate_subgraph_js_1 = require("./subgraph/validation/validate-subgraph.js");
|
|
@@ -39,7 +40,7 @@ function buildGraphList(subgraphs) {
|
|
|
39
40
|
name,
|
|
40
41
|
id: proposedId + '_' + (count + 1),
|
|
41
42
|
url,
|
|
42
|
-
typeDefs,
|
|
43
|
+
typeDefs: (0, helpers_js_1.moveSchemaAndDirectiveDefinitionsToTop)(typeDefs),
|
|
43
44
|
});
|
|
44
45
|
idCounter.set(proposedId, count + 1);
|
|
45
46
|
}
|
|
@@ -49,7 +50,7 @@ function buildGraphList(subgraphs) {
|
|
|
49
50
|
name,
|
|
50
51
|
id: proposedId,
|
|
51
52
|
url,
|
|
52
|
-
typeDefs,
|
|
53
|
+
typeDefs: (0, helpers_js_1.moveSchemaAndDirectiveDefinitionsToTop)(typeDefs),
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
56
|
}
|
package/esm/graphql/helpers.js
CHANGED
|
@@ -2,3 +2,21 @@ import { Kind } from 'graphql';
|
|
|
2
2
|
export function isDirectiveDefinition(node) {
|
|
3
3
|
return node.kind === Kind.DIRECTIVE_DEFINITION;
|
|
4
4
|
}
|
|
5
|
+
const kindOrderWeightMap = {
|
|
6
|
+
[Kind.SCHEMA_DEFINITION]: 0,
|
|
7
|
+
[Kind.SCHEMA_EXTENSION]: 1,
|
|
8
|
+
[Kind.DIRECTIVE_DEFINITION]: 2,
|
|
9
|
+
};
|
|
10
|
+
export function moveSchemaAndDirectiveDefinitionsToTop(ast) {
|
|
11
|
+
return {
|
|
12
|
+
kind: Kind.DOCUMENT,
|
|
13
|
+
definitions: ast.definitions.slice().sort((a, b) => {
|
|
14
|
+
const aWeight = kindOrderWeightMap[a.kind] ?? 3;
|
|
15
|
+
const bWeight = kindOrderWeightMap[b.kind] ?? 3;
|
|
16
|
+
if (aWeight === bWeight) {
|
|
17
|
+
return 0;
|
|
18
|
+
}
|
|
19
|
+
return aWeight < bWeight ? -1 : 1;
|
|
20
|
+
}),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
1
|
import { createObjectTypeNode } from './ast.js';
|
|
2
2
|
import { convertToConst } from './common.js';
|
|
3
3
|
export function isRealExtension(meta, version) {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const hasExtendsDirective = meta.extensionType === '@extends';
|
|
5
|
+
if (meta.extension) {
|
|
6
|
+
if (version === 'v1.0' && !hasExtendsDirective) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
if (hasExtendsDirective) {
|
|
10
|
+
return true;
|
|
11
|
+
}
|
|
12
|
+
if (meta.hasDefinition) {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
return false;
|
|
9
18
|
}
|
|
10
19
|
export function objectTypeBuilder() {
|
|
11
20
|
return {
|
|
@@ -38,6 +47,7 @@ export function objectTypeBuilder() {
|
|
|
38
47
|
}
|
|
39
48
|
type.interfaces.forEach(interfaceName => objectTypeState.interfaces.add(interfaceName));
|
|
40
49
|
objectTypeState.byGraph.set(graph.id, {
|
|
50
|
+
hasDefinition: isDefinition,
|
|
41
51
|
extension: type.extension,
|
|
42
52
|
extensionType: type.extensionType,
|
|
43
53
|
external: type.external,
|
|
@@ -46,6 +56,7 @@ export function objectTypeBuilder() {
|
|
|
46
56
|
shareable: type.shareable,
|
|
47
57
|
interfaces: type.interfaces,
|
|
48
58
|
});
|
|
59
|
+
const typeInGraph = objectTypeState.byGraph.get(graph.id);
|
|
49
60
|
for (const field of type.fields.values()) {
|
|
50
61
|
const fieldState = getOrCreateField(objectTypeState, field.name, field.type);
|
|
51
62
|
field.tags.forEach(tag => fieldState.tags.add(tag));
|
|
@@ -54,7 +65,7 @@ export function objectTypeBuilder() {
|
|
|
54
65
|
fieldState.usedAsKey = true;
|
|
55
66
|
}
|
|
56
67
|
const isExternal = graph.version === 'v1.0'
|
|
57
|
-
? field.external && isRealExtension(
|
|
68
|
+
? field.external && isRealExtension(typeInGraph, graph.version)
|
|
58
69
|
: field.external;
|
|
59
70
|
const shouldForceType = !usedAsKey && !isExternal && !fieldState.internal.seenNonExternal;
|
|
60
71
|
const shouldChangeType = shouldForceType ||
|
|
@@ -113,7 +124,7 @@ export function objectTypeBuilder() {
|
|
|
113
124
|
if (arg.inaccessible) {
|
|
114
125
|
argState.inaccessible = true;
|
|
115
126
|
}
|
|
116
|
-
if (!
|
|
127
|
+
if (arg.description && !argState.description) {
|
|
117
128
|
argState.description = arg.description;
|
|
118
129
|
}
|
|
119
130
|
if (arg.deprecated && !argState.deprecated) {
|
package/esm/validate.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { constantCase } from 'constant-case';
|
|
2
|
+
import { moveSchemaAndDirectiveDefinitionsToTop } from './graphql/helpers.js';
|
|
2
3
|
import { detectFederationVersion } from './specifications/federation.js';
|
|
3
4
|
import { cleanSubgraphStateFromFederationSpec, cleanSubgraphStateFromLinkSpec, createSubgraphStateBuilder, } from './subgraph/state.js';
|
|
4
5
|
import { validateSubgraph as internal_validateSubgraph, validateSubgraphCore, } from './subgraph/validation/validate-subgraph.js';
|
|
@@ -36,7 +37,7 @@ function buildGraphList(subgraphs) {
|
|
|
36
37
|
name,
|
|
37
38
|
id: proposedId + '_' + (count + 1),
|
|
38
39
|
url,
|
|
39
|
-
typeDefs,
|
|
40
|
+
typeDefs: moveSchemaAndDirectiveDefinitionsToTop(typeDefs),
|
|
40
41
|
});
|
|
41
42
|
idCounter.set(proposedId, count + 1);
|
|
42
43
|
}
|
|
@@ -46,7 +47,7 @@ function buildGraphList(subgraphs) {
|
|
|
46
47
|
name,
|
|
47
48
|
id: proposedId,
|
|
48
49
|
url,
|
|
49
|
-
typeDefs,
|
|
50
|
+
typeDefs: moveSchemaAndDirectiveDefinitionsToTop(typeDefs),
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
53
|
}
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { type DefinitionNode, type DirectiveDefinitionNode } from 'graphql';
|
|
1
|
+
import { DocumentNode, type DefinitionNode, type DirectiveDefinitionNode } from 'graphql';
|
|
2
2
|
export declare function isDirectiveDefinition(node: DefinitionNode): node is DirectiveDefinitionNode;
|
|
3
|
+
export declare function moveSchemaAndDirectiveDefinitionsToTop(ast: DocumentNode): DocumentNode;
|
|
3
4
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { type DefinitionNode, type DirectiveDefinitionNode } from 'graphql';
|
|
1
|
+
import { DocumentNode, type DefinitionNode, type DirectiveDefinitionNode } from 'graphql';
|
|
2
2
|
export declare function isDirectiveDefinition(node: DefinitionNode): node is DirectiveDefinitionNode;
|
|
3
|
+
export declare function moveSchemaAndDirectiveDefinitionsToTop(ast: DocumentNode): DocumentNode;
|
|
3
4
|
//# sourceMappingURL=helpers.d.ts.map
|