forked from thlorenz/doctoc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtransform.js
106 lines (86 loc) · 2.64 KB
/
transform.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
'use strict';
var _ = require('underscore');
function notNull(x) { return x !== null; }
function addLink(header) {
return _(header).extend({
link: '#' +
header.name
.trim()
.toLowerCase()
.replace(/ /g,'-')
.replace(/[\[\]`.,()*]/g,'')
});
}
function getHashedHeaders (_lines) {
// Find headers of the form '### xxxx xxx xx'
return _lines
.map(function (x, index) {
var match = /^(\#{1,8})[ ]*(.+)$/.exec(x);
return match
? { rank : match[1].length
, name : match[2]
, line : index
}
: null;
})
.filter(notNull)
.value();
}
function getUnderlinedHeaders (_lines) {
// Find headers of the form
// h1 h2
// == --
return _lines
.map(function (line, index, lines) {
if (index === 0) return null;
var rank;
if (/^==+/.exec(line)) rank = 1;
else if (/^--+/.exec(line)) rank = 2;
else return null;
return {
rank : rank,
name : lines[index - 1],
line : index - 1
};
})
.filter(notNull)
.value();
}
module.exports = function transform(f, content) {
var lines = content.split('\n')
, _lines = _(lines).chain()
, allHeaders = getHashedHeaders(_lines).concat(getUnderlinedHeaders(_lines))
, lowestRank = _(allHeaders).chain().pluck('rank').min().value()
, linkedHeaders = _(allHeaders).map(addLink);
if (linkedHeaders.length === 0) return { transformed: false };
var toc =
'**Table of Contents** *generated with [DocToc](http://doctoc.herokuapp.com/)*'
+ '\n\n'
+ linkedHeaders.map(function (x) {
var indent = _(_.range(x.rank - lowestRank))
.reduce(function (acc, x) { return acc + '\t'; }, '');
return indent + '- [' + x.name + '](' + x.link + ')';
})
.join('\n')
+ '\n';
var currentToc = _lines
.first(linkedHeaders[0].line)
.value()
.join('\n');
if (currentToc === toc) {
console.log('"%s" is up to date', f.path);
return { transformed: false };
}
console.log('"%s" will be updated', f.path);
// Skip all lines up to first header since that is the old table of content
var remainingContent = _lines
.rest(linkedHeaders[0].line)
.value()
.join('\n');
var data = toc + '\n' + remainingContent;
return {
transformed : true,
data : data,
path : f.path
};
};