Skip to content
File

Blob: src/shared/sites/pm-json-schemas.ts

typescript58 lines
1import { z } from "zod";
2 
3export interface PmJsonMark {
4 type: string;
5 attrs?: Record<string, unknown>;
6 [key: string]: unknown;
7}
8 
9export interface PmJsonContent {
10 type?: string;
11 attrs?: Record<string, unknown>;
12 content?: PmJsonContent[];
13 marks?: PmJsonMark[];
14 text?: string;
15 [key: string]: unknown;
16}
17 
18const PmJsonAttrsSchema = z.record(z.string(), z.unknown());
19 
20export const PmJsonMarkSchema: z.ZodType<PmJsonMark> = z.looseObject({
21 type: z.string(),
22 attrs: PmJsonAttrsSchema.optional(),
23});
24 
25export const PmJsonContentSchema: z.ZodType<PmJsonContent> = z.lazy(() =>
26 z.looseObject({
27 type: z.string().optional(),
28 attrs: PmJsonAttrsSchema.optional(),
29 content: z.array(PmJsonContentSchema).optional(),
30 marks: z.array(PmJsonMarkSchema).optional(),
31 text: z.string().optional(),
32 }),
33);
34 
35export const EditorTextMetricsSchema = z.object({
36 words: z.number().int().nonnegative(),
37 characters: z.number().int().nonnegative(),
38});
39 
40export const SitePmJsonEnvelopeSchema = z.object({
41 content: PmJsonContentSchema,
42 metrics: EditorTextMetricsSchema,
43 updatedAt: z.string().min(1),
44});
45 
46export type SitePmJsonEnvelope = z.infer<typeof SitePmJsonEnvelopeSchema>;
47 
48export function parseSitePmJsonEnvelope(text: string): SitePmJsonEnvelope | null {
49 let value: unknown;
50 try {
51 value = JSON.parse(text);
52 } catch {
53 return null;
54 }
55 const parsed = SitePmJsonEnvelopeSchema.safeParse(value);
56 return parsed.success ? parsed.data : null;
57}