UNPKG

abap-adt-api

Version:

Interface to Abap Developer Tools webservice

328 lines (327 loc) 15.6 kB
"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;