diff --git a/src/__testUtils__/__tests__/genFuzzStrings-test.js b/src/__testUtils__/__tests__/genFuzzStrings-test.js index 0e9ec2b189..c9d79cf47a 100644 --- a/src/__testUtils__/__tests__/genFuzzStrings-test.js +++ b/src/__testUtils__/__tests__/genFuzzStrings-test.js @@ -5,7 +5,10 @@ import { describe, it } from 'mocha'; import genFuzzStrings from '../genFuzzStrings'; -function expectFuzzStrings(options) { +function expectFuzzStrings(options: {| + allowedChars: Array, + maxLength: number, +|}) { return expect(Array.from(genFuzzStrings(options))); } diff --git a/src/__tests__/starWarsData.js b/src/__tests__/starWarsData.js index 5144f3735e..977d25c3bd 100644 --- a/src/__tests__/starWarsData.js +++ b/src/__tests__/starWarsData.js @@ -1,5 +1,35 @@ // @flow strict +/** + * These are types which correspond to the schema. + * They represent the shape of the data visited during field resolution. + */ +export type Character = { + id: string, + name: string, + friends: Array, + appearsIn: Array, + ... +}; + +export type Human = {| + type: 'Human', + id: string, + name: string, + friends: Array, + appearsIn: Array, + homePlanet?: string, +|}; + +export type Droid = {| + type: 'Droid', + id: string, + name: string, + friends: Array, + appearsIn: Array, + primaryFunction: string, +|}; + /** * This defines a basic set of data for our Star Wars Schema. * @@ -8,7 +38,7 @@ * JSON objects in a more complex demo. */ -const luke = { +const luke: Human = { type: 'Human', id: '1000', name: 'Luke Skywalker', @@ -17,7 +47,7 @@ const luke = { homePlanet: 'Tatooine', }; -const vader = { +const vader: Human = { type: 'Human', id: '1001', name: 'Darth Vader', @@ -26,7 +56,7 @@ const vader = { homePlanet: 'Tatooine', }; -const han = { +const han: Human = { type: 'Human', id: '1002', name: 'Han Solo', @@ -34,7 +64,7 @@ const han = { appearsIn: [4, 5, 6], }; -const leia = { +const leia: Human = { type: 'Human', id: '1003', name: 'Leia Organa', @@ -43,7 +73,7 @@ const leia = { homePlanet: 'Alderaan', }; -const tarkin = { +const tarkin: Human = { type: 'Human', id: '1004', name: 'Wilhuff Tarkin', @@ -51,7 +81,7 @@ const tarkin = { appearsIn: [4], }; -const humanData = { +const humanData: {| [id: string]: Human |} = { '1000': luke, '1001': vader, '1002': han, @@ -59,7 +89,7 @@ const humanData = { '1004': tarkin, }; -const threepio = { +const threepio: Droid = { type: 'Droid', id: '2000', name: 'C-3PO', @@ -68,7 +98,7 @@ const threepio = { primaryFunction: 'Protocol', }; -const artoo = { +const artoo: Droid = { type: 'Droid', id: '2001', name: 'R2-D2', @@ -77,45 +107,15 @@ const artoo = { primaryFunction: 'Astromech', }; -const droidData = { +const droidData: {| [id: string]: Droid |} = { '2000': threepio, '2001': artoo, }; -/** - * These are Flow types which correspond to the schema. - * They represent the shape of the data visited during field resolution. - */ -export type Character = { - id: string, - name: string, - friends: Array, - appearsIn: Array, - ... -}; - -export type Human = {| - type: 'Human', - id: string, - name: string, - friends: Array, - appearsIn: Array, - homePlanet: string, -|}; - -export type Droid = {| - type: 'Droid', - id: string, - name: string, - friends: Array, - appearsIn: Array, - primaryFunction: string, -|}; - /** * Helper function to get a character by ID. */ -function getCharacter(id) { +function getCharacter(id: string): Promise { // Returning a promise just to illustrate that GraphQL.js supports it. return Promise.resolve(humanData[id] ?? droidData[id]); } @@ -123,7 +123,9 @@ function getCharacter(id) { /** * Allows us to query for a character's friends. */ -export function getFriends(character: Character): Array> { +export function getFriends( + character: Character, +): Array> { // Notice that GraphQL accepts Arrays of Promises. return character.friends.map((id) => getCharacter(id)); } @@ -143,13 +145,13 @@ export function getHero(episode: number): Character { /** * Allows us to query for the human with the given id. */ -export function getHuman(id: string): Human { +export function getHuman(id: string): Human | null { return humanData[id]; } /** * Allows us to query for the droid with the given id. */ -export function getDroid(id: string): Droid { +export function getDroid(id: string): Droid | null { return droidData[id]; } diff --git a/src/__tests__/starWarsIntrospection-test.js b/src/__tests__/starWarsIntrospection-test.js index 8db0c324c6..4d23b0f459 100644 --- a/src/__tests__/starWarsIntrospection-test.js +++ b/src/__tests__/starWarsIntrospection-test.js @@ -7,7 +7,7 @@ import { graphqlSync } from '../graphql'; import { StarWarsSchema } from './starWarsSchema'; -function queryStarWars(source) { +function queryStarWars(source: string) { const result = graphqlSync({ schema: StarWarsSchema, source }); expect(Object.keys(result)).to.deep.equal(['data']); return result.data; diff --git a/src/__tests__/starWarsValidation-test.js b/src/__tests__/starWarsValidation-test.js index e746b60688..33019338e6 100644 --- a/src/__tests__/starWarsValidation-test.js +++ b/src/__tests__/starWarsValidation-test.js @@ -13,7 +13,7 @@ import { StarWarsSchema } from './starWarsSchema'; /** * Helper function to test a query and the expected response. */ -function validationErrors(query) { +function validationErrors(query: string) { const source = new Source(query, 'StarWars.graphql'); const ast = parse(source); return validate(StarWarsSchema, ast); diff --git a/src/execution/__tests__/abstract-promise-test.js b/src/execution/__tests__/abstract-promise-test.js index 0c79b54ff2..3831a6e076 100644 --- a/src/execution/__tests__/abstract-promise-test.js +++ b/src/execution/__tests__/abstract-promise-test.js @@ -20,7 +20,7 @@ class Dog { name: string; woofs: boolean; - constructor(name, woofs) { + constructor(name: string, woofs: boolean) { this.name = name; this.woofs = woofs; } @@ -30,7 +30,7 @@ class Cat { name: string; meows: boolean; - constructor(name, meows) { + constructor(name: string, meows: boolean) { this.name = name; this.meows = meows; } @@ -39,7 +39,7 @@ class Cat { class Human { name: string; - constructor(name) { + constructor(name: string) { this.name = name; } } diff --git a/src/execution/__tests__/abstract-test.js b/src/execution/__tests__/abstract-test.js index 3e42ead8b5..2eae2f679f 100644 --- a/src/execution/__tests__/abstract-test.js +++ b/src/execution/__tests__/abstract-test.js @@ -20,7 +20,7 @@ class Dog { name: string; woofs: boolean; - constructor(name, woofs) { + constructor(name: string, woofs: boolean) { this.name = name; this.woofs = woofs; } @@ -30,7 +30,7 @@ class Cat { name: string; meows: boolean; - constructor(name, meows) { + constructor(name: string, meows: boolean) { this.name = name; this.meows = meows; } @@ -39,7 +39,7 @@ class Cat { class Human { name: string; - constructor(name) { + constructor(name: string) { this.name = name; } } diff --git a/src/execution/__tests__/directives-test.js b/src/execution/__tests__/directives-test.js index 810cd51b68..1f1f148d8b 100644 --- a/src/execution/__tests__/directives-test.js +++ b/src/execution/__tests__/directives-test.js @@ -30,7 +30,7 @@ const rootValue = { }, }; -function executeTestQuery(query) { +function executeTestQuery(query: string) { const document = parse(query); return execute({ schema, document, rootValue }); } diff --git a/src/execution/__tests__/executor-test.js b/src/execution/__tests__/executor-test.js index ef5d02076e..affaea0c1e 100644 --- a/src/execution/__tests__/executor-test.js +++ b/src/execution/__tests__/executor-test.js @@ -103,7 +103,7 @@ describe('Execute: Handles basic execution tasks', () => { e: () => 'Egg', f: 'Fish', // Called only by DataType::pic static resolver - pic: (size) => 'Pic of size: ' + size, + pic: (size: number) => 'Pic of size: ' + size, deep: () => deepData, promise: promiseData, }; @@ -1006,7 +1006,7 @@ describe('Execute: Handles basic execution tasks', () => { class Special { value: string; - constructor(value) { + constructor(value: string) { this.value = value; } } @@ -1014,7 +1014,7 @@ describe('Execute: Handles basic execution tasks', () => { class NotSpecial { value: string; - constructor(value) { + constructor(value: string) { this.value = value; } } @@ -1131,12 +1131,15 @@ describe('Execute: Handles basic execution tasks', () => { }); const document = parse('{ foo }'); - function fieldResolver(_source, _args, _context, info) { - // For the purposes of test, just return the name of the field! - return info.fieldName; - } + const result = execute({ + schema, + document, + fieldResolver(_source, _args, _context, info) { + // For the purposes of test, just return the name of the field! + return info.fieldName; + }, + }); - const result = execute({ schema, document, fieldResolver }); expect(result).to.deep.equal({ data: { foo: 'foo' } }); }); @@ -1168,16 +1171,20 @@ describe('Execute: Handles basic execution tasks', () => { types: [fooObject], }); - let possibleTypes; - function typeResolver(_source, _context, info, abstractType) { - // Resolver should be able to figure out all possible types on its own - possibleTypes = info.schema.getPossibleTypes(abstractType); + const rootValue = { foo: { bar: 'bar' } }; - return 'FooObject'; - } + let possibleTypes; + const result = execute({ + schema, + document, + rootValue, + typeResolver(_source, _context, info, abstractType) { + // Resolver should be able to figure out all possible types on its own + possibleTypes = info.schema.getPossibleTypes(abstractType); - const rootValue = { foo: { bar: 'bar' } }; - const result = execute({ schema, document, rootValue, typeResolver }); + return 'FooObject'; + }, + }); expect(result).to.deep.equal({ data: { foo: { bar: 'bar' } } }); expect(possibleTypes).to.deep.equal([fooObject]); diff --git a/src/execution/__tests__/lists-test.js b/src/execution/__tests__/lists-test.js index c665c9f9ec..4c07164658 100644 --- a/src/execution/__tests__/lists-test.js +++ b/src/execution/__tests__/lists-test.js @@ -11,6 +11,7 @@ import { GraphQLList, GraphQLNonNull, GraphQLObjectType, + type GraphQLOutputType, } from '../../type/definition'; import { execute } from '../execute'; @@ -27,7 +28,7 @@ const rejected = Promise.reject.bind(Promise); * contains a rejection, testData should be a function that returns that * rejection so as not to trigger the "unhandled rejection" error watcher. */ -function check(testType, testData, expected) { +function check(testType: GraphQLOutputType, testData: mixed, expected: mixed) { return async () => { const data = { test: testData }; @@ -71,7 +72,7 @@ describe('Execute: Accepts any iterable as list value', () => { }), ); - function getArgs(...args) { + function getArgs(...args: Array) { return args; } diff --git a/src/execution/__tests__/nonnull-test.js b/src/execution/__tests__/nonnull-test.js index 3312a1b275..2a04b14337 100644 --- a/src/execution/__tests__/nonnull-test.js +++ b/src/execution/__tests__/nonnull-test.js @@ -3,6 +3,8 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; +import invariant from '../../jsutils/invariant'; + import { parse } from '../../language/parser'; import { GraphQLSchema } from '../../type/schema'; @@ -11,7 +13,7 @@ import { GraphQLNonNull, GraphQLObjectType } from '../../type/definition'; import { buildSchema } from '../../utilities/buildASTSchema'; -import { execute } from '../execute'; +import { execute, type ExecutionResult } from '../execute'; const syncError = new Error('sync'); const syncNonNullError = new Error('syncNonNull'); @@ -105,24 +107,31 @@ const schema = buildSchema(` } `); -function executeQuery(query, rootValue) { +function executeQuery( + query: string, + rootValue: mixed, +): ExecutionResult | Promise { return execute({ schema, document: parse(query), rootValue }); } +function patch(str: string): string { + return str + .replace(/\bsync\b/g, 'promise') + .replace(/\bsyncNonNull\b/g, 'promiseNonNull'); +} + // avoids also doing any nests -function patch(data) { - return JSON.parse( - JSON.stringify(data) - .replace(/\bsync\b/g, 'promise') - .replace(/\bsyncNonNull\b/g, 'promiseNonNull'), - ); +function patchData(data: ExecutionResult): ExecutionResult { + return JSON.parse(patch(JSON.stringify(data))); } -async function executeSyncAndAsync(query, rootValue) { +async function executeSyncAndAsync(query: string, rootValue: mixed) { const syncResult = await executeQuery(query, rootValue); + invariant(!(syncResult instanceof Promise)); + const asyncResult = await executeQuery(patch(query), rootValue); - expect(asyncResult).to.deep.equal(patch(syncResult)); + expect(asyncResult).to.deep.equal(patchData(syncResult)); return syncResult; } diff --git a/src/execution/__tests__/resolve-test.js b/src/execution/__tests__/resolve-test.js index cd1f13b8fb..f210531d9d 100644 --- a/src/execution/__tests__/resolve-test.js +++ b/src/execution/__tests__/resolve-test.js @@ -4,13 +4,16 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; import { GraphQLSchema } from '../../type/schema'; -import { GraphQLObjectType } from '../../type/definition'; import { GraphQLInt, GraphQLString } from '../../type/scalars'; +import { + GraphQLObjectType, + type GraphQLFieldConfig, +} from '../../type/definition'; import { graphqlSync } from '../../graphql'; describe('Execute: resolve function', () => { - function testSchema(testField) { + function testSchema(testField: GraphQLFieldConfig) { return new GraphQLSchema({ query: new GraphQLObjectType({ name: 'Query', @@ -59,12 +62,12 @@ describe('Execute: resolve function', () => { class Adder { _num: number; - constructor(num) { + constructor(num: number) { this._num = num; } - test({ addend1 }, context) { - return this._num + addend1 + context.addend2; + test(args: {| addend1: number |}, context: {| addend2: number |}) { + return this._num + args.addend1 + context.addend2; } } const rootValue = new Adder(700); @@ -94,7 +97,7 @@ describe('Execute: resolve function', () => { resolve: (source, args) => JSON.stringify([source, args]), }); - function execute(source, rootValue, contextValue) { + function execute(source: string, rootValue?: mixed, contextValue?: mixed) { return graphqlSync({ schema, source, rootValue, contextValue }); } diff --git a/src/execution/__tests__/schema-test.js b/src/execution/__tests__/schema-test.js index 7c8115ce9c..866e6b4299 100644 --- a/src/execution/__tests__/schema-test.js +++ b/src/execution/__tests__/schema-test.js @@ -87,14 +87,14 @@ describe('Execute: Handles execution with a complex schema', () => { query: BlogQuery, }); - function article(id) { + function article(id: number) { return { id, isPublished: true, author: { id: 123, name: 'John Smith', - pic: (width, height) => getPic(123, width, height), + pic: (width: number, height: number) => getPic(123, width, height), recentArticle: () => article(1), }, title: 'My Article ' + id, @@ -104,7 +104,7 @@ describe('Execute: Handles execution with a complex schema', () => { }; } - function getPic(uid, width, height) { + function getPic(uid: number, width: number, height: number) { return { url: `cdn://${uid}`, width: `${width}`, diff --git a/src/execution/__tests__/union-interface-test.js b/src/execution/__tests__/union-interface-test.js index 602385edaf..43941e5b0e 100644 --- a/src/execution/__tests__/union-interface-test.js +++ b/src/execution/__tests__/union-interface-test.js @@ -21,11 +21,11 @@ import { execute } from '../execute'; class Dog { name: string; barks: boolean; - mother: ?Dog; - father: ?Dog; + mother: Dog | null; + father: Dog | null; progeny: Array; - constructor(name, barks) { + constructor(name: string, barks: boolean) { this.name = name; this.barks = barks; this.mother = null;