UNPKG

@inversify-cn/swagger-express-ts

Version:

Generate and serve swagger.json

289 lines (287 loc) 14.6 kB
"use strict"; 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 __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; Object.defineProperty(exports, "__esModule", { value: true }); exports.interfacePropertyToModelProperty = exports.getPropertyType = exports.parseProperty = exports.sanitize = exports.generateModels = exports.generateModelsOnlyOnce = exports.addModel = void 0; var swagger_service_1 = require("./swagger.service"); var fs = require('fs'); var exec = require('await-exec'); var _ = require('lodash'); var modelNames = []; var modelNamesGenerated = []; var models = swagger_service_1.SwaggerService.getInstance().getData().definitions; function addModel(args) { var successfulResponseModelName = args && args.responses && args.responses[200] && args.responses[200].model; var bodyModelName = args && args.parameters && args.parameters.body && args.parameters.body.model; if (successfulResponseModelName) { modelNames.push(successfulResponseModelName); } if (bodyModelName) { modelNames.push(bodyModelName); } } exports.addModel = addModel; exports.generateModelsOnlyOnce = _.memoize(generateModels); function generateModels(interfaceScanPaths) { return __awaiter(this, void 0, void 0, function () { var modelNamesToGenerate, promises; return __generator(this, function (_a) { switch (_a.label) { case 0: modelNamesToGenerate = modelNames.filter(function (elem, index, self) { return index === self.indexOf(elem); }); promises = modelNamesToGenerate.map(function (name) { return generateModelWithChildModels(name, interfaceScanPaths); }); return [4 /*yield*/, Promise.all(promises)]; case 1: _a.sent(); swagger_service_1.SwaggerService.getInstance().setDefinitions(models); return [2 /*return*/]; } }); }); } exports.generateModels = generateModels; function generateModelWithChildModels(modelName, interfaceScanPaths) { return __awaiter(this, void 0, void 0, function () { var interfaceProperties; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, getInterfaceProperties(modelName, interfaceScanPaths)]; case 1: interfaceProperties = _a.sent(); return [4 /*yield*/, interfaceToModel(modelName, interfaceProperties, interfaceScanPaths)]; case 2: _a.sent(); return [2 /*return*/]; } }); }); } function getInterfaceProperties(interfaceName, interfaceScanPaths) { return __awaiter(this, void 0, void 0, function () { var path; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, findFileInterfaceOnlyOnce(interfaceName, interfaceScanPaths)]; case 1: path = _a.sent(); return [2 /*return*/, path ? getPropertiesFromFileOnlyOnce(path, interfaceName, interfaceScanPaths) : []]; } }); }); } var findFileInterfaceOnlyOnce = _.memoize(findFileInterface); function findFileInterface(interfaceName, interfaceScanPaths) { return __awaiter(this, void 0, void 0, function () { var _i, interfaceScanPaths_1, path, grep, grepResponse, output, file, err_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _i = 0, interfaceScanPaths_1 = interfaceScanPaths; _a.label = 1; case 1: if (!(_i < interfaceScanPaths_1.length)) return [3 /*break*/, 6]; path = interfaceScanPaths_1[_i]; grep = "grep -r \"export interface " + interfaceName + " \" " + path; if (!fs.existsSync(path)) return [3 /*break*/, 5]; _a.label = 2; case 2: _a.trys.push([2, 4, , 5]); return [4 /*yield*/, exec(grep)]; case 3: grepResponse = _a.sent(); output = grepResponse.stdout; if (!output) { return [3 /*break*/, 5]; } file = output.split(':')[0]; if (file) { return [2 /*return*/, file]; } return [3 /*break*/, 5]; case 4: err_1 = _a.sent(); // console.warn(err); // console.log('GREP FAILED: ', interfaceName, path); return [3 /*break*/, 5]; case 5: _i++; return [3 /*break*/, 1]; case 6: return [2 /*return*/, undefined]; } }); }); } var getPropertiesFromFileOnlyOnce = _.memoize(getPropertiesFromFile, function (path, interfaceName) { return path + "|" + interfaceName; }); function getPropertiesFromFile(path, interfaceName, interfaceScanPaths) { return __awaiter(this, void 0, void 0, function () { var replace, regex, file, interfaceObj, interfaceProperties, header, extendsOtherInterface, parentInterface, parentProperties; return __generator(this, function (_a) { switch (_a.label) { case 0: replace = "export interface " + interfaceName + " [^]*}"; regex = new RegExp(replace, 'g'); file = fs.readFileSync(path, 'utf8'); interfaceObj = file.match(regex)[0].split('}')[0]; interfaceProperties = interfaceObj.split('\n'); header = interfaceProperties.shift(); interfaceProperties = interfaceProperties.map(function (property) { return property.replace('\t', ''); }); interfaceProperties = interfaceProperties.filter(function (property) { return property; }); extendsOtherInterface = header.includes('extends'); if (!extendsOtherInterface) return [3 /*break*/, 2]; parentInterface = header.split('extends')[1].split('{')[0].trim(); return [4 /*yield*/, getInterfaceProperties(parentInterface, interfaceScanPaths)]; case 1: parentProperties = _a.sent(); interfaceProperties = interfaceProperties.concat(parentProperties); _a.label = 2; case 2: return [2 /*return*/, interfaceProperties]; } }); }); } function interfaceToModel(interfaceName, interfaceProperties, interfaceScanPaths) { return __awaiter(this, void 0, void 0, function () { var _i, interfaceProperties_1, property; return __generator(this, function (_a) { switch (_a.label) { case 0: models[interfaceName] = { properties: {}, type: '' }; _i = 0, interfaceProperties_1 = interfaceProperties; _a.label = 1; case 1: if (!(_i < interfaceProperties_1.length)) return [3 /*break*/, 4]; property = interfaceProperties_1[_i]; return [4 /*yield*/, interfacePropertyToModelProperty(interfaceName, property, interfaceScanPaths)]; case 2: _a.sent(); _a.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); } function sanitize(interfaceProperty) { return interfaceProperty.replace(';', '').split('//')[0].trim().replace(/^\[/, '').replace(/:\s*\w+\s*]\s*:/, ':'); } exports.sanitize = sanitize; function parseProperty(interfaceProperty) { var split = interfaceProperty.split(':'); var lhs = split[0]; var rhs = split[1].trim(); return [lhs, rhs]; } exports.parseProperty = parseProperty; function getPropertyType(propertyRightSide) { var arrayRemoved = propertyRightSide.replace('[]', '').replace('Array<', '').replace('>', ''); var firstType = arrayRemoved.split('| undefined')[0]; return firstType.trim(); } exports.getPropertyType = getPropertyType; function interfacePropertyToModelProperty(interfaceName, interfaceProperty, interfaceScanPaths) { return __awaiter(this, void 0, void 0, function () { var _a, propertyLeftSide, propertyRightSide, propertyName, isOptional, propertyType, isArray, isIndexedObject, isAny, model, isPrimitive, properties, e_1; return __generator(this, function (_b) { switch (_b.label) { case 0: _b.trys.push([0, 6, , 7]); interfaceProperty = sanitize(interfaceProperty); _a = parseProperty(interfaceProperty), propertyLeftSide = _a[0], propertyRightSide = _a[1]; propertyName = propertyLeftSide.replace('?', ''); isOptional = propertyLeftSide.indexOf('?') >= 0 || propertyRightSide.indexOf('| undefined') >= 0; propertyType = getPropertyType(propertyRightSide); isArray = propertyRightSide.indexOf('[]') >= 0 || propertyRightSide.indexOf('Array<') >= 0; isIndexedObject = propertyLeftSide.indexOf('[') >= 0; isAny = propertyType.toLowerCase().indexOf('any') >= 0 || propertyType.toLowerCase().indexOf('{') >= 0; model = { description: propertyName, required: !isOptional, type: propertyType, }; isPrimitive = isPropertyPrimitive(model); if (!(!isPrimitive && !isIndexedObject && !isAny)) return [3 /*break*/, 4]; if (!!models[model.type]) return [3 /*break*/, 3]; if (!(modelNamesGenerated.indexOf(model.type) === -1)) return [3 /*break*/, 3]; modelNamesGenerated.push(model.type); return [4 /*yield*/, getInterfaceProperties(model.type, interfaceScanPaths)]; case 1: properties = _b.sent(); return [4 /*yield*/, interfaceToModel(model.type, properties, interfaceScanPaths)]; case 2: _b.sent(); _b.label = 3; case 3: model.model = model.type; model.type = 'object'; return [3 /*break*/, 5]; case 4: if (model.type === 'Date') { model.type = 'string'; model.format = 'date'; } _b.label = 5; case 5: if (isArray) { model.itemType = isAny ? 'object' : model.type; model.type = 'array'; } if (isAny) { model.type = 'object'; } if (isIndexedObject) { models[interfaceName].type = 'object'; } else if (models[interfaceName] && models[interfaceName].properties) { models[interfaceName].properties[model.description] = model; } return [2 /*return*/, model]; case 6: e_1 = _b.sent(); return [3 /*break*/, 7]; case 7: return [2 /*return*/]; } }); }); } exports.interfacePropertyToModelProperty = interfacePropertyToModelProperty; function isPropertyPrimitive(modelPropery) { var primitives = ['string', 'integer', 'number', 'boolean', 'Date']; return primitives.includes(modelPropery.type); } //# sourceMappingURL=model-generator.js.map