aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Effect
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/Effect')
-rw-r--r--src/lib/Effect/json.test.ts19
-rw-r--r--src/lib/Effect/json.ts31
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,
+ });
+};