csan-core 0.7.1

Cutter call number generation (Cutter-Sanborn and Library of Congress) for library cataloging
Documentation

csan

csan generates Cutter-Sanborn and Library of Congress cutter numbers for library cataloging from author names and titles. It is a command-line tool and a library for Rust, Python, JavaScript (npm), and Typst.

$ csan --forename Charles --surname Dickens --title "Oliver Twist"
D548o
$ csan --method cutter-loc --forename Charles --surname Dickens
D535

It implements two methods:

  • Cutter-Sanborn three-figure: a lookup against the bundled Cutter-Sanborn table (12,000+ entries), with an optional call number prefix and a lowercase work mark derived from the title.
  • Library of Congress: the LoC character-branching rules (Cutter table, CSM G 63), producing an initial plus a digit sequence.

Input names are normalized first: whitespace and punctuation are stripped, diacritics and ligatures are folded to ASCII (Čapek → Capek, Strauß → Strauss), Mc/M' prefixes expand to Mac, and a surname of St/Ste (as in Saint Patrick) expands to Saint/Sainte, matching the conventions of the underlying tables. Anonymous works are cuttered by title.

Install

  • Command-line tool: cargo install csan, or prebuilt with cargo binstall csan or the installers and archives on each GitHub release. With Nix (Linux, aarch64 macOS): nix run github:veralvx/csan -- --help. Without installing: npx @veralvx/csan --help.
  • Rust library: cargo add csan-core.
  • Python: pip install csan (library and CLI), or uv tool install csan for the CLI alone.
  • JavaScript (Node): npm install @veralvx/csan (library and CLI).
  • Typst: see Typst.

Command line

csan --surname Dickens --title "Oliver Twist"            # D548o
csan --method cutter-loc --surname Carter                # C378
csan --method cutter-loc --title "100 best recipes"      # A153
csan --surname Borges --json                             # {"cutter_sanborn": {"formatted": "B732", ...}}

--method selects the method, cutter-sanborn (the default) or cutter-loc, and at least one non-blank input (--forename, --surname, --title) is required. --prefix-len/--suffix-len tune the Cutter-Sanborn output, --max-len the LoC digits, and --json emits the parts as a JSON object keyed by method (cutter_sanborn or cutter_loc). Errors exit non-zero with a message on stderr.

With Nix, the flake builds the binary with the toolchain that rust-toolchain.toml pins:

nix run github:veralvx/csan -- --help
nix build github:veralvx/csan     # ./result/bin/csan
nix profile install github:veralvx/csan

Rust

The library is the csan-core crate (up to 0.5.x it was published as csan, a name that now belongs to the command-line tool):

use csan_core::{
    Attribution, Author, CutterConfig, CutterGenerator, CutterLocMethod,
    CutterSanbornMethod, Opus,
};

fn main() -> Result<(), csan_core::NormalizationError> {
    let entry = Attribution::Both {
        author: Author::new("Charles", "Dickens"),
        opus: Opus::new("Oliver Twist"),
    };

    let sanborn = CutterSanbornMethod::generate(&entry, CutterConfig::default())?;
    assert_eq!(sanborn.to_string(), "D548o");

    let loc = CutterLocMethod::generate(&entry, CutterConfig::default())?;
    assert_eq!(loc.to_string(), "D535");
    Ok(())
}

CutterConfig tunes the output: prefix_len and suffix_len control the Cutter-Sanborn prefix and work mark, and max_len controls the LoC digit count (clamped to 4). Works without an author use Attribution::OpusOnly(...) and are cuttered by title, including the LoC numeral rule ("100 best recipes" → A153). The API reference is on docs.rs.

Python

The PyPI package csan (CPython 3.9+, abi3 wheels) provides the library and the csan command:

import csan

csan.cutter_sanborn(surname="Dickens", title="Oliver Twist")  # 'D548o'
csan.cutter_loc_detailed(surname="Carter")
# {'alpha_prefix': 'C', 'formatted': 'C378', 'numeric': 378}

See the Python package README for the full API.

JavaScript

The npm package @veralvx/csan is the library compiled to WebAssembly, built for Node (CommonJS, with TypeScript declarations):

const { cutterLoc, cutterSanborn } = require("@veralvx/csan");

cutterSanborn({ surname: "Dickens", title: "Oliver Twist" }); // "D548o"
cutterLoc({ surname: "Carter" }); // "C378"

It also provides the csan command, with the same interface as the native binary. See the npm package README for the full API and the browser build.

Typst

The Typst package exposes two functions:

// Replace <version> with the installed release.
#import "@local/csan:<version>": cutter-sanborn, cutter-loc

#cutter-sanborn(
  forename: "Charles",
  surname: "Dickens",
  title: "Oliver Twist",
) // -> "D548o"

#cutter-loc(surname: "Carter") // -> "C378"

Both accept forename, surname, and title (at least one must be non-blank; blank strings count as absent). cutter-sanborn also takes prefix-len and suffix-len; cutter-loc takes max-len. Pass detailed: true to receive a dictionary of the parts (alpha_prefix, numeric, …) instead of the formatted string. Requires Typst 0.14.2 or later.

Until the package is published to Typst Universe, install it as a local package: extract the csan_typst-<version>.tar.gz attached to each GitHub release into {data-dir}/typst/packages/local/csan/<version>/, then import @local/csan:<version>. The plugin binary alone is attached as csan_typst.wasm.

Expected values

Generated by cargo run --example showcase with the default configuration:

Author Cutter-Sanborn Library of Congress
Jane Austen A933 A978
Eric Blair B635 B535
Agatha Christie C555 C475
Samuel Clemens C625 C546
Jorge De la Cruz D332 D453
Charles Dickens D548 D535
Emily Dickinson D553 D535
Fyodor Dostoyevsky D724 D678
Stephen King K54 K564
VERA LVX L979 L89
Herman Melville M531 M458
George Orwell O79 O794
William Shakespeare S527 S535
Lord Sith S623 S584
Ivan Smith S649 S658
William Smith S664 S658
Leo Tolstoy T654 T657
Mark Twain T969 T835
Virginia Woolf W913 W665
Emile Zola Z86 Z653

Contributing

Path Contents
crates/csan-core The library: normalization, models, generators, the table.
crates/csan The csan command-line tool (clap).
crates/csan-py Python bindings and the PyPI package (pyo3 + maturin).
crates/csan-web JavaScript/npm bindings via WebAssembly (wasm-bindgen).
crates/csan-typst The Typst WASM plugin wrapping the library.
crates/csan-typst/pkg The Typst package (typst.toml, lib.typ, plugin binary).

CONTRIBUTING.md covers the development setup, the checks CI runs, building the Typst plugin, and the release process. Changes are listed in the changelog.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.