Skip to content

Commit 83e8a0a

Browse files
authored
Merge pull request #18 from Code-Hex/add/scalarSchemas-option
added a new option scalarSchemas
2 parents 8105f2b + b927527 commit 83e8a0a

File tree

6 files changed

+134
-6
lines changed

6 files changed

+134
-6
lines changed

README.md

+26
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,32 @@ type: `boolean` default: `false`
9191

9292
Generates validation string schema as do not allow empty characters by default.
9393

94+
### `scalarSchemas`
95+
96+
type: `ScalarSchemas`
97+
98+
Extends or overrides validation schema for the built-in scalars and custom GraphQL scalars.
99+
100+
#### yup schema
101+
102+
```yml
103+
config:
104+
schema: yup
105+
scalarSchemas:
106+
Date: yup.date()
107+
Email: yup.string().email()
108+
```
109+
110+
#### zod schema
111+
112+
```yml
113+
config:
114+
schema: zod
115+
scalarSchemas:
116+
Date: z.date()
117+
Email: z.string().email()
118+
```
119+
94120
### `directives`
95121

96122
type: `DirectiveConfig`

src/config.ts

+26
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export interface DirectiveObjectArguments {
1212
[matched: string]: string | string[];
1313
}
1414

15+
interface ScalarSchemas {
16+
[name: string]: string;
17+
}
18+
1519
export interface ValidationSchemaPluginConfig extends TypeScriptPluginConfig {
1620
/**
1721
* @description specify generate schema
@@ -88,6 +92,28 @@ export interface ValidationSchemaPluginConfig extends TypeScriptPluginConfig {
8892
* ```
8993
*/
9094
notAllowEmptyString?: boolean;
95+
/**
96+
* @description Extends or overrides validation schema for the built-in scalars and custom GraphQL scalars.
97+
*
98+
* @exampleMarkdown
99+
* ```yml
100+
* config:
101+
* schema: yup
102+
* scalarSchemas:
103+
* Date: yup.date()
104+
* Email: yup.string().email()
105+
* ```
106+
*
107+
* @exampleMarkdown
108+
* ```yml
109+
* config:
110+
* schema: zod
111+
* scalarSchemas:
112+
* Date: z.date()
113+
* Email: z.string().email()
114+
* ```
115+
*/
116+
scalarSchemas?: ScalarSchemas;
91117
/**
92118
* @description Generates validation schema with more API based on directive schema.
93119
* @exampleMarkdown

src/yup/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ const generateNameNodeYupSchema = (
151151
return `${enumName}Schema`;
152152
}
153153

154-
const primitive = yup4Scalar(tsVisitor, node.value);
154+
const primitive = yup4Scalar(config, tsVisitor, node.value);
155155
return primitive;
156156
};
157157

@@ -180,7 +180,10 @@ const maybeNonEmptyString = (
180180
return `${schema}.defined()`;
181181
};
182182

183-
const yup4Scalar = (tsVisitor: TsVisitor, scalarName: string): string => {
183+
const yup4Scalar = (config: ValidationSchemaPluginConfig, tsVisitor: TsVisitor, scalarName: string): string => {
184+
if (config.scalarSchemas?.[scalarName]) {
185+
return config.scalarSchemas[scalarName];
186+
}
184187
const tsType = tsVisitor.scalars[scalarName];
185188
switch (tsType) {
186189
case 'string':

src/zod/index.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ const generateInputObjectFieldTypeZodSchema = (
114114
return maybeLazy(type.type, gen);
115115
}
116116
if (isNamedType(type)) {
117-
const gen = generateNameNodeZodSchema(tsVisitor, schema, type.name);
117+
const gen = generateNameNodeZodSchema(config, tsVisitor, schema, type.name);
118118
if (isNonNullType(parentType)) {
119119
if (config.notAllowEmptyString === true) {
120120
const tsType = tsVisitor.scalars[type.name.value];
@@ -131,7 +131,12 @@ const generateInputObjectFieldTypeZodSchema = (
131131
return '';
132132
};
133133

134-
const generateNameNodeZodSchema = (tsVisitor: TsVisitor, schema: GraphQLSchema, node: NameNode): string => {
134+
const generateNameNodeZodSchema = (
135+
config: ValidationSchemaPluginConfig,
136+
tsVisitor: TsVisitor,
137+
schema: GraphQLSchema,
138+
node: NameNode
139+
): string => {
135140
const typ = schema.getType(node.value);
136141

137142
if (typ && typ.astNode?.kind === 'InputObjectTypeDefinition') {
@@ -144,7 +149,7 @@ const generateNameNodeZodSchema = (tsVisitor: TsVisitor, schema: GraphQLSchema,
144149
return `${enumName}Schema`;
145150
}
146151

147-
return zod4Scalar(tsVisitor, node.value);
152+
return zod4Scalar(config, tsVisitor, node.value);
148153
};
149154

150155
const maybeLazy = (type: TypeNode, schema: string): string => {
@@ -154,7 +159,10 @@ const maybeLazy = (type: TypeNode, schema: string): string => {
154159
return schema;
155160
};
156161

157-
const zod4Scalar = (tsVisitor: TsVisitor, scalarName: string): string => {
162+
const zod4Scalar = (config: ValidationSchemaPluginConfig, tsVisitor: TsVisitor, scalarName: string): string => {
163+
if (config.scalarSchemas?.[scalarName]) {
164+
return config.scalarSchemas[scalarName];
165+
}
158166
const tsType = tsVisitor.scalars[scalarName];
159167
switch (tsType) {
160168
case 'string':

tests/yup.spec.ts

+32
Original file line numberDiff line numberDiff line change
@@ -243,4 +243,36 @@ describe('yup', () => {
243243
expect(result.content).toContain(wantContain);
244244
}
245245
});
246+
247+
it('with scalarSchemas', async () => {
248+
const schema = buildSchema(/* GraphQL */ `
249+
input ScalarsInput {
250+
date: Date!
251+
email: Email
252+
str: String!
253+
}
254+
scalar Date
255+
scalar Email
256+
`);
257+
const result = await plugin(
258+
schema,
259+
[],
260+
{
261+
scalarSchemas: {
262+
Date: 'yup.date()',
263+
Email: 'yup.string().email()',
264+
},
265+
},
266+
{}
267+
);
268+
const wantContains = [
269+
'export function ScalarsInputSchema(): yup.SchemaOf<ScalarsInput>',
270+
'date: yup.date().defined(),',
271+
'email: yup.string().email(),',
272+
'str: yup.string().defined()',
273+
];
274+
for (const wantContain of wantContains) {
275+
expect(result.content).toContain(wantContain);
276+
}
277+
});
246278
});

tests/zod.spec.ts

+33
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,37 @@ describe('zod', () => {
247247
expect(result.content).toContain(wantContain);
248248
}
249249
});
250+
251+
it('with scalarSchemas', async () => {
252+
const schema = buildSchema(/* GraphQL */ `
253+
input ScalarsInput {
254+
date: Date!
255+
email: Email
256+
str: String!
257+
}
258+
scalar Date
259+
scalar Email
260+
`);
261+
const result = await plugin(
262+
schema,
263+
[],
264+
{
265+
schema: 'zod',
266+
scalarSchemas: {
267+
Date: 'z.date()',
268+
Email: 'z.string().email()',
269+
},
270+
},
271+
{}
272+
);
273+
const wantContains = [
274+
'export function ScalarsInputSchema(): z.ZodSchema<ScalarsInput>',
275+
'date: z.date(),',
276+
'email: z.string().email().nullish(),',
277+
'str: z.string()',
278+
];
279+
for (const wantContain of wantContains) {
280+
expect(result.content).toContain(wantContain);
281+
}
282+
});
250283
});

0 commit comments

Comments
 (0)