abap-adt-api
Version:
Interface to Abap Developer Tools webservice
328 lines (327 loc) • 15.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.typeHierarchy = exports.prettyPrinter = exports.setPrettyPrinterSetting = exports.prettyPrinterSetting = exports.fragmentMappings = exports.classComponents = exports.usageReferenceSnippets = exports.usageReferences = exports.findDefinition = exports.codeCompletionElement = exports.codeCompletionFull = exports.codeCompletion = exports.syntaxCheck = exports.parseCheckResults = exports.syntaxCheckTypes = void 0;
const AdtException_1 = require("../AdtException");
const utilities_1 = require("../utilities");
async function syntaxCheckTypes(h) {
const response = await h.request("/sap/bc/adt/checkruns/reporters");
const raw = (0, utilities_1.fullParse)(response.body);
const reporters = (0, utilities_1.xmlArray)(raw, "chkrun:checkReporters", "chkrun:reporter").reduce((acc, cur) => {
acc.set(cur["@_chkrun:name"], (0, utilities_1.xmlArray)(cur, "chkrun:supportedType"));
return acc;
}, new Map());
return reporters;
}
exports.syntaxCheckTypes = syntaxCheckTypes;
function parseCheckResults(raw) {
const messages = [];
(0, utilities_1.xmlArray)(raw, "chkrun:checkRunReports", "chkrun:checkReport", "chkrun:checkMessageList", "chkrun:checkMessage").forEach((m) => {
const rawUri = m["@_chkrun:uri"] || "";
let message = {
uri: rawUri,
line: 0,
offset: 0,
severity: m["@_chkrun:type"],
text: m["@_chkrun:shortText"]
};
const matches = rawUri.match(/([^#]+)#start=([\d]+),([\d]+)/);
if (matches) {
const [uri, line, offset] = matches.slice(1);
message = { ...message, uri, line: (0, utilities_1.toInt)(line), offset: (0, utilities_1.toInt)(offset) };
}
messages.push(message);
});
return messages;
}
exports.parseCheckResults = parseCheckResults;
async function syntaxCheck(h, inclUrl, sourceUrl, content, mainProgram = "", version = "active") {
const source = mainProgram
? `${sourceUrl}?context=${encodeURIComponent(mainProgram)}`
: sourceUrl;
const body = `xml version="1.0" encoding="UTF-8"
<chkrun:checkObjectList xmlns:chkrun="http://www.sap.com/adt/checkrun" xmlns:adtcore="http://www.sap.com/adt/core">
<chkrun:checkObject adtcore:uri="${source}" chkrun:version="${version}">
<chkrun:artifacts>
<chkrun:artifact chkrun:contentType="text/plain; charset=utf-8" chkrun:uri="${inclUrl}">
<chkrun:content>${(0, utilities_1.btoa)(content)}</chkrun:content>
</chkrun:artifact>
</chkrun:artifacts>
</chkrun:checkObject>
</chkrun:checkObjectList>`;
const headers = {
// Accept: "application/vnd.sap.adt.checkmessages+xml",
// "Content-Type": "application/vnd.sap.adt.checkobjects+xml"
"Content-Type": "application/*"
};
const response = await h.request("/sap/bc/adt/checkruns?reporters=abapCheckRun", { method: "POST", headers, body });
const raw = (0, utilities_1.fullParse)(response.body);
return parseCheckResults(raw);
}
exports.syntaxCheck = syntaxCheck;
async function codeCompletion(h, url, body, line, offset) {
const uri = `${url}#start=${line},${offset}`;
const qs = { uri, signalCompleteness: true };
const headers = { "Content-Type": "application/*" };
const response = await h.request("/sap/bc/adt/abapsource/codecompletion/proposal", { method: "POST", qs, headers, body });
const raw = (0, utilities_1.parse)(response.body);
const proposals = (0, utilities_1.xmlArray)(raw, "asx:abap", "asx:values", "DATA", "SCC_COMPLETION")
.filter((p) => p.IDENTIFIER && p.IDENTIFIER !== "@end")
.map((p) => ({
...p,
IDENTIFIER: p.IDENTIFIER
}));
return proposals;
}
exports.codeCompletion = codeCompletion;
async function codeCompletionFull(h, url, body, line, offset, patternKey) {
const uri = `${url}#start=${line},${offset}`;
const qs = { uri, patternKey };
const headers = { "Content-Type": "application/*" };
const response = await h.request("/sap/bc/adt/abapsource/codecompletion/insertion", { method: "POST", qs, headers, body });
return response.body;
}
exports.codeCompletionFull = codeCompletionFull;
function extractDocLink(raw) {
const link = (0, utilities_1.xmlNode)(raw, "abapsource:elementInfo", "atom:link", "@_href") || "";
return link.replace(/\w+:\/\/[^\/]*/, "");
}
async function codeCompletionElement(h, url, body, line, offset) {
const qs = { uri: `${url}#start=${line},${offset}` };
const headers = { "Content-Type": "text/plain", Accept: "application/*" };
const response = await h.request("/sap/bc/adt/abapsource/codecompletion/elementinfo", { method: "POST", qs, headers, body });
const raw = (0, utilities_1.fullParse)(response.body);
if (!(0, utilities_1.xmlNode)(raw, "abapsource:elementInfo"))
return response.body;
const elinfo = (0, utilities_1.xmlNodeAttr)((0, utilities_1.xmlNode)(raw, "abapsource:elementInfo"));
const doc = (0, utilities_1.xmlNode)(raw, "abapsource:elementInfo", "abapsource:documentation", "#text") || "";
const href = extractDocLink(raw);
const components = (0, utilities_1.xmlArray)(raw, "abapsource:elementInfo", "abapsource:elementInfo").map((c) => {
return {
...(0, utilities_1.xmlNodeAttr)(c),
entries: (0, utilities_1.xmlArray)(c, "abapsource:properties", "abapsource:entry").map((e) => {
return {
value: e["#text"],
key: e["@_abapsource:key"]
};
})
};
});
return {
name: elinfo["adtcore:name"],
type: elinfo["adtcore:type"],
doc,
href,
components
};
}
exports.codeCompletionElement = codeCompletionElement;
async function findDefinition(h, url, body, line, firstof, lastof, implementation, mainProgram) {
const ctx = mainProgram ? `?context=${encodeURIComponent(mainProgram)}` : "";
const qs = {
uri: `${url}${ctx}#start=${line},${firstof};end=${line},${lastof}`,
filter: implementation ? "implementation" : "definition"
};
const headers = { "Content-Type": "text/plain", Accept: "application/*" };
const response = await h.request("/sap/bc/adt/navigation/target", {
method: "POST",
qs,
headers,
body
});
const raw = (0, utilities_1.fullParse)(response.body);
const rawLink = (0, utilities_1.xmlNode)(raw, "adtcore:objectReference", "@_adtcore:uri") || "";
const match = rawLink.match(/([^#]+)#start=(\d+),(\d+)/);
return {
url: (match && match[1]) || rawLink,
line: (0, utilities_1.toInt)(match && match[2]),
column: (0, utilities_1.toInt)(match && match[3])
};
}
exports.findDefinition = findDefinition;
async function usageReferences(h, url, line, column) {
const headers = { "Content-Type": "application/*", Accept: "application/*" };
const uri = line && column ? `${url}#start=${line},${column}` : url;
const qs = { uri };
const body = `xml version="1.0" encoding="ASCII"
<usagereferences:usageReferenceRequest xmlns:usagereferences="http://www.sap.com/adt/ris/usageReferences">
<usagereferences:affectedObjects/>
</usagereferences:usageReferenceRequest>`;
const response = await h.request("/sap/bc/adt/repository/informationsystem/usageReferences", {
method: "POST",
qs,
headers,
body
});
const raw = (0, utilities_1.fullParse)(response.body);
const rawreferences = (0, utilities_1.xmlArray)(raw, "usageReferences:usageReferenceResult", "usageReferences:referencedObjects", "usageReferences:referencedObject");
const references = rawreferences.map((r) => {
const reference = {
...(0, utilities_1.xmlNodeAttr)(r),
...(0, utilities_1.xmlNodeAttr)((0, utilities_1.xmlNode)(r, "usageReferences:adtObject") || {}),
packageRef: (0, utilities_1.xmlNodeAttr)((0, utilities_1.xmlNode)(r, "usageReferences:adtObject", "adtcore:packageRef") || {}),
objectIdentifier: r.objectIdentifier || ""
};
// older systems hide the type in the URI
if (!reference["adtcore:type"]) {
const uriParts = splitReferenceUri(reference.uri, "");
reference["adtcore:type"] = uriParts.type;
}
return reference;
});
return references;
}
exports.usageReferences = usageReferences;
function splitReferenceUri(url, matches) {
const [uri, context, hash] = (0, utilities_1.parts)(url, /([^#\?]*)(?:\?context=([^#]*))?(?:#(.*))/);
const uparts = { uri, context };
if (hash) {
hash.split(";").forEach(p => {
const [name, value] = p.split("=");
if (name === "start" || name === "end") {
const [line, column] = value.split(",");
if (line)
uparts[name] = { line: (0, utilities_1.toInt)(line), column: (0, utilities_1.toInt)(column) };
}
else if (name === "type" || name === "name")
uparts[name] = decodeURIComponent(value);
});
}
const [start, end] = (0, utilities_1.parts)(matches, /(\d+)-(\d+)/);
if (!uparts.start)
uparts.start = { line: 0, column: (0, utilities_1.toInt)(start) };
if (!uparts.start.column)
uparts.start.column = (0, utilities_1.toInt)(start);
if (!uparts.end)
uparts.end = {
line: uparts.start.line,
column: (0, utilities_1.toInt)(end) || uparts.start.column
};
return uparts;
}
async function usageReferenceSnippets(h, references) {
const headers = { "Content-Type": "application/*", Accept: "application/*" };
const refNodes = references
.filter(r => r.objectIdentifier)
.reduce((last, current) => `${last}<usagereferences:objectIdentifier optional="false">${current.objectIdentifier}</usagereferences:objectIdentifier>`, "");
const body = `xml version="1.0" encoding="UTF-8"
<usagereferences:usageSnippetRequest xmlns:usagereferences="http://www.sap.com/adt/ris/usageReferences">
<usagereferences:objectIdentifiers>
${refNodes}
</usagereferences:objectIdentifiers>
<usagereferences:affectedObjects/>
</usagereferences:usageSnippetRequest>`;
const response = await h.request("/sap/bc/adt/repository/informationsystem/usageSnippets", {
method: "POST",
headers,
body
});
const raw = (0, utilities_1.fullParse)(response.body);
const snippetReferences = (0, utilities_1.xmlArray)(raw, "usageReferences:usageSnippetResult", "usageReferences:codeSnippetObjects", "usageReferences:codeSnippetObject").map((o) => {
const snippets = (0, utilities_1.xmlArray)(o, "usageReferences:codeSnippets", "usageReferences:codeSnippet").map((s) => {
const parms = (0, utilities_1.xmlNodeAttr)(s);
const uri = splitReferenceUri(parms.uri, parms.matches);
return {
uri,
matches: parms.matches,
content: s.content,
description: s.description
};
});
return { objectIdentifier: o.objectIdentifier, snippets };
});
return snippetReferences;
}
exports.usageReferenceSnippets = usageReferenceSnippets;
const parseElement = (e) => {
const attrs = (0, utilities_1.xmlNodeAttr)(e);
const links = (0, utilities_1.xmlArray)(e, "atom:link").map(utilities_1.xmlNodeAttr);
const components = (0, utilities_1.xmlArray)(e, "abapsource:objectStructureElement").map(parseElement);
return { ...attrs, links, components };
};
async function classComponents(h, url) {
(0, AdtException_1.ValidateObjectUrl)(url);
const uri = `${url}/objectstructure`;
const qs = { version: "active", withShortDescriptions: true };
const headers = { "Content-Type": "application/*" };
const response = await h.request(uri, { qs, headers });
const raw = (0, utilities_1.fullParse)(response.body);
const header = parseElement((0, utilities_1.xmlNode)(raw, "abapsource:objectStructureElement"));
return header;
}
exports.classComponents = classComponents;
async function fragmentMappings(h, url, type, name) {
(0, AdtException_1.ValidateObjectUrl)(url);
const qs = { uri: `${url}#type=${type};name=${name}` };
const headers = { "Content-Type": "application/*" };
const response = await h.request("/sap/bc/adt/urifragmentmappings", {
qs,
headers
});
const [sourceUrl, line, column] = (0, utilities_1.parts)(response.body, /([^#]*)#start=([\d]+),([\d]+)/);
if (!column)
throw (0, AdtException_1.adtException)("Fragment not found");
const location = {
uri: sourceUrl,
line: (0, utilities_1.toInt)(line),
column: (0, utilities_1.toInt)(column)
};
return location;
}
exports.fragmentMappings = fragmentMappings;
async function prettyPrinterSetting(h) {
const response = await h.request("/sap/bc/adt/abapsource/prettyprinter/settings");
const raw = (0, utilities_1.fullParse)(response.body);
const settings = (0, utilities_1.xmlNodeAttr)(raw["abapformatter:PrettyPrinterSettings"]);
return settings;
}
exports.prettyPrinterSetting = prettyPrinterSetting;
async function setPrettyPrinterSetting(h, indent, style) {
const headers = { "Content-Type": "application/*" };
const body = `xml version="1.0" encoding="UTF-8"<prettyprintersettings:PrettyPrinterSettings
xmlns:prettyprintersettings="http://www.sap.com/adt/prettyprintersettings"
prettyprintersettings:indentation="${indent}" prettyprintersettings:style="${style}"/>`;
const response = await h.request("/sap/bc/adt/abapsource/prettyprinter/settings", { method: "PUT", headers, body });
return response.body || "";
}
exports.setPrettyPrinterSetting = setPrettyPrinterSetting;
async function prettyPrinter(h, body) {
const headers = { "Content-Type": "text/plain", Accept: "text/plain" };
const response = await h.request("/sap/bc/adt/abapsource/prettyprinter", {
method: "POST",
headers,
body
});
return (response.body || body).toString();
}
exports.prettyPrinter = prettyPrinter;
async function typeHierarchy(h, url, body, line, offset, superTypes = false) {
const qs = {
uri: `${url}#start=${line},${offset}`,
type: superTypes ? "superTypes" : "subTypes"
};
const headers = { "Content-Type": "text/plain", Accept: "application/*" };
const response = await h.request("/sap/bc/adt/abapsource/typehierarchy", {
method: "POST",
qs,
headers,
body
});
const raw = (0, utilities_1.fullParse)(response.body);
const hierarchy = (0, utilities_1.xmlArray)(raw, "hierarchy:info", "entries", "entry").map(he => {
const rawh = (0, utilities_1.xmlNodeAttr)(he);
const [uri, srcline, character] = (0, utilities_1.parts)(rawh["adtcore:uri"], /([^#]+)(?:#start=(\d+)(?:,(\d+))?)?/);
const node = {
hasDefOrImpl: rawh.hasDefOrImpl,
uri,
line: (0, utilities_1.toInt)(srcline),
character: (0, utilities_1.toInt)(character),
type: rawh["adtcore:type"] || "",
name: rawh["adtcore:name"] || "",
parentUri: rawh["adtcore:parentUri"] || "",
description: rawh["adtcore:description"] || ""
};
return node;
});
return hierarchy;
}
exports.typeHierarchy = typeHierarchy;