ditto/src/schema.ts

46 lines
1.5 KiB
TypeScript
Raw Normal View History

2023-08-12 16:28:16 +00:00
import { z } from '@/deps.ts';
2023-03-05 04:10:56 +00:00
2023-05-12 04:49:32 +00:00
/** Validates individual items in an array, dropping any that aren't valid. */
function filteredArray<T extends z.ZodTypeAny>(schema: T) {
return z.any().array().catch([])
.transform((arr) => (
arr.map((item) => {
const parsed = schema.safeParse(item);
return parsed.success ? parsed.data : undefined;
}).filter((item): item is z.infer<T> => Boolean(item))
));
}
const jsonSchema = z.string().transform((value, ctx) => {
try {
2023-07-08 23:41:11 +00:00
return JSON.parse(value) as unknown;
} catch (_e) {
ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid JSON' });
return z.NEVER;
}
});
2023-05-12 04:49:32 +00:00
const emojiTagSchema = z.tuple([z.literal('emoji'), z.string(), z.string().url()]);
2023-07-08 23:41:11 +00:00
/** https://developer.mozilla.org/en-US/docs/Glossary/Base64#the_unicode_problem */
const decode64Schema = z.string().transform((value, ctx) => {
try {
const binString = atob(value);
const bytes = Uint8Array.from(binString, (m) => m.codePointAt(0)!);
return new TextDecoder().decode(bytes);
} catch (_e) {
2023-07-09 02:01:49 +00:00
ctx.addIssue({ code: z.ZodIssueCode.custom, message: 'Invalid base64', fatal: true });
2023-07-08 23:41:11 +00:00
return z.NEVER;
}
});
const hashtagSchema = z.string().regex(/^\w{1,30}$/);
2023-08-14 17:29:54 +00:00
/**
* Limits the length before trying to parse the URL.
* https://stackoverflow.com/a/417184/8811886
*/
const safeUrlSchema = z.string().max(2048).url();
export { decode64Schema, emojiTagSchema, filteredArray, hashtagSchema, jsonSchema, safeUrlSchema };