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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
import { file, glob } from "astro/loaders";
import { defineCollection, reference, z } from "astro:content";
//import { parse } from "@std/toml";
import { parse } from "toml";
import { EntityTypesEnum, KeywordsEnum, LicensesEnum } from "./consts.ts";
import { get, instanciate } from "./utils/anonymous.ts";
import { isValidLocale } from "./utils/lang.ts";
const Blog = z.object({
title: z.string().trim(),
subtitle: z.string().trim().optional(),
description: z.string().trim().optional(),
keywords: z.array(KeywordsEnum).optional().refine(
(keywords) => new Set(keywords).size === (keywords?.length ?? 0),
{
message: "Keywords must be unique",
},
).transform((keywords) =>
keywords !== undefined ? new Set(keywords).values().toArray() : undefined
),
dateCreated: z.coerce.date(),
dateUpdated: z.coerce.date().optional(),
locationCreated: z.string().trim().optional(),
relatedPosts: z.array(reference("blog")).default([]).refine(
(posts) => new Set(posts).size === (posts?.length ?? 0),
{
message: "Related posts referenced multiple times",
},
).transform((x) => new Set(x)).transform((set) => set.values().toArray()),
lang: z.string().trim().refine(isValidLocale),
translationOf: reference("blog").optional(),
signers: z.array(
z.object({ entity: reference("entity"), role: EntityTypesEnum }),
).optional().refine(
(signers) => {
if (signers === undefined) return true;
return signers.filter((s) => s.role === "author").length <= 1;
},
{
message: "There can only be one author",
},
).refine(
(signers) => {
const ids = signers?.map(get("entity")) ?? [];
return new Set(ids).size === ids.length;
},
{
message: "Reusing signers",
},
//).transform((signers) =>
// Object.fromEntries(new Map(signers?.map(({ entity, ...rest }) => [entity, rest]) ?? []))
),
license: LicensesEnum,
}).refine(
({ dateCreated, dateUpdated }) =>
dateUpdated === undefined || dateCreated.getTime() <= dateUpdated.getTime(),
{ message: "Update before creation" },
).refine(
({ translationOf, keywords }) =>
translationOf !== undefined || (keywords?.length ?? 0) > 0,
{
message: "Originals must include at least one keyword",
path: ["keywords"],
},
).refine(
({ translationOf, keywords }) =>
(translationOf === undefined) !== ((keywords?.length ?? 0) <= 0),
{
message: "we will use this information from the original, " +
"so no need to specify it for translations",
path: ["keywords"],
},
).refine(
({ translationOf, relatedPosts }) =>
(translationOf === undefined) || (relatedPosts.length <= 0),
{
message: "we will use this information from the original, " +
"so no need to specify it for translations",
path: ["relatedPosts"],
},
).refine(
({ translationOf, signers = [] }) =>
(translationOf === undefined) ||
(signers.values().every(({ role }) => role !== "translator")),
{
message: "There can't be translator signers on non translated work",
path: ["signers"],
},
);
const blog = defineCollection({
loader: glob({ base: "./public/blog", pattern: "+([0-9a-z-]).md" }),
schema: Blog,
});
export type Blog = z.infer<typeof Blog>;
const Entity = z.object({
websites: z.array(z.string().url().trim()).default([]).transform((websites) =>
websites.map(instanciate(URL))
),
publickey: z.object({
armor: z.string().trim(),
}),
});
type Entity = z.infer<typeof Entity>;
const entity = defineCollection({
loader: file("./src/content/entities.toml", {
parser: (text) => parse(text).entities as Entity[],
}),
schema: Entity,
});
export const collections = { blog, entity };
|