@apollo/federation-internals 2.0.0-alpha.6 → 2.0.0-preview.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.
Files changed (105) hide show
  1. package/CHANGELOG.md +12 -0
  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 +9 -1
  19. package/dist/error.d.ts.map +1 -1
  20. package/dist/error.js +20 -2
  21. package/dist/error.js.map +1 -1
  22. package/dist/extractSubgraphsFromSupergraph.d.ts.map +1 -1
  23. package/dist/extractSubgraphsFromSupergraph.js +28 -93
  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 +706 -228
  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 +7 -0
  64. package/dist/utils.d.ts.map +1 -1
  65. package/dist/utils.js +34 -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/package.json +3 -3
  78. package/src/__tests__/definitions.test.ts +19 -17
  79. package/src/__tests__/federation.test.ts +31 -0
  80. package/src/__tests__/operations.test.ts +2 -3
  81. package/src/__tests__/schemaUpgrader.test.ts +168 -0
  82. package/src/__tests__/subgraphValidation.test.ts +5 -19
  83. package/src/__tests__/values.test.ts +2 -4
  84. package/src/buildSchema.ts +55 -36
  85. package/src/coreSpec.ts +112 -31
  86. package/src/definitions.ts +247 -260
  87. package/src/directiveAndTypeSpecification.ts +276 -0
  88. package/src/error.ts +55 -5
  89. package/src/extractSubgraphsFromSupergraph.ts +34 -118
  90. package/src/federation.ts +912 -295
  91. package/src/federationSpec.ts +113 -0
  92. package/src/index.ts +2 -0
  93. package/src/joinSpec.ts +2 -1
  94. package/src/operations.ts +22 -7
  95. package/src/print.ts +51 -38
  96. package/src/schemaUpgrader.ts +657 -0
  97. package/src/sharing.ts +68 -0
  98. package/src/supergraphs.ts +3 -3
  99. package/src/tagSpec.ts +1 -3
  100. package/src/utils.ts +63 -0
  101. package/src/validate.ts +13 -7
  102. package/src/validation/KnownTypeNamesInFederationRule.ts +1 -7
  103. package/src/values.ts +7 -3
  104. package/tsconfig.test.tsbuildinfo +1 -1
  105. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,168 @@
