UNPKG

changelog-to-html

Version:

CLI to convert a CHANGELOG.md following the http://keepachangelog.com convention to a static web page with permalinks and a GitHub look and feel

89 lines (73 loc) 2.74 kB
'use strict'; const path = require('path'); const fs = require('fs-extra'); const {getSlug} = require('./slug'); const permalinkIcon = String( // eslint-disable-next-line no-sync fs.readFileSync(path.join(__dirname, 'permalink.svg')) ); const markdownItChangelogPlugin = (md, {h1TitleCb}) => { md.core.ruler.push('h1Title', state => { const {tokens} = state; const h1OpeningTagIndex = tokens.findIndex( ({tag, type}) => type === 'heading_open' && tag === 'h1' ); h1TitleCb( h1OpeningTagIndex >= 0 ? tokens[h1OpeningTagIndex + 1].content : 'Missing <h1> title' ); }); md.core.ruler.push('permalinks', state => { const breadcrumbs = []; const replacements = []; const {Token, tokens} = state; const replaceTokenWithOthers = ({replacementTokens, tokenToReplace}) => { const tokenToReplaceIndex = tokens.indexOf(tokenToReplace); if (replacementTokens.length === 0) { return; } const [firstToken, ...otherTokens] = replacementTokens; tokens.splice(tokenToReplaceIndex, 1, firstToken); otherTokens.forEach((token, index) => { tokens.splice(tokenToReplaceIndex + index + 1, 0, token); }); }; tokens.forEach(token => { // We discard <h1> title because according to http://keepachangelog.com/en/1.0.0, // there should be only one of these and it's the main title. if (token.type !== 'heading_open' || token.tag === 'h1') { return; } const indexInBreadcrumbs = Number(token.tag.substring(1)) - 2; const indexOfTitleToken = tokens.indexOf(token) + 1; const titleToken = tokens[indexOfTitleToken]; const title = indexInBreadcrumbs === 0 ? // <h2> titles are release titles. // We only keep the release name and discard the release date. titleToken.content.match(/\[([^\\]+)\]/)[1] : titleToken.content; breadcrumbs.length = indexInBreadcrumbs; breadcrumbs[indexInBreadcrumbs] = title; const slug = getSlug(breadcrumbs); const linkOpenToken = new Token('link_open', 'a', 1); linkOpenToken.attrSet('class', 'anchor'); linkOpenToken.attrSet('href', `#${slug}`); linkOpenToken.attrSet('id', slug); const permalinkToken = new Token('html_inline', '', 0); permalinkToken.content = permalinkIcon; replacements.push({ replacementTokens: [ linkOpenToken, permalinkToken, new Token('link_close', 'a', -1), titleToken, ], tokenToReplace: titleToken, }); }); replacements.forEach(replaceTokenWithOthers); }); }; module.exports = {markdownItChangelogPlugin};