feat(markdown): add markdown

This commit is contained in:
Alois 2026-08-09 20:54:00 +02:00
commit 0193880cb0
Signed by: alois
SSH key fingerprint: SHA256:GBzT2DXvAuGV9XIV5W3WrzVpjU54FThmxHXdbz95J24
4036 changed files with 25057 additions and 1990 deletions

108
scripts/update-twemoji.mjs Normal file
View file

@ -0,0 +1,108 @@
import { createHash } from "node:crypto";
import {
cp,
mkdtemp,
mkdir,
readFile,
readdir,
rm,
writeFile,
} from "node:fs/promises";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { spawnSync } from "node:child_process";
const version = "17.0.3";
const expectedSha256 =
"a0855654b633045ae2337537e77f1bb4361162f7fcd910e613eaab1d6d9c5fca";
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const outputRoot = join(repositoryRoot, "src/markdown/assets/twemoji");
const assetMapPath = join(repositoryRoot, "src/markdown/twemoji-assets.ts");
const temporaryRoot = await mkdtemp(join(tmpdir(), "methanium-twemoji-"));
try {
const archivePath = join(temporaryRoot, `twemoji-${version}.tar.gz`);
const response = await fetch(
`https://codeload.github.com/jdecked/twemoji/tar.gz/refs/tags/v${version}`,
);
if (!response.ok) {
throw new Error(`Could not download Twemoji: ${response.status}`);
}
const archive = Buffer.from(await response.arrayBuffer());
const actualSha256 = createHash("sha256").update(archive).digest("hex");
if (actualSha256 !== expectedSha256) {
throw new Error(
`Twemoji archive checksum mismatch: expected ${expectedSha256}, received ${actualSha256}`,
);
}
await writeFile(archivePath, archive);
const extractedRoot = join(temporaryRoot, "extracted");
await mkdir(extractedRoot);
const extraction = spawnSync(
"tar",
["-xzf", archivePath, "-C", extractedRoot],
{
stdio: "inherit",
},
);
if (extraction.status !== 0) throw new Error("Could not extract Twemoji");
const sourceRoot = join(extractedRoot, `twemoji-${version}`);
await rm(outputRoot, { force: true, recursive: true });
await mkdir(outputRoot, { recursive: true });
await cp(join(sourceRoot, "assets/svg"), join(outputRoot, "svg"), {
recursive: true,
});
await cp(join(sourceRoot, "LICENSE"), join(outputRoot, "LICENSE"));
await cp(
join(sourceRoot, "LICENSE-GRAPHICS"),
join(outputRoot, "LICENSE-GRAPHICS"),
);
for (const licenseName of ["LICENSE", "LICENSE-GRAPHICS"]) {
const licensePath = join(outputRoot, licenseName);
const license = await readFile(licensePath, "utf8");
await writeFile(licensePath, license.replace(/[\t ]+(?=\r?$)/gm, ""));
}
await writeFile(
join(outputRoot, "ATTRIBUTION.md"),
[
"# Twemoji Attribution",
"",
`Twemoji ${version} graphics are provided by the Twemoji project:`,
"https://github.com/jdecked/twemoji",
"",
"Copyright 2023 Twitter, Inc and other contributors.",
"Graphics licensed under CC-BY 4.0.",
"Code licensed under the MIT License.",
"",
].join("\n"),
);
const files = (await readdir(join(outputRoot, "svg")))
.filter((file) => file.endsWith(".svg"))
.sort();
const entries = files.map((file) => {
const hexcode = file.slice(0, -4);
return ` ${JSON.stringify(hexcode)}: new URL(${JSON.stringify(`./assets/twemoji/svg/${file}`)}, import.meta.url).href,`;
});
await writeFile(
assetMapPath,
[
`// Generated by scripts/update-twemoji.mjs from Twemoji ${version}.`,
"export const twemojiAssetUrls: Readonly<Record<string, string>> = {",
...entries,
"};",
"",
].join("\n"),
);
const license = await readFile(join(outputRoot, "ATTRIBUTION.md"), "utf8");
console.log(
`Vendored ${files.length} Twemoji SVGs. ${license.split("\n")[0]}`,
);
} finally {
await rm(temporaryRoot, { force: true, recursive: true });
}