@citation-js/core
Parses and converts bibliographic metadata between BibTeX, CSL-JSON, RIS, Wikidata, and other citation formats through a pluggable parser architecture.
Repository Health
Technical Analysis
@citation-js/core is the engine behind Citation.js, a JavaScript library that normalizes bibliographic metadata from disparate sources - BibTeX, RIS, Wikidata JSON, BibJSON, and DOI records - into a common CSL-JSON representation, then re-exports it as formatted citations in styles like APA, Vancouver, and Chicago. The Cite class is the primary entry point: it accepts almost any recognizable input, parses it through a chain of registered format plugins, and exposes methods to add, sort, filter, and format the resulting reference list, either synchronously or through an async API for network-backed sources like Wikidata and DOI lookups.
Rather than hard-coding format support, core ships a plugin registry (plugins.add/plugins.input/plugins.output/plugins.dict) that lets separate packages - plugin-bibtex, plugin-csl, plugin-ris, plugin-doi, plugin-wikidata, plugin-bibjson, and third-party plugins - register their own input parsers, output formatters, and citation-style dictionaries at runtime. A companion Translator utility declaratively maps properties between a plugin’s native schema and CSL-JSON, so new format support can be added without touching core’s parsing logic.
What You Get
Citeclass - constructor for parsing, storing, and reformatting bibliographic entries from almost any recognized input.- Plugin registry -
plugins.add/remove/has/listAPI for registering input parsers, output formatters, and CSL dictionaries. Translatorutility - declarative source-to-target property mapping for converting between a plugin’s native schema and CSL-JSON.- Async API -
Cite.async()for input sources that require network requests, like Wikidata and DOI lookups. - Graph-based input chain resolution - automatic format detection and parser chaining so callers don’t have to specify an input type.
Common Use Cases
- Converting a BibTeX bibliography to APA- or Vancouver-formatted HTML for a webpage.
- Normalizing citation exports from multiple reference managers into one CSL-JSON dataset.
- Fetching and formatting a reference directly from a DOI or Wikidata identifier.
- Building a custom citation-format plugin on top of a stable parsing/formatting core.
Under The Hood
Architecture
The Cite class (packages/core/src/Cite/index.js) composes mixins - log, options, set, sort, get, static - onto its prototype via Object.assign rather than deep class inheritance, keeping each concern in its own file. Parsing is decoupled from the Cite class entirely: plugins/input/chain.js implements a ChainParser that treats format conversion as a graph-traversal problem - it repeatedly applies registered type/data parsers to walk the input’s format graph toward a target format (default @csl/list+object), recording each hop for debugging and enforcing a maxChainLength to avoid infinite loops. The plugin system (plugins/index.js) is an in-memory registry keyed by plugin reference, delegating to per-type registries (input, output, dict, config) via a small Register class. Because every one of the eight published packages in this monorepo (core, cli, and six format plugins) depends on this exact registry/chain-parser contract, changing chain resolution or the Register interface would require coordinated changes across the whole monorepo.
Tech Stack
Plain ES-module JavaScript, transpiled via Babel to two output targets - a CommonJS lib/ build and an ES-module lib-mjs/ build - so consumers get both require() and import support from one source tree. The monorepo is managed with npm workspaces plus Lerna, with each of the eight sub-packages versioned and published independently. Core’s only runtime dependencies are two sibling packages, @citation-js/date and @citation-js/name, plus sync-fetch for synchronous HTTP requests so the non-async constructor can still resolve network-backed inputs like DOIs. Docs are generated with JSDoc from inline annotations, and CI runs on GitHub Actions.
Code Quality
Tests use Mocha with expect.js (mocha -c -R dot -r @babel/register test/*.spec.js), run per-package via lerna run test; core’s suite covers iteration, save-log behavior, async/callback duality, and plugin re-registration against fixture data. Coverage is measured with nyc/istanbul and reported as lcov for CI. Linting is StandardJS via a shared Babel-aware ESLint parser, enforced in a preversion hook. There is no TypeScript - the codebase is untyped JS with JSDoc annotations standing in for static types, so there’s no compiler-level correctness guarantee, though error handling is largely explicit (cause-chained conversion errors, a strict option and chain-length guard on the parser).
API Design
The public API favors minimal ceremony: new Cite(anything) auto-detects format through a type-parser registry instead of requiring callers to declare an input type, and the constructor doubles as a factory when called without new. The graph-based ChainParser is the most distinctive design choice for a citation library - plugins only need to define format detection and a to-CSL parser, and the chain resolver generically finds a path from any registered format to CSL-JSON, so adding a new format needs one converter into CSL rather than pairwise converters against every existing format. Documentation is thorough and tutorial-driven, and the two-line quick start (new Cite('Q21972834').format(...)) keeps first-use boilerplate low relative to comparable bibliography tooling.