UNPKG

github

Version:
211 lines (173 loc) 7.26 kB
#!/usr/bin/env node /** section: github, internal * class ApiGenerator * * Copyright 2012 Cloud9 IDE, Inc. * * This product includes software developed by * Cloud9 IDE, Inc (http://c9.io). * * Author: Mike de Boer <mike@c9.io> **/ "use strict"; var fs = require("fs"); var Path = require("path"); var Url = require("url"); var Util = require("./util"); var npmPackageJSON = require("../package.json"); var TestSectionTpl = fs.readFileSync(__dirname + "/../templates/test_section.js.tpl", "utf8"); var TestHandlerTpl = fs.readFileSync(__dirname + "/../templates/test_handler.js.tpl", "utf8"); var main = module.exports = function() { // check routes path var routesPath = Path.join(__dirname, "routes.json"); var routes = JSON.parse(fs.readFileSync(routesPath, "utf8")); if (!routes.defines) { Util.log("No routes defined.", "fatal"); process.exit(1); } Util.log("Generating..."); var defines = routes.defines; delete routes.defines; var sections = {}; var testSections = {}; var apidocs = ""; function prepareApi(struct, baseType) { if (!baseType) { baseType = ""; } Object.keys(struct).sort().forEach(function(routePart) { var block = struct[routePart]; if (!block) { return; } var messageType = baseType + "/" + routePart; if (block.url && block.params) { // we ended up at an API definition part! var parts = messageType.split("/"); var section = Util.toCamelCase(parts[1]); if (!block.method) { throw new Error("No HTTP method specified for " + messageType + "in section " + section); } // add the handler to the sections if (!sections[section]) { sections[section] = []; } parts.splice(0, 2); var funcName = Util.toCamelCase(parts.join("-")); apidocs += createComment(section, funcName, block); // add test to the testSections if (!testSections[section]) { testSections[section] = []; } testSections[section].push(TestHandlerTpl .replace("<%name%>", block.method + " " + block.url + " (" + funcName + ")") .replace("<%funcName%>", section + "." + funcName) .replace("<%params%>", getParams(block.params, " ")) ); } else { // recurse into this block next: prepareApi(block, messageType); } }); } function createComment(section, funcName, block) { var method = block['method'].toLowerCase(); var url = block['url']; var funcDisplayName = funcName; var apiVersion = npmPackageJSON['version']; var commentLines = [ "/**", " * @api {" + method + "} " + url + " " + funcName, " * @apiVersion " + apiVersion, " * @apiName " + funcDisplayName, " * @apiDescription " + block['description'], " * @apiGroup " + section, " *" ]; var paramsObj = block['params']; // sort params so Required come before Optional var paramKeys = Object.keys(paramsObj); paramKeys.sort(function(paramA, paramB) { var cleanParamA = paramA.replace(/^\$/, ""); var cleanParamB = paramB.replace(/^\$/, ""); var paramInfoA = paramsObj[paramA] || defines['params'][cleanParamA]; var paramInfoB = paramsObj[paramB] || defines['params'][cleanParamB]; var paramRequiredA = paramInfoA['required']; var paramRequiredB = paramInfoB['required']; if (paramRequiredA && !paramRequiredB) return -1; if (!paramRequiredA && paramRequiredB) return 1; return 0; }); paramKeys.forEach(function(param) { var cleanParam = param.replace(/^\$/, ""); var paramInfo = paramsObj[param] || defines['params'][cleanParam]; var paramRequired = paramInfo['required']; var paramType = paramInfo['type']; var paramDescription = paramInfo['description']; var paramDefaultVal = paramInfo['default']; var paramLabel = cleanParam; // add default value if there is one if (typeof paramDefaultVal !== "undefined") { paramLabel += '=' + paramDefaultVal } // show param as either required or optional if (!paramRequired) { paramLabel = "[" + paramLabel + "]"; } var allowedValues = ''; if (paramInfo['enum']) { allowedValues = '=' + paramInfo['enum'].map(function(val) { return val; //"\"" + val + "\""; }).join(','); } commentLines.push(" * @apiParam {" + paramType + allowedValues + "} " + paramLabel + " " + paramDescription); }); commentLines.push(" * @apiExample {js} ex:\ngithub." + section + "." + funcName + "({ ... });"); return commentLines.join("\n") + "\n */\n\n"; } function getParams(paramsStruct, indent) { var params = Object.keys(paramsStruct); if (!params.length) { return "{}"; } var values = []; var paramName, def; for (var i = 0, l = params.length; i < l; ++i) { paramName = params[i]; if (paramName.charAt(0) == "$") { paramName = paramName.substr(1); if (!defines.params[paramName]) { Util.log("Invalid variable parameter name substitution; param '" + paramName + "' not found in defines block", "fatal"); process.exit(1); } else { def = defines.params[paramName]; } } else { def = paramsStruct[paramName]; } values.push(indent + " " + paramName + ": \"" + def.type + "\""); } return "{\n" + values.join(",\n") + "\n" + indent + "}"; } Util.log("Converting routes to functions"); prepareApi(routes); var apidocsPath = Path.join(__dirname, "/../doc", "apidoc.js"); fs.writeFileSync(apidocsPath, apidocs); Object.keys(sections).forEach(function(section) { Util.log("Writing test file for " + section); var def = testSections[section]; var body = TestSectionTpl .replace("<%version%>", "3.0.0") .replace(/<%sectionName%>/g, section) .replace(/<%sectionAuthType%>/g, section == "installations" ? "integration" : "oauth") .replace("<%testBody%>", def.join("\n\n")); var path = Path.join(__dirname, "/../test", section + "Test.js"); fs.writeFileSync(path, body, "utf8"); }); require('./generateFlowTypes.js'); require('./generateTypeScriptTypes.js'); }; main();