@linkup-ai/abap-ai 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/README.md +384 -0
  2. package/dist/adt-client.js +364 -0
  3. package/dist/cli/activate.js +113 -0
  4. package/dist/cli/init.js +333 -0
  5. package/dist/cli/remove.js +80 -0
  6. package/dist/cli/status.js +229 -0
  7. package/dist/cli/systems.js +68 -0
  8. package/dist/cli.js +81 -0
  9. package/dist/index.js +1318 -0
  10. package/dist/knowledge/abap/abap-dictionary.md +199 -0
  11. package/dist/knowledge/abap/abap-sql.md +296 -0
  12. package/dist/knowledge/abap/amdp.md +273 -0
  13. package/dist/knowledge/abap/clean-code.md +293 -0
  14. package/dist/knowledge/abap/cloud-background-processing.md +250 -0
  15. package/dist/knowledge/abap/cloud-communication.md +265 -0
  16. package/dist/knowledge/abap/cloud-development.md +176 -0
  17. package/dist/knowledge/abap/cloud-extensibility.md +252 -0
  18. package/dist/knowledge/abap/cloud-released-apis.md +261 -0
  19. package/dist/knowledge/abap/constructor-expressions.md +289 -0
  20. package/dist/knowledge/abap/enhancements.md +232 -0
  21. package/dist/knowledge/abap/exceptions.md +271 -0
  22. package/dist/knowledge/abap/internal-tables.md +205 -0
  23. package/dist/knowledge/abap/object-orientation.md +298 -0
  24. package/dist/knowledge/abap/performance.md +216 -0
  25. package/dist/knowledge/abap/rap-abstract-entities.md +206 -0
  26. package/dist/knowledge/abap/rap-business-events.md +216 -0
  27. package/dist/knowledge/abap/rap-draft.md +191 -0
  28. package/dist/knowledge/abap/rap-eml.md +453 -0
  29. package/dist/knowledge/abap/rap-end-to-end.md +486 -0
  30. package/dist/knowledge/abap/rap-feature-control.md +185 -0
  31. package/dist/knowledge/abap/rap-numbering.md +280 -0
  32. package/dist/knowledge/abap/rap-service-exposure.md +163 -0
  33. package/dist/knowledge/abap/rap-unmanaged.md +468 -0
  34. package/dist/knowledge/abap/string-processing.md +180 -0
  35. package/dist/knowledge/abap/unit-testing.md +303 -0
  36. package/dist/knowledge/abap-cds/access-control.md +241 -0
  37. package/dist/knowledge/abap-cds/annotations.md +331 -0
  38. package/dist/knowledge/abap-cds/associations.md +254 -0
  39. package/dist/knowledge/abap-cds/expressions.md +230 -0
  40. package/dist/knowledge/abap-cds/functions.md +245 -0
  41. package/dist/knowledge/abap-cds/metadata-extensions.md +294 -0
  42. package/dist/knowledge/cap/authentication.md +278 -0
  43. package/dist/knowledge/cap/cdl-syntax.md +247 -0
  44. package/dist/knowledge/cap/cql-queries.md +266 -0
  45. package/dist/knowledge/cap/deployment.md +343 -0
  46. package/dist/knowledge/cap/event-handlers.md +287 -0
  47. package/dist/knowledge/cap/fiori-integration.md +303 -0
  48. package/dist/knowledge/cap/service-definitions.md +287 -0
  49. package/dist/knowledge/fiori/annotations.md +347 -0
  50. package/dist/knowledge/fiori/deployment.md +340 -0
  51. package/dist/knowledge/fiori/fiori-elements.md +332 -0
  52. package/dist/knowledge/fiori/fiori-side-effects.md +107 -0
  53. package/dist/knowledge/fiori/fiori-valuelist.md +144 -0
  54. package/dist/knowledge/fiori/ui5-controllers.md +358 -0
  55. package/dist/knowledge/fiori/ui5-data-binding.md +311 -0
  56. package/dist/knowledge/fiori/ui5-fragments-dialogs.md +330 -0
  57. package/dist/knowledge/fiori/ui5-manifest.md +411 -0
  58. package/dist/knowledge/fiori/ui5-routing.md +303 -0
  59. package/dist/knowledge/fiori/ui5-xml-views.md +294 -0
  60. package/dist/logger.js +114 -0
  61. package/dist/system-profile.js +207 -0
  62. package/dist/tools/abap-doc.js +72 -0
  63. package/dist/tools/abapgit.js +161 -0
  64. package/dist/tools/activate.js +68 -0
  65. package/dist/tools/atc-check.js +117 -0
  66. package/dist/tools/auth-object.js +56 -0
  67. package/dist/tools/breakpoints.js +76 -0
  68. package/dist/tools/call-hierarchy.js +84 -0
  69. package/dist/tools/cds-annotations.js +98 -0
  70. package/dist/tools/cds-dependencies.js +65 -0
  71. package/dist/tools/check.js +47 -0
  72. package/dist/tools/code-completion.js +70 -0
  73. package/dist/tools/code-coverage.js +111 -0
  74. package/dist/tools/create-amdp.js +111 -0
  75. package/dist/tools/create-dcl.js +81 -0
  76. package/dist/tools/create-transport.js +38 -0
  77. package/dist/tools/create.js +285 -0
  78. package/dist/tools/data-preview.js +37 -0
  79. package/dist/tools/delete.js +45 -0
  80. package/dist/tools/deploy-bsp.js +298 -0
  81. package/dist/tools/discovery.js +59 -0
  82. package/dist/tools/element-info.js +93 -0
  83. package/dist/tools/enhancements.js +186 -0
  84. package/dist/tools/extract-method.js +44 -0
  85. package/dist/tools/function-group.js +59 -0
  86. package/dist/tools/knowledge.js +275 -0
  87. package/dist/tools/lock-object.js +75 -0
  88. package/dist/tools/message-class.js +67 -0
  89. package/dist/tools/navigate.js +80 -0
  90. package/dist/tools/number-range.js +57 -0
  91. package/dist/tools/object-documentation.js +43 -0
  92. package/dist/tools/object-structure.js +78 -0
  93. package/dist/tools/object-versions.js +57 -0
  94. package/dist/tools/package-contents.js +60 -0
  95. package/dist/tools/pretty-printer.js +35 -0
  96. package/dist/tools/publish-binding.js +49 -0
  97. package/dist/tools/quick-fix.js +69 -0
  98. package/dist/tools/read.js +167 -0
  99. package/dist/tools/refactor-rename.js +60 -0
  100. package/dist/tools/release-transport.js +24 -0
  101. package/dist/tools/released-apis.js +51 -0
  102. package/dist/tools/repository-tree.js +90 -0
  103. package/dist/tools/scaffold-rap.js +642 -0
  104. package/dist/tools/search.js +73 -0
  105. package/dist/tools/shared/data-format.js +101 -0
  106. package/dist/tools/sql-console.js +17 -0
  107. package/dist/tools/system-info.js +270 -0
  108. package/dist/tools/traces.js +66 -0
  109. package/dist/tools/transport-contents.js +83 -0
  110. package/dist/tools/transports.js +67 -0
  111. package/dist/tools/unit-test.js +135 -0
  112. package/dist/tools/where-used.js +59 -0
  113. package/dist/tools/write.js +101 -0
  114. package/package.json +49 -0
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapObjectVersions = abapObjectVersions;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function parseVersions(xml) {
6
+ const versions = [];
7
+ // Formato ADT: <version ... version="X" date="Y" author="Z" description="W" />
8
+ const versionRegex = /<(?:[a-zA-Z0-9_:]*)?version[^>]*>/gi;
9
+ let match;
10
+ while ((match = versionRegex.exec(xml)) !== null) {
11
+ const element = match[0];
12
+ const verMatch = element.match(/(?:version(?:Number)?)\s*=\s*"([^"]*)"/i);
13
+ const dateMatch = element.match(/(?:date|modifiedAt|changedAt)\s*=\s*"([^"]*)"/i);
14
+ const authorMatch = element.match(/(?:author|modifiedBy|changedBy)\s*=\s*"([^"]*)"/i);
15
+ const descMatch = element.match(/(?:description|title)\s*=\s*"([^"]*)"/i);
16
+ if (verMatch || dateMatch) {
17
+ versions.push({
18
+ version: verMatch?.[1] ?? "",
19
+ date: dateMatch?.[1] ?? "",
20
+ author: authorMatch?.[1] ?? "",
21
+ description: descMatch?.[1] ?? "",
22
+ });
23
+ }
24
+ }
25
+ return versions;
26
+ }
27
+ function formatVersions(objectName, versions) {
28
+ if (versions.length === 0) {
29
+ return `${objectName}: nenhuma versão encontrada.`;
30
+ }
31
+ const lines = [
32
+ `Versões de ${objectName} (${versions.length})`,
33
+ "─".repeat(70),
34
+ `${"Versão".padEnd(10)} ${"Data".padEnd(22)} ${"Autor".padEnd(15)} Descrição`,
35
+ "─".repeat(70),
36
+ ];
37
+ for (const v of versions) {
38
+ lines.push(`${v.version.padEnd(10)} ${v.date.padEnd(22)} ${v.author.padEnd(15)} ${v.description}`);
39
+ }
40
+ return lines.join("\n");
41
+ }
42
+ async function abapObjectVersions(input) {
43
+ const { object_type, object_name } = input;
44
+ const name = object_name.toUpperCase();
45
+ const adtPath = (0, adt_client_js_1.resolveAdtPath)(object_type);
46
+ await (0, adt_client_js_1.ensureSession)();
47
+ const response = await adt_client_js_1.http.get(`/${adtPath}/${name.toLowerCase()}/source/main/versions`, {
48
+ headers: { Accept: "application/atom+xml;type=feed" },
49
+ responseType: "text",
50
+ validateStatus: (status) => status < 500,
51
+ });
52
+ if (response.status >= 400) {
53
+ throw new Error(`Versões não disponíveis para ${name} (${object_type}).`);
54
+ }
55
+ const versions = parseVersions(response.data);
56
+ return formatVersions(name, versions);
57
+ }
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapPackageContents = abapPackageContents;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function parsePackageContents(xml) {
6
+ const objects = [];
7
+ // Formato SAP ABAP XML: <SEU_ADT_REPOSITORY_OBJ_NODE>
8
+ // <OBJECT_TYPE>PROG/P</OBJECT_TYPE>
9
+ // <OBJECT_NAME>ZAIT_REPORT_TEST</OBJECT_NAME>
10
+ // <OBJECT_URI>/sap/bc/adt/programs/programs/zait_report_test</OBJECT_URI>
11
+ const nodeRegex = /<SEU_ADT_REPOSITORY_OBJ_NODE>([\s\S]*?)<\/SEU_ADT_REPOSITORY_OBJ_NODE>/gi;
12
+ let match;
13
+ while ((match = nodeRegex.exec(xml)) !== null) {
14
+ const block = match[1];
15
+ const type = block.match(/<OBJECT_TYPE>([^<]*)<\/OBJECT_TYPE>/)?.[1] ?? "";
16
+ const name = block.match(/<OBJECT_NAME>([^<]*)<\/OBJECT_NAME>/)?.[1] ?? "";
17
+ const uri = block.match(/<OBJECT_URI>([^<]*)<\/OBJECT_URI>/)?.[1] ?? "";
18
+ // Ignorar pacotes (DEVC/*) e entradas sem nome
19
+ if (!name || type.startsWith("DEVC/"))
20
+ continue;
21
+ objects.push({ name, type, uri });
22
+ }
23
+ return objects;
24
+ }
25
+ function formatPackageContents(packageName, objects) {
26
+ if (objects.length === 0) {
27
+ return `Pacote ${packageName}: vazio ou não encontrado.`;
28
+ }
29
+ const lines = [
30
+ `Pacote ${packageName} (${objects.length} objetos)`,
31
+ "─".repeat(70),
32
+ `${"Nome".padEnd(40)} Tipo`,
33
+ "─".repeat(70),
34
+ ];
35
+ const sorted = [...objects].sort((a, b) => a.type.localeCompare(b.type) || a.name.localeCompare(b.name));
36
+ for (const obj of sorted) {
37
+ lines.push(`${obj.name.padEnd(40)} ${obj.type}`);
38
+ }
39
+ return lines.join("\n");
40
+ }
41
+ async function abapPackageContents(input) {
42
+ const { package_name } = input;
43
+ const name = package_name.toUpperCase();
44
+ const csrf = await (0, adt_client_js_1.ensureSession)();
45
+ const response = await adt_client_js_1.http.post("/repository/nodestructure", "", {
46
+ params: { parent_type: "DEVC/K", parent_name: name },
47
+ headers: {
48
+ Accept: "application/vnd.sap.as+xml",
49
+ "Content-Type": "text/plain",
50
+ "X-CSRF-Token": csrf,
51
+ },
52
+ responseType: "text",
53
+ validateStatus: (status) => status < 500,
54
+ });
55
+ if (response.status === 404) {
56
+ throw new Error(`Pacote ${name} não encontrado.`);
57
+ }
58
+ const objects = parsePackageContents(response.data);
59
+ return formatPackageContents(name, objects);
60
+ }
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapPrettyPrinter = abapPrettyPrinter;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapPrettyPrinter(input) {
6
+ const { source } = input;
7
+ const csrf = await (0, adt_client_js_1.ensureSession)();
8
+ // Tentar endpoint /abapsource/prettyprinter primeiro
9
+ let response = await adt_client_js_1.http.post("/abapsource/prettyprinter", source, {
10
+ headers: {
11
+ "Content-Type": "text/plain",
12
+ "Accept": "text/plain",
13
+ "X-CSRF-Token": csrf,
14
+ },
15
+ responseType: "text",
16
+ validateStatus: (status) => status < 500,
17
+ });
18
+ // Se 404, tentar variante sem 'er' no final
19
+ if (response.status === 404) {
20
+ response = await adt_client_js_1.http.post("/abapsource/prettyprint", source, {
21
+ headers: {
22
+ "Content-Type": "text/plain",
23
+ "Accept": "text/plain",
24
+ "X-CSRF-Token": csrf,
25
+ },
26
+ responseType: "text",
27
+ validateStatus: (status) => status < 500,
28
+ });
29
+ }
30
+ if (response.status >= 300) {
31
+ const body = typeof response.data === "string" ? response.data : JSON.stringify(response.data);
32
+ throw new Error(`Pretty Printer falhou (HTTP ${response.status}): ${body.slice(0, 500)}`);
33
+ }
34
+ return response.data;
35
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapPublishBinding = abapPublishBinding;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ const system_profile_js_1 = require("../system-profile.js");
6
+ async function abapPublishBinding(input) {
7
+ const { binding_name, service_version = "0001" } = input;
8
+ const name = binding_name.toUpperCase();
9
+ const profile = (0, system_profile_js_1.getProfile)();
10
+ // Pre-flight: verificar se o mandante permite publish
11
+ if (!profile.client.allowLocalPublish) {
12
+ return `AVISO: Mandante configurado como "${profile.client.role}" — publish local pode não ser permitido. Tente assim mesmo ou altere a configuração do mandante no Gateway.`;
13
+ }
14
+ // BTP com auto-registration não precisa de publish
15
+ if (profile.gateway.autoRegistration) {
16
+ const odataUrl = (0, system_profile_js_1.resolveODataV4Url)(name, service_version);
17
+ return `Service Binding ${name} — publish não necessário (auto-registration ativo no BTP).\nOData URL: ${odataUrl}`;
18
+ }
19
+ const csrf = await (0, adt_client_js_1.ensureSession)();
20
+ const body = `<adtcore:objectReferences xmlns:adtcore="http://www.sap.com/adt/core">
21
+ <adtcore:objectReference adtcore:name="${name}"/>
22
+ </adtcore:objectReferences>`;
23
+ const response = await adt_client_js_1.http.post("/businessservices/odatav4/publishjobs", body, {
24
+ headers: {
25
+ "Accept": "application/*",
26
+ "Content-Type": "application/xml",
27
+ "X-CSRF-Token": csrf,
28
+ },
29
+ params: {
30
+ servicename: name,
31
+ serviceversion: service_version,
32
+ },
33
+ validateStatus: (status) => status >= 200 && status < 500,
34
+ });
35
+ if (response.status === 200 || response.status === 201) {
36
+ const raw = typeof response.data === "string" ? response.data : JSON.stringify(response.data);
37
+ const severity = raw.match(/<SEVERITY[^>]*>([^<]*)<\/SEVERITY>/)?.[1] ?? "";
38
+ const shortText = raw.match(/<SHORT_TEXT[^>]*>([^<]*)<\/SHORT_TEXT>/)?.[1] ?? "";
39
+ const longText = raw.match(/<LONG_TEXT[^>]*>([^<]*)<\/LONG_TEXT>/)?.[1] ?? "";
40
+ const details = [shortText, longText].filter(Boolean).join("\n");
41
+ const odataUrl = (0, system_profile_js_1.resolveODataV4Url)(name, service_version);
42
+ if (severity && severity !== "S") {
43
+ return `Publish concluído com aviso (${severity}): ${details || "(sem detalhe)"}${odataUrl ? `\nOData URL: ${odataUrl}` : ""}`;
44
+ }
45
+ return `Service Binding ${name} publicada com sucesso.${details ? `\n${details}` : ""}${odataUrl ? `\nOData URL: ${odataUrl}` : ""}`;
46
+ }
47
+ const errorBody = typeof response.data === "string" ? response.data : JSON.stringify(response.data);
48
+ throw new Error(`Erro ao publicar Service Binding (HTTP ${response.status}): ${errorBody.slice(0, 500)}`);
49
+ }
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapQuickFix = abapQuickFix;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function resolveSourceUri(objectType, objectName, classInclude) {
6
+ const adtPath = (0, adt_client_js_1.resolveAdtPath)(objectType);
7
+ const name = objectName.toUpperCase();
8
+ if (objectType === "CLAS/OC" && classInclude && classInclude !== "main") {
9
+ return `/sap/bc/adt/${adtPath}/${name}/includes/${classInclude}/source/main`;
10
+ }
11
+ return `/sap/bc/adt/${adtPath}/${name}/source/main`;
12
+ }
13
+ async function abapQuickFix(input) {
14
+ const { object_type, object_name, line, column, fix_index, class_include, transport_request } = input;
15
+ const uri = resolveSourceUri(object_type, object_name, class_include);
16
+ if (fix_index === undefined || fix_index === null) {
17
+ // Listar quick fixes disponíveis
18
+ const body = `<?xml version="1.0" encoding="UTF-8"?>
19
+ <quickfix:evaluation xmlns:quickfix="http://www.sap.com/adt/quickfixes">
20
+ <quickfix:context uri="${uri}" line="${line}" column="${column}"/>
21
+ </quickfix:evaluation>`;
22
+ const { data, status } = await (0, adt_client_js_1.adtPostXml)("/quickfixes/evaluation", body);
23
+ if (status >= 400) {
24
+ throw new Error(`Quick fix evaluation falhou (HTTP ${status}): ${data.slice(0, 500)}`);
25
+ }
26
+ // Parse fixes
27
+ const fixes = [];
28
+ const fixRegex = /<(?:quickfix:)?fix[^>]*>/gi;
29
+ let match;
30
+ let idx = 0;
31
+ while ((match = fixRegex.exec(data)) !== null) {
32
+ const el = match[0];
33
+ const descMatch = el.match(/description\s*=\s*"([^"]*)"/i);
34
+ const idxMatch = el.match(/index\s*=\s*"([^"]*)"/i);
35
+ fixes.push({
36
+ index: idxMatch ? parseInt(idxMatch[1], 10) : idx,
37
+ description: descMatch?.[1] ?? `Fix ${idx}`,
38
+ });
39
+ idx++;
40
+ }
41
+ if (fixes.length === 0) {
42
+ return `Nenhum quick fix disponível para ${object_name} na posição ${line}:${column}.`;
43
+ }
44
+ const lines = [];
45
+ lines.push(`Quick Fixes disponíveis para ${object_name} (linha ${line}, coluna ${column}):`);
46
+ lines.push("─".repeat(60));
47
+ for (const f of fixes) {
48
+ lines.push(` [${f.index}] ${f.description}`);
49
+ }
50
+ lines.push(`\nPara aplicar, chame novamente com fix_index=<número>.`);
51
+ return lines.join("\n");
52
+ }
53
+ else {
54
+ // Aplicar quick fix específico
55
+ const body = `<?xml version="1.0" encoding="UTF-8"?>
56
+ <quickfix:application xmlns:quickfix="http://www.sap.com/adt/quickfixes">
57
+ <quickfix:fix index="${fix_index}"/>
58
+ <quickfix:context uri="${uri}" line="${line}" column="${column}"/>
59
+ </quickfix:application>`;
60
+ const params = {};
61
+ if (transport_request)
62
+ params.corrNr = transport_request;
63
+ const { data, status } = await (0, adt_client_js_1.adtPostXml)("/quickfixes/application", body, params);
64
+ if (status >= 400) {
65
+ throw new Error(`Quick fix application falhou (HTTP ${status}): ${data.slice(0, 500)}`);
66
+ }
67
+ return `Quick fix #${fix_index} aplicado com sucesso em ${object_name} (linha ${line}, coluna ${column}).`;
68
+ }
69
+ }
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapReadTool = void 0;
4
+ exports.abapRead = abapRead;
5
+ const adt_client_js_1 = require("../adt-client.js");
6
+ const object_versions_js_1 = require("./object-versions.js");
7
+ function resolveSourcePath(adtPath, name, objectType, classInclude) {
8
+ if (objectType === "CLAS/OC" && classInclude && classInclude !== "main") {
9
+ return `/${adtPath}/${name}/includes/${classInclude}/source/main`;
10
+ }
11
+ return `/${adtPath}/${name}/source/main`;
12
+ }
13
+ /** Tipos DDIC cujos campos vêm de metadados XML, não de /source/main */
14
+ const DDIC_METADATA_TYPES = ["TABL/DT", "TABL/DS", "TTYP/TT"];
15
+ function parseDdicFieldsFromXml(xml, objectName, objectType) {
16
+ const typeLabel = objectType === "TABL/DS" ? "Estrutura" : "Tabela transparente";
17
+ // Extrair campos dos elementos XML <field> ou <column>
18
+ const fields = [];
19
+ // Padrão ADT: campos aparecem como <field> com atributos ou sub-elementos
20
+ // Formato 1: <adtcore:field ... name="FIELD" type="CHAR" length="10" description="..." />
21
+ // Formato 2: <field adtcore:name="FIELD" adtcore:type="CHAR" .../>
22
+ // Formato 3: Elementos genéricos com name/type atributos
23
+ // Extrair todos os elementos que parecem campos
24
+ const fieldRegex = /<(?:[a-zA-Z0-9_:]+:)?(?:field|column|component)[^>]*?(?:adtcore:)?name\s*=\s*"([^"]*)"[^>]*?>/gi;
25
+ let match;
26
+ while ((match = fieldRegex.exec(xml)) !== null) {
27
+ const element = match[0];
28
+ const name = match[1];
29
+ const typeMatch = element.match(/(?:adtcore:)?type\s*=\s*"([^"]*)"/i) ||
30
+ element.match(/dataType\s*=\s*"([^"]*)"/i);
31
+ const lengthMatch = element.match(/(?:adtcore:)?length\s*=\s*"([^"]*)"/i);
32
+ const descMatch = element.match(/(?:adtcore:)?description\s*=\s*"([^"]*)"/i);
33
+ fields.push({
34
+ name,
35
+ type: typeMatch?.[1] ?? "",
36
+ length: lengthMatch?.[1] ?? "",
37
+ description: descMatch?.[1] ?? "",
38
+ });
39
+ }
40
+ // Se não encontrou campos pelo regex acima, tentar abordagem mais genérica
41
+ // para elementos com atributos name que contenham info de tipo
42
+ if (fields.length === 0) {
43
+ // Tentar extrair de qualquer elemento com adtcore:name dentro de listas/coleções
44
+ const genericRegex = /<[^>]+?(?:adtcore:name|ddicName)\s*=\s*"([^"]+)"[^>]*?>/gi;
45
+ while ((match = genericRegex.exec(xml)) !== null) {
46
+ const element = match[0];
47
+ const name = match[1];
48
+ // Evitar duplicatas e elementos que não são campos (ex: o próprio objeto raiz)
49
+ if (name === objectName)
50
+ continue;
51
+ const typeMatch = element.match(/(?:ddicType|dataType|type)\s*=\s*"([^"]*)"/i);
52
+ const lengthMatch = element.match(/(?:ddicLength|length)\s*=\s*"([^"]*)"/i);
53
+ const descMatch = element.match(/(?:description)\s*=\s*"([^"]*)"/i);
54
+ fields.push({
55
+ name,
56
+ type: typeMatch?.[1] ?? "",
57
+ length: lengthMatch?.[1] ?? "",
58
+ description: descMatch?.[1] ?? "",
59
+ });
60
+ }
61
+ }
62
+ if (fields.length > 0) {
63
+ const header = `${typeLabel}: ${objectName} (${fields.length} campos)\n${"─".repeat(60)}`;
64
+ const lines = fields.map((f) => {
65
+ const parts = [f.name];
66
+ if (f.type)
67
+ parts.push(f.type + (f.length ? `(${f.length})` : ""));
68
+ if (f.description)
69
+ parts.push(`— ${f.description}`);
70
+ return parts.join(" ");
71
+ });
72
+ return `${header}\n${lines.join("\n")}`;
73
+ }
74
+ // Fallback: retornar XML bruto formatado se não conseguimos parsear
75
+ return `${typeLabel}: ${objectName}\n\nMetadados XML (campos não puderam ser parseados automaticamente):\n\n${xml}`;
76
+ }
77
+ /** Busca resumo de versão do objeto (best-effort, não bloqueia em erro) */
78
+ async function getVersionSummary(objectType, objectName) {
79
+ try {
80
+ const result = await (0, object_versions_js_1.abapObjectVersions)({ object_type: objectType, object_name: objectName });
81
+ // Extrair info relevante do resultado formatado
82
+ const lines = result.split("\n").filter((l) => l.trim() && !l.startsWith("─") && !l.startsWith("Versão "));
83
+ const header = lines[0] || "";
84
+ // Pegar a versão mais recente (primeira após o header)
85
+ const latest = lines[1] || "";
86
+ if (!latest.trim())
87
+ return "";
88
+ // Contar versões do header: "Versões de NOME (N)"
89
+ const countMatch = header.match(/\((\d+)\)/);
90
+ const count = countMatch ? parseInt(countMatch[1]) : 0;
91
+ if (count <= 1)
92
+ return ""; // Só 1 versão = nunca foi modificado, sem risco
93
+ // Extrair autor e data da versão mais recente
94
+ const parts = latest.trim().split(/\s{2,}/);
95
+ const version = parts[0] || "";
96
+ const date = parts[1] || "";
97
+ const author = parts[2] || "";
98
+ return `\n\n⚠️ ATENÇÃO: Este objeto tem ${count} versões. Última modificação: ${date} por ${author} (versão ${version}).\n Verifique se a versão no DEV está alinhada com PRD antes de modificar (abap_object_versions para detalhes).`;
99
+ }
100
+ catch {
101
+ // Silenciar — versões não disponíveis não deve impedir a leitura
102
+ return "";
103
+ }
104
+ }
105
+ async function abapRead(input) {
106
+ const { object_type, object_name, class_include } = input;
107
+ const name = object_name.toUpperCase();
108
+ const adtPath = (0, adt_client_js_1.resolveAdtPath)(object_type);
109
+ // Para TABL/DT, TABL/DS e TTYP/TT: tentar /source/main primeiro (CDS DDL), se 404 ler metadados XML
110
+ if (DDIC_METADATA_TYPES.includes(object_type)) {
111
+ const nameLower = name.toLowerCase();
112
+ const sourcePath = `/${adtPath}/${nameLower}/source/main`;
113
+ try {
114
+ const source = await (0, adt_client_js_1.adtGet)(sourcePath);
115
+ const versionInfo = await getVersionSummary(object_type, name);
116
+ return source + versionInfo;
117
+ }
118
+ catch (error) {
119
+ const is404 = error instanceof Error && (error.message.includes("404") || error.message.includes("não encontrado"));
120
+ if (!is404)
121
+ throw error;
122
+ }
123
+ // /source/main retornou 404 — ler metadados XML com campos
124
+ // Usar Accept header específico por tipo
125
+ const acceptMap = {
126
+ "TABL/DT": "application/vnd.sap.adt.tables.v2+xml",
127
+ "TABL/DS": "application/vnd.sap.adt.structures.v2+xml",
128
+ "TTYP/TT": "application/vnd.sap.adt.tabletype.v1+xml",
129
+ };
130
+ const metadataPath = `/${adtPath}/${nameLower}`;
131
+ await (0, adt_client_js_1.ensureSession)();
132
+ const response = await adt_client_js_1.http.get(metadataPath, {
133
+ headers: { Accept: acceptMap[object_type] ?? "application/xml" },
134
+ responseType: "text",
135
+ validateStatus: (status) => status < 500,
136
+ });
137
+ if (response.status >= 400) {
138
+ throw new Error(`Objeto ${name} (${object_type}) não encontrado.`);
139
+ }
140
+ const xml = response.data;
141
+ return parseDdicFieldsFromXml(xml, name, object_type);
142
+ }
143
+ const sourcePath = resolveSourcePath(adtPath, name, object_type, class_include);
144
+ const source = await (0, adt_client_js_1.adtGet)(sourcePath);
145
+ // Apenas para objetos com source code (não DDIC metadados): incluir aviso de versão
146
+ const versionInfo = await getVersionSummary(object_type, name);
147
+ return source + versionInfo;
148
+ }
149
+ exports.abapReadTool = {
150
+ name: "abap_read",
151
+ description: "Lê o código-fonte de um objeto ABAP no sistema SAP via ADT API.",
152
+ inputSchema: {
153
+ type: "object",
154
+ properties: {
155
+ object_type: {
156
+ type: "string",
157
+ description: "Tipo do objeto SAP. Exemplos: PROG/P (report), CLAS/OC (classe), FUGR/FF (function module), DDLS/DF (CDS view), TABL/DT (tabela transparente), TABL/DS (estrutura), INTF/OI (interface).",
158
+ enum: ["PROG/P", "CLAS/OC", "FUGR/FF", "DOMA/D", "DTEL/D", "TABL/DT", "TABL/DS", "INTF/OI", "DDLS/DF", "DDLX/MX", "SRVD/SRV", "BDEF/BDO", "SRVB/SVB"],
159
+ },
160
+ object_name: {
161
+ type: "string",
162
+ description: "Nome do objeto ABAP (ex: ZR_SD_PEDIDOS_ABERTOS). Case insensitive.",
163
+ },
164
+ },
165
+ required: ["object_type", "object_name"],
166
+ },
167
+ };
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapRefactorRename = abapRefactorRename;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function resolveSourceUri(objectType, objectName, classInclude) {
6
+ const adtPath = (0, adt_client_js_1.resolveAdtPath)(objectType);
7
+ if (objectType === "CLAS/OC" && classInclude && classInclude !== "main") {
8
+ return `/sap/bc/adt/${adtPath}/${objectName}/includes/${classInclude}/source/main`;
9
+ }
10
+ return `/sap/bc/adt/${adtPath}/${objectName}/source/main`;
11
+ }
12
+ function parseRenameResponse(xml) {
13
+ // Verificar se a resposta contém uma lista de alterações
14
+ const changes = [];
15
+ const changeRegex = /adtcore:uri\s*=\s*"([^"]*)"[^>]*?adtcore:name\s*=\s*"([^"]*)"/gi;
16
+ let match;
17
+ while ((match = changeRegex.exec(xml)) !== null) {
18
+ changes.push(` ${match[2]} (${match[1]})`);
19
+ }
20
+ if (changes.length > 0) {
21
+ return `Renomeação aplicada em ${changes.length} local(is):\n${changes.join("\n")}`;
22
+ }
23
+ // Tentar extrair mensagem de sucesso genérica
24
+ const msgMatch = xml.match(/<(?:message|shortText)[^>]*>([^<]*)<\//i);
25
+ if (msgMatch)
26
+ return msgMatch[1];
27
+ return "Renomeação aplicada com sucesso.";
28
+ }
29
+ async function abapRefactorRename(input) {
30
+ const { object_type, object_name, old_name, new_name, line, column, class_include } = input;
31
+ const name = object_name.toUpperCase();
32
+ const uri = resolveSourceUri(object_type, name, class_include);
33
+ const csrf = await (0, adt_client_js_1.ensureSession)();
34
+ // Payload XML para renomeação
35
+ const payload = `<?xml version="1.0" encoding="UTF-8"?>
36
+ <renaming:renameRefactoring xmlns:renaming="http://www.sap.com/adt/ris/renaming"
37
+ xmlns:adtcore="http://www.sap.com/adt/core">
38
+ <renaming:newName>${new_name}</renaming:newName>
39
+ <adtcore:objectReference adtcore:uri="${uri}" adtcore:name="${old_name}"/>
40
+ </renaming:renameRefactoring>`;
41
+ // Tentar execução direta
42
+ const response = await adt_client_js_1.http.post("/refactorings/rename", payload, {
43
+ headers: {
44
+ "Content-Type": "application/xml",
45
+ "Accept": "application/xml",
46
+ "X-CSRF-Token": csrf,
47
+ },
48
+ params: { uri, line: String(line), column: String(column) },
49
+ responseType: "text",
50
+ validateStatus: (status) => status < 500,
51
+ });
52
+ if (response.status >= 300) {
53
+ const body = typeof response.data === "string" ? response.data : JSON.stringify(response.data);
54
+ // Extrair mensagem de erro
55
+ const errMatch = body.match(/<(?:message|shortText|exception)[^>]*>([^<]*)<\//i);
56
+ const errorDetail = errMatch?.[1] ?? body.slice(0, 500);
57
+ throw new Error(`Renomeação falhou (HTTP ${response.status}): ${errorDetail}`);
58
+ }
59
+ return parseRenameResponse(response.data);
60
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapReleaseTransport = abapReleaseTransport;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapReleaseTransport(input) {
6
+ const { transport_request } = input;
7
+ const trId = transport_request.toUpperCase();
8
+ const csrf = await (0, adt_client_js_1.ensureSession)();
9
+ const response = await adt_client_js_1.http.post(`/cts/transportrequests/${trId}/newreleasejobs`, "", {
10
+ headers: {
11
+ "X-CSRF-Token": csrf,
12
+ "Accept": "application/xml",
13
+ },
14
+ validateStatus: (status) => status < 500,
15
+ });
16
+ if (response.status >= 200 && response.status < 300) {
17
+ return `Ordem de transporte ${trId} liberada com sucesso.`;
18
+ }
19
+ // Tentar extrair mensagem de erro do XML
20
+ const body = typeof response.data === "string" ? response.data : JSON.stringify(response.data);
21
+ const msgMatch = body.match(/<(?:message|shortText|exception)[^>]*>([^<]*)<\//i);
22
+ const errorDetail = msgMatch?.[1] ?? body.slice(0, 500);
23
+ throw new Error(`Falha ao liberar ${trId} (HTTP ${response.status}): ${errorDetail}`);
24
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapReleasedApis = abapReleasedApis;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapReleasedApis(input) {
6
+ const { filter, api_type = "all" } = input;
7
+ const params = {};
8
+ if (filter)
9
+ params.name = filter;
10
+ if (api_type && api_type !== "all") {
11
+ const typeMap = {
12
+ class: "CLAS/OC",
13
+ interface: "INTF/OI",
14
+ cds: "DDLS/DF",
15
+ };
16
+ if (typeMap[api_type])
17
+ params.type = typeMap[api_type];
18
+ }
19
+ params.releasedApi = "true";
20
+ const xml = await (0, adt_client_js_1.adtGetXmlWithParams)("/repository/informationsystem/search", {
21
+ ...params,
22
+ operation: "quickSearch",
23
+ maxResults: "100",
24
+ });
25
+ // Parse results (same format as abap_search)
26
+ const results = [];
27
+ const refRegex = /adtcore:uri\s*=\s*"[^"]*"\s+adtcore:type\s*=\s*"([^"]+)"\s+adtcore:name\s*=\s*"([^"]+)"(?:\s+adtcore:packageName\s*=\s*"([^"]*)")?(?:[^>]*adtcore:description\s*=\s*"([^"]*)")?/gi;
28
+ let match;
29
+ while ((match = refRegex.exec(xml)) !== null) {
30
+ results.push({
31
+ type: match[1],
32
+ name: match[2],
33
+ packageName: match[3] ?? "",
34
+ description: match[4] ?? "",
35
+ });
36
+ }
37
+ if (results.length === 0) {
38
+ return filter
39
+ ? `Nenhuma API released encontrada com filtro "${filter}".`
40
+ : "Nenhuma API released retornada. O endpoint pode não estar disponível neste sistema.";
41
+ }
42
+ const lines = [];
43
+ lines.push(`APIs Released (C1 Contract)${filter ? ` — filtro: ${filter}` : ""} — ${results.length} encontradas`);
44
+ lines.push("═".repeat(70));
45
+ for (const r of results) {
46
+ const desc = r.description ? ` — ${r.description}` : "";
47
+ const pkg = r.packageName ? ` [${r.packageName}]` : "";
48
+ lines.push(` ${r.name} (${r.type})${pkg}${desc}`);
49
+ }
50
+ return lines.join("\n");
51
+ }