import { htmlToMarkdown } from "../../html.js"; import { getJson, getText } from "../handler.js"; import { type Registry, fullFromArchive, metaBlock, seg } from "./common.js"; export const crates: Registry = { name: "crates.io", match: (url) => { if (!/(^|\.)crates\.io$/.test(url.hostname)) return undefined; const s = seg(url); return s[0] === "crates" ? s[1] : undefined; }, async light(pkg, ctx) { const d = await getJson(`https://crates.io/api/v1/crates/${pkg}`, ctx.signal); const c = d.crate; const header = metaBlock(`${pkg} (crates.io)`, { version: c?.newest_version, description: c?.description, repository: c?.repository, docs: c?.documentation ?? `https://docs.rs/${pkg}`, downloads: c?.downloads, }); let readme = "(no readme)"; try { const r = await getText(`https://crates.io/api/v1/crates/${pkg}/${c.newest_version}/readme`, ctx.signal); readme = /html/i.test(r.contentType) ? htmlToMarkdown(r.text).markdown : r.text; } catch { // readme endpoint missing for some crates; metadata alone is fine } return { kind: "package-info", title: pkg, content: `${header}\n\n---\n\n${readme}` }; }, async full(pkg, ctx) { const d = await getJson(`https://crates.io/api/v1/crates/${pkg}`, ctx.signal); const v = d.crate?.newest_version; return fullFromArchive( `https://crates.io/api/v1/crates/${pkg}/${v}/download`, `${pkg}.crate.tgz`, ctx, metaBlock(`${pkg}@${v} (crates.io)`, { description: d.crate?.description }), ); }, };