UNPKG

markdown-toc-gen

Version:

Generating and updating table of contents in Markdown files which conform with prettier.

138 lines (137 loc) 5.33 kB
"use strict"; /* eslint-disable no-control-regex */ Object.defineProperty(exports, "__esModule", { value: true }); exports.Toc = void 0; const markdown_1 = require("../markdown"); const toc_service_1 = require("./toc.service"); /** * Toc * * class to parse and insert/update markdown files with * a generated table of content * * To create a toc it is necessary that the markdown file * has the following placeholder * * <!-- toc --> * <!-- tocstop --> */ class Toc { /** file path of markdown file */ get filePath() { return this._mdPath; } /** set file path of markdown file */ set filePath(path) { this._mdPath = path; const mdString = this.mdService.parseMarkdown(path); this._isWindows = mdString.includes(this._carriageReturn); this._mdString = mdString.replace(new RegExp(this._carriageReturn, 'g'), this._lineFeed); } /** * set max depth for parsing headings */ set maxDepth(value) { this.mdService.setMaxDepth(value); } /** * returns carriage return for windows os and linefeed for unix systems */ get newLineChar() { return this._isWindows ? this._carriageReturn : this._lineFeed; } constructor(mdService = new markdown_1.MarkdownService(), tocService = new toc_service_1.TocService()) { this.mdService = mdService; this.tocService = tocService; this._isWindows = false; this._mdPath = ''; this._mdString = ''; this._tocPlaceholder = new RegExp('(?<toc>(<!--\\s?toc\\s?-->\n?(?<tocInline>(?:.*?\n)*?)<!--\\s?tocstop\\s?-->\n))'); this._tocStart = '<!-- toc -->\n'; this._tocStop = '<!-- tocstop -->\n'; this._indentation = ' '; this._hyphen = '- '; this._carriageReturn = '\r\n'; this._lineFeed = '\n'; } /** * create table of content * @returns table of content */ createToc() { let toc = ''; const cleandedContent = this.mdService.removeCodeBlocks(this._mdString); this.mdService.parseHeadings(cleandedContent).forEach((heading) => { toc += this._indentation.repeat(heading.level - 1) + this._hyphen + this.createTocEntry(heading.heading, heading.counter) + this._lineFeed; }); return toc; } /** * insert/update toc in given markdown file */ insertToc() { const tocMatch = this._tocPlaceholder.exec(this._mdString); const placeholderMatch = new RegExp('<!--\\s?(toc|tocstop)\\s?-->').exec(this._mdString); if (tocMatch && tocMatch.groups && tocMatch.groups.toc) { const mdWithToc = this._mdString.replace(tocMatch.groups.toc, this._tocStart + '\n' + this.createToc() + '\n' + this._tocStop); this.mdService.updateMarkdown(this.filePath, mdWithToc.replace(new RegExp(this._lineFeed, 'g'), this.newLineChar)); return; } else if (placeholderMatch) { throw new Error([ 'Could not find placeholder', '<!-- toc -->', '<!-- tocstop -->', 'A toc update or insertion was not possible. Please sure the placeholder are set.', ].join(this.newLineChar)); } else { const toc = this._tocStart + '\n' + this.createToc() + '\n' + this._tocStop + '\n'; const posFirstSecondHeading = this._mdString.search(new RegExp('\n##\\s')); if (posFirstSecondHeading === -1) { throw new Error([ 'Could not find placeholder', '<!-- toc -->', '<!-- tocstop -->', 'or there is an semantic issue in your heading level.', 'A toc insertion was not possible. Please sure the placeholders are set or your semantic is correct', ].join(this.newLineChar)); } const replacedContent = (this._mdString.slice(0, posFirstSecondHeading + 1) + toc + this._mdString.slice(posFirstSecondHeading + 1)).replace(new RegExp(this._lineFeed, 'g'), this.newLineChar); this.mdService.updateMarkdown(this.filePath, replacedContent); return; } } /** * evaluates if given toc is valid * the given toc will be compared with the generated toc * @returns is table of content valid */ isTocValid() { const parsedToc = this.tocService.parseToc(this.mdService.removeCodeBlocks(this._mdString)); const expectedToc = this.createToc(); const tocDiff = this.tocService.validateToc(parsedToc, expectedToc); if (tocDiff) { console.log(`validation of ${this.filePath} failed:`); console.log(tocDiff); return false; } return true; } /** * create table of content entry with creating unique id * @param caption - headline which is a toc entry * @param counter - counts the amount of a given headline to create an unique id * @returns toc entry */ createTocEntry(caption, counter) { return `[${caption}]${this.tocService.createLink(caption, counter)}`; } } exports.Toc = Toc;