aboutsummaryrefslogtreecommitdiff
path: root/src/lib/Effect/json.ts
blob: 24414fb03a53616bdb36f45ef7f0d7eb54caa359 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import { Effect, Result, Schema } from "effect";

type SyncDecodingSchema = Schema.Top & {
	readonly DecodingServices: never;
};

export const parseJsonStringEffect = (value: string) =>
	Effect.try({
		try: () => JSON.parse(value) as unknown,
		catch: (cause) => new Error("Invalid JSON payload", { cause }),
	});

export const parseJsonStringEither = (value: string) =>
	Result.try({
		try: () => Effect.runSync(parseJsonStringEffect(value)),
		catch: (cause) =>
			cause instanceof Error
				? cause
				: new Error("Failed to parse JSON payload", { cause }),
	});

export const parseJsonStringOrThrow = <T = unknown>(value: string): T =>
	Result.getOrThrow(parseJsonStringEither(value)) as T;

export const parseJsonStringOrDefault = <T>(value: string, fallback: T): T => {
	const parsed = parseJsonStringEither(value);

	return Result.match(parsed, {
		onSuccess: (decoded) => decoded as 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,
	});
};