Skip to content
This repository has been archived by the owner on Apr 15, 2020. It is now read-only.

Commit

Permalink
fix(ci): properly polyfill graphql v14.1 and 14.2
Browse files Browse the repository at this point in the history
to properly support all graphql versions >= v0.12
  • Loading branch information
yaacovCR committed Feb 28, 2020
1 parent 52af218 commit c3d6515
Show file tree
Hide file tree
Showing 20 changed files with 156 additions and 76 deletions.
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
!dist/*
!dist/generate/*
!dist/links/*
!dist/polyfills/*
!dist/scalars/*
!dist/stitching/*
!dist/transforms/*
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ node_js:
env:
- GRAPHQL_VERSION='0.12'
- GRAPHQL_VERSION='0.13'
- GRAPHQL_VERSION='14.0'
- GRAPHQL_VERSION='14.1'
- GRAPHQL_VERSION='14.2'
- GRAPHQL_VERSION='14.3'
Expand Down
4 changes: 2 additions & 2 deletions src/generate/addResolversToSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ import {
healSchema,
forEachField,
forEachDefaultValue,
typeToConfig,
} from '../utils';
import { toConfig } from '../polyfills';

import SchemaError from './SchemaError';
import checkForResolveTypeResolver from './checkForResolveTypeResolver';
Expand Down Expand Up @@ -105,7 +105,7 @@ function addResolversToSchema(
}
});

const config = typeToConfig(type);
const config = toConfig(type);

const values = type.getValues();
const newValues = {};
Expand Down
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './Interfaces';
export * from './links';
export * from './makeExecutableSchema';
export * from './mock';
export * from './polyfills';
export * from './scalars';
export * from './stitching';
export * from './transforms';
Expand Down
9 changes: 9 additions & 0 deletions src/polyfills/buildSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Source, buildASTSchema, parse, BuildSchemaOptions } from 'graphql';

// polyfill for graphql prior to v13 which do not pass options to buildASTSchema
export function buildSchema(
ast: string | Source,
buildSchemaOptions: BuildSchemaOptions,
) {
return buildASTSchema(parse(ast), buildSchemaOptions);
}
37 changes: 37 additions & 0 deletions src/polyfills/extendSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {
DocumentNode,
GraphQLSchema,
extendSchema as graphqlExtendSchema,
} from 'graphql';

import { getResolversFromSchema } from '../utils';
import { IResolverOptions } from '../Interfaces';

// polyfill for graphql < v14.2 which does not support subscriptions
export function extendSchema(
schema: GraphQLSchema,
extension: DocumentNode,
options: any,
): GraphQLSchema {
const subscriptionType = schema.getSubscriptionType();
if (subscriptionType == null) {
return graphqlExtendSchema(schema, extension, options);
}

const resolvers = getResolversFromSchema(schema);

const subscriptionTypeName = subscriptionType.name;
const subscriptionResolvers = resolvers[
subscriptionTypeName
] as IResolverOptions;

const extendedSchema = graphqlExtendSchema(schema, extension, options);

const fields = extendedSchema.getSubscriptionType().getFields();
Object.keys(subscriptionResolvers).forEach(fieldName => {
fields[fieldName].resolve = subscriptionResolvers[fieldName].resolve;
fields[fieldName].subscribe = subscriptionResolvers[fieldName].subscribe;
});

return extendedSchema;
}
18 changes: 18 additions & 0 deletions src/polyfills/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export { isSpecifiedScalarType } from './isSpecifiedScalarType';

export { buildSchema } from './buildSchema';

export { extendSchema } from './extendSchema';

export {
toConfig,
schemaToConfig,
typeToConfig,
objectTypeToConfig,
interfaceTypeToConfig,
unionTypeToConfig,
enumTypeToConfig,
scalarTypeToConfig,
inputObjectTypeToConfig,
directiveToConfig,
} from './toConfig';
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export const specifiedScalarTypes: Array<GraphQLScalarType> = [
GraphQLID,
];

export default function isSpecifiedScalarType(type: any): boolean {
export function isSpecifiedScalarType(type: any): boolean {
return (
isNamedType(type) &&
// Would prefer to use specifiedScalarTypes.some(), however %checks needs
Expand Down
45 changes: 44 additions & 1 deletion src/utils/toConfig.ts → src/polyfills/toConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ import {
isEnumType,
isScalarType,
isInputObjectType,
isSchema,
isDirective,
isNamedType,
} from 'graphql';

import { graphqlVersion } from './graphqlVersion';
import { graphqlVersion } from '../utils/graphqlVersion';

export function schemaToConfig(schema: GraphQLSchema): GraphQLSchemaConfig {
const newTypes: Array<GraphQLNamedType> = [];
Expand Down Expand Up @@ -66,6 +69,45 @@ export function schemaToConfig(schema: GraphQLSchema): GraphQLSchemaConfig {
return schemaConfig;
}

export function toConfig(
schemaOrTypeOrDirective: GraphQLSchema,
): GraphQLSchemaConfig;
export function toConfig(
schemaOrTypeOrDirective: GraphQLObjectType,
): GraphQLObjectTypeConfig<any, any>;
export function toConfig(
schemaOrTypeOrDirective: GraphQLInterfaceType,
): GraphQLInterfaceTypeConfig<any, any>;
export function toConfig(
schemaOrTypeOrDirective: GraphQLUnionType,
): GraphQLUnionTypeConfig<any, any>;
export function toConfig(
schemaOrTypeOrDirective: GraphQLEnumType,
): GraphQLEnumTypeConfig;
export function toConfig(
schemaOrTypeOrDirective: GraphQLScalarType,
): GraphQLScalarTypeConfig<any, any>;
export function toConfig(
schemaOrTypeOrDirective: GraphQLInputObjectType,
): GraphQLInputObjectTypeConfig;
export function toConfig(
schemaOrTypeOrDirective: GraphQLDirective,
): GraphQLDirectiveConfig;
export function toConfig(schemaOrTypeOrDirective: any): any;
export function toConfig(schemaOrTypeOrDirective: any) {
if (isSchema(schemaOrTypeOrDirective)) {
return schemaToConfig(schemaOrTypeOrDirective);
} else if (isDirective(schemaOrTypeOrDirective)) {
return directiveToConfig(schemaOrTypeOrDirective);
} else if (isNamedType(schemaOrTypeOrDirective)) {
return typeToConfig(schemaOrTypeOrDirective);
}

throw new Error(
`Unknown object ${(schemaOrTypeOrDirective as unknown) as string}`,
);
}

export function typeToConfig(
type: GraphQLObjectType,
): GraphQLObjectTypeConfig<any, any>;
Expand All @@ -82,6 +124,7 @@ export function typeToConfig(
export function typeToConfig(
type: GraphQLInputObjectType,
): GraphQLInputObjectTypeConfig;
export function typeToConfig(type: any): any;
export function typeToConfig(type: any) {
if (isObjectType(type)) {
return objectTypeToConfig(type);
Expand Down
5 changes: 2 additions & 3 deletions src/stitching/makeRemoteExecutableSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import {
GraphQLResolveInfo,
BuildSchemaOptions,
DocumentNode,
buildASTSchema,
parse,
} from 'graphql';

import { addResolversToSchema } from '../generate';
import { Fetcher, Operation } from '../Interfaces';
import { cloneSchema } from '../utils';
import { buildSchema } from '../polyfills';

import linkToFetcher, { execute } from './linkToFetcher';
import { addTypenameToAbstract } from './addTypenameToAbstract';
Expand Down Expand Up @@ -49,7 +48,7 @@ export default function makeRemoteExecutableSchema({

const targetSchema =
typeof schemaOrTypeDefs === 'string'
? buildASTSchema(parse(schemaOrTypeDefs), buildSchemaOptions)
? buildSchema(schemaOrTypeDefs, buildSchemaOptions)
: schemaOrTypeDefs;

const remoteSchema = cloneSchema(targetSchema);
Expand Down
44 changes: 12 additions & 32 deletions src/stitching/mergeSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import {
GraphQLObjectType,
GraphQLScalarType,
GraphQLSchema,
extendSchema,
getNamedType,
isNamedType,
parse,
Expand Down Expand Up @@ -36,10 +35,9 @@ import {
healTypes,
forEachField,
mergeDeep,
typeToConfig,
graphqlVersion,
getResolversFromSchema,
} from '../utils';
import { toConfig, extendSchema } from '../polyfills';

import typeFromAST from './typeFromAST';
import { createMergeInfo, completeMergeInfo } from './mergeInfo';
Expand Down Expand Up @@ -246,28 +244,11 @@ export default function mergeSchemas({
: undefined,
});

let proxyingResolvers: IResolvers;
if (graphqlVersion() >= 14) {
extensions.forEach(extension => {
mergedSchema = extendSchema(mergedSchema, extension, {
commentDescriptions: true,
});
});
} else {
// extendSchema in graphql < v14 does not support subscriptions?
proxyingResolvers = getResolversFromSchema(mergedSchema);

extensions.forEach(extension => {
mergedSchema = extendSchema(mergedSchema, extension, {
commentDescriptions: true,
});
extensions.forEach(extension => {
mergedSchema = extendSchema(mergedSchema, extension, {
commentDescriptions: true,
});

addResolversToSchema({
schema: mergedSchema,
resolvers: proxyingResolvers,
});
}
});

addResolversToSchema({
schema: mergedSchema,
Expand Down Expand Up @@ -361,12 +342,12 @@ function merge(
fields: candidates.reduce(
(acc, candidate) => ({
...acc,
...typeToConfig(candidate.type as GraphQLObjectType).fields,
...toConfig(candidate.type as GraphQLObjectType).fields,
}),
{},
),
interfaces: candidates.reduce((acc, candidate) => {
const interfaces = typeToConfig(candidate.type as GraphQLObjectType)
const interfaces = toConfig(candidate.type as GraphQLObjectType)
.interfaces;
return interfaces != null ? acc.concat(interfaces) : acc;
}, []),
Expand All @@ -377,16 +358,15 @@ function merge(
fields: candidates.reduce(
(acc, candidate) => ({
...acc,
...typeToConfig(candidate.type as GraphQLObjectType).fields,
...toConfig(candidate.type as GraphQLObjectType).fields,
}),
{},
),
interfaces:
graphqlVersion() >= 15
? candidates.reduce((acc, candidate) => {
const interfaces = typeToConfig(
candidate.type as GraphQLObjectType,
).interfaces;
const interfaces = toConfig(candidate.type as GraphQLObjectType)
.interfaces;
return interfaces != null ? acc.concat(interfaces) : acc;
}, [])
: undefined,
Expand All @@ -397,7 +377,7 @@ function merge(
name: typeName,
types: candidates.reduce(
(acc, candidate) =>
acc.concat(typeToConfig(candidate.type as GraphQLUnionType).types),
acc.concat(toConfig(candidate.type as GraphQLUnionType).types),
[],
),
});
Expand All @@ -407,7 +387,7 @@ function merge(
values: candidates.reduce(
(acc, candidate) => ({
...acc,
...typeToConfig(candidate.type as GraphQLEnumType).values,
...toConfig(candidate.type as GraphQLEnumType).values,
}),
{},
),
Expand Down
5 changes: 2 additions & 3 deletions src/test/testAlternateMergeSchemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
FilterRootFields,
FilterObjectFields,
} from '../transforms';
import { isSpecifiedScalarType, toConfig } from '../polyfills';

import { makeExecutableSchema } from '../makeExecutableSchema';
import {
Expand All @@ -35,12 +36,10 @@ import {
createMergedResolver,
} from '../stitching';
import { SubschemaConfig } from '../Interfaces';
import isSpecifiedScalarType from '../utils/isSpecifiedScalarType';
import {
wrapFieldNode,
renameFieldNode,
hoistFieldNodes,
typeToConfig,
graphqlVersion,
} from '../utils';

Expand Down Expand Up @@ -355,7 +354,7 @@ describe('transform object fields', () => {
return undefined;
}
const type = propertySchema.getType(typeName) as GraphQLObjectType;
const typeConfig = typeToConfig(type);
const typeConfig = toConfig(type);
const fieldConfig = typeConfig.fields[
fieldName
] as GraphQLFieldConfig<any, any>;
Expand Down
5 changes: 3 additions & 2 deletions src/test/testUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { expect } from 'chai';
import { GraphQLObjectType } from 'graphql';

import { healSchema, typeToConfig } from '../utils';
import { healSchema } from '../utils';
import { toConfig } from '../polyfills';
import { makeExecutableSchema } from '../makeExecutableSchema';

describe('heal', () => {
Expand All @@ -19,7 +20,7 @@ describe('heal', () => {
});
const originalTypeMap = schema.getTypeMap();

const config = typeToConfig(
const config = toConfig(
originalTypeMap['WillBeEmptyObject'] as GraphQLObjectType,
);
originalTypeMap['WillBeEmptyObject'] = new GraphQLObjectType({
Expand Down
2 changes: 1 addition & 1 deletion src/transforms/RenameTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
GraphQLScalarType,
} from 'graphql';

import isSpecifiedScalarType from '../utils/isSpecifiedScalarType';
import { isSpecifiedScalarType } from '../polyfills';
import { Request, Result, VisitSchemaKind } from '../Interfaces';
import { Transform } from '../transforms/transforms';
import { visitSchema, cloneType } from '../utils';
Expand Down

0 comments on commit c3d6515

Please sign in to comment.