/** * @fileoverview This task helps you to run jsdoc3 to generate doc in your Grunt build sequence * @copyright Bertrand Chevrier 2012 * @author Bertrand Chevrier * @license MIT * * @module tasks/jsdoc-plugin */ /** * Register the jsdoc task and helpers to Grunt * @type GruntTask * @constructor * @param {Object} grunt - the grunt context */ module.exports = function jsDocTask(grunt) { 'use strict'; var util = require('util'), errorCode = { generic : 1, task : 3 }; /** * Register the jsdoc task to Grunt */ function registerJsdocTask() { var fs = require('fs'), path = require('path'), exec = require('./lib/exec'), options = grunt.task.current.options({'private': true}), done = grunt.task.current.async(), srcs = grunt.task.current.filesSrc, jsDocPath = grunt.task.current.data.jsdoc, jsDocNpmPath = 'node_modules/.bin/jsdoc', timeout = 60000, //todo implement and move in options cliFlags = ['recurse', 'private', 'lenient', 'explain', 'help', 'version', 'test', 'verbose', 'nocolor', 'template', 'configure', 'destination', 'encoding', 'tutorials', 'match', 'query'], jsDoc; //validate options if (!options.destination) { // Support for old syntax where destination was provided through 'dest' key options.destination = grunt.task.current.files[0].dest || 'doc'; } //legacy configs if(options.config){ options.configure = options.config; } // Compute JSDoc flags from options for(var optionName in options){ var option = options[optionName]; if(cliFlags.indexOf(optionName) === -1 || !option){ delete options[optionName]; } } grunt.log.debug(util.inspect(options)); if(jsDocPath && grunt.file.exists(jsDocPath) && grunt.file.isFile(jsDocPath)){ //use the given jsdoc path if set jsDoc = jsDocPath; } else { //lookup jsdoc jsDoc = exec.lookup(grunt, jsDocNpmPath, ['node_modules/grunt-jsdoc/']); } // convert jsdoc path to relative path jsDoc = path.relative('.', jsDoc);//, path.resolve('.')); //check if jsdoc npm module is installed if(jsDoc === undefined){ grunt.log.error('Unable to locate jsdoc'); grunt.fail.warn('Wrong installation/environnement', errorCode.generic); } else { grunt.log.debug("jsdoc found at : " + jsDoc); } //check if there is sources to generate the doc for if(srcs.length === 0 && !options.configure){ grunt.log.error('No source files defined'); grunt.fail.warn('Wrong configuration', errorCode.generic); } //check if jsdoc config file path is provided and does exist if (options.configure && !fs.existsSync(options.configure)){ grunt.log.error('jsdoc config file path does not exist'); grunt.fail.warn('Wrong configuration', errorCode.generic); } fs.exists(options.destination, function(exists){ //if the destination don't exists, we create it if(!exists){ grunt.file.mkdir(options.destination); grunt.log.debug('create destination : ' + options.destination); } //execution of the jsdoc command var child = exec.buildSpawned(grunt, jsDoc, srcs, options); child.stdout.on('data', function (data) { grunt.log.debug('jsdoc output : ' + data); }); child.stderr.on('data', function (data) { grunt.log.error('An error occurs in jsdoc process:\n' + data); grunt.fail.warn('jsdoc failure', errorCode.task); }); child.on('exit', function(code){ if(code === 0){ grunt.log.write('Documentation generated to ' + path.resolve(options.destination)); done(true); } else { grunt.log.error('jsdoc terminated'); grunt.fail.warn('jsdoc failure', errorCode.task); } }); }); } //bind the task to the grunt context grunt.registerMultiTask('jsdoc', 'Generates source documentation using jsdoc', registerJsdocTask); };