Last active
April 22, 2022 07:04
-
-
Save jamesone/78cd77df89a1a4e485cc46e5e5ad17ae to your computer and use it in GitHub Desktop.
Extends https://avishwakarma.medium.com/generate-typescript-types-from-graphql-schema-using-apollo-cli-7a19690c3a7 and adds ENUM (which is used in Hasura) conversion support as well as proper NON NULL typescript representation (by removing `?:` optional indicator)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const { exec } = require('child_process'); | |
| const { readFileSync, writeFileSync } = require('fs'); | |
| const { unix } = require('dayjs'); | |
| const fieldMap = { | |
| String: 'string', | |
| Date: 'string', | |
| JSON: 'any', | |
| Boolean: 'boolean', | |
| Int: 'number', | |
| Float: 'number' | |
| } | |
| const outPath = `${__dirname}/graphql.types.ts`; | |
| const exclude = ['__Schema', '__Type', '__Field', '__InputValue', '__EnumValue', '__Directive'] | |
| function init() { | |
| exec('npm run graphql:download:schema', (error) => { | |
| if(error) { | |
| console.log(error); | |
| return; | |
| } | |
| const json = JSON.parse(readFileSync(`${__dirname}/schema.json`, 'utf8')); | |
| // Add you default types if need be | |
| const types = [``]; | |
| function extractFields(name, fields, includeTypeName = false) { | |
| const type = [`export interface ${name} {`, includeTypeName ? ` __typename?: '${name}'` : '']; | |
| fields.forEach(field => { | |
| const isNonNull = field.type.kind === 'NON_NULL'; | |
| let f = [` ${field.name}${isNonNull ? '' : '?'}: `]; | |
| if(field.type.kind === 'LIST') { | |
| if(field.type.ofType.kind === 'SCALAR') { | |
| f.push(`Array<${fieldMap[field.type.ofType.name]}>;`) | |
| } else { | |
| f.push(`Array<${field.type.ofType.name}>;`); | |
| } | |
| } else if(field.type.kind === 'SCALAR'){ | |
| f.push(`${fieldMap[field.type.name]};`) | |
| } else if (field.type.kind === 'NON_NULL') { | |
| f.push(`${fieldMap[field.type.ofType.name]};`) | |
| } else { | |
| f.push(`${field.type.name};`) | |
| } | |
| type.push(f.join("")) | |
| }); | |
| type.push(`}`); | |
| return type.join("\n"); | |
| } | |
| function extractEnum(name, enumValues) { | |
| const type = [`export enum ${name} {`,]; | |
| enumValues.forEach(enumValue => { | |
| let f = [` ${enumValue.name} = "${enumValue.name}", `]; | |
| type.push(f.join("")) | |
| }); | |
| type.push(`}`); | |
| return type.join("\n"); | |
| } | |
| function titleCase(str) { | |
| return str.charAt(0).toUpperCase() + str.substring(1); | |
| } | |
| function extractResult(fields) { | |
| const result = []; | |
| fields.forEach(field => { | |
| const type = [`export interface ${titleCase(field.name)}Result {`]; | |
| if(field.type.kind === 'LIST') { | |
| type.push(` ${field.name}: Array<${field.type.ofType.name}>;`); | |
| } else if(field.type.kind === 'SCALAR'){ | |
| type.push(` ${field.name}: Array<${fieldMap[field.type.name]}>;`); | |
| } else if(field.type.kind === 'OBJECT') { | |
| type.push(` ${field.name}: ${field.type.name};`); | |
| } | |
| type.push("}") | |
| result.push(type.join("\n")); | |
| }) | |
| return result.join("\n\n"); | |
| } | |
| function generateObject(schema) { | |
| if(exclude.includes(schema.name)) { | |
| return; | |
| } | |
| let fields = ''; | |
| if(schema.name === 'Mutation') { | |
| fields = extractResult(schema.fields); | |
| } else if(schema.name === 'Query') { | |
| fields = extractResult(schema.fields); | |
| } else { | |
| fields = extractFields(schema.name, schema.fields); | |
| } | |
| types.push(fields); | |
| } | |
| function generateEnum(schema) { | |
| if(exclude.includes(schema.name)) { | |
| return; | |
| } | |
| const enumStr = extractEnum(schema.name, schema.enumValues); | |
| types.push(enumStr); | |
| } | |
| function generateInputObject(schema) { | |
| if(exclude.includes(schema.name)) { | |
| return; | |
| } | |
| let fields = extractFields(schema.name, schema.inputFields);; | |
| types.push(fields); | |
| } | |
| function generateUnion(schema) { | |
| const pt = []; | |
| schema.possibleTypes.forEach(field => { | |
| if(field.kind === 'LIST') { | |
| if(field.ofType.kind === 'SCALAR') { | |
| pt.push(`Array<${fieldMap[field.ofType.name]}>`) | |
| } else { | |
| pt.push(`Array<${field.ofType.name}>`); | |
| } | |
| } else if(field.kind === 'SCALAR'){ | |
| pt.push(`${fieldMap[field.name]}`) | |
| } else { | |
| pt.push(`${field.name}`) | |
| } | |
| }) | |
| types.push(`export type ${schema.name} = ${pt.join(' | ')};`) | |
| } | |
| json.__schema.types.forEach(schema => { | |
| if(schema.kind === 'UNION') { | |
| generateUnion(schema); | |
| } | |
| if(schema.kind === 'OBJECT') { | |
| generateObject(schema); | |
| } | |
| if(schema.kind === 'ENUM') { | |
| generateEnum(schema); | |
| } | |
| if(schema.kind === 'INPUT_OBJECT') { | |
| generateInputObject(schema); | |
| } | |
| }); | |
| writeFileSync(outPath, types.join("\n\n")); | |
| console.log(`File created: ${outPath}`); | |
| }); | |
| } | |
| init(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment