From f9a77c5c27aede4e5978eb55d9b7af781b680a1d Mon Sep 17 00:00:00 2001 From: João Augusto Costa Branco Marado Torres Date: Tue, 24 Jun 2025 12:08:41 -0300 Subject: feat!: initial commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: João Augusto Costa Branco Marado Torres --- src/content.config.ts | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 src/content.config.ts (limited to 'src/content.config.ts') 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; + +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; + +const entity = defineCollection({ + loader: file("./src/content/entities.toml", { + parser: (text) => parse(text).entities as Entity[], + }), + schema: Entity, +}); + +export const collections = { blog, entity }; -- cgit v1.2.3