Skip to content

Instantly share code, notes, and snippets.

@jnicklas
Created February 11, 2022 09:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jnicklas/4cc2bd560a48bb5ed9b3aa26ff3f94c1 to your computer and use it in GitHub Desktop.
Save jnicklas/4cc2bd560a48bb5ed9b3aa26ff3f94c1 to your computer and use it in GitHub Desktop.
A plugin for GraphQL Codegen which generates yup schemas
// A custom plugin for graphql-codegen, which generate `yup` schemas for input objects
// Loosely based on https://github.com/kazuyaseki/graphql-codegen-yup-schema
module.exports = {
plugin: schema => {
function buildObject(node) {
let fieldsResult = node.fields.map(buildField).filter(Boolean).map((fieldResult) => {
return ` ${fieldResult}`;
}).join(',\n');
return `yup.object().shape({\n${fieldsResult}\n});`
}
function buildField(field) {
return `${field.name.value}: ${buildFieldValue(field.type)}`;
}
function buildFieldValue(type) {
if(type.kind === 'NamedType') {
let name = type.name.value;
let builtInTypes = {
"ID": "yup.string()",
"Int": "yup.number().transform((v) => v ? parseInt(v) : undefined)",
"String": "yup.string()",
"Boolean": "yup.boolean().transform((v) => !![v].flat().find((i) => [true, 'on'].includes(i)))"
};
if(builtInTypes[name]) {
return builtInTypes[name];
} else {
let customType = Object.values(schema._typeMap).map((node) => node.astNode).filter(Boolean).find((node) => node.name.value === name);
if(!customType) {
throw new Error(`unable to find custom type ${name}`);
} else if(customType.kind === 'EnumTypeDefinition') {
let values = customType.values.map((v) => v.name.value);
return `yup.mixed<${customType.name.value}>().oneOf(${JSON.stringify(values)})`;
} else if(customType.kind === 'InputObjectTypeDefinition') {
return `${customType.name.value}SchemaFn()`;
} else {
throw new Error(`unknown custom type kind ${customType.kind}`);
}
}
} else if(type.kind === 'NonNullType') {
return `${buildFieldValue(type.type)}.required()`;
} else if(type.kind === 'ListType') {
return `yup.array().of(${buildFieldValue(type.type)})`;
} else {
throw new Error(`unknown type kind ${type.kind}`);
}
}
let inputFields = Object.values(schema._typeMap).map((node) => node.astNode).filter((node) => {
return node && node.kind === 'InputObjectTypeDefinition';
});
let definitions = inputFields
.map(node => {
return `const ${node.name.value}SchemaFn = () => ${buildObject(node)}`;
})
.join('\n\n');
let exports = inputFields
.map(node => {
return `export const ${node.name.value}Schema = ${node.name.value}SchemaFn()`;
})
.join('\n\n');
return `import * as yup from 'yup'\n\n${definitions}\n\n${exports}`;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment