From a9965ec0baced5da30589de8c8a96470ba8d04ca Mon Sep 17 00:00:00 2001 From: Jesse Rosenberger Date: Wed, 19 Feb 2020 13:35:53 +0200 Subject: [PATCH] compat: minimal changes to support graphql@15 within Apollo Server (#1284) * Inline `PrintSchemaOptions` type, whose parent module has been moved. This option will likely be deprecated in `graphql@16`. For now, we'll inline this type into this module to continue emitting it into the declaration file for `makeRemoteExecutableSchema`. This is necessary since the TypeScript compiler can no longer resolve its previous location as `graphql` has moved the location of the `schemaPrinter` module to `printSchema` in https://github.com/graphql/graphql-js/pull/2426. cc @IvanGoncharov * Fix incompatibility between `iterall` and newer TypeScript types. This wouldn't be necessary if this project had a `package-lock.json`, but... * compat: filter extensions prior to passing to `buildASTSchema`. .@IvanGoncharov originally brought this to my attention when he pointed me to https://github.com/yaacovCR/graphql-tools-fork/issues/32#issuecomment-571252686 and suggested stripping extension nodes prior to invoking `buildASTSchema` as a cross-version (v14 <=> v15) approach for interim compatibility on the v4 series of `graphql-tools`. The most urgent and pertinent need here from my perspective is to allow user-exploration of the new `graphql@15` release candidate within Apollo Server which currently re-exports the entirety of `graphql-tools` (even though it only relies on small portions of it). Upon further investigation of the above-referenced issue, it appears that @yaacovCR had already crafted the solution that @IvanGoncharov had suggested to me, which I found in 2280eef8ad6c1cbc90c640228eb68094546f60f9 within the well-organized https://github.com/apollographql/graphql-tools/pull/1206 (which I am thankful for the continued updates on!). My commit here merely grabs a sub-set of that commit that seemed most pertinent; I certainly don't claim that this solution is nearly as comprehensive as the original 2280eef8ad6c1cbc90c640228eb68094546f60f9. My hope is that by using the same code/implementation here, it will marginally lessen future merge conflicts. Since this is basically a re-working of @yaacovCR's commit, I've attributed co-authorship of this commit accordingly. (Thank you, again!) Ref: https://github.com/apollographql/graphql-tools/issues/1272 Co-authored-by: yaacovCR * Add CHANGELOG for #1284. Co-authored-by: Yaacov Rydzinski --- CHANGELOG.md | 4 ++++ .../buildSchemaFromTypeDefinitions.ts | 4 +++- src/generate/filterExtensionDefinitions.ts | 19 ++++++++++++++++ src/stitching/makeRemoteExecutableSchema.ts | 22 ++++++++++++++++++- src/stitching/observableToAsyncIterable.ts | 6 ++++- 5 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 src/generate/filterExtensionDefinitions.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index befeb9d3ebe..02e36917390 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change log +### vNEXT + +* Filter `extensions` prior to passing them to `buildASTSchema`, in an effort to provide minimum compatibilty for `graphql@14`-compatible schemas with the upcoming `graphql@15` release. This PR does not, however, bring support for newer `graphql@15` features like interfaces implementing interfaces. [#1284](https://github.com/apollographql/graphql-tools/pull/1284) + ### 4.0.6 * Use `getIntrospectionQuery` instead of deprecated `introspectionQuery` constant from graphql-js diff --git a/src/generate/buildSchemaFromTypeDefinitions.ts b/src/generate/buildSchemaFromTypeDefinitions.ts index 7f8481b84d2..a122a993365 100644 --- a/src/generate/buildSchemaFromTypeDefinitions.ts +++ b/src/generate/buildSchemaFromTypeDefinitions.ts @@ -12,6 +12,7 @@ import { concatenateTypeDefs, SchemaError, } from '.'; +import filterExtensionDefinitions from './filterExtensionDefinitions'; function buildSchemaFromTypeDefinitions( typeDefinitions: ITypeDefinitions, @@ -38,10 +39,11 @@ function buildSchemaFromTypeDefinitions( } const backcompatOptions = { commentDescriptions: true }; + const typesAst = filterExtensionDefinitions(astDocument); // TODO fix types https://github.com/apollographql/graphql-tools/issues/542 let schema: GraphQLSchema = (buildASTSchema as any)( - astDocument, + typesAst, backcompatOptions, ); diff --git a/src/generate/filterExtensionDefinitions.ts b/src/generate/filterExtensionDefinitions.ts new file mode 100644 index 00000000000..e53a43a0640 --- /dev/null +++ b/src/generate/filterExtensionDefinitions.ts @@ -0,0 +1,19 @@ +import { DocumentNode, DefinitionNode, Kind } from 'graphql'; + +export default function filterExtensionDefinitions(ast: DocumentNode) { + const extensionDefs = ast.definitions.filter( + (def: DefinitionNode) => + def.kind !== Kind.OBJECT_TYPE_EXTENSION && + def.kind !== Kind.INTERFACE_TYPE_EXTENSION && + def.kind !== Kind.INPUT_OBJECT_TYPE_EXTENSION && + def.kind !== Kind.UNION_TYPE_EXTENSION && + def.kind !== Kind.ENUM_TYPE_EXTENSION && + def.kind !== Kind.SCALAR_TYPE_EXTENSION && + def.kind !== Kind.SCHEMA_EXTENSION, + ); + + return { + ...ast, + definitions: extensionDefs, + }; +} diff --git a/src/stitching/makeRemoteExecutableSchema.ts b/src/stitching/makeRemoteExecutableSchema.ts index dfc31702dc2..5ea5c7789a0 100644 --- a/src/stitching/makeRemoteExecutableSchema.ts +++ b/src/stitching/makeRemoteExecutableSchema.ts @@ -31,7 +31,6 @@ import resolveParentFromTypename from './resolveFromParentTypename'; import defaultMergedResolver from './defaultMergedResolver'; import { checkResultAndHandleErrors } from './errors'; import { observableToAsyncIterable } from './observableToAsyncIterable'; -import { Options as PrintSchemaOptions } from 'graphql/utilities/schemaPrinter'; export type ResolverFn = ( rootValue?: any, @@ -49,6 +48,27 @@ export type FetcherOperation = { context?: { [key: string]: any }; }; +/** + * This type has been copied inline from its source on `@types/graphql`: + * + * https://git.io/Jv8NX + * + * Previously, it was imported from `graphql/utilities/schemaPrinter`, however + * that module has been removed in `graphql@15`. Furthermore, the sole property + * on this type is due to be deprecated in `graphql@16`. + */ +interface PrintSchemaOptions { + /** + * Descriptions are defined as preceding string literals, however an older + * experimental version of the SDL supported preceding comments as + * descriptions. Set to true to enable this deprecated behavior. + * This option is provided to ease adoption and will be removed in v16. + * + * Default: false + */ + commentDescriptions?: boolean; +} + export default function makeRemoteExecutableSchema({ schema, link, diff --git a/src/stitching/observableToAsyncIterable.ts b/src/stitching/observableToAsyncIterable.ts index 9de23102b7b..7b0cd203e02 100644 --- a/src/stitching/observableToAsyncIterable.ts +++ b/src/stitching/observableToAsyncIterable.ts @@ -2,7 +2,11 @@ import { Observable } from 'apollo-link'; import { $$asyncIterator } from 'iterall'; type Callback = (value?: any) => any; -export function observableToAsyncIterable(observable: Observable): AsyncIterator { +export function observableToAsyncIterable( + observable: Observable +): AsyncIterator & { + [$$asyncIterator]: () => AsyncIterator; +} { const pullQueue: Callback[] = []; const pushQueue: any[] = [];