Skip to content

Instantly share code, notes, and snippets.

@jamesone
Last active April 22, 2022 07:04
Show Gist options
  • Select an option

  • Save jamesone/78cd77df89a1a4e485cc46e5e5ad17ae to your computer and use it in GitHub Desktop.

Select an option

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)
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