2023-07-21 23:07:57 +00:00
|
|
|
#!/usr/bin/env -S deno run --allow-env --allow-read --allow-write --allow-net
|
|
|
|
|
2023-11-21 14:25:59 +00:00
|
|
|
import { join } from "std/path/mod.ts";
|
2023-12-01 14:42:23 +00:00
|
|
|
import { updateReadme, validateYaml } from "catppuccin-deno-lib";
|
2023-12-02 22:16:57 +00:00
|
|
|
import { MergeExclusive, SetOptional } from "type-fest";
|
2023-12-01 14:42:23 +00:00
|
|
|
|
|
|
|
import portsSchema from "@/ports.schema.json" assert { type: "json" };
|
|
|
|
import userstylesSchema from "catppuccin-userstyles/scripts/userstyles.schema.json" assert {
|
|
|
|
type: "json",
|
|
|
|
};
|
|
|
|
const userstylesYaml = await fetch(
|
2024-02-28 21:29:40 +00:00
|
|
|
"https://raw.githubusercontent.com/catppuccin/userstyles/main/scripts/userstyles.yml",
|
2023-12-01 14:42:23 +00:00
|
|
|
).then((res) => res.text());
|
|
|
|
|
2023-11-21 14:25:59 +00:00
|
|
|
import type { PortsSchema, UserStylesSchema } from "@/types/mod.ts";
|
2023-01-29 20:54:12 +00:00
|
|
|
|
|
|
|
const root = new URL(".", import.meta.url).pathname;
|
|
|
|
|
2023-12-01 14:42:23 +00:00
|
|
|
const portsYaml = await Deno.readTextFile(join(root, "../ports.yml"));
|
2023-11-21 14:25:59 +00:00
|
|
|
|
|
|
|
const [portsData, userstylesData] = await Promise.all([
|
|
|
|
await validateYaml<PortsSchema.PortsSchema>(
|
|
|
|
portsYaml,
|
|
|
|
portsSchema,
|
|
|
|
),
|
|
|
|
await validateYaml<UserStylesSchema.UserstylesSchema>(
|
|
|
|
userstylesYaml,
|
|
|
|
userstylesSchema,
|
|
|
|
),
|
|
|
|
]);
|
|
|
|
if (!portsData.ports || !portsData.categories || !userstylesData.userstyles) {
|
|
|
|
throw new Error("ports.yml is empty");
|
2023-07-21 23:07:57 +00:00
|
|
|
}
|
2023-01-29 20:54:12 +00:00
|
|
|
|
2023-12-02 22:16:57 +00:00
|
|
|
export type MappedPort =
|
|
|
|
& MergeExclusive<PortsSchema.Port, UserStylesSchema.Userstyle>
|
|
|
|
& {
|
|
|
|
type: "port" | "userstyle";
|
|
|
|
};
|
2023-07-21 23:07:57 +00:00
|
|
|
|
2023-12-02 22:16:57 +00:00
|
|
|
// label the ports with their type
|
|
|
|
const ports = {
|
|
|
|
...Object.entries(portsData.ports)
|
|
|
|
.reduce((acc, [slug, port]) => {
|
|
|
|
acc[slug] = {
|
|
|
|
...port,
|
|
|
|
type: "port",
|
|
|
|
};
|
|
|
|
return acc;
|
|
|
|
}, {} as Record<string, MappedPort>),
|
|
|
|
...Object.entries(userstylesData.userstyles)
|
|
|
|
.reduce((acc, [slug, userstyle]) => {
|
|
|
|
acc[slug] = {
|
|
|
|
...userstyle,
|
|
|
|
type: "userstyle",
|
|
|
|
};
|
|
|
|
return acc;
|
2024-06-06 00:36:50 +00:00
|
|
|
}, {} as Record<string, MappedPort>),
|
2023-11-21 14:25:59 +00:00
|
|
|
};
|
2023-07-21 23:07:57 +00:00
|
|
|
|
2023-12-02 22:16:57 +00:00
|
|
|
const portSlugs = Object.entries(ports).map(([slug]) => slug);
|
|
|
|
|
2023-11-21 14:25:59 +00:00
|
|
|
const categorized = Object.entries(ports)
|
|
|
|
.reduce(
|
|
|
|
(acc, [slug, port]) => {
|
|
|
|
// create a new array if it doesn't exist
|
2024-02-28 20:44:41 +00:00
|
|
|
acc[port.categories[0]] ??= [];
|
2023-11-21 14:25:59 +00:00
|
|
|
|
2023-12-02 22:16:57 +00:00
|
|
|
// validate the alias against an existing port
|
|
|
|
if (port.alias && !portSlugs.includes(port.alias)) {
|
|
|
|
throw new Error(
|
|
|
|
`port \`${slug}\` points to an alias \`${port.alias}\` that doesn't exist`,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
let url = port.url;
|
|
|
|
if (!url) {
|
|
|
|
switch (port.type) {
|
|
|
|
case "port": {
|
|
|
|
const repo = port.alias ?? slug;
|
|
|
|
url = `https://github.com/catppuccin/${repo}`;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case "userstyle": {
|
|
|
|
url =
|
|
|
|
`https://github.com/catppuccin/userstyles/tree/main/styles/${slug}`;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-06-06 00:36:50 +00:00
|
|
|
acc[port.categories[0]].push({
|
2023-11-21 14:25:59 +00:00
|
|
|
...port,
|
2023-12-02 22:16:57 +00:00
|
|
|
url,
|
2023-11-21 14:25:59 +00:00
|
|
|
name: [port.name].flat().join(", "),
|
|
|
|
});
|
2024-06-06 00:36:50 +00:00
|
|
|
acc[port.categories[0]].sort((a, b) =>
|
2023-11-21 14:25:59 +00:00
|
|
|
[a.name].flat()[0].localeCompare([b.name].flat()[0])
|
|
|
|
);
|
|
|
|
return acc;
|
|
|
|
},
|
2023-12-02 22:16:57 +00:00
|
|
|
{} as Record<string, SetOptional<MappedPort, "readme" | "platform">[]>,
|
2023-11-21 14:25:59 +00:00
|
|
|
);
|
2023-07-21 23:07:57 +00:00
|
|
|
|
|
|
|
const portListData = portsData.categories.map((category) => {
|
2023-01-29 20:54:12 +00:00
|
|
|
return {
|
|
|
|
meta: category,
|
2024-02-28 20:44:41 +00:00
|
|
|
ports: categorized[category.key] ?? [],
|
2023-01-29 20:54:12 +00:00
|
|
|
};
|
|
|
|
});
|
|
|
|
|
2023-11-21 14:25:59 +00:00
|
|
|
const readmePath = join(root, "../../README.md");
|
2023-12-01 14:42:23 +00:00
|
|
|
let readmeContent = await Deno.readTextFile(readmePath);
|
2023-01-29 20:54:12 +00:00
|
|
|
|
2023-07-21 23:07:57 +00:00
|
|
|
const portContent = portListData
|
2024-02-28 20:44:41 +00:00
|
|
|
.filter((data) => data.ports.length !== 0)
|
2023-07-21 23:07:57 +00:00
|
|
|
.map((data) => {
|
|
|
|
return `<details open>
|
2023-01-29 20:54:12 +00:00
|
|
|
<summary>${data.meta.emoji} ${data.meta.name}</summary>
|
|
|
|
|
2023-12-02 22:16:57 +00:00
|
|
|
${data.ports.map((port) => `- [${port.name}](${port.url})`).join("\n")}
|
2023-01-29 20:54:12 +00:00
|
|
|
|
|
|
|
</details>`;
|
2023-07-21 23:07:57 +00:00
|
|
|
})
|
|
|
|
.join("\n");
|
|
|
|
|
|
|
|
const showcaseContent = portsData.showcases
|
2023-11-21 14:25:59 +00:00
|
|
|
?.map((showcase) => {
|
2023-07-21 23:07:57 +00:00
|
|
|
return `- [${showcase.title}](${showcase.link}) - ${showcase.description}`;
|
|
|
|
})
|
|
|
|
.join("\n");
|
2023-01-29 20:54:12 +00:00
|
|
|
|
|
|
|
try {
|
2023-12-01 14:42:23 +00:00
|
|
|
readmeContent = updateReadme(readmeContent, portContent, {
|
2023-01-29 20:54:12 +00:00
|
|
|
section: "portlist",
|
|
|
|
});
|
2023-11-21 14:25:59 +00:00
|
|
|
showcaseContent && (
|
2023-12-01 14:42:23 +00:00
|
|
|
readmeContent = updateReadme(readmeContent, showcaseContent, {
|
2023-11-21 14:25:59 +00:00
|
|
|
section: "showcase",
|
|
|
|
})
|
|
|
|
);
|
2023-01-29 20:54:12 +00:00
|
|
|
} catch (e) {
|
|
|
|
console.log("Failed to update the README:", e);
|
|
|
|
} finally {
|
2023-12-01 14:42:23 +00:00
|
|
|
await Deno.writeTextFile(readmePath, readmeContent);
|
2023-01-29 20:54:12 +00:00
|
|
|
}
|