UNPKG

graphql-codegen-typescript-validation-schema

Version:

GraphQL Code Generator plugin to generate form validation schema from your GraphQL schema

246 lines (245 loc) 13.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ZodV4SchemaVisitor = void 0; const visitor_plugin_common_1 = require("@graphql-codegen/visitor-plugin-common"); const graphql_1 = require("graphql"); const graphql_js_1 = require("../graphql.js"); const schema_visitor_js_1 = require("../schema_visitor.js"); const operation_js_1 = require("../zod/operation.js"); const zod_shared_js_1 = require("../zod_shared.js"); class ZodV4SchemaVisitor extends schema_visitor_js_1.BaseSchemaVisitor { constructor(schema, config) { super(schema, config); } importValidationSchema() { return `import * as z from 'zod'`; } initialEmit() { return (`\n${[ new visitor_plugin_common_1.DeclarationBlock({}) .asKind('type') .withName('Properties<T>') .withContent(['{', ' [K in keyof T]: z.ZodType<T[K], T[K] | undefined>;', '}'].join('\n')) .string, // Unfortunately, zod doesn’t provide non-null defined any schema. // This is a temporary hack until it is fixed. // see: https://github.com/colinhacks/zod/issues/884 new visitor_plugin_common_1.DeclarationBlock({}).asKind('type').withName('definedNonNullAny').withContent('{}').string, new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('const') .withName(`isDefinedNonNullAny`) .withContent(`(v: any): v is definedNonNullAny => v !== undefined && v !== null`) .string, new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('const') .withName(`${zod_shared_js_1.anySchema}`) .withContent(`z.any().refine((v) => isDefinedNonNullAny(v))`) .string, ...this.enumDeclarations, ].join('\n')}`); } buildOperationDefinitions(documents) { const visitor = this.createVisitor('output'); const result = (0, operation_js_1.buildZodOperationSchemas)(this.schema, this.config, documents, visitor); this.importTypes.push(...result.typeNames); return result.blocks; } get InputObjectTypeDefinition() { return { leave: (node) => { const visitor = this.createVisitor('input'); const name = visitor.convertName(node.name.value); this.importTypes.push(name); if ((0, zod_shared_js_1.isOneOfInputObject)(node)) return this.buildOneOfInputFields(node.fields ?? [], visitor, name, node.description?.value); return this.buildInputFields(node.fields ?? [], visitor, name, node.description?.value); }, }; } get InterfaceTypeDefinition() { return { leave: (0, graphql_js_1.InterfaceTypeDefinitionBuilder)(this.config.withObjectType, (node) => { const visitor = this.createVisitor('output'); const name = visitor.convertName(node.name.value); const typeName = visitor.prefixTypeNamespace(name); this.importTypes.push(name); // Building schema for field arguments. const argumentBlocks = this.buildTypeDefinitionArguments(node, visitor); const appendArguments = argumentBlocks ? `\n${argumentBlocks}` : ''; // Building schema for fields. const shape = node.fields?.map(field => (0, zod_shared_js_1.generateFieldZodSchema)(this.config, visitor, field, 2, (0, zod_shared_js_1.schemaDepthVariable)(this.config))).join(',\n'); switch (this.config.validationSchemaExportType) { case 'const': return (new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('const') .withName(`${name}Schema: z.ZodObject<Properties<${typeName}>>`) .withContent((0, zod_shared_js_1.buildObjectExpression)(this.config, shape, node.description?.value)) .string + appendArguments); case 'function': default: return (new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('function') .withName(`${name}Schema(${(0, zod_shared_js_1.schemaDepthParameter)(this.config)}): z.ZodObject<Properties<${typeName}>>`) .withBlock((0, zod_shared_js_1.buildObjectReturn)(this.config, shape, node.description?.value)) .string + appendArguments); } }), }; } get ObjectTypeDefinition() { return { leave: (0, graphql_js_1.ObjectTypeDefinitionBuilder)(this.config.withObjectType, (node) => { const visitor = this.createVisitor('output'); const name = visitor.convertName(node.name.value); const typeName = visitor.prefixTypeNamespace(name); this.importTypes.push(name); // Building schema for field arguments. const argumentBlocks = this.buildTypeDefinitionArguments(node, visitor); const appendArguments = argumentBlocks ? `\n${argumentBlocks}` : ''; // Building schema for fields. const shape = node.fields?.map(field => (0, zod_shared_js_1.generateFieldZodSchema)(this.config, visitor, field, 2, (0, zod_shared_js_1.schemaDepthVariable)(this.config))).join(',\n'); switch (this.config.validationSchemaExportType) { case 'const': return (new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('const') .withName(`${name}Schema: z.ZodObject<Properties<${typeName}>>`) .withContent((0, zod_shared_js_1.buildObjectExpression)(this.config, [(0, visitor_plugin_common_1.indent)(`__typename: z.literal('${node.name.value}').optional(),`, 2), shape].join('\n'), node.description?.value)) .string + appendArguments); case 'function': default: return (new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('function') .withName(`${name}Schema(${(0, zod_shared_js_1.schemaDepthParameter)(this.config)}): z.ZodObject<Properties<${typeName}>>`) .withBlock((0, zod_shared_js_1.buildObjectReturn)(this.config, [(0, visitor_plugin_common_1.indent)(`__typename: z.literal('${node.name.value}').optional(),`, 2), shape].join('\n'), node.description?.value)) .string + appendArguments); } }), }; } get EnumTypeDefinition() { return { leave: (node) => { const visitor = this.createVisitor('both'); const enumname = visitor.convertSchemaName(node.name.value, node.kind); const enumTypeName = visitor.prefixTypeNamespace(enumname); this.importTypes.push(enumname); if (!this.config.enumsAsTypes) this.importValueTypes.push(enumname); const enumValues = node.values?.map(enumOption => enumOption.name.value) ?? []; // hoist enum declarations this.enumDeclarations.push(new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('const') .withName(this.config.enumsAsTypes ? `${enumname}Schema: z.ZodType<${(0, zod_shared_js_1.unionLiterals)(enumValues)}, ${(0, zod_shared_js_1.unionLiterals)(enumValues)}>` : `${enumname}Schema: z.ZodType<${enumTypeName}, ${enumTypeName}>`) .withContent(this.config.enumsAsTypes ? `z.enum([${enumValues.map(enumOption => `'${enumOption}'`).join(', ')}])` : `z.enum(${enumTypeName})`) .string); }, }; } get UnionTypeDefinition() { return { leave: (node) => { if (!node.types || !this.config.withObjectType) return; const visitor = this.createVisitor('output'); const unionName = visitor.convertName(node.name.value); const depthVariable = (0, zod_shared_js_1.schemaDepthVariable)(this.config); const unionElements = node.types.map((t) => { const element = visitor.convertName(t.name.value); const typ = visitor.getType(t.name.value); if (typ?.astNode?.kind === 'EnumTypeDefinition') return `${element}Schema`; switch (this.config.validationSchemaExportType) { case 'const': return `${element}Schema`; case 'function': default: return depthVariable ? `${element}Schema(depth)` : `${element}Schema()`; } }).join(', '); const unionElementsCount = node.types.length ?? 0; const union = unionElementsCount > 1 ? `z.union([${unionElements}])` : unionElements; switch (this.config.validationSchemaExportType) { case 'const': return new visitor_plugin_common_1.DeclarationBlock({}).export().asKind('const').withName(`${unionName}Schema`).withContent(union).string; case 'function': default: return new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('function') .withName(`${unionName}Schema(${(0, zod_shared_js_1.schemaDepthParameter)(this.config)})`) .withBlock((0, visitor_plugin_common_1.indent)(`return ${union}`)) .string; } }, }; } buildInputFields(fields, visitor, name, description) { const typeName = visitor.prefixTypeNamespace(name); const shape = fields.map(field => (0, zod_shared_js_1.generateFieldZodSchema)(this.config, visitor, field, 2)).join(',\n'); const objectSchema = (0, zod_shared_js_1.buildObjectExpression)(this.config, shape, description); const schemaType = hasDefaultValue(fields) ? `z.ZodType<${typeName}>` : `z.ZodObject<Properties<${typeName}>>`; switch (this.config.validationSchemaExportType) { case 'const': return new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('const') .withName(`${name}Schema: ${schemaType}`) .withContent(objectSchema) .string; case 'function': default: return new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('function') .withName(`${name}Schema(): ${schemaType}`) .withBlock((0, zod_shared_js_1.buildObjectReturn)(this.config, shape, description)) .string; } } buildOneOfInputFields(fields, visitor, name, description) { const typeName = visitor.prefixTypeNamespace(name); const variants = fields.map((selectedField) => { const shape = fields.map((field) => { if (field === selectedField) { const gen = (0, zod_shared_js_1.generateFieldTypeZodSchema)(this.config, visitor, field, field.type, undefined, true, true); return (0, visitor_plugin_common_1.indent)(`${field.name.value}: ${(0, zod_shared_js_1.withDescription)(this.config, field, (0, zod_shared_js_1.maybeLazy)(visitor, field.type, gen))}`, 2); } return (0, visitor_plugin_common_1.indent)(`${field.name.value}: z.never().optional()`, 2); }).join(',\n'); return (0, zod_shared_js_1.buildObjectExpression)(this.config, shape); }); const schema = (0, zod_shared_js_1.withTypeDescription)(this.config, description, variants.length > 1 ? `z.union([\n${variants.map(variant => (0, visitor_plugin_common_1.indent)(variant, 2)).join(',\n')}\n])` : variants[0]); switch (this.config.validationSchemaExportType) { case 'const': return new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('const') .withName(`${name}Schema: z.ZodType<${typeName}>`) .withContent(schema) .string; case 'function': default: return new visitor_plugin_common_1.DeclarationBlock({}) .export() .asKind('function') .withName(`${name}Schema(): z.ZodType<${typeName}>`) .withBlock((0, visitor_plugin_common_1.indent)(`return ${schema}`)) .string; } } } exports.ZodV4SchemaVisitor = ZodV4SchemaVisitor; function hasDefaultValue(fields) { return fields.some(field => field.kind === graphql_1.Kind.INPUT_VALUE_DEFINITION && field.defaultValue !== undefined); }