UNPKG

navidev-adt-api

Version:

API de conexión al Abap Developer Tools

339 lines (337 loc) 16.7 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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const packageConstants_1 = require("./packageConstants"); const xmlParser_1 = __importDefault(require("../shared/utilities/parser/xmlParser")); const Result_1 = require("../shared/core/Result"); const repositoryConstants_1 = require("../adtRepository/repositoryConstants"); const adtExceptionController_1 = __importDefault(require("../shared/exceptions/adtExceptionController")); const formatters_1 = __importDefault(require("../shared/utilities/general/formatters")); class PackageApp { constructor(connectionController, AdtRepository) { this.adtExceptionController = new adtExceptionController_1.default(); this.connectionController = connectionController; this.AdtRepository = AdtRepository; this.levelPackages = 0; } /** * Devuelve los paquetes de desarrollo del sistema * @returns Result con la lista de valores o Errores */ readAllPackages() { return __awaiter(this, void 0, void 0, function* () { const response = yield this.connectionController.request(packageConstants_1.PACKAGE_URL.CONTENT, { method: "POST", qs: { parent_type: repositoryConstants_1.REPOSITORY_TYPES.PACKAGE, withShortDescriptions: true, }, }); if (response.isSuccess) { let httpResponse = response.getValue(); let bodyParsed = xmlParser_1.default.fullParse(httpResponse.body); let packages = bodyParsed["asx:abap"]["asx:values"]["DATA"]["TREE_CONTENT"]["SEU_ADT_REPOSITORY_OBJ_NODE"].map((row) => { return { type: row.OBJECT_TYPE, name: row.OBJECT_NAME, techName: row.TECH_NAME, url: row.OBJECT_URI, }; }); return Result_1.Result.ok(packages); } else { return Result_1.Result.fail(response.getErrorValue()); } }); } /** * Lectura del contenido completo de un paquete o clase de desarrollo, eso incluye, * los paquetes hijos y sus objetos. * @param packageName Nombre del paquete * @returns Resultado con los objetos y subpaquetes */ readFullPackagesContent(packageName) { return __awaiter(this, void 0, void 0, function* () { try { if (!this.packageInfoObjectType) yield this.getInfoPackageObjectType(); return this.readPackageContent(packageName); } catch (error) { return Result_1.Result.fail(this.adtExceptionController.fromException(error)); } }); } readFullPackagesContentFlat(packageName) { return __awaiter(this, void 0, void 0, function* () { let responseFullContent = yield this.readFullPackagesContent(packageName); if (responseFullContent.isSuccess) { let flatContent = []; let fullContent = responseFullContent.getValue(); this.levelPackages = 1; flatContent.push({ level: this.levelPackages, objectType: fullContent.objectType, objectTypeDesc: fullContent.objectTypeDesc, objectName: fullContent.objectName, objectNameParent: "", techName: fullContent.techName, categories: fullContent.categories, }); if (fullContent.subpackages.length > 0) flatContent = flatContent.concat(this.convertSubPackages2FlatTable(fullContent.subpackages, fullContent.objectName)); return Result_1.Result.ok(flatContent); } else { return Result_1.Result.fail(responseFullContent.getErrorValue()); } }); } /** * Recupera el contenido de un paquete. Hace recursividad para * ir obteniendo sus subpaquetes * @param packageName Nombre del paquete * @returns Result con el contenido del paquete */ readPackageContent(packageName) { return __awaiter(this, void 0, void 0, function* () { var _a; // Creamos el registro base del paquete let tmpPackageContent = { objectName: packageName, objectType: this.packageInfoObjectType.internalType, categories: [], objectTypeDesc: this.packageInfoObjectType.nameDesc, techName: packageName, subpackages: [], }; const response = yield this.connectionController.request(packageConstants_1.PACKAGE_URL.CONTENT, { method: "POST", qs: { parent_type: (_a = this.packageInfoObjectType) === null || _a === void 0 ? void 0 : _a.internalType, parent_tech_name: packageName, parent_name: packageName, withShortDescriptions: true, }, body: packageConstants_1.BODY.PACKAGE_ROOT, }); if (response.isSuccess) { let httpResponse = response.getValue(); // La primera parte es sacar los objetos asociados al paquete if (httpResponse.body.length == 0) return Result_1.Result.fail(this.adtExceptionController.fromText(`Package ${packageName} not exist`, 400)); // Sacamos los objetos del paquete. let responseObjects = yield this.readPackageObjects(packageName, httpResponse.body); // si ha ido bien se añaden los objetos con este nivel:categoria->tipo objeto->objeto if (responseObjects.isSuccess) tmpPackageContent.categories = responseObjects.getValue(); // La segunda parte es extraer los nodos y recorrerlos llamando al let subPackages = this.extractSubPackages(httpResponse.body); for (let x = 0; x < subPackages.length; x++) { let responseSubPackage = yield this.readPackageContent(subPackages[x]); if (responseSubPackage.isSuccess) { tmpPackageContent.subpackages.push(responseSubPackage.getValue()); } } return Result_1.Result.ok(tmpPackageContent); } else { return Result_1.Result.fail(response.getErrorValue()); } }); } /** * Obtiene la información interna asociada al paquete */ getInfoPackageObjectType() { return __awaiter(this, void 0, void 0, function* () { // Buscamo la info del tipo de objeto del paquete let response = yield this.AdtRepository.getObjectTypeFromObjectName(repositoryConstants_1.REPOSITORY_TYPES.PACKAGE); if (response.isSuccess) { this.packageInfoObjectType = response.getValue(); // Ahora buscamo del tipo interno asociado al paquete let responseType = yield this.AdtRepository.getTypeFromObjectType(this.packageInfoObjectType.internalType); if (response.isSuccess) this.packageInfoType = responseType.getValue(); else throw response.getErrorValue(); } else throw response.getErrorValue(); }); } /** * Lectura de los objetos asociados a los ID de nodos * @param packageName Nombre paquete * @param categoriesNodeIDs Array con los ID de nodos * @returns Resultado */ readPackageObjects(packageName, packageBody) { return __awaiter(this, void 0, void 0, function* () { var _a; // Sacamos una estructura que contiene las categorias->tipos objeto->objetos, y los tipos de objeto y sus ID de nodo // para buscar los objetos asociados. let categoriesNodeIDs = this.extractCategoriesNodeIDs(packageBody); if (categoriesNodeIDs.objectTypes.length == 0) return Result_1.Result.ok([]); // Body para poder recuperar los objetos a asociados a los ID de nodo por tipo de objeto let body = `<?xml version="1.0" encoding="UTF-8"?><asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0"><asx:values><DATA>`; categoriesNodeIDs.objectTypes.forEach((row) => { body += `<TV_NODEKEY>${row.nodeID}</TV_NODEKEY>`; }); body += `</DATA></asx:values></asx:abap>`; const response = yield this.connectionController.request(packageConstants_1.PACKAGE_URL.CONTENT, { method: "POST", qs: { parent_type: (_a = this.packageInfoObjectType) === null || _a === void 0 ? void 0 : _a.internalType, parent_tech_name: packageName, parent_name: packageName, withShortDescriptions: true, }, headers: { "Content-Type": "application/vnd.sap.as+xml; charset=UTF-8", }, body: body, }); if (response.isSuccess) { let httpResponse = response.getValue(); // Se extraen los objetos y su jeraquia:categoria->tipo->objeto y se devuelve al proceso. return Result_1.Result.ok(this.extractObjects(httpResponse.body, categoriesNodeIDs)); } else { return Result_1.Result.fail(response.getErrorValue()); } }); } /** * Extrae los subpaquetes del cuerpo de la llamada del paquete principal * @param bodyPackage String con los datos del paquete principal * @returns Array con los subpaquetes */ extractSubPackages(bodyPackage) { let bodyParsed = xmlParser_1.default.fullParse(bodyPackage); // Cuando solo hay un paquete se devuelve un objeto, si hay más de uno es un array. Y si no hay datos // no hay nada. Porque se llama a una utilidad para que se siempre devuelva un array. let treeContent = xmlParser_1.default.nodeArray(bodyParsed["asx:abap"]["asx:values"].DATA.TREE_CONTENT .SEU_ADT_REPOSITORY_OBJ_NODE); return treeContent .filter((row) => { var _a; return row.OBJECT_TYPE == ((_a = this.packageInfoType) === null || _a === void 0 ? void 0 : _a.type); }) .map((row) => { return row.OBJECT_NAME; }); } /** * Extrae las categorias y los ID de los nodos para buscarlos. * @param bodyParsed | Cuerpo de la llamada * @returns Categorias y sus nodos */ extractCategoriesNodeIDs(body) { let returnData = { categories: [], objectTypes: [], }; if (body.length == 0) return returnData; let bodyParsed = xmlParser_1.default.fullParse(body); let xmlCategories = xmlParser_1.default.nodeArray(bodyParsed["asx:abap"]["asx:values"].DATA.CATEGORIES .SEU_ADT_OBJECT_CATEGORY_INFO); let xmlObjectTypes = xmlParser_1.default.nodeArray(bodyParsed["asx:abap"]["asx:values"].DATA.OBJECT_TYPES .SEU_ADT_OBJECT_TYPE_INFO); // Vamos a recorrer primero las categorias,SEU_ADT_OBJECT_CATEGORY_INFO, excluyendo los paquetes. Porque los paquetes // Ya vienen en el nodo SEU_ADT_REPOSITORY_OBJ_NODE y estos los procesaré una vez procesado los objetos // En el nodo SEU_ADT_REPOSITORY_OBJ_NODE tenemos los tipos de código y su ID de nodo para poderlos buscar el paso siguiente xmlCategories .filter((row) => { var _a; return row.CATEGORY != ((_a = this.packageInfoType) === null || _a === void 0 ? void 0 : _a.category); }) .forEach((rowCategory) => { returnData.categories.push({ category: rowCategory.CATEGORY, categoryDesc: rowCategory.CATEGORY_LABEL, objectTypes: [], }); // Ahora sacamos los id de los nodos de la categoria que sea esta procesando xmlObjectTypes .filter((row) => row.CATEGORY_TAG == rowCategory.CATEGORY) .forEach((rowObjectTypes) => returnData.objectTypes.push({ nodeID: formatters_1.default.paddingLeftZerosNumber(rowObjectTypes.NODE_ID, 6), objectType: rowObjectTypes.OBJECT_TYPE, objectTypeDesc: rowObjectTypes.OBJECT_TYPE_LABEL, categoryTag: rowObjectTypes.CATEGORY_TAG, })); }); return returnData; } extractObjects(body, categoriesNodeIDs) { let bodyParsed = xmlParser_1.default.fullParse(body); let returnData = categoriesNodeIDs.categories; let xmlTreeContent = xmlParser_1.default.nodeArray(bodyParsed["asx:abap"]["asx:values"].DATA.TREE_CONTENT .SEU_ADT_REPOSITORY_OBJ_NODE); // Se recorre cada categoria:codigo fuente, diccionario, etc.. returnData.forEach((rowCategory) => { // De cada categoria recorremos los tipos de objetos asociados categoriesNodeIDs.objectTypes .filter((row) => row.categoryTag == rowCategory.category) .forEach((rowObjectTypeCategory) => { // Se rellena la estructura donde se pondrá por cada tipo de objeto sus objetos let objectTypesObjects = { objectType: rowObjectTypeCategory.objectType, objectTypeDesc: rowObjectTypeCategory.objectTypeDesc, objects: [], }; // De cada tipo de objeto recorremos los objetos obtenidos en el servicio que tengan dicho tipo de objeto y se // va añadiendo a los objetos. xmlTreeContent .filter((row) => row.OBJECT_TYPE == rowObjectTypeCategory.objectType) .forEach((rowTreeContent) => { objectTypesObjects.objects.push({ objectName: rowTreeContent.OBJECT_NAME, techName: rowTreeContent.TECH_NAME, objectUri: rowTreeContent.OBJECT_URI, }); }); rowCategory.objectTypes.push(objectTypesObjects); }); }); return returnData; } /** * Convierte los subpaquetes a una tabla plana mediante recursividad * @param subPackages Array con los subpaquetes * @param packageNameParent Nombre del paquete padre * @returns Array con los paquetes en formato plano */ convertSubPackages2FlatTable(subPackages, packageNameParent) { if (subPackages.length == 0) return []; let flatContent = []; subPackages.forEach((subPackage) => { this.levelPackages++; flatContent.push({ level: this.levelPackages, objectType: subPackage.objectType, objectTypeDesc: subPackage.objectTypeDesc, objectName: subPackage.objectName, objectNameParent: packageNameParent, techName: subPackage.techName, categories: subPackage.categories, }); if (subPackage.subpackages.length > 0) flatContent = flatContent.concat(this.convertSubPackages2FlatTable(subPackage.subpackages, subPackage.objectName)); }); return flatContent; } } exports.default = PackageApp;