Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove usage of Flow placeholder argument + cleanup #1669

Merged
merged 1 commit into from
Jan 16, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 106 additions & 86 deletions src/utilities/buildASTSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { Kind } from '../language/kinds';

import type {
DocumentNode,
NameNode,
TypeNode,
NamedTypeNode,
SchemaDefinitionNode,
Expand All @@ -49,8 +50,9 @@ import type {
GraphQLType,
GraphQLNamedType,
GraphQLFieldConfig,
GraphQLArgumentConfig,
GraphQLEnumValueConfig,
GraphQLInputField,
GraphQLInputFieldConfig,
} from '../type/definition';

import {
Expand Down Expand Up @@ -256,17 +258,17 @@ export class ASTDefinitionBuilder {
return this.buildType(typeNode);
}

buildDirective(directiveNode: DirectiveDefinitionNode): GraphQLDirective {
buildDirective(directive: DirectiveDefinitionNode): GraphQLDirective {
const locations = directive.locations.map(
({ value }) => ((value: any): DirectiveLocationEnum),
);

return new GraphQLDirective({
name: directiveNode.name.value,
description: getDescription(directiveNode, this._options),
locations: directiveNode.locations.map(
node => ((node.value: any): DirectiveLocationEnum),
),
args:
directiveNode.arguments &&
this._makeInputValues(directiveNode.arguments),
astNode: directiveNode,
name: directive.name.value,
description: getDescription(directive, this._options),
locations,
args: keyByNameNode(directive.arguments || [], arg => this.buildArg(arg)),
astNode: directive,
});
}

Expand All @@ -277,19 +279,31 @@ export class ASTDefinitionBuilder {
// with validateSchema() will produce more actionable results.
type: (this._buildWrappedType(field.type): any),
description: getDescription(field, this._options),
args: field.arguments && this._makeInputValues(field.arguments),
args: keyByNameNode(field.arguments || [], arg => this.buildArg(arg)),
deprecationReason: getDeprecationReason(field),
astNode: field,
};
}

buildInputField(value: InputValueDefinitionNode): GraphQLInputField {
buildArg(value: InputValueDefinitionNode): GraphQLArgumentConfig {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably shouldn't expose this, as we're not building a schema GraphQLArgument but just a GraphQLArgumentConfig.

Having buildFoo sometimes return a GraphQLFoo and sometimes a GraphQLFooConfig is confusing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see we're already doing this with buildField. That is quite confusing but is fine then. I wish buildDirective was also building a GraphQLDirectiveConfig too, but that ship has sailed. Maybe a wishlist for v15?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mjmahone The entire class is internal it's just a bunch of functions that buildSchema/extendSchema are using.
So it's just cleanup of internal API.

// Note: While this could make assertions to get the correctly typed
// value, that would throw immediately while type system validation
// with validateSchema() will produce more actionable results.
const type: any = this._buildWrappedType(value.type);
return {
type,
description: getDescription(value, this._options),
defaultValue: valueFromAST(value.defaultValue, type),
astNode: value,
};
}

buildInputField(value: InputValueDefinitionNode): GraphQLInputFieldConfig {
// Note: While this could make assertions to get the correctly typed
// value, that would throw immediately while type system validation
// with validateSchema() will produce more actionable results.
const type: any = this._buildWrappedType(value.type);
return {
name: value.name.value,
type,
description: getDescription(value, this._options),
defaultValue: valueFromAST(value.defaultValue, type),
Expand All @@ -305,121 +319,127 @@ export class ASTDefinitionBuilder {
};
}

_makeSchemaDef(def: TypeDefinitionNode): GraphQLNamedType {
switch (def.kind) {
_makeSchemaDef(astNode: TypeDefinitionNode): GraphQLNamedType {
switch (astNode.kind) {
case Kind.OBJECT_TYPE_DEFINITION:
return this._makeTypeDef(def);
return this._makeTypeDef(astNode);
case Kind.INTERFACE_TYPE_DEFINITION:
return this._makeInterfaceDef(def);
return this._makeInterfaceDef(astNode);
case Kind.ENUM_TYPE_DEFINITION:
return this._makeEnumDef(def);
return this._makeEnumDef(astNode);
case Kind.UNION_TYPE_DEFINITION:
return this._makeUnionDef(def);
return this._makeUnionDef(astNode);
case Kind.SCALAR_TYPE_DEFINITION:
return this._makeScalarDef(def);
return this._makeScalarDef(astNode);
case Kind.INPUT_OBJECT_TYPE_DEFINITION:
return this._makeInputObjectDef(def);
return this._makeInputObjectDef(astNode);
default:
throw new Error(`Type kind "${def.kind}" not supported.`);
throw new Error(`Type kind "${astNode.kind}" not supported.`);
}
}

_makeTypeDef(def: ObjectTypeDefinitionNode) {
const interfaces: ?$ReadOnlyArray<NamedTypeNode> = def.interfaces;
_makeTypeDef(astNode: ObjectTypeDefinitionNode) {
const interfaceNodes = astNode.interfaces;
const fieldNodes = astNode.fields;

// Note: While this could make assertions to get the correctly typed
// values below, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
const interfaces =
interfaceNodes && interfaceNodes.length > 0
? () => interfaceNodes.map(ref => (this.buildType(ref): any))
: [];

const fields =
fieldNodes && fieldNodes.length > 0
? () => keyByNameNode(fieldNodes, field => this.buildField(field))
: Object.create(null);

return new GraphQLObjectType({
name: def.name.value,
description: getDescription(def, this._options),
fields: () => this._makeFieldDefMap(def),
// Note: While this could make early assertions to get the correctly
// typed values, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
interfaces: interfaces
? () => interfaces.map(ref => (this.buildType(ref): any))
: [],
astNode: def,
name: astNode.name.value,
description: getDescription(astNode, this._options),
interfaces,
fields,
astNode,
});
}

_makeFieldDefMap(
def: ObjectTypeDefinitionNode | InterfaceTypeDefinitionNode,
) {
return def.fields
? keyValMap<_, GraphQLFieldConfig<mixed, mixed>>(
def.fields,
field => field.name.value,
field => this.buildField(field),
)
: {};
}
_makeInterfaceDef(astNode: InterfaceTypeDefinitionNode) {
const fieldNodes = astNode.fields;

_makeInputValues(values: $ReadOnlyArray<InputValueDefinitionNode>) {
return keyValMap<_, GraphQLInputField>(
values,
value => value.name.value,
value => this.buildInputField(value),
);
}
const fields =
fieldNodes && fieldNodes.length > 0
? () => keyByNameNode(fieldNodes, field => this.buildField(field))
: Object.create(null);

_makeInterfaceDef(def: InterfaceTypeDefinitionNode) {
return new GraphQLInterfaceType({
name: def.name.value,
description: getDescription(def, this._options),
fields: () => this._makeFieldDefMap(def),
astNode: def,
name: astNode.name.value,
description: getDescription(astNode, this._options),
fields,
astNode,
});
}

_makeEnumDef(def: EnumTypeDefinitionNode) {
_makeEnumDef(astNode: EnumTypeDefinitionNode) {
const valueNodes = astNode.values || [];

return new GraphQLEnumType({
name: def.name.value,
description: getDescription(def, this._options),
values: this._makeValueDefMap(def),
astNode: def,
name: astNode.name.value,
description: getDescription(astNode, this._options),
values: keyByNameNode(valueNodes, value => this.buildEnumValue(value)),
astNode,
});
}

_makeValueDefMap(def: EnumTypeDefinitionNode) {
return def.values
? keyValMap<_, GraphQLEnumValueConfig>(
def.values,
enumValue => enumValue.name.value,
enumValue => this.buildEnumValue(enumValue),
)
: {};
}
_makeUnionDef(astNode: UnionTypeDefinitionNode) {
const typeNodes = astNode.types;

// Note: While this could make assertions to get the correctly typed
// values below, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
const types =
typeNodes && typeNodes.length > 0
? () => typeNodes.map(ref => (this.buildType(ref): any))
: [];

_makeUnionDef(def: UnionTypeDefinitionNode) {
const types: ?$ReadOnlyArray<NamedTypeNode> = def.types;
return new GraphQLUnionType({
name: def.name.value,
description: getDescription(def, this._options),
// Note: While this could make assertions to get the correctly typed
// values below, that would throw immediately while type system
// validation with validateSchema() will produce more actionable results.
types: types ? () => types.map(ref => (this.buildType(ref): any)) : [],
astNode: def,
name: astNode.name.value,
description: getDescription(astNode, this._options),
types,
astNode,
});
}

_makeScalarDef(def: ScalarTypeDefinitionNode) {
_makeScalarDef(astNode: ScalarTypeDefinitionNode) {
return new GraphQLScalarType({
name: def.name.value,
description: getDescription(def, this._options),
astNode: def,
name: astNode.name.value,
description: getDescription(astNode, this._options),
astNode,
serialize: value => value,
});
}

_makeInputObjectDef(def: InputObjectTypeDefinitionNode) {
const { fields } = def;

return new GraphQLInputObjectType({
name: def.name.value,
description: getDescription(def, this._options),
fields: () => (def.fields ? this._makeInputValues(def.fields) : {}),
fields: fields
? () => keyByNameNode(fields, field => this.buildInputField(field))
: Object.create(null),
astNode: def,
});
}
}

function keyByNameNode<T: { +name: NameNode }, V>(
list: $ReadOnlyArray<T>,
valFn: (item: T) => V,
): ObjMap<V> {
return keyValMap(list, ({ name }) => name.value, valFn);
}

/**
* Given a field or enum value node, returns the string value for the
* deprecation reason.
Expand Down