UNPKG

apidoc

Version:

RESTful web API Documentation Generator

332 lines (293 loc) 10.2 kB
var _ = require("underscore"); var path = require("path"); var semver = require("semver"); var findFiles = require("./utils/find_files"); var path = require("path"); var PackageInfo = require("./package_info"); var Parser = require("./parser"); var Worker = require("./worker"); var Filter = require("./filter"); var colors = require("colors"); var fs = require("fs-extra"); // Options var _defaultOptions = { excludeFilters: [], includeFilters: [ ".*\\.(coffee|cs|dart|erl|go|java|js|php?|py|rb|ts|pm)$" ], src: path.join(__dirname, "../example/"), dest: path.join(__dirname, "../doc/"), debug: false, log: true, simulate: false, template: path.join(__dirname, "../template/"), filters: {}, parsers: {}, workers: {}, marked: { gfm: true, tables: true, breaks: false, pedantic: false, sanitize: false, smartLists: false, smartypants: false } }; var options = {}; _.defaults(options, _defaultOptions); // uncaughtException process.on("uncaughtException", function(err) { console.error((new Date()).toUTCString() + " uncaughtException:", err.message); console.error(err.stack); process.exit(1); }); /** * Output Debug-Messages * * @param {String} message */ function debug(message) { if(options.debug) console.log("apidoc: " + message); } // debug /** * Output Log-Messages * * @param {String} message */ function log(message) { if(options.log) console.log("apidoc: " + message); } // log /** * Output Error-Log-Messages * * @param {String} message */ function logWarn(message) { if(options.log) console.warn("apidoc: " + message.yellow); } // logWarn var app = { debug: debug, log: log, logWarn: logWarn, options: options, filters: { apierror : "./plugins/filter_api_error.js", apiinfo : "./plugins/filter_api_info.js", apiparam : "./plugins/filter_api_param.js", apisuccess : "./plugins/filter_api_success.js" }, parsers: { api : "./plugins/parser_api.js", apidefineerrorstructure : "./plugins/parser_api_define_error_structure.js", apidefineheaderstructure : "./plugins/parser_api_define_header_structure.js", apidefinepermission : "./plugins/parser_api_define_permission.js", apidefinestructure : "./plugins/parser_api_define_structure.js", apidefinesuccessstructure: "./plugins/parser_api_define_success_structure.js", apigroupdescription : "./plugins/parser_api_group_description.js", apidescription : "./plugins/parser_api_description.js", apierror : "./plugins/parser_api_error.js", apierrorexample : "./plugins/parser_api_error_example.js", apierrorstructure : "./plugins/parser_api_error_structure.js", apierrortitle : "./plugins/parser_api_error_title.js", apiexample : "./plugins/parser_api_example.js", apiheader : "./plugins/parser_api_header.js", apiheaderexample : "./plugins/parser_api_header_example.js", apiheaderstructure : "./plugins/parser_api_header_structure.js", apiheadertitle : "./plugins/parser_api_header_title.js", apigroup : "./plugins/parser_api_group.js", apiinfo : "./plugins/parser_api_info.js", apiinfoexample : "./plugins/parser_api_info_example.js", apiinfotitle : "./plugins/parser_api_info_title.js", apiname : "./plugins/parser_api_name.js", apiparam : "./plugins/parser_api_param.js", apiparamtitle : "./plugins/parser_api_param_title.js", apipermission : "./plugins/parser_api_permission.js", apistructure : "./plugins/parser_api_structure.js", apisuccess : "./plugins/parser_api_success.js", apisuccessexample : "./plugins/parser_api_success_example.js", apisuccessstructure : "./plugins/parser_api_success_structure.js", apisuccesstitle : "./plugins/parser_api_success_title.js", apiversion : "./plugins/parser_api_version.js" }, workers: { workererrorstructure : "./plugins/worker_error_structure.js", workererrortitle : "./plugins/worker_error_title.js", workerheaderstructure : "./plugins/worker_header_structure.js", workerheadertitle : "./plugins/worker_header_title.js", workerparamtitle : "./plugins/worker_param_title.js", workerpermission : "./plugins/worker_permission.js", workerstructure : "./plugins/worker_structure.js", workersuccessstructure : "./plugins/worker_success_structure.js", workersuccesstitle : "./plugins/worker_success_title.js" } }; // app /** * Output parsed content to files * * @param {Object[]} parsedFiles * @param {String[]} filenames * @returns {Object} */ function createOutputFiles(parsedFiles, parsedFilenames, packageInfos) { var blocks = []; // Reduce to get only local blocks. for(var fileIndex = 0; fileIndex < parsedFiles.length; fileIndex += 1) { var parsedFile = parsedFiles[fileIndex]; for(var blockIndex = 0; blockIndex < parsedFile.length; blockIndex += 1) { var block = parsedFile[blockIndex]; // "<= 1" if successTitle gets removed, empty Object remain. if(Object.keys(block.global).length <= 1 && Object.keys(block.local).length > 0) { // Add needed Elements for sorting if( ! block.local.group) block.local.group = path.basename( parsedFilenames[fileIndex] ); if( ! block.local.type) block.local.type = ""; if( ! block.local.url) block.local.url = ""; if( ! block.local.version) block.local.version = "0.0.0"; // Info Element if( ! block.local.filename) block.local.filename = parsedFilenames[fileIndex]; // Convert dir delimeter \\ to / block.local.filename = block.local.filename.replace(/\\/g, "/"); blocks.push(block.local); } } // for blockIndex } // for fileIndex // Empty parsedFiles = null; parsedFilenames = null; // Sort by group ASC, name ASC, version DESC blocks.sort(function(a, b) { var nameA = a.group + a.name; var nameB = b.group + b.name; if(nameA === nameB) { if(a.version === b.version) return 0; return (semver.gte(a.version, b.version)) ? -1 : 1; } return (nameA < nameB) ? -1 : 1; }); if(options.simulate) { app.debug(""); app.debug("!!! Simulation !!! No file or dir will be copied or created."); app.debug(""); } app.debug("create dir: " + options.dest); if( ! options.simulate) fs.mkdirsSync(options.dest); app.debug("copy template " + options.template + " to: " + options.dest); if( ! options.simulate) fs.copySync(options.template, options.dest); // api_data var json = JSON.stringify(blocks, null, 2); json = json.replace(/(\r\n|\n|\r)/g, "\r\n"); app.debug("write json file: " + options.dest + "api_data.json"); if( ! options.simulate) fs.writeFileSync(options.dest + "./api_data.json", json); app.debug("write js file: " + options.dest + "api_data.js"); if( ! options.simulate) fs.writeFileSync(options.dest + "./api_data.js", "define({ api: " + json + " });"); // api_project var json = JSON.stringify(packageInfos, null, 2); json = json.replace(/(\r\n|\n|\r)/g, "\r\n"); app.debug("write json file: " + options.dest + "api_project.json"); if( ! options.simulate) fs.writeFileSync(options.dest + "./api_project.json", json); app.debug("write js file: " + options.dest + "api_project.js"); if( ! options.simulate) fs.writeFileSync(options.dest + "./api_project.js", "define(" + json + ");"); } // createOutputFiles /** * Parse files in specified folder. * @param {Object} parser Util to parse the files. * @param {Object} options The options used to parse and filder the files. * @param {Object[]} parsedFiles List of parsed files. * @param {String[]} parsedFilenames List of parsed files, with full path. */ function parseFiles(parser, options, parsedFiles, parsedFilenames) { var files = findFiles(options); // Parser for(var i = 0; i < files.length; i += 1) { var filename = options.src + files[i]; var parsedFile = parser.parseFile(filename); if(parsedFile) { app.log("parse file: " + filename); parsedFiles.push(parsedFile); parsedFilenames.push(filename); } } // for } // parseFiles /** * Main * * @return {Number} Count parsed files. */ function main(defaults) { // bin-parameters if(defaults) options = _.defaults(defaults, options); // Paths options.dest = path.join(options.dest, "./"); options.template = path.join(options.template, "./"); // Funktionen erweitern / ersetzen _.defaults(options.logger, app.logger); _.defaults(options.filters, app.filters); _.defaults(options.parsers, app.parsers); _.defaults(options.workers, app.workers); // Options app.options = options; var packageInfo = new PackageInfo(app); var parser = new Parser(app); var parsedFiles = []; var parsedFilenames = []; var worker = new Worker(app); var filter = new Filter(app); try { // If input option for source is an array of folders, // parse each folder in the order provided. if (options.src instanceof Array) { options.src.forEach(function(folder) { // Keep same options for each folder, but ensure the "src" of options // is the folder currently being processed. var folderOptions = options; folderOptions.src = path.join(folder, "./"); parseFiles(parser, folderOptions, parsedFiles, parsedFilenames); }); } else { // If the input option for source is a single folder, parse as usual. options.src = path.join(options.src, "./"); parseFiles(parser, options, parsedFiles, parsedFilenames); } // Worker / Filter if(parsedFiles.length > 0) { worker.process(parsedFiles, parsedFilenames); filter.process(parsedFiles, parsedFilenames); createOutputFiles(parsedFiles, parsedFilenames, packageInfo.get()); return parsedFiles.length; } else { app.log("Nothing to do."); return 0; } } catch(e) { if(e.stack) app.debug(e.stack); app.log(e); } return; } // main /** * Exports */ module.exports = main; // Direct call if(path.dirname(process.argv[1]) === __dirname) main();