remote-abap-compiler
Version:
Remote ABAP compilation
158 lines (156 loc) • 6.58 kB
JavaScript
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
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) : new P(function (resolve) { resolve(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 abap_adt_api_1 = require("abap-adt-api");
const randomstring_1 = __importDefault(require("randomstring"));
class CompilationRequest {
constructor(url, user, client, password) {
this.url = url;
this.user = user;
this.client = client;
this.password = password;
this.adtClient = new abap_adt_api_1.ADTClient(url, user, password, client, "EN", { rejectUnauthorized: false });
this.className = "RAC_" + randomstring_1.default.generate({
capitalization: "uppercase",
charset: "alphanumeric",
length: 26,
});
this.classUrl = "/sap/bc/adt/oo/classes/" + this.className.toLowerCase();
}
compile(code) {
return __awaiter(this, void 0, void 0, function* () {
yield this.cleanup(true);
let mappedResult;
try {
yield this.createClass();
const result = yield this.putClassSource(this.getGlobalClassSource(), code);
mappedResult = this.mapToCompilationResult(result);
if (mappedResult.success) {
mappedResult.output = yield this.runClass();
}
}
finally {
yield this.cleanup();
}
return mappedResult;
});
}
cleanup(ignoreError = false) {
return __awaiter(this, void 0, void 0, function* () {
try {
this.adtClient.stateful = abap_adt_api_1.session_types.stateful;
const lock = yield this.adtClient.lock(this.classUrl);
yield this.adtClient.deleteObject(this.classUrl, lock.LOCK_HANDLE);
yield this.adtClient.dropSession();
}
catch (error) {
if (!ignoreError) {
throw error;
}
}
});
}
createClass() {
return __awaiter(this, void 0, void 0, function* () {
yield this.adtClient.statelessClone.createObject("CLAS/OC", this.className, "$TMP", "remote ABAP compiler", "/sap/bc/adt/packages/$TMP");
});
}
getGlobalClassSource() {
const source = `class ${this.className} definition public create public final.
public section.
interfaces if_oo_adt_classrun.
endclass.
class ${this.className} implementation.
method if_oo_adt_classrun~main.
new main( )->run( out ).
endmethod.
endclass.`;
return source;
}
putClassSource(globalClass, localTypes) {
return __awaiter(this, void 0, void 0, function* () {
this.adtClient.stateful = abap_adt_api_1.session_types.stateful;
const lock = yield this.adtClient.lock(this.classUrl);
yield this.adtClient.setObjectSource(this.classUrl + "/source/main", globalClass, lock.LOCK_HANDLE);
yield this.adtClient.setObjectSource(this.classUrl + "/includes/implementations", localTypes, lock.LOCK_HANDLE);
yield this.adtClient.dropSession();
const result = yield this.adtClient.activate(this.className, this.classUrl);
return result;
});
}
mapToCompilationResult(activationResult) {
if (!activationResult.success && activationResult.messages.length > 0) {
return {
className: this.className,
errors: activationResult.messages.map(this.mapErrorMessages.bind(this)),
success: activationResult.success,
};
}
return {
className: this.className,
success: activationResult.success,
};
}
mapErrorMessages(message) {
const mainMethodErrorTag = `Class ${this.className}, Method IF_OO_ADT_CLASSRUN~MAIN`;
if (message.objDescr === mainMethodErrorTag) {
return this.mapErrorFromGlobalClass(message);
}
else {
return this.mapErrorFromLocalTypesInclude(message);
}
}
mapErrorFromLocalTypesInclude(message) {
const search = /#start=(\d+),(\d+)/g;
const match = search.exec(message.href);
if (match !== null) {
return {
errorMessage: message.shortText,
line: parseInt(match[1], 10),
offset: parseInt(match[2], 10),
};
}
else {
return {
errorMessage: message.shortText,
line: -1,
offset: -1,
};
}
}
mapErrorFromGlobalClass(message) {
if (message.shortText === "Type \"MAIN\" is unknown." ||
message.shortText === "Method \"RUN\" is unknown or PROTECTED or PRIVATE.") {
return {
errorMessage: "Missing class named \"MAIN\" with public method \"RUN\".",
line: -1,
offset: -1,
};
}
else {
const defaultErrorMessage = "The method \"RUN\" of class \"MAIN\" " +
"must have exactly one importing parameter of type \"REF TO IF_OO_ADT_CLASSRUN_OUT\".";
return {
errorMessage: defaultErrorMessage,
line: -1,
offset: -1,
};
}
}
runClass() {
return __awaiter(this, void 0, void 0, function* () {
return this.adtClient.runClass(this.className);
});
}
}
exports.CompilationRequest = CompilationRequest;