1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | const _ = require('underscore');
|
14 | const path = require('path');
|
15 | const fs = require('graceful-fs');
|
16 | const readdirp = require('readdirp');
|
17 | const debug = require('debug')('firedoc:firedoc');
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | function Firedoc (config) {
|
27 | if (!(this instanceof Firedoc)) {
|
28 | return new Firedoc(config);
|
29 | }
|
30 |
|
31 | |
32 |
|
33 |
|
34 |
|
35 |
|
36 |
|
37 | this.filecount = 0;
|
38 | |
39 |
|
40 |
|
41 |
|
42 |
|
43 |
|
44 | this.filemap = {};
|
45 | |
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 | this.dirmap = {};
|
52 |
|
53 | |
54 |
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | this.options = {
|
60 | writeJSON: true,
|
61 | extensions: '.js',
|
62 | excludes: [
|
63 | '.git',
|
64 | '.svn',
|
65 | 'CVS',
|
66 | 'build_rollup_tmp',
|
67 | 'build_tmp',
|
68 | 'node_modules'
|
69 | ],
|
70 | norecurse: false,
|
71 | paths: ['./'],
|
72 | cwd: process.cwd(),
|
73 | http: false,
|
74 | dest: path.join(process.cwd(), 'out'),
|
75 | theme: path.join(__dirname, '../themes/default'),
|
76 | syntaxtype: 'js'
|
77 | };
|
78 |
|
79 |
|
80 | var cwd = config.cwd || this.options.cwd;
|
81 | var pkg;
|
82 | var firedocOptions;
|
83 | if (fs.existsSync(cwd + '/yuidoc.json')) {
|
84 | pkg = require(cwd + '/yuidoc.json');
|
85 | firedocOptions = pkg.options;
|
86 | delete pkg.options;
|
87 | } else if (fs.existsSync(cwd + '/package.json')) {
|
88 | pkg = require(cwd + '/package.json');
|
89 | firedocOptions = pkg.firedoc;
|
90 | delete pkg.firedoc;
|
91 |
|
92 | if (pkg.yuidoc && pkg.yuidoc.options) {
|
93 | firedocOptions = _.extend(firedocOptions, pkg.yuidoc.options);
|
94 | delete pkg.yuidoc;
|
95 | }
|
96 |
|
97 | var envOption = pkg['firedoc.' + process.env.NODE_ENV];
|
98 | if (envOption) {
|
99 | firedocOptions = _.extend(firedocOptions, envOption);
|
100 | delete pkg['firedoc.' + process.env.NODE_ENV];
|
101 | }
|
102 | }
|
103 |
|
104 |
|
105 | if (firedocOptions) {
|
106 | this.options = _.extend(this.options, firedocOptions);
|
107 | }
|
108 | this.options.project = pkg;
|
109 |
|
110 |
|
111 | for (var key in config) {
|
112 | if (!_.isUndefined(config[key])) this.options[key] = config[key];
|
113 | }
|
114 |
|
115 | if (_.isString(this.options.paths)) {
|
116 | this.options.paths = [this.options.paths];
|
117 | }
|
118 | if (this.options.markdown === true) {
|
119 | this.options.theme = path.join(__dirname, '../themes/markdown');
|
120 | }
|
121 | if (this.options.outdir) {
|
122 | this.options.dest = this.options.outdir;
|
123 | }
|
124 | if (!path.isAbsolute(this.options.dest)) {
|
125 | this.options.dest = path.join(process.cwd(), this.options.dest);
|
126 | }
|
127 | };
|
128 | exports.Firedoc = Firedoc;
|
129 |
|
130 | Firedoc.prototype = {
|
131 |
|
132 | |
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 | walk: function (next) {
|
139 | var self = this;
|
140 | var paths = _.clone(self.options.paths);
|
141 | var curr = paths.shift() || './';
|
142 | self.walkOne(curr, onfinish);
|
143 |
|
144 | function onfinish (err) {
|
145 | if (err) throw err;
|
146 | curr = paths.shift();
|
147 | if (_.isString(curr))
|
148 | return self.walkOne(curr, onfinish);
|
149 | else
|
150 | return next();
|
151 | }
|
152 | },
|
153 |
|
154 | |
155 |
|
156 |
|
157 |
|
158 |
|
159 |
|
160 |
|
161 | walkOne: function (root, next) {
|
162 | debug('walking path: ' + root);
|
163 | if (!path.isAbsolute(root)) {
|
164 | root = path.join(process.cwd(), root);
|
165 | }
|
166 |
|
167 | var self = this;
|
168 | readdirp(
|
169 | {
|
170 | root: root,
|
171 | fileFilter: '*.@(js|rs|ts|coffee)',
|
172 | directoryFilter: self.options.excludes.map(
|
173 | function (ex) {
|
174 | return '!' + ex;
|
175 | }
|
176 | )
|
177 | }
|
178 | )
|
179 | .on('data', function (entry) {
|
180 | var text = fs.readFileSync(entry.fullPath, 'utf8');
|
181 | self.filecount += 1;
|
182 | self.filemap[entry.fullPath] = text.replace(/\r?\n|\r/g, '\n');
|
183 | self.dirmap[entry.fullPath] = entry.fullParentDir;
|
184 | })
|
185 | .on('end', next)
|
186 | .on('error', next);
|
187 | },
|
188 |
|
189 | lint: function (warnings) {
|
190 | var code = 0, count = 0;
|
191 | if (warnings && warnings.length) {
|
192 | code = 1;
|
193 | console.log('FireDoc found', warnings.length, 'lint errors in your docs');
|
194 | warnings.forEach(function (item) {
|
195 | count++;
|
196 | console.log('#' + count, item.message, item.line + '\n');
|
197 | });
|
198 | }
|
199 | },
|
200 |
|
201 | |
202 |
|
203 |
|
204 |
|
205 |
|
206 | build: function (callback) {
|
207 | debug('Starting from: ' + this.options.path);
|
208 | var self = this;
|
209 | this.walk(function () {
|
210 | var parser = require('./docparser');
|
211 | var builder = require('./builder');
|
212 | var ast = parser.parse(
|
213 | self.options.syntaxtype,
|
214 | self.filemap,
|
215 | self.dirmap);
|
216 |
|
217 | debug('Parsing completed');
|
218 | if (self.options.lint) {
|
219 | debug('lint the warnings from ast');
|
220 | self.lint(ast.warnings);
|
221 | if (_.isFunction(callback)) return callback(ast.warnings);
|
222 | }
|
223 | if (self.options.parseOnly) {
|
224 | debug('skip the build because parse only');
|
225 | if (_.isFunction(callback)) callback(null, ast, self.options);
|
226 | return;
|
227 | }
|
228 | builder.compile(ast, self.options, callback);
|
229 | });
|
230 | }
|
231 | };
|