diff options
Diffstat (limited to 'src/lib/Effect')
| -rw-r--r-- | src/lib/Effect/json.test.ts | 19 | ||||
| -rw-r--r-- | src/lib/Effect/json.ts | 31 |
2 files changed, 49 insertions, 1 deletions
diff --git a/src/lib/Effect/json.test.ts b/src/lib/Effect/json.test.ts index b315fe61..c13824fe 100644 --- a/src/lib/Effect/json.test.ts +++ b/src/lib/Effect/json.test.ts @@ -2,7 +2,9 @@ import { describe, expect, it } from "vitest"; import { parseJsonStringOrDefault, parseJsonStringOrThrow, + parseJsonStringWithSchemaOrDefault, } from "$lib/Effect/json"; +import { Schema } from "effect"; describe("effect json parsing", () => { it("parses valid json strings", () => { @@ -21,4 +23,21 @@ describe("effect json parsing", () => { ok: false, }); }); + + it("decodes json with a schema and returns fallback on schema mismatch", () => { + expect( + parseJsonStringWithSchemaOrDefault( + "[1,2,3]", + Schema.Array(Schema.Number), + [], + ), + ).toEqual([1, 2, 3]); + expect( + parseJsonStringWithSchemaOrDefault( + `["a",2]`, + Schema.Array(Schema.Number), + [], + ), + ).toEqual([]); + }); }); diff --git a/src/lib/Effect/json.ts b/src/lib/Effect/json.ts index b905cc41..24414fb0 100644 --- a/src/lib/Effect/json.ts +++ b/src/lib/Effect/json.ts @@ -1,4 +1,8 @@ -import { Effect, Result } from "effect"; +import { Effect, Result, Schema } from "effect"; + +type SyncDecodingSchema = Schema.Top & { + readonly DecodingServices: never; +}; export const parseJsonStringEffect = (value: string) => Effect.try({ @@ -26,3 +30,28 @@ export const parseJsonStringOrDefault = <T>(value: string, fallback: T): T => { onFailure: () => fallback, }); }; + +export const parseJsonStringWithSchemaOrDefault = < + S extends SyncDecodingSchema, +>( + value: string, + schema: S, + fallback: S["Type"], +): S["Type"] => { + const parsed = parseJsonStringEither(value); + + return Result.match(parsed, { + onSuccess: (decoded) => { + const decodedWithSchema = Result.try({ + try: () => Schema.decodeUnknownSync(schema)(decoded), + catch: () => fallback, + }); + + return Result.match(decodedWithSchema, { + onSuccess: (value) => value, + onFailure: () => fallback, + }); + }, + onFailure: () => fallback, + }); +}; |