var fs = require('fs') var remark = require('remark') var html = require('remark-html') var slug = require('remark-slug') var autolinkHeadings = require('remark-autolink-headings') var com = require('./tmpl/com.part') var select = require('unist-util-select') var ssbRef = require('ssb-ref') const linkSvg = '' module.exports.doc = function (path) { var text = fs.readFileSync(path, 'utf-8') return remark() .use(slug) .use(autolinkHeadings, { attributes: { class: 'anchor' }, template: linkSvg }) .use(html) .use(injectTOC) .use(transformCodeExamples) .use(transformSsbLinks) .process(text) } // find all h2s and create a dropdown table-of-contents function injectTOC (remark, options) { remark.Compiler.prototype.visitors.tableOfContents = renderTOC return ast => { var headings = ast.children.filter(node => node.type == 'heading' && node.depth == 2) if (headings.length > 3) createTOC(ast, headings) return ast } } // add the tableOfContents node to the ast function createTOC (ast, headings) { ast.children.unshift({ type: 'tableOfContents', children: headings }) } // render the tableOfContents widget function renderTOC (node, root) { return com.tableOfContents(node.children) } // find any sections and group them together into our code-examples component function transformCodeExamples (remark, options) { remark.Compiler.prototype.visitors.codeExamples = renderCodeExamples return ast => { var groups = findCodeGroupings(ast) createCodeExamples(ast, groups) return ast } } // locate the contiguous groupings function findCodeGroupings (ast) { var groups = [], groupStart = false ast.children.forEach((node, i) => { if (groupStart) { // in a grouping, look for a non-code item if (node.type !== 'code' || !node.lang) { groups.push([groupStart, i]) groupStart = false } } else { // not in a grouping, look for a code item if (node.type === 'code' && node.lang) { groupStart = i } } }) if (groupStart) groups.push([groupStart, ast.children.length]) return groups } // replace groupings with code-example nodes function createCodeExamples (ast, groups) { var offset = 0 // offset to counter the changes introduced by splices groups.forEach(group => { var start = group[0], end = group[1] var len = end - start ast.children.splice(start-offset, len, { type: 'codeExamples', children: ast.children.slice(start-offset, start-offset+len), position: false // TODO - needed? doesnt look like it }) offset += len - 1 }) } // convert from AST to html function renderCodeExamples (node, root) { var codes = {} node.children.forEach(node => { if (node.type == 'code' && !!node.lang) codes[node.lang] = node.value }) return com.code(codes) } // add a prefix to links to ssb refs function transformSsbLinks (remark, options) { return ast => { select(ast, "link").forEach(link => { if (ssbRef.isLink(link.url)) { link.url = 'https://git.scuttlebot.io/' + link.url } }) return ast } }