1
+ import { buildSubgraph, Subgraphs } from '../federation';
2
+ import { UpgradeChangeID, UpgradeResult, upgradeSubgraphsIfNecessary } from '../schemaUpgrader';
3
+ import './matchers';
4
+
5
+ function changeMessages(res: UpgradeResult, subgraphName: string, id: UpgradeChangeID): string[] {
6
+ const changes = res.changes?.get(subgraphName)?.get(id);
7
+ return changes?.map(c => c.toString()) ?? [];
8
+ }
9
+
10
+ /**
11
+ * A lot of the schema upgrader behaviors are tested as part of composing fed1 schema in `composeFed1Subgraphs.test.ts`.
12
+ * This test file thus mostly focuses on the change-reporting of the schema upgrader.
13
+ */
14
+
15
+ test('upgrade complex schema', () => {
16
+ const s1 = `
17
+ type Query {
18
+ products: [Product!]! @provides(fields: "upc description")
19
+ }
20
+
21
+ interface I @key(fields: "upc") {
22
+ upc: ID!
23
+ description: String @external
24
+ }
25
+
26
+ extend type Product implements I @key(fields: "upc") {
27
+ upc: ID! @external
28
+ name: String @external
29
+ inventory: Int @requires(fields: "upc")
30
+ description: String @external
31
+ }
32
+
33
+ # A type with a genuine 'graphqQL' extension, to ensure the extend don't get removed.
34
+ type Random {
35
+ x: Int @provides(fields: "x")
36
+ }
37
+
38
+ extend type Random {
39
+ y: Int
40
+ }
41
+ `;
42
+
43
+ // Note that no changes are really expected on that 2nd schema: it is just there to make the example not throw due to
44
+ // then Product type extension having no "base".
45
+ const s2 = `
46
+ type Product @key(fields: "upc") {
47
+ upc: ID!
48
+ name: String
49
+ description: String
50
+ }
51
+ `;
52
+
53
+ const subgraphs = new Subgraphs();
54
+ subgraphs.add(buildSubgraph('s1', 'http://s1', s1));
55
+ subgraphs.add(buildSubgraph('s2', 'http://s1', s2));
56
+ const res = upgradeSubgraphsIfNecessary(subgraphs);
57
+ expect(res.errors).toBeUndefined();
58
+
59
+ expect(changeMessages(res, 's1', 'EXTERNAL_ON_TYPE_EXTENSION_REMOVAL')).toStrictEqual([
60
+ 'Removed @external from field "Product.upc" as it is a key of an extension type'
61
+ ]);
62
+
63
+ expect(changeMessages(res, 's1', 'TYPE_EXTENSION_REMOVAL')).toStrictEqual([
64
+ 'Switched type "Product" from an extension to a definition'
65
+ ]);
66
+
67
+ expect(changeMessages(res, 's1', 'UNUSED_EXTERNAL_REMOVAL')).toStrictEqual([
68
+ 'Removed @external field "Product.name" as it was not used in any @key, @provides or @requires'
69
+ ]);
70
+
71
+ expect(changeMessages(res, 's1', 'EXTERNAL_ON_INTERFACE_REMOVAL')).toStrictEqual([
72
+ 'Removed @external directive on interface type field "I.description": @external is nonsensical on interface fields'
73
+ ]);
74
+
75
+ expect(changeMessages(res, 's1', 'INACTIVE_PROVIDES_OR_REQUIRES_REMOVAL')).toStrictEqual([
76
+ 'Removed directive @requires(fields: "upc") on "Product.inventory": none of the fields were truly @external'
77
+ ]);
78
+
79
+ expect(changeMessages(res, 's1', 'INACTIVE_PROVIDES_OR_REQUIRES_FIELDS_REMOVAL')).toStrictEqual([
80
+ 'Updated directive @provides(fields: "upc description") on "Query.products" to @provides(fields: "description"): removed fields that were not truly @external'
81
+ ]);
82
+
83
+ expect(changeMessages(res, 's1', 'KEY_ON_INTERFACE_REMOVAL')).toStrictEqual([
84
+ 'Removed @key on interface "I": while allowed by federation 0.x, @key on interfaces were completely ignored/had no effect'
85
+ ]);
86
+
87
+ expect(changeMessages(res, 's1', 'PROVIDES_ON_NON_COMPOSITE_REMOVAL')).toStrictEqual([
88
+ 'Removed @provides directive on field "Random.x" as it is of non-composite type "Int": while not rejected by federation 0.x, such @provide is nonsensical and was ignored'
89
+ ]);
90
+
91
+ expect(res.subgraphs?.get('s1')?.toString()).toMatchString(`
92
+ schema
93
+ @link(url: "https://specs.apollo.dev/link/v1.0")
94
+ @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@requires", "@provides", "@external", "@shareable", "@tag", "@extends"])
95
+ {
96
+ query: Query
97
+ }
98
+
99
+ type Query {
100
+ products: [Product!]! @provides(fields: "description")
101
+ }
102
+
103
+ interface I {
104
+ upc: ID!
105
+ description: String
106
+ }
107
+
108
+ type Product implements I
109
+ @key(fields: "upc")
110
+ {
111
+ upc: ID!
112
+ inventory: Int
113
+ description: String @external
114
+ }
115
+
116
+ type Random {
117
+ x: Int
118
+ }
119
+
120
+ extend type Random {
121
+ y: Int
122
+ }
123
+ `);
124
+ });
125
+
126
+ test('update federation directive non-string arguments', () => {
127
+ const s = `
128
+ type Query {
129
+ a: A
130
+ }
131
+
132
+ type A @key(fields: id) @key(fields: ["id", "x"]) {
133
+ id: String
134
+ x: Int
135
+ }
136
+ `;
137
+
138
+ const subgraphs = new Subgraphs();
139
+ subgraphs.add(buildSubgraph('s', 'http://s', s));
140
+ const res = upgradeSubgraphsIfNecessary(subgraphs);
141
+ expect(res.errors).toBeUndefined();
142
+
143
+ expect(changeMessages(res, 's', 'FIELDS_ARGUMENT_COERCION_TO_STRING')).toStrictEqual([
144
+ 'Coerced "fields" argument for directive @key for "A" into a string: coerced from @key(fields: id) to @key(fields: "id")',
145
+ 'Coerced "fields" argument for directive @key for "A" into a string: coerced from @key(fields: ["id", "x"]) to @key(fields: "id x")',
146
+ ]);
147
+
148
+ expect(res.subgraphs?.get('s')?.toString()).toMatchString(`
149
+ schema
150
+ @link(url: "https://specs.apollo.dev/link/v1.0")
151
+ @link(url: "https://specs.apollo.dev/federation/v2.0", import: ["@key", "@requires", "@provides", "@external", "@shareable", "@tag", "@extends"])
152
+ {
153
+ query: Query
154
+ }
155
+
156
+ type Query {
157
+ a: A
158
+ }
159
+
160
+ type A
161
+ @key(fields: "id")
162
+ @key(fields: "id x")
163
+ {
164
+ id: String
165
+ x: Int
166
+ }
167
+ `);
168
+ })
@@ -1,14 +1,15 @@
1
1
  import { DocumentNode } from 'graphql';
