Skip to content

Commit 509c85d

Browse files
committed
Flow type the AST schema builder
1 parent dfe676c commit 509c85d

File tree

2 files changed

+81
-67
lines changed

2 files changed

+81
-67
lines changed

src/utilities/buildASTSchema.js

Lines changed: 76 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* @noflow */
1+
/* @flow */
22
/**
33
* Copyright (c) 2015, Facebook, Inc.
44
* All rights reserved.
@@ -8,7 +8,7 @@
88
* of patent rights can be found in the PATENTS file in the same directory.
99
*/
1010

11-
import isNullish from '../jsutils/isNullish';
11+
import invariant from '../jsutils/invariant';
1212
import keyMap from '../jsutils/keyMap';
1313
import keyValMap from '../jsutils/keyValMap';
1414
import { valueFromAST } from './valueFromAST';
@@ -29,6 +29,9 @@ import {
2929

3030
import type {
3131
Document,
32+
Type,
33+
NamedType,
34+
TypeDefinition,
3235
ObjectTypeDefinition,
3336
InputValueDefinition,
3437
InterfaceTypeDefinition,
@@ -55,27 +58,38 @@ import {
5558
GraphQLNonNull,
5659
} from '../type';
5760

61+
import type {
62+
GraphQLType,
63+
GraphQLNamedType
64+
} from '../type/definition';
65+
5866

5967
type CompositeDefinition =
6068
ObjectTypeDefinition |
6169
InterfaceTypeDefinition |
6270
UnionTypeDefinition;
6371

64-
function buildWrappedType(innerType, inputTypeAST) {
72+
function buildWrappedType(
73+
innerType: GraphQLType,
74+
inputTypeAST: Type
75+
): GraphQLType {
6576
if (inputTypeAST.kind === LIST_TYPE) {
6677
return new GraphQLList(buildWrappedType(innerType, inputTypeAST.type));
6778
}
6879
if (inputTypeAST.kind === NON_NULL_TYPE) {
69-
return new GraphQLNonNull(buildWrappedType(innerType, inputTypeAST.type));
80+
const wrappedType = buildWrappedType(innerType, inputTypeAST.type);
81+
invariant(!(wrappedType instanceof GraphQLNonNull), 'No nesting nonnull.');
82+
return new GraphQLNonNull(wrappedType);
7083
}
7184
return innerType;
7285
}
7386

74-
function getInnerTypeName(typeAST) {
75-
if (typeAST.kind === LIST_TYPE || typeAST.kind === NON_NULL_TYPE) {
76-
return getInnerTypeName(typeAST.type);
87+
function getNamedTypeAST(typeAST: Type): NamedType {
88+
let namedType = typeAST;
89+
while (namedType.kind === LIST_TYPE || namedType.kind === NON_NULL_TYPE) {
90+
namedType = namedType.type;
7791
}
78-
return typeAST.name.value;
92+
return namedType;
7993
}
8094

8195
/**
@@ -92,100 +106,97 @@ export function buildASTSchema(
92106
mutationTypeName: ?string,
93107
subscriptionTypeName: ?string
94108
): GraphQLSchema {
95-
96-
if (isNullish(ast)) {
109+
if (!ast) {
97110
throw new Error('must pass in ast');
98111
}
99-
if (isNullish(queryTypeName)) {
112+
113+
if (!queryTypeName) {
100114
throw new Error('must pass in query type');
101115
}
102116

103-
const typeDefs = ast.definitions.filter(d => {
117+
const typeDefs: Array<TypeDefinition> = [];
118+
for (let i = 0; i < ast.definitions.length; i++) {
119+
const d = ast.definitions[i];
104120
switch (d.kind) {
105121
case OBJECT_TYPE_DEFINITION:
106122
case INTERFACE_TYPE_DEFINITION:
107123
case ENUM_TYPE_DEFINITION:
108124
case UNION_TYPE_DEFINITION:
109125
case SCALAR_TYPE_DEFINITION:
110-
case INPUT_OBJECT_TYPE_DEFINITION: return true;
126+
case INPUT_OBJECT_TYPE_DEFINITION:
127+
typeDefs.push(d);
111128
}
112-
});
129+
}
113130

114-
const astMap = keyMap(typeDefs, d => d.name.value);
131+
const astMap: {[name: string]: TypeDefinition} =
132+
keyMap(typeDefs, d => d.name.value);
115133

116-
if (isNullish(astMap[queryTypeName])) {
134+
if (!astMap[queryTypeName]) {
117135
throw new Error('Specified query type ' + queryTypeName +
118136
' not found in document.');
119137
}
120138

121-
if (!isNullish(mutationTypeName) && isNullish(astMap[mutationTypeName])) {
139+
if (mutationTypeName && !astMap[mutationTypeName]) {
122140
throw new Error('Specified mutation type ' + mutationTypeName +
123141
' not found in document.');
124142
}
125143

126-
if (!isNullish(subscriptionTypeName) &&
127-
isNullish(astMap[subscriptionTypeName])) {
144+
if (subscriptionTypeName && !astMap[subscriptionTypeName]) {
128145
throw new Error('Specified subscription type ' + subscriptionTypeName +
129146
' not found in document.');
130147
}
131148

132-
/**
133-
* This generates a function that allows you to produce
134-
* type definitions on demand. We produce the function
135-
* in order to close over the memoization dictionaries
136-
* that need to be retained over multiple functions calls.
137-
**/
138-
function getTypeDefProducer() {
139-
140-
const innerTypeMap = {
141-
String: GraphQLString,
142-
Int: GraphQLInt,
143-
Float: GraphQLFloat,
144-
Boolean: GraphQLBoolean,
145-
ID: GraphQLID,
146-
};
149+
const innerTypeMap = {
150+
String: GraphQLString,
151+
Int: GraphQLInt,
152+
Float: GraphQLFloat,
153+
Boolean: GraphQLBoolean,
154+
ID: GraphQLID,
155+
};
147156

148-
return typeAST => {
149-
const typeName = getInnerTypeName(typeAST);
150-
if (!isNullish(innerTypeMap[typeName])) {
151-
return buildWrappedType(innerTypeMap[typeName], typeAST);
152-
}
157+
typeDefs.forEach(def => typeDefNamed(def.name.value));
153158

154-
if (isNullish(astMap[typeName])) {
155-
throw new Error(`Type ${typeName} not found in document`);
156-
}
159+
return new GraphQLSchema({
160+
query: getObjectType(astMap[queryTypeName]),
161+
mutation: mutationTypeName ? getObjectType(astMap[mutationTypeName]) : null,
162+
subscription:
163+
subscriptionTypeName ? getObjectType(astMap[subscriptionTypeName]) : null,
164+
});
157165

158-
const innerTypeDef = makeSchemaDef(astMap[typeName]);
159-
if (isNullish(innerTypeDef)) {
160-
throw new Error('Nothing constructed for ' + typeName);
161-
}
162-
innerTypeMap[typeName] = innerTypeDef;
163-
return buildWrappedType(innerTypeDef, typeAST);
164-
};
166+
function getObjectType(typeAST: TypeDefinition): GraphQLObjectType {
167+
const type = typeDefNamed(typeAST.name.value);
168+
invariant(
169+
type instanceof GraphQLObjectType,
170+
`AST must provide object type.`
171+
);
172+
return (type: any);
165173
}
166174

167-
const produceTypeDef = getTypeDefProducer(ast);
168-
169-
ast.definitions.forEach(produceTypeDef);
170-
171-
const queryType = produceTypeDef(astMap[queryTypeName]);
175+
function produceTypeDef(typeAST: Type): GraphQLType {
176+
const typeName = getNamedTypeAST(typeAST).name.value;
177+
const typeDef = typeDefNamed(typeName);
178+
return buildWrappedType(typeDef, typeAST);
179+
}
172180

173-
const schemaBody = {
174-
query: queryType
175-
};
181+
function typeDefNamed(typeName: string): GraphQLNamedType {
182+
if (innerTypeMap[typeName]) {
183+
return innerTypeMap[typeName];
184+
}
176185

177-
if (!isNullish(mutationTypeName)) {
178-
schemaBody.mutation = produceTypeDef(astMap[mutationTypeName]);
179-
}
186+
if (!astMap[typeName]) {
187+
throw new Error(`Type ${typeName} not found in document`);
188+
}
180189

181-
if (!isNullish(subscriptionTypeName)) {
182-
schemaBody.subscription = produceTypeDef(astMap[subscriptionTypeName]);
190+
const innerTypeDef = makeSchemaDef(astMap[typeName]);
191+
if (!innerTypeDef) {
192+
throw new Error('Nothing constructed for ' + typeName);
193+
}
194+
innerTypeMap[typeName] = innerTypeDef;
195+
return innerTypeDef;
183196
}
184197

185-
return new GraphQLSchema(schemaBody);
186-
187198
function makeSchemaDef(def) {
188-
if (isNullish(def)) {
199+
if (!def) {
189200
throw new Error('def must be defined');
190201
}
191202
switch (def.kind) {

src/utilities/buildClientSchema.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import { TypeKind } from '../type/introspection';
4242

4343
import type {
4444
GraphQLType,
45-
GraphQLNullableType,
4645
GraphQLInputType,
4746
GraphQLOutputType,
4847
GraphQLNamedType,
@@ -112,7 +111,11 @@ export function buildClientSchema(
112111
throw new Error('Decorated type deeper than introspection query.');
113112
}
114113
const nullableType = getType(nullableRef);
115-
return new GraphQLNonNull(((nullableType: any): GraphQLNullableType));
114+
invariant(
115+
!(nullableType instanceof GraphQLNonNull),
116+
'No nesting nonnull.'
117+
);
118+
return new GraphQLNonNull(nullableType);
116119
}
117120
return getNamedType(typeRef.name);
118121
}

0 commit comments

Comments
 (0)