diff --git a/packages/gatsby-source-graphql/src/batching/__tests__/dataloader-link.ts b/packages/gatsby-source-graphql/src/batching/__tests__/dataloader-link.js similarity index 89% rename from packages/gatsby-source-graphql/src/batching/__tests__/dataloader-link.ts rename to packages/gatsby-source-graphql/src/batching/__tests__/dataloader-link.js index fa025e36c09fb..a60879a366ee4 100644 --- a/packages/gatsby-source-graphql/src/batching/__tests__/dataloader-link.ts +++ b/packages/gatsby-source-graphql/src/batching/__tests__/dataloader-link.js @@ -1,14 +1,13 @@ -import { parse } from "graphql" -import { execute } from "apollo-link" -import { createDataloaderLink } from "../dataloader-link" +const { parse } = require(`graphql`) +const { execute } = require(`apollo-link`) +const { createDataloaderLink } = require(`../dataloader-link`) const sampleQuery = parse(`{ foo }`) const expectedSampleQueryResult = { data: { foo: `bar` } } -// eslint-disable-next-line @typescript-eslint/camelcase const fetchResult = { data: { gatsby0_foo: `bar` } } -const makeFetch = (expectedResult: any = fetchResult): jest.Mock => +const makeFetch = (expectedResult = fetchResult) => jest.fn(() => Promise.resolve({ json: () => Promise.resolve(expectedResult), @@ -23,7 +22,7 @@ describe(`createDataloaderLink`, () => { }) const observable = execute(link, { query: sampleQuery }) observable.subscribe({ - next: (result: any) => { + next: result => { expect(result).toEqual(expectedSampleQueryResult) done() }, diff --git a/packages/gatsby-source-graphql/src/batching/__tests__/merge-queries.ts b/packages/gatsby-source-graphql/src/batching/__tests__/merge-queries.js similarity index 95% rename from packages/gatsby-source-graphql/src/batching/__tests__/merge-queries.ts rename to packages/gatsby-source-graphql/src/batching/__tests__/merge-queries.js index bcf6654c849f0..faa52143c0ebf 100644 --- a/packages/gatsby-source-graphql/src/batching/__tests__/merge-queries.ts +++ b/packages/gatsby-source-graphql/src/batching/__tests__/merge-queries.js @@ -1,5 +1,5 @@ -import { print, parse } from "graphql" -import { IQuery, merge, resolveResult } from "../merge-queries" +const { print, parse } = require(`graphql`) +const { merge, resolveResult } = require(`../merge-queries`) describe(`Query merging`, () => { it(`merges simple queries`, () => { @@ -213,7 +213,7 @@ describe(`Resolving merged query results`, () => { }) it(`throws on unexpected results`, () => { - const shouldThrow = (): void => { + const shouldThrow = () => { resolveResult({ data: { gatsby0_foo: `foo`, @@ -225,10 +225,8 @@ describe(`Resolving merged query results`, () => { }) }) -type QueryFixture = [string, object] - -function fromFixtures(fixtures: QueryFixture[]): IQuery[] { - return fixtures.map(([query, variables]: QueryFixture) => { +function fromFixtures(fixtures) { + return fixtures.map(([query, variables]) => { return { query: parse(query), variables, diff --git a/packages/gatsby-source-graphql/src/batching/dataloader-link.ts b/packages/gatsby-source-graphql/src/batching/dataloader-link.js similarity index 67% rename from packages/gatsby-source-graphql/src/batching/dataloader-link.ts rename to packages/gatsby-source-graphql/src/batching/dataloader-link.js index 87895e3ace8df..8967befce06ae 100644 --- a/packages/gatsby-source-graphql/src/batching/dataloader-link.ts +++ b/packages/gatsby-source-graphql/src/batching/dataloader-link.js @@ -1,22 +1,14 @@ -import DataLoader from "dataloader" -import { ApolloLink, Observable, Operation, FetchResult } from "apollo-link" -import { print } from "graphql" -import { IQuery, IQueryResult, merge, resolveResult } from "./merge-queries" +const DataLoader = require(`dataloader`) +const { ApolloLink, Observable } = require(`apollo-link`) +const { print } = require(`graphql`) +const { merge, resolveResult } = require(`./merge-queries`) -interface IOptions { - uri: string - fetch: Function - fetchOptions?: object - dataLoaderOptions?: object - headers?: object -} - -export function createDataloaderLink(options: IOptions): ApolloLink { - const load = async (keys: ReadonlyArray): Promise => { +export function createDataloaderLink(options) { + const load = async keys => { const query = merge(keys) - const result: object = await request(query, options) + const result = await request(query, options) if (!isValidGraphQLResult(result)) { - const error: any = new Error( + const error = new Error( `Failed to load query batch:\n${formatErrors(result)}` ) error.name = `GraphQLError` @@ -34,12 +26,12 @@ export function createDataloaderLink(options: IOptions): ApolloLink { const dataloader = new DataLoader(load, { cache: false, maxBatchSize, - batchScheduleFn: (callback): any => setTimeout(callback, 50), + batchScheduleFn: callback => setTimeout(callback, 50), ...options.dataLoaderOptions, }) return new ApolloLink( - (operation: Operation): Observable => + operation => new Observable(observer => { const { query, variables } = operation @@ -61,7 +53,7 @@ export function createDataloaderLink(options: IOptions): ApolloLink { ) } -function formatErrors(result: any): string { +function formatErrors(result) { if (result?.errors?.length > 0) { return result.errors .map(error => { @@ -75,7 +67,7 @@ function formatErrors(result: any): string { return `Unexpected GraphQL result` } -function isValidGraphQLResult(response): response is IQueryResult { +function isValidGraphQLResult(response) { return ( response && response.data && @@ -83,7 +75,7 @@ function isValidGraphQLResult(response): response is IQueryResult { ) } -async function request(query: IQuery, options: IOptions): Promise { +async function request(query, options) { const { uri, headers = {}, fetch, fetchOptions } = options const body = JSON.stringify({ diff --git a/packages/gatsby-source-graphql/src/batching/merge-queries.ts b/packages/gatsby-source-graphql/src/batching/merge-queries.js similarity index 68% rename from packages/gatsby-source-graphql/src/batching/merge-queries.ts rename to packages/gatsby-source-graphql/src/batching/merge-queries.js index 3f1229b836792..85474b9cbf2e1 100644 --- a/packages/gatsby-source-graphql/src/batching/merge-queries.ts +++ b/packages/gatsby-source-graphql/src/batching/merge-queries.js @@ -1,35 +1,9 @@ -import { - visit, - visitInParallel, - Kind, - DocumentNode, - VariableNode, - SelectionNode, - FragmentSpreadNode, - FragmentDefinitionNode, - InlineFragmentNode, - FieldNode, - NameNode, - OperationDefinitionNode, - Visitor, - ASTKindToNode, - VariableDefinitionNode, - DirectiveNode, -} from "graphql" -import _ from "lodash" - -export interface IQuery { - query: DocumentNode - variables: object -} - -export interface IQueryResult { - data: object -} +const { visit, visitInParallel, Kind } = require(`graphql`) +const _ = require(`lodash`) const Prefix = { - create: (index: number): string => `gatsby${index}_`, - parseKey: (prefixedKey: string): { index: number; originalKey: string } => { + create: index => `gatsby${index}_`, + parseKey: prefixedKey => { const match = /^gatsby([\d]+)_(.*)$/.exec(prefixedKey) if (!match || match.length !== 3 || isNaN(Number(match[1])) || !match[2]) { throw new Error(`Unexpected data key: ${prefixedKey}`) @@ -74,13 +48,13 @@ const Prefix = { * } * fragment FooQuery on Query { baz } */ -export function merge(queries: ReadonlyArray): IQuery { - const mergedVariables: object = {} - const mergedVariableDefinitions: VariableDefinitionNode[] = [] - const mergedSelections: SelectionNode[] = [] - const mergedFragmentMap: Map = new Map() +export function merge(queries) { + const mergedVariables = {} + const mergedVariableDefinitions = [] + const mergedSelections = [] + const mergedFragmentMap = new Map() - queries.forEach((query: IQuery, index: number) => { + queries.forEach((query, index) => { const prefixedQuery = prefixQueryParts(Prefix.create(index), query) prefixedQuery.query.definitions.forEach(def => { @@ -99,7 +73,7 @@ export function merge(queries: ReadonlyArray): IQuery { Object.assign(mergedVariables, prefixedQuery.variables) }) - const mergedQueryDefinition: OperationDefinitionNode = { + const mergedQueryDefinition = { kind: Kind.OPERATION_DEFINITION, operation: `query`, variableDefinitions: mergedVariableDefinitions, @@ -121,72 +95,60 @@ export function merge(queries: ReadonlyArray): IQuery { /** * Split and transform result of the query produced by the `merge` function */ -export function resolveResult(mergedQueryResult: IQueryResult): IQueryResult[] { +export function resolveResult(mergedQueryResult) { const data = mergedQueryResult.data - return Object.keys(data).reduce( - (acc: IQueryResult[], prefixedKey: string): IQueryResult[] => { - const { index, originalKey } = Prefix.parseKey(prefixedKey) - if (!acc[index]) acc[index] = { data: {} } - acc[index].data[originalKey] = data[prefixedKey] - return acc - }, - [] - ) + return Object.keys(data).reduce((acc, prefixedKey) => { + const { index, originalKey } = Prefix.parseKey(prefixedKey) + if (!acc[index]) acc[index] = { data: {} } + acc[index].data[originalKey] = data[prefixedKey] + return acc + }, []) } const Visitors = { - detectFragmentsWithVariables: ( - fragmentsWithVariables: Set - ): Visitor => { + detectFragmentsWithVariables: fragmentsWithVariables => { let currentFragmentName return { [Kind.FRAGMENT_DEFINITION]: { - enter: (def: FragmentDefinitionNode): void => { + enter: def => { currentFragmentName = def.name.value }, - leave: (): void => { + leave: () => { currentFragmentName = null }, }, - [Kind.VARIABLE]: (): void => { + [Kind.VARIABLE]: () => { if (currentFragmentName) { fragmentsWithVariables.add(currentFragmentName) } }, } }, - prefixVariables: (prefix: string): Visitor => { + prefixVariables: prefix => { return { - [Kind.VARIABLE]: (variable: VariableNode): VariableNode => - prefixNodeName(variable, prefix), + [Kind.VARIABLE]: variable => prefixNodeName(variable, prefix), } }, - prefixFragmentNames: ( - prefix: string, - fragmentNames: Set - ): Visitor => { + prefixFragmentNames: (prefix, fragmentNames) => { return { - [Kind.FRAGMENT_DEFINITION]: ( - def: FragmentDefinitionNode - ): FragmentDefinitionNode | void => + [Kind.FRAGMENT_DEFINITION]: def => fragmentNames.has(def.name.value) ? prefixNodeName(def, prefix) : def, - - [Kind.FRAGMENT_SPREAD]: (def: FragmentSpreadNode): FragmentSpreadNode => + [Kind.FRAGMENT_SPREAD]: def => fragmentNames.has(def.name.value) ? prefixNodeName(def, prefix) : def, } }, } -function prefixQueryParts(prefix: string, query: IQuery): IQuery { - let document: DocumentNode = aliasTopLevelFields(prefix, query.query) +function prefixQueryParts(prefix, query) { + let document = aliasTopLevelFields(prefix, query.query) const variableNames = Object.keys(query.variables) if (variableNames.length === 0) { return { ...query, query: document } } - const fragmentsWithVariables: Set = new Set() + const fragmentsWithVariables = new Set() document = visit( document, @@ -211,7 +173,7 @@ function prefixQueryParts(prefix: string, query: IQuery): IQuery { [Kind.INLINE_FRAGMENT]: [`selectionSet`], [Kind.FIELD]: [`selectionSet`], [Kind.SELECTION_SET]: [`selections`], - } as any + } ) } @@ -231,9 +193,9 @@ function prefixQueryParts(prefix: string, query: IQuery): IQuery { * * @see aliasFieldsInSelection for implementation details */ -function aliasTopLevelFields(prefix: string, doc: DocumentNode): DocumentNode { +function aliasTopLevelFields(prefix, doc) { const transformer = { - [Kind.OPERATION_DEFINITION]: (def): OperationDefinitionNode => { + [Kind.OPERATION_DEFINITION]: def => { const { selections } = def.selectionSet return { ...def, @@ -244,7 +206,7 @@ function aliasTopLevelFields(prefix: string, doc: DocumentNode): DocumentNode { } }, } - return visit(doc, transformer, { [Kind.DOCUMENT]: [`definitions`] } as any) + return visit(doc, transformer, { [Kind.DOCUMENT]: [`definitions`] }) } /** @@ -267,26 +229,18 @@ function aliasTopLevelFields(prefix: string, doc: DocumentNode): DocumentNode { * ... on Query { gatsby1_bar: bar } * } */ -function aliasFieldsInSelection( - prefix: string, - selections: ReadonlyArray, - document: DocumentNode -): SelectionNode[] { - return _.flatMap(selections, (selection: SelectionNode): SelectionNode[] => { +function aliasFieldsInSelection(prefix, selections, document) { + return _.flatMap(selections, selection => { switch (selection.kind) { case Kind.INLINE_FRAGMENT: return [aliasFieldsInInlineFragment(prefix, selection, document)] - case Kind.FRAGMENT_SPREAD: { const inlineFragment = inlineFragmentSpread(selection, document) return [ addSkipDirective(selection), aliasFieldsInInlineFragment(prefix, inlineFragment, document), - // Keep original spread in selection with @skip(if: true) - // otherwise if this was a single fragment usage the query will fail validation ] } - case Kind.FIELD: default: return [aliasField(selection, prefix)] @@ -294,12 +248,8 @@ function aliasFieldsInSelection( }) } -interface INodeWithDirectives { - readonly directives?: ReadonlyArray -} - -function addSkipDirective(node: T): T { - const skipDirective: DirectiveNode = { +function addSkipDirective(node) { + const skipDirective = { kind: Kind.DIRECTIVE, name: { kind: Kind.NAME, value: `skip` }, arguments: [ @@ -325,11 +275,7 @@ function addSkipDirective(node: T): T { * To * ... on Query { gatsby1_foo: foo, ... on Query { gatsby1_bar: foo } } */ -function aliasFieldsInInlineFragment( - prefix: string, - fragment: InlineFragmentNode, - document: DocumentNode -): InlineFragmentNode { +function aliasFieldsInInlineFragment(prefix, fragment, document) { const { selections } = fragment.selectionSet return { ...fragment, @@ -350,10 +296,7 @@ function aliasFieldsInInlineFragment( * Transforms to: * query { ... on Query { bar } } */ -function inlineFragmentSpread( - spread: FragmentSpreadNode, - document: DocumentNode -): InlineFragmentNode { +function inlineFragmentSpread(spread, document) { const fragment = document.definitions.find( def => def.kind === Kind.FRAGMENT_DEFINITION && @@ -362,8 +305,7 @@ function inlineFragmentSpread( if (!fragment) { throw new Error(`Fragment ${spread.name.value} does not exist`) } - const { typeCondition, selectionSet } = fragment as FragmentDefinitionNode - + const { typeCondition, selectionSet } = fragment return { kind: Kind.INLINE_FRAGMENT, typeCondition, @@ -372,10 +314,7 @@ function inlineFragmentSpread( } } -function prefixNodeName( - namedNode: T, - prefix: string -): T { +function prefixNodeName(namedNode, prefix) { return { ...namedNode, name: { @@ -392,7 +331,7 @@ function prefixNodeName( * { foo } -> { gatsby1_foo: foo } * { foo: bar } -> { gatsby1_foo: bar } */ -function aliasField(field: FieldNode, aliasPrefix: string): FieldNode { +function aliasField(field, aliasPrefix) { const aliasNode = field.alias ? field.alias : field.name return { ...field, @@ -403,10 +342,10 @@ function aliasField(field: FieldNode, aliasPrefix: string): FieldNode { } } -function isQueryDefinition(def): def is OperationDefinitionNode { +function isQueryDefinition(def) { return def.kind === Kind.OPERATION_DEFINITION && def.operation === `query` } -function isFragmentDefinition(def): def is FragmentDefinitionNode { +function isFragmentDefinition(def) { return def.kind === Kind.FRAGMENT_DEFINITION }