1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | 'use strict';
|
11 |
|
12 | var _ = require('underscore');
|
13 | var jsdoc = {
|
14 | name: require('jsdoc/name'),
|
15 | src: {
|
16 | astnode: require('jsdoc/src/astnode'),
|
17 | Syntax: require('jsdoc/src/syntax').Syntax
|
18 | },
|
19 | tag: {
|
20 | Tag: require('jsdoc/tag').Tag,
|
21 | dictionary: require('jsdoc/tag/dictionary')
|
22 | }
|
23 | };
|
24 | var path = require('jsdoc/path');
|
25 | var Syntax = jsdoc.src.Syntax;
|
26 | var util = require('util');
|
27 |
|
28 | function applyTag(doclet, tag) {
|
29 | if (tag.title === 'name') {
|
30 | doclet.name = tag.value;
|
31 | }
|
32 |
|
33 | if (tag.title === 'kind') {
|
34 | doclet.kind = tag.value;
|
35 | }
|
36 |
|
37 | if (tag.title === 'description') {
|
38 | doclet.description = tag.value;
|
39 | }
|
40 | }
|
41 |
|
42 |
|
43 | function codeToKind(code) {
|
44 | var isFunction = jsdoc.src.astnode.isFunction;
|
45 | var kind = 'member';
|
46 | var node = code.node;
|
47 |
|
48 | if ( isFunction(code.type) ) {
|
49 | kind = 'function';
|
50 | }
|
51 | else if ( code.node && code.node.parent && isFunction(code.node.parent) ) {
|
52 | kind = 'param';
|
53 | }
|
54 |
|
55 | return kind;
|
56 | }
|
57 |
|
58 | function unwrap(docletSrc) {
|
59 | if (!docletSrc) { return ''; }
|
60 |
|
61 |
|
62 |
|
63 |
|
64 |
|
65 | docletSrc =
|
66 | docletSrc.replace(/^\/\*\*+/, '')
|
67 | .replace(/\**\*\/$/, '\\Z')
|
68 | .replace(/^\s*(\* ?|\\Z)/gm, '')
|
69 | .replace(/\s*\\Z$/g, '');
|
70 |
|
71 | return docletSrc;
|
72 | }
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | function toTags(docletSrc) {
|
79 | var parsedTag;
|
80 | var tagData = [];
|
81 | var tagText;
|
82 | var tagTitle;
|
83 |
|
84 |
|
85 |
|
86 | docletSrc
|
87 |
|
88 | .replace(/^(\s*)@(\S)/gm, '$1\\@$2')
|
89 |
|
90 | .split('\\@')
|
91 | .forEach(function($) {
|
92 | if ($) {
|
93 | parsedTag = $.match(/^(\S+)(?:\s+(\S[\s\S]*))?/);
|
94 |
|
95 | if (parsedTag) {
|
96 | tagTitle = parsedTag[1];
|
97 | tagText = parsedTag[2];
|
98 |
|
99 | if (tagTitle) {
|
100 | tagData.push({
|
101 | title: tagTitle,
|
102 | text: tagText
|
103 | });
|
104 | }
|
105 | }
|
106 | }
|
107 | });
|
108 |
|
109 | return tagData;
|
110 | }
|
111 |
|
112 | function fixDescription(docletSrc) {
|
113 | if (!/^\s*@/.test(docletSrc) && docletSrc.replace(/\s/g, '').length) {
|
114 | docletSrc = '@description ' + docletSrc;
|
115 | }
|
116 | return docletSrc;
|
117 | }
|
118 |
|
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 | exports._replaceDictionary = function _replaceDictionary(dict) {
|
128 | jsdoc.tag.dictionary = dict;
|
129 | require('jsdoc/tag')._replaceDictionary(dict);
|
130 | require('jsdoc/util/templateHelper')._replaceDictionary(dict);
|
131 | };
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 |
|
139 | var Doclet = exports.Doclet = function(docletSrc, meta) {
|
140 | var newTags = [];
|
141 |
|
142 |
|
143 | this.comment = docletSrc;
|
144 | this.setMeta(meta);
|
145 |
|
146 | docletSrc = unwrap(docletSrc);
|
147 | docletSrc = fixDescription(docletSrc);
|
148 |
|
149 | newTags = toTags.call(this, docletSrc);
|
150 |
|
151 | for (var i = 0, l = newTags.length; i < l; i++) {
|
152 | this.addTag(newTags[i].title, newTags[i].text);
|
153 | }
|
154 |
|
155 | this.postProcess();
|
156 | };
|
157 |
|
158 |
|
159 | Doclet.prototype.postProcess = function() {
|
160 | var i;
|
161 | var l;
|
162 |
|
163 | if (!this.preserveName) {
|
164 | jsdoc.name.resolve(this);
|
165 | }
|
166 | if (this.name && !this.longname) {
|
167 | this.setLongname(this.name);
|
168 | }
|
169 | if (this.memberof === '') {
|
170 | delete this.memberof;
|
171 | }
|
172 |
|
173 | if (!this.kind && this.meta && this.meta.code) {
|
174 | this.addTag( 'kind', codeToKind(this.meta.code) );
|
175 | }
|
176 |
|
177 | if (this.variation && this.longname && !/\)$/.test(this.longname) ) {
|
178 | this.longname += '(' + this.variation + ')';
|
179 | }
|
180 |
|
181 |
|
182 | if (this.params && this.meta && this.meta.code && this.meta.code.paramnames) {
|
183 | for (i = 0, l = this.params.length; i < l; i++) {
|
184 | if (!this.params[i].name) {
|
185 | this.params[i].name = this.meta.code.paramnames[i] || '';
|
186 | }
|
187 | }
|
188 | }
|
189 | };
|
190 |
|
191 |
|
192 |
|
193 |
|
194 |
|
195 |
|
196 |
|
197 | Doclet.prototype.addTag = function(title, text) {
|
198 | var tagDef = jsdoc.tag.dictionary.lookUp(title),
|
199 | newTag = new jsdoc.tag.Tag(title, text, this.meta);
|
200 |
|
201 | if (tagDef && tagDef.onTagged) {
|
202 | tagDef.onTagged(this, newTag);
|
203 | }
|
204 |
|
205 | if (!tagDef) {
|
206 | this.tags = this.tags || [];
|
207 | this.tags.push(newTag);
|
208 | }
|
209 |
|
210 | applyTag(this, newTag);
|
211 | };
|
212 |
|
213 | function removeGlobal(longname) {
|
214 | var globalRegexp = new RegExp('^' + jsdoc.name.LONGNAMES.GLOBAL + '\\.?');
|
215 |
|
216 | return longname.replace(globalRegexp, '');
|
217 | }
|
218 |
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 | Doclet.prototype.setMemberof = function(sid) {
|
225 | |
226 |
|
227 |
|
228 |
|
229 | this.memberof = removeGlobal(sid)
|
230 | .replace(/\.prototype/g, jsdoc.name.SCOPE.PUNC.INSTANCE);
|
231 | };
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 | Doclet.prototype.setLongname = function(name) {
|
239 | |
240 |
|
241 |
|
242 |
|
243 | this.longname = removeGlobal(name);
|
244 | if (jsdoc.tag.dictionary.isNamespace(this.kind)) {
|
245 | this.longname = jsdoc.name.applyNamespace(this.longname, this.kind);
|
246 | }
|
247 | };
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 | function getFilepath(doclet) {
|
258 | if (!doclet || !doclet.meta || !doclet.meta.filename) {
|
259 | return '';
|
260 | }
|
261 |
|
262 | return path.join(doclet.meta.path || '', doclet.meta.filename);
|
263 | }
|
264 |
|
265 |
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 | Doclet.prototype.setScope = function(scope) {
|
274 | var errorMessage;
|
275 | var filepath;
|
276 | var scopeNames = _.values(jsdoc.name.SCOPE.NAMES);
|
277 |
|
278 | if (scopeNames.indexOf(scope) === -1) {
|
279 | filepath = getFilepath(this);
|
280 |
|
281 | errorMessage = util.format('The scope name "%s" is not recognized. Use one of the ' +
|
282 | 'following values: %j', scope, scopeNames);
|
283 | if (filepath) {
|
284 | errorMessage += util.format(' (Source file: %s)', filepath);
|
285 | }
|
286 |
|
287 | throw new Error(errorMessage);
|
288 | }
|
289 |
|
290 | this.scope = scope;
|
291 | };
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 |
|
298 |
|
299 | Doclet.prototype.borrow = function(source, target) {
|
300 | var about = { from: source };
|
301 | if (target) {
|
302 | about.as = target;
|
303 | }
|
304 |
|
305 | if (!this.borrowed) {
|
306 | |
307 |
|
308 |
|
309 |
|
310 | this.borrowed = [];
|
311 | }
|
312 | this.borrowed.push(about);
|
313 | };
|
314 |
|
315 | Doclet.prototype.mix = function(source) {
|
316 | |
317 |
|
318 |
|
319 |
|
320 | this.mixes = this.mixes || [];
|
321 | this.mixes.push(source);
|
322 | };
|
323 |
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 | Doclet.prototype.augment = function(base) {
|
330 | |
331 |
|
332 |
|
333 |
|
334 | this.augments = this.augments || [];
|
335 | this.augments.push(base);
|
336 | };
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 |
|
343 | Doclet.prototype.setMeta = function(meta) {
|
344 | |
345 |
|
346 |
|
347 |
|
348 | this.meta = this.meta || {};
|
349 |
|
350 | if (meta.range) {
|
351 | |
352 |
|
353 |
|
354 |
|
355 | this.meta.range = meta.range.slice(0);
|
356 | }
|
357 |
|
358 | if (meta.lineno) {
|
359 | |
360 |
|
361 |
|
362 |
|
363 | this.meta.filename = path.basename(meta.filename);
|
364 | |
365 |
|
366 |
|
367 |
|
368 | this.meta.lineno = meta.lineno;
|
369 |
|
370 | var pathname = path.dirname(meta.filename);
|
371 | if (pathname && pathname !== '.') {
|
372 | this.meta.path = pathname;
|
373 | }
|
374 | }
|
375 |
|
376 | |
377 |
|
378 |
|
379 |
|
380 | this.meta.code = this.meta.code || {};
|
381 | if (meta.id) { this.meta.code.id = meta.id; }
|
382 | if (meta.code) {
|
383 | if (meta.code.name) {
|
384 |
|
385 | this.meta.code.name = meta.code.name;
|
386 | }
|
387 | if (meta.code.type) {
|
388 |
|
389 | this.meta.code.type = meta.code.type;
|
390 | }
|
391 |
|
392 |
|
393 | if (meta.code.node) {
|
394 | Object.defineProperty(this.meta.code, 'node', {
|
395 | value: meta.code.node,
|
396 | enumerable: global.env.opts.debug ? true : false
|
397 | });
|
398 | }
|
399 | if (meta.code.funcscope) {
|
400 | this.meta.code.funcscope = meta.code.funcscope;
|
401 | }
|
402 | if (typeof meta.code.value !== 'undefined') {
|
403 |
|
404 | this.meta.code.value = meta.code.value;
|
405 | }
|
406 | if (meta.code.paramnames) {
|
407 | this.meta.code.paramnames = meta.code.paramnames.slice(0);
|
408 | }
|
409 | }
|
410 | };
|