npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@hosanna/chordpro

v1.7.2

Published

ChordPro parser, renderer, and editor for Hosanna

Readme

@hosanna/chordpro

A modular ChordPro parser, transformation pipeline, formatter, instrument registry, React renderer, and Ace editor for JavaScript and TypeScript.

Features

  • ChordPro AST parsing with metadata, sections, tabs, grids, comments, repeats, and named variants.
  • Immutable, chainable song transformations: transpose, capo, chord simplification, chord removal, variant selection, and instrument selection.
  • Extensible formatting and linting utilities.
  • Registry-based instrument diagrams for guitar, piano, ukulele, and consumer-defined instruments.
  • React rendering from an already transformed SongAST.
  • Lazy Ace editor with ChordPro syntax support, snippets, linting, formatting, and transpose commands.

Installation

npm install @hosanna/chordpro

React consumers also need the peer dependencies:

npm install react react-dom ace-builds react-ace

Modular entry points

| Entry point | Contents | | ------------------------------- | ----------------------------------------------------------------------------- | | @hosanna/chordpro | All public APIs | | @hosanna/chordpro/parser | Parser, AST types, transformations, transposition, dictionary, and converters | | @hosanna/chordpro/renderer | ChordProRenderer, ChordRoll, and diagram components | | @hosanna/chordpro/editor | Editor, ChordFinder, Ace modes, snippets, and editor integrations | | @hosanna/chordpro/formatter | ChordPro formatter and formatter types | | @hosanna/chordpro/instruments | Instrument profiles and the instrument registry | | @hosanna/chordpro/diff | ChordProDiffEditor (VS Code-style diff review) and the diff engine |

Review a proposed change (diff editor)

Pass a proposal to Editor to swap the text editor for an inline diff against the current value. Every change can be kept or undone individually; nothing touches the document until onAccept runs.

<Editor
  value={content}
  onChange={setContent}
  proposal={
    pending && {
      content: pending.content,
      title: "AI proposal",
      onAccept: (next) => {
        setContent(next); // the proposal minus any undone changes
        setPending(null);
      },
      onReject: () => setPending(null),
    }
  }
/>

ChordProDiffEditor is also available standalone (original, modified, onAccept, onReject), with inline and side-by-side views, word-level highlights that treat [chords] as atomic tokens, collapsible unchanged regions, an overview ruler, and shortcuts (F7 / Shift+F7 next/previous change, Ctrl/Cmd+Enter apply, Ctrl/Cmd+Z undo/keep the active change). Colours come from --hcd-* CSS variables; strings from the labels prop. The raw engine (computeDiff, resolveHunks, wordDiff) is exported too.

Parse and transform a song

parseChordPro returns a SongAST. Every transformation returns a new song, so pipelines can be reused safely without mutating the parsed source:

import { parseChordPro } from "@hosanna/chordpro/parser";

const source = `
{title: Hallelujah}
{key: C}
{start_of_version: Acoustic}
[C]Halle---lu---jha
{end_of_version}
`;

const song = parseChordPro(source)
  .transpose(2)
  .withCapo(3)
  .simplifyChords(1)
  .removeChords(true)
  .selectVariant("acoustic")
  .instrument("guitar");

Transformation operations

| Operation | Description | | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | | .transpose(semitones) | Transposes every chord, key, and bass note by the requested interval. | | .withCapo(position) | Stores the capo and moves chord shapes into capo-relative notation. 0 disables it. | | .simplifyChords(level) | Simplifies chord qualities. 0 original, 1 slightly simplified, 2 beginner, 3 basic triads only. | | .removeChords(cleanText) | Removes chord annotations from every variant. With true, also joins display-only hyphenation such as Halle---lu---jha. | | .selectVariant(id) | Selects a named variant (null, undefined, or "default" selects the default) and returns a song containing only that version. | | .instrument(id) | Stores the instrument used by downstream renderers. Pass null to clear it. |

The functional equivalent is available for consumers that prefer an explicit pipeline entry point:

import { transformSong } from "@hosanna/chordpro/parser";

const transformed = transformSong(parseChordPro(source))
  .transpose(2)
  .withCapo(3);

The pipeline is extensible: custom transformations can clone a SongAST, update its sections or metadata, and return the result for the next operation.

