diff --git a/lib/util/schema-utils.spec.ts b/lib/util/schema-utils.spec.ts index c194236ce6c8bd961f6e6607d1e3056760108bf9..5d89bbeb2aa561022a6cbfe277c7e17644b2a280 100644 --- a/lib/util/schema-utils.spec.ts +++ b/lib/util/schema-utils.spec.ts @@ -1,9 +1,11 @@ +import { codeBlock } from 'common-tags'; import { z } from 'zod'; import { Json, Json5, LooseArray, LooseRecord, + Toml, Url, UtcDate, Yaml, @@ -340,4 +342,55 @@ describe('util/schema-utils', () => { }); }); }); + + describe('Toml', () => { + const Schema = Toml.pipe( + z.object({ foo: z.object({ bar: z.literal('baz') }) }) + ); + + it('parses valid toml', () => { + const content = codeBlock` + [foo] + bar = "baz" + `; + expect(Schema.parse(content)).toEqual({ + foo: { bar: 'baz' }, + }); + }); + + it('throws error for invalid schema', () => { + const content = codeBlock` + [foo] + bar = "brb" + `; + expect(Schema.safeParse(content)).toMatchObject({ + error: { + issues: [ + { + received: 'brb', + code: 'invalid_literal', + expected: 'baz', + path: ['foo', 'bar'], + }, + ], + }, + success: false, + }); + }); + + it('throws error for invalid toml', () => { + expect(Schema.safeParse('clearly_invalid')).toMatchObject({ + error: { + issues: [ + { + message: 'Invalid TOML', + code: 'custom', + path: [], + }, + ], + }, + success: false, + }); + }); + }); }); diff --git a/lib/util/schema-utils.ts b/lib/util/schema-utils.ts index e200a04bd10e8295c8fdcaa2e0f538f09c1c3bcf..086722cddfb743a00a5210efe2e34a4a19920d4e 100644 --- a/lib/util/schema-utils.ts +++ b/lib/util/schema-utils.ts @@ -1,3 +1,4 @@ +import { JsonMap, parse } from '@iarna/toml'; import { load } from 'js-yaml'; import JSON5 from 'json5'; import { DateTime } from 'luxon'; @@ -242,3 +243,12 @@ export const Yaml = z.string().transform((str, ctx): JsonValue => { return z.NEVER; } }); + +export const Toml = z.string().transform((str, ctx): JsonMap => { + try { + return parse(str); + } catch (e) { + ctx.addIssue({ code: 'custom', message: 'Invalid TOML' }); + return z.NEVER; + } +});