UNPKG

crojsdoc

Version:

A documentation generator for JavaScript and CoffeeScript

341 lines (332 loc) 8.45 kB
// Generated by CoffeeScript 2.4.1 //# // Module dependencies. var dox, parseCodeContextCoffee; dox = require('./dox'); //# // Parse comments in the given string of `coffee`. // @param {String} coffee // @param {Object} options // @return {Array} // @see exports.parseComment // @api public exports.parseCommentsCoffee = function(coffee, options = {}) { var addBuf, addBufLine, addComment, buf, buf_line_number, comments, getCodeContext, ignore, indent, j, len, line_number, pos, raw; coffee = coffee.replace(/\r\n/gm, '\n'); comments = []; raw = options.raw; buf = ''; line_number = 1; indent = void 0; buf_line_number = void 0; getCodeContext = function() { var code, comment, i, indentre, k, len1, line, lines; lines = buf.split('\n'); // skip start empty lines while (lines.length > 0 && lines[0].trim() === '') { lines.splice(0, 1); buf_line_number++; } if (lines.length !== 0) { // get expected indent indentre = new RegExp('^' + lines[0].match(/^(\s*)/)[1]); // remove 'indent' from beginning for each line for (i = k = 0, len1 = lines.length; k < len1; i = ++k) { line = lines[i]; // skip empty line if (line.trim() === '') { continue; } lines[i] = line = line.replace(indentre, ''); // find line of same or little indent to stop there if (i !== 0 && !line.match(/^\s/)) { break; } } // cut below lines lines.length = i; } code = lines.join('\n').trim(); // add code to previous comment comment = comments[comments.length - 1]; if (comment) { // find parent i = comments.length - 2; while (i >= 0) { if (comments[i].indent.search(comment.indent) < 0) { break; } i--; } comment.ctx = parseCodeContextCoffee(code, i >= 0 ? comments[i] : null); comment.tags.forEach(function(tag) { if (tag.type === 'class') { comment.ctx || (comment.ctx = {}); comment.ctx.type = 'class'; } }); if (comment.ctx && comment.ctx.type === 'class') { comment.class_code = code; comment.class_codeStart = buf_line_number; } else { comment.code = code; comment.codeStart = buf_line_number; } } return buf = ''; }; addBuf = function() { buf += coffee[pos]; if ('\n' === coffee[pos]) { line_number++; return true; } return false; }; addBufLine = function() { var results; results = []; while (pos < len) { if (addBuf()) { break; } results.push(pos++); } return results; }; addComment = function() { var comment; comment = dox.parseComment(buf, options); comment.ignore = ignore; comment.indent = indent; comments.push(comment); buf = ''; return buf_line_number = line_number; }; pos = 0; len = coffee.length; while (pos < coffee.length) { // block comment if (coffee.slice(pos, pos + 3) === '###') { indent = buf.match(/([ \t]*)$/)[1]; // code following previous comment getCodeContext(); pos += 3; if ('\n' === coffee[pos]) { line_number++; } ignore = '!' === coffee[pos]; pos++; while (pos < len) { if (coffee.slice(pos, pos + 3) === '###') { pos += 3; if ('\n' === coffee[pos]) { line_number++; } buf = buf.replace(/^[ \t]*[\*\#] ?/gm, ''); addComment(); break; } addBuf(); pos++; } // doxygen style comment } else if ('#' === coffee[pos] && '#' === coffee[pos + 1]) { indent = buf.match(/([ \t]*)$/)[1]; // code following previous comment getCodeContext(); pos += 2; ignore = '!' === coffee[pos]; if ('\n' === coffee[pos]) { line_number++; } else { pos++; addBufLine(); } while (1) { pos++; // check whether line comment j = pos; while (j < len) { if ('#' === coffee[j]) { break; } if (' ' !== coffee[j] && '\t' !== coffee[j]) { break; } j++; } if ('#' !== coffee[j]) { buf = buf.replace(/^[ \t]*#{1,2} {0,1}/gm, ''); addComment(); pos--; break; } // add this line if comment addBufLine(); } // line comment } else if ('#' === coffee[pos]) { addBufLine(); } else { // buffer code addBuf(); } pos++; } if (comments.length === 0) { comments.push({ tags: [], description: { full: '', summary: '', body: '' }, isPrivate: false }); } // trailing code getCodeContext(); return comments; }; //# // Parse the context from the given `str` of coffee. // This method attempts to discover the context // for the comment based on it's code. Currently // supports: // - function statements // - function expressions // - prototype methods // - prototype properties // - methods // - properties // - declarations // @param {String} str // @return {Object} // @api public parseCodeContextCoffee = function(str, parent) { var class_name; str = str.split('\n')[0]; // function expression if (/^(\w+) *= *(\(.*\)|) *[-=]>/.exec(str)) { return { type: 'function', name: RegExp.$1, string: RegExp.$1 + '()' }; // prototype method } else if (/^(\w+)::(\w+) *= *(\(.*\)|) *[-=]>/.exec(str)) { return { type: 'method', constructor: RegExp.$1, cons: RegExp.$1, name: RegExp.$2, string: RegExp.$1 + '::' + RegExp.$2 + '()' }; // prototype property } else if (/^(\w+)::(\w+) *= *([^\n]+)/.exec(str)) { return { type: 'property', constructor: RegExp.$1, cons: RegExp.$1, name: RegExp.$2, value: RegExp.$3, string: RegExp.$1 + '::' + RegExp.$2 }; // method } else if (/^[\w.]*?(\w+)\.(\w+) *= *(\(.*\)|) *[-=]>/.exec(str)) { return { type: 'method', receiver: RegExp.$1, name: RegExp.$2, string: RegExp.$1 + '.' + RegExp.$2 + '()' }; // property } else if (/^[\w.]*?(\w+)\.(\w+) *= *([^\n]+)/.exec(str)) { return { type: 'property', receiver: RegExp.$1, name: RegExp.$2, value: RegExp.$3, string: RegExp.$1 + '.' + RegExp.$2 }; // declaration } else if (/^(\w+) *= *([^\n]+)/.exec(str)) { return { type: 'declaration', name: RegExp.$1, value: RegExp.$2, string: RegExp.$1 }; } if (parent && parent.ctx && parent.ctx.type === 'class') { class_name = parent.ctx.name; } // CoffeeScript class syntax if (/\bclass +(\w+)/.exec(str)) { return { type: 'class', name: RegExp.$1, string: 'class ' + RegExp.$1 }; // prototype method } else if (/^(\w+) *: *(\(.*\)|) *[-=]>/.exec(str)) { if (class_name) { return { type: 'method', constructor: class_name, cons: class_name, name: RegExp.$1, string: class_name + '::' + RegExp.$1 + '()', is_constructor: RegExp.$1 === 'constructor' }; } else { return { type: 'method', name: RegExp.$1, string: RegExp.$1 + '()' }; } // prototype property } else if (/^(\w+) *: *([^\n]+)/.exec(str)) { if (class_name) { return { type: 'property', constructor: class_name, cons: class_name, name: RegExp.$1, value: RegExp.$2, string: class_name + '::' + RegExp.$1 }; } else { return { type: 'property', name: RegExp.$1, value: RegExp.$2, string: RegExp.$1 }; } } else if (!class_name) { // method } else if (/^@(\w+) *: *(\(.*\)|) *[-=]>/.exec(str)) { return { type: 'method', receiver: class_name, name: RegExp.$1, string: class_name + '.' + RegExp.$1 + '()' }; // property } else if (/^@(\w+) *: *([^\n]+)/.exec(str)) { return { type: 'property', receiver: class_name, name: RegExp.$1, value: RegExp.$2, string: class_name + '.' + RegExp.$1 }; } else { return { class_name: class_name }; } };