Skip to content

Commit

Permalink
feat(contract): new type util for custom schema (#94)
Browse files Browse the repository at this point in the history
* feat(contract):new  type util for custom schema

* map input
  • Loading branch information
unnoq authored Jan 16, 2025
1 parent 43c0c87 commit 44bdf93
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 1 deletion.
1 change: 1 addition & 0 deletions packages/contract/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export * from './procedure-decorated'
export * from './router'
export * from './router-builder'
export * from './router-client'
export * from './schema-utils'
export * from './types'

export const oc = new ContractBuilder<Record<never, never>>({
Expand Down
28 changes: 28 additions & 0 deletions packages/contract/src/schema-utils.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type { SchemaInput, SchemaOutput } from './types'
import { type } from './schema-utils'

describe('type', () => {
it('without map', () => {
const schema = type<string>()

expectTypeOf<SchemaInput<typeof schema>>().toEqualTypeOf<string>()
expectTypeOf<SchemaOutput<typeof schema>>().toEqualTypeOf<string>()
})

it('with map', () => {
const schema2 = type<string, number>((val) => {
expectTypeOf(val).toEqualTypeOf<string>()

return Number(val)
})

expectTypeOf<SchemaInput<typeof schema2>>().toEqualTypeOf<string>()
expectTypeOf<SchemaOutput<typeof schema2>>().toEqualTypeOf<number>()

// @ts-expect-error - map is required when TInput !== TOutput
type<string, number>()

// @ts-expect-error - output not match number
type<string, number>(() => '123')
})
})
17 changes: 17 additions & 0 deletions packages/contract/src/schema-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { type } from './schema-utils'

describe('type', async () => {
it('without map', async () => {
const schema = type()
const val = {}
expect((await schema['~standard'].validate(val) as any).value).toBe(val)
})

it('with map', async () => {
const val = {}
const check = vi.fn().mockReturnValueOnce('__mapped__')
const schema = type(check)
expect((await schema['~standard'].validate(val) as any).value).toBe('__mapped__')
expect(check).toHaveBeenCalledWith(val)
})
})
22 changes: 22 additions & 0 deletions packages/contract/src/schema-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { IsEqual, Promisable } from '@orpc/shared'
import type { StandardSchemaV1 } from '@standard-schema/spec'

export type TypeRest<TInput, TOutput> =
| [map: (input: TInput) => Promisable<TOutput>]
| (IsEqual<TInput, TOutput> extends true ? [] : never)

export function type<TInput, TOutput = TInput>(...[map]: TypeRest<TInput, TOutput>): StandardSchemaV1<TInput, TOutput> {
return {
'~standard': {
vendor: 'custom',
version: 1,
async validate(value) {
if (map) {
return { value: await map(value as TInput) as TOutput }
}

return { value: value as TOutput }
},
},
}
}
3 changes: 2 additions & 1 deletion packages/server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export * from './router-client'
export * from './router-implementer'
export * from './types'
export * from './utils'
export { configGlobal, fallbackToGlobalConfig, isDefinedError, ORPCError, safe } from '@orpc/contract'

export { configGlobal, fallbackToGlobalConfig, isDefinedError, ORPCError, safe, type } from '@orpc/contract'

export const os = new Builder<WELL_CONTEXT>({})

0 comments on commit 44bdf93

Please sign in to comment.