| import { Router, type Request, type Response } from "express"; |
| import { Cite } from "@citation-js/core"; |
| import "@citation-js/plugin-bibtex"; |
| import "@citation-js/plugin-doi"; |
| import "@citation-js/plugin-csl"; |
|
|
| const router = Router(); |
|
|
| |
| |
| |
| |
| |
| router.post("/resolve", async (req: Request, res: Response) => { |
| try { |
| const { input } = req.body; |
| if (!input || typeof input !== "string") { |
| res.status(400).json({ error: "Missing 'input' string" }); |
| return; |
| } |
|
|
| const cite = await Cite.async(input.trim()); |
| const entries = cite.get({ format: "real", type: "json", style: "csl" }); |
|
|
| if (!entries.length) { |
| res.status(404).json({ error: "Could not resolve any reference" }); |
| return; |
| } |
|
|
| const enriched = entries.map((entry: any) => ({ |
| ...entry, |
| id: entry.id || generateKey(entry), |
| })); |
|
|
| res.json({ entries: enriched }); |
| } catch (err: any) { |
| console.error("[citations] resolve error:", err.message); |
| res.status(422).json({ error: err.message || "Failed to resolve" }); |
| } |
| }); |
|
|
| |
| |
| |
| |
| |
| router.post("/format", async (req: Request, res: Response) => { |
| try { |
| const { entries, style = "apa", locale = "en-US" } = req.body; |
| if (!Array.isArray(entries) || !entries.length) { |
| res.status(400).json({ error: "Missing 'entries' array" }); |
| return; |
| } |
|
|
| const cite = new Cite(entries); |
| const html = cite.format("bibliography", { |
| format: "html", |
| template: style, |
| lang: locale, |
| }); |
|
|
| res.json({ html }); |
| } catch (err: any) { |
| console.error("[citations] format error:", err.message); |
| res.status(422).json({ error: err.message || "Failed to format" }); |
| } |
| }); |
|
|
| |
| |
| |
| |
| |
| router.post("/import-bib", async (req: Request, res: Response) => { |
| try { |
| const { bibtex } = req.body; |
| if (!bibtex || typeof bibtex !== "string") { |
| res.status(400).json({ error: "Missing 'bibtex' string" }); |
| return; |
| } |
|
|
| const cite = new Cite(bibtex.trim()); |
| const entries = cite.get({ format: "real", type: "json", style: "csl" }); |
|
|
| const enriched = entries.map((entry: any) => ({ |
| ...entry, |
| id: entry.id || generateKey(entry), |
| })); |
|
|
| res.json({ entries: enriched }); |
| } catch (err: any) { |
| console.error("[citations] import-bib error:", err.message); |
| res.status(422).json({ error: err.message || "Failed to parse BibTeX" }); |
| } |
| }); |
|
|
| function generateKey(entry: any): string { |
| const firstAuthor = entry.author?.[0]?.family || "unknown"; |
| const year = entry.issued?.["date-parts"]?.[0]?.[0] || "nd"; |
| const base = `${firstAuthor.toLowerCase()}${year}`; |
| return base.replace(/[^a-z0-9]/gi, ""); |
| } |
|
|
| export { router as citationsRouter }; |
|
|