UNPKG

short-jsdoc

Version:

short and simple jsdoc Object Oriented syntax format and implementation

306 lines (256 loc) 8.13 kB
/* @module shortjsdoc.node nodejs command line utility for generating the .json definition scanning a given source folder or file. Depends on src/JsDocMaker.js *IMPORTANT* don't use console.log here since the output is dumped to stdout */ var fs = require('fs') , path = require('path') , esprima = require('esprima') , _ = require('underscore') , JsDocMaker = require('./jsdocmaker/main.js') , shell = require('shelljs'); //@class ShortJsDoc main class for running jsdocmaker using node through the command line. var ShortJsDoc = function() { this.maker = new JsDocMaker(); this.projectMetadata = {jsdoc: {}}; this.sources = {}; }; ShortJsDoc.make = function(options) { return (new ShortJsDoc()).jsdoc(options); }; _(ShortJsDoc.prototype).extend({ //@method error dumps an error @param {String} m error: function (m) { console.log(m + '\nUSAGE:\n\tnode src/shortjsdoc.js home/my-js-project/ home/another-js-project/ ... > html/data.json'); process.exit(1); } // @method tryToParseJsonFile @param {String} path , tryToParseJsonFile: function(path) { try { var s = fs.readFileSync(path); return JSON.parse(s); } catch(ex) { return null; } } //@method execute MAIN method to parse the parsed folder's javascript files recursively and return the AST of the jsdoc. //@param {JsDocOptions}options meta information about the project like title, url, license, etc. Hsa the same format as package.json file //@return {Object} the jsdoc AST object of all the parsed files. , execute: function(options) { var self=this; this.computeVendorDirs(options); _(options.input).each(function(inputDir) { _(self.sources).extend(self.buildSources(inputDir)); }); this.parsedSources = null; try { parsedSources = this.parseSources(); } catch (ex) { // will print the javascript syntax error detected in the sources. we parse only valid js! console.error('There is JavaScript syntax error in your source. It cannot be parsed'); //TODO: file and line number and string console.error('Failing code fragment: \n', this.maker.data.source.substring(ex.index - 50, ex.index + 50)); fs.writeFileSync('jsdoc_failed_source.js', this.maker.data.source); console.log('\n * Dumped file that fails at jsdoc_failed_source.js * \n'); console.error(ex); throw ex; } var jsdoc = this.maker.data; this.projectMetadata = jsdoc.projectMetadata = options.projectMetadata || {name: 'Untitled Project'}; this.maker.postProccess(); return jsdoc; } //@method computeVendorDirs @param {JsDocOptions} options , computeVendorDirs: function(options) { _(options.vendor).each(function(vendorName) { if(!vendorName) { return } var f = path.join(ShortJsDoc.getThisFolder(), 'vendor-jsdoc', vendorName); var stats = null; try { stats = fs.statSync(f); } catch(ex) { // console.log(ex) //TODO: log vendor name nor found? } if(stats && (stats.isDirectory() || stats.isFile())) { options.input.push(f); } }); // console.log('options.vendor', options.vendor) } //@method jsdoc public method meant to be called from user projects build-time code. It will perform all the job of soing the parse and generating a full html output project ready to be used. //@param {JsDocOptions}options meta information about the project like title, url, license, etc. Hsa the same format as package.json file , jsdoc: function(options) { //generate the data.json file var jsdoc = this.execute(options); var output = this.dumpJSON(jsdoc, options); if(!options.jsonOuput && options.output) { shell.rm('-rf', options.output) var htmlFolder = ShortJsDoc.getHtmlFolder(); shell.cp('-rf', htmlFolder, options.output); // ShortJsDoc.copyRecursiveSync(htmlFolder, options.output); var f = path.join(options.output, 'data.json'); output = 'window.__shortjsdoc_data = ' + output; fs.writeFileSync(f, output); } else { console.log(output); // prints on stdout } } // @method dumpJSON dump to json string the full ast. configurable through this.projectMetadata.jsdoc.dontMinifyOutput , dumpJSON: function(jsdoc, options) { if(options && options.dontMinifyOutput) { return JSON.stringify(jsdoc, null, 4); // dump the output indented: } else { return JSON.stringify(jsdoc); // dump the output minified: } } //@method parseSources , parseSources: function() { var buffer = [], self = this; _(this.sources).each(function(val, file) { self.maker.addFile(val, file); }); this.maker.jsdoc(); } //@method __parseSourcesFastVersion this was the previous implementation without file separation support. Nevertheless we // let this uncommented and unused because parsing separate files introduced a significant parsing duration (parformance). // TODO. let the user performa a --fast-parsing not supporting files but much faster just for fast jsdoc writting.. , __parseSourcesFastVersion: function() { var buffer = [], self = this; _(this.sources).each(function(val, file) { maker.addFile(value, name); buffer.push(val); }); this.maker.parseFile(buffer.join('\n\n'), 'ALL.js'); } //@method buildSources parse all files in passed folders and returns the parsed results in t //@param Array<String> inputDir @returns {Object} the parsed jsdoc AST object of all passed folders , buildSources: function buildSources(inputDir) { var map = {} , self = this; if(!inputDir) { console.log('ERROR invalid null input directory'); return; } if(!fs.statSync(inputDir).isDirectory()) { self.readSource(inputDir, map); } else { ShortJsDoc.folderWalk(inputDir, function(error, file) { if(!error && file && JsDocMaker.stringEndsWith(file, '.js')) { self.readSource(file, map); } }); } return map; } //@method readSource @param file @param map , readSource: function(file, map) { var src = fs.readFileSync(file, 'utf8'); map[file] = src; } }); //@method getHtmlFolder @return {String} this module's html folder path @static ShortJsDoc.getHtmlFolder = function() { var f = ShortJsDoc.getThisFolder(); return path.join(f, 'html'); }; //@method getThisFolder @return {String} this module's folder path @static ShortJsDoc.getThisFolder = function() { var f = module.filename; f = f.substring(0, f.length - path.join('src','shortjsdoc.js').length); return f; }; //UTILITIES // @method folderWalk General function for walking a folder recusively and sync @static ShortJsDoc.folderWalk = function (dir, action) { if (typeof action !== "function") { action = function (error, file) { }; } var list = fs.readdirSync(dir); list.forEach(function (file) { var sep = JsDocMaker.stringEndsWith(dir, '/') ? '' : '/'; var path = dir + sep + file; var stat = fs.statSync(path); if (stat && stat.isDirectory()) { ShortJsDoc.folderWalk(path, action); } else { action(null, path); } }); }; // // @method copyRecursiveSync copy directories recursively just like cp -r @static // // @param {String} src The path to the thing to copy. // // @param {String} dest The path to the new copy. // ShortJsDoc.copyRecursiveSync = function(src, dest) // { // var exists = fs.existsSync(src); // var stats = exists && fs.statSync(src); // var isDirectory = exists && stats.isDirectory(); // if (exists && isDirectory) // { // fs.mkdirSync(dest); // fs.readdirSync(src).forEach(function(childItemName) // { // ShortJsDoc.copyRecursiveSync(path.join(src, childItemName), path.join(dest, childItemName)); // }); // } // else // { // fs.linkSync(src, dest); // } // }; ShortJsDoc.JsDocMaker = JsDocMaker; module.exports = ShortJsDoc; // @class JsDocOptions // @property {String} output output folder // @property {Array<String>} input the source code folders that will be parsed recursively. // @property {Array<String>} vendor include the jsdoc of libraries supported by short-jsdoc (see vendor-jsdoc folder). Example: vendor: ['javascript', 'html']