/
renderDocs.js
134 lines (115 loc) · 3.97 KB
/
renderDocs.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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
var cp = require('child_process')
, fs = require('fs')
, path = require('path')
, util = require('util')
, mustache = require('mustache')
, Seq = require('seq')
, Showdown = require('showdown')
/**
* Run dox on `files`, render markdown & html, then write to doc files
*
* @param {array} files array of absolute paths of files to document
*/
module.exports = function renderDocs (files) {
var self = this
//absolute paths to doc files
var absHtmlPath = this.config.doc_base+'.html'
, absMdPath = this.config.doc_base+'.md'
Seq()
//get template and cache it
.seq(function () {
var seqThis = this
fs.readFile(self.config.template_path, 'utf8', function (err, contents) {
if (err) throw err
self.cachedTemplate = contents
seqThis(null)
})
})
.seq(function () {
this(null, files)
})
.flatten()
//run dox on files in parallel
.parMap(function (file, i) {
console.log(('rendering doc for '+file).green)
var seqThis = this
var doxExecPath = path.resolve(__dirname, '../node_modules/dox/bin/dox')
var doxCommand = doxExecPath+' < '+file
//run dox, pass stdout to seq
cp.exec(doxCommand, function (err, stdout, stderr) {
if (err) throw err
if (stderr) return console.log('dox stderr:'.red, stderr)
var doxOut = null
try {
doxOutput = JSON.parse(stdout)
} catch (err) {
var error = new Error('dox did not generate valid json for filename '+filename)
throw error
}
//augment dox's output.
// - generate function signature for any doc block that's a function
// - if a tag type is `param`, set the `type` field to null for better rendering
var doxOut = doxOutput.map(function (docBlock) {
//if this doc block is a function, write its signature
if (!docBlock.ctx)
return docBlock
var blockType = docBlock.ctx.type
if (docBlock.ctx && (blockType === 'function' || blockType === 'method')) {
//grab function params to generate the signature
var params = []
docBlock.tags.forEach(function (tag) {
if (tag.type === 'param') {
params.push(tag.name)
tag.type = null
}
})
var paramString = params.join(',')
var name = null
if (blockType === 'method') {
if (docBlock.ctx.receiver)
name = docBlock.ctx.receiver+'.'+docBlock.ctx.name
else
name = docBlock.ctx.constructor+'.'+docBlock.ctx.name
} else {
name = docBlock.ctx.name
}
docBlock.signature = name+'('+paramString+')'
}
return docBlock
})
var entry = {
filename: path.relative(self.root, file)
, doxOutput: doxOut
}
return seqThis.into(i)(null, entry)
})
})
.unflatten()
//render dox output into markdown template
.seq(function (doxArray) {
var seqThis = this
var template = self.cachedTemplate
var templateParams = {
dirname: path.basename(self.root)
, doxArray: doxArray
}
//render the template using mustache
var markdown = mustache.render(self.cachedTemplate, templateParams)
this(null, markdown)
})
//write rendered markdown file
.par(function (markdown) {
console.log('writing to %s'.blue, absMdPath)
fs.writeFile(absMdPath, markdown, this)
})
//convert rendered markdown to html and write html file
.par(function (markdown) {
var converter = new Showdown.converter()
var html = converter.makeHtml(markdown)
console.log('writing to %s'.blue, absHtmlPath)
fs.appendFile(absHtmlPath, html, this)
})
.seq(function () {
console.log('\nsuccessfully wrote `%s` and `%s`\n'.blue, absMdPath, absHtmlPath)
})
}