From 79fd506d30eef3d113f4a8e3ab9ebd9004f1e8cc Mon Sep 17 00:00:00 2001 From: João Augusto Costa Branco Marado Torres Date: Sat, 28 Jun 2025 18:14:22 -0300 Subject: feat: index page 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/lib/collection/schemas.ts | 133 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 src/lib/collection/schemas.ts (limited to 'src/lib/collection/schemas.ts') diff --git a/src/lib/collection/schemas.ts b/src/lib/collection/schemas.ts new file mode 100644 index 0000000..eca996f --- /dev/null +++ b/src/lib/collection/schemas.ts @@ -0,0 +1,133 @@ +import { reference, z } from "astro:content"; +import { isValidLocale } from "../../utils/lang.ts"; +import { get } from "../../utils/anonymous.ts"; +import type { CollectionEntry } from "astro:content"; + +export const KEYWORDS = ["Portugal", "democracy", "test"] as const; +export const KeywordsEnum = z.enum(KEYWORDS); + +export const ENTITY_TYPES = ["author", "co-author", "translator"] as const; +export const EntityTypesEnum = z.enum(ENTITY_TYPES); + +export const CREATIVE_COMMONS_LICENSES = [ + "CC0", + "CC-BY", + "CC-BY-SA", + "CC-BY-ND", + "CC-BY-NC", + "CC-BY-NC-SA", + "CC-BY-NC-ND", +] as const; +export const LICENSES = [ + ...CREATIVE_COMMONS_LICENSES, + "WTFPL", + "public domain", +] as const; +export const LicensesEnum = z.enum(LICENSES); + +export const Original = z.object({ + kind: z.literal("original"), + title: z.string().trim(), + subtitle: z.string().trim().optional(), + description: z.string().trim().optional(), + keywords: z.array(KeywordsEnum).refine( + (keywords) => new Set(keywords).size === keywords.length, + { message: "Keywords must be unique" }, + ), + 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, + { message: "Related posts referenced multiple times" }, + ), + lang: z.string().trim().refine(isValidLocale), + signers: z.array( + z.object({ entity: reference("entity"), role: EntityTypesEnum }), + ).default([]).refine( + (signers) => 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" }).refine( + (signers) => signers.every(({ role }) => role !== "translator"), + { message: "There can't be translator signers on non translated work" }, + ), + license: LicensesEnum.default("public domain"), +}); + +export const Translation = z.object({ + kind: z.literal("translation"), + title: z.string().trim(), + subtitle: z.string().trim().optional(), + description: z.string().trim().optional(), + dateCreated: z.coerce.date(), + dateUpdated: z.coerce.date().optional(), + lang: z.string().trim().refine(isValidLocale), + translationOf: reference("blog"), + signers: z.array( + z.object({ entity: reference("entity"), role: EntityTypesEnum }), + ).default([]).refine( + (signers) => 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" }), + license: LicensesEnum.default("public domain"), +}); + +export const Micro = z.object({ + kind: z.literal("micro"), + title: z.string().trim(), + keywords: z.array(KeywordsEnum).refine( + (keywords) => new Set(keywords).size === keywords.length, + { message: "Keywords must be unique" }, + ), + dateCreated: z.coerce.date(), + dateUpdated: z.coerce.date().optional(), + locationCreated: z.string().trim().optional(), + lang: z.string().trim().refine(isValidLocale), + signers: z.array( + z.object({ entity: reference("entity"), role: EntityTypesEnum }), + ).default([]).refine( + (signers) => 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" }).refine( + (signers) => signers.every(({ role }) => role !== "translator"), + { message: "There can't be translator signers on non translated work" }, + ), + license: LicensesEnum.default("public domain"), +}); + +export const Blog = z.discriminatedUnion("kind", [ + Original, + Translation, + Micro, +]).refine( + ({ dateCreated, dateUpdated }) => + dateUpdated === undefined || dateCreated.getTime() <= dateUpdated.getTime(), + { message: "Update before creation" }, +); + +export type OriginalEntry = CollectionEntry<"blog"> & { + data: z.infer; +}; +export type TranslationEntry = CollectionEntry<"blog"> & { + data: z.infer; +}; +export type MicroEntry = CollectionEntry<"blog"> & { + data: z.infer; +}; +export type Entry = OriginalEntry | TranslationEntry | MicroEntry; + +export const Entity = z.object({ + websites: z.array(z.string().url().trim()).default([]).transform((websites) => + websites.map((x) => new URL(x).href) + ), + publickey: z.object({ armor: z.string().trim() }), +}); -- cgit v1.2.3