diff --git a/coercion.ts b/coercion.ts index a35e7d0..1ee8490 100644 --- a/coercion.ts +++ b/coercion.ts @@ -143,17 +143,10 @@ function generateReturnSchema< ) { if ("pipe" in originalSchema) { if (originalSchema.async && coercionSchema.async) { - return pipeAsync( - coercionSchema, - // @ts-expect-error - ...originalSchema.pipe.slice(1), - ); + return pipeAsync(coercionSchema, ...originalSchema.pipe.slice(1)); } - return pipe( - coercionSchema, - // @ts-expect-error - ...originalSchema.pipe.slice(1), - ); + // @ts-expect-error + return pipe(coercionSchema, ...originalSchema.pipe.slice(1)); } return coercionSchema; @@ -237,6 +230,20 @@ export function enableTypeCoercion< schema: generateReturnSchema(type, coerceArray(arraySchema)), }; } + case "exact_optional": { + // @ts-expect-error + const { schema: wrapSchema } = enableTypeCoercion(type.wrapped); + + const exactOptionalSchema = { + ...type, + wrapped: wrapSchema, + }; + + return { + coerced: false, + schema: generateReturnSchema(type, exactOptionalSchema), + }; + } case "optional": case "nullish": case "nullable": diff --git a/package-lock.json b/package-lock.json index 29ec053..2c1a482 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,7 @@ "semantic-release": "^22.0.8", "tsup": "^8.0.0", "typescript": "^5.5.4", - "valibot": "^0.34.0", + "valibot": "^1.0.0-beta.13", "vitest": "2.0.5" }, "peerDependencies": { @@ -7810,10 +7810,18 @@ "dev": true }, "node_modules/valibot": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.34.0.tgz", - "integrity": "sha512-TELvxO0hEB1/6XjTS5Jfi4dS0oyawA5flxs4/sK/tSUXnlLMiKTMYE6Atuu0a7kvtP3eqPv3yZ80msfM+qMDHA==", - "dev": true + "version": "1.0.0-beta.14", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0-beta.14.tgz", + "integrity": "sha512-tLyV2rE5QL6U29MFy3xt4AqMrn+/HErcp2ZThASnQvPMwfSozjV1uBGKIGiegtZIGjinJqn0SlBdannf18wENA==", + "dev": true, + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, "node_modules/validate-npm-package-license": { "version": "3.0.4", diff --git a/package.json b/package.json index 0c956e1..762488e 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "semantic-release": "^22.0.8", "tsup": "^8.0.0", "typescript": "^5.5.4", - "valibot": "^0.34.0", + "valibot": "^1.0.0-beta.13", "vitest": "2.0.5" } } diff --git a/parse.ts b/parse.ts index e46f37e..3e1c921 100644 --- a/parse.ts +++ b/parse.ts @@ -82,7 +82,6 @@ export function parseWithValibot< } const name = formatPaths( - // @ts-expect-error e.path?.map((d) => d.key as string | number) ?? [], ); diff --git a/tests/coercion/schema/exactOptional.test.ts b/tests/coercion/schema/exactOptional.test.ts new file mode 100644 index 0000000..bc0f2b9 --- /dev/null +++ b/tests/coercion/schema/exactOptional.test.ts @@ -0,0 +1,27 @@ +import { exactOptional, number, object, string } from "valibot"; +import { describe, expect, test } from "vitest"; +import { parseWithValibot } from "../../../parse"; +import { createFormData } from "../../helpers/FormData"; + +describe("exactOptional", () => { + test("should pass only exactOptional", () => { + const schema = object({ name: string(), age: exactOptional(number()) }); + const formData1 = createFormData("name", "Jane"); + expect(parseWithValibot(formData1, { schema })).toMatchObject({ + status: "success", + value: { name: "Jane" }, + }); + + formData1.append("age", "20"); + expect(parseWithValibot(formData1, { schema })).toMatchObject({ + status: "success", + value: { name: "Jane", age: 20 }, + }); + + const formData2 = createFormData("name", "Jane"); + formData2.append("age", "abc"); + expect(parseWithValibot(formData2, { schema })).toMatchObject({ + error: { age: expect.anything() }, + }); + }); +}); diff --git a/tests/coercion/schema/exactOptionalAsync.test.ts b/tests/coercion/schema/exactOptionalAsync.test.ts new file mode 100644 index 0000000..6607619 --- /dev/null +++ b/tests/coercion/schema/exactOptionalAsync.test.ts @@ -0,0 +1,30 @@ +import { exactOptionalAsync, number, objectAsync, string } from "valibot"; +import { describe, expect, test } from "vitest"; +import { parseWithValibot } from "../../../parse"; +import { createFormData } from "../../helpers/FormData"; + +describe("exactOptionalAsync", () => { + test("should pass only exactOptional", async () => { + const schema = objectAsync({ + name: string(), + age: exactOptionalAsync(number()), + }); + const formData1 = createFormData("name", "Jane"); + expect(await parseWithValibot(formData1, { schema })).toMatchObject({ + status: "success", + value: { name: "Jane" }, + }); + + formData1.append("age", "20"); + expect(await parseWithValibot(formData1, { schema })).toMatchObject({ + status: "success", + value: { name: "Jane", age: 20 }, + }); + + const formData2 = createFormData("name", "Jane"); + formData2.append("age", "abc"); + expect(await parseWithValibot(formData2, { schema })).toMatchObject({ + error: { age: expect.anything() }, + }); + }); +}); diff --git a/tests/coercion/schema/undefined.test.ts b/tests/coercion/schema/undefined.test.ts index 16bc1a5..bbe254f 100644 --- a/tests/coercion/schema/undefined.test.ts +++ b/tests/coercion/schema/undefined.test.ts @@ -7,11 +7,6 @@ describe("undefined", () => { test("should pass only undefined", () => { const schema = object({ name: string(), age: undefined_() }); const formData1 = createFormData("name", "Jane"); - expect(parseWithValibot(formData1, { schema })).toMatchObject({ - status: "success", - value: { name: "Jane" }, - }); - formData1.append("age", ""); expect(parseWithValibot(formData1, { schema })).toMatchObject({ status: "success", @@ -19,6 +14,10 @@ describe("undefined", () => { }); const formData2 = createFormData("name", "Jane"); + expect(parseWithValibot(formData2, { schema })).toMatchObject({ + error: { age: expect.anything() }, + }); + formData2.append("age", "20"); expect(parseWithValibot(formData2, { schema })).toMatchObject({ error: { age: expect.anything() },