@apollo/federation-internals 2.8.1 → 2.8.3-beta.0
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/dist/definitions.d.ts +5 -5
- package/dist/definitions.d.ts.map +1 -1
- package/dist/definitions.js +72 -58
- package/dist/definitions.js.map +1 -1
- package/dist/federation.d.ts +1 -1
- package/dist/federation.d.ts.map +1 -1
- package/dist/federation.js +6 -2
- package/dist/federation.js.map +1 -1
- package/dist/operations.d.ts.map +1 -1
- package/dist/operations.js +4 -3
- package/dist/operations.js.map +1 -1
- package/dist/schemaUpgrader.js +1 -1
- package/dist/schemaUpgrader.js.map +1 -1
- package/package.json +1 -1
- package/src/definitions.ts +80 -61
- package/src/federation.ts +10 -3
- package/src/operations.ts +4 -3
- package/src/schemaUpgrader.ts +1 -1
package/src/definitions.ts
CHANGED
|
@@ -59,6 +59,8 @@ import { coreFeatureDefinitionIfKnown } from "./knownCoreFeatures";
|
|
|
59
59
|
const validationErrorCode = 'GraphQLValidationFailed';
|
|
60
60
|
const DEFAULT_VALIDATION_ERROR_MESSAGE = 'The schema is not a valid GraphQL schema.';
|
|
61
61
|
|
|
62
|
+
const EMPTY_SET = new Set<never>();
|
|
63
|
+
|
|
62
64
|
export const ErrGraphQLValidationFailed = (causes: GraphQLError[], message: string = DEFAULT_VALIDATION_ERROR_MESSAGE) =>
|
|
63
65
|
aggregateError(validationErrorCode, message, causes);
|
|
64
66
|
|
|
@@ -660,7 +662,7 @@ export abstract class NamedSchemaElement<TOwnType extends NamedSchemaElement<TOw
|
|
|
660
662
|
}
|
|
661
663
|
|
|
662
664
|
abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSchemaElement<TOwnType, Schema, TReferencer>> extends NamedSchemaElement<TOwnType, Schema, TReferencer> {
|
|
663
|
-
protected _referencers?: TReferencer
|
|
665
|
+
protected _referencers?: Set<TReferencer>;
|
|
664
666
|
protected _extensions?: Extension<TOwnType>[];
|
|
665
667
|
public preserveEmptyDefinition: boolean = false;
|
|
666
668
|
|
|
@@ -669,19 +671,12 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
669
671
|
}
|
|
670
672
|
|
|
671
673
|
private addReferencer(referencer: TReferencer) {
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
this._referencers.push(referencer);
|
|
675
|
-
}
|
|
676
|
-
} else {
|
|
677
|
-
this._referencers = [ referencer ];
|
|
678
|
-
}
|
|
674
|
+
this._referencers ??= new Set();
|
|
675
|
+
this._referencers.add(referencer);
|
|
679
676
|
}
|
|
680
677
|
|
|
681
678
|
private removeReferencer(referencer: TReferencer) {
|
|
682
|
-
|
|
683
|
-
removeArrayElement(referencer, this._referencers);
|
|
684
|
-
}
|
|
679
|
+
this._referencers?.delete(referencer)
|
|
685
680
|
}
|
|
686
681
|
|
|
687
682
|
get coordinate(): string {
|
|
@@ -789,10 +784,11 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
789
784
|
this.removeAppliedDirectives();
|
|
790
785
|
this.removeInnerElements();
|
|
791
786
|
// Remove this type's references.
|
|
792
|
-
const toReturn =
|
|
787
|
+
const toReturn: TReferencer[] = [];
|
|
788
|
+
this._referencers?.forEach(r => {
|
|
793
789
|
SchemaElement.prototype['removeTypeReferenceInternal'].call(r, this);
|
|
794
|
-
|
|
795
|
-
})
|
|
790
|
+
toReturn.push(r);
|
|
791
|
+
});
|
|
796
792
|
this._referencers = undefined;
|
|
797
793
|
// Remove this type from its parent schema.
|
|
798
794
|
Schema.prototype['removeTypeInternal'].call(this._parent, this);
|
|
@@ -820,8 +816,8 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
|
|
|
820
816
|
|
|
821
817
|
protected abstract removeReferenceRecursive(ref: TReferencer): void;
|
|
822
818
|
|
|
823
|
-
referencers():
|
|
824
|
-
return this._referencers ??
|
|
819
|
+
referencers(): ReadonlySet<TReferencer> {
|
|
820
|
+
return this._referencers ?? EMPTY_SET;
|
|
825
821
|
}
|
|
826
822
|
|
|
827
823
|
isReferenced(): boolean {
|
|
@@ -1261,7 +1257,7 @@ export class Schema {
|
|
|
1261
1257
|
if (!this.apiSchema) {
|
|
1262
1258
|
this.validate();
|
|
1263
1259
|
|
|
1264
|
-
const apiSchema = this.clone();
|
|
1260
|
+
const apiSchema = this.clone(undefined, false);
|
|
1265
1261
|
|
|
1266
1262
|
// As we compute the API schema of a supergraph, we want to ignore explicit definitions of `@defer` and `@stream` because
|
|
1267
1263
|
// those correspond to the merging of potential definitions from the subgraphs, but whether the supergraph API schema
|
|
@@ -1611,9 +1607,9 @@ export class Schema {
|
|
|
1611
1607
|
this.isValidated = true;
|
|
1612
1608
|
}
|
|
1613
1609
|
|
|
1614
|
-
clone(builtIns?: SchemaBlueprint): Schema {
|
|
1610
|
+
clone(builtIns?: SchemaBlueprint, cloneJoinDirectives: boolean = true): Schema {
|
|
1615
1611
|
const cloned = new Schema(builtIns ?? this.blueprint);
|
|
1616
|
-
copy(this, cloned);
|
|
1612
|
+
copy(this, cloned, cloneJoinDirectives);
|
|
1617
1613
|
if (this.isValidated) {
|
|
1618
1614
|
cloned.assumeValid();
|
|
1619
1615
|
}
|
|
@@ -2124,7 +2120,13 @@ export class ObjectType extends FieldBasedType<ObjectType, ObjectTypeReferencer>
|
|
|
2124
2120
|
}
|
|
2125
2121
|
|
|
2126
2122
|
unionsWhereMember(): readonly UnionType[] {
|
|
2127
|
-
|
|
2123
|
+
const unions: UnionType[] = [];
|
|
2124
|
+
this._referencers?.forEach((r) => {
|
|
2125
|
+
if (r instanceof BaseNamedType && isUnionType(r)) {
|
|
2126
|
+
unions.push(r);
|
|
2127
|
+
}
|
|
2128
|
+
});
|
|
2129
|
+
return unions;
|
|
2128
2130
|
}
|
|
2129
2131
|
}
|
|
2130
2132
|
|
|
@@ -2133,7 +2135,13 @@ export class InterfaceType extends FieldBasedType<InterfaceType, InterfaceTypeRe
|
|
|
2133
2135
|
readonly astDefinitionKind = Kind.INTERFACE_TYPE_DEFINITION;
|
|
2134
2136
|
|
|
2135
2137
|
allImplementations(): (ObjectType | InterfaceType)[] {
|
|
2136
|
-
|
|
2138
|
+
const implementations: (ObjectType | InterfaceType)[] = [];
|
|
2139
|
+
this.referencers().forEach(ref => {
|
|
2140
|
+
if (ref.kind === 'ObjectType' || ref.kind === 'InterfaceType') {
|
|
2141
|
+
implementations.push(ref);
|
|
2142
|
+
}
|
|
2143
|
+
});
|
|
2144
|
+
return implementations;
|
|
2137
2145
|
}
|
|
2138
2146
|
|
|
2139
2147
|
possibleRuntimeTypes(): readonly ObjectType[] {
|
|
@@ -2291,7 +2299,7 @@ export class UnionType extends BaseNamedType<OutputTypeReferencer, UnionType> {
|
|
|
2291
2299
|
export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
|
|
2292
2300
|
readonly kind = 'EnumType' as const;
|
|
2293
2301
|
readonly astDefinitionKind = Kind.ENUM_TYPE_DEFINITION;
|
|
2294
|
-
|
|
2302
|
+
private _values = new Map<string, EnumValue>();
|
|
2295
2303
|
|
|
2296
2304
|
get values(): readonly EnumValue[] {
|
|
2297
2305
|
// Because our abstractions are mutable, and removal is done by calling
|
|
@@ -2299,11 +2307,11 @@ export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
|
|
|
2299
2307
|
// try to iterate on the result of this method and call `remove()` on
|
|
2300
2308
|
// some of the return value based on some condition. But this will break
|
|
2301
2309
|
// in an error-prone way if we don't copy, so we do.
|
|
2302
|
-
return Array.from(this._values);
|
|
2310
|
+
return Array.from(this._values.values());
|
|
2303
2311
|
}
|
|
2304
|
-
|
|
2312
|
+
|
|
2305
2313
|
value(name: string): EnumValue | undefined {
|
|
2306
|
-
return this._values.
|
|
2314
|
+
return this._values.get(name);
|
|
2307
2315
|
}
|
|
2308
2316
|
|
|
2309
2317
|
addValue(value: EnumValue): EnumValue;
|
|
@@ -2319,7 +2327,7 @@ export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
|
|
|
2319
2327
|
}
|
|
2320
2328
|
const existing = this.value(toAdd.name);
|
|
2321
2329
|
if (!existing) {
|
|
2322
|
-
this._values.
|
|
2330
|
+
this._values.set(toAdd.name, toAdd);
|
|
2323
2331
|
Element.prototype['setParent'].call(toAdd, this);
|
|
2324
2332
|
this.onModification();
|
|
2325
2333
|
return toAdd;
|
|
@@ -2333,7 +2341,7 @@ export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
|
|
|
2333
2341
|
}
|
|
2334
2342
|
|
|
2335
2343
|
private removeValueInternal(value: EnumValue) {
|
|
2336
|
-
|
|
2344
|
+
this._values.delete(value.name);
|
|
2337
2345
|
}
|
|
2338
2346
|
|
|
2339
2347
|
protected removeInnerElements(): void {
|
|
@@ -2345,7 +2353,7 @@ export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
|
|
|
2345
2353
|
}
|
|
2346
2354
|
|
|
2347
2355
|
protected hasNonExtensionInnerElements(): boolean {
|
|
2348
|
-
return this._values.some(v => v.ofExtension() === undefined);
|
|
2356
|
+
return Array.from(this._values.values()).some(v => v.ofExtension() === undefined);
|
|
2349
2357
|
}
|
|
2350
2358
|
|
|
2351
2359
|
protected removeReferenceRecursive(ref: OutputTypeReferencer): void {
|
|
@@ -2353,7 +2361,9 @@ export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
|
|
|
2353
2361
|
}
|
|
2354
2362
|
|
|
2355
2363
|
protected removeInnerElementsExtensions(): void {
|
|
2356
|
-
|
|
2364
|
+
for (const v of this._values.values()) {
|
|
2365
|
+
v.removeOfExtension();
|
|
2366
|
+
}
|
|
2357
2367
|
}
|
|
2358
2368
|
}
|
|
2359
2369
|
|
|
@@ -2893,7 +2903,7 @@ export class DirectiveDefinition<TApplicationArgs extends {[key: string]: any} =
|
|
|
2893
2903
|
private _args?: MapWithCachedArrays<string, ArgumentDefinition<DirectiveDefinition>>;
|
|
2894
2904
|
repeatable: boolean = false;
|
|
2895
2905
|
private readonly _locations: DirectiveLocation[] = [];
|
|
2896
|
-
private _referencers?: Directive<SchemaElement<any, any>, TApplicationArgs
|
|
2906
|
+
private _referencers?: Set<Directive<SchemaElement<any, any>, TApplicationArgs>>;
|
|
2897
2907
|
|
|
2898
2908
|
constructor(name: string, readonly isBuiltIn: boolean = false) {
|
|
2899
2909
|
super(name);
|
|
@@ -2997,25 +3007,19 @@ export class DirectiveDefinition<TApplicationArgs extends {[key: string]: any} =
|
|
|
2997
3007
|
return this.locations.some((loc) => isTypeSystemDirectiveLocation(loc));
|
|
2998
3008
|
}
|
|
2999
3009
|
|
|
3000
|
-
applications():
|
|
3001
|
-
|
|
3010
|
+
applications(): ReadonlySet<Directive<SchemaElement<any, any>, TApplicationArgs>> {
|
|
3011
|
+
this._referencers ??= new Set();
|
|
3012
|
+
return this._referencers;
|
|
3002
3013
|
}
|
|
3003
3014
|
|
|
3004
3015
|
private addReferencer(referencer: Directive<SchemaElement<any, any>, TApplicationArgs>) {
|
|
3005
3016
|
assert(referencer, 'Referencer should exists');
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
this._referencers.push(referencer);
|
|
3009
|
-
}
|
|
3010
|
-
} else {
|
|
3011
|
-
this._referencers = [ referencer ];
|
|
3012
|
-
}
|
|
3017
|
+
this._referencers ??= new Set();
|
|
3018
|
+
this._referencers.add(referencer);
|
|
3013
3019
|
}
|
|
3014
3020
|
|
|
3015
3021
|
private removeReferencer(referencer: Directive<SchemaElement<any, any>, TApplicationArgs>) {
|
|
3016
|
-
|
|
3017
|
-
removeArrayElement(referencer, this._referencers);
|
|
3018
|
-
}
|
|
3022
|
+
this._referencers?.delete(referencer);
|
|
3019
3023
|
}
|
|
3020
3024
|
|
|
3021
3025
|
protected removeTypeReference(type: NamedType) {
|
|
@@ -3046,7 +3050,7 @@ export class DirectiveDefinition<TApplicationArgs extends {[key: string]: any} =
|
|
|
3046
3050
|
// doesn't store a link to that definition. Instead, we fetch the definition
|
|
3047
3051
|
// from the schema when requested. So we don't have to do anything on the
|
|
3048
3052
|
// referencers other than clear them (and return the pre-cleared set).
|
|
3049
|
-
const toReturn = this._referencers ?? [];
|
|
3053
|
+
const toReturn = Array.from(this._referencers ?? []);
|
|
3050
3054
|
this._referencers = undefined;
|
|
3051
3055
|
// Remove this directive definition from its parent schema.
|
|
3052
3056
|
Schema.prototype['removeDirectiveInternal'].call(this._parent, this);
|
|
@@ -3596,7 +3600,7 @@ export function copyDirectiveDefinitionToSchema({
|
|
|
3596
3600
|
);
|
|
3597
3601
|
}
|
|
3598
3602
|
|
|
3599
|
-
function copy(source: Schema, dest: Schema) {
|
|
3603
|
+
function copy(source: Schema, dest: Schema, cloneJoinDirectives: boolean) {
|
|
3600
3604
|
// We shallow copy types first so any future reference to any of them can be dereferenced.
|
|
3601
3605
|
for (const type of typesToCopy(source, dest)) {
|
|
3602
3606
|
dest.addType(newNamedType(type.kind, type.name));
|
|
@@ -3613,7 +3617,7 @@ function copy(source: Schema, dest: Schema) {
|
|
|
3613
3617
|
|
|
3614
3618
|
copySchemaDefinitionInner(source.schemaDefinition, dest.schemaDefinition);
|
|
3615
3619
|
for (const type of typesToCopy(source, dest)) {
|
|
3616
|
-
copyNamedTypeInner(type, dest.type(type.name)
|
|
3620
|
+
copyNamedTypeInner(type, dest.type(type.name)!, cloneJoinDirectives);
|
|
3617
3621
|
}
|
|
3618
3622
|
}
|
|
3619
3623
|
|
|
@@ -3653,7 +3657,7 @@ function copySchemaDefinitionInner(source: SchemaDefinition, dest: SchemaDefinit
|
|
|
3653
3657
|
dest.sourceAST = source.sourceAST;
|
|
3654
3658
|
}
|
|
3655
3659
|
|
|
3656
|
-
function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
3660
|
+
function copyNamedTypeInner(source: NamedType, dest: NamedType, cloneJoinDirectives: boolean) {
|
|
3657
3661
|
dest.preserveEmptyDefinition = source.preserveEmptyDefinition;
|
|
3658
3662
|
const extensionsMap = copyExtensions(source, dest);
|
|
3659
3663
|
// Same as copyAppliedDirectives, but as the directive applies to the type, we need to remember if the application
|
|
@@ -3670,7 +3674,7 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
|
3670
3674
|
for (const sourceField of source.fields()) {
|
|
3671
3675
|
const destField = destFieldBasedType.addField(new FieldDefinition(sourceField.name));
|
|
3672
3676
|
copyOfExtension(extensionsMap, sourceField, destField);
|
|
3673
|
-
copyFieldDefinitionInner(sourceField, destField);
|
|
3677
|
+
copyFieldDefinitionInner(sourceField, destField, cloneJoinDirectives);
|
|
3674
3678
|
}
|
|
3675
3679
|
for (const sourceImpl of source.interfaceImplementations()) {
|
|
3676
3680
|
const destImpl = destFieldBasedType.addImplementedInterface(sourceImpl.interface.name);
|
|
@@ -3690,7 +3694,7 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
|
3690
3694
|
const destValue = destEnumType.addValue(sourceValue.name);
|
|
3691
3695
|
destValue.description = sourceValue.description;
|
|
3692
3696
|
copyOfExtension(extensionsMap, sourceValue, destValue);
|
|
3693
|
-
copyAppliedDirectives(sourceValue, destValue);
|
|
3697
|
+
copyAppliedDirectives(sourceValue, destValue, cloneJoinDirectives);
|
|
3694
3698
|
}
|
|
3695
3699
|
break
|
|
3696
3700
|
case 'InputObjectType':
|
|
@@ -3698,13 +3702,13 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
|
|
|
3698
3702
|
for (const sourceField of source.fields()) {
|
|
3699
3703
|
const destField = destInputType.addField(new InputFieldDefinition(sourceField.name));
|
|
3700
3704
|
copyOfExtension(extensionsMap, sourceField, destField);
|
|
3701
|
-
copyInputFieldDefinitionInner(sourceField, destField);
|
|
3705
|
+
copyInputFieldDefinitionInner(sourceField, destField, cloneJoinDirectives);
|
|
3702
3706
|
}
|
|
3703
3707
|
}
|
|
3704
3708
|
}
|
|
3705
3709
|
|
|
3706
|
-
function copyAppliedDirectives(source: SchemaElement<any, any>, dest: SchemaElement<any, any
|
|
3707
|
-
source.appliedDirectives.forEach((d) => copyAppliedDirective(d, dest));
|
|
3710
|
+
function copyAppliedDirectives(source: SchemaElement<any, any>, dest: SchemaElement<any, any>, cloneJoinDirectives: boolean) {
|
|
3711
|
+
source.appliedDirectives.filter(d => cloneJoinDirectives || !d.name.startsWith('join__')).forEach((d) => copyAppliedDirective(d, dest));
|
|
3708
3712
|
}
|
|
3709
3713
|
|
|
3710
3714
|
function copyAppliedDirective(source: Directive<any, any>, dest: SchemaElement<any, any>): Directive<any, any> {
|
|
@@ -3713,23 +3717,27 @@ function copyAppliedDirective(source: Directive<any, any>, dest: SchemaElement<a
|
|
|
3713
3717
|
return res;
|
|
3714
3718
|
}
|
|
3715
3719
|
|
|
3716
|
-
function copyFieldDefinitionInner<P extends ObjectType | InterfaceType>(source: FieldDefinition<P>, dest: FieldDefinition<P
|
|
3720
|
+
function copyFieldDefinitionInner<P extends ObjectType | InterfaceType>(source: FieldDefinition<P>, dest: FieldDefinition<P>, cloneJoinDirectives: boolean) {
|
|
3717
3721
|
const type = copyWrapperTypeOrTypeRef(source.type, dest.schema()) as OutputType;
|
|
3718
3722
|
dest.type = type;
|
|
3719
3723
|
for (const arg of source.arguments()) {
|
|
3720
3724
|
const argType = copyWrapperTypeOrTypeRef(arg.type, dest.schema());
|
|
3721
|
-
copyArgumentDefinitionInner(
|
|
3725
|
+
copyArgumentDefinitionInner({
|
|
3726
|
+
source: arg,
|
|
3727
|
+
dest: dest.addArgument(arg.name, argType as InputType),
|
|
3728
|
+
cloneJoinDirectives,
|
|
3729
|
+
});
|
|
3722
3730
|
}
|
|
3723
|
-
copyAppliedDirectives(source, dest);
|
|
3731
|
+
copyAppliedDirectives(source, dest, cloneJoinDirectives);
|
|
3724
3732
|
dest.description = source.description;
|
|
3725
3733
|
dest.sourceAST = source.sourceAST;
|
|
3726
3734
|
}
|
|
3727
3735
|
|
|
3728
|
-
function copyInputFieldDefinitionInner(source: InputFieldDefinition, dest: InputFieldDefinition) {
|
|
3736
|
+
function copyInputFieldDefinitionInner(source: InputFieldDefinition, dest: InputFieldDefinition, cloneJoinDirectives: boolean) {
|
|
3729
3737
|
const type = copyWrapperTypeOrTypeRef(source.type, dest.schema()) as InputType;
|
|
3730
3738
|
dest.type = type;
|
|
3731
3739
|
dest.defaultValue = source.defaultValue;
|
|
3732
|
-
copyAppliedDirectives(source, dest);
|
|
3740
|
+
copyAppliedDirectives(source, dest, cloneJoinDirectives);
|
|
3733
3741
|
dest.description = source.description;
|
|
3734
3742
|
dest.sourceAST = source.sourceAST;
|
|
3735
3743
|
}
|
|
@@ -3748,16 +3756,22 @@ function copyWrapperTypeOrTypeRef(source: Type | undefined, destParent: Schema):
|
|
|
3748
3756
|
}
|
|
3749
3757
|
}
|
|
3750
3758
|
|
|
3751
|
-
function copyArgumentDefinitionInner<P extends FieldDefinition<any> | DirectiveDefinition>(
|
|
3759
|
+
function copyArgumentDefinitionInner<P extends FieldDefinition<any> | DirectiveDefinition>({
|
|
3760
|
+
source,
|
|
3761
|
+
dest,
|
|
3762
|
+
copyDirectiveApplications = true,
|
|
3763
|
+
cloneJoinDirectives,
|
|
3764
|
+
}: {
|
|
3752
3765
|
source: ArgumentDefinition<P>,
|
|
3753
3766
|
dest: ArgumentDefinition<P>,
|
|
3754
|
-
copyDirectiveApplications
|
|
3755
|
-
|
|
3767
|
+
copyDirectiveApplications?: boolean,
|
|
3768
|
+
cloneJoinDirectives: boolean,
|
|
3769
|
+
}) {
|
|
3756
3770
|
const type = copyWrapperTypeOrTypeRef(source.type, dest.schema()) as InputType;
|
|
3757
3771
|
dest.type = type;
|
|
3758
3772
|
dest.defaultValue = source.defaultValue;
|
|
3759
3773
|
if (copyDirectiveApplications) {
|
|
3760
|
-
copyAppliedDirectives(source, dest);
|
|
3774
|
+
copyAppliedDirectives(source, dest, cloneJoinDirectives);
|
|
3761
3775
|
}
|
|
3762
3776
|
dest.description = source.description;
|
|
3763
3777
|
dest.sourceAST = source.sourceAST;
|
|
@@ -3779,7 +3793,12 @@ function copyDirectiveDefinitionInner(
|
|
|
3779
3793
|
|
|
3780
3794
|
for (const arg of source.arguments()) {
|
|
3781
3795
|
const type = copyWrapperTypeOrTypeRef(arg.type, dest.schema());
|
|
3782
|
-
copyArgumentDefinitionInner(
|
|
3796
|
+
copyArgumentDefinitionInner({
|
|
3797
|
+
source: arg,
|
|
3798
|
+
dest: dest.addArgument(arg.name, type as InputType),
|
|
3799
|
+
copyDirectiveApplications: copyDirectiveApplicationsInArguments,
|
|
3800
|
+
cloneJoinDirectives: true,
|
|
3801
|
+
});
|
|
3783
3802
|
}
|
|
3784
3803
|
dest.repeatable = source.repeatable;
|
|
3785
3804
|
dest.addLocations(...locations);
|
package/src/federation.ts
CHANGED
|
@@ -1195,7 +1195,7 @@ export class FederationMetadata {
|
|
|
1195
1195
|
): Post20FederationDirectiveDefinition<TApplicationArgs> {
|
|
1196
1196
|
return this.getFederationDirective<TApplicationArgs>(name) ?? {
|
|
1197
1197
|
name,
|
|
1198
|
-
applications: () => new
|
|
1198
|
+
applications: () => new Set<Directive<any, TApplicationArgs>>(),
|
|
1199
1199
|
};
|
|
1200
1200
|
}
|
|
1201
1201
|
|
|
@@ -1391,7 +1391,7 @@ export class FederationMetadata {
|
|
|
1391
1391
|
|
|
1392
1392
|
export type FederationDirectiveNotDefinedInSchema<TApplicationArgs extends {[key: string]: any}> = {
|
|
1393
1393
|
name: string,
|
|
1394
|
-
applications: () =>
|
|
1394
|
+
applications: () => ReadonlySet<Directive<any, TApplicationArgs>>,
|
|
1395
1395
|
}
|
|
1396
1396
|
|
|
1397
1397
|
export type Post20FederationDirectiveDefinition<TApplicationArgs extends {[key: string]: any}> =
|
|
@@ -1577,12 +1577,19 @@ export class FederationBlueprint extends SchemaBlueprint {
|
|
|
1577
1577
|
const parent = application.parent;
|
|
1578
1578
|
const name = application.arguments().name as string;
|
|
1579
1579
|
|
|
1580
|
+
const match = name.match(/^([A-Za-z]\w*)$/);
|
|
1580
1581
|
if (name.includes('_')) {
|
|
1581
1582
|
errorCollector.push(ERRORS.CONTEXT_NAME_INVALID.err(
|
|
1582
1583
|
`Context name "${name}" may not contain an underscore.`,
|
|
1583
1584
|
{ nodes: sourceASTs(application) }
|
|
1584
1585
|
));
|
|
1585
1586
|
}
|
|
1587
|
+
else if (!match) {
|
|
1588
|
+
errorCollector.push(ERRORS.CONTEXT_NAME_INVALID.err(
|
|
1589
|
+
`Context name "${name}" is invalid. It should have only alphanumeric characters.`,
|
|
1590
|
+
{ nodes: sourceASTs(application) }
|
|
1591
|
+
));
|
|
1592
|
+
}
|
|
1586
1593
|
const types = contextToTypeMap.get(name);
|
|
1587
1594
|
if (types) {
|
|
1588
1595
|
types.push(parent);
|
|
@@ -2033,7 +2040,7 @@ function completeFed1SubgraphSchema(schema: Schema): GraphQLError[] {
|
|
|
2033
2040
|
// definition to re-add the "correct" version, we'd have to re-attach existing applications (doable but not
|
|
2034
2041
|
// done). This assert is so we notice it quickly if that ever happens (again, unlikely, because fed1 schema
|
|
2035
2042
|
// is a backward compatibility thing and there is no reason to expand that too much in the future).
|
|
2036
|
-
assert(directive.applications().
|
|
2043
|
+
assert(directive.applications().size === 0, `${directive} shouldn't have had validation at that places`);
|
|
2037
2044
|
|
|
2038
2045
|
// The patterns we recognize and "correct" (by essentially ignoring the definition)
|
|
2039
2046
|
// are:
|
package/src/operations.ts
CHANGED
|
@@ -1594,16 +1594,17 @@ export class SelectionSet {
|
|
|
1594
1594
|
// No match, so we need to create a new fragment. First, we minimize the
|
|
1595
1595
|
// selection set before creating the fragment with it.
|
|
1596
1596
|
const [minimizedSelectionSet] = selection.selectionSet.minimizeSelectionSet(namedFragments, seenSelections);
|
|
1597
|
+
const updatedEquivalentSelectionSetCandidates = seenSelections.get(mockHashCode); // may have changed after previous statement
|
|
1597
1598
|
const fragmentDefinition = new NamedFragmentDefinition(
|
|
1598
1599
|
this.parentType.schema(),
|
|
1599
|
-
`_generated_${mockHashCode}_${
|
|
1600
|
+
`_generated_${mockHashCode}_${updatedEquivalentSelectionSetCandidates?.length ?? 0}`,
|
|
1600
1601
|
selection.element.typeCondition
|
|
1601
1602
|
).setSelectionSet(minimizedSelectionSet);
|
|
1602
1603
|
namedFragments.add(fragmentDefinition);
|
|
1603
1604
|
|
|
1604
1605
|
// Create a new "hash code" bucket or add to the existing one.
|
|
1605
|
-
if (
|
|
1606
|
-
|
|
1606
|
+
if (updatedEquivalentSelectionSetCandidates) {
|
|
1607
|
+
updatedEquivalentSelectionSetCandidates.push([selection.selectionSet, fragmentDefinition]);
|
|
1607
1608
|
} else {
|
|
1608
1609
|
seenSelections.set(mockHashCode, [[selection.selectionSet, fragmentDefinition]]);
|
|
1609
1610
|
}
|
package/src/schemaUpgrader.ts
CHANGED
|
@@ -233,7 +233,7 @@ export function upgradeSubgraphsIfNecessary(inputs: Subgraphs): UpgradeResult {
|
|
|
233
233
|
for (const subgraph of inputs.values()) {
|
|
234
234
|
if (subgraph.isFed2Subgraph()) {
|
|
235
235
|
subgraphs.add(subgraph);
|
|
236
|
-
if (subgraph.metadata().interfaceObjectDirective().applications().
|
|
236
|
+
if (subgraph.metadata().interfaceObjectDirective().applications().size > 0) {
|
|
237
237
|
subgraphsUsingInterfaceObject.push(subgraph.name);
|
|
238
238
|
}
|
|
239
239
|
} else {
|