Skip to content

Commit bd3e1b3

Browse files
authored
Merge pull request Code-Hex#454 from Code-Hex/refactoring
Refactoring to use class
2 parents a026ce1 + eb05f42 commit bd3e1b3

File tree

8 files changed

+313
-303
lines changed

8 files changed

+313
-303
lines changed

example/yup/schemas.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,9 @@ export function MyTypeSchema(): yup.ObjectSchema<MyType> {
8989

9090
export function MyTypeFooArgsSchema(): yup.ObjectSchema<MyTypeFooArgs> {
9191
return yup.object({
92-
a: yup.string().defined().nullable(),
92+
a: yup.string().defined().nullable().optional(),
9393
b: yup.number().defined().nonNullable(),
94-
c: yup.boolean().defined().nullable(),
94+
c: yup.boolean().defined().nullable().optional(),
9595
d: yup.number().defined().nonNullable()
9696
})
9797
}

src/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const plugin: PluginFunction<ValidationSchemaPluginConfig, Types.ComplexP
1515
config: ValidationSchemaPluginConfig
1616
): Types.ComplexPluginOutput => {
1717
const { schema: _schema, ast } = _transformSchemaAST(schema, config);
18-
const { buildImports, initialEmit, ...visitor } = schemaVisitor(_schema, config);
18+
const visitor = schemaVisitor(_schema, config);
1919

2020
const result = visit(ast, visitor);
2121

@@ -24,18 +24,18 @@ export const plugin: PluginFunction<ValidationSchemaPluginConfig, Types.ComplexP
2424
const generated = result.definitions.filter(def => typeof def === 'string');
2525

2626
return {
27-
prepend: buildImports(),
28-
content: [initialEmit(), ...generated].join('\n'),
27+
prepend: visitor.buildImports(),
28+
content: [visitor.initialEmit(), ...generated].join('\n'),
2929
};
3030
};
3131

3232
const schemaVisitor = (schema: GraphQLSchema, config: ValidationSchemaPluginConfig): SchemaVisitor => {
3333
if (config?.schema === 'zod') {
34-
return ZodSchemaVisitor(schema, config);
34+
return new ZodSchemaVisitor(schema, config);
3535
} else if (config?.schema === 'myzod') {
36-
return MyZodSchemaVisitor(schema, config);
36+
return new MyZodSchemaVisitor(schema, config);
3737
}
38-
return YupSchemaVisitor(schema, config);
38+
return new YupSchemaVisitor(schema, config);
3939
};
4040

4141
const _transformSchemaAST = (schema: GraphQLSchema, config: ValidationSchemaPluginConfig) => {

src/myzod/index.ts

Lines changed: 78 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -13,94 +13,58 @@ import {
1313

1414
import { ValidationSchemaPluginConfig } from '../config';
1515
import { buildApi, formatDirectiveConfig } from '../directive';
16-
import { SchemaVisitor } from '../types';
16+
import { BaseSchemaVisitor } from '../schema_visitor';
1717
import { Visitor } from '../visitor';
1818
import { isInput, isListType, isNamedType, isNonNullType, ObjectTypeDefinitionBuilder } from './../graphql';
1919

20-
const importZod = `import * as myzod from 'myzod'`;
2120
const anySchema = `definedNonNullAnySchema`;
2221

23-
export const MyZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchemaPluginConfig): SchemaVisitor => {
24-
const importTypes: string[] = [];
25-
const enumDeclarations: string[] = [];
22+
export class MyZodSchemaVisitor extends BaseSchemaVisitor {
23+
constructor(schema: GraphQLSchema, config: ValidationSchemaPluginConfig) {
24+
super(schema, config);
25+
}
2626

27-
return {
28-
buildImports: (): string[] => {
29-
if (config.importFrom && importTypes.length > 0) {
30-
return [
31-
importZod,
32-
`import ${config.useTypeImports ? 'type ' : ''}{ ${importTypes.join(', ')} } from '${config.importFrom}'`,
33-
];
34-
}
35-
return [importZod];
36-
},
37-
initialEmit: (): string =>
27+
importValidationSchema(): string {
28+
return `import * as myzod from 'myzod'`;
29+
}
30+
31+
initialEmit(): string {
32+
return (
3833
'\n' +
3934
[
4035
new DeclarationBlock({}).export().asKind('const').withName(`${anySchema}`).withContent(`myzod.object({})`)
4136
.string,
42-
...enumDeclarations,
43-
].join('\n'),
44-
InputObjectTypeDefinition: {
37+
...this.enumDeclarations,
38+
].join('\n')
39+
);
40+
}
41+
42+
get InputObjectTypeDefinition() {
43+
return {
4544
leave: (node: InputObjectTypeDefinitionNode) => {
46-
const visitor = new Visitor('input', schema, config);
45+
const visitor = this.createVisitor('input');
4746
const name = visitor.convertName(node.name.value);
48-
importTypes.push(name);
49-
50-
const shape = node.fields?.map(field => generateFieldMyZodSchema(config, visitor, field, 2)).join(',\n');
51-
52-
switch (config.validationSchemaExportType) {
53-
case 'const':
54-
return new DeclarationBlock({})
55-
.export()
56-
.asKind('const')
57-
.withName(`${name}Schema: myzod.Type<${name}>`)
58-
.withContent(['myzod.object({', shape, '})'].join('\n')).string;
59-
60-
case 'function':
61-
default:
62-
return new DeclarationBlock({})
63-
.export()
64-
.asKind('function')
65-
.withName(`${name}Schema(): myzod.Type<${name}>`)
66-
.withBlock([indent(`return myzod.object({`), shape, indent('})')].join('\n')).string;
67-
}
47+
this.importTypes.push(name);
48+
return this.buildInputFields(node.fields ?? [], visitor, name);
6849
},
69-
},
70-
ObjectTypeDefinition: {
71-
leave: ObjectTypeDefinitionBuilder(config.withObjectType, (node: ObjectTypeDefinitionNode) => {
72-
const visitor = new Visitor('output', schema, config);
50+
};
51+
}
52+
53+
get ObjectTypeDefinition() {
54+
return {
55+
leave: ObjectTypeDefinitionBuilder(this.config.withObjectType, (node: ObjectTypeDefinitionNode) => {
56+
const visitor = this.createVisitor('output');
7357
const name = visitor.convertName(node.name.value);
74-
importTypes.push(name);
58+
this.importTypes.push(name);
7559

7660
// Building schema for field arguments.
77-
const argumentBlocks = visitor.buildArgumentsSchemaBlock(node, (typeName, field) => {
78-
importTypes.push(typeName);
79-
const args = field.arguments ?? [];
80-
const shape = args.map(field => generateFieldMyZodSchema(config, visitor, field, 2)).join(',\n');
81-
switch (config.validationSchemaExportType) {
82-
case 'const':
83-
return new DeclarationBlock({})
84-
.export()
85-
.asKind('const')
86-
.withName(`${typeName}Schema: myzod.Type<${typeName}>`)
87-
.withContent([`myzod.object({`, shape, '})'].join('\n')).string;
88-
89-
case 'function':
90-
default:
91-
return new DeclarationBlock({})
92-
.export()
93-
.asKind('function')
94-
.withName(`${typeName}Schema(): myzod.Type<${typeName}>`)
95-
.withBlock([indent(`return myzod.object({`), shape, indent('})')].join('\n')).string;
96-
}
97-
});
61+
const argumentBlocks = this.buildObjectTypeDefinitionArguments(node, visitor);
9862
const appendArguments = argumentBlocks ? '\n' + argumentBlocks : '';
9963

10064
// Building schema for fields.
101-
const shape = node.fields?.map(field => generateFieldMyZodSchema(config, visitor, field, 2)).join(',\n');
65+
const shape = node.fields?.map(field => generateFieldMyZodSchema(this.config, visitor, field, 2)).join(',\n');
10266

103-
switch (config.validationSchemaExportType) {
67+
switch (this.config.validationSchemaExportType) {
10468
case 'const':
10569
return (
10670
new DeclarationBlock({})
@@ -135,16 +99,19 @@ export const MyZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSche
13599
);
136100
}
137101
}),
138-
},
139-
EnumTypeDefinition: {
102+
};
103+
}
104+
105+
get EnumTypeDefinition() {
106+
return {
140107
leave: (node: EnumTypeDefinitionNode) => {
141-
const visitor = new Visitor('both', schema, config);
108+
const visitor = this.createVisitor('both');
142109
const enumname = visitor.convertName(node.name.value);
143-
importTypes.push(enumname);
110+
this.importTypes.push(enumname);
144111
// z.enum are basically myzod.literals
145112
// hoist enum declarations
146-
enumDeclarations.push(
147-
config.enumsAsTypes
113+
this.enumDeclarations.push(
114+
this.config.enumsAsTypes
148115
? new DeclarationBlock({})
149116
.export()
150117
.asKind('type')
@@ -159,12 +126,15 @@ export const MyZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSche
159126
.withContent(`myzod.enum(${enumname})`).string
160127
);
161128
},
162-
},
163-
UnionTypeDefinition: {
129+
};
130+
}
131+
132+
get UnionTypeDefinition() {
133+
return {
164134
leave: (node: UnionTypeDefinitionNode) => {
165-
if (!node.types || !config.withObjectType) return;
135+
if (!node.types || !this.config.withObjectType) return;
166136

167-
const visitor = new Visitor('output', schema, config);
137+
const visitor = this.createVisitor('output');
168138

169139
const unionName = visitor.convertName(node.name.value);
170140
const unionElements = node.types
@@ -174,7 +144,7 @@ export const MyZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSche
174144
if (typ?.astNode?.kind === 'EnumTypeDefinition') {
175145
return `${element}Schema`;
176146
}
177-
switch (config.validationSchemaExportType) {
147+
switch (this.config.validationSchemaExportType) {
178148
case 'const':
179149
return `${element}Schema`;
180150
case 'function':
@@ -187,7 +157,7 @@ export const MyZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSche
187157

188158
const union = unionElementsCount > 1 ? `myzod.union([${unionElements}])` : unionElements;
189159

190-
switch (config.validationSchemaExportType) {
160+
switch (this.config.validationSchemaExportType) {
191161
case 'const':
192162
return new DeclarationBlock({}).export().asKind('const').withName(`${unionName}Schema`).withContent(union)
193163
.string;
@@ -200,9 +170,34 @@ export const MyZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSche
200170
.withBlock(indent(`return ${union}`)).string;
201171
}
202172
},
203-
},
204-
};
205-
};
173+
};
174+
}
175+
176+
protected buildInputFields(
177+
fields: readonly (FieldDefinitionNode | InputValueDefinitionNode)[],
178+
visitor: Visitor,
179+
name: string
180+
) {
181+
const shape = fields.map(field => generateFieldMyZodSchema(this.config, visitor, field, 2)).join(',\n');
182+
183+
switch (this.config.validationSchemaExportType) {
184+
case 'const':
185+
return new DeclarationBlock({})
186+
.export()
187+
.asKind('const')
188+
.withName(`${name}Schema: myzod.Type<${name}>`)
189+
.withContent(['myzod.object({', shape, '})'].join('\n')).string;
190+
191+
case 'function':
192+
default:
193+
return new DeclarationBlock({})
194+
.export()
195+
.asKind('function')
196+
.withName(`${name}Schema(): myzod.Type<${name}>`)
197+
.withBlock([indent(`return myzod.object({`), shape, indent('})')].join('\n')).string;
198+
}
199+
}
200+
}
206201

207202
const generateFieldMyZodSchema = (
208203
config: ValidationSchemaPluginConfig,

src/schema_visitor.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { FieldDefinitionNode, GraphQLSchema, InputValueDefinitionNode, ObjectTypeDefinitionNode } from 'graphql';
2+
3+
import { ValidationSchemaPluginConfig } from './config';
4+
import { SchemaVisitor } from './types';
5+
import { Visitor } from './visitor';
6+
7+
export abstract class BaseSchemaVisitor implements SchemaVisitor {
8+
protected importTypes: string[] = [];
9+
protected enumDeclarations: string[] = [];
10+
11+
constructor(
12+
protected schema: GraphQLSchema,
13+
protected config: ValidationSchemaPluginConfig
14+
) {}
15+
16+
abstract importValidationSchema(): string;
17+
18+
buildImports(): string[] {
19+
if (this.config.importFrom && this.importTypes.length > 0) {
20+
return [
21+
this.importValidationSchema(),
22+
`import ${this.config.useTypeImports ? 'type ' : ''}{ ${this.importTypes.join(', ')} } from '${
23+
this.config.importFrom
24+
}'`,
25+
];
26+
}
27+
return [this.importValidationSchema()];
28+
}
29+
30+
abstract initialEmit(): string;
31+
32+
createVisitor(scalarDirection: 'input' | 'output' | 'both'): Visitor {
33+
return new Visitor(scalarDirection, this.schema, this.config);
34+
}
35+
36+
protected abstract buildInputFields(
37+
fields: readonly (FieldDefinitionNode | InputValueDefinitionNode)[],
38+
visitor: Visitor,
39+
name: string
40+
): string;
41+
42+
protected buildObjectTypeDefinitionArguments(node: ObjectTypeDefinitionNode, visitor: Visitor) {
43+
return visitor.buildArgumentsSchemaBlock(node, (typeName, field) => {
44+
this.importTypes.push(typeName);
45+
return this.buildInputFields(field.arguments ?? [], visitor, typeName);
46+
});
47+
}
48+
}

src/types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ export type NewVisitor = Partial<{
55
leave?: ASTVisitFn<NodeT>;
66
};
77
}>;
8-
export type SchemaVisitor = {
8+
9+
export interface SchemaVisitor extends NewVisitor {
910
buildImports: () => string[];
1011
initialEmit: () => string;
11-
} & NewVisitor;
12+
}

0 commit comments

Comments
 (0)