"""BibTeX parsing utilities.""" from __future__ import annotations try: import bibtexparser BIBTEXPARSER_AVAILABLE = True except ImportError: BIBTEXPARSER_AVAILABLE = False PLACEHOLDER_PATTERNS = ["xx", "xxxx", "art. no.", "tbd", "forthcoming", "in press"] def parse_bibtex(bibtex_str: str) -> list[dict]: """Parse BibTeX string into a list of entry dicts.""" if not BIBTEXPARSER_AVAILABLE: return [] try: bib_db = bibtexparser.loads(bibtex_str) return bib_db.entries except Exception: return [] def has_placeholder(text: str) -> tuple[bool, list[str]]: """Detect placeholder values in a citation field. Returns (found, patterns).""" found = [] lower = text.lower() for pattern in PLACEHOLDER_PATTERNS: if pattern in lower: found.append(pattern) return bool(found), found def entry_to_bibtex(entry: dict) -> str: """Convert a bibtexparser entry dict back to a BibTeX string.""" etype = entry.get("ENTRYTYPE", "misc") key = entry.get("ID", "unknown") fields = {k: v for k, v in entry.items() if k not in ("ENTRYTYPE", "ID")} lines = [f"@{etype}{{{key},"] for k, v in fields.items(): lines.append(f" {k} = {{{v}}},") lines.append("}") return "\n".join(lines) def generate_bibtex_from_metadata( key: str, title: str | None, authors: list[str], year: str | None, venue: str | None, url: str | None, doi: str | None, ) -> str: """Generate a minimal BibTeX entry from known metadata.""" author_str = " and ".join(authors) if authors else "Unknown Author" lines = [f"@article{{{key},"] if title: lines.append(f" title = {{{title}}},") lines.append(f" author = {{{author_str}}},") if year: lines.append(f" year = {{{year}}},") if venue: lines.append(f" journal = {{{venue}}},") if doi: lines.append(f" doi = {{{doi}}},") if url: lines.append(f" url = {{{url}}},") lines.append(" note = {Citation status: needs-verification},") lines.append("}") return "\n".join(lines)