UNPKG

graphql-request

Version:

Minimal GraphQL client supporting Node and browsers for scripts or simple apps.

154 lines 6.89 kB
import { isEnumType, isInputObjectType, isInterfaceType, isListType, isNamedType, isObjectType, isScalarType, isUnionType, } from 'graphql'; import { hasMutation, hasQuery, hasSubscription, unwrapToNamed, unwrapToNonNull } from '../../../lib/graphql.js'; import { createCodeGenerator } from '../createCodeGenerator.js'; import { moduleNameScalar } from './Scalar.js'; export const { generate: generateRuntimeSchema, moduleName: moduleNameSchemaRuntime } = createCodeGenerator(`SchemaRuntime`, (config) => { const code = []; code.push(`/* eslint-disable */\n`); code.push(` import * as $ from '${config.libraryPaths.schema}' import * as $Scalar from './${moduleNameScalar}.js' `); code.push(config.typeMapByKind.GraphQLEnumType.map(type => enum$(config, type)).join(`\n`), config.typeMapByKind.GraphQLInputObjectType.map(type => inputObject(config, type)).join(`\n`), config.typeMapByKind.GraphQLObjectType.map(type => object(config, type)).join(`\n`), config.typeMapByKind.GraphQLUnionType.map(type => union(config, type)).join(`\n`), config.typeMapByKind.GraphQLInterfaceType.map(type => interface$(config, type)).join(`\n`), config.typeMapByKind.GraphQLRootType.map(type => object(config, type)).join(`\n`)); code.push(index(config)); return code.join(`\n`); }); const index = (config) => { // todo input objects for decode/encode input object fields return ` export const $Index = { name: "${config.name}" as const, Root: { Query ${hasQuery(config.typeMapByKind) ? `` : `:null`} , Mutation ${hasMutation(config.typeMapByKind) ? `` : `:null`}, Subscription ${hasSubscription(config.typeMapByKind) ? `` : `:null`} }, objects: { ${config.typeMapByKind.GraphQLObjectType.map(type => type.name).join(`,\n`)} }, unions: { ${config.typeMapByKind.GraphQLUnionType.map(type => type.name).join(`,\n`)} }, interfaces: { ${config.typeMapByKind.GraphQLInterfaceType.map(type => type.name).join(`,\n`)} }, error: { objects: { ${config.error.objects.map(type => type.name).join(`,\n`)} }, objectsTypename: { ${config.error.objects.map(_ => `${_.name}: { __typename: "${_.name}" }`).join(`,\n`)} }, rootResultFields: { ${Object.entries(config.rootTypes).map(([rootTypeName, rootType]) => { if (!rootType) return `${rootTypeName}: {}`; const resultFields = Object.values(rootType.getFields()).filter((field) => { const type = unwrapToNamed(field.type); return isUnionType(type) && type.getTypes().some(_ => config.error.objects.some(__ => __.name === _.name)); }).map((field) => field.name); return `${rootType.name}: {\n${resultFields.map(_ => `${_}: "${_}" as const`).join(`,\n`)} }`; }).join(`,\n`)} } } } `; }; const union = (_config, type) => { // todo probably need thunks here const members = type.getTypes().map(t => t.name).join(`, `); return ` // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. export const ${type.name} = $.Union(\`${type.name}\`, [${members}])\n`; }; const interface$ = (config, type) => { // todo probably need thunks here const implementors = config.typeMapByKind.GraphQLObjectType.filter(_ => _.getInterfaces().filter(_ => _.name === type.name).length > 0).map(_ => _.name).join(`,`); const fields = Object.values(type.getFields()).map((field) => { return `${field.name}: ${outputField(config, field)}`; }).join(`,\n`); return `export const ${type.name} = $.Interface(\`${type.name}\`, {${fields}}, [${implementors}])`; }; const enum$ = (_config, type) => { const members = type.getValues().map((value) => { return `\`${value.name}\``; }).join(`, `); return `export const ${type.name} = $.Enum(\`${type.name}\`, [${members}])`; }; const object = (config, type) => { const fields = Object.values(type.getFields()).map((field) => { return `${field.name}: ${outputField(config, field)}`; }).join(`,\n`); return ` // @ts-ignore - circular types cannot infer. Ignore in case there are any. This comment is always added, it does not indicate if this particular type could infer or not. export const ${type.name} = $.Object$(\`${type.name}\`, { ${fields} }) `; }; const inputObject = (config, type) => { const fields = Object.values(type.getFields()).map((field) => `${field.name}: ${inputField(config, field)}`).join(`,\n`); return ` export const ${type.name} = $.InputObject(\`${type.name}\`, { ${fields} }) `; }; unwrapToNamed; const inputField = (config, field) => { const type = buildType(`input`, config, field.type); const isNeedThunk = isInputObjectType(unwrapToNamed(field.type)); return `$.Input.field(${isNeedThunk ? `() => ${type}` : type})`; }; const outputField = (config, field) => { const type = buildType(`output`, config, field.type); return field.args.length > 0 ? `$.field(${type}, ${renderArgs(config, field.args)})` : `$.field(${type})`; }; const renderArgs = (config, args) => { return `$.Args({${args.map(arg => renderArg(config, arg)).join(`, `)}})`; }; const renderArg = (config, arg) => { const type = buildType(`input`, config, arg.type); return `${arg.name}: ${type}`; }; const scalar = (_config, type) => { return `$Scalar.${type.name}`; }; const dispatchNamedType = (config, type) => { if (isScalarType(type)) return scalar(config, type); if (isEnumType(type)) return type.name; if (isObjectType(type)) return thunk(type.name); if (isInterfaceType(type)) return thunk(type.name); if (isUnionType(type)) return thunk(type.name); if (isInputObjectType(type)) return type.name; throw new Error(`Unhandled type: ${String(type)}`); }; const thunk = (code) => `() => ${code}`; const buildType = (direction, config, node) => { const ns = direction === `input` ? `Input` : `Output`; const { ofType: nodeInner, nullable } = unwrapToNonNull(node); if (isNamedType(nodeInner)) { const namedTypeReference = dispatchNamedType(config, nodeInner); const namedTypeCode = namedTypeReference; return nullable ? `$.${ns}.Nullable(${namedTypeCode})` : namedTypeCode; } if (isListType(nodeInner)) { const fieldType = `$.${ns}.List(${buildType(direction, config, nodeInner.ofType)})`; return nullable ? `$.${ns}.Nullable(${fieldType})` : fieldType; } throw new Error(`Unhandled type: ${String(node)}`); }; //# sourceMappingURL=SchemaRuntime.js.map