UNPKG

crojsdoc

Version:

A documentation generator for JavaScript and CoffeeScript

767 lines (741 loc) 25.6 kB
// Generated by CoffeeScript 1.8.0 (function() { var Collector, collect, dox, inflect, is_test_mode, markdown, _; _ = require('lodash'); dox = require('./dox'); inflect = require('inflect'); markdown = require('marked'); is_test_mode = process.env.NODE_ENV === 'test'; Collector = (function() { function Collector(contents, options) { this.contents = contents; this.options = options != null ? options : {}; this.result = { project_title: this.options.title || 'croquis-jsdoc', ids: {}, classes: {}, guides: [], pages: {}, restapis: {}, features: [], files: [] }; } Collector.prototype.addGuide = function(file, data) { var id, item; id = file.substr(0, file.length - 3); file = file.substr(0, file.length - 8).replace(/\//g, '.'); item = { name: inflect.humanize(inflect.underscore(file)), filename: 'guides/' + file, content: markdown(data) }; this.result.guides.push(item); return this.result.ids[id] = item; }; Collector.prototype.addFeature = function(file, data) { var feature, namespace; file = file.substr(0, file.length - 8); namespace = ''; file = file.replace(/(.*)\//, function(_, $1) { namespace = $1 + '/'; return ''; }); feature = ''; data = data.replace(/Feature: (.*)/, function(_, $1) { feature = $1; return ''; }); return this.result.features.push({ name: namespace + file, namespace: namespace, filename: 'features/' + namespace.replace(/\//g, '.') + file, feature: feature, content: data }); }; Collector.prototype.addFile = function(file, data) { var namespace; namespace = ''; file = file.replace(/(.*)\//, function(_, $1) { namespace = $1 + '/'; return ''; }); return this.result.files.push({ name: namespace + file, namespace: namespace, filename: 'files/' + namespace.replace(/\//g, '.') + file, content: data }); }; Collector.prototype.processParamFlags = function(tag) { var pos; if (tag.name[0] === '[' && tag.name[tag.name.length - 1] === ']') { tag.name = tag.name.substr(1, tag.name.length - 2); if ((pos = tag.name.indexOf('=')) >= 0) { tag.default_value = tag.name.substr(pos + 1); tag.name = tag.name.substr(0, pos); } tag.optional = true; } if (tag.name.substr(0, 1) === '+') { tag.name = tag.name.substr(1); tag.addable = true; } if (tag.name.substr(0, 1) === '-') { tag.name = tag.name.substr(1); tag.excludable = true; } return tag; }; Collector.prototype.findParam = function(params, name) { var found, param, _i, _len; for (_i = 0, _len = params.length; _i < _len; _i++) { param = params[_i]; if (param.name === name) { return param; } if (param.params) { found = this.findParam(param.params, name); if (found) { return found; } } } }; Collector.prototype.makeNested = function(comment, targetName) { var i, match, param, parentParam, _results; i = comment[targetName].length; _results = []; while (i-- > 0) { param = comment[targetName][i]; if (match = param.name.match(/\[?([^=]*)\.([^\]]*)\]?/)) { parentParam = this.findParam(comment[targetName], match[1]); if (parentParam) { comment[targetName].splice(i, 1); parentParam[targetName] = parentParam[targetName] || []; param.name = match[2]; _results.push(parentParam[targetName].unshift(param)); } else { _results.push(void 0); } } else { _results.push(void 0); } } return _results; }; Collector.prototype.applyMarkdown = function(str) { str = str.replace(/#\\#/g, '##'); return markdown(str); }; Collector.prototype.classifyComments = function(comments) { var current_class, current_module; current_class = void 0; current_module = void 0; return comments.forEach((function(_this) { return function(comment) { var i, id, last, seperator, tag, _i, _len, _ref; comment.ctx || (comment.ctx = {}); comment.params = []; comment.returnprops = []; comment.throws = []; comment.resterrors = []; comment.sees = []; comment.reverse_sees = []; comment.todos = []; comment["extends"] = []; comment.subclasses = []; comment.uses = []; comment.usedbys = []; comment.properties = []; comment.examples = []; if (comment.ctx.type === 'property' || comment.ctx.type === 'method') { id = comment.ctx.string.replace('()', ''); } else { id = comment.ctx.name; } comment.ctx.fullname = id; comment.namespace = ''; if (comment.ctx.type === 'property' || comment.ctx.type === 'method') { if (comment.ctx.cons != null) { comment["static"] = false; comment.ctx.class_name = comment.ctx.cons; } else if (comment.ctx.receiver != null) { comment["static"] = true; comment.ctx.class_name = comment.ctx.receiver; } } last = 0; _ref = comment.tags; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { tag = _ref[i]; if (tag.type === '') { comment.tags[last].string += "\n" + tag.string; continue; } last = i; switch (tag.type) { case 'page': case 'restapi': case 'class': comment.ctx.type = tag.type; if (tag.string) { comment.ctx.name = tag.string; comment.ctx.fullname = id = comment.ctx.name; } break; case 'module': comment.ctx.type = 'class'; comment.is_module = true; if (tag.string) { comment.ctx.name = tag.string; comment.ctx.fullname = id = comment.ctx.name; } comment.code = null; break; case 'memberof': if (/(::|#|\.prototype)$/.test(tag.parent)) { comment["static"] = false; comment.ctx.class_name = tag.parent.replace(/(::|#|\.prototype)$/, ''); } else { comment["static"] = true; comment.ctx.class_name = tag.parent; } break; case 'namespace': comment.namespace = tag.string ? tag.string + '.' : ''; break; case 'property': case 'method': comment.ctx.type = tag.type; if (tag.string) { comment.ctx.name = tag.string; } break; case 'static': comment["static"] = true; break; case 'private': comment.isPrivate = true; break; case 'abstract': comment.abstract = true; break; case 'async': comment.async = true; break; case 'promise': comment.return_promise = true; break; case 'nodejscallback': comment.return_nodejscallback = true; break; case 'chainable': comment.chainable = true; break; case 'param': case 'return': case 'returnprop': case 'throws': case 'resterror': case 'see': case 'extends': case 'todo': case 'type': case 'api': case 'uses': case 'override': break; default: console.log("Unknown tag : " + tag.type + " in " + comment.defined_in); } } if (comment.ctx.class_name) { if (comment.ctx.type === 'function') { comment.ctx.type = 'method'; } else if (comment.ctx.type === 'declaration') { comment.ctx.type = 'property'; } seperator = comment["static"] ? '.' : '::'; id = comment.ctx.class_name + seperator + comment.ctx.name; comment.ctx.fullname = comment.ctx.class_name.replace(/.*[\./](\w+)/, '$1') + seperator + comment.ctx.name; } if (comment.ctx.type === 'class') { current_class = comment; if (comment.is_module) { current_module = comment; } } if ((comment.ctx.type === 'property' || comment.ctx.type === 'method') && !comment.namespace) { if (current_class) { comment.namespace = current_class.namespace; } if (current_module && !comment.ctx.class_name) { comment.ctx.class_name = current_module.ctx.name; } } if (id) { comment.id = id; if (_this.result.ids.hasOwnProperty(id)) { _this.result.ids[id] = 'DUPLICATED ENTRY'; } else { _this.result.ids[id] = comment; } if (comment.namespace && _this.result.ids.hasOwnProperty(comment.namespace + id)) { _this.result.ids[comment.namespace + id] = 'DUPLICATED ENTRY'; } else { _this.result.ids[comment.namespace + id] = comment; } comment.html_id = (comment.namespace + id).replace(/[^A-Za-z0-9_]/g, '_'); } switch (comment.ctx.type) { case 'class': comment.ctx.name = comment.namespace + comment.ctx.name; comment.ctx.fullname = comment.namespace + comment.ctx.fullname; _this.result.classes[comment.ctx.name] = comment; if (comment.is_module) { return comment.filename = 'modules/' + comment.ctx.name.replace(/\//g, '.'); } else { return comment.filename = 'classes/' + comment.ctx.name.replace(/\//g, '.'); } break; case 'property': case 'method': comment.ctx.class_name = comment.namespace + comment.ctx.class_name; return comment.filename = 'classes/' + comment.ctx.class_name.replace(/\//g, '.'); case 'page': return comment.filename = 'pages'; case 'restapi': return comment.filename = 'restapis'; } }; })(this)); }; Collector.prototype.getComments = function(type, path, file, data) { var comments, namespace; if (type === 'coffeescript') { comments = dox.parseCommentsCoffee(data, { raw: true }); } else if (type === 'javascript') { comments = dox.parseComments(data, { raw: true }); } else if (type === 'page') { namespace = ''; file = file.substr(0, file.length - 3).replace(/[^A-Za-z0-9]*Page$/, ''); file = file.replace(/(.*)\//, function(_, $1) { namespace = $1; return ''; }); comments = [ { description: { summary: '', body: data, full: '' }, tags: [ { type: 'page', string: file }, { type: 'namespace', string: namespace } ] } ]; } if (comments == null) { return; } comments = comments.filter(function(comment) { var _ref; return comment.description.full || comment.description.summary || comment.description.body || ((_ref = comment.tags) != null ? _ref.length : void 0) > 0; }); comments.forEach((function(_this) { return function(comment) { return comment.defined_in = path; }; })(this)); this.classifyComments(comments); return comments; }; Collector.prototype.processComments = function(comments) { return comments.forEach((function(_this) { return function(comment) { var callback_params, class_comment, class_name, desc, i, str, tag, type, _i, _j, _k, _l, _len, _len1, _len2, _len3, _len4, _m, _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7; desc = comment.description; if (desc) { desc.full = _this.applyMarkdown(desc.full); desc.summary = _this.applyMarkdown(desc.summary); desc.body = _this.applyMarkdown(desc.body); } _ref = comment.tags; for (_i = 0, _len = _ref.length; _i < _len; _i++) { tag = _ref[_i]; switch (tag.type) { case 'param': tag = _this.processParamFlags(tag); _ref1 = tag.types; for (i = _j = 0, _len1 = _ref1.length; _j < _len1; i = ++_j) { type = _ref1[i]; tag.types[i] = type; } tag.description = tag.description; comment.params.push(tag); break; case 'return': _ref2 = tag.types; for (i = _k = 0, _len2 = _ref2.length; _k < _len2; i = ++_k) { type = _ref2[i]; tag.types[i] = type; } tag.description = tag.description; comment["return"] = tag; break; case 'returnprop': tag = dox.parseTag('@param ' + tag.string); tag = _this.processParamFlags(tag); _ref3 = tag.types; for (i = _l = 0, _len3 = _ref3.length; _l < _len3; i = ++_l) { type = _ref3[i]; tag.types[i] = type; } tag.description = tag.description; comment.returnprops.push(tag); break; case 'throws': if (/{([^}]+)}\s*(.*)/.exec(tag.string)) { comment.throws.push({ message: RegExp.$1, description: RegExp.$2 }); } else { comment.throws.push({ message: tag.string, description: '' }); } break; case 'resterror': if (/{(\d+)\/([A-Za-z0-9_ ]+)}\s*(.*)/.exec(tag.string)) { comment.resterrors.push({ code: RegExp.$1, message: RegExp.$2, description: RegExp.$3 }); } break; case 'see': str = tag.local || tag.url; comment.sees.push(str); break; case 'todo': comment.todos.push(tag.string); break; case 'extends': comment["extends"].push(tag.string); if ((_ref4 = _this.result.ids[tag.string]) != null) { _ref4.subclasses.push(comment.ctx.name); } break; case 'uses': comment.uses.push(tag.string); if ((_ref5 = _this.result.ids[tag.string]) != null) { _ref5.usedbys.push(comment.ctx.name); } break; case 'type': _ref6 = tag.types; for (i = _m = 0, _len4 = _ref6.length; _m < _len4; i = ++_m) { type = _ref6[i]; tag.types[i] = type; } comment.types = tag.types; break; case 'example': comment.examples.push(tag); break; case 'override': if (_this.result.ids[tag.string] && _this.result.ids[tag.string] !== 'DUPLICATED ENTRY') { comment.override = _this.result.ids[tag.string]; } comment.override_link = tag.string; } } if (comment.ctx.type === 'class') { if (/^class +\w+ +extends +([\w\.]+)/.exec(comment.class_code)) { comment["extends"].push(RegExp.$1); if ((_ref7 = _this.result.ids[RegExp.$1]) != null) { _ref7.subclasses.push(comment.ctx.name); } } } _this.makeNested(comment, 'params'); _this.makeNested(comment, 'returnprops'); if (comment.return_nodejscallback) { callback_params = [ { name: 'error', types: ['Error'], description: 'See throws' } ]; if (comment["return"]) { callback_params.push({ name: 'result', types: comment["return"].types, description: 'See returns' }); } comment.params.push({ name: 'callback', types: ['Function'], optional: comment.return_promise, description: 'NodeJS style\'s callback', params: callback_params }); } if (comment.chainable && !comment["return"]) { comment["return"] = { types: [comment.ctx.class_name], description: 'this' }; } switch (comment.ctx.type) { case 'property': case 'method': class_name = comment.ctx.class_name; if (class_name && (class_comment = _this.result.classes[class_name])) { if (comment.ctx.is_coffeescript_constructor) { class_comment.code = comment.code; class_comment.line_number = comment.line_number; return class_comment.params = comment.params; } else { class_comment.properties.push(comment); if (class_comment.is_module) { return comment.filename = comment.filename.replace('classes/', 'modules/'); } } } break; case 'page': return _this.result.pages[comment.ctx.name] = comment; case 'restapi': return _this.result.restapis[comment.ctx.name] = comment; } }; })(this)); }; Collector.prototype.refineResult = function() { var result; result = this.result; result.classes = Object.keys(result.classes).sort(function(a, b) { var a_ns, b_ns; a_ns = result.classes[a].namespace; b_ns = result.classes[b].namespace; if (a_ns < b_ns) { return -1; } if (a_ns > b_ns) { return 1; } if (a < b) { return -1; } else { return 1; } }).map(function(name) { return result.classes[name]; }); result.pages = Object.keys(result.pages).sort(function(a, b) { var a_ns, b_ns; a_ns = result.pages[a].namespace; b_ns = result.pages[b].namespace; if (a_ns < b_ns) { return -1; } if (a_ns > b_ns) { return 1; } if (a < b) { return -1; } else { return 1; } }).map(function(name) { return result.pages[name]; }); result.restapis = Object.keys(result.restapis).sort(function(a, b) { var a_ns, b_ns; a_ns = result.restapis[a].namespace; b_ns = result.restapis[b].namespace; if (a_ns < b_ns) { return -1; } if (a_ns > b_ns) { return 1; } a = a.replace(/([A-Z]+) \/(.*)/, '-$2 $1'); b = b.replace(/([A-Z]+) \/(.*)/, '-$2 $1'); if (a < b) { return -1; } else { return 1; } }).map(function(name) { return result.restapis[name]; }); result.guides = result.guides.sort(function(a, b) { if (a.name < b.name) { return -1; } else { return 1; } }); result.features = result.features.sort(function(a, b) { if (a.name < b.name) { return -1; } else { return 1; } }); result.files = result.files.sort(function(a, b) { var a_ns, b_ns; a_ns = a.namespace; b_ns = b.namespace; if (a_ns < b_ns) { return -1; } if (a_ns > b_ns) { return 1; } if (a.name < b.name) { return -1; } else { return 1; } }); result.classes.forEach(function(klass) { var property, _i, _len, _ref, _results; klass.properties.sort(function(a, b) { if (a.ctx.name < b.ctx.name) { return -1; } else { return 1; } }); _ref = klass.properties; _results = []; for (_i = 0, _len = _ref.length; _i < _len; _i++) { property = _ref[_i]; _results.push(property.ctx = _.pick(property.ctx, 'type', 'name', 'fullname')); } return _results; }); result.modules = result.classes.filter(function(klass) { return klass.is_module; }); return result.classes = result.classes.filter(function(klass) { return !klass.is_module; }); }; Collector.prototype.getType = function(file) { if (/\.coffee$/.test(file)) { return 'coffeescript'; } else if (/\.js$/.test(file)) { return 'javascript'; } else if (/Page\.md$/.test(file)) { return 'page'; } else if (/Guide\.md$/.test(file)) { return 'guide'; } else if (/\.feature$/.test(file)) { return 'feature'; } else if (file === 'README') { return 'readme'; } else { return 'unknown'; } }; Collector.prototype.makeReverseSeeAlso = function(comments) { var comment, me, other, see, _i, _j, _len, _len1, _ref, _ref1, _ref2; for (_i = 0, _len = comments.length; _i < _len; _i++) { comment = comments[_i]; _ref = comment.sees; for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { see = _ref[_j]; other = this.result.ids[see]; if (other && other !== 'DUPLICATED ENTRY') { me = this.result.ids[comment.id]; if (me && me === 'DUPLICATED ENTRY') { if ((_ref1 = other.reverse_sees) != null) { _ref1.push(comment.namespace + comment.id); } } else { if ((_ref2 = other.reverse_sees) != null) { _ref2.push(comment.id); } } } } } }; Collector.prototype.run = function() { var all_comments, comments, data, file, file_count_read, path, type, _i, _len, _ref, _ref1; all_comments = []; file_count_read = 0; _ref = this.contents; for (_i = 0, _len = _ref.length; _i < _len; _i++) { _ref1 = _ref[_i], path = _ref1.path, file = _ref1.file, data = _ref1.data; type = this.getType(file); switch (type) { case 'guide': this.addGuide(file, data); break; case 'feature': this.addFeature(file, data); break; case 'coffeescript': case 'javascript': case 'page': comments = this.getComments(type, path, file, data); if (comments != null) { [].push.apply(all_comments, comments); } break; case 'readme': this.result.readme = markdown(data); } if (type === 'coffeescript' || type === 'javascript') { this.addFile(file, data); } file_count_read++; if (!(this.options.quite || is_test_mode)) { console.log(file + ' is processed'); } } if (!is_test_mode) { console.log('Total ' + file_count_read + ' files processed'); } this.processComments(all_comments); if (this.options.reverse_see_also) { this.makeReverseSeeAlso(all_comments); } if (!this.options.files) { this.result.files = []; } return this.refineResult(); }; return Collector; })(); collect = function(contents, options) { var collector; collector = new Collector(contents, options); collector.run(); return collector.result; }; module.exports = collect; }).call(this);