rests
Version:
Easily generate API client's SDK — organize and simplify API Requests.
247 lines (244 loc) • 10.4 kB
JavaScript
#!/usr/bin/env node
"use strict";
/*!
* Rests CLI v1.1.1
* Author: Elis <github@elis.cc>
* License: MIT
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const cp = require('child_process');
const YAML = require("yaml");
const path = require("path");
const Rests = require('../index.js');
const getArgs = require('getarg');
const ts = require("typescript");
const package_info = require("../../package.json");
const { capitalize, dent, copyOptions, parseSet, mergeOptions, get, escapeRegExp, isInitializable, formatModulePath, tsToJs } = require("./helpers");
const generateDocs = require("./markdown");
const generateTypes = require("./types");
const privateMessage = (...args) => __awaiter(void 0, void 0, void 0, function* () {
return (console.log("This feature is only available on the private edition :)"),
process.exit());
});
const getModule = (name) => {
const globalRoot = cp.execSync('npm root -g').toString().trim();
const globalModulePath = path.join(globalRoot, name);
try {
return require(globalModulePath);
}
catch (e) {
}
try {
return require(name);
}
catch (e) { }
return false;
};
const privateModule = getModule('rests-private');
const generatePython = privateModule ? privateModule.generatePython : privateMessage;
const generateOpen = privateModule ? privateModule.generateOpen : privateMessage;
const main = () => __awaiter(void 0, void 0, void 0, function* () {
const ascii_art = decodeURIComponent("%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20_%20%20%20%20%20%20%20%0A%20_%20__%20___%20%20___%7C%20%7C_%20___%20%0A%7C%20%27__%2F%20_%20%5C%2F%20__%7C%20__%2F%20__%7C%0A%7C%20%7C%20%7C%20%20__%2F%5C__%20%5C%20%7C_%5C__%20%5C%0A%7C_%7C%20%20%5C___%7C%7C___%2F%5C__%7C___%2F%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A");
const usage = dent(`${ascii_art}
V.${package_info.version} by ${package_info.author}
\u001b[0m\u001b[94mUsage:\u001b[0m rests ./api.js --types --watch
The schema file can be a .js/.jsm/.ts file that has a default export of a Rests instance 'API' \u001b[33m(i.e export default API)\u001b[0m, or it can be a json file.\u001b[94m
`, 2);
const args = getArgs({
types: {
help: "Generate types, optionally pass the output file dir",
alias: "t"
},
docs: {
help: "Generate markdown docs, optionally pass the output file dir",
alias: "d",
},
python: {
help: "Generate Python API SDK",
alias: "p"
},
openapi: {
help: "Generate open API file",
},
watch: {
help: "Watch for changes and automatically generate",
alias: "w"
},
print: {
help: "Print to console instead of saving",
},
types_template: {
help: "The types file template path",
type: "string"
},
python_template: {
help: "The python file template path",
type: "string"
},
openapi_template: {
help: "The openapi template file, JSON or YAML object.",
type: "string"
},
responses: {
help: "Automatically make responses schema examples for documentation",
type: "boolean",
},
code_samples: {
help: "Automatically generate code samples for documentation",
type: "boolean",
default: true
},
use_cache: {
help: "OpenAPI: Use cached responses/request samples",
},
examples: {
help: "Include examples in documentation and comments",
type: "boolean",
default: true
},
}, {
usage
});
const schemaFile = path.join(process.cwd(), process.argv[0] === 'rests' ? process.argv[1] : process.argv[2]);
if (!schemaFile) {
console.error(usage);
process.exit();
}
const schemaName = path.basename(schemaFile).replace(/\.[^\.]+$/g, ''), schemaImportPath = formatModulePath(schemaFile);
//@ts-ignore
const isJSON = /\.json$/.test(schemaFile), isJS = /\.(m?jsx?|tsx?)$/.test(schemaFile), isTS = /\.tsx?$/.test(schemaFile) && tsToJs(schemaFile), tsImportPath = formatModulePath(isTS), importFile = isJS ?
(isTS
? (yield Promise.resolve().then(() => import(tsImportPath))).default
: (yield Promise.resolve().then(() => import(schemaImportPath))).default)
:
(isJSON ? JSON.parse(fs.readFileSync(schemaFile, "utf-8")) : null), parseFile = importFile.__esModule && importFile.default ? importFile.default : importFile;
if (isJS && !parseFile) {
console.error("We couldn't import the Rests instance. Make sure you have exported it correctly, i.e \u001b[33mexport default API\u001b[0m");
process.exit();
}
if (!parseFile) {
console.error("Invalid schema file");
process.exit();
}
const restsInstance = isJS && parseFile, schema = restsInstance ? restsInstance.__schema__.schema : parseFile, options = restsInstance ? restsInstance.__schema__.options : undefined;
const makeDocs = () => __awaiter(void 0, void 0, void 0, function* () {
const docsOutFile = (typeof args.types == "string" ?
path.join(process.cwd(), args.types) :
path.join(process.cwd(), 'API.md'));
const generatedDocs = yield generateDocs(schema, restsInstance, options, {
responses: args.responses,
output: args.print ? false : docsOutFile
});
console.info("[+] " + (new Date()).toLocaleTimeString() + " Docs have been generated.");
if (args.print) {
console.log(generatedDocs);
return generatedDocs;
}
return docsOutFile;
});
const makeTypes = () => __awaiter(void 0, void 0, void 0, function* () {
const typesOutFile = (typeof args.types == "string" ?
path.join(process.cwd(), args.types) :
path.join(process.cwd(), schemaName + '.d.ts'));
const generatedTypes = generateTypes(schema, {
output: args.print ? false : typesOutFile,
includeExamples: args.examples,
template: args.types_template
});
console.info("[+] " + (new Date()).toLocaleTimeString() + " Types have been generated.");
if (args.print) {
console.log(generatedTypes);
return generatedTypes;
}
return typesOutFile;
});
const makePython = () => __awaiter(void 0, void 0, void 0, function* () {
const pythonOutFile = (typeof args.python == "string" ?
path.join(process.cwd(), args.python) :
path.join(process.cwd(), schemaName + '.py'));
const generatedAPI = generatePython(schema, {
output: args.print ? false : pythonOutFile,
includeExamples: args.examples,
template: args.python_template
});
console.info("[+] " + (new Date()).toLocaleTimeString() + " Python API has been generated.");
if (args.print) {
console.log(generatedAPI);
return generatedAPI;
}
return pythonOutFile;
});
const makeOpenAPI = () => __awaiter(void 0, void 0, void 0, function* () {
const openAPIOut = (typeof args.openapi == "string" ?
path.join(process.cwd(), args.openapi) :
path.join(process.cwd(), schemaName + '-openapi.yaml'));
const generatedOpenAPI = generateOpen(schema, restsInstance, {
output: args.print ? false : openAPIOut,
template: args.openapi_template,
responses: args.responses,
codeSamples: args.code_samples,
useCache: args.use_cache,
includeExamples: args.examples
});
console.info("[+] " + (new Date()).toLocaleTimeString() + " Open API schema has been generated.");
if (args.print) {
generatedOpenAPI.then(console.log);
return generatedOpenAPI;
}
return generatedOpenAPI;
});
if (args.docs) {
makeDocs();
}
if (args.types) {
makeTypes();
}
if (args.python) {
makePython();
}
if (args.openapi) {
makeOpenAPI();
}
if (args.watch) {
const watchFile = isTS || schemaFile;
if (isTS) {
(function watchTs() {
return __awaiter(this, void 0, void 0, function* () {
tsToJs(schemaFile, true);
});
})();
}
console.info("[*] Watching for changes..");
let lastStats = (yield fs.promises.stat(watchFile));
while (true) {
yield new Promise((res, rej) => setTimeout(res.bind(null, true), 1000));
let currentStats = (yield fs.promises.stat(watchFile));
if (currentStats.mtimeMs !== lastStats.mtimeMs) {
if (args.docs) {
makeDocs();
}
if (args.types) {
makeTypes();
}
if (args.python) {
makePython();
}
if (args.openapi) {
makeOpenAPI();
}
}
lastStats = currentStats;
}
}
});
main();