Analyze a song

analyze() returns structural and harmonic information without changing the song:

const analysis = parseChordPro(source).analyze();
// {
//   key: "G",
//   detectedKey: "G",
//   tempo: 72,
//   chordCount: 14,
//   uniqueChords: ["G", "C", "Em", "D"],
//   sections: 8,
//   lyricsLength: 1240,
//   hasTabs: false,
//   hasAnnotations: true,
//   hasVariants: true
// }

detectedKey is inferred from chord roots, chord qualities, and diatonic major/minor scale membership. It is independent from the optional declared key, so consumers can compare source metadata with the detected harmonic center.

Render a transformed song

Pass the transformed AST to the renderer. The renderer does not parse source text or apply a second transformation:

import { ChordProRenderer } from "@hosanna/chordpro/renderer";

export function SongViewer({ source }: { source: string }) {
  const song = parseChordPro(source)
    .selectVariant("acoustic")
    .transpose(2)
    .withCapo(3)
    .instrument("guitar");

  return <ChordProRenderer song={song} showDiagrams />;
}

The renderer accepts only a transformed SongAST. It derives chord visibility from the AST and reads the selected instrument from song.metadata.instrument; call .removeChords(true) or .instrument("guitar") in the pipeline before rendering.

Source-preserving transpose

When you need ChordPro text back (for saving or MCP proposals) without losing unrelated content, use transposeChordProSource instead of round-tripping the AST:

import { transposeChordProSource } from "@hosanna/chordpro/parser";

const { content, semitones, fromKey, toKey } = transposeChordProSource(
  source,
  { toKey: "A" },
);
// or: transposeChordProSource(source, 2)

This rewrites [chords] (including timings like [Am@2x]) and {key:} / {original_key:} while preserving lyrics, variants, comments, and unknown directives.

Capability manifest

import {
  getChordProCapabilities,
  explainChordProDirective,
} from "@hosanna/chordpro/parser";

const manifest = getChordProCapabilities();
const version = explainChordProDirective("start_of_version");

Each directive is marked parsed, formatter-only, or unsupported. Features such as variants, grids, and AST serialization are marked implemented, partial, or not_implemented.

Variants

Use version blocks in ChordPro:

{title: Amazing Grace}
[G]Amazing grace

{start_of_version: Acoustic}
[C]Amazing grace
{end_of_version}

Variant IDs are generated as stable slugs ("Acoustic" becomes "acoustic"). Variant metadata inherits from the preceding version and can override individual fields.

Instruments

Instrument diagrams use a registry rather than renderer conditionals:

import { instrumentRegistry } from "@hosanna/chordpro/instruments";

instrumentRegistry.register({
  id: "mandolin",
  displayName: "Mandolin",
  category: "string",
  supportsCapo: true,
  getFingering: (chord) => resolveMandolinShape(chord),
  renderDiagram: (shape) => <MandolinDiagram shape={shape} />,
});

An InstrumentProfile resolves a chord into instrument-specific shape data and renders that data. Custom instruments work with ChordRoll and ChordProRenderer without changing either component.

Formatting and editor

import { formatChordPro } from "@hosanna/chordpro/formatter";

const result = formatChordPro(source, {
  normalizeNotationAliases: true,
  expandDirectiveAliases: true,
});
import { Editor } from "@hosanna/chordpro/editor";

<Editor
  value={source}
  onChange={setSource}
  onSave={(nextSource) => save(nextSource)}
  settings={{ theme: "textmate", fontSize: 14, wordWrap: true }}
/>;

The editor includes ChordPro completion, diagnostics, section shortcuts (Alt+V, Alt+R, Alt+B), transpose (Alt+T), and formatting (Ctrl/Cmd+Shift+F).

Supported directives

Metadata includes title, subtitle, artist, composer, album, copyright, key, original_key, capo, tempo, time, duration, song_number, ccli, and youtube. Sections include verses, choruses, bridges, tabs, grids, comments (with optional |style suffixes), repeats, and named versions (start_of_version / end_of_version).

Comment styles example: {c: Softly|warning}. Layout directives such as define, fonts, new_page, and column_break may be recognized by the formatter but are not fully supported by Hosanna’s parser or renderer — see getChordProCapabilities().

License

Licensed under the Apache License 2.0.