From f0b488e6b65d54d07889261451c7343134ce5ca1 Mon Sep 17 00:00:00 2001 From: Daniel Cousens Date: Wed, 24 Aug 2022 12:37:58 +1000 Subject: [PATCH] rewrite schema type printer --- packages/core/src/lib/schema-type-printer.tsx | 177 +++++++++++------- 1 file changed, 110 insertions(+), 67 deletions(-) diff --git a/packages/core/src/lib/schema-type-printer.tsx b/packages/core/src/lib/schema-type-printer.tsx index 623c25e8901..19549fccbe5 100644 --- a/packages/core/src/lib/schema-type-printer.tsx +++ b/packages/core/src/lib/schema-type-printer.tsx @@ -14,93 +14,136 @@ import { InitialisedList } from './core/types-for-lists'; const introspectionTypesSet = new Set(introspectionTypes); -let printEnumTypeDefinition = (type: GraphQLEnumType) => { - return `export type ${type.name} =\n${type - .getValues() - .map(x => ` | ${JSON.stringify(x.name)}`) - .join('\n')};`; +const printEnumTypeDefinition = (type: GraphQLEnumType) => { + return [ + `export type ${type.name} =`, + type + .getValues() + .map(x => ` | ${JSON.stringify(x.name)}`) + .join('\n') + ';', + ].join('\n'); }; -function printInputTypesFromSchema(schema: GraphQLSchema, scalars: Record) { - let printTypeReferenceWithoutNullable = ( - type: GraphQLNamedType | GraphQLList - ): string => { - if (type instanceof GraphQLList) { - return `ReadonlyArray<${printTypeReference(type.ofType)}> | ${printTypeReference( - type.ofType - )}`; - } - let name = type.name; - if (type instanceof GraphQLScalarType) { - if (scalars[name] === undefined) { - return 'any'; - } - return `Scalars[${JSON.stringify(name)}]`; - } - return name; - }; - let printTypeReference = (type: GraphQLType): string => { - if (type instanceof GraphQLNonNull) { - return printTypeReferenceWithoutNullable(type.ofType); - } - return `${printTypeReferenceWithoutNullable(type)} | null`; - }; - let printInputObjectTypeDefinition = (type: GraphQLInputObjectType) => { - let str = `export type ${type.name} = {\n`; - for (const field of Object.values(type.getFields())) { - str += ` readonly ${field.name}${ - field.type instanceof GraphQLNonNull && field.defaultValue === undefined ? '' : '?' - }: ${printTypeReference(field.type)};\n`; - } +function printTypeReference(type: GraphQLType, scalars: Record): string { + if (type instanceof GraphQLNonNull) { + return printTypeReferenceWithoutNullable(type.ofType, scalars); + } + return `${printTypeReferenceWithoutNullable(type, scalars)} | null`; +} - str += '};'; - return str; - }; - let typeString = 'type Scalars = {\n'; - for (let scalar in scalars) { - typeString += ` readonly ${scalar}: ${scalars[scalar]};\n`; +function printTypeReferenceWithoutNullable( + type: GraphQLNamedType | GraphQLList, + scalars: Record +): string { + if (type instanceof GraphQLList) { + return `ReadonlyArray<${printTypeReference(type.ofType, scalars)}> | ${printTypeReference( + type.ofType, + scalars + )}`; } - typeString += '};'; + + const name = type.name; + if (type instanceof GraphQLScalarType) { + if (scalars[name] === undefined) return 'any'; + return `Scalars[${JSON.stringify(name)}]`; + } + + return name; +} + +function printInputObjectTypeDefinition( + type: GraphQLInputObjectType, + scalars: Record +) { + return [ + `export type ${type.name} = {`, + ...Object.values(type.getFields()).map(field => { + const maybe = field.type instanceof GraphQLNonNull && field.defaultValue === undefined ? '' : '?'; + return ` readonly ${field.name}${maybe}: ${printTypeReference(field.type, scalars)};`; + }), + '};', + ].join('\n'); +} + +function printInputTypesFromSchema(schema: GraphQLSchema, scalars: Record) { + const output = [ + 'type Scalars = {', + ...Object.keys(scalars).map(scalar => ` readonly ${scalar}: ${scalars[scalar]};`), + '};', + ]; + for (const type of Object.values(schema.getTypeMap())) { // We don't want to print TS types for the built-in GraphQL introspection types // they won't be used for anything we want to print here. if (introspectionTypesSet.has(type)) continue; if (type instanceof GraphQLInputObjectType) { - typeString += '\n\n' + printInputObjectTypeDefinition(type); + output.push('', printInputObjectTypeDefinition(type, scalars)); } if (type instanceof GraphQLEnumType) { - typeString += '\n\n' + printEnumTypeDefinition(type); + output.push('', printEnumTypeDefinition(type)); } } - return typeString + '\n\n'; + + return output.join('\n') + '\n\n'; +} + +function printInterimFieldType({ + listKey, + fieldKey, + operation, +}: { + listKey: string; + fieldKey: string; + operation: string; +}) { + return ` ${fieldKey}?: import('.prisma/client').Prisma.${listKey}${operation}Input["${fieldKey}"];`; +} + +function printInterimMultiFieldType({ + listKey, + fieldKey, + operation, + fields, +}: { + listKey: string; + fieldKey: string; + operation: string; + fields: { [key: string]: unknown }; +}) { + return [ + ` ${fieldKey}: {`, + ...Object.keys(fields).map(subFieldKey => { + return ` ${subFieldKey}?: import('.prisma/client').Prisma.${listKey}${operation}Input["${fieldKey}_${subFieldKey}"];`; + }), + ` };`, + ].join('\n'); } function printInterimType( list: L, listKey: string, typename: string, - type: 'Create' | 'Update' + operation: 'Create' | 'Update' ) { - let resolvedTypeString = `type Resolved${typename} = {\n`; - for (let [fieldKey, { dbField }] of Object.entries(list.fields)) { - if (dbField.kind === 'multi') { - resolvedTypeString += - ` ${fieldKey}: {\n` + - Object.keys(dbField.fields) - .map( - key => - ` ${key}?: import('.prisma/client').Prisma.${listKey}${type}Input["${fieldKey}_${key}"];` - ) - .join('\n') + - '\n }\n'; - } else if (dbField.kind === 'none') { - resolvedTypeString += ` ${fieldKey}?: undefined\n`; - } else { - resolvedTypeString += ` ${fieldKey}?: import('.prisma/client').Prisma.${listKey}${type}Input["${fieldKey}"];\n`; - } - } - resolvedTypeString += '};\n\n'; - return resolvedTypeString; + return ( + [ + `type Resolved${typename} = {`, + ...Object.entries(list.fields).map(([fieldKey, { dbField }]) => { + if (dbField.kind === 'none') return ` ${fieldKey}?: undefined\n`; + if (dbField.kind === 'multi') { + return printInterimMultiFieldType({ + listKey, + fieldKey, + operation, + fields: dbField.fields, + }); + } + + return printInterimFieldType({ listKey, fieldKey, operation }); + }), + `};`, + ].join('\n') + '\n' + ); } export function printGeneratedTypes(