summaryrefslogtreecommitdiff
path: root/src/content.config.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/content.config.ts')
-rw-r--r--src/content.config.ts116
1 files changed, 116 insertions, 0 deletions
diff --git a/src/content.config.ts b/src/content.config.ts
new file mode 100644
index 0000000..f652cc3
--- /dev/null
+++ b/src/content.config.ts
@@ -0,0 +1,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 };