@apollo/federation-internals 2.4.0 → 2.4.2
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/CHANGELOG.md +36 -0
- package/dist/argumentCompositionStrategies.d.ts +34 -0
- package/dist/argumentCompositionStrategies.d.ts.map +1 -0
- package/dist/argumentCompositionStrategies.js +35 -0
- package/dist/argumentCompositionStrategies.js.map +1 -0
- package/dist/coreSpec.d.ts +12 -3
- package/dist/coreSpec.d.ts.map +1 -1
- package/dist/coreSpec.js +69 -18
- package/dist/coreSpec.js.map +1 -1
- package/dist/definitions.d.ts +1 -0
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +30 -27
- package/dist/definitions.js.map +1 -1
- package/dist/directiveAndTypeSpecification.d.ts +26 -7
- package/dist/directiveAndTypeSpecification.d.ts.map +1 -1
- package/dist/directiveAndTypeSpecification.js +56 -4
- package/dist/directiveAndTypeSpecification.js.map +1 -1
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +24 -2
- package/dist/federation.js.map +1 -1
- package/dist/federationSpec.d.ts +2 -13
- package/dist/federationSpec.d.ts.map +1 -1
- package/dist/federationSpec.js +10 -60
- package/dist/federationSpec.js.map +1 -1
- package/dist/inaccessibleSpec.d.ts +0 -2
- package/dist/inaccessibleSpec.d.ts.map +1 -1
- package/dist/inaccessibleSpec.js +3 -6
- package/dist/inaccessibleSpec.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/knownCoreFeatures.d.ts +1 -0
- package/dist/knownCoreFeatures.d.ts.map +1 -1
- package/dist/knownCoreFeatures.js +5 -1
- package/dist/knownCoreFeatures.js.map +1 -1
- package/dist/operations.d.ts +92 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +192 -48
- package/dist/operations.js.map +1 -1
- package/dist/print.d.ts +7 -1
- package/dist/print.d.ts.map +1 -1
- package/dist/print.js +33 -5
- package/dist/print.js.map +1 -1
- package/dist/tagSpec.d.ts +0 -2
- package/dist/tagSpec.d.ts.map +1 -1
- package/dist/tagSpec.js +4 -10
- package/dist/tagSpec.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/directiveAndTypeSpecifications.test.ts +41 -0
- package/src/__tests__/operations.test.ts +598 -45
- package/src/__tests__/schemaUpgrader.test.ts +1 -1
- package/src/argumentCompositionStrategies.ts +39 -0
- package/src/coreSpec.ts +94 -34
- package/src/definitions.ts +35 -29
- package/src/directiveAndTypeSpecification.ts +101 -14
- package/src/federation.ts +33 -4
- package/src/federationSpec.ts +13 -73
- package/src/inaccessibleSpec.ts +4 -11
- package/src/index.ts +3 -0
- package/src/knownCoreFeatures.ts +9 -0
- package/src/operations.ts +318 -102
- package/src/print.ts +39 -4
- package/src/tagSpec.ts +4 -12
- package/tsconfig.tsbuildinfo +1 -1
package/src/federation.ts
CHANGED
|
@@ -80,6 +80,8 @@ import {
|
|
|
80
80
|
import { defaultPrintOptions, PrintOptions as PrintOptions, printSchema } from "./print";
|
|
81
81
|
import { createObjectTypeSpecification, createScalarTypeSpecification, createUnionTypeSpecification } from "./directiveAndTypeSpecification";
|
|
82
82
|
import { didYouMean, suggestionList } from "./suggestions";
|
|
83
|
+
import { coreFeatureDefinitionIfKnown } from "./knownCoreFeatures";
|
|
84
|
+
import { joinIdentity } from "./joinSpec";
|
|
83
85
|
|
|
84
86
|
const linkSpec = LINK_VERSIONS.latest();
|
|
85
87
|
const tagSpec = TAG_VERSIONS.latest();
|
|
@@ -110,7 +112,6 @@ const FEDERATION_SPECIFIC_VALIDATION_RULES = [
|
|
|
110
112
|
const FEDERATION_VALIDATION_RULES = specifiedSDLRules.filter(rule => !FEDERATION_OMITTED_VALIDATION_RULES.includes(rule)).concat(FEDERATION_SPECIFIC_VALIDATION_RULES);
|
|
111
113
|
|
|
112
114
|
const ALL_DEFAULT_FEDERATION_DIRECTIVE_NAMES: string[] = Object.values(FederationDirectiveName);
|
|
113
|
-
|
|
114
115
|
function validateFieldSetSelections({
|
|
115
116
|
directiveName,
|
|
116
117
|
selectionSet,
|
|
@@ -1342,12 +1343,14 @@ function completeFed1SubgraphSchema(schema: Schema): GraphQLError[] {
|
|
|
1342
1343
|
}
|
|
1343
1344
|
}
|
|
1344
1345
|
|
|
1345
|
-
|
|
1346
|
+
const errors = FEDERATION1_TYPES.map((spec) => spec.checkOrAdd(schema, '_' + spec.name))
|
|
1346
1347
|
.concat(FEDERATION1_DIRECTIVES.map((spec) => spec.checkOrAdd(schema)))
|
|
1347
1348
|
.flat();
|
|
1349
|
+
|
|
1350
|
+
return errors.length === 0 ? expandKnownFeatures(schema) : errors;
|
|
1348
1351
|
}
|
|
1349
1352
|
|
|
1350
|
-
function completeFed2SubgraphSchema(schema: Schema) {
|
|
1353
|
+
function completeFed2SubgraphSchema(schema: Schema): GraphQLError[] {
|
|
1351
1354
|
const coreFeatures = schema.coreFeatures;
|
|
1352
1355
|
assert(coreFeatures, 'This method should not have been called on a non-core schema');
|
|
1353
1356
|
|
|
@@ -1362,7 +1365,33 @@ function completeFed2SubgraphSchema(schema: Schema) {
|
|
|
1362
1365
|
)];
|
|
1363
1366
|
}
|
|
1364
1367
|
|
|
1365
|
-
|
|
1368
|
+
const errors = spec.addElementsToSchema(schema);
|
|
1369
|
+
return errors.length === 0 ? expandKnownFeatures(schema) : errors;
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
function expandKnownFeatures(schema: Schema): GraphQLError[] {
|
|
1373
|
+
const coreFeatures = schema.coreFeatures;
|
|
1374
|
+
if (!coreFeatures) {
|
|
1375
|
+
return [];
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
let errors: GraphQLError[] = [];
|
|
1379
|
+
for (const feature of coreFeatures.allFeatures()) {
|
|
1380
|
+
// We should already have dealt with the core/link spec and federation at this point. Also, we shouldn't have the `join` spec in subgraphs,
|
|
1381
|
+
// but some tests play with the idea and currently the join spec is implemented in a way that is not idempotent (it doesn't use
|
|
1382
|
+
// `DirectiveSpecification.checkAndAdd`; we should clean it up at some point, but not exactly urgent).
|
|
1383
|
+
if (feature === coreFeatures.coreItself || feature.url.identity === federationIdentity || feature.url.identity === joinIdentity) {
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
const spec = coreFeatureDefinitionIfKnown(feature.url);
|
|
1388
|
+
if (!spec) {
|
|
1389
|
+
continue;
|
|
1390
|
+
}
|
|
1391
|
+
|
|
1392
|
+
errors = errors.concat(spec.addElementsToSchema(schema));
|
|
1393
|
+
}
|
|
1394
|
+
return errors;
|
|
1366
1395
|
}
|
|
1367
1396
|
|
|
1368
1397
|
export function parseFieldSetArgument({
|
package/src/federationSpec.ts
CHANGED
|
@@ -8,11 +8,9 @@ import {
|
|
|
8
8
|
ArgumentSpecification,
|
|
9
9
|
createDirectiveSpecification,
|
|
10
10
|
createScalarTypeSpecification,
|
|
11
|
-
DirectiveSpecification,
|
|
12
|
-
TypeSpecification,
|
|
13
11
|
} from "./directiveAndTypeSpecification";
|
|
14
|
-
import { DirectiveLocation
|
|
15
|
-
import { assert
|
|
12
|
+
import { DirectiveLocation } from "graphql";
|
|
13
|
+
import { assert } from "./utils";
|
|
16
14
|
import { TAG_VERSIONS } from "./tagSpec";
|
|
17
15
|
import { federationMetadata } from "./federation";
|
|
18
16
|
import { registerKnownFeature } from "./knownCoreFeatures";
|
|
@@ -40,17 +38,16 @@ export enum FederationDirectiveName {
|
|
|
40
38
|
|
|
41
39
|
const fieldSetTypeSpec = createScalarTypeSpecification({ name: FederationTypeName.FIELD_SET });
|
|
42
40
|
|
|
41
|
+
const fieldsArgument: ArgumentSpecification = { name: 'fields', type: (schema) => fieldSetType(schema) };
|
|
42
|
+
|
|
43
43
|
const keyDirectiveSpec = createDirectiveSpecification({
|
|
44
44
|
name: FederationDirectiveName.KEY,
|
|
45
45
|
locations: [DirectiveLocation.OBJECT, DirectiveLocation.INTERFACE],
|
|
46
46
|
repeatable: true,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
],
|
|
52
|
-
errors: [],
|
|
53
|
-
}),
|
|
47
|
+
args: [
|
|
48
|
+
fieldsArgument,
|
|
49
|
+
{ name: 'resolvable', type: (schema) => schema.booleanType(), defaultValue: true },
|
|
50
|
+
]
|
|
54
51
|
});
|
|
55
52
|
|
|
56
53
|
const extendsDirectiveSpec = createDirectiveSpecification({
|
|
@@ -61,28 +58,19 @@ const extendsDirectiveSpec = createDirectiveSpecification({
|
|
|
61
58
|
const externalDirectiveSpec = createDirectiveSpecification({
|
|
62
59
|
name: FederationDirectiveName.EXTERNAL,
|
|
63
60
|
locations: [DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION],
|
|
64
|
-
|
|
65
|
-
args: [{ name: 'reason', type: schema.stringType() }],
|
|
66
|
-
errors: [],
|
|
67
|
-
}),
|
|
61
|
+
args: [{ name: 'reason', type: (schema) => schema.stringType() }],
|
|
68
62
|
});
|
|
69
63
|
|
|
70
64
|
const requiresDirectiveSpec = createDirectiveSpecification({
|
|
71
65
|
name: FederationDirectiveName.REQUIRES,
|
|
72
66
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
73
|
-
|
|
74
|
-
args: [fieldsArgument(schema)],
|
|
75
|
-
errors: [],
|
|
76
|
-
}),
|
|
67
|
+
args: [fieldsArgument],
|
|
77
68
|
});
|
|
78
69
|
|
|
79
70
|
const providesDirectiveSpec = createDirectiveSpecification({
|
|
80
71
|
name: FederationDirectiveName.PROVIDES,
|
|
81
72
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
82
|
-
|
|
83
|
-
args: [fieldsArgument(schema)],
|
|
84
|
-
errors: [],
|
|
85
|
-
}),
|
|
73
|
+
args: [fieldsArgument],
|
|
86
74
|
});
|
|
87
75
|
|
|
88
76
|
const legacyFederationTypes = [
|
|
@@ -103,9 +91,6 @@ const legacyFederationDirectives = [
|
|
|
103
91
|
export const FEDERATION1_TYPES = legacyFederationTypes;
|
|
104
92
|
export const FEDERATION1_DIRECTIVES = legacyFederationDirectives;
|
|
105
93
|
|
|
106
|
-
function fieldsArgument(schema: Schema): ArgumentSpecification {
|
|
107
|
-
return { name: 'fields', type: fieldSetType(schema) };
|
|
108
|
-
}
|
|
109
94
|
|
|
110
95
|
function fieldSetType(schema: Schema): InputType {
|
|
111
96
|
const metadata = federationMetadata(schema);
|
|
@@ -114,9 +99,6 @@ function fieldSetType(schema: Schema): InputType {
|
|
|
114
99
|
}
|
|
115
100
|
|
|
116
101
|
export class FederationSpecDefinition extends FeatureDefinition {
|
|
117
|
-
private readonly _directiveSpecs = new MapWithCachedArrays<string, DirectiveSpecification>();
|
|
118
|
-
private readonly _typeSpecs = new MapWithCachedArrays<string, TypeSpecification>();
|
|
119
|
-
|
|
120
102
|
constructor(version: FeatureVersion) {
|
|
121
103
|
super(new FeatureUrl(federationIdentity, 'federation', version));
|
|
122
104
|
|
|
@@ -139,10 +121,7 @@ export class FederationSpecDefinition extends FeatureDefinition {
|
|
|
139
121
|
this.registerDirective(createDirectiveSpecification({
|
|
140
122
|
name: FederationDirectiveName.OVERRIDE,
|
|
141
123
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
142
|
-
|
|
143
|
-
args: [{ name: 'from', type: new NonNullType(schema.stringType()) }],
|
|
144
|
-
errors: [],
|
|
145
|
-
}),
|
|
124
|
+
args: [{ name: 'from', type: (schema) => new NonNullType(schema.stringType()) }],
|
|
146
125
|
}));
|
|
147
126
|
|
|
148
127
|
if (version >= (new FeatureVersion(2, 1))) {
|
|
@@ -150,10 +129,7 @@ export class FederationSpecDefinition extends FeatureDefinition {
|
|
|
150
129
|
name: FederationDirectiveName.COMPOSE_DIRECTIVE,
|
|
151
130
|
locations: [DirectiveLocation.SCHEMA],
|
|
152
131
|
repeatable: true,
|
|
153
|
-
|
|
154
|
-
args: [{ name: 'name', type: schema.stringType() }],
|
|
155
|
-
errors: [],
|
|
156
|
-
}),
|
|
132
|
+
args: [{ name: 'name', type: (schema) => schema.stringType() }],
|
|
157
133
|
}));
|
|
158
134
|
}
|
|
159
135
|
|
|
@@ -167,42 +143,6 @@ export class FederationSpecDefinition extends FeatureDefinition {
|
|
|
167
143
|
);
|
|
168
144
|
}
|
|
169
145
|
}
|
|
170
|
-
|
|
171
|
-
private registerDirective(spec: DirectiveSpecification) {
|
|
172
|
-
this._directiveSpecs.set(spec.name, spec);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
private registerType(spec: TypeSpecification) {
|
|
176
|
-
this._typeSpecs.set(spec.name, spec);
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
directiveSpecs(): readonly DirectiveSpecification[] {
|
|
180
|
-
return this._directiveSpecs.values();
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
typeSpecs(): readonly TypeSpecification[] {
|
|
184
|
-
return this._typeSpecs.values();
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
addElementsToSchema(schema: Schema): GraphQLError[] {
|
|
188
|
-
const feature = this.featureInSchema(schema);
|
|
189
|
-
assert(feature, 'The federation specification should have been added to the schema before this is called');
|
|
190
|
-
|
|
191
|
-
let errors: GraphQLError[] = [];
|
|
192
|
-
for (const type of this.typeSpecs()) {
|
|
193
|
-
errors = errors.concat(this.addTypeSpec(schema, type));
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
for (const directive of this.directiveSpecs()) {
|
|
197
|
-
errors = errors.concat(this.addDirectiveSpec(schema, directive));
|
|
198
|
-
}
|
|
199
|
-
return errors;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
allElementNames(): string[] {
|
|
203
|
-
return this.directiveSpecs().map((spec) => `@${spec.name}`)
|
|
204
|
-
.concat(this.typeSpecs().map((spec) => spec.name));
|
|
205
|
-
}
|
|
206
146
|
}
|
|
207
147
|
|
|
208
148
|
export const FEDERATION_VERSIONS = new FeatureDefinitions<FederationSpecDefinition>(federationIdentity)
|
package/src/inaccessibleSpec.ts
CHANGED
|
@@ -62,17 +62,16 @@ export class InaccessibleSpecDefinition extends FeatureDefinition {
|
|
|
62
62
|
this.inaccessibleDirectiveSpec = createDirectiveSpecification({
|
|
63
63
|
name: 'inaccessible',
|
|
64
64
|
locations: this.inaccessibleLocations,
|
|
65
|
+
composes: true,
|
|
66
|
+
supergraphSpecification: () => INACCESSIBLE_VERSIONS.latest(),
|
|
65
67
|
});
|
|
68
|
+
this.registerDirective(this.inaccessibleDirectiveSpec);
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
isV01() {
|
|
69
72
|
return this.version.equals(new FeatureVersion(0, 1));
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
addElementsToSchema(schema: Schema): GraphQLError[] {
|
|
73
|
-
return this.addDirectiveSpec(schema, this.inaccessibleDirectiveSpec);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
75
|
inaccessibleDirective(schema: Schema): DirectiveDefinition<Record<string, never>> | undefined {
|
|
77
76
|
return this.directive(schema, 'inaccessible');
|
|
78
77
|
}
|
|
@@ -89,10 +88,6 @@ export class InaccessibleSpecDefinition extends FeatureDefinition {
|
|
|
89
88
|
return undefined;
|
|
90
89
|
}
|
|
91
90
|
|
|
92
|
-
allElementNames(): string[] {
|
|
93
|
-
return ['@inaccessible'];
|
|
94
|
-
}
|
|
95
|
-
|
|
96
91
|
get defaultCorePurpose(): CorePurpose | undefined {
|
|
97
92
|
return 'SECURITY';
|
|
98
93
|
}
|
|
@@ -891,9 +886,7 @@ function getInputType(element: SchemaElementWithDefaultValue): InputType {
|
|
|
891
886
|
// similar to the "Values of Correct Type" validation in the GraphQL spec.
|
|
892
887
|
// However, there are two noteable differences:
|
|
893
888
|
// 1. Variable references are not allowed.
|
|
894
|
-
// 2. Scalar values are not required to be coercible (due to machine-specific
|
|
895
|
-
// differences in input coercion rules).
|
|
896
|
-
//
|
|
889
|
+
// 2. Scalar values are not required to be coercible (due to machine-specific differences in input coercion rules).
|
|
897
890
|
// As it turns out, building a Schema object validates this (and a bit more)
|
|
898
891
|
// already, so in the interests of not duplicating validations/keeping the logic
|
|
899
892
|
// centralized, this code assumes the input values it receives satisfy the above
|
package/src/index.ts
CHANGED
|
@@ -18,3 +18,6 @@ export * from './error';
|
|
|
18
18
|
export * from './schemaUpgrader';
|
|
19
19
|
export * from './suggestions';
|
|
20
20
|
export * from './graphQLJSSchemaToAST';
|
|
21
|
+
export * from './directiveAndTypeSpecification';
|
|
22
|
+
export { coreFeatureDefinitionIfKnown } from './knownCoreFeatures';
|
|
23
|
+
export * from './argumentCompositionStrategies';
|
package/src/knownCoreFeatures.ts
CHANGED
|
@@ -11,3 +11,12 @@ export function registerKnownFeature(definitions: FeatureDefinitions) {
|
|
|
11
11
|
export function coreFeatureDefinitionIfKnown(url: FeatureUrl): FeatureDefinition | undefined {
|
|
12
12
|
return registeredFeatures.get(url.identity)?.find(url.version);
|
|
13
13
|
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Removes a feature from the set of known features.
|
|
17
|
+
*
|
|
18
|
+
* This exists purely for testing purposes. There is no reason to unregistered features otherwise.
|
|
19
|
+
*/
|
|
20
|
+
export function unregisterKnownFeatures(definitions: FeatureDefinitions) {
|
|
21
|
+
registeredFeatures.delete(definitions.identity);
|
|
22
|
+
}
|