chord_pro 0.8.0 copy "chord_pro: ^0.8.0" to clipboard
chord_pro: ^0.8.0 copied to clipboard

A Dart parser for the ChordPro 6 song format. Extracts chords, lyrics, metadata, comments, layout hints and chord diagrams.

0.8.0 #

Round-tripping release. Text that the parser used to drop on the floor — the body of a selector-suppressed section, and a verbatim line that happens to start with { — now survives into the AST, so re-emitting a song from what was parsed no longer loses lines.

Breaking #

  • A {start_of_X-sel} whose selector is not active now produces a Section in Song.sections instead of being dropped. The section is flagged with the new Section.isSelectorSuppressed and carries its body lines, so re-emitting a song from the AST no longer deletes the text between the markers (#36). A renderer that honours selectors should iterate the new Song.activeSections (sections minus the suppressed ones) instead of sections. Two consequences of the section now being real: a run of loose lines interrupted by a suppressed section is split into two loose sections rather than joined into one, and a suppressed start inside an open section auto-closes it with the same nestedSection diagnostic an applying start already produced. Spec: https://www.chordpro.org/chordpro/chordpro-configuration-selectors/

New #

  • Section.isSelectorSuppressed — true when the section's start directive carried a selector that was not active for this parse. Carried through Song.transposed and part of Section equality.
  • Song.activeSections — the sections a selector-honouring renderer should output, i.e. sections without the suppressed ones.

Fixed #

  • Inside a verbatim environment (tab, grid, abc, ly, svg, textblock, grille) only the matching {end_of_X} is interpreted now. A body line starting with { — a LilyPond {\key c \major}, a tab annotated {riff x2} — used to be parsed as a directive, so it vanished from the section body and reappeared in Song.directives with no diagnostic. Such lines are Line.verbatim body text again, and no longer land in Song.directives. The same rule applies to a selector-suppressed verbatim environment. Spec: https://www.chordpro.org/chordpro/directives-env_tab/

0.7.0 #

Correctness and API release from a full package review. Three parser bugs fixed, value equality added across the AST, diagnostics given stable codes, and the spec audit taught to check its own forward direction.

Breaking #

  • Diagnostic now requires a code, a DiagnosticCode naming the condition it reports. Switch on code instead of matching message, which is prose and may be reworded in any release. Code that constructs a Diagnostic must pass one; code that only reads them is unaffected.
  • Chord.extensions (a List<String> that never held more than one element) is now Chord.extension, a String? holding everything after the quality verbatim. Replace chord.extensions.join() with chord.extension ?? ''. The ChordPro spec defines no grammar for what follows the quality, so the remainder was never actually split. Spec: https://www.chordpro.org/chordpro/chordpro-chords/
  • Song.transposed no longer returns this when the shift is a whole number of octaves. It normalises chord spelling to the requested accidentals as well as the pitch, so transposed(0, accidentals: AccidentalPreference.flats) now respells a song in flats instead of doing nothing. Callers that relied on transposed(0) being an identity should skip the call instead.
  • Chord.tryParse('b7') and its siblings b1–b7 now report ChordSystem.nashville rather than ChordSystem.letter. See Fixed.

New #

  • Every public type in the AST implements == and hashCode structurally: Song, Metadata, Section, Line, all five InlineToken subtypes, Chord, ChordDefinition, Directive, ImageDirective, GridAttributes, TextblockAttributes, DiagramsSetting, FormattingProps, FormattingSettings, Diagnostic, ParseResult, SourceSpan and RawLine. Parsed songs can now be compared in tests, deduped, cached or used as map keys. The package still has zero runtime dependencies.
  • DiagnosticCode — a stable identifier on every diagnostic, exported from the barrel.
  • Numeric metadata directives given a non-number ({capo: high}, {year: MCMXCIX}, {tempo: fast}, {columns: many}, {transpose: up}) now produce a DiagnosticCode.invalidNumericValue warning instead of being dropped in silence.
  • An unterminated selector-suppressed section is reported as DiagnosticCode.unterminatedSuppressedSection, matching the warning an unterminated ordinary section already produced.

Fixed #

  • Song.transposed dropped Section.attributes, so transposing a song lost its grid geometry and every textblock attribute — {start_of_grid: 4x4} came back with no shape at all. The attributes are now carried over. Spec: https://www.chordpro.org/chordpro/directives-env_grid/
  • A selector-suppressed section with no matching end directive swallowed the rest of the document, {new_song} included: two songs collapsed into one with no sections and both titles merged. Song boundaries are structural and are never conditional, so they now end the suppression. Nesting is tracked too, so a same-kind section inside a suppressed one no longer ends the suppression early and leaks its lines. Spec: https://www.chordpro.org/chordpro/chordpro-directives/
  • Flat Nashville roots (b1–b7) were reported as ChordSystem.letter, because the notation system was re-derived from the root text, where a leading b is ambiguous between a flat and a notes-mode lowercase root. The system now comes from the branch that matched the root. Spec: https://www.chordpro.org/chordpro/chordpro-chords/
  • Line.tokens, ChordDefinition.frets / fingers / keys and the chord extension list were handed out as mutable lists, so a caller could rewrite a parsed song in place. Every collection the parser produces is now unmodifiable, including the ones rebuilt by Song.transposed.
  • A single-hex-digit brace escape on a line of its own (\u{7}) was left unresolved by a minimum-length guard, and the inline tokenizer then ate the backslash and read {7} as a directive. The guard is gone; lines with no backslash take a fast path instead, which is also cheaper than the three rewriting passes it replaces. Spec: https://www.chordpro.org/chordpro/chordpro-introduction/
  • altBrackets was a whole-document string replacement, so the configured pair was rewritten inside directive values and verbatim bodies too — a song using «» as quotation marks in its {title} came back with brackets. The rewrite now applies to lyric lines only. Spec: https://www.chordpro.org/chordpro/chordpro-configuration-generic/
  • A {chorus} recall inside an open section was appended to Song.sections before the section it appeared inside, losing source order. The open section is now closed first (reported as DiagnosticCode.chorusRecallInsideSection) and its own end directive is consumed quietly rather than reported as a stray end. Spec: https://www.chordpro.org/chordpro/directives-chorus/
  • settings.strict scanned the raw directive stream, so {meta: key D} satisfied Metadata.keys yet still warned that no key was declared. It now reads the reduced metadata, and the warning's span points at the song that is missing the key instead of always at line 1.
  • {define: ""} produced a chord definition named "", and {image: ""} produced nothing at all — in both cases silently, because the "malformed" diagnostic for each was unreachable. Both are now reported.

Internal #

  • test/spec_coverage_test.dart gained the checklist → audit direction: every checklist subsection holding ticked spec obligations must be named by an [§…] coordinate in test/spec_audit_test.dart. Backfilled the subsections it found bare (§2.12, §6.7, §13.1–§13.4, §13.7, §13.8).
  • The {start_of_grid} body-token vocabulary is unticked in chordpro-spec-checklist.md and recorded in doc/reference/limitations.md: grid bodies are captured verbatim, so those tokens were never surfaced.
  • Added test/fuzz_test.dart, a seeded property test asserting that parsing is total — random input never throws and always yields at least one song — across the plain, option-laden and transposing paths.

0.6.3 #

Maintenance release: documents the {colb} shorthand, adds a reverse-direction spec-coverage guard to the test suite, and widens the very_good_analysis dev-dependency constraint to <12.0.0. No parser or public API changes.

Fixed #

  • {colb} — the parser's non-spec shorthand for {column_break} — is now listed in the non-spec extensions table (doc/reference/non-spec-extensions.md). The spec's own shorthand {cb} is already taken by {comment_box}, so {colb} provides an unambiguous short form. It was recognised by the assembler but undocumented; a new test/spec_coverage_test.dart guard now fails when any name in the parser's dispatch tables is absent from both the spec checklist and that table. Spec: https://www.chordpro.org/chordpro/directives-column_break/

0.6.2 #

Breaking #

  • InlineToken is a sealed class. Adding ChordRecallToken to its hierarchy is a breaking change for any code with an exhaustive switch on InlineToken subtypes. Add a ChordRecallToken case (or a wildcard _ fallback) to fix.

New #

  • ChordRecallToken — new InlineToken subtype emitted when the tokenizer encounters [^], the chord-recall operator introduced in ChordPro 6.070 (experimental). Renderers should advance the active chord-change set (cc) cursor when they encounter this token. Spec: https://www.chordpro.org/chordpro/ChordChanges/
  • notesMode parameter on Chord.tryParse, tokenizeInline, assemble, ChordPro.parse, and ChordPro.parseSong — when true, lowercase a–g are accepted as letter-system chord roots, mirroring the settings.notes ChordPro configuration option. Defaults to false; no behaviour change for existing call sites. Transposition of notes-mode roots is supported through the same chromatic table as uppercase roots.
  • strict parameter on ChordPro.parse and ChordPro.parseSong (and the internal assemble) — when true, a DiagnosticSeverity.warning is emitted for each song that lacks a {key} directive, mirroring the settings.strict ChordPro configuration option. Defaults to false, consistent with the ChordPro 6.100 change that made forgiving the built-in default.
  • forceCommonKeys parameter on Song.transposed, Chord.transpose, and transposeRoot — when true, roots that would produce key signatures with more than 5 accidentals are substituted with their enharmonic equivalents: C#→Db, D#→Eb, G#→Ab, A#→Bb. Mirrors the keys.force-common ChordPro 6.100 configuration option. Defaults to false; no behaviour change for existing call sites.
  • Preprocessor typedef (String Function(String line)) exported from package:chord_pro/chord_pro.dart. Pass a list of preprocessors to ChordPro.parse / ChordPro.parseSong via the preprocessors: named argument; each function is applied to every physical source line in list order before scanning begins. Line endings (\r\n, \r) are normalised to \n before preprocessing.

0.6.1 #

Maintenance release: adds the grille delegated environment and corrects the legacy {no_grid} / {ng} directives. No breaking changes.

New #

  • SectionKind.grille — recognises {start_of_grille} / {end_of_grille} as the experimental Grille.pm delegated environment from the reference implementation. Previously these fell through to SectionKind.custom (non-verbatim); they are now captured verbatim, consistent with other delegated environments (abc, ly, svg, textblock). Spec: https://www.chordpro.org/chordpro/directives-env_grille/

Fixed #

  • Legacy {no_grid} / {ng} now disable chord diagrams (equivalent to {diagrams: off}), matching their {diagrams} / {g} counterparts. Previously they fell through to the generic directive path, leaving Song.diagrams unset. Both forms remain in the lossless Song.directives stream.

0.6.0 #

Final ChordPro 6 spec-parity pass: fills the parser-implementable gaps left by 0.5.0's audit. Surface changes are mostly additive; a handful of multi-valued metadata fields move from scalar to list to match the spec.

Breaking #

  • Metadata.sortTitle / Metadata.sortArtist → Metadata.sortTitles / Metadata.sortArtists (lists). One sort entry per title / artist in matching source order per directives-sorttitle/ and directives-sortartist/. The old scalar names remain as convenience getters returning the first entry.
  • Metadata.key / Metadata.time / Metadata.tempo → Metadata.keys / Metadata.times / Metadata.tempos (lists). Each declaration applies from its position onward per directives-key/, directives-time/, directives-tempo/. The scalar names remain as convenience getters for the first (primary) declaration.

New #

  • ChordPro.parse / parseSong accept an altBrackets argument that rewrites a configured two-character pair (e.g. «») to [ / ] before parsing. Mirrors the parser.altbrackets configuration option.
  • GridAttributes.ccName and .ccProgression decode the ChordPro 6.070 cc="Name" / cc="Name:C1 C2 …" forms into a typed name plus chord list. The raw cc string is still surfaced verbatim.
  • ImageDirective accepts trbl= as a synonym for bordertrbl= (both names appear in the official docs).
  • {define} / {chord} accept base_fret (underscore) as a synonym for base-fret per directives-define/.
  • Falsy keyword set for toc=, omit=, … now covers the full key_value_pairs/ list: 0, false, null, no, none, off, plus the empty string.
  • Reserved metadata namespace extended to cover the full chordpro-configuration-format-strings/ list: page, pageno, pages, pagerange, instrument, instrument.type, instrument.description, tuning, user, user.name, user.fullname.

0.5.0 #

ChordPro 6 spec parity pass against the upstream reference parser (ChordPro/chordpro head, currently 6.101). Net additive surface — no breaking changes from 0.4.0.

New typed accessors #

  • Metadata.arrangers (list, like composers and lyricists). Spec: https://www.chordpro.org/chordpro/directives-arranger/.
  • Metadata.transposeQualifier (TransposeQualifier enum: none, sharps, flats, followKey). Captures the postfix s | # | ♯ | f | b | ♭ | k on {transpose: N…} per Transpose.pm:114. The k qualifier was added in ChordPro 6.100.
  • ImageDirective.label (visible caption, ChordPro 6.040), .href (6.060), .x, .y, .spread, .bordertrbl, .center, .chord, .type, .persist, .omit.
  • ImageDirective.anchorEnum (ImageAnchor enum: paper, page, allpages, column, float, line). allpages was added in ChordPro 6.080.
  • ChordDefinition.display (5.989), .format, .keys (0.979), .copy, .copyall, .diagram (6.010), .isTransposable (6.100). Fingers may now be string letters (A–M, O–W, Y, Z) in addition to integers and muted markers.
  • Section.label is now populated from {start_of_*: label="…"} as well as the legacy bare-value form. Section.attributes exposes any extra KV pairs.
  • Section.gridAttributes (GridAttributes with shape, cc, label — cc defaults to "grid" per spec).
  • Section.textblockAttributes (TextblockAttributes covering the full ChordPro 6.050 attribute set plus image-inherited fields).
  • Song.tocSuppressed (from {ns toc=no}, ChordPro 6.040).
  • Song.titlesAlignment (TitlesAlignment.left|center|right; centre accepted as alias).
  • Song.diagrams (DiagramsSetting{enabled, position}; position enum top|bottom|right|below). The {g} shorthand now aliases {diagrams} per spec.

Parser / scanner #

  • + accepted as an augmented quality marker (spec alternate for aug). C+ now parses as quality: '+' rather than extensions: ['+'].
  • \u{X+} brace-form unicode escape (1+ hex digits, surrogates recombined) added in ChordPro 6.060, alongside the existing \uXXXX 4-digit form.
  • Empty [], whitespace-only [ ]+, and pipe [|] chord brackets are recognised per ChordPro 6.020/6.080 emergency rules: whitespace-only and pipe become AnnotationTokens; empty [] is a zero-width placeholder (no token emitted).
  • Auto-generated metadata names (_key, key.print, key.sound, today, songindex, chordpro.version, …) are reserved — user {meta:} cannot collide.
  • {define} fret values now accept -1 (ChordPro 6.060) and N (in addition to x/X/-).
  • Bracketed {define: [Name] …} form parses as transposable (attributes discarded per spec).

Reference #

Verified against lib/ChordPro/Song.pm and lib/ChordPro/Chords/Transpose.pm at ChordPro/chordpro HEAD plus the upstream Changes file through 6.101 (2026-04-30).

0.4.0 #

Spec-compliance pass against the ChordPro reference parser.

  • Breaking: the canonical negation form is now postfix ! — {name-sel!} — matching the ChordPro spec and the reference Perl parser (s/\!$//). Directive.toString emits this form. The previous prefix {name-!sel} and legacy {name+sel} forms continue to be accepted on input for backward compatibility but are now flagged as non-spec.
  • Conditional selectors now gate all directives, not just metadata and formatting. Sections with an inactive selector skip their entire body (lines, nested directives, and the section end), per spec ("selection applies to everything in the section, up to and including the final section end directive"). Comments, images, layout breaks, chorus recalls, and {define}/{chord} definitions are likewise suppressed when their selector polarity does not match.
  • Add the spec-listed chord qualifiers ^ (alternate for maj), h (half-diminished), and 0 (diminished, literal zero). The pre-existing ø/° glyphs remain as documented non-spec extensions.
  • Add ChordPro 6.01 scanner features: \-terminated line continuation (with leading whitespace stripped from the next line) and \uXXXX Unicode escapes anywhere in the source.
  • Document explicitly which features are non-spec extensions of this parser (German H, unicode accidentals, ø/°, NC/N.C./N.C, bracket-escapes, mid-lyric directives, legacy selector forms) and which spec features are not yet covered (label="…" parsing, Pango markup, {define} format strings).

0.3.0 #

  • Add selectors: argument to ChordPro.parse / parseSong so callers can activate conditional directives. The same set is forwarded to reduceFormatting, which now honours selector polarity. Matching is case-insensitive.
  • Directive.toString emits a postfix ! for negative polarity instead of the legacy +sel form.
  • Drop the unused collection dependency.

0.2.0 #

  • Skip # file-comment lines per spec.
  • Add sortartist and tag metadata fields.
  • Accept spec-form {name-!sel: …} selector negation alongside the legacy +sel form.
  • Emit {comment} / {comment_italic} (ci) / {comment_box} (cb) / {highlight} as Line.comment entries.
  • Parse {image: …} into a typed ImageDirective exposed as Line.image entries.
  • Add Chord.transpose, Song.transposed, and metadata.transpose.
  • Recognise {new_page} / {new_physical_page} / {column_break} as Line.layoutBreak entries; capture {columns} / {col} as metadata.columns.
  • Add svg and textblock verbatim section kinds.
  • Reduce font/size/colour directives into Song.formatting (FormattingSettings keyed by target).
  • Recognise x_* custom-extension directives via Directive.isCustomExtension and Song.customExtensions.
  • Extend the chord parser to handle German H, unicode ♯/♭, minor variants (mi, -), half-diminished ø, diminished °, and NC/N.C. no-chord markers.

0.1.0 #

  • Intial
0
likes
160
points
194
downloads

Documentation

Documentation
API reference

Publisher

verified publisherryzizub.com

Weekly Downloads

A Dart parser for the ChordPro 6 song format. Extracts chords, lyrics, metadata, comments, layout hints and chord diagrams.

Repository (GitHub)
View/report issues

Topics

#chordpro #parser #music #chords #songbook

License

MIT (license)

More

Packages that depend on chord_pro