A Keep a Changelog parser and serializer implemented as an mq module.
- Parse
CHANGELOG.mdfiles into structured dictionaries - Serialize structured data back to Keep a Changelog format
- Access versions, dates, and categorized entries (Added, Fixed, Changed, etc.)
- Preserves version order
- Handles
[Unreleased]sections (no date)
Copy changelog.mq to your mq module directory:
cp changelog.mq ~/.mq/mq -I raw 'import "changelog" | changelog::changelog_parse(.)' CHANGELOG.mdParses a Keep a Changelog Markdown string. Returns:
{
title: string,
versions: [
{
version: string, # e.g. "1.2.0" or "Unreleased"
date: string | None, # e.g. "2025-03-01"
sections: {
"Added": [string],
"Fixed": [string],
...
}
}
]
}
Serializes changelog data back to Keep a Changelog Markdown format.
Returns the first (latest) version object, or None if there are no versions.
Returns an array of version strings in document order.
Returns an array of entry strings for the given section type (e.g. "Added", "Fixed") within a version object. Returns [] if the section is absent.
Returns true if the changelog contains a version matching the given string.
Given CHANGELOG.md:
# Changelog
## [Unreleased]
### Added
- New API endpoint
## [1.2.0] - 2025-03-01
### Added
- Dark mode support
### Fixed
- Login redirect bug# Get the latest version string
mq -I raw '
import "changelog"
| changelog::changelog_latest(changelog::changelog_parse(.))["version"]
' CHANGELOG.md
# => "Unreleased"
# List all versions
mq -I raw '
import "changelog"
| changelog::changelog_versions(changelog::changelog_parse(.))
' CHANGELOG.md
# => ["Unreleased", "1.2.0"]
# Get "Added" entries from 1.2.0
mq -I raw '
import "changelog"
| let data = changelog::changelog_parse(.)
| let v = data["versions"][1]
| changelog::changelog_entries(v, "Added")
' CHANGELOG.md
# => ["Dark mode support"]
# Check if a version exists
mq -I raw '
import "changelog"
| changelog::changelog_has_version(changelog::changelog_parse(.), "1.2.0")
' CHANGELOG.md
# => trueRequires mq v0.5 or later.
MIT