You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fixed: the check command now audits every bare (unbraced) field value for a reference to an undefined @string macro, not just journal. Such a reference renders as the macro name itself (month = sept becomes literal sept, publisher = elsevir becomes elsevir) and is refused by Library.save, so a file could previously pass check and then be impossible to write (a subsequent bibdeskparser set_field ... failing with an undefined macro(s) referenced by one or more entries error naming those bare values); a passing check now implies a writable file. Only a value that is a valid macro name is considered, so a bare non-macro value like volume = 90 is not flagged, and keywords (always literal text) is exempt, matching what save scans. The audit name in the --json output is undefined_macro; an undefined macro that is also not a month (month = sept) is reported by both the month and the undefined_macro audit. [[#56], [#61]]
Added: two new check audits over the date fields, reporting values that the citation-key specifiers %Y and %m mis-read in silence. year reports an entry whose year does not read as a four-digit year (Monroe2008: year 'August, 2008' does not read as a four-digit year (%Y gives '0')), which is what %Y reduces (about 1984), in press, and n.d. to as well. A value BibDesk reads correctly without being a bare four-digit string still passes: 08 maps into 1950--2049, and trailing text after the digits (2008a, 2001--) is ignored. month reports an entry whose month is anything but a bare reference to one of the twelve standard month macros jan ... dec, either a literal value (Monroe2008: month is the literal string 'June', not one of the twelve standard month macros (jan ... dec)) or a macro outside the twelve, defined or not (month = sept). A literal 06 or June is reported although it renders correctly, for the same reason a literal journal value is: a .bst style typesets jun as June, Jun., Juni, or 6, and writing the month out freezes one of those choices into the database. Unlike the year audit, the month audit inspects the stored value rather than what %m renders, since %m answers 01 for every value it cannot parse, indistinguishable from a genuine January. Both audits look only at a field the entry defines with a non-empty value; an absent or empty one is reported by the required_fields and empty_fields audits instead. The audit names year and month also appear in the --json output. [[#55], [#60]]
Changed: Library.eval_format_spec (and the eval_format_spec CLI command) now always returns the evaluated citation key, even one that equals the entry's own crossref value, instead of raising ValueError: evaluating a format is a preview and applies nothing. Library.rekey (and the rekey command) still refuses to apply such a key. The check --key-format audit reports such an entry as an ordinary key deviation, naming the generated key, rather than as unevaluable. [[#60]]
Added: two new check audits over every entry. entry_type reports an entry whose type is not one of the recognized entry types (Bogus2026: unrecognized entry type 'bogustype'), and required_fields reports each field the entry's type lists as required that the entry does not have (NoYear2014: missing required field 'year' for entry type 'article'), one problem per field. Loading a .bib file deliberately never validates, so nothing had ever looked at either: an @article holding only a doi, and an entry of a type that does not exist, both passed the gate. A defined-but-empty field counts as missing, so year = {} is reported by both required_fields and empty_fields. An entry whose type is unrecognized is not additionally audited for required fields, and a recognized type BibDesk does not template (an extended biblatex type such as dataset) has no required fields on record and is skipped; a types.NAME table in bibdeskparser.toml declares either, making the type recognized and supplying the required list to audit against. Neither audit is gated by verify_types/verify_fields, which govern what happens when a type or field is assigned in Python, nor exempted by a known-missing group, which records a verified-absent optional field: an @article with no year is not an article, and the fix for one is @misc, which requires nothing. The audit names entry_type and required_fields also appear in the --json output. [[#54], [#59]]
Fixed: a citation-key or file-name format that references a field an entry does not have now renders that field as empty, as BibDesk does, instead of refusing to generate anything. The entry simply gets a shorter result: under %a1%c{journal}0%Y%u0, an entry without a journal keys as Smith2020, one without a year as SmithPRA. An entry that renders every specifier of a file-name format empty is filed as a.pdf rather than under the bare extension .pdf, i.e. the format's required unique specifier fills the stem instead of the file becoming a hidden one (BibDesk guarantees a non-empty name, but not a non-empty stem). A format can therefore reference a field only some entries carry -- keying @misc talks by their howpublished venue while the software and lecture notes in the same library key as author plus year -- where previously the venue had to be dropped from the format for every @misc entry, since the entries lacking it could not be keyed at all. This affects Library.rekey, Library.eval_format_spec, Library.import_bibtex, Library.add_file, and Library.rename_file, along with the rekey, eval_format_spec, import, add, add_file, and rename_file CLI commands. The check --key-format audit no longer reports such an entry as unevaluable: it now conforms if its key matches the shortened form, and is otherwise reported like any other deviating key, naming the key the format generates. [[#53], [#58]]
Fixed: citation-key generation now folds a non-ASCII Latin letter to its ASCII base letter instead of deleting it. Only letters that Unicode decomposes into a base letter plus a combining mark (ü, ğ, ř) were handled before, along with a hand-written table of ligatures and stroked letters (æ, ß, ø, đ); every other letter was silently dropped, so Kılıç keyed as Klc, Masłowski as Masowski, and Əliyev as liyev. The base letter is now read off the Unicode character name, which covers the whole class rather than the codepoints someone thought to list: dotless ı, ł (whose uppercase Ł was in the table), ĸ, ŋ, ə, and 100+ more. Ligatures and digraphs are spelled out (dž → dz), matching BibDesk, which transliterates before falling back to a lossy conversion. Existing keys are unaffected unless they contain such a letter, in which case single-argument rekey (and the check --key-format audit) will now propose the corrected key. Text in a script with no Latin rendering (Greek, Cyrillic, CJK) is still dropped. [[#52], [#57]]
Fixed: Library.search (and the search CLI command) now finds such a letter by its ASCII spelling at the folded match level. Its fold handled only decomposable accents plus ß, so Mølmer was reachable by Molmer only at the fuzzy level, below the default, and bibdeskparser search Molmer on a library full of Mølmer entries returned nothing; Kılıç was unreachable by Kilic at any level, since two unfoldable letters in a short word put it under the fuzzy threshold. Entries affected by this move up the ladder, which changes their rank in a result list. Text in a script with no ASCII spelling is left intact by the fold rather than dropped, so a Cyrillic or CJK value is still found by itself. [[#52], [#57]]
Fixed: Library.add_preprint and Library.add_doi now compare an author's last name correctly when it contains such a letter. The fold behind the comparison covered 24 hand-listed letters, so ə, ŀ, ĸ, ʼn, and the rest of the class went unfolded on the entry side but were stripped on the arXiv/Crossref side (əliyev against liyev), which silently disabled the title+author acceptance rung for those entries and, with a known-missing group configured, could record a false verified-absent. [[#52], [#57]]