Skip to content

Commit f3140fd

Browse files
authored
Merge pull request #351 from Code-Hex/fix/upgrade-yup-v1
Upgrade yup v1
2 parents 0b65db1 + 5838234 commit f3140fd

File tree

3 files changed

+175
-178
lines changed

3 files changed

+175
-178
lines changed

example/yup/schemas.ts

+58-58
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,114 @@
11
import * as yup from 'yup'
22
import { Admin, AttributeInput, ButtonComponentType, ComponentInput, DropDownComponentInput, EventArgumentInput, EventInput, EventOptionType, Guest, HttpInput, HttpMethod, LayoutInput, PageInput, PageType, User, UserKind } from '../types'
33

4-
function union<T>(...schemas: ReadonlyArray<yup.SchemaOf<T>>): yup.BaseSchema<T> {
5-
return yup.mixed().test({
4+
function union<T extends {}>(...schemas: ReadonlyArray<yup.ObjectSchema<T>>): yup.MixedSchema<T> {
5+
return yup.mixed<T>().test({
66
test: (value) => schemas.some((schema) => schema.isValidSync(value))
7-
})
7+
}).defined()
88
}
99

10-
export function AdminSchema(): yup.SchemaOf<Admin> {
10+
export function AdminSchema(): yup.ObjectSchema<Admin> {
1111
return yup.object({
12-
__typename: yup.mixed().oneOf(['Admin', undefined]),
13-
lastModifiedAt: yup.mixed()
12+
__typename: yup.string<'Admin'>().optional(),
13+
lastModifiedAt: yup.mixed().nullable().optional()
1414
})
1515
}
1616

17-
export function AttributeInputSchema(): yup.SchemaOf<AttributeInput> {
17+
export function AttributeInputSchema(): yup.ObjectSchema<AttributeInput> {
1818
return yup.object({
19-
key: yup.string(),
20-
val: yup.string()
19+
key: yup.string().defined().nullable().optional(),
20+
val: yup.string().defined().nullable().optional()
2121
})
2222
}
2323

24-
export const ButtonComponentTypeSchema = yup.mixed().oneOf([ButtonComponentType.Button, ButtonComponentType.Submit]);
24+
export const ButtonComponentTypeSchema = yup.string<ButtonComponentType>().oneOf([ButtonComponentType.Button, ButtonComponentType.Submit]).defined();
2525

26-
export function ComponentInputSchema(): yup.SchemaOf<ComponentInput> {
26+
export function ComponentInputSchema(): yup.ObjectSchema<ComponentInput> {
2727
return yup.object({
28-
child: yup.lazy(() => ComponentInputSchema()) as never,
29-
childrens: yup.array().of(yup.lazy(() => ComponentInputSchema()) as never).optional(),
30-
event: yup.lazy(() => EventInputSchema()) as never,
31-
name: yup.string().defined(),
32-
type: ButtonComponentTypeSchema.defined()
28+
child: yup.lazy(() => ComponentInputSchema()).optional(),
29+
childrens: yup.array(yup.lazy(() => ComponentInputSchema())).defined().nullable().optional(),
30+
event: yup.lazy(() => EventInputSchema()).optional(),
31+
name: yup.string().defined().nonNullable(),
32+
type: ButtonComponentTypeSchema.nonNullable()
3333
})
3434
}
3535

36-
export function DropDownComponentInputSchema(): yup.SchemaOf<DropDownComponentInput> {
36+
export function DropDownComponentInputSchema(): yup.ObjectSchema<DropDownComponentInput> {
3737
return yup.object({
38-
dropdownComponent: yup.lazy(() => ComponentInputSchema()) as never,
39-
getEvent: yup.lazy(() => EventInputSchema().defined()) as never
38+
dropdownComponent: yup.lazy(() => ComponentInputSchema()).optional(),
39+
getEvent: yup.lazy(() => EventInputSchema().nonNullable())
4040
})
4141
}
4242

43-
export function EventArgumentInputSchema(): yup.SchemaOf<EventArgumentInput> {
43+
export function EventArgumentInputSchema(): yup.ObjectSchema<EventArgumentInput> {
4444
return yup.object({
45-
name: yup.string().defined().min(5),
46-
value: yup.string().defined().matches(/^foo/)
45+
name: yup.string().defined().nonNullable().min(5),
46+
value: yup.string().defined().nonNullable().matches(/^foo/)
4747
})
4848
}
4949

50-
export function EventInputSchema(): yup.SchemaOf<EventInput> {
50+
export function EventInputSchema(): yup.ObjectSchema<EventInput> {
5151
return yup.object({
52-
arguments: yup.array().of(yup.lazy(() => EventArgumentInputSchema().defined()) as never).defined(),
53-
options: yup.array().of(EventOptionTypeSchema.defined()).optional()
52+
arguments: yup.array(yup.lazy(() => EventArgumentInputSchema().nonNullable())).defined(),
53+
options: yup.array(EventOptionTypeSchema.nonNullable()).defined().nullable().optional()
5454
})
5555
}
5656

57-
export const EventOptionTypeSchema = yup.mixed().oneOf([EventOptionType.Reload, EventOptionType.Retry]);
57+
export const EventOptionTypeSchema = yup.string<EventOptionType>().oneOf([EventOptionType.Reload, EventOptionType.Retry]).defined();
5858

59-
export function GuestSchema(): yup.SchemaOf<Guest> {
59+
export function GuestSchema(): yup.ObjectSchema<Guest> {
6060
return yup.object({
61-
__typename: yup.mixed().oneOf(['Guest', undefined]),
62-
lastLoggedIn: yup.mixed()
61+
__typename: yup.string<'Guest'>().optional(),
62+
lastLoggedIn: yup.mixed().nullable().optional()
6363
})
6464
}
6565

66-
export function HttpInputSchema(): yup.SchemaOf<HttpInput> {
66+
export function HttpInputSchema(): yup.ObjectSchema<HttpInput> {
6767
return yup.object({
68-
method: HttpMethodSchema,
69-
url: yup.mixed().defined()
68+
method: HttpMethodSchema.nullable().optional(),
69+
url: yup.mixed().nonNullable()
7070
})
7171
}
7272

73-
export const HttpMethodSchema = yup.mixed().oneOf([HttpMethod.Get, HttpMethod.Post]);
73+
export const HttpMethodSchema = yup.string<HttpMethod>().oneOf([HttpMethod.Get, HttpMethod.Post]).defined();
7474

75-
export function LayoutInputSchema(): yup.SchemaOf<LayoutInput> {
75+
export function LayoutInputSchema(): yup.ObjectSchema<LayoutInput> {
7676
return yup.object({
77-
dropdown: yup.lazy(() => DropDownComponentInputSchema()) as never
77+
dropdown: yup.lazy(() => DropDownComponentInputSchema()).optional()
7878
})
7979
}
8080

81-
export function PageInputSchema(): yup.SchemaOf<PageInput> {
81+
export function PageInputSchema(): yup.ObjectSchema<PageInput> {
8282
return yup.object({
83-
attributes: yup.array().of(yup.lazy(() => AttributeInputSchema().defined()) as never).optional(),
84-
date: yup.mixed(),
85-
height: yup.number().defined(),
86-
id: yup.string().defined(),
87-
layout: yup.lazy(() => LayoutInputSchema().defined()) as never,
88-
pageType: PageTypeSchema.defined(),
89-
postIDs: yup.array().of(yup.string().defined()).optional(),
90-
show: yup.boolean().defined(),
91-
tags: yup.array().of(yup.string()).optional(),
92-
title: yup.string().defined(),
93-
width: yup.number().defined()
83+
attributes: yup.array(yup.lazy(() => AttributeInputSchema().nonNullable())).defined().nullable().optional(),
84+
date: yup.mixed().nullable().optional(),
85+
height: yup.number().defined().nonNullable(),
86+
id: yup.string().defined().nonNullable(),
87+
layout: yup.lazy(() => LayoutInputSchema().nonNullable()),
88+
pageType: PageTypeSchema.nonNullable(),
89+
postIDs: yup.array(yup.string().defined().nonNullable()).defined().nullable().optional(),
90+
show: yup.boolean().defined().nonNullable(),
91+
tags: yup.array(yup.string().defined().nullable()).defined().nullable().optional(),
92+
title: yup.string().defined().nonNullable(),
93+
width: yup.number().defined().nonNullable()
9494
})
9595
}
9696

97-
export const PageTypeSchema = yup.mixed().oneOf([PageType.BasicAuth, PageType.Lp, PageType.Restricted, PageType.Service]);
97+
export const PageTypeSchema = yup.string<PageType>().oneOf([PageType.BasicAuth, PageType.Lp, PageType.Restricted, PageType.Service]).defined();
9898

99-
export function UserSchema(): yup.SchemaOf<User> {
99+
export function UserSchema(): yup.ObjectSchema<User> {
100100
return yup.object({
101-
__typename: yup.mixed().oneOf(['User', undefined]),
102-
createdAt: yup.mixed(),
103-
email: yup.string(),
104-
id: yup.string(),
105-
kind: UserKindSchema(),
106-
name: yup.string(),
107-
password: yup.string(),
108-
updatedAt: yup.mixed()
101+
__typename: yup.string<'User'>().optional(),
102+
createdAt: yup.mixed().nullable().optional(),
103+
email: yup.string().defined().nullable().optional(),
104+
id: yup.string().defined().nullable().optional(),
105+
kind: UserKindSchema().nullable().optional(),
106+
name: yup.string().defined().nullable().optional(),
107+
password: yup.string().defined().nullable().optional(),
108+
updatedAt: yup.mixed().nullable().optional()
109109
})
110110
}
111111

112-
export function UserKindSchema(): yup.BaseSchema<UserKind> {
112+
export function UserKindSchema(): yup.MixedSchema<UserKind> {
113113
return union<UserKind>(AdminSchema(), GuestSchema())
114114
}

src/yup/index.ts

+37-42
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
3636
'\n' +
3737
new DeclarationBlock({})
3838
.asKind('function')
39-
.withName('union<T>(...schemas: ReadonlyArray<yup.SchemaOf<T>>): yup.BaseSchema<T>')
39+
.withName('union<T extends {}>(...schemas: ReadonlyArray<yup.ObjectSchema<T>>): yup.MixedSchema<T>')
4040
.withBlock(
4141
[
42-
indent('return yup.mixed().test({'),
42+
indent('return yup.mixed<T>().test({'),
4343
indent('test: (value) => schemas.some((schema) => schema.isValidSync(value))', 2),
44-
indent('})'),
44+
indent('}).defined()'),
4545
].join('\n')
4646
).string
4747
);
@@ -52,13 +52,16 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
5252
importTypes.push(name);
5353

5454
const shape = node.fields
55-
?.map(field => generateFieldYupSchema(config, tsVisitor, schema, field, 2))
55+
?.map(field => {
56+
const fieldSchema = generateFieldYupSchema(config, tsVisitor, schema, field, 2);
57+
return isNonNullType(field.type) ? fieldSchema : `${fieldSchema}.optional()`;
58+
})
5659
.join(',\n');
5760

5861
return new DeclarationBlock({})
5962
.export()
6063
.asKind('function')
61-
.withName(`${name}Schema(): yup.SchemaOf<${name}>`)
64+
.withName(`${name}Schema(): yup.ObjectSchema<${name}>`)
6265
.withBlock([indent(`return yup.object({`), shape, indent('})')].join('\n')).string;
6366
},
6467
},
@@ -68,17 +71,20 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
6871
importTypes.push(name);
6972

7073
const shape = node.fields
71-
?.map(field => generateFieldYupSchema(config, tsVisitor, schema, field, 2))
74+
?.map(field => {
75+
const fieldSchema = generateFieldYupSchema(config, tsVisitor, schema, field, 2);
76+
return isNonNullType(field.type) ? fieldSchema : `${fieldSchema}.optional()`;
77+
})
7278
.join(',\n');
7379

7480
return new DeclarationBlock({})
7581
.export()
7682
.asKind('function')
77-
.withName(`${name}Schema(): yup.SchemaOf<${name}>`)
83+
.withName(`${name}Schema(): yup.ObjectSchema<${name}>`)
7884
.withBlock(
7985
[
8086
indent(`return yup.object({`),
81-
indent(`__typename: yup.mixed().oneOf(['${node.name.value}', undefined]),`, 2),
87+
indent(`__typename: yup.string<'${node.name.value}'>().optional(),`, 2),
8288
shape,
8389
indent('})'),
8490
].join('\n')
@@ -91,13 +97,13 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
9197
importTypes.push(enumname);
9298

9399
if (config.enumsAsTypes) {
100+
const enums = node.values?.map(enumOption => `'${enumOption.name.value}'`);
101+
94102
return new DeclarationBlock({})
95103
.export()
96104
.asKind('const')
97105
.withName(`${enumname}Schema`)
98-
.withContent(
99-
`yup.mixed().oneOf([${node.values?.map(enumOption => `'${enumOption.name.value}'`).join(', ')}])`
100-
).string;
106+
.withContent(`yup.string().oneOf([${enums?.join(', ')}]).defined()`).string;
101107
}
102108

103109
const values = node.values
@@ -113,7 +119,7 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
113119
.export()
114120
.asKind('const')
115121
.withName(`${enumname}Schema`)
116-
.withContent(`yup.mixed().oneOf([${values}])`).string;
122+
.withContent(`yup.string<${enumname}>().oneOf([${values}]).defined()`).string;
117123
},
118124
},
119125
UnionTypeDefinition: {
@@ -129,7 +135,7 @@ export const YupSchemaVisitor = (schema: GraphQLSchema, config: ValidationSchema
129135
return new DeclarationBlock({})
130136
.export()
131137
.asKind('function')
132-
.withName(`${unionName}Schema(): yup.BaseSchema<${unionName}>`)
138+
.withName(`${unionName}Schema(): yup.MixedSchema<${unionName}>`)
133139
.withBlock(union).string;
134140
},
135141
},
@@ -180,22 +186,28 @@ const generateFieldTypeYupSchema = (
180186
if (isListType(type)) {
181187
const gen = generateFieldTypeYupSchema(config, tsVisitor, schema, type.type, type);
182188
if (!isNonNullType(parentType)) {
183-
return `yup.array().of(${maybeLazy(type.type, gen)}).optional()`;
189+
return `yup.array(${maybeLazy(type.type, gen)}).defined().nullable()`;
184190
}
185-
return `yup.array().of(${maybeLazy(type.type, gen)})`;
191+
return `yup.array(${maybeLazy(type.type, gen)}).defined()`;
186192
}
187193
if (isNonNullType(type)) {
188194
const gen = generateFieldTypeYupSchema(config, tsVisitor, schema, type.type, type);
189-
const nonNullGen = maybeNonEmptyString(config, tsVisitor, gen, type.type);
190-
return maybeLazy(type.type, nonNullGen);
195+
return maybeLazy(type.type, gen);
191196
}
192197
if (isNamedType(type)) {
193198
const gen = generateNameNodeYupSchema(config, tsVisitor, schema, type.name);
199+
if (isNonNullType(parentType)) {
200+
if (config.notAllowEmptyString === true) {
201+
const tsType = tsVisitor.scalars[type.name.value];
202+
if (tsType === 'string') return `${gen}.required()`;
203+
}
204+
return `${gen}.nonNullable()`;
205+
}
194206
const typ = schema.getType(type.name.value);
195-
if (typ?.astNode?.kind === 'ObjectTypeDefinition') {
196-
return `${gen}.optional()`;
207+
if (typ?.astNode?.kind === 'InputObjectTypeDefinition') {
208+
return `${gen}`;
197209
}
198-
return gen;
210+
return `${gen}.nullable()`;
199211
}
200212
console.warn('unhandled type:', type);
201213
return '';
@@ -236,40 +248,23 @@ const generateNameNodeYupSchema = (
236248
const maybeLazy = (type: TypeNode, schema: string): string => {
237249
if (isNamedType(type) && isInput(type.name.value)) {
238250
// https://github.com/jquense/yup/issues/1283#issuecomment-786559444
239-
return `yup.lazy(() => ${schema}) as never`;
251+
return `yup.lazy(() => ${schema})`;
240252
}
241253
return schema;
242254
};
243255

244-
const maybeNonEmptyString = (
245-
config: ValidationSchemaPluginConfig,
246-
tsVisitor: TsVisitor,
247-
schema: string,
248-
childType: TypeNode
249-
): string => {
250-
if (config.notAllowEmptyString === true && isNamedType(childType)) {
251-
const maybeScalarName = childType.name.value;
252-
const tsType = tsVisitor.scalars[maybeScalarName];
253-
if (tsType === 'string') {
254-
return `${schema}.required()`;
255-
}
256-
}
257-
// fallback
258-
return `${schema}.defined()`;
259-
};
260-
261256
const yup4Scalar = (config: ValidationSchemaPluginConfig, tsVisitor: TsVisitor, scalarName: string): string => {
262257
if (config.scalarSchemas?.[scalarName]) {
263-
return config.scalarSchemas[scalarName];
258+
return `${config.scalarSchemas[scalarName]}.defined()`;
264259
}
265260
const tsType = tsVisitor.scalars[scalarName];
266261
switch (tsType) {
267262
case 'string':
268-
return `yup.string()`;
263+
return `yup.string().defined()`;
269264
case 'number':
270-
return `yup.number()`;
265+
return `yup.number().defined()`;
271266
case 'boolean':
272-
return `yup.boolean()`;
267+
return `yup.boolean().defined()`;
273268
}
274269
console.warn('unhandled name:', scalarName);
275270
return `yup.mixed()`;

0 commit comments

Comments
 (0)