Skip to content

Commit 770295f

Browse files
committedMay 14, 2024
feat(hono): add validator option
1 parent 692f749 commit 770295f

File tree

8 files changed

+132
-47
lines changed

8 files changed

+132
-47
lines changed
 

‎packages/core/src/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ export type OverrideOutputContentType = {
361361

362362
export type NormalizedHonoOptions = {
363363
handlers?: string;
364+
validator: boolean | 'hono';
364365
};
365366

366367
export type ZodOptions = {
@@ -415,6 +416,7 @@ export type NormalizedZodOptions = {
415416

416417
export type HonoOptions = {
417418
handlers?: string;
419+
validator?: boolean | 'hono';
418420
};
419421

420422
export type NormalizedQueryOptions = {

‎packages/hono/src/index.ts

+116-43
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
jsDoc,
1919
generateMutatorImports,
2020
GeneratorMutator,
21+
NormalizedMutator,
2122
} from '@orval/core';
2223
import { getRoute } from './route';
2324
import fs from 'fs-extra';
@@ -54,7 +55,7 @@ export const getHonoHeader: ClientHeaderBuilder = ({
5455

5556
let handlers = '';
5657

57-
if (output.override.hono?.handlers) {
58+
if (output.override.hono.handlers) {
5859
const handlerFileInfo = getFileInfo(output.override.hono.handlers);
5960
handlers = Object.values(verbOptions)
6061
.filter((verbOption) =>
@@ -117,40 +118,48 @@ const getHonoHandlers = ({
117118
handlerName,
118119
contextTypeName,
119120
verbOption,
121+
validator,
120122
}: {
121123
handlerName: string;
122124
contextTypeName: string;
123125
verbOption: GeneratorVerbOptions;
126+
validator: boolean | 'hono' | NormalizedMutator;
124127
}) => {
128+
let currentValidator = '';
129+
130+
if (validator) {
131+
if (verbOption.headers) {
132+
currentValidator += `zValidator('header', ${verbOption.operationName}Header),\n`;
133+
}
134+
if (verbOption.params.length) {
135+
currentValidator += `zValidator('param', ${verbOption.operationName}Params),\n`;
136+
}
137+
if (verbOption.queryParams) {
138+
currentValidator += `zValidator('query', ${verbOption.operationName}QueryParams),\n`;
139+
}
140+
if (verbOption.body.definition) {
141+
currentValidator += `zValidator('json', ${verbOption.operationName}Body),\n`;
142+
}
143+
if (
144+
validator !== 'hono' &&
145+
verbOption.response.originalSchema?.['200']?.content?.['application/json']
146+
) {
147+
currentValidator += `zValidator('response', ${verbOption.operationName}Response),\n`;
148+
}
149+
}
150+
125151
return `
126152
export const ${handlerName} = factory.createHandlers(
127-
${
128-
verbOption.headers
129-
? `zValidator('header', ${verbOption.operationName}Header),\n`
130-
: ''
131-
}${
132-
verbOption.params.length
133-
? `zValidator('param', ${verbOption.operationName}Params),\n`
134-
: ''
135-
}${
136-
verbOption.queryParams
137-
? `zValidator('query', ${verbOption.operationName}QueryParams),\n`
138-
: ''
139-
}${
140-
verbOption.body.definition
141-
? `zValidator('json', ${verbOption.operationName}Body),\n`
142-
: ''
143-
}${
144-
!!verbOption.response.originalSchema?.['200']?.content?.['application/json']
145-
? `zValidator('response', ${verbOption.operationName}Response),\n`
146-
: ''
147-
}async (c: ${contextTypeName}) => {
153+
${currentValidator}async (c: ${contextTypeName}) => {
148154
149155
},
150156
);`;
151157
};
152158

153-
const getZvalidatorImports = (verbOption: GeneratorVerbOptions) => {
159+
const getZvalidatorImports = (
160+
verbOption: GeneratorVerbOptions,
161+
isHonoValidator: boolean,
162+
) => {
154163
let imports = [];
155164

156165
if (verbOption.headers) {
@@ -170,6 +179,7 @@ const getZvalidatorImports = (verbOption: GeneratorVerbOptions) => {
170179
}
171180

172181
if (
182+
!isHonoValidator &&
173183
!!verbOption.response.originalSchema?.['200']?.content?.['application/json']
174184
) {
175185
imports.push(`${verbOption.operationName}Response`);
@@ -238,6 +248,7 @@ const generateHandlers = async (
238248
handlerName,
239249
contextTypeName,
240250
verbOption,
251+
validator: output.override.hono.validator,
241252
});
242253
}
243254

@@ -247,20 +258,34 @@ const generateHandlers = async (
247258
};
248259
}
249260

250-
const content = `import { createFactory } from 'hono/factory';${
251-
hasZValidator
252-
? `\nimport { zValidator } from '${outputPath}.validator';`
253-
: ''
261+
let validatorImport = '';
262+
263+
if (hasZValidator) {
264+
if (output.override.hono.validator === true) {
265+
validatorImport = `\nimport { zValidator } from '${outputPath}.validator';`;
266+
} else if (output.override.hono.validator === 'hono') {
267+
validatorImport = `\nimport { zValidator } from '@hono/zod-validator';`;
268+
}
254269
}
270+
271+
const zodImports = output.override.hono.validator
272+
? `import { ${getZvalidatorImports(
273+
verbOption,
274+
output.override.hono.validator === 'hono',
275+
)} } from '${outputPath}.zod';`
276+
: '';
277+
278+
const content = `import { createFactory } from 'hono/factory';${validatorImport}
255279
import { ${contextTypeName} } from '${outputPath}.context';
256-
import { ${getZvalidatorImports(verbOption)} } from '${outputPath}.zod';
280+
${zodImports}
257281
258282
const factory = createFactory();
259283
260284
${getHonoHandlers({
261285
handlerName,
262286
contextTypeName,
263287
verbOption,
288+
validator: output.override.hono.validator,
264289
})}
265290
`;
266291

@@ -307,6 +332,7 @@ ${getHonoHandlers({
307332
handlerName,
308333
contextTypeName,
309334
verbOption,
335+
validator: output.override.hono.validator,
310336
});
311337
}
312338

@@ -321,17 +347,32 @@ ${getHonoHandlers({
321347

322348
const outputRelativePath = `./${kebab(tag)}`;
323349

324-
let content = `import { createFactory } from 'hono/factory';${
325-
hasZValidator
326-
? `\nimport { zValidator } from '${outputRelativePath}.validator';`
327-
: ''
350+
let validatorImport = '';
351+
352+
if (hasZValidator) {
353+
if (output.override.hono.validator === true) {
354+
validatorImport = `\nimport { zValidator } from '${outputRelativePath}.validator';`;
355+
} else if (output.override.hono.validator === 'hono') {
356+
validatorImport = `\nimport { zValidator } from '@hono/zod-validator';`;
357+
}
328358
}
359+
360+
const zodImports = output.override.hono.validator
361+
? `import { ${Object.values(verbs)
362+
.map((verb) =>
363+
getZvalidatorImports(
364+
verb,
365+
output.override.hono.validator === 'hono',
366+
),
367+
)
368+
.join(',\n')} } from '${outputRelativePath}.zod'`
369+
: '';
370+
371+
let content = `import { createFactory } from 'hono/factory';${validatorImport}
329372
import { ${Object.values(verbs)
330373
.map((verb) => `${pascal(verb.operationName)}Context`)
331374
.join(',\n')} } from '${outputRelativePath}.context';
332-
import { ${Object.values(verbs)
333-
.map((verb) => getZvalidatorImports(verb))
334-
.join(',\n')} } from '${outputRelativePath}.zod';
375+
${zodImports};
335376
336377
const factory = createFactory();`;
337378

@@ -343,6 +384,7 @@ const factory = createFactory();`;
343384
handlerName,
344385
contextTypeName,
345386
verbOption,
387+
validator: output.override.hono.validator,
346388
});
347389

348390
return acc;
@@ -383,6 +425,7 @@ const factory = createFactory();`;
383425
handlerName,
384426
contextTypeName,
385427
verbOption,
428+
validator: output.override.hono.validator,
386429
});
387430
}
388431

@@ -399,17 +442,29 @@ const factory = createFactory();`;
399442

400443
const outputRelativePath = `./${filename}`;
401444

402-
let content = `import { createFactory } from 'hono/factory';${
403-
hasZValidator
404-
? `\nimport { zValidator } from '${outputRelativePath}.validator';`
405-
: ''
445+
let validatorImport = '';
446+
447+
if (hasZValidator) {
448+
if (output.override.hono.validator === true) {
449+
validatorImport = `\nimport { zValidator } from '${outputRelativePath}.validator';`;
450+
} else if (output.override.hono.validator === 'hono') {
451+
validatorImport = `\nimport { zValidator } from '@hono/zod-validator';`;
452+
}
406453
}
454+
455+
const zodImports = output.override.hono.validator
456+
? `import { ${Object.values(verbOptions)
457+
.map((verb) =>
458+
getZvalidatorImports(verb, output.override.hono.validator === 'hono'),
459+
)
460+
.join(',\n')} } from '${outputRelativePath}.zod';`
461+
: '';
462+
463+
let content = `import { createFactory } from 'hono/factory';${validatorImport}
407464
import { ${Object.values(verbOptions)
408465
.map((verb) => `${pascal(verb.operationName)}Context`)
409466
.join(',\n')} } from '${outputRelativePath}.context';
410-
import { ${Object.values(verbOptions)
411-
.map((verb) => getZvalidatorImports(verb))
412-
.join(',\n')} } from '${outputRelativePath}.zod';
467+
${zodImports}
413468
414469
const factory = createFactory();`;
415470

@@ -421,6 +476,7 @@ const factory = createFactory();`;
421476
handlerName,
422477
contextTypeName,
423478
verbOption,
479+
validator: output.override.hono.validator,
424480
});
425481

426482
return acc;
@@ -805,6 +861,13 @@ export const zValidator =
805861
}
806862
} else {
807863
await next();
864+
865+
if (
866+
c.res.status !== 200 ||
867+
c.res.headers.get('Content-Type') !== 'application/json'
868+
) {
869+
return;
870+
}
808871
809872
const clonedResponse = c.res.clone();
810873
@@ -814,6 +877,8 @@ export const zValidator =
814877
} catch {
815878
const message = 'Malformed JSON in response';
816879
c.res = new Response(message, { status: 400 });
880+
881+
return;
817882
}
818883
819884
const result = await schema.safeParseAsync(value);
@@ -874,7 +939,15 @@ export const generateExtraFiles: ClientExtraFilesBuilder = async (
874939
generateZvalidator(output, context),
875940
]);
876941

877-
return [...handlers, ...contexts, ...zods, validator];
942+
return [
943+
...handlers,
944+
...contexts,
945+
...zods,
946+
...(output.override.hono.validator &&
947+
output.override.hono.validator !== 'hono'
948+
? [validator]
949+
: []),
950+
];
878951
};
879952

880953
const honoClientBuilder: ClientGeneratorsBuilder = {

‎packages/orval/src/utils/options.ts

+1
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,7 @@ const normalizeHonoOptions = (
544544
...(hono.handlers
545545
? { handlers: upath.resolve(workspace, hono.handlers) }
546546
: {}),
547+
validator: hono.validator ?? true,
547548
};
548549
};
549550

‎samples/hono/src/handlers/createPets.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ const factory = createFactory();
88
export const createPetsHandlers = factory.createHandlers(
99
zValidator('json', createPetsBody),
1010
zValidator('response', createPetsResponse),
11-
(c: CreatePetsContext) => {},
11+
async (c: CreatePetsContext) => {},
1212
);

‎samples/hono/src/handlers/listPets.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ const factory = createFactory();
88
export const listPetsHandlers = factory.createHandlers(
99
zValidator('query', listPetsQueryParams),
1010
zValidator('response', listPetsResponse),
11-
(c: ListPetsContext) => {},
11+
async (c: ListPetsContext) => {},
1212
);

‎samples/hono/src/handlers/showPetById.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ const factory = createFactory();
88
export const showPetByIdHandlers = factory.createHandlers(
99
zValidator('param', showPetByIdParams),
1010
zValidator('response', showPetByIdResponse),
11-
(c: ShowPetByIdContext) => {},
11+
async (c: ShowPetByIdContext) => {},
1212
);

‎samples/hono/src/handlers/updatePets.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ const factory = createFactory();
88
export const updatePetsHandlers = factory.createHandlers(
99
zValidator('json', updatePetsBody),
1010
zValidator('response', updatePetsResponse),
11-
(c: UpdatePetsContext) => {},
11+
async (c: UpdatePetsContext) => {},
1212
);

‎samples/hono/src/petstore.validator.ts

+9
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ export const zValidator =
9292
} else {
9393
await next();
9494

95+
if (
96+
c.res.status !== 200 ||
97+
c.res.headers.get('Content-Type') !== 'application/json'
98+
) {
99+
return;
100+
}
101+
95102
const clonedResponse = c.res.clone();
96103

97104
let value: unknown;
@@ -100,6 +107,8 @@ export const zValidator =
100107
} catch {
101108
const message = 'Malformed JSON in response';
102109
c.res = new Response(message, { status: 400 });
110+
111+
return;
103112
}
104113

105114
const result = await schema.safeParseAsync(value);

0 commit comments

Comments
 (0)
Please sign in to comment.