feat(effect-validator): support `effect@3.10.0` (#859)

* upgrade effect to 3.10.0

* add changeset

* tidy import

* update lock file

* remove RemoveReadonly
pull/863/head
Yuichiro Yamashita 2024-12-02 10:56:10 +09:00 committed by GitHub
parent 71c1e669e2
commit 739d4a01fc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 38 additions and 50 deletions

View File

@ -0,0 +1,5 @@
---
'@hono/effect-validator': minor
---
feat: support `effect@3.10.0`

View File

@ -38,12 +38,11 @@
}, },
"homepage": "https://github.com/honojs/middleware", "homepage": "https://github.com/honojs/middleware",
"peerDependencies": { "peerDependencies": {
"@effect/schema": ">=0.68.18", "effect": ">=3.10.0",
"hono": ">=4.4.13" "hono": ">=4.4.13"
}, },
"devDependencies": { "devDependencies": {
"@effect/schema": "^0.68.21", "effect": "3.10.0",
"effect": "^3.4.8",
"hono": "^4.4.13", "hono": "^4.4.13",
"tsup": "^8.1.0", "tsup": "^8.1.0",
"typescript": "^5.5.3", "typescript": "^5.5.3",

View File

@ -1,22 +1,18 @@
import { ArrayFormatter } from '@effect/schema' import { Schema as S, ParseResult, Either } from 'effect'
import * as S from '@effect/schema/Schema'
import { Either } from 'effect'
import type { Env, Input, MiddlewareHandler, ValidationTargets } from 'hono' import type { Env, Input, MiddlewareHandler, ValidationTargets } from 'hono'
import type { Simplify } from 'hono/utils/types' import type { Simplify } from 'hono/utils/types'
import { validator } from 'hono/validator' import { validator } from 'hono/validator'
type RemoveReadonly<T> = { -readonly [P in keyof T]: RemoveReadonly<T[P]> }
type HasUndefined<T> = undefined extends T ? true : false type HasUndefined<T> = undefined extends T ? true : false
export const effectValidator = < export const effectValidator = <
// eslint-disable-next-line @typescript-eslint/no-explicit-any
T extends S.Schema.Variance<any, any, any>,
Target extends keyof ValidationTargets, Target extends keyof ValidationTargets,
E extends Env, E extends Env,
P extends string, P extends string,
In = Simplify<RemoveReadonly<S.Schema.Type<T>>>, Type,
Out = Simplify<RemoveReadonly<S.Schema.Type<T>>>, Encoded,
In = Simplify<Encoded>,
Out = Simplify<Type>,
I extends Input = { I extends Input = {
in: HasUndefined<In> extends true in: HasUndefined<In> extends true
? { ? {
@ -34,23 +30,22 @@ export const effectValidator = <
: { [K2 in keyof In]: ValidationTargets[K][K2] } : { [K2 in keyof In]: ValidationTargets[K][K2] }
} }
out: { [K in Target]: Out } out: { [K in Target]: Out }
}, }
V extends I = I
>( >(
target: Target, target: Target,
schema: T schema: S.Schema<Type, Encoded, never>
): MiddlewareHandler<E, P, V> => ): MiddlewareHandler<E, P, I> => {
// @ts-expect-error not typed well
validator(target, async (value, c) => {
// @ts-expect-error not typed well // @ts-expect-error not typed well
return validator(target, async (value, c) => {
const result = S.decodeUnknownEither(schema)(value) const result = S.decodeUnknownEither(schema)(value)
return Either.match(result, { return Either.match(result, {
onLeft: (error) => onLeft: (error) =>
c.json({ success: false, error: ArrayFormatter.formatErrorSync(error) }, 400), c.json({ success: false, error: ParseResult.ArrayFormatter.formatErrorSync(error) }, 400),
onRight: (data) => { onRight: (data) => {
c.req.addValidatedData(target, data as object) c.req.addValidatedData(target, data as object)
return data return data
}, },
}) })
}) })
}

View File

@ -1,5 +1,4 @@
import type { ArrayFormatter } from '@effect/schema' import { Schema as S } from 'effect'
import { Schema as S } from '@effect/schema'
import { Hono } from 'hono' import { Hono } from 'hono'
import type { StatusCode } from 'hono/utils/http-status' import type { StatusCode } from 'hono/utils/http-status'
import type { Equal, Expect } from 'hono/utils/types' import type { Equal, Expect } from 'hono/utils/types'
@ -45,14 +44,14 @@ describe('Basic', () => {
'/author': { '/author': {
$post: { $post: {
input: { input: {
json: { json: Readonly<{
name: string name: string
age: number age: number
} }>
} & { } & {
query?: { query?: Readonly<{
name?: string | string[] | undefined name?: string | string[] | undefined
} }>
} }
output: { output: {
success: boolean success: boolean
@ -104,7 +103,7 @@ describe('Basic', () => {
expect(res).not.toBeNull() expect(res).not.toBeNull()
expect(res.status).toBe(400) expect(res.status).toBe(400)
const data = await res.json<{ success: boolean; error: ArrayFormatter.Issue[] }>() const data = await res.json()
expect(data.success).toBe(false) expect(data.success).toBe(false)
expect(data.error[0].path).toEqual(['age']) expect(data.error[0].path).toEqual(['age'])
expect(data.error[0].message).toBeDefined() expect(data.error[0].message).toBeDefined()
@ -128,9 +127,9 @@ describe('coerce', () => {
'/page': { '/page': {
$get: { $get: {
input: { input: {
query: { query: Readonly<{
page: string | string[] page: string | string[]
} }>
} }
output: { output: {
page: number page: number

View File

@ -1041,17 +1041,6 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"@effect/schema@npm:^0.68.21":
version: 0.68.21
resolution: "@effect/schema@npm:0.68.21"
dependencies:
fast-check: "npm:^3.19.0"
peerDependencies:
effect: ^3.5.1
checksum: 127b4b89ce637c9be1dc84d933cefd63fdbf30f1fad9acf656c32a19df41875b646f2775129b331db9090f198a08f67f3ffe277af914a157a0c6711f3669b9a7
languageName: node
linkType: hard
"@emnapi/runtime@npm:^0.44.0": "@emnapi/runtime@npm:^0.44.0":
version: 0.44.0 version: 0.44.0
resolution: "@emnapi/runtime@npm:0.44.0" resolution: "@emnapi/runtime@npm:0.44.0"
@ -2540,14 +2529,13 @@ __metadata:
version: 0.0.0-use.local version: 0.0.0-use.local
resolution: "@hono/effect-validator@workspace:packages/effect-validator" resolution: "@hono/effect-validator@workspace:packages/effect-validator"
dependencies: dependencies:
"@effect/schema": "npm:^0.68.21" effect: "npm:3.10.0"
effect: "npm:^3.4.8"
hono: "npm:^4.4.13" hono: "npm:^4.4.13"
tsup: "npm:^8.1.0" tsup: "npm:^8.1.0"
typescript: "npm:^5.5.3" typescript: "npm:^5.5.3"
vitest: "npm:^2.0.1" vitest: "npm:^2.0.1"
peerDependencies: peerDependencies:
"@effect/schema": ">=0.68.18" effect: ">=3.10.0"
hono: ">=4.4.13" hono: ">=4.4.13"
languageName: unknown languageName: unknown
linkType: soft linkType: soft
@ -8610,10 +8598,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"effect@npm:^3.4.8": "effect@npm:3.10.0":
version: 3.4.8 version: 3.10.0
resolution: "effect@npm:3.4.8" resolution: "effect@npm:3.10.0"
checksum: 951962386775fa8506a6bfae75dc2802b00557dc58d9aecc7dff552c2e01ba651b87d662bdbf1f7c5ba1e450bc1a58f6daf44628222b0260471c5b52e0e76a8f dependencies:
fast-check: "npm:^3.21.0"
checksum: 9d59b7c50ece9e9f9b87df587941927f206e863226ebad607a0880aab3287d67d751288e796db138d6682a130c97a92361a881c2fa1b6864810905372ecff159
languageName: node languageName: node
linkType: hard linkType: hard
@ -10173,12 +10163,12 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"fast-check@npm:^3.19.0": "fast-check@npm:^3.21.0":
version: 3.19.0 version: 3.23.1
resolution: "fast-check@npm:3.19.0" resolution: "fast-check@npm:3.23.1"
dependencies: dependencies:
pure-rand: "npm:^6.1.0" pure-rand: "npm:^6.1.0"
checksum: 5a15484d380fb5a3e94ec951c97e59b940ac4f2e1f3f7a05578d67851e5cb5283121bcf08c57e3238bc85899ce691b47ab477a6dd481a6f520e2e7ab4952d1ee checksum: d61ee4a7a2e1abc5126bf2f1894413f532f686b3d1fc15c67fefb60dcca66024934b69a6454d3eba92e6568ac1abbb9882080e212d255865c3b3bbe52c5bf702
languageName: node languageName: node
linkType: hard linkType: hard