import * as Either from "effect/Either"; import * as ParseResult from "effect/ParseResult"; import * as Schema from "effect/Schema"; const JsonStringMapSchema = Schema.parseJson( Schema.Record({ key: Schema.String, value: Schema.String, }), ); const JsonStringArraySchema = Schema.parseJson( Schema.Array(Schema.String), ); const formatJsonFieldError = ( label: string, error: ParseResult.ParseError, ): Error => new Error( `${label} is invalid: ${ParseResult.TreeFormatter.formatErrorSync(error)}`, ); const decodeJsonField = (input: { label: string; text: string; schema: Schema.Schema; }): A | null => { const trimmed = input.text.trim(); if (trimmed.length === 0) { return null; } const decoded = Schema.decodeUnknownEither(input.schema)(trimmed); if (Either.isLeft(decoded)) { throw formatJsonFieldError(input.label, decoded.left); } return decoded.right; }; export const parseJsonStringMap = ( label: string, text: string, ): Record | null => { const decoded = decodeJsonField({ label, text, schema: JsonStringMapSchema, }); return decoded && Object.keys(decoded).length > 0 ? decoded : null; }; export const parseJsonStringArray = ( label: string, text: string, ): Array | null => { const decoded = decodeJsonField({ label, text, schema: JsonStringArraySchema, }); if (!decoded) { return null; } const normalized = decoded .map((value) => value.trim()) .filter((value) => value.length > 0); return normalized.length > 0 ? normalized : null; };