Skip to content

Commit 5aea9f0

Browse files
authored
Merge pull request #248 from Code-Hex/fix-237
slight modifications for #237
2 parents efe8628 + 1cb521f commit 5aea9f0

File tree

12 files changed

+122
-35
lines changed

12 files changed

+122
-35
lines changed

example/myzod/schemas.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11
import * as myzod from 'myzod'
2-
import { AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, HttpInput, HttpMethod, LayoutInput, PageInput, PageType, User } from '../types'
2+
import { Admin, AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, Guest, HttpInput, HttpMethod, LayoutInput, PageInput, PageType, User } from '../types'
33

44
export const definedNonNullAnySchema = myzod.object({});
55

6+
export function AdminSchema(): myzod.Type<Admin> {
7+
return myzod.object({
8+
__typename: myzod.literal('Admin').optional(),
9+
lastModifiedAt: definedNonNullAnySchema.optional().nullable()
10+
})
11+
}
12+
613
export function AttributeInputSchema(): myzod.Type<AttributeInput> {
714
return myzod.object({
815
key: myzod.string().optional().nullable(),
@@ -45,6 +52,13 @@ export function EventInputSchema(): myzod.Type<EventInput> {
4552

4653
export const EventOptionTypeSchema = myzod.enum(EventOptionType);
4754

55+
export function GuestSchema(): myzod.Type<Guest> {
56+
return myzod.object({
57+
__typename: myzod.literal('Guest').optional(),
58+
lastLoggedIn: definedNonNullAnySchema.optional().nullable()
59+
})
60+
}
61+
4862
export function HttpInputSchema(): myzod.Type<HttpInput> {
4963
return myzod.object({
5064
method: HttpMethodSchema.optional().nullable(),
@@ -84,8 +98,13 @@ export function UserSchema(): myzod.Type<User> {
8498
createdAt: definedNonNullAnySchema.optional().nullable(),
8599
email: myzod.string().optional().nullable(),
86100
id: myzod.string().optional().nullable(),
101+
kind: UserKindSchema().optional().nullable(),
87102
name: myzod.string().optional().nullable(),
88103
password: myzod.string().optional().nullable(),
89104
updatedAt: definedNonNullAnySchema.optional().nullable()
90105
})
91106
}
107+
108+
export function UserKindSchema() {
109+
return myzod.union([AdminSchema(), GuestSchema()])
110+
}

example/test.graphql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,22 @@ enum PageType {
55
BASIC_AUTH
66
}
77

8+
type Admin {
9+
lastModifiedAt: Date
10+
}
11+
12+
type Guest {
13+
lastLoggedIn: Date
14+
}
15+
16+
union UserKind = Admin | Guest
17+
818
type User {
919
id: ID
1020
name: String
1121
email: String
1222
password: String
23+
kind: UserKind
1324
createdAt: Date
1425
updatedAt: Date
1526
}

example/types.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ export type Scalars = {
1414
URL: any;
1515
};
1616

17+
export type Admin = {
18+
__typename?: 'Admin';
19+
lastModifiedAt?: Maybe<Scalars['Date']>;
20+
};
21+
1722
export type AttributeInput = {
1823
key?: InputMaybe<Scalars['String']>;
1924
val?: InputMaybe<Scalars['String']>;
@@ -52,6 +57,11 @@ export enum EventOptionType {
5257
Retry = 'RETRY'
5358
}
5459

60+
export type Guest = {
61+
__typename?: 'Guest';
62+
lastLoggedIn?: Maybe<Scalars['Date']>;
63+
};
64+
5565
export type HttpInput = {
5666
method?: InputMaybe<HttpMethod>;
5767
url: Scalars['URL'];
@@ -92,7 +102,10 @@ export type User = {
92102
createdAt?: Maybe<Scalars['Date']>;
93103
email?: Maybe<Scalars['String']>;
94104
id?: Maybe<Scalars['ID']>;
105+
kind?: Maybe<UserKind>;
95106
name?: Maybe<Scalars['String']>;
96107
password?: Maybe<Scalars['String']>;
97108
updatedAt?: Maybe<Scalars['Date']>;
98109
};
110+
111+
export type UserKind = Admin | Guest;

example/yup/schemas.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
import * as yup from 'yup'
2-
import { AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, HttpInput, HttpMethod, LayoutInput, PageInput, PageType, User } from '../types'
2+
import { Admin, AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, Guest, HttpInput, HttpMethod, LayoutInput, PageInput, PageType, User, UserKind } from '../types'
3+
4+
function union<T>(...schemas: ReadonlyArray<yup.SchemaOf<T>>): yup.BaseSchema<T> {
5+
return yup.mixed().test({
6+
test: (value) => schemas.some((schema) => schema.isValidSync(value))
7+
})
8+
}
9+
10+
export function AdminSchema(): yup.SchemaOf<Admin> {
11+
return yup.object({
12+
__typename: yup.mixed().oneOf(['Admin', undefined]),
13+
lastModifiedAt: yup.mixed()
14+
})
15+
}
316

417
export function AttributeInputSchema(): yup.SchemaOf<AttributeInput> {
518
return yup.object({
@@ -43,6 +56,13 @@ export function EventInputSchema(): yup.SchemaOf<EventInput> {
4356

4457
export const EventOptionTypeSchema = yup.mixed().oneOf([EventOptionType.Reload, EventOptionType.Retry]);
4558

59+
export function GuestSchema(): yup.SchemaOf<Guest> {
60+
return yup.object({
61+
__typename: yup.mixed().oneOf(['Guest', undefined]),
62+
lastLoggedIn: yup.mixed()
63+
})
64+
}
65+
4666
export function HttpInputSchema(): yup.SchemaOf<HttpInput> {
4767
return yup.object({
4868
method: HttpMethodSchema,
@@ -82,8 +102,13 @@ export function UserSchema(): yup.SchemaOf<User> {
82102
createdAt: yup.mixed(),
83103
email: yup.string(),
84104
id: yup.string(),
105+
kind: UserKindSchema(),
85106
name: yup.string(),
86107
password: yup.string(),
87108
updatedAt: yup.mixed()
88109
})
89110
}
111+
112+
export function UserKindSchema(): yup.BaseSchema<UserKind> {
113+
return union<UserKind>(AdminSchema(), GuestSchema())
114+
}

example/zod/schemas.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { z } from 'zod'
2-
import { AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, HttpInput, HttpMethod, LayoutInput, PageInput, PageType, User } from '../types'
2+
import { Admin, AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, Guest, HttpInput, HttpMethod, LayoutInput, PageInput, PageType, User } from '../types'
33

44
type Properties<T> = Required<{
55
[K in keyof T]: z.ZodType<T[K], any, T[K]>;
@@ -11,6 +11,13 @@ export const isDefinedNonNullAny = (v: any): v is definedNonNullAny => v !== und
1111

1212
export const definedNonNullAnySchema = z.any().refine((v) => isDefinedNonNullAny(v));
1313

14+
export function AdminSchema(): z.ZodObject<Properties<Admin>> {
15+
return z.object<Properties<Admin>>({
16+
__typename: z.literal('Admin').optional(),
17+
lastModifiedAt: definedNonNullAnySchema.nullish()
18+
})
19+
}
20+
1421
export function AttributeInputSchema(): z.ZodObject<Properties<AttributeInput>> {
1522
return z.object<Properties<AttributeInput>>({
1623
key: z.string().nullish(),
@@ -53,6 +60,13 @@ export function EventInputSchema(): z.ZodObject<Properties<EventInput>> {
5360

5461
export const EventOptionTypeSchema = z.nativeEnum(EventOptionType);
5562

63+
export function GuestSchema(): z.ZodObject<Properties<Guest>> {
64+
return z.object<Properties<Guest>>({
65+
__typename: z.literal('Guest').optional(),
66+
lastLoggedIn: definedNonNullAnySchema.nullish()
67+
})
68+
}
69+
5670
export function HttpInputSchema(): z.ZodObject<Properties<HttpInput>> {
5771
return z.object<Properties<HttpInput>>({
5872
method: HttpMethodSchema.nullish(),
@@ -92,8 +106,13 @@ export function UserSchema(): z.ZodObject<Properties<User>> {
92106
createdAt: definedNonNullAnySchema.nullish(),
93107
email: z.string().nullish(),
94108
id: z.string().nullish(),
109+
kind: UserKindSchema().nullish(),
95110
name: z.string().nullish(),
96111
password: z.string().nullish(),
97112
updatedAt: definedNonNullAnySchema.nullish()
98113
})
99114
}
115+
116+
export function UserKindSchema() {
117+
return z.union([AdminSchema(), GuestSchema()])
118+
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
],
1717
"scripts": {
1818
"type-check": "tsc --noEmit",
19+
"type-check:yup": "tsc --strict --noEmit example/yup/schemas.ts",
20+
"type-check:zod": "tsc --strict --noEmit example/zod/schemas.ts",
21+
"type-check:myzod": "tsc --strict --noEmit example/myzod/schemas.ts",
1922
"test": "jest --no-watchman",
2023
"build": "run-p build:*",
2124
"build:main": "tsc -p tsconfig.main.json",

src/myzod/index.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,20 +91,17 @@ export const MyZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSche
9191
.withContent(`myzod.enum(${enumname})`).string;
9292
},
9393
UnionTypeDefinition: (node: UnionTypeDefinitionNode) => {
94+
if (!node.types) return;
95+
9496
const unionName = tsVisitor.convertName(node.name.value);
9597
const unionElements = node.types?.map(t => `${tsVisitor.convertName(t.name.value)}Schema()`).join(', ');
9698
const unionElementsCount = node.types?.length ?? 0;
9799

98100
const union =
99101
unionElementsCount > 1 ? indent(`return myzod.union([${unionElements}])`) : indent(`return ${unionElements}`);
100102

101-
const result = new DeclarationBlock({})
102-
.export()
103-
.asKind('function')
104-
.withName(`${unionName}Schema()`)
105-
.withBlock(union);
106-
107-
return result.string;
103+
return new DeclarationBlock({}).export().asKind('function').withName(`${unionName}Schema()`).withBlock(union)
104+
.string;
108105
},
109106
};
110107
};

src/yup/index.ts

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
3030
return [importYup];
3131
},
3232
initialEmit: (): string =>
33+
'\n' +
3334
new DeclarationBlock({})
3435
.asKind('function')
3536
.withName('union<T>(...schemas: ReadonlyArray<yup.SchemaOf<T>>): yup.BaseSchema<T>')
@@ -101,22 +102,19 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
101102
.withContent(`yup.mixed().oneOf([${values}])`).string;
102103
},
103104
UnionTypeDefinition: (node: UnionTypeDefinitionNode) => {
105+
if (!node.types) return;
106+
104107
const unionName = tsVisitor.convertName(node.name.value);
105-
const unionElements = node.types?.map(t => `${tsVisitor.convertName(t.name.value)}Schema()`).join(', ');
106-
const unionElementsCount = node.types?.length ?? 0;
108+
importTypes.push(unionName);
107109

108-
const union =
109-
unionElementsCount > 1
110-
? indent(`return union<${unionName}>(${unionElements})`)
111-
: indent(`return ${unionElements}`);
110+
const unionElements = node.types?.map(t => `${tsVisitor.convertName(t.name.value)}Schema()`).join(', ');
111+
const union = indent(`return union<${unionName}>(${unionElements})`);
112112

113-
const result = new DeclarationBlock({})
113+
return new DeclarationBlock({})
114114
.export()
115115
.asKind('function')
116116
.withName(`${unionName}Schema(): yup.BaseSchema<${unionName}>`)
117-
.withBlock(union);
118-
119-
return result.string;
117+
.withBlock(union).string;
120118
},
121119
// ScalarTypeDefinition: (node) => {
122120
// const decl = new DeclarationBlock({})
@@ -209,6 +207,11 @@ const generateNameNodeYupSchema = (
209207
return `${enumName}Schema`;
210208
}
211209

210+
if (typ?.astNode?.kind === 'UnionTypeDefinition') {
211+
const enumName = tsVisitor.convertName(typ.astNode.name.value);
212+
return `${enumName}Schema()`;
213+
}
214+
212215
const primitive = yup4Scalar(config, tsVisitor, node.value);
213216
return primitive;
214217
};

src/zod/index.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,20 +102,17 @@ export const ZodSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
102102
.withContent(`z.nativeEnum(${enumname})`).string;
103103
},
104104
UnionTypeDefinition: (node: UnionTypeDefinitionNode) => {
105+
if (!node.types) return;
106+
105107
const unionName = tsVisitor.convertName(node.name.value);
106-
const unionElements = node.types?.map(t => `${tsVisitor.convertName(t.name.value)}Schema()`).join(', ');
107-
const unionElementsCount = node.types?.length ?? 0;
108+
const unionElements = node.types.map(t => `${tsVisitor.convertName(t.name.value)}Schema()`).join(', ');
109+
const unionElementsCount = node.types.length ?? 0;
108110

109111
const union =
110112
unionElementsCount > 1 ? indent(`return z.union([${unionElements}])`) : indent(`return ${unionElements}`);
111113

112-
const result = new DeclarationBlock({})
113-
.export()
114-
.asKind('function')
115-
.withName(`${unionName}Schema()`)
116-
.withBlock(union);
117-
118-
return result.string;
114+
return new DeclarationBlock({}).export().asKind('function').withName(`${unionName}Schema()`).withBlock(union)
115+
.string;
119116
},
120117
};
121118
};

tests/myzod.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -563,7 +563,7 @@ describe('myzod', () => {
563563
const wantContains = [
564564
// Shape Schema
565565
'export function ShapeSchema() {',
566-
'myzod.union([CircleSchema(), SquareSchema()])',
566+
'return myzod.union([CircleSchema(), SquareSchema()])',
567567
'}',
568568
];
569569
for (const wantContain of wantContains) {
@@ -629,7 +629,7 @@ describe('myzod', () => {
629629
const wantContains = [
630630
// Shape Schema
631631
'export function ShapeSchema() {',
632-
'CircleSchema()',
632+
'return CircleSchema()',
633633
'}',
634634
];
635635
for (const wantContain of wantContains) {

tests/yup.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ describe('yup', () => {
513513
'export function GeometrySchema(): yup.SchemaOf<Geometry> {',
514514
'return yup.object({',
515515
"__typename: yup.mixed().oneOf(['Geometry', undefined]),",
516-
'shape: yup.mixed()',
516+
'shape: ShapeSchema()',
517517
'})',
518518
];
519519
for (const wantContain of wantContains) {
@@ -542,7 +542,7 @@ describe('yup', () => {
542542
const wantContains = [
543543
// Shape Schema
544544
'export function ShapeSchema(): yup.BaseSchema<Shape> {',
545-
'CircleSchema()',
545+
'return union<Shape>(CircleSchema())',
546546
'}',
547547
];
548548
for (const wantContain of wantContains) {

tests/zod.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -661,7 +661,7 @@ describe('zod', () => {
661661
const wantContains = [
662662
// Shape Schema
663663
'export function ShapeSchema() {',
664-
'z.union([CircleSchema(), SquareSchema()])',
664+
'return z.union([CircleSchema(), SquareSchema()])',
665665
'}',
666666
];
667667
for (const wantContain of wantContains) {
@@ -725,7 +725,7 @@ describe('zod', () => {
725725
const wantContains = [
726726
// Shape Schema
727727
'export function ShapeSchema() {',
728-
'CircleSchema()',
728+
'return CircleSchema()',
729729
'}',
730730
];
731731
for (const wantContain of wantContains) {

0 commit comments

Comments
 (0)