Files: 18ca2b47b86cd361c03c92c0682500c5fa00451f / markdown.js
3697 bytesRaw
1 | var fs = require('fs') |
2 | var remark = require('remark') |
3 | var html = require('remark-html') |
4 | var slug = require('remark-slug') |
5 | var autolinkHeadings = require('remark-autolink-headings') |
6 | var com = require('./tmpl/com.part') |
7 | var select = require('unist-util-select') |
8 | var ssbRef = require('ssb-ref') |
9 | |
10 | const linkSvg = '<svg aria-hidden="true" class="octicon octicon-link" height="16" role="img" version="1.1" viewBox="0 0 16 16" width="16"><path d="M4 9h1v1h-1c-1.5 0-3-1.69-3-3.5s1.55-3.5 3-3.5h4c1.45 0 3 1.69 3 3.5 0 1.41-0.91 2.72-2 3.25v-1.16c0.58-0.45 1-1.27 1-2.09 0-1.28-1.02-2.5-2-2.5H4c-0.98 0-2 1.22-2 2.5s1 2.5 2 2.5z m9-3h-1v1h1c1 0 2 1.22 2 2.5s-1.02 2.5-2 2.5H9c-0.98 0-2-1.22-2-2.5 0-0.83 0.42-1.64 1-2.09v-1.16c-1.09 0.53-2 1.84-2 3.25 0 1.81 1.55 3.5 3 3.5h4c1.45 0 3-1.69 3-3.5s-1.5-3.5-3-3.5z"></path></svg>' |
11 | |
12 | module.exports.doc = function (path) { |
13 | var text = fs.readFileSync(path, 'utf-8') |
14 | return remark() |
15 | .use(slug) |
16 | .use(autolinkHeadings, { |
17 | attributes: { class: 'anchor' }, |
18 | template: linkSvg |
19 | }) |
20 | .use(html) |
21 | .use(injectTOC) |
22 | .use(transformCodeExamples) |
23 | .use(transformSsbLinks) |
24 | .process(text) |
25 | } |
26 | |
27 | // find all h2s and create a dropdown table-of-contents |
28 | function injectTOC (remark, options) { |
29 | remark.Compiler.prototype.visitors.tableOfContents = renderTOC |
30 | return ast => { |
31 | var headings = ast.children.filter(node => node.type == 'heading' && node.depth == 2) |
32 | if (headings.length > 3) |
33 | createTOC(ast, headings) |
34 | return ast |
35 | } |
36 | } |
37 | |
38 | // add the tableOfContents node to the ast |
39 | function createTOC (ast, headings) { |
40 | ast.children.unshift({ type: 'tableOfContents', children: headings }) |
41 | } |
42 | |
43 | // render the tableOfContents widget |
44 | function renderTOC (node, root) { |
45 | return com.tableOfContents(node.children) |
46 | } |
47 | |
48 | // find any <code> sections and group them together into our code-examples component |
49 | function transformCodeExamples (remark, options) { |
50 | remark.Compiler.prototype.visitors.codeExamples = renderCodeExamples |
51 | return ast => { |
52 | var groups = findCodeGroupings(ast) |
53 | createCodeExamples(ast, groups) |
54 | return ast |
55 | } |
56 | } |
57 | |
58 | // locate the contiguous <code> groupings |
59 | function findCodeGroupings (ast) { |
60 | var groups = [], groupStart = false |
61 | ast.children.forEach((node, i) => { |
62 | if (groupStart) { |
63 | // in a grouping, look for a non-code item |
64 | if (node.type !== 'code' || !node.lang) { |
65 | groups.push([groupStart, i]) |
66 | groupStart = false |
67 | } |
68 | } else { |
69 | // not in a grouping, look for a code item |
70 | if (node.type === 'code' && node.lang) { |
71 | groupStart = i |
72 | } |
73 | } |
74 | }) |
75 | if (groupStart) |
76 | groups.push([groupStart, ast.children.length]) |
77 | return groups |
78 | } |
79 | |
80 | // replace <code> groupings with code-example nodes |
81 | function createCodeExamples (ast, groups) { |
82 | var offset = 0 // offset to counter the changes introduced by splices |
83 | groups.forEach(group => { |
84 | var start = group[0], end = group[1] |
85 | var len = end - start |
86 | ast.children.splice(start-offset, len, { |
87 | type: 'codeExamples', |
88 | children: ast.children.slice(start-offset, start-offset+len), |
89 | position: false // TODO - needed? doesnt look like it |
90 | }) |
91 | offset += len - 1 |
92 | }) |
93 | } |
94 | |
95 | // convert from AST to html |
96 | function renderCodeExamples (node, root) { |
97 | var codes = {} |
98 | node.children.forEach(node => { |
99 | if (node.type == 'code' && !!node.lang) |
100 | codes[node.lang] = node.value |
101 | }) |
102 | |
103 | return com.code(codes) |
104 | } |
105 | |
106 | // add a prefix to links to ssb refs |
107 | function transformSsbLinks (remark, options) { |
108 | return ast => { |
109 | select(ast, "link").forEach(link => { |
110 | if (ssbRef.isLink(link.url)) { |
111 | link.url = 'https://git.scuttlebot.io/' + link.url |
112 | } |
113 | }) |
114 | return ast |
115 | } |
116 | } |
117 |
Built with git-ssb-web