Skip to content

Commit 8fc3c7d

Browse files
committed
feat: allows for passthrough of a default/fallback scalar type
1 parent 4cca198 commit 8fc3c7d

File tree

9 files changed

+180
-0
lines changed

9 files changed

+180
-0
lines changed

src/config.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,24 @@ export interface ValidationSchemaPluginConfig extends TypeScriptPluginConfig {
176176
* ```
177177
*/
178178
scalarSchemas?: ScalarSchemas
179+
/**
180+
* @description Fallback scalar type for undefined scalar types in the schema not found in `scalarSchemas`.
181+
*
182+
* @exampleMarkdown
183+
* ```yml
184+
* config:
185+
* schema: yup
186+
* defaultScalarSchema: yup.unknown()
187+
* ```
188+
*
189+
* @exampleMarkdown
190+
* ```yml
191+
* config:
192+
* schema: zod
193+
* defaultScalarSchema: z.unknown()
194+
* ```
195+
*/
196+
defaultScalarTypeSchema?: string
179197
/**
180198
* @description Generates validation schema with GraphQL type objects.
181199
* but excludes "Query", "Mutation", "Subscription" objects.

src/myzod/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,11 @@ function myzod4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor, sc
374374
case 'boolean':
375375
return `myzod.boolean()`;
376376
}
377+
378+
if (config.defaultScalarTypeSchema) {
379+
return config.defaultScalarTypeSchema;
380+
}
381+
377382
console.warn('unhandled name:', scalarName);
378383
return anySchema;
379384
}

src/valibot/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@ function valibot4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor,
294294
case 'boolean':
295295
return `v.boolean()`;
296296
}
297+
298+
if (config.defaultScalarTypeSchema) {
299+
return config.defaultScalarTypeSchema;
300+
}
301+
297302
console.warn('unhandled scalar name:', scalarName);
298303
return 'v.any()';
299304
}

src/yup/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,11 @@ function yup4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor, scal
396396
case 'boolean':
397397
return `yup.boolean().defined()`;
398398
}
399+
400+
if (config.defaultScalarTypeSchema) {
401+
return config.defaultScalarTypeSchema
402+
}
403+
399404
console.warn('unhandled name:', scalarName);
400405
return `yup.mixed()`;
401406
}

src/zod/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,11 @@ function zod4Scalar(config: ValidationSchemaPluginConfig, visitor: Visitor, scal
390390
case 'boolean':
391391
return `z.boolean()`;
392392
}
393+
394+
if (config.defaultScalarTypeSchema) {
395+
return config.defaultScalarTypeSchema;
396+
}
397+
393398
console.warn('unhandled scalar name:', scalarName);
394399
return anySchema;
395400
}

tests/myzod.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,41 @@ describe('myzod', () => {
467467
"
468468
`)
469469
});
470+
471+
it('with defaultScalarTypeSchema', async () => {
472+
const schema = buildSchema(/* GraphQL */ `
473+
input ScalarsInput {
474+
date: Date!
475+
email: Email
476+
str: String!
477+
}
478+
scalar Date
479+
scalar Email
480+
`);
481+
const result = await plugin(
482+
schema,
483+
[],
484+
{
485+
schema: 'myzod',
486+
scalarSchemas: {
487+
Email: 'myzod.string()', // generate the basic type. User can later extend it using `withPredicate(fn: (val: string) => boolean), errMsg?: string }`
488+
},
489+
defaultScalarTypeSchema: 'myzod.string()',
490+
},
491+
{},
492+
);
493+
expect(removedInitialEmitValue(result.content)).toMatchInlineSnapshot(`
494+
"
495+
export function ScalarsInputSchema(): myzod.Type<ScalarsInput> {
496+
return myzod.object({
497+
date: myzod.string(),
498+
email: myzod.string().optional().nullable(),
499+
str: myzod.string()
500+
})
501+
}
502+
"
503+
`)
504+
});
470505
it('with typesPrefix', async () => {
471506
const schema = buildSchema(/* GraphQL */ `
472507
input Say {

tests/valibot.spec.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,43 @@ describe('valibot', () => {
338338
"
339339
`)
340340
});
341+
342+
it('with defaultScalarTypeSchema', async () => {
343+
const schema = buildSchema(/* GraphQL */ `
344+
input ScalarsInput {
345+
date: Date!
346+
email: Email
347+
str: String!
348+
}
349+
scalar Date
350+
scalar Email
351+
`);
352+
const result = await plugin(
353+
schema,
354+
[],
355+
{
356+
schema: 'valibot',
357+
scalarSchemas: {
358+
Email: 'v.string([v.email()])',
359+
},
360+
defaultScalarTypeSchema: 'v.string()',
361+
},
362+
{},
363+
);
364+
expect(result.content).toMatchInlineSnapshot(`
365+
"
366+
367+
export function ScalarsInputSchema(): v.GenericSchema<ScalarsInput> {
368+
return v.object({
369+
date: v.string(),
370+
email: v.nullish(v.string([v.email()])),
371+
str: v.string()
372+
})
373+
}
374+
"
375+
`)
376+
});
377+
341378
it.todo('with typesPrefix')
342379
it.todo('with typesSuffix')
343380
it.todo('with default input values')

tests/yup.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,41 @@ describe('yup', () => {
472472
`)
473473
});
474474

475+
it('with defaultScalarTypeSchema', async () => {
476+
const schema = buildSchema(/* GraphQL */ `
477+
input ScalarsInput {
478+
date: Date!
479+
email: Email
480+
str: String!
481+
}
482+
scalar Date
483+
scalar Email
484+
`);
485+
const result = await plugin(
486+
schema,
487+
[],
488+
{
489+
scalarSchemas: {
490+
Email: 'yup.string().email()',
491+
},
492+
defaultScalarTypeSchema: 'yup.string()',
493+
},
494+
{},
495+
);
496+
expect(result.content).toMatchInlineSnapshot(`
497+
"
498+
499+
export function ScalarsInputSchema(): yup.ObjectSchema<ScalarsInput> {
500+
return yup.object({
501+
date: yup.string().nonNullable(),
502+
email: yup.string().email().defined().nullable().optional(),
503+
str: yup.string().defined().nonNullable()
504+
})
505+
}
506+
"
507+
`)
508+
});
509+
475510
it('with typesPrefix', async () => {
476511
const schema = buildSchema(/* GraphQL */ `
477512
input Say {

tests/zod.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,41 @@ describe('zod', () => {
464464
`)
465465
});
466466

467+
it('with defaultScalarTypeSchema', async () => {
468+
const schema = buildSchema(/* GraphQL */ `
469+
input ScalarsInput {
470+
date: Date!
471+
email: Email
472+
str: String!
473+
}
474+
scalar Date
475+
scalar Email
476+
`);
477+
const result = await plugin(
478+
schema,
479+
[],
480+
{
481+
schema: 'zod',
482+
scalarSchemas: {
483+
Email: 'z.string().email()',
484+
},
485+
defaultScalarTypeSchema: 'z.string()',
486+
},
487+
{},
488+
);
489+
expect(removedInitialEmitValue(result.content)).toMatchInlineSnapshot(`
490+
"
491+
export function ScalarsInputSchema(): z.ZodObject<Properties<ScalarsInput>> {
492+
return z.object({
493+
date: z.string(),
494+
email: z.string().email().nullish(),
495+
str: z.string()
496+
})
497+
}
498+
"
499+
`)
500+
});
501+
467502
it('with typesPrefix', async () => {
468503
const schema = buildSchema(/* GraphQL */ `
469504
input Say {

0 commit comments

Comments
 (0)