Skip to content

Commit 3cddea4

Browse files
committed
feat: support directives
1 parent b7bdcae commit 3cddea4

File tree

2 files changed

+89
-4
lines changed

2 files changed

+89
-4
lines changed

src/valibot/index.ts

+16-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
isNamedType,
1919
isNonNullType,
2020
} from './../graphql';
21+
import { buildApi, buildApiForValibot, formatDirectiveConfig } from 'src/directive';
2122

2223
export class ValibotSchemaVisitor extends BaseSchemaVisitor {
2324
constructor(schema: GraphQLSchema, config: ValidationSchemaPluginConfig) {
@@ -118,28 +119,39 @@ function generateFieldTypeValibotSchema(config: ValidationSchemaPluginConfig, vi
118119
if (isListType(parentType))
119120
return `v.nullable(${gen})`;
120121

122+
let appliedDirectivesGen = applyDirectives(config, field, gen);
123+
121124
if (field.kind === Kind.INPUT_VALUE_DEFINITION) {
122125
const { defaultValue } = field;
123126
if (defaultValue?.kind === Kind.INT || defaultValue?.kind === Kind.FLOAT || defaultValue?.kind === Kind.BOOLEAN)
124-
gen = `v.optional(${gen}, ${defaultValue.value})`;
127+
appliedDirectivesGen = `v.optional(${appliedDirectivesGen}, ${defaultValue.value})`;
125128

126129
if (defaultValue?.kind === Kind.STRING || defaultValue?.kind === Kind.ENUM)
127-
gen = `v.optional(${gen}, "${defaultValue.value}")`;
130+
appliedDirectivesGen = `v.optional(${appliedDirectivesGen}, "${defaultValue.value}")`;
128131

129132
}
130133
if (isNonNullType(parentType)) {
131134
if (visitor.shouldEmitAsNotAllowEmptyString(type.name.value))
132135
return "v.string([v.minLength(1)])"; // TODO
133136

134-
return gen;
137+
return appliedDirectivesGen;
135138
}
136139

137-
return `v.nullish(${gen})`;
140+
return `v.nullish(${appliedDirectivesGen})`;
138141
}
139142
console.warn('unhandled type:', type);
140143
return '';
141144
}
142145

146+
function applyDirectives(config: ValidationSchemaPluginConfig, field: InputValueDefinitionNode | FieldDefinitionNode, gen: string): string {
147+
if (config.directives && field.directives) {
148+
const formatted = formatDirectiveConfig(config.directives);
149+
// TODO: handle other scalar
150+
return `v.string([${buildApiForValibot(formatted, field.directives).join('')}])`;
151+
}
152+
return gen;
153+
}
154+
143155
function generateNameNodeValibotSchema(config: ValidationSchemaPluginConfig, visitor: Visitor, node: NameNode): string {
144156
const converter = visitor.getNameNodeConverter(node);
145157

tests/valibot.spec.ts

+73
Original file line numberDiff line numberDiff line change
@@ -366,4 +366,77 @@ describe('valibot', () => {
366366
"
367367
`)
368368
});
369+
370+
describe('issues #19', () => {
371+
it('string field', async () => {
372+
const schema = buildSchema(/* GraphQL */ `
373+
input UserCreateInput {
374+
profile: String @constraint(minLength: 1, maxLength: 5000)
375+
}
376+
377+
directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION
378+
`);
379+
const result = await plugin(
380+
schema,
381+
[],
382+
{
383+
schema: 'valibot',
384+
directives: {
385+
constraint: {
386+
minLength: ['minLength', '$1', 'Please input more than $1'],
387+
maxLength: ['maxLength', '$1', 'Please input less than $1'],
388+
},
389+
},
390+
},
391+
{},
392+
);
393+
expect(result.content).toMatchInlineSnapshot(`
394+
"
395+
396+
export function UserCreateInputSchema() {
397+
return v.object({
398+
profile: v.nullish(v.string([v.minLength(1, "Please input more than 1"), v.maxLength(5000, "Please input less than 5000")]))
399+
})
400+
}
401+
"
402+
`)
403+
});
404+
405+
it('not null field', async () => {
406+
const schema = buildSchema(/* GraphQL */ `
407+
input UserCreateInput {
408+
profile: String! @constraint(minLength: 1, maxLength: 5000)
409+
}
410+
411+
directive @constraint(minLength: Int!, maxLength: Int!) on INPUT_FIELD_DEFINITION
412+
`);
413+
const result = await plugin(
414+
schema,
415+
[],
416+
{
417+
schema: 'valibot',
418+
directives: {
419+
constraint: {
420+
minLength: ['minLength', '$1', 'Please input more than $1'],
421+
maxLength: ['maxLength', '$1', 'Please input less than $1'],
422+
},
423+
},
424+
},
425+
{},
426+
);
427+
428+
expect(result.content).toMatchInlineSnapshot(`
429+
"
430+
431+
export function UserCreateInputSchema() {
432+
return v.object({
433+
profile: v.string([v.minLength(1, "Please input more than 1"), v.maxLength(5000, "Please input less than 5000")])
434+
})
435+
}
436+
"
437+
`)
438+
});
439+
440+
it.todo('list field');
441+
})
369442
})

0 commit comments

Comments
 (0)