Skip to content

Commit

Permalink
feat: Add typia validation adapter
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
ryoppippi committed Jun 6, 2024
1 parent 5d6331e commit 77889a7
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/lib/adapters/adapters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type ValidationLibrary =
| 'joi'
| 'superform'
| 'typebox'
| 'typia'
| 'valibot'
| 'yup'
| 'zod'
Expand Down
65 changes: 65 additions & 0 deletions src/lib/adapters/typia.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import type { IValidation } from 'typia';
import {
type ValidationAdapter,
type ValidationIssue,
type RequiredDefaultsOptions,
createAdapter,
type ClientValidationAdapter,
type ValidationResult,
createJsonSchema
} from './adapters.js';
import { memoize } from '$lib/memoize.js';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
type Validation<O = any> = (input: unknown) => IValidation<O>;
type OutputType<T> = T extends Validation<infer O> ? O : never;

async function _validate<T extends Validation>(
validate: T,
data: unknown
): Promise<ValidationResult<OutputType<T>>> {
const result = validate(data);
if (result.success) {
return {
data: result.data,
success: true
};
}

const issues: ValidationIssue[] = [];
for (const { expected, value, path } of result.errors) {
issues.push({
path: [path.replace('$input.', '')],
message: JSON.stringify({ expected, value })
});
}

return {
issues,
success: false
};
}

function _typia<T extends Validation>(
validate: T,
options: RequiredDefaultsOptions<OutputType<T>>
): ValidationAdapter<OutputType<T>> {
return createAdapter({
superFormValidationLibrary: 'typia',
defaults: options.defaults,
jsonSchema: createJsonSchema(options),
validate: async (data) => _validate(validate, data)
});
}

function _typiaClient<T extends Validation>(
validate: T
): ClientValidationAdapter<ReturnType<typeof _validate<T>>> {
return {
superFormValidationLibrary: 'typia',
validate: async (data) => _validate(validate, data)
};
}

export const typia = /* @__PURE__ */ memoize(_typia);
export const typiaClient = /* @__PURE__ */ memoize(_typiaClient);
21 changes: 21 additions & 0 deletions src/tests/superValidate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ import Vine from '@vinejs/vine';

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

import { typia as typiaAdapter } from '$lib/adapters/typia.js';
import typia, { type tags } from 'typia';

import { traversePath } from '$lib/traversal.js';
import { splitPath } from '$lib/stringPath.js';
import { SchemaError, type JSONSchema } from '$lib/index.js';
Expand Down Expand Up @@ -457,6 +460,24 @@ describe('ajv', () => {

/////////////////////////////////////////////////////////////////////

describe('typia', () => {
interface Schema extends Record<string, unknown> {
name: string;
email: string & tags.Format<'email'>;
tags: (string & tags.MinLength<2>)[] & tags.MinItems<3>;
score: number & tags.Type<'uint32'> & tags.Minimum<0>;
date?: Date;
nospace?: string & tags.Pattern<'^\\S*$'>;
extra: string | null;
}

const validate = typia.createValidate<Schema>();
const adapter = typiaAdapter(validate, { defaults });
schemaTest(adapter, ['email', 'nospace', 'tags'], 'simple');
});

/////////////////////////////////////////////////////////////////////

describe('Zod', () => {
const schema = z
.object({
Expand Down

0 comments on commit 77889a7

Please sign in to comment.