diff --git a/packages/ensjs/src/GqlManager.test.ts b/packages/ensjs/src/GqlManager.test.ts index 730d1b39..0dc68bf6 100644 --- a/packages/ensjs/src/GqlManager.test.ts +++ b/packages/ensjs/src/GqlManager.test.ts @@ -1,7 +1,7 @@ +import { parse, print, visit } from 'graphql' import traverse from 'traverse' -import { visit, parse } from 'graphql' -import { requestMiddleware, responseMiddleware, enter } from './GqlManager' +import { requestMiddleware, responseMiddleware } from './GqlManager' import { namehash } from './utils/normalise' describe('GqlManager', () => { @@ -153,8 +153,9 @@ query getNames($id: ID!, $expiryDate: Int) { describe('requestMiddleware', () => { it('should add id to a SelectionSet if name is present and id is not', () => { - const result = requestMiddleware(visit, parse)(mockRequest) - expect(result.body.includes('id')).toBe(true) + const result = requestMiddleware(visit, parse, print)(mockRequest) + const body = result.body as string + expect(body.match(/domain.*id.*id.*domains.*id.*id/)?.length).toBe(1) }) }) describe('responseMiddleware', () => { diff --git a/packages/ensjs/src/GqlManager.ts b/packages/ensjs/src/GqlManager.ts index a897c716..256ba595 100644 --- a/packages/ensjs/src/GqlManager.ts +++ b/packages/ensjs/src/GqlManager.ts @@ -1,10 +1,17 @@ -// @ts-nocheck +import type { + Kind, + parse as Parse, + print as Print, + SelectionSetNode, + visit as Visit, +} from 'graphql' +import type Traverse from 'traverse' import { namehash } from './utils/normalise' const generateSelection = (selection: any) => ({ - kind: 'Field', + kind: 'Field' as Kind.FIELD, name: { - kind: 'Name', + kind: 'Name' as Kind.NAME, value: selection, }, arguments: [], @@ -13,47 +20,58 @@ const generateSelection = (selection: any) => ({ selectionSet: undefined, }) -export const enter = (node: any) => { - if (node.kind === 'SelectionSet') { - const id = node.selections.find((x) => x.name && x.name.value === 'id') - const name = node.selections.find((x) => x.name && x.name.value === 'name') +export const enter = (node: SelectionSetNode) => { + let hasName = false + let hasId = false - if (!id && name) { - node.selections = [...node.selections, generateSelection('id')] - return node + for (const selection of node.selections) { + if ('name' in selection) { + if (selection.name.value === 'name') hasName = true + else if (selection.name.value === 'id') hasId = true } } + + if (hasName && !hasId) { + node.selections = [...node.selections, generateSelection('id')] + return node + } } -export const requestMiddleware = (visit, parse) => (request: any) => { - const requestBody = JSON.parse(request.body) - const rawQuery = requestBody.query - const parsedQuery = parse(rawQuery) - const updatedQuery = visit(parsedQuery, { enter }) - const updatedBody = { ...requestBody, query: updatedQuery.loc.source.body } +export const requestMiddleware = + (visit: typeof Visit, parse: typeof Parse, print: typeof Print) => + (request: any) => { + const requestBody = JSON.parse(request.body) + const rawQuery = requestBody.query + const parsedQuery = parse(rawQuery) + const updatedQuery = visit(parsedQuery, { + SelectionSet: { + enter, + }, + }) - return { - ...request, - body: JSON.stringify(updatedBody), + return { + ...request, + body: JSON.stringify({ ...requestBody, query: print(updatedQuery) }), + } } -} -export const responseMiddleware = (traverse) => (response: any) => { - traverse(response).forEach(function (responseItem: any) { - if (responseItem instanceof Object && responseItem.name) { - //Name already in hashed form - if (responseItem.name && responseItem.name.includes('[')) { - return - } +export const responseMiddleware = + (traverse: typeof Traverse) => (response: any) => { + traverse(response).forEach(function (responseItem: any) { + if (responseItem instanceof Object && responseItem.name) { + //Name already in hashed form + if (responseItem.name && responseItem.name.includes('[')) { + return + } - const hashedName = namehash(responseItem.name) - if (responseItem.id !== hashedName) { - this.update({ ...responseItem, name: hashedName, invalidName: true }) + const hashedName = namehash(responseItem.name) + if (responseItem.id !== hashedName) { + this.update({ ...responseItem, name: hashedName, invalidName: true }) + } } - } - }) - return response -} + }) + return response + } export default class GqlManager { public gql: any = () => null @@ -61,14 +79,14 @@ export default class GqlManager { public setUrl = async (url: string | null) => { if (url) { - const [imported, traverse, { visit, parse }] = await Promise.all([ + const [imported, traverse, { visit, parse, print }] = await Promise.all([ import('graphql-request'), import('traverse'), import('graphql/language'), ]) this.client = new imported.GraphQLClient(url, { - requestMiddleware: requestMiddleware(visit, parse), + requestMiddleware: requestMiddleware(visit, parse, print), responseMiddleware: responseMiddleware(traverse.default), }) this.gql = imported.gql