navidev-adt-api
Version:
API de conexión al Abap Developer Tools
339 lines (337 loc) • 16.7 kB
JavaScript
"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;