Skip to content

Commit 77889a7

Browse files
committed
feat: Add typia validation adapter
This commit introduces a new validation adapter for the 'typia' library. The adapter is implemented in 'src/lib/adapters/typia.ts'. It includes functions for both server-side and client-side validation. The implementation also includes a test case in 'src/tests/superValidate.test.ts' to ensure the adapter works as expected.
1 parent 5d6331e commit 77889a7

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

src/lib/adapters/adapters.ts

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export type ValidationLibrary =
2424
| 'joi'
2525
| 'superform'
2626
| 'typebox'
27+
| 'typia'
2728
| 'valibot'
2829
| 'yup'
2930
| 'zod'

src/lib/adapters/typia.ts

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import type { IValidation } from 'typia';
2+
import {
3+
type ValidationAdapter,
4+
type ValidationIssue,
5+
type RequiredDefaultsOptions,
6+
createAdapter,
7+
type ClientValidationAdapter,
8+
type ValidationResult,
9+
createJsonSchema
10+
} from './adapters.js';
11+
import { memoize } from '$lib/memoize.js';
12+
13+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
14+
type Validation<O = any> = (input: unknown) => IValidation<O>;
15+
type OutputType<T> = T extends Validation<infer O> ? O : never;
16+
17+
async function _validate<T extends Validation>(
18+
validate: T,
19+
data: unknown
20+
): Promise<ValidationResult<OutputType<T>>> {
21+
const result = validate(data);
22+
if (result.success) {
23+
return {
24+
data: result.data,
25+
success: true
26+
};
27+
}
28+
29+
const issues: ValidationIssue[] = [];
30+
for (const { expected, value, path } of result.errors) {
31+
issues.push({
32+
path: [path.replace('$input.', '')],
33+
message: JSON.stringify({ expected, value })
34+
});
35+
}
36+
37+
return {
38+
issues,
39+
success: false
40+
};
41+
}
42+
43+
function _typia<T extends Validation>(
44+
validate: T,
45+
options: RequiredDefaultsOptions<OutputType<T>>
46+
): ValidationAdapter<OutputType<T>> {
47+
return createAdapter({
48+
superFormValidationLibrary: 'typia',
49+
defaults: options.defaults,
50+
jsonSchema: createJsonSchema(options),
51+
validate: async (data) => _validate(validate, data)
52+
});
53+
}
54+
55+
function _typiaClient<T extends Validation>(
56+
validate: T
57+
): ClientValidationAdapter<ReturnType<typeof _validate<T>>> {
58+
return {
59+
superFormValidationLibrary: 'typia',
60+
validate: async (data) => _validate(validate, data)
61+
};
62+
}
63+
64+
export const typia = /* @__PURE__ */ memoize(_typia);
65+
export const typiaClient = /* @__PURE__ */ memoize(_typiaClient);

src/tests/superValidate.test.ts

+21
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ import Vine from '@vinejs/vine';
4949

5050
import { schemasafe } from '$lib/adapters/schemasafe.js';
5151

52+
import { typia as typiaAdapter } from '$lib/adapters/typia.js';
53+
import typia, { type tags } from 'typia';
54+
5255
import { traversePath } from '$lib/traversal.js';
5356
import { splitPath } from '$lib/stringPath.js';
5457
import { SchemaError, type JSONSchema } from '$lib/index.js';
@@ -457,6 +460,24 @@ describe('ajv', () => {
457460

458461
/////////////////////////////////////////////////////////////////////
459462

463+
describe('typia', () => {
464+
interface Schema extends Record<string, unknown> {
465+
name: string;
466+
email: string & tags.Format<'email'>;
467+
tags: (string & tags.MinLength<2>)[] & tags.MinItems<3>;
468+
score: number & tags.Type<'uint32'> & tags.Minimum<0>;
469+
date?: Date;
470+
nospace?: string & tags.Pattern<'^\\S*$'>;
471+
extra: string | null;
472+
}
473+
474+
const validate = typia.createValidate<Schema>();
475+
const adapter = typiaAdapter(validate, { defaults });
476+
schemaTest(adapter, ['email', 'nospace', 'tags'], 'simple');
477+
});
478+
479+
/////////////////////////////////////////////////////////////////////
480+
460481
describe('Zod', () => {
461482
const schema = z
462483
.object({

0 commit comments

Comments
 (0)