2
2
  import gql from 'graphql-tag';
3
- import { errorCauses } from '..';
4
- import { buildSubgraph } from "../federation"
3
+ import { errorCauses } from '../definitions';
4
+ import { asFed2SubgraphDocument, buildSubgraph } from "../federation"
5
5
 
6
6
  // Builds the provided subgraph (using name 'S' for the subgraph) and, if the
7
7
  // subgraph is invalid/has errors, return those errors as a list of [code, message].
8
8
  // If the subgraph is valid, return undefined.
9
9
  function buildForErrors(subgraphDefs: DocumentNode, subgraphName: string = 'S'): [string, string][] | undefined {
10
10
  try {
11
- buildSubgraph(subgraphName, subgraphDefs);
11
+ const doc = asFed2SubgraphDocument(subgraphDefs);
12
+ buildSubgraph(subgraphName, `http://${subgraphName}`, doc).validate();
12
13
  return undefined;
13
14
  } catch (e) {
14
15
  const causes = errorCauses(e);
@@ -144,6 +145,7 @@ describe('fieldset-based directives', () => {
144
145
  `
145
146
  expect(buildForErrors(subgraph)).toStrictEqual([
146
147
  ['REQUIRES_UNSUPPORTED_ON_INTERFACE', '[S] Cannot use @requires on field "T.g" of parent type "T": @requires is not yet supported within interfaces' ],
148
+ ['EXTERNAL_ON_INTERFACE', '[S] Interface type field "T.f" is marked @external but @external is not allowed on interface fields (it is nonsensical).' ],
147
149
  ]);
148
150
  });
149
151
 
@@ -335,22 +337,6 @@ describe('fieldset-based directives', () => {
335
337
  `
336
338
  expect(buildForErrors(subgraph)).toStrictEqual([
337
339
  ['REQUIRES_INVALID_FIELDS', '[S] On field "T.g", for @requires(fields: "f b"): Cannot query field "b" on type "T" (if the field is defined in another subgraph, you need to add it to this subgraph with @external).'],
338
- ['EXTERNAL_UNUSED', '[S] Field "T.f" is marked @external but is not used in any federation directive (@key, @provides, @requires) or to satisfy an interface; the field declaration has no use and should be removed (or the field should not be @external).' ],
339
- ]);
340
- });
341
-
342
- it('rejects @key on a list field', () => {
343
- const subgraph = gql`
344
- type Query {
345
- t: T
346
- }
347
-
348
- type T @key(fields: "f") {
349
- f: [Int]
350
- }
351
- `
352
- expect(buildForErrors(subgraph)).toStrictEqual([
353
- ['KEY_FIELDS_SELECT_INVALID_TYPE', '[S] On type "T", for @key(fields: "f"): field "T.f" is a List type which is not allowed in @key'],
354
340
  ]);
355
341
  });
356
342
 
@@ -1,19 +1,17 @@
1
1
  import {
2
2
  Schema,
3
- BuiltIns
4
3
  } from '../../dist/definitions';
5
4
  import { buildSchema } from '../../dist/buildSchema';
6
5
  import { parseOperation } from '../../dist/operations';
7
6
 
8
- function parseSchema(schema: string, builtIns?: BuiltIns): Schema {
7
+ function parseSchema(schema: string): Schema {
9
8
  try {
10
- return buildSchema(schema, builtIns);
9
+ return buildSchema(schema);
11
10
  } catch (e) {
12
11
  throw new Error('Error parsing the schema:\n' + e.toString());
13
12
  }
14
13
  }
15
14
 
16
-
17
15
  test('handles non-list value for list argument (as singleton)', () => {
18
16
  const schema = parseSchema(`
19
17
  enum Day {
@@ -11,7 +11,6 @@ import {
11
11
  SchemaDefinitionNode,
12
12
  Source,
13
13
  TypeNode,
14
- valueFromASTUntyped,
15
14
  ValueNode,
16
15
  NamedTypeNode,
17
16
  ArgumentNode,
@@ -22,10 +21,10 @@ import {
22
21
  Kind,
23
22
  } from "graphql";
24
23
  import { Maybe } from "graphql/jsutils/Maybe";
24
+ import { valueFromASTUntyped } from "./values";
25
25
  import {
26
- BuiltIns,
26
+ SchemaBlueprint,
27
27
  Schema,
28
- graphQLBuiltIns,
29
28
  newNamedType,
30
29
  NamedTypeKind,
31
30
  NamedType,
@@ -51,57 +50,56 @@ import {
51
50
  } from "./definitions";
52
51
 
53
52
  function buildValue(value?: ValueNode): any {
54
- // TODO: Should we rewrite a version of valueFromAST instead of using valueFromASTUntyped? Afaict, what we're missing out on is
55
- // 1) coercions, which concretely, means:
56
- // - for enums, we get strings
57
- // - for int, we don't get the validation that it should be a 32bit value.
58
- // - for ID, which accepts strings and int, we don't get int converted to string.
59
- // - for floats, we get either int or float, we don't get int converted to float.
60
- // - we don't get any custom coercion (but neither is buildSchema in graphQL-js anyway).
61
- // 2) type validation.
62
53
  return value ? valueFromASTUntyped(value) : undefined;
63
54
  }
64
55
 
65
- export function buildSchema(source: string | Source, builtIns: BuiltIns = graphQLBuiltIns, validate: boolean = true): Schema {
66
- return buildSchemaFromAST(parse(source), builtIns, validate);
56
+ export type BuildSchemaOptions = {
57
+ blueprint?: SchemaBlueprint,
58
+ validate?: boolean,
67
59
  }
68
60
 
69
- export function buildSchemaFromAST(documentNode: DocumentNode, builtIns: BuiltIns = graphQLBuiltIns, validate: boolean = true): Schema {
70
- const schema = new Schema(builtIns);
61
+ export function buildSchema(source: string | Source, options?: BuildSchemaOptions): Schema {
62
+ return buildSchemaFromAST(parse(source), options);
63
+ }
64
+
65
+ export function buildSchemaFromAST(
66
+ documentNode: DocumentNode,
67
+ options?: BuildSchemaOptions,
68
+ ): Schema {
69
+ const schema = new Schema(options?.blueprint);
71
70
  // We do a first pass to add all empty types and directives definition. This ensure any reference on one of
72
71
  // those can be resolved in the 2nd pass, regardless of the order of the definitions in the AST.
73
- const directiveDefinitionNodes = buildNamedTypeAndDirectivesShallow(documentNode, schema);
72
+ const { directiveDefinitions, schemaDefinitions, schemaExtensions } = buildNamedTypeAndDirectivesShallow(documentNode, schema);
74
73
 
75
74
  // We then deal with directive definition first. This is mainly for the sake of core schemas: the core schema
76
75
  // handling in `Schema` detects that the schema is a core one when it see the application of `@core(feature: ".../core/...")`
77
76
  // to the schema element. But that detection necessitates that the corresponding directive definition has been fully
78
77
  // populated (and at this point, we don't really know the name of the `@core` directive since it can be renamed, so
79
78
  // we just handle all directives).
80
- for (const directiveDefinitionNode of directiveDefinitionNodes) {
79
+ for (const directiveDefinitionNode of directiveDefinitions) {
81
80
  buildDirectiveDefinitionInner(directiveDefinitionNode, schema.directive(directiveDefinitionNode.name.value)!);
82
81
  }
82
+ for (const schemaDefinition of schemaDefinitions) {
83
+ buildSchemaDefinitionInner(schemaDefinition, schema.schemaDefinition);
84
+ }
85
+ for (const schemaExtension of schemaExtensions) {
86
+ buildSchemaDefinitionInner(schemaExtension, schema.schemaDefinition, schema.schemaDefinition.newExtension());
87
+ }
88
+
89
+ schema.blueprint.onDirectiveDefinitionAndSchemaParsed(schema);
83
90
 
84
91
  for (const definitionNode of documentNode.definitions) {
85
92
  switch (definitionNode.kind) {
86
93
  case 'OperationDefinition':
87
94
  case 'FragmentDefinition':
88
95
  throw new GraphQLError("Invalid executable definition found while building schema", definitionNode);
89
- case 'SchemaDefinition':
90
- buildSchemaDefinitionInner(definitionNode, schema.schemaDefinition);
91
- break;
92
- case 'SchemaExtension':
93
- buildSchemaDefinitionInner(
94
- definitionNode,
95
- schema.schemaDefinition,
96
- schema.schemaDefinition.newExtension());
97
- break;
98
96
  case 'ScalarTypeDefinition':
99
97
  case 'ObjectTypeDefinition':
100
98
  case 'InterfaceTypeDefinition':
101
99
  case 'UnionTypeDefinition':
102
100
  case 'EnumTypeDefinition':
103
101
  case 'InputObjectTypeDefinition':
104
- buildNamedTypeInner(definitionNode, schema.type(definitionNode.name.value)!);
102
+ buildNamedTypeInner(definitionNode, schema.type(definitionNode.name.value)!, schema.blueprint);
105
103
  break;
106
104
  case 'ScalarTypeExtension':
107
105
  case 'ObjectTypeExtension':
@@ -112,23 +110,34 @@ export function buildSchemaFromAST(documentNode: DocumentNode, builtIns: BuiltIn
112
110
  const toExtend = schema.type(definitionNode.name.value)!;
113
111
  const extension = toExtend.newExtension();
114
112
  extension.sourceAST = definitionNode;
115
- buildNamedTypeInner(definitionNode, toExtend, extension);
113
+ buildNamedTypeInner(definitionNode, toExtend, schema.blueprint, extension);
116
114
  break;
117
115
  }
118
116
  }
119
117
 
120
- Schema.prototype['forceSetCachedDocument'].call(schema, documentNode);
121
- if (validate) {
118
+ if (options?.validate ?? true) {
122
119
  schema.validate();
123
120
  }
124
121
 
125
122
  return schema;
126
123
  }
127
124
 
128
- function buildNamedTypeAndDirectivesShallow(documentNode: DocumentNode, schema: Schema): DirectiveDefinitionNode[] {
129
- const directiveDefinitionNodes = [];
125
+ function buildNamedTypeAndDirectivesShallow(documentNode: DocumentNode, schema: Schema): {
126
+ directiveDefinitions: DirectiveDefinitionNode[],
127
+ schemaDefinitions: SchemaDefinitionNode[],
128
+ schemaExtensions: SchemaExtensionNode[],
129
+ } {
130
+ const directiveDefinitions = [];
131
+ const schemaDefinitions = [];
132
+ const schemaExtensions = [];
130
133
  for (const definitionNode of documentNode.definitions) {
131
134
  switch (definitionNode.kind) {
135
+ case 'SchemaDefinition':
136
+ schemaDefinitions.push(definitionNode);
137
+ break;
138
+ case 'SchemaExtension':
139
+ schemaExtensions.push(definitionNode);
140
+ break;
132
141
  case 'ScalarTypeDefinition':
133
142
  case 'ObjectTypeDefinition':
134
143
  case 'InterfaceTypeDefinition':
@@ -149,12 +158,16 @@ function buildNamedTypeAndDirectivesShallow(documentNode: DocumentNode, schema:
149
158
  }
150
159
  break;
151
160
  case 'DirectiveDefinition':
152
- directiveDefinitionNodes.push(definitionNode);
161
+ directiveDefinitions.push(definitionNode);
153
162
  schema.addDirectiveDefinition(definitionNode.name.value);
154
163
  break;
155
164
  }
156
165
  }
157
- return directiveDefinitionNodes;
166
+ return {
167
+ directiveDefinitions,
168
+ schemaDefinitions,
169
+ schemaExtensions,
170
+ }
158
171
  }
159
172
 
160
173
  type NodeWithDirectives = {directives?: ReadonlyArray<DirectiveNode>};
@@ -206,7 +219,9 @@ function buildSchemaDefinitionInner(
206
219
  opTypeNode);
207
220
  }
208
221
  schemaDefinition.sourceAST = schemaNode;
209
- schemaDefinition.description = 'description' in schemaNode ? schemaNode.description?.value : undefined;
222
+ if ('description' in schemaNode) {
223
+ schemaDefinition.description = schemaNode.description?.value;
224
+ }
210
225
  buildAppliedDirectives(schemaNode, schemaDefinition, extension);
211
226
  }
212
227
 
@@ -235,7 +250,8 @@ function buildArgs(argumentsNode: NodeWithArguments): Record<string, any> {
235
250
  function buildNamedTypeInner(
236
251
  definitionNode: DefinitionNode & NodeWithDirectives & NodeWithDescription,
237
252
  type: NamedType,
238
- extension?: Extension<any>
253
+ blueprint: SchemaBlueprint,
254
+ extension?: Extension<any>,
239
255
  ) {
240
256
  switch (definitionNode.kind) {
241
257
  case 'ObjectTypeDefinition':
@@ -244,6 +260,9 @@ function buildNamedTypeInner(
244
260
  case 'InterfaceTypeExtension':
245
261
  const fieldBasedType = type as ObjectType | InterfaceType;
246
262
  for (const fieldNode of definitionNode.fields ?? []) {
263
+ if (blueprint.ignoreParsedField(type, fieldNode.name.value)) {
264
+ continue;
265
+ }
247
266
  const field = fieldBasedType.addField(fieldNode.name.value);
248
267
  field.setOfExtension(extension);
249
268
  buildFieldDefinitionInner(fieldNode, field);