Skip to content

Commit 1e49cc5

Browse files
simonljusCode-Hex
authored andcommitted
InterfaceTypeDefinition for myzod
1 parent 9a40f72 commit 1e49cc5

File tree

2 files changed

+116
-2
lines changed

2 files changed

+116
-2
lines changed

src/myzod/index.ts

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type {
55
GraphQLSchema,
66
InputObjectTypeDefinitionNode,
77
InputValueDefinitionNode,
8+
InterfaceTypeDefinitionNode,
89
NameNode,
910
ObjectTypeDefinitionNode,
1011
TypeNode,
@@ -17,8 +18,15 @@ import {
1718
import type { ValidationSchemaPluginConfig } from '../config';
1819
import { buildApi, formatDirectiveConfig } from '../directive';
1920
import { BaseSchemaVisitor } from '../schema_visitor';
20-
import type { Visitor } from '../visitor';
21-
import { ObjectTypeDefinitionBuilder, isInput, isListType, isNamedType, isNonNullType } from './../graphql';
21+
import { Visitor } from '../visitor';
22+
import {
23+
InterfaceTypeDefinitionBuilder,
24+
isInput,
25+
isListType,
26+
isNamedType,
27+
isNonNullType,
28+
ObjectTypeDefinitionBuilder,
29+
} from './../graphql';
2230

2331
const anySchema = `definedNonNullAnySchema`;
2432

@@ -53,6 +61,51 @@ export class MyZodSchemaVisitor extends BaseSchemaVisitor {
5361
};
5462
}
5563

64+
get InterfaceTypeDefinition() {
65+
return {
66+
leave: InterfaceTypeDefinitionBuilder(this.config.withInterfaceType, (node: InterfaceTypeDefinitionNode) => {
67+
const visitor = this.createVisitor('output');
68+
const name = visitor.convertName(node.name.value);
69+
this.importTypes.push(name);
70+
71+
// Building schema for field arguments.
72+
const argumentBlocks = this.buildTypeDefinitionArguments(node, visitor);
73+
const appendArguments = argumentBlocks ? '\n' + argumentBlocks : '';
74+
75+
// Building schema for fields.
76+
const shape = node.fields?.map(field => generateFieldMyZodSchema(this.config, visitor, field, 2)).join(',\n');
77+
78+
switch (this.config.validationSchemaExportType) {
79+
case 'const':
80+
return (
81+
new DeclarationBlock({})
82+
.export()
83+
.asKind('const')
84+
.withName(`${name}Schema: myzod.Type<${name}>`)
85+
.withContent([`myzod.object({`, shape, '})'].join('\n')).string + appendArguments
86+
);
87+
88+
case 'function':
89+
default:
90+
return (
91+
new DeclarationBlock({})
92+
.export()
93+
.asKind('function')
94+
.withName(`${name}Schema(): myzod.Type<${name}>`)
95+
.withBlock(
96+
[
97+
indent(`return myzod.object({`),
98+
indent(`__typename: myzod.literal('${node.name.value}').optional(),`, 2),
99+
shape,
100+
indent('})'),
101+
].join('\n')
102+
).string + appendArguments
103+
);
104+
}
105+
}),
106+
};
107+
}
108+
56109
get ObjectTypeDefinition() {
57110
return {
58111
leave: ObjectTypeDefinitionBuilder(this.config.withObjectType, (node: ObjectTypeDefinitionNode) => {
@@ -266,6 +319,7 @@ function generateNameNodeMyZodSchema(config: ValidationSchemaPluginConfig, visit
266319
const converter = visitor.getNameNodeConverter(node);
267320

268321
switch (converter?.targetKind) {
322+
case 'InterfaceTypeDefinition':
269323
case 'InputObjectTypeDefinition':
270324
case 'ObjectTypeDefinition':
271325
case 'UnionTypeDefinition':
@@ -279,7 +333,12 @@ function generateNameNodeMyZodSchema(config: ValidationSchemaPluginConfig, visit
279333
}
280334
case 'EnumTypeDefinition':
281335
return `${converter.convertName()}Schema`;
336+
case 'ScalarTypeDefinition':
337+
return myzod4Scalar(config, visitor, node.value);
282338
default:
339+
if (converter?.targetKind) {
340+
console.warn('Unknown target kind', converter.targetKind);
341+
}
283342
return myzod4Scalar(config, visitor, node.value);
284343
}
285344
}

tests/myzod.spec.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,61 @@ describe('myzod', () => {
486486
});
487487
});
488488

489+
describe('with withInterfaceType', () => {
490+
it('not generate if withObjectType false', async () => {
491+
const schema = buildSchema(/* GraphQL */ `
492+
interface User {
493+
id: ID!
494+
name: String
495+
}
496+
`);
497+
const result = await plugin(
498+
schema,
499+
[],
500+
{
501+
schema: 'myzod',
502+
},
503+
{}
504+
);
505+
expect(result.content).not.toContain('export function UserSchema(): myzod.Type<User> {');
506+
});
507+
508+
it('generate interface type contains interface type', async () => {
509+
const schema = buildSchema(/* GraphQL */ `
510+
interface Book {
511+
author: Author
512+
title: String
513+
}
514+
515+
interface Author {
516+
books: [Book]
517+
name: String
518+
}
519+
`);
520+
const result = await plugin(
521+
schema,
522+
[],
523+
{
524+
schema: 'myzod',
525+
withInterfaceType: true,
526+
},
527+
{}
528+
);
529+
const wantContains = [
530+
'export function AuthorSchema(): myzod.Type<Author> {',
531+
'books: myzod.array(BookSchema().nullable()).optional().nullable(),',
532+
'name: myzod.string().optional().nullable()',
533+
534+
'export function BookSchema(): myzod.Type<Book> {',
535+
'author: AuthorSchema().optional().nullable(),',
536+
'title: myzod.string().optional().nullable()',
537+
];
538+
for (const wantContain of wantContains) {
539+
expect(result.content).toContain(wantContain);
540+
}
541+
});
542+
});
543+
489544
describe('with withObjectType', () => {
490545
it('not generate if withObjectType false', async () => {
491546
const schema = buildSchema(/* GraphQL */ `

0 commit comments

Comments
 (0)