UNPKG

2.09 kBJavaScriptView Raw
1'use strict'
2
3/**
4 * md_block (module):
5 * Deals with markdown text.
6 */
7
8/**
9 * Normalizes markdown text. Converts code blocks into fenced code blocks.
10 *
11 * Options:
12 *
13 * - `lang` - language string (eg, 'js')
14 */
15
16exports.normalize = function (str, options) {
17 let blocks = exports.splitBlocks(str)
18 blocks = exports.normalizeCode(blocks, options)
19 return blocks.join('\n\n')
20}
21
22/**
23 * Breaks apart Markdown text into logical blocks. Takes code fences into account.
24 *
25 * splitBlocks('hello\n' + there\n' + '\n' + 'world')
26 * => ['hello\nthere', 'world']
27 */
28
29exports.splitBlocks = function (str) {
30 let blocks = str.split('\n\n')
31 let out = []
32 let last = {}
33 let state = {}
34
35 for (let i = 0; i < blocks.length; i++) {
36 let block = blocks[i]
37 let now = {
38 isCode: block.match(/^ {4}/),
39 isFenceOpen: block.match(/^(```|~~~)/),
40 isFenceClose: block.match(/(```|~~~)$/)
41 }
42
43 if (now.isFenceOpen) {
44 state.open = true
45 out.push(rtrim(block))
46 } else if (state.open) {
47 if (now.isFenceClose) {
48 state.open = false
49 }
50 out[out.length - 1] += '\n\n' + block
51 } else if (last.isCode && now.isCode) {
52 out[out.length - 1] += '\n\n' + block
53 } else {
54 out.push(rtrim(block))
55 }
56
57 last = now
58 }
59
60 return out
61}
62
63/**
64 * Normalizes code blocks into code fences
65 */
66
67exports.normalizeCode = function (blocks, options) {
68 return blocks.map((block) => {
69 let redented = unindent(block, { min: 2, max: 4 })
70 if (redented === block) return block
71
72 return '```' + (options && options.lang || '') + '\n' + redented + '\n```'
73 })
74}
75
76function unindent (block, options) {
77 let match = block.match(/^[ \t]*(?=\S)/gm)
78 let indent = Math.min.apply(Math, match.map((el) => el.length))
79
80 if (options && options.min && indent < options.min) return block
81 if (options && options.max && indent > options.max) indent = options.max
82
83 let re = new RegExp('^[ \\t]{' + indent + '}', 'gm')
84 return indent > 0 ? block.replace(re, '') : block
85}
86
87function rtrim (str) {
88 return str.replace(/[\n\s]*$/, '')
89}