@hyperfrontend/versioning/changelog/parseparse
Tokenizer and parser for converting Keep-a-Changelog markdown into structured Changelog objects.
tokenize walks markdown character-by-character to emit a typed Token[] stream: headings, list items, links, and section markers. parseChangelog consumes that stream and assembles entries, sections, and items in their declared order. Per-line helpers (parseVersionFromHeading, parseCommitRefs, parseIssueRefs, parseBreakingFromItem, parseScopeFromItem) extract the structured fragments embedded in entry headers and bullet items. No regex is used anywhere in the parsing pipeline, keeping behavior linear in input length and free of catastrophic backtracking risk.
parseBreakingFromItem lifts the breaking-change markers an item opens with onto the item's breaking flag, which is what keeps a parse then serialize round trip a fixpoint: the serializer re-emits exactly one marker, and any run of markers left by an earlier round trip collapses back to that one.
API Reference§
ƒ Functions
Recognized openers, case-insensitive and repeatable:
BREAKING, BREAKING:, [BREAKING], ⚠️ BREAKING:, a bare BREAKING:, and the BREAKING CHANGE/BREAKING CHANGES spelling of each. A bare mention needs its colon to count, so prose such as Breaking apart the parser is left alone. Scanning is character-by-character to stay ReDoS-safe.Parameters
| Name | Type | Description |
|---|---|---|
§text | string | The changelog item text, without its list marker |
Returns
BreakingFromItemExample
Lifting markers out of item text
parseBreakingFromItem('**BREAKING** **BREAKING:** drop the sync open')
// => { breaking: true, text: 'drop the sync open' }
parseBreakingFromItem('add a retry budget')
// => { breaking: false, text: 'add a retry budget' }Parameters
Returns
ChangelogExample
Parsing a changelog markdown string
const markdown = `# Changelog
## [1.0.0] - 2024-01-15
### Added
- Initial release`
const changelog = parseChangelog(markdown, 'CHANGELOG.md')
// => { header: { title: '# Changelog', ... }, entries: [{ version: '1.0.0', ... }] }Parameters
Returns
CommitRef[]Example
Parsing commit references from text
parseCommitRefs('Fixed bug (abc1234)', 'https://github.com/org/repo')
// => [{ hash: 'abc1234', shortHash: 'abc1234', url: 'https://github.com/org/repo/commit/abc1234' }]Parameters
Returns
IssueRef[]Example
Parsing issue references from text
parseIssueRefs('Closes #42 and PR #123', 'https://github.com/org/repo')
// => [{ number: 42, type: 'issue', url: '...' }, { number: 123, type: 'pull-request', url: '...' }]Parameters
| Name | Type | Description |
|---|---|---|
§text | string | The text to parse for scope |
Returns
ScopeFromItemExample
Parsing scope from changelog items
parseScopeFromItem('**api:** Add new endpoint')
// => { scope: 'api', description: 'Add new endpoint' }
parseScopeFromItem('Simple change without scope')
// => { scope: undefined, description: 'Simple change without scope' }Parameters
| Name | Type | Description |
|---|---|---|
§heading | string | The heading string to parse |
Returns
ParsedVersionHeadingExample
Parsing version headings
parseVersionFromHeading('[1.2.3] - 2024-01-15')
// => { version: '1.2.3', date: '2024-01-15', compareUrl: undefined }
parseVersionFromHeading('v2.0.0')
// => { version: '2.0.0', date: null, compareUrl: undefined }Parameters
| Name | Type | Description |
|---|---|---|
§input | string | The markdown content to tokenize |
Returns
Token[]Example
Tokenizing changelog markdown
const tokens = tokenize('# Changelog\n\n## [1.0.0]\n- Added feature')
// => [{ type: 'heading-1', value: 'Changelog', ... }, { type: 'heading-2', ... }, ...]◈ Interfaces
Properties
◆ Types
type TokenType = "heading-1" | "heading-2" | "heading-3" | "heading-4" | "list-item" | "link-text" | "link-url" | "text" | "newline" | "blank-line" | "bold" | "code" | "eof"