@nestia/sdk
Version:
Nestia SDK and Swagger generator
259 lines • 12.7 kB
JavaScript
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());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NestiaSdkApplication = void 0;
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const tstl_1 = require("tstl");
const AccessorAnalyzer_1 = require("./analyses/AccessorAnalyzer");
const ConfigAnalyzer_1 = require("./analyses/ConfigAnalyzer");
const PathAnalyzer_1 = require("./analyses/PathAnalyzer");
const ReflectControllerAnalyzer_1 = require("./analyses/ReflectControllerAnalyzer");
const TypedHttpRouteAnalyzer_1 = require("./analyses/TypedHttpRouteAnalyzer");
const TypedWebSocketRouteAnalyzer_1 = require("./analyses/TypedWebSocketRouteAnalyzer");
const E2eGenerator_1 = require("./generates/E2eGenerator");
const SdkGenerator_1 = require("./generates/SdkGenerator");
const SwaggerGenerator_1 = require("./generates/SwaggerGenerator");
const IReflectOperationError_1 = require("./structures/IReflectOperationError");
const StringUtil_1 = require("./utils/StringUtil");
const VersioningStrategy_1 = require("./utils/VersioningStrategy");
class NestiaSdkApplication {
constructor(config) {
this.config = config;
}
all() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (!this.config.output && !((_a = this.config.swagger) === null || _a === void 0 ? void 0 : _a.output))
throw new Error([
"Error on NestiaApplication.all(): nothing to generate, configure at least one property of below:",
"",
" - INestiaConfig.output",
" - INestiaConfig.swagger.output",
" - INestiaConfig.openai.output",
].join("\n"));
print_title("Nestia All Generator");
yield this.generate({
generate: (app) => __awaiter(this, void 0, void 0, function* () {
if (this.config.output) {
yield SdkGenerator_1.SdkGenerator.generate(app);
if (this.config.e2e)
yield E2eGenerator_1.E2eGenerator.generate(app);
}
if (this.config.swagger)
yield SwaggerGenerator_1.SwaggerGenerator.generate(app);
}),
validate: this.config.output ? SdkGenerator_1.SdkGenerator.validate : undefined,
});
});
}
e2e() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.config.output)
throw new Error("Error on NestiaApplication.e2e(): configure INestiaConfig.output property.");
else if (!this.config.e2e)
throw new Error("Error on NestiaApplication.e2e(): configure INestiaConfig.e2e property.");
const validate = (title) => (location) => __awaiter(this, void 0, void 0, function* () {
const parent = path_1.default.resolve(location + "/..");
const stats = yield fs_1.default.promises.lstat(parent);
if (stats.isDirectory() === false)
throw new Error(`Error on NestiaApplication.e2e(): output directory of ${title} does not exists.`);
});
yield validate("sdk")(this.config.output);
yield validate("e2e")(this.config.e2e);
print_title("Nestia E2E Generator");
yield this.generate({
generate: (app) => __awaiter(this, void 0, void 0, function* () {
yield SdkGenerator_1.SdkGenerator.generate(app);
yield E2eGenerator_1.E2eGenerator.generate(app);
}),
});
});
}
sdk() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.config.output)
throw new Error("Error on NestiaApplication.sdk(): configure INestiaConfig.output property.");
const parent = path_1.default.resolve(this.config.output + "/..");
const stats = yield fs_1.default.promises.lstat(parent);
if (stats.isDirectory() === false)
throw new Error("Error on NestiaApplication.sdk(): output directory does not exists.");
print_title("Nestia SDK Generator");
yield this.generate({
generate: SdkGenerator_1.SdkGenerator.generate,
validate: SdkGenerator_1.SdkGenerator.validate,
});
});
}
swagger() {
return __awaiter(this, void 0, void 0, function* () {
var _a;
if (!((_a = this.config.swagger) === null || _a === void 0 ? void 0 : _a.output))
throw new Error(`Error on NestiaApplication.swagger(): configure INestiaConfig.swagger property.`);
const parsed = path_1.default.parse(this.config.swagger.output);
const directory = !!parsed.ext
? path_1.default.resolve(parsed.dir)
: this.config.swagger.output;
const stats = yield fs_1.default.promises.lstat(directory);
if (stats.isDirectory() === false)
throw new Error("Error on NestiaApplication.swagger(): output directory does not exists.");
print_title("Nestia Swagger Generator");
yield this.generate({
generate: SwaggerGenerator_1.SwaggerGenerator.generate,
});
});
}
generate(props) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d;
//----
// ANALYZE REFLECTS
//----
const unique = new WeakSet();
const project = {
config: this.config,
input: yield ConfigAnalyzer_1.ConfigAnalyzer.input(this.config),
checker: null,
errors: [],
warnings: [],
};
console.log("Analyzing reflections");
const controllers = project.input.controllers
.map((c) => ReflectControllerAnalyzer_1.ReflectControllerAnalyzer.analyze({ project, controller: c, unique }))
.filter((c) => c !== null);
if (project.warnings.length)
report({
type: "warning",
errors: project.warnings,
});
if (project.errors.length)
return report({
type: "error",
errors: project.errors,
});
const agg = (() => {
const set = new tstl_1.HashSet();
for (const controller of controllers)
for (const controllerPath of controller.paths)
for (const operation of controller.operations)
for (const operationPath of operation.paths)
set.insert(new tstl_1.Pair(`${controllerPath}/${operationPath}`, operation.protocol === "http" ? operation.method : ""));
return set.size();
})();
console.log(` - controllers: #${controllers.length}`);
console.log(` - paths: #${agg}`);
console.log(` - routes: #${controllers
.map((c) => c.paths.length *
c.operations.map((f) => f.paths.length).reduce((a, b) => a + b, 0))
.reduce((a, b) => a + b, 0)}`);
//----
// ANALYZE TYPESCRIPT CODE
//----
console.log("Analyzing source codes");
// METADATA COMPONENTS
const collection = TypedHttpRouteAnalyzer_1.TypedHttpRouteAnalyzer.dictionary(controllers);
// CONVERT TO TYPED OPERATIONS
const globalPrefix = (_b = (_a = project.input.globalPrefix) === null || _a === void 0 ? void 0 : _a.prefix) !== null && _b !== void 0 ? _b : "";
const routes = [];
for (const c of controllers)
for (const o of c.operations) {
const pathList = new Set();
const versions = VersioningStrategy_1.VersioningStrategy.merge(project)([
...((_c = c.versions) !== null && _c !== void 0 ? _c : []),
...((_d = o.versions) !== null && _d !== void 0 ? _d : []),
]);
for (const v of versions)
for (const prefix of wrapPaths(c.prefixes))
for (const cPath of wrapPaths(c.paths))
for (const filePath of wrapPaths(o.paths))
pathList.add(PathAnalyzer_1.PathAnalyzer.join(globalPrefix, v, prefix, cPath, filePath));
if (o.protocol === "http")
routes.push(...TypedHttpRouteAnalyzer_1.TypedHttpRouteAnalyzer.analyze({
controller: c,
errors: project.errors,
dictionary: collection,
operation: o,
paths: Array.from(pathList),
}));
else if (o.protocol === "websocket")
routes.push(...TypedWebSocketRouteAnalyzer_1.TypedWebSocketRouteAnalyzer.analyze({
controller: c,
operation: o,
paths: Array.from(pathList),
}));
}
AccessorAnalyzer_1.AccessorAnalyzer.analyze(routes);
if (props.validate !== undefined)
project.errors.push(...props.validate({
project,
collection,
routes,
}));
if (project.errors.length)
return report({
type: "error",
errors: project.errors,
});
yield props.generate({
project,
collection,
routes,
});
});
}
}
exports.NestiaSdkApplication = NestiaSdkApplication;
const print_title = (str) => {
console.log("-----------------------------------------------------------");
console.log(` ${str}`);
console.log("-----------------------------------------------------------");
};
const report = (props) => {
const map = new tstl_1.TreeMap();
for (const e of props.errors)
map.take(new IReflectOperationError_1.IReflectOperationError.Key(e), () => []).push(...e.contents);
console.log("");
print_title(`Nestia ${StringUtil_1.StringUtil.capitalize(props.type)} Report`);
for (const { first: { error }, second: contents, } of map) {
if (error.contents.length === 0)
continue;
const location = path_1.default.relative(process.cwd(), error.file);
const message = [
`${location} - `,
error.class,
...(error.function !== null ? [`.${error.function}()`] : [""]),
...(error.from !== null ? [` from ${error.from}`] : [""]),
":\n",
contents
.map((c) => {
if (typeof c === "string")
return ` - ${c}`;
else
return [
c.accessor
? ` - ${c.name}: `
: ` - ${c.name} (${c.accessor}): `,
...c.messages.map((msg) => ` - ${msg}`),
].join("\n");
})
.join("\n"),
].join("");
if (props.type === "error")
throw new Error(message);
else
console.log(message);
}
};
const wrapPaths = (paths) => paths.length === 0 ? [""] : paths;
//# sourceMappingURL=NestiaSdkApplication.js.map
;