@apollo/federation-internals 2.0.0-alpha.4 → 2.0.0-preview.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +11 -1
  2. package/dist/buildSchema.d.ts +7 -3
  3. package/dist/buildSchema.d.ts.map +1 -1
  4. package/dist/buildSchema.js +41 -22
  5. package/dist/buildSchema.js.map +1 -1
  6. package/dist/coreSpec.d.ts +26 -4
  7. package/dist/coreSpec.d.ts.map +1 -1
  8. package/dist/coreSpec.js +86 -25
  9. package/dist/coreSpec.js.map +1 -1
  10. package/dist/definitions.d.ts +50 -43
  11. package/dist/definitions.d.ts.map +1 -1
  12. package/dist/definitions.js +201 -217
  13. package/dist/definitions.js.map +1 -1
  14. package/dist/directiveAndTypeSpecification.d.ts +38 -0
  15. package/dist/directiveAndTypeSpecification.d.ts.map +1 -0
  16. package/dist/directiveAndTypeSpecification.js +196 -0
  17. package/dist/directiveAndTypeSpecification.js.map +1 -0
  18. package/dist/error.d.ts +10 -1
  19. package/dist/error.d.ts.map +1 -1
  20. package/dist/error.js +22 -2
  21. package/dist/error.js.map +1 -1
  22. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  23. package/dist/extractSubgraphsFromSupergraph.js +29 -94
  24. package/dist/extractSubgraphsFromSupergraph.js.map +1 -1
  25. package/dist/federation.d.ts +88 -46
  26. package/dist/federation.d.ts.map +1 -1
  27. package/dist/federation.js +745 -233
  28. package/dist/federation.js.map +1 -1
  29. package/dist/federationSpec.d.ts +19 -0
  30. package/dist/federationSpec.d.ts.map +1 -0
  31. package/dist/federationSpec.js +91 -0
  32. package/dist/federationSpec.js.map +1 -0
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +7 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/joinSpec.d.ts +1 -0
  38. package/dist/joinSpec.d.ts.map +1 -1
  39. package/dist/joinSpec.js +1 -0
  40. package/dist/joinSpec.js.map +1 -1
  41. package/dist/operations.d.ts +8 -1
  42. package/dist/operations.d.ts.map +1 -1
  43. package/dist/operations.js +11 -4
  44. package/dist/operations.js.map +1 -1
  45. package/dist/print.d.ts +11 -9
  46. package/dist/print.d.ts.map +1 -1
  47. package/dist/print.js +21 -11
  48. package/dist/print.js.map +1 -1
  49. package/dist/schemaUpgrader.d.ts +108 -0
  50. package/dist/schemaUpgrader.d.ts.map +1 -0
  51. package/dist/schemaUpgrader.js +498 -0
  52. package/dist/schemaUpgrader.js.map +1 -0
  53. package/dist/sharing.d.ts +3 -0
  54. package/dist/sharing.d.ts.map +1 -0
  55. package/dist/sharing.js +51 -0
  56. package/dist/sharing.js.map +1 -0
  57. package/dist/supergraphs.d.ts.map +1 -1
  58. package/dist/supergraphs.js +2 -3
  59. package/dist/supergraphs.js.map +1 -1
  60. package/dist/tagSpec.d.ts.map +1 -1
  61. package/dist/tagSpec.js +1 -3
  62. package/dist/tagSpec.js.map +1 -1
  63. package/dist/utils.d.ts +8 -0
  64. package/dist/utils.d.ts.map +1 -1
  65. package/dist/utils.js +49 -1
  66. package/dist/utils.js.map +1 -1
  67. package/dist/validate.d.ts.map +1 -1
  68. package/dist/validate.js +9 -4
  69. package/dist/validate.js.map +1 -1
  70. package/dist/validation/KnownTypeNamesInFederationRule.d.ts.map +1 -1
  71. package/dist/validation/KnownTypeNamesInFederationRule.js +1 -2
  72. package/dist/validation/KnownTypeNamesInFederationRule.js.map +1 -1
  73. package/dist/values.d.ts +1 -0
  74. package/dist/values.d.ts.map +1 -1
  75. package/dist/values.js +3 -2
  76. package/dist/values.js.map +1 -1
  77. package/jest.config.js +5 -1
  78. package/package.json +4 -7
  79. package/src/__tests__/definitions.test.ts +19 -17
  80. package/src/__tests__/extractSubgraphsFromSupergraph.test.ts +103 -0
  81. package/src/__tests__/federation.test.ts +31 -0
  82. package/src/__tests__/operations.test.ts +2 -3
  83. package/src/__tests__/schemaUpgrader.test.ts +168 -0
  84. package/src/__tests__/subgraphValidation.test.ts +33 -19
  85. package/src/__tests__/values.test.ts +2 -4
  86. package/src/buildSchema.ts +55 -36
  87. package/src/coreSpec.ts +112 -31
  88. package/src/definitions.ts +247 -260
  89. package/src/directiveAndTypeSpecification.ts +276 -0
  90. package/src/error.ts +61 -5
  91. package/src/extractSubgraphsFromSupergraph.ts +35 -119
  92. package/src/federation.ts +960 -293
  93. package/src/federationSpec.ts +113 -0
  94. package/src/index.ts +2 -0
  95. package/src/joinSpec.ts +2 -1
  96. package/src/operations.ts +22 -7
  97. package/src/print.ts +51 -38
  98. package/src/schemaUpgrader.ts +657 -0
  99. package/src/sharing.ts +68 -0
  100. package/src/supergraphs.ts +3 -3
  101. package/src/tagSpec.ts +1 -3
  102. package/src/utils.ts +85 -0
  103. package/src/validate.ts +13 -7
  104. package/src/validation/KnownTypeNamesInFederationRule.ts +1 -7
  105. package/src/values.ts +7 -3
  106. package/tsconfig.test.tsbuildinfo +1 -1
  107. package/tsconfig.tsbuildinfo +1 -1
@@ -12,16 +12,24 @@ import {
12
12
  ListTypeNode,
13
13
  NamedTypeNode,
14
14
  parse,
15
- printError,
16
15
  TypeNode,
17
16
  VariableDefinitionNode,
18
17
  VariableNode
19
18
  } from "graphql";
20
- import { CoreDirectiveArgs, CoreSpecDefinition, CORE_VERSIONS, FeatureUrl, isCoreSpecDirectiveApplication, removeFeatureElements } from "./coreSpec";
21
- import { arrayEquals, assert, mapValues, MapWithCachedArrays, setValues } from "./utils";
19
+ import {
20
+ CoreImport,
21
+ CoreOrLinkDirectiveArgs,
22
+ CoreSpecDefinition,
23
+ extractCoreFeatureImports,
24
+ FeatureUrl,
25
+ findCoreSpecVersion,
26
+ isCoreSpecDirectiveApplication,
27
+ removeFeatureElements,
28
+ } from "./coreSpec";
29
+ import { assert, mapValues, MapWithCachedArrays, setValues } from "./utils";
22
30
  import { withDefaultValues, valueEquals, valueToString, valueToAST, variablesInValue, valueFromAST, valueNodeToConstValueNode } from "./values";
23
31
  import { removeInaccessibleElements } from "./inaccessibleSpec";
24
- import { printSchema, Options, defaultPrintOptions } from './print';
32
+ import { defaultPrintOptions, printSchema } from './print';
25
33
  import { sameType } from './types';
26
34
  import { addIntrospectionFields, introspectionFieldNames, isIntrospectionName } from "./introspection";
27
35
  import { err } from '@apollo/core-schema';
@@ -30,6 +38,7 @@ import { validateSDL } from "graphql/validation/validate";
30
38
  import { SDLValidationRule } from "graphql/validation/ValidationContext";
31
39
  import { specifiedSDLRules } from "graphql/validation/specifiedRules";
32
40
  import { validateSchema } from "./validate";
41
+ import { createDirectiveSpecification, createScalarTypeSpecification, DirectiveSpecification, TypeSpecification } from "./directiveAndTypeSpecification";
33
42
 
34
43
  const validationErrorCode = 'GraphQLValidationFailed';
35
44
 
@@ -61,11 +70,11 @@ export function printGraphQLErrorsOrRethrow(e: Error): string {
61
70
  if (!causes) {
62
71
  throw e;
63
72
  }
64
- return causes.map(e => printError(e)).join('\n\n');
73
+ return causes.map(e => e.toString()).join('\n\n');
65
74
  }
66
75
 
67
76
  export function printErrors(errors: GraphQLError[]): string {
68
- return errors.map(e => printError(e)).join('\n\n');
77
+ return errors.map(e => e.toString()).join('\n\n');
69
78
  }
70
79
 
71
80
  export const typenameFieldName = '__typename';
@@ -93,6 +102,10 @@ function checkDefaultSchemaRoot(type: NamedType): SchemaRootKind | undefined {
93
102
  }
94
103
  }
95
104
 
105
+ export function isSchemaRootType(type: NamedType): boolean {
106
+ return isObjectType(type) && type.isRootType();
107
+ }
108
+
96
109
  export type Type = NamedType | WrapperType;
97
110
  export type NamedType = ScalarType | ObjectType | InterfaceType | UnionType | EnumType | InputObjectType;
98
111
  export type OutputType = ScalarType | ObjectType | InterfaceType | UnionType | EnumType | ListType<any> | NonNullType<any>;
@@ -131,7 +144,7 @@ export function isScalarType(type: Type): type is ScalarType {
131
144
  }
132
145
 
133
146
  export function isCustomScalarType(type: Type): boolean {
134
- return isScalarType(type) && !graphQLBuiltIns.defaultGraphQLBuiltInTypes.includes(type.name);
147
+ return isScalarType(type) && !graphQLBuiltInTypes.includes(type.name);
135
148
  }
136
149
 
137
150
  export function isIntType(type: Type): boolean {
@@ -490,7 +503,7 @@ export abstract class SchemaElement<TOwnType extends SchemaElement<any, TParent>
490
503
  let name: string;
491
504
  if (typeof nameOrDefOrDirective === 'string') {
492
505
  this.checkUpdate();
493
- const def = this.schema().directive(nameOrDefOrDirective);
506
+ const def = this.schema().directive(nameOrDefOrDirective) ?? this.schema().blueprint.onMissingDirectiveDefinition(this.schema(), nameOrDefOrDirective);
494
507
  if (!def) {
495
508
  throw new GraphQLError(`Cannot apply unknown directive "@${nameOrDefOrDirective}"`);
496
509
  }
@@ -636,6 +649,18 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
636
649
  return extension;
637
650
  }
638
651
 
652
+ removeExtensions() {
653
+ if (this._extensions.size === 0) {
654
+ return;
655
+ }
656
+
657
+ this._extensions.clear();
658
+ for (const directive of this._appliedDirectives) {
659
+ directive.removeOfExtension();
660
+ }
661
+ this.removeInnerElementsExtensions();
662
+ }
663
+
639
664
  isIntrospectionType(): boolean {
640
665
  return isIntrospectionName(this.name);
641
666
  }
@@ -649,6 +674,7 @@ abstract class BaseNamedType<TReferencer, TOwnType extends NamedType & NamedSche
649
674
  }
650
675
 
651
676
  protected abstract hasNonExtensionInnerElements(): boolean;
677
+ protected abstract removeInnerElementsExtensions(): void;
652
678
 
653
679
  protected isElementBuiltIn(): boolean {
654
680
  return this.isBuiltIn;
@@ -773,6 +799,10 @@ abstract class BaseExtensionMember<TExtended extends ExtendableElement> extends
773
799
  return this._extension;
774
800
  }
775
801
 
802
+ removeOfExtension() {
803
+ this._extension = undefined;
804
+ }
805
+
776
806
  setOfExtension(extension: Extension<TExtended> | undefined) {
777
807
  this.checkUpdate();
778
808
  // See similar comment on FieldDefinition.setOfExtension for why we have to cast.
@@ -792,224 +822,51 @@ abstract class BaseExtensionMember<TExtended extends ExtendableElement> extends
792
822
  protected abstract removeInner(): void;
793
823
  }
794
824
 
795
- function sortedMemberNames(u: UnionType): string[] {
796
- return u.members().map(m => m.type.name).sort((n1, n2) => n1.localeCompare(n2));
797
- }
798
-
799
- export class BuiltIns {
800
- readonly defaultGraphQLBuiltInTypes: readonly string[] = [ 'Int', 'Float', 'String', 'Boolean', 'ID' ];
801
- private readonly defaultGraphQLBuiltInDirectives: readonly string[] = [ 'include', 'skip', 'deprecated', 'specifiedBy' ];
802
-
803
- addBuiltInTypes(schema: Schema) {
804
- this.defaultGraphQLBuiltInTypes.forEach(t => this.addBuiltInScalar(schema, t));
805
- }
806
-
807
- addBuiltInDirectives(schema: Schema) {
808
- for (const name of ['include', 'skip']) {
809
- this.addBuiltInDirective(schema, name)
810
- .addLocations(DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT)
811
- .addArgument('if', new NonNullType(schema.booleanType()));
812
- }
813
- this.addBuiltInDirective(schema, 'deprecated')
814
- .addLocations(
815
- DirectiveLocation.FIELD_DEFINITION,
816
- DirectiveLocation.ENUM_VALUE,
817
- DirectiveLocation.ARGUMENT_DEFINITION,
818
- DirectiveLocation.INPUT_FIELD_DEFINITION,
819
- ).addArgument('reason', schema.stringType(), 'No longer supported');
820
- this.addBuiltInDirective(schema, 'specifiedBy')
821
- .addLocations(DirectiveLocation.SCALAR)
822
- .addArgument('url', new NonNullType(schema.stringType()));
823
- }
824
-
825
- isGraphQLBuiltIn(element: NamedType | DirectiveDefinition | FieldDefinition<any>): boolean {
826
- if (isIntrospectionName(element.name)) {
827
- return true;
828
- }
829
- if (element instanceof FieldDefinition) {
830
- return false;
831
- } else if (element instanceof DirectiveDefinition) {
832
- return this.defaultGraphQLBuiltInDirectives.includes(element.name);
833
- } else {
834
- return this.defaultGraphQLBuiltInTypes.includes(element.name);
835
- }
836
- }
837
-
838
- prepareValidation(_: Schema) {
839
- // No-op for graphQL built-ins, but overriden for federation built-ins.
840
- }
841
-
842
- onValidation(schema: Schema, unvalidatedDirectives?: string[]): GraphQLError[] {
843
- const errors: GraphQLError[] = [];
844
- // We make sure that if any of the built-ins has been redefined, then the redefinition is
845
- // the same as the built-in one.
846
- for (const type of schema.builtInTypes(undefined, true)) {
847
- const maybeRedefined = schema.type(type.name)!;
848
- if (!maybeRedefined.isBuiltIn) {
849
- this.ensureSameTypeStructure(type, maybeRedefined, errors);
850
- }
851
- }
852
-
853
- for (const directive of schema.builtInDirectives(true)) {
854
- if (unvalidatedDirectives && unvalidatedDirectives.includes(directive.name)) {
855
- continue;
856
- }
857
- const maybeRedefined = schema.directive(directive.name)!;
858
- if (!maybeRedefined.isBuiltIn) {
859
- this.ensureSameDirectiveStructure(directive, maybeRedefined, errors);
860
- }
861
- }
862
- return errors;
863
- }
864
-
865
- validationRules(): readonly SDLValidationRule[] {
866
- return specifiedSDLRules;
867
- }
868
-
869
- maybeUpdateSubgraphDocument(_: Schema, document: DocumentNode): DocumentNode {
870
- return document;
871
- }
872
-
873
- private ensureSameDirectiveStructure(builtIn: DirectiveDefinition<any>, manuallyDefined: DirectiveDefinition<any>, errors: GraphQLError[]) {
874
- this.ensureSameArguments(builtIn, manuallyDefined, `directive ${builtIn}`, errors);
875
- // It's ok to say you'll never repeat a built-in that is repeatable. It's not ok to repeat one that isn't.
876
- if (!builtIn.repeatable && manuallyDefined.repeatable) {
877
- errors.push(error(`Invalid redefinition of built-in directive ${builtIn}: ${builtIn} should${builtIn.repeatable ? "" : " not"} be repeatable`));
878
- }
879
- // Similarly, it's ok to say that you will never use a directive in some locations, but not that you will use it in places not allowed by the built-in.
880
- if (!manuallyDefined.locations.every(loc => builtIn.locations.includes(loc))) {
881
- errors.push(error(`Invalid redefinition of built-in directive ${builtIn}: ${builtIn} should have locations ${builtIn.locations.join(', ')}, but found (non-subset) ${manuallyDefined.locations.join(', ')}`));
882
- }
883
- }
884
-
885
- private ensureSameArguments(
886
- builtIn: { arguments(): readonly ArgumentDefinition<any>[] },
887
- manuallyDefined: { argument(name: string): ArgumentDefinition<any> | undefined, arguments(): readonly ArgumentDefinition<any>[] },
888
- what: string,
889
- errors: GraphQLError[]
890
- ) {
891
- const expectedArguments = builtIn.arguments();
892
- const foundArguments = manuallyDefined.arguments();
893
- if (expectedArguments.length !== foundArguments.length) {
894
- errors.push(error(`Invalid redefinition of built-in ${what}: should have ${expectedArguments.length} arguments but ${foundArguments.length} found in redefinition`));
895
- return;
896
- }
897
- for (const expectedArgument of expectedArguments) {
898
- const foundArgument = manuallyDefined.argument(expectedArgument.name)!;
899
- const expectedType = expectedArgument.type!;
900
- let actualType = foundArgument.type!;
901
- if (isNonNullType(actualType) && !isNonNullType(expectedType)) {
902
- // It's ok to redefine an optional argument as mandatory. For instance, if you want to force people on your team to provide a "deprecation reason", you can
903
- // redefine @deprecated as `directive @deprecated(reason: String!)...` to get validation. In other words, you are allowed to always pass an argument that
904
- // is optional if you so wish.
905
- actualType = actualType.ofType;
906
- }
907
- if (!sameType(expectedType, actualType)) {
908
- errors.push(error(`Invalid redefinition of built-in ${what}: ${expectedArgument.coordinate} should have type ${expectedArgument.type!} but found type ${foundArgument.type!}`));
909
- } else if (!isNonNullType(actualType) && !valueEquals(expectedArgument.defaultValue, foundArgument.defaultValue)) {
910
- errors.push(error(`Invalid redefinition of built-in ${what}: ${expectedArgument.coordinate} should have default value ${valueToString(expectedArgument.defaultValue)} but found default value ${valueToString(foundArgument.defaultValue)}`));
911
- }
912
- }
913
- }
914
-
915
- private ensureSameTypeStructure(builtIn: NamedType, manuallyDefined: NamedType, errors: GraphQLError[]) {
916
- if (builtIn.kind !== manuallyDefined.kind) {
917
- errors.push(error(`Invalid redefinition of built-in type ${builtIn}: ${builtIn} should be a ${builtIn.kind} type but redefined as a ${manuallyDefined.kind}`));
918
- return;
919
- }
920
-
921
- switch (builtIn.kind) {
922
- case 'ScalarType':
923
- // Nothing more to check for scalars.
924
- return;
925
- case 'ObjectType':
926
- const redefinedObject = manuallyDefined as ObjectType;
927
- for (const builtInField of builtIn.fields()) {
928
- const redefinedField = redefinedObject.field(builtInField.name);
929
- if (!redefinedField) {
930
- errors.push(error(`Invalid redefinition of built-in type ${builtIn}: redefinition is missing field ${builtInField}`));
931
- return;
932
- }
933
- // We allow adding non-nullability because we've seen redefinition of the federation _Service type with type String! for the `sdl` field
934
- // and we don't want to break backward compatibility as this doesn't feel too harmful.
935
- let rType = redefinedField.type!;
936
- if (!isNonNullType(builtInField.type!) && isNonNullType(rType)) {
937
- rType = rType.ofType;
938
- }
939
- if (!sameType(builtInField.type!, rType)) {
940
- errors.push(error(`Invalid redefinition of field ${builtInField} of built-in type ${builtIn}: should have type ${builtInField.type} but redefined with type ${redefinedField.type}`));
941
- return;
942
- }
943
- this.ensureSameArguments(builtInField, redefinedField, `field ${builtInField.coordinate}`, errors);
944
- }
945
- break;
946
- case 'UnionType':
947
- const redefinedUnion = manuallyDefined as UnionType;
948
- const builtInMembers = sortedMemberNames(builtIn);
949
- const redefinedMembers = sortedMemberNames(redefinedUnion);
950
- if (!arrayEquals(builtInMembers, redefinedMembers)) {
951
- errors.push(error(`Invalid redefinition of built-in type ${builtIn}: redefinition has members [${redefinedMembers}] but should have members [${builtInMembers}]`));
952
- }
953
- break;
954
- default:
955
- // Let's not bother with the rest until we actually need it.
956
- errors.push(error(`Invalid redefinition of built-in type ${builtIn}: cannot redefine ${builtIn.kind} built-in types`));
957
- }
958
- }
959
-
960
- protected addBuiltInScalar(schema: Schema, name: string): ScalarType {
961
- return schema.addType(new ScalarType(name, true));
962
- }
963
-
964
- protected addBuiltInObject(schema: Schema, name: string): ObjectType {
965
- return schema.addType(new ObjectType(name, true));
825
+ export class SchemaBlueprint {
826
+ onMissingDirectiveDefinition(_schema: Schema, _name: string): DirectiveDefinition | undefined {
827
+ // No-op by default, but used for federation.
828
+ return undefined;
966
829
  }
967
830
 
968
- protected addBuiltInUnion(schema: Schema, name: string): UnionType {
969
- return schema.addType(new UnionType(name, true));
831
+ onDirectiveDefinitionAndSchemaParsed(_: Schema) {
832
+ // No-op by default, but used for federation.
970
833
  }
971
834
 
972
- protected addBuiltInDirective(schema: Schema, name: string): DirectiveDefinition {
973
- return schema.addDirectiveDefinition(new DirectiveDefinition(name, true));
835
+ ignoreParsedField(_type: NamedType, _fieldName: string): boolean {
836
+ // No-op by default, but used for federation.
837
+ return false;
974
838
  }
975
839
 
976
- protected addBuiltInField(parentType: ObjectType, name: string, type: OutputType): FieldDefinition<ObjectType> {
977
- return parentType.addField(new FieldDefinition(name, true), type);
840
+ onConstructed(_: Schema) {
841
+ // No-op by default, but used for federation.
978
842
  }
979
843
 
980
- protected getTypedDirective<TApplicationArgs extends {[key: string]: any}>(
981
- schema: Schema,
982
- name: string
983
- ): DirectiveDefinition<TApplicationArgs> {
984
- const directive = schema.directive(name);
985
- if (!directive) {
986
- throw new Error(`The provided schema has not be built with the ${name} directive built-in`);
987
- }
988
- return directive as DirectiveDefinition<TApplicationArgs>;
844
+ onAddedCoreFeature(_schema: Schema, _feature: CoreFeature) {
845
+ // No-op by default, but used for federation.
989
846
  }
990
847
 
991
- includeDirective(schema: Schema): DirectiveDefinition<{if: boolean}> {
992
- return this.getTypedDirective(schema, 'include');
848
+ onInvalidation(_: Schema) {
849
+ // No-op by default, but used for federation.
993
850
  }
994
851
 
995
- skipDirective(schema: Schema): DirectiveDefinition<{if: boolean}> {
996
- return this.getTypedDirective(schema, 'skip');
852
+ onValidation(_schema: Schema): GraphQLError[] {
853
+ // No-op by default, but used for federation.
854
+ return []
997
855
  }
998
856
 
999
- deprecatedDirective(schema: Schema): DirectiveDefinition<{reason?: string}> {
1000
- return this.getTypedDirective(schema, 'deprecated');
1001
- }
1002
-
1003
- specifiedByDirective(schema: Schema): DirectiveDefinition<{url: string}> {
1004
- return this.getTypedDirective(schema, 'specifiedBy');
857
+ validationRules(): readonly SDLValidationRule[] {
858
+ return specifiedSDLRules;
1005
859
  }
1006
860
  }
1007
861
 
862
+ export const defaultSchemaBlueprint = new SchemaBlueprint();
863
+
1008
864
  export class CoreFeature {
1009
865
  constructor(
1010
866
  readonly url: FeatureUrl,
1011
867
  readonly nameInSchema: string,
1012
868
  readonly directive: Directive<SchemaDefinition>,
869
+ readonly imports: CoreImport[],
1013
870
  readonly purpose?: string,
1014
871
  ) {
1015
872
  }
@@ -1018,6 +875,19 @@ export class CoreFeature {
1018
875
  return element.name.startsWith(this.nameInSchema + '__')
1019
876
  || (element.kind === 'DirectiveDefinition' && element.name === this.nameInSchema);
1020
877
  }
878
+
879
+ directiveNameInSchema(name: string): string {
880
+ if (name === this.url.name) {
881
+ return this.nameInSchema;
882
+ }
883
+ const elementImport = this.imports.find((i) => i.name.charAt(0) === '@' && i.name.slice(1) === name);
884
+ return elementImport ? (elementImport.as?.slice(1) ?? name) : this.nameInSchema + '__' + name;
885
+ }
886
+
887
+ typeNameInSchema(name: string): string {
888
+ const elementImport = this.imports.find((i) => i.name === name);
889
+ return elementImport ? (elementImport.as ?? name) : this.nameInSchema + '__' + name;
890
+ }
1021
891
  }
1022
892
 
1023
893
  export class CoreFeatures {
@@ -1027,9 +897,9 @@ export class CoreFeatures {
1027
897
 
1028
898
  constructor(readonly coreItself: CoreFeature) {
1029
899
  this.add(coreItself);
1030
- const coreDef = CORE_VERSIONS.find(coreItself.url.version);
900
+ const coreDef = findCoreSpecVersion(coreItself.url);
1031
901
  if (!coreDef) {
1032
- throw error(`Schema uses unknown version ${coreItself.url.version} of the core spec (known versions: ${CORE_VERSIONS.versions().join(', ')})`);
902
+ throw error(`Schema uses unknown version ${coreItself.url.version} of the ${coreItself.url.name} spec`);
1033
903
  }
1034
904
  this.coreDefinition = coreDef;
1035
905
  }
@@ -1054,14 +924,17 @@ export class CoreFeatures {
1054
924
  if (directive.definition?.name !== this.coreItself.nameInSchema) {
1055
925
  return undefined;
1056
926
  }
1057
- const args = (directive as Directive<SchemaDefinition, CoreDirectiveArgs>).arguments();
1058
- const url = FeatureUrl.parse(args.feature);
927
+ const typedDirective = directive as Directive<SchemaDefinition, CoreOrLinkDirectiveArgs>
928
+ const args = typedDirective.arguments();
929
+ const url = this.coreDefinition.extractFeatureUrl(args);
1059
930
  const existing = this.byIdentity.get(url.identity);
1060
931
  if (existing) {
1061
932
  throw error(`Duplicate inclusion of feature ${url.identity}`);
1062
933
  }
1063
- const feature = new CoreFeature(url, args.as ?? url.name, directive, args.for);
934
+ const imports = extractCoreFeatureImports(typedDirective);
935
+ const feature = new CoreFeature(url, args.as ?? url.name, directive, imports, args.for);
1064
936
  this.add(feature);
937
+ directive.schema().blueprint.onAddedCoreFeature(directive.schema(), feature);
1065
938
  return feature;
1066
939
  }
1067
940
 
@@ -1069,9 +942,58 @@ export class CoreFeatures {
1069
942
  this.byAlias.set(feature.nameInSchema, feature);
1070
943
  this.byIdentity.set(feature.url.identity, feature);
1071
944
  }
945
+
946
+ sourceFeature(element: DirectiveDefinition | NamedType): CoreFeature | undefined {
947
+ const isDirective = element instanceof DirectiveDefinition;
948
+ const splitted = element.name.split('__');
949
+ if (splitted.length > 1) {
950
+ return this.byAlias.get(splitted[0]);
951
+ } else {
952
+ const directFeature = this.byAlias.get(element.name);
953
+ if (directFeature && isDirective) {
954
+ return directFeature;
955
+ }
956
+
957
+ // Let's see if it's an import. If not, it's not associated to a declared feature.
958
+ const importName = isDirective ? '@' + element.name : element.name;
959
+ const allFeatures = [this.coreItself, ...this.byIdentity.values()];
960
+ for (const feature of allFeatures) {
961
+ for (const { as } of feature.imports) {
962
+ if (as === importName) {
963
+ return feature;
964
+ }
965
+ }
966
+ }
967
+ return undefined;
968
+ }
969
+ }
1072
970
  }
1073
971
 
1074
- const toASTPrintOptions: Options = { ...defaultPrintOptions, showNonGraphQLBuiltIns: true };
972
+ const graphQLBuiltInTypes: readonly string[] = [ 'Int', 'Float', 'String', 'Boolean', 'ID' ];
973
+ const graphQLBuiltInTypesSpecifications: readonly TypeSpecification[] = graphQLBuiltInTypes.map((name) => createScalarTypeSpecification({ name }));
974
+
975
+ const graphQLBuiltInDirectivesSpecifications: readonly DirectiveSpecification[] = [
976
+ createDirectiveSpecification({
977
+ name: 'include',
978
+ locations: [DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT],
979
+ argumentFct: (schema) => [{ name: 'if', type: new NonNullType(schema.booleanType()) }]
980
+ }),
981
+ createDirectiveSpecification({
982
+ name: 'skip',
983
+ locations: [DirectiveLocation.FIELD, DirectiveLocation.FRAGMENT_SPREAD, DirectiveLocation.INLINE_FRAGMENT],
984
+ argumentFct: (schema) => [{ name: 'if', type: new NonNullType(schema.booleanType()) }]
985
+ }),
986
+ createDirectiveSpecification({
987
+ name: 'deprecated',
988
+ locations: [DirectiveLocation.FIELD_DEFINITION, DirectiveLocation.ENUM_VALUE, DirectiveLocation.ARGUMENT_DEFINITION, DirectiveLocation.INPUT_FIELD_DEFINITION],
989
+ argumentFct: (schema) => [{ name: 'reason', type: schema.stringType(), defaultValue: 'No longer supported' }]
990
+ }),
991
+ createDirectiveSpecification({
992
+ name: 'specifiedBy',
993
+ locations: [DirectiveLocation.SCALAR],
994
+ argumentFct: (schema) => [{ name: 'url', type: new NonNullType(schema.stringType()) }]
995
+ }),
996
+ ];
1075
997
 
1076
998
  export class Schema {
1077
999
  private _schemaDefinition: SchemaDefinition;
@@ -1081,16 +1003,17 @@ export class Schema {
1081
1003
  private readonly _directives = new MapWithCachedArrays<string, DirectiveDefinition>();
1082
1004
  private _coreFeatures?: CoreFeatures;
1083
1005
  private isConstructed: boolean = false;
1084
- private isValidated: boolean = false;
1006
+ public isValidated: boolean = false;
1085
1007
 
1086
1008
  private cachedDocument?: DocumentNode;
1087
1009
  private apiSchema?: Schema;
1088
1010
 
1089
- constructor(readonly builtIns: BuiltIns = graphQLBuiltIns) {
1011
+ constructor(readonly blueprint: SchemaBlueprint = defaultSchemaBlueprint) {
1090
1012
  this._schemaDefinition = new SchemaDefinition();
1091
1013
  Element.prototype['setParent'].call(this._schemaDefinition, this);
1092
- builtIns.addBuiltInTypes(this);
1093
- builtIns.addBuiltInDirectives(this);
1014
+ graphQLBuiltInTypesSpecifications.forEach((spec) => spec.checkOrAdd(this, undefined, true));
1015
+ graphQLBuiltInDirectivesSpecifications.forEach((spec) => spec.checkOrAdd(this, undefined, true));
1016
+ blueprint.onConstructed(this);
1094
1017
  this.isConstructed = true;
1095
1018
  }
1096
1019
 
@@ -1135,10 +1058,8 @@ export class Schema {
1135
1058
  }
1136
1059
  }
1137
1060
 
1138
- private forceSetCachedDocument(document: DocumentNode, addNonGraphQLBuiltIns: boolean = true) {
1139
- this.cachedDocument = addNonGraphQLBuiltIns
1140
- ? this.builtIns.maybeUpdateSubgraphDocument(this, document)
1141
- : document;
1061
+ private forceSetCachedDocument(document: DocumentNode) {
1062
+ this.cachedDocument = document;
1142
1063
  }
1143
1064
 
1144
1065
  isCoreSchema(): boolean {
@@ -1152,7 +1073,7 @@ export class Schema {
1152
1073
  toAST(): DocumentNode {
1153
1074
  if (!this.cachedDocument) {
1154
1075
  // As we're not building the document from a file, having locations info might be more confusing that not.
1155
- this.forceSetCachedDocument(parse(printSchema(this, toASTPrintOptions), { noLocation: true }), false);
1076
+ this.forceSetCachedDocument(parse(printSchema(this), { noLocation: true }));
1156
1077
  }
1157
1078
  return this.cachedDocument!;
1158
1079
  }
@@ -1185,8 +1106,8 @@ export class Schema {
1185
1106
 
1186
1107
  // Some subgraphs, especially federation 1 ones, cannot be properly converted to a GraphQLSchema because they are invalid graphQL.
1187
1108
  // And the main culprit is type extensions that don't have a corresponding definition. So to avoid that problem, we print
1188
- // up the AST without extensions. Another issue is the non graph built-ins which needs to be explicitely defined.
1189
- const ast = parse(printSchema(this, { ...toASTPrintOptions, mergeTypesAndExtensions: true }), { noLocation: true });
1109
+ // up the AST without extensions.
1110
+ const ast = parse(printSchema(this, { ...defaultPrintOptions, mergeTypesAndExtensions: true }), { noLocation: true });
1190
1111
  return buildGraphqlSchemaFromAST(ast);
1191
1112
  }
1192
1113
 
@@ -1197,12 +1118,9 @@ export class Schema {
1197
1118
  /**
1198
1119
  * All the types defined on this schema, excluding the built-in types.
1199
1120
  */
1200
- types<T extends NamedType>(kind?: T['kind'], includeNonGraphQLBuiltIns: boolean = false): readonly T[] {
1121
+ types<T extends NamedType>(kind?: T['kind']): readonly T[] {
1201
1122
  const allKinds = this._types.values();
1202
- const forKind = (kind ? allKinds.filter(t => t.kind === kind) : allKinds) as readonly T[];
1203
- return includeNonGraphQLBuiltIns
1204
- ? this.builtInTypes(kind).filter(t => !graphQLBuiltIns.isGraphQLBuiltIn(t)).concat(forKind)
1205
- : forKind;
1123
+ return (kind ? allKinds.filter(t => t.kind === kind) : allKinds) as readonly T[];
1206
1124
  }
1207
1125
 
1208
1126
  /**
@@ -1262,9 +1180,12 @@ export class Schema {
1262
1180
 
1263
1181
  addType<T extends NamedType>(type: T): T {
1264
1182
  const existing = this.type(type.name);
1265
- // Like for directive, we let use shadow built-in types, but validation will ensure the definition is compatible.
1266
- if (existing && !existing.isBuiltIn) {
1267
- throw error(`Type ${type} already exists in this schema`);
1183
+ if (existing) {
1184
+ // Like for directive, we let user shadow built-in types, but the definition must be valid.
1185
+ if (existing.isBuiltIn) {
1186
+ } else {
1187
+ throw error(`Type ${type} already exists in this schema`);
1188
+ }
1268
1189
  }
1269
1190
  if (type.isAttached()) {
1270
1191
  // For convenience, let's not error out on adding an already added type.
@@ -1297,10 +1218,8 @@ export class Schema {
1297
1218
  /**
1298
1219
  * All the directive defined on this schema, excluding the built-in directives.
1299
1220
  */
1300
- directives(includeNonGraphQLBuiltIns: boolean = false): readonly DirectiveDefinition[] {
1301
- return includeNonGraphQLBuiltIns
1302
- ? this.builtInDirectives().filter(d => !graphQLBuiltIns.isGraphQLBuiltIn(d)).concat(this._directives.values())
1303
- : this._directives.values();
1221
+ directives(): readonly DirectiveDefinition[] {
1222
+ return this._directives.values();
1304
1223
  }
1305
1224
 
1306
1225
  /**
@@ -1322,7 +1241,11 @@ export class Schema {
1322
1241
 
1323
1242
  directive(name: string): DirectiveDefinition | undefined {
1324
1243
  const directive = this._directives.get(name);
1325
- return directive ? directive : this._builtInDirectives.get(name);
1244
+ return directive ? directive : this.builtInDirective(name);
1245
+ }
1246
+
1247
+ builtInDirective(name: string): DirectiveDefinition | undefined {
1248
+ return this._builtInDirectives.get(name);
1326
1249
  }
1327
1250
 
1328
1251
  *allNamedSchemaElement(): Generator<NamedSchemaElement<any, any, any>, void, undefined> {
@@ -1374,6 +1297,7 @@ export class Schema {
1374
1297
 
1375
1298
  invalidate() {
1376
1299
  this.isValidated = false;
1300
+ this.blueprint.onInvalidation(this);
1377
1301
  }
1378
1302
 
1379
1303
  validate() {
@@ -1381,22 +1305,20 @@ export class Schema {
1381
1305
  return;
1382
1306
  }
1383
1307
 
1384
- // This needs to run _before_ graphQL validation: otherwise, the _Entity union will be empty and fail validation.
1385
1308
  this.runWithBuiltInModificationAllowed(() => {
1386
- this.builtIns.prepareValidation(this);
1387
1309
  addIntrospectionFields(this);
1388
1310
  });
1389
1311
 
1390
- // TODO: we should ensure first that there is no undefined types (or maybe throw properly when printing the AST
1391
- // and catching that properly).
1392
- let errors = validateSDL(this.toAST(), undefined, this.builtIns.validationRules());
1312
+ // TODO: we check that all types are properly set (aren't undefined) in `validateSchema`, but `validateSDL` will error out beforehand. We should
1313
+ // probably extract that part of `validateSchema` and run `validateSDL` conditionally on that first check.
1314
+ let errors = validateSDL(this.toAST(), undefined, this.blueprint.validationRules());
1393
1315
  errors = errors.concat(validateSchema(this));
1394
1316
 
1395
1317
  // We avoid adding federation-specific validations if the base schema is not proper graphQL as the later can easily trigger
1396
1318
  // the former (for instance, someone mistyping the 'fields' argument name of a @key).
1397
1319
  if (errors.length === 0) {
1398
1320
  this.runWithBuiltInModificationAllowed(() => {
1399
- errors = this.builtIns.onValidation(this);
1321
+ errors = this.blueprint.onValidation(this);
1400
1322
  });
1401
1323
  }
1402
1324
 
@@ -1407,8 +1329,8 @@ export class Schema {
1407
1329
  this.isValidated = true;
1408
1330
  }
1409
1331
 
1410
- clone(builtIns?: BuiltIns): Schema {
1411
- const cloned = new Schema(builtIns ?? this.builtIns);
1332
+ clone(builtIns?: SchemaBlueprint): Schema {
1333
+ const cloned = new Schema(builtIns ?? this.blueprint);
1412
1334
  copy(this, cloned);
1413
1335
  if (this.isValidated) {
1414
1336
  // TODO: when we do actual validation, no point in redoing it, but we should
@@ -1417,6 +1339,31 @@ export class Schema {
1417
1339
  }
1418
1340
  return cloned;
1419
1341
  }
1342
+
1343
+ private getBuiltInDirective<TApplicationArgs extends {[key: string]: any}>(
1344
+ schema: Schema,
1345
+ name: string
1346
+ ): DirectiveDefinition<TApplicationArgs> {
1347
+ const directive = schema.directive(name);
1348
+ assert(directive, `The provided schema has not be built with the ${name} directive built-in`);
1349
+ return directive as DirectiveDefinition<TApplicationArgs>;
1350
+ }
1351
+
1352
+ includeDirective(schema: Schema): DirectiveDefinition<{if: boolean}> {
1353
+ return this.getBuiltInDirective(schema, 'include');
1354
+ }
1355
+
1356
+ skipDirective(schema: Schema): DirectiveDefinition<{if: boolean}> {
1357
+ return this.getBuiltInDirective(schema, 'skip');
1358
+ }
1359
+
1360
+ deprecatedDirective(schema: Schema): DirectiveDefinition<{reason?: string}> {
1361
+ return this.getBuiltInDirective(schema, 'deprecated');
1362
+ }
1363
+
1364
+ specifiedByDirective(schema: Schema): DirectiveDefinition<{url: string}> {
1365
+ return this.getBuiltInDirective(schema, 'specifiedBy');
1366
+ }
1420
1367
  }
1421
1368
 
1422
1369
  export class RootType extends BaseExtensionMember<SchemaDefinition> {
@@ -1451,12 +1398,13 @@ export class SchemaDefinition extends SchemaElement<SchemaDefinition, Schema> {
1451
1398
  const coreFeatures = schema.coreFeatures;
1452
1399
  if (isCoreSpecDirectiveApplication(applied)) {
1453
1400
  if (coreFeatures) {
1454
- throw error(`Invalid duplicate application of the @core feature`);
1401
+ throw error(`Invalid duplicate application of @core/@link`);
1455
1402
  }
1456
- const schemaDirective = applied as Directive<SchemaDefinition, CoreDirectiveArgs>;
1403
+ const schemaDirective = applied as Directive<SchemaDefinition, CoreOrLinkDirectiveArgs>;
1457
1404
  const args = schemaDirective.arguments();
1458
- const url = FeatureUrl.parse(args.feature);
1459
- const core = new CoreFeature(url, args.as ?? 'core', schemaDirective, args.for);
1405
+ const url = FeatureUrl.parse((args.url ?? args.feature)!);
1406
+ const imports = extractCoreFeatureImports(schemaDirective);
1407
+ const core = new CoreFeature(url, args.as ?? url.name, schemaDirective, imports, args.for);
1460
1408
  Schema.prototype['markAsCoreSchema'].call(schema, core);
1461
1409
  } else if (coreFeatures) {
1462
1410
  CoreFeatures.prototype['maybeAddFeature'].call(coreFeatures, applied);
@@ -1551,6 +1499,10 @@ export class ScalarType extends BaseNamedType<OutputTypeReferencer | InputTypeRe
1551
1499
  return false; // No inner elements
1552
1500
  }
1553
1501
 
1502
+ protected removeInnerElementsExtensions(): void {
1503
+ // No inner elements
1504
+ }
1505
+
1554
1506
  protected removeInnerElements(): void {
1555
1507
  // No inner elements
1556
1508
  }
@@ -1657,18 +1609,15 @@ abstract class FieldBasedType<T extends (ObjectType | InterfaceType) & NamedSche
1657
1609
  /**
1658
1610
  * All the fields of this type, excluding the built-in ones.
1659
1611
  */
1660
- fields(includeNonGraphQLBuiltIns: boolean = false): readonly FieldDefinition<T>[] {
1661
- if (includeNonGraphQLBuiltIns) {
1662
- return this.allFields().filter(f => !graphQLBuiltIns.isGraphQLBuiltIn(f));
1663
- }
1612
+ fields(): readonly FieldDefinition<T>[] {
1664
1613
  if (!this._cachedNonBuiltInFields) {
1665
1614
  this._cachedNonBuiltInFields = this._fields.values().filter(f => !f.isBuiltIn);
1666
1615
  }
1667
1616
  return this._cachedNonBuiltInFields;
1668
1617
  }
1669
1618
 
1670
- hasFields(includeNonGraphQLBuiltIns: boolean = false): boolean {
1671
- return this.fields(includeNonGraphQLBuiltIns).length > 0;
1619
+ hasFields(): boolean {
1620
+ return this.fields().length > 0;
1672
1621
  }
1673
1622
 
1674
1623
  /**
@@ -1761,6 +1710,11 @@ abstract class FieldBasedType<T extends (ObjectType | InterfaceType) & NamedSche
1761
1710
  return this.interfaceImplementations().some(itf => itf.ofExtension() === undefined)
1762
1711
  || this.fields().some(f => f.ofExtension() === undefined);
1763
1712
  }
1713
+
1714
+ protected removeInnerElementsExtensions(): void {
1715
+ this.interfaceImplementations().forEach(itf => itf.removeOfExtension());
1716
+ this.fields().forEach(f => f.removeOfExtension());
1717
+ }
1764
1718
  }
1765
1719
 
1766
1720
  export class ObjectType extends FieldBasedType<ObjectType, ObjectTypeReferencer> {
@@ -1949,6 +1903,10 @@ export class UnionType extends BaseNamedType<OutputTypeReferencer, UnionType> {
1949
1903
  protected removeReferenceRecursive(ref: OutputTypeReferencer): void {
1950
1904
  ref.removeRecursive();
1951
1905
  }
1906
+
1907
+ protected removeInnerElementsExtensions(): void {
1908
+ this.members().forEach(m => m.removeOfExtension());
1909
+ }
1952
1910
  }
1953
1911
 
1954
1912
  export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
@@ -1960,7 +1918,7 @@ export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
1960
1918
  }
1961
1919
 
1962
1920
  value(name: string): EnumValue | undefined {
1963
- return this._values.find(v => v.name == name);
1921
+ return this._values.find(v => v.name === name);
1964
1922
  }
1965
1923
 
1966
1924
  addValue(value: EnumValue): EnumValue;
@@ -2007,6 +1965,10 @@ export class EnumType extends BaseNamedType<OutputTypeReferencer, EnumType> {
2007
1965
  protected removeReferenceRecursive(ref: OutputTypeReferencer): void {
2008
1966
  ref.removeRecursive();
2009
1967
  }
1968
+
1969
+ protected removeInnerElementsExtensions(): void {
1970
+ this._values.forEach(v => v.removeOfExtension());
1971
+ }
2010
1972
  }
2011
1973
 
2012
1974
  export class InputObjectType extends BaseNamedType<InputTypeReferencer, InputObjectType> {
@@ -2090,6 +2052,10 @@ export class InputObjectType extends BaseNamedType<InputTypeReferencer, InputObj
2090
2052
  ref.removeRecursive();
2091
2053
  }
2092
2054
  }
2055
+
2056
+ protected removeInnerElementsExtensions(): void {
2057
+ this.fields().forEach(f => f.removeOfExtension());
2058
+ }
2093
2059
  }
2094
2060
 
2095
2061
  class BaseWrapperType<T extends Type> {
@@ -2208,6 +2174,10 @@ export class FieldDefinition<TParent extends CompositeType> extends NamedSchemaE
2208
2174
  return this._extension;
2209
2175
  }
2210
2176
 
2177
+ removeOfExtension() {
2178
+ this._extension = undefined;
2179
+ }
2180
+
2211
2181
  setOfExtension(extension: Extension<TParent> | undefined) {
2212
2182
  this.checkUpdate();
2213
2183
  // It seems typescript "expand" `TParent` below into `ObjectType | Interface`, so it essentially lose the context that
@@ -2302,6 +2272,10 @@ export class InputFieldDefinition extends NamedSchemaElementWithType<InputType,
2302
2272
  return this._extension;
2303
2273
  }
2304
2274
 
2275
+ removeOfExtension() {
2276
+ this._extension = undefined;
2277
+ }
2278
+
2305
2279
  setOfExtension(extension: Extension<InputObjectType> | undefined) {
2306
2280
  this.checkUpdate();
2307
2281
  // It seems typescript "expand" `TParent` below into `ObjectType | Interface`, so it essentially lose the context that
@@ -2414,6 +2388,10 @@ export class EnumValue extends NamedSchemaElement<EnumValue, EnumType, never> {
2414
2388
  return this._extension;
2415
2389
  }
2416
2390
 
2391
+ removeOfExtension() {
2392
+ this._extension = undefined;
2393
+ }
2394
+
2417
2395
  setOfExtension(extension: Extension<EnumType> | undefined) {
2418
2396
  this.checkUpdate();
2419
2397
  if (extension && !this._parent?.extensions().has(extension)) {
@@ -2622,6 +2600,9 @@ export class Directive<
2622
2600
  }
2623
2601
 
2624
2602
  get definition(): DirectiveDefinition | undefined {
2603
+ if (!this.isAttached()) {
2604
+ return undefined;
2605
+ }
2625
2606
  const doc = this.schema();
2626
2607
  return doc.directive(this.name);
2627
2608
  }
@@ -2681,6 +2662,10 @@ export class Directive<
2681
2662
  return this._extension;
2682
2663
  }
2683
2664
 
2665
+ removeOfExtension() {
2666
+ this._extension = undefined;
2667
+ }
2668
+
2684
2669
  setOfExtension(extension: Extension<any> | undefined) {
2685
2670
  this.checkUpdate();
2686
2671
  if (extension) {
@@ -2933,8 +2918,6 @@ export function variableDefinitionFromAST(schema: Schema, definitionNode: Variab
2933
2918
  return def;
2934
2919
  }
2935
2920
 
2936
- export const graphQLBuiltIns = new BuiltIns();
2937
-
2938
2921
  function addReferenceToType(referencer: SchemaElement<any, any>, type: Type) {
2939
2922
  switch (type.kind) {
2940
2923
  case 'ListType':
@@ -3043,7 +3026,7 @@ function copySchemaDefinitionInner(source: SchemaDefinition, dest: SchemaDefinit
3043
3026
  // Same as copyAppliedDirectives, but as the directive applies to the schema definition, we need to remember if the application
3044
3027
  // is for the extension or not.
3045
3028
  for (const directive of source.appliedDirectives) {
3046
- copyOfExtension(extensionsMap, directive, dest.applyDirective(directive.name, { ...directive.arguments() }));
3029
+ copyOfExtension(extensionsMap, directive, copyAppliedDirective(directive, dest));
3047
3030
  }
3048
3031
  dest.description = source.description;
3049
3032
  dest.sourceAST = source.sourceAST;
@@ -3054,7 +3037,7 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
3054
3037
  // Same as copyAppliedDirectives, but as the directive applies to the type, we need to remember if the application
3055
3038
  // is for the extension or not.
3056
3039
  for (const directive of source.appliedDirectives) {
3057
- copyOfExtension(extensionsMap, directive, dest.applyDirective(directive.name, { ...directive.arguments() }));
3040
+ copyOfExtension(extensionsMap, directive, copyAppliedDirective(directive, dest));
3058
3041
  }
3059
3042
  dest.description = source.description;
3060
3043
  dest.sourceAST = source.sourceAST;
@@ -3099,9 +3082,13 @@ function copyNamedTypeInner(source: NamedType, dest: NamedType) {
3099
3082
  }
3100
3083
 
3101
3084
  function copyAppliedDirectives(source: SchemaElement<any, any>, dest: SchemaElement<any, any>) {
3102
- for (const directive of source.appliedDirectives) {
3103
- dest.applyDirective(directive.name, { ...directive.arguments() });
3104
- }
3085
+ source.appliedDirectives.forEach((d) => copyAppliedDirective(d, dest));
3086
+ }
3087
+
3088
+ function copyAppliedDirective(source: Directive<any, any>, dest: SchemaElement<any, any>): Directive<any, any> {
3089
+ const res = dest.applyDirective(source.name, { ...source.arguments() });
3090
+ res.sourceAST = source.sourceAST
3091
+ return res;
3105
3092
  }
3106
3093
 
3107
3094
  function copyFieldDefinitionInner<P extends ObjectType | InterfaceType>(source: FieldDefinition<P>, dest: FieldDefinition<P>) {