@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,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapDiscovery = abapDiscovery;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapDiscovery() {
6
+ await (0, adt_client_js_1.ensureSession)();
7
+ const response = await adt_client_js_1.http.get("/discovery", {
8
+ headers: { Accept: "application/atomsvc+xml" },
9
+ responseType: "text",
10
+ });
11
+ const xml = response.data;
12
+ // Parse collections
13
+ const collections = [];
14
+ const collRegex = /<app:collection[^>]*href\s*=\s*"([^"]*)"[^>]*>([\s\S]*?)<\/app:collection>/gi;
15
+ let match;
16
+ while ((match = collRegex.exec(xml)) !== null) {
17
+ const href = match[1];
18
+ const content = match[2];
19
+ const titleMatch = content.match(/<atom:title[^>]*>([\s\S]*?)<\/atom:title>/i)
20
+ ?? content.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
21
+ const title = titleMatch?.[1]?.trim() ?? "";
22
+ const contentTypes = [];
23
+ const ctRegex = /<app:accept[^>]*>([\s\S]*?)<\/app:accept>/gi;
24
+ let ctMatch;
25
+ while ((ctMatch = ctRegex.exec(content)) !== null) {
26
+ contentTypes.push(ctMatch[1].trim());
27
+ }
28
+ collections.push({ href, title, contentTypes });
29
+ }
30
+ // Fallback: simpler parsing
31
+ if (collections.length === 0) {
32
+ const simpleRegex = /<collection[^>]*href\s*=\s*"([^"]*)"[^>]*>/gi;
33
+ while ((match = simpleRegex.exec(xml)) !== null) {
34
+ const href = match[0];
35
+ const hrefVal = match[1];
36
+ const titleMatch = href.match(/title\s*=\s*"([^"]*)"/i);
37
+ collections.push({
38
+ href: hrefVal,
39
+ title: titleMatch?.[1] ?? "",
40
+ contentTypes: [],
41
+ });
42
+ }
43
+ }
44
+ if (collections.length === 0) {
45
+ return "Discovery: nenhuma coleção ADT encontrada. Verifique a conectividade.";
46
+ }
47
+ const lines = [];
48
+ lines.push(`ADT Discovery: ${collections.length} APIs/serviços disponíveis`);
49
+ lines.push("═".repeat(70));
50
+ for (const c of collections) {
51
+ const title = c.title ? `${c.title}` : "(sem título)";
52
+ lines.push(` ${title}`);
53
+ lines.push(` URI: ${c.href}`);
54
+ if (c.contentTypes.length > 0) {
55
+ lines.push(` Tipos: ${c.contentTypes.join(", ")}`);
56
+ }
57
+ }
58
+ return lines.join("\n");
59
+ }
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapElementInfo = abapElementInfo;
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 `/${adtPath}/${objectName}/includes/${classInclude}/source/main`;
9
+ }
10
+ return `/${adtPath}/${objectName}/source/main`;
11
+ }
12
+ function parseElementInfo(xml) {
13
+ const detail = {
14
+ name: "",
15
+ type: "",
16
+ description: "",
17
+ uri: "",
18
+ parameters: [],
19
+ };
20
+ // Nome do elemento
21
+ const nameMatch = xml.match(/adtcore:name\s*=\s*"([^"]*)"/i);
22
+ if (nameMatch)
23
+ detail.name = nameMatch[1];
24
+ // Tipo
25
+ const typeMatch = xml.match(/adtcore:type\s*=\s*"([^"]*)"/i);
26
+ if (typeMatch)
27
+ detail.type = typeMatch[1];
28
+ // Descrição
29
+ const descMatch = xml.match(/adtcore:description\s*=\s*"([^"]*)"/i);
30
+ if (descMatch)
31
+ detail.description = descMatch[1];
32
+ // URI
33
+ const uriMatch = xml.match(/adtcore:uri\s*=\s*"([^"]*)"/i);
34
+ if (uriMatch)
35
+ detail.uri = uriMatch[1];
36
+ // Parâmetros (para métodos/function modules)
37
+ const paramRegex = /<[^>]*?(?:parameter|param)[^>]*?adtcore:name\s*=\s*"([^"]*)"[^>]*>/gi;
38
+ let match;
39
+ while ((match = paramRegex.exec(xml)) !== null) {
40
+ const element = match[0];
41
+ const name = match[1];
42
+ const dirMatch = element.match(/direction\s*=\s*"([^"]*)"/i);
43
+ const typeMatch = element.match(/(?:dataType|abapType|type)\s*=\s*"([^"]*)"/i);
44
+ detail.parameters.push({
45
+ name,
46
+ direction: dirMatch?.[1] ?? "",
47
+ type: typeMatch?.[1] ?? "",
48
+ });
49
+ }
50
+ return detail;
51
+ }
52
+ function formatElementInfo(detail) {
53
+ const lines = [];
54
+ if (detail.name)
55
+ lines.push(`Nome: ${detail.name}`);
56
+ if (detail.type)
57
+ lines.push(`Tipo: ${detail.type}`);
58
+ if (detail.description)
59
+ lines.push(`Descrição: ${detail.description}`);
60
+ if (detail.uri)
61
+ lines.push(`URI: ${detail.uri}`);
62
+ if (detail.parameters.length > 0) {
63
+ lines.push("");
64
+ lines.push(`Parâmetros (${detail.parameters.length}):`);
65
+ lines.push("─".repeat(50));
66
+ for (const p of detail.parameters) {
67
+ const dir = p.direction ? `[${p.direction}]` : "";
68
+ const type = p.type ? `: ${p.type}` : "";
69
+ lines.push(` ${p.name.padEnd(30)} ${dir.padEnd(12)} ${type}`);
70
+ }
71
+ }
72
+ if (lines.length === 0) {
73
+ return "Nenhuma informação encontrada para o elemento na posição indicada.";
74
+ }
75
+ return lines.join("\n");
76
+ }
77
+ async function abapElementInfo(input) {
78
+ const { object_type, object_name, line, column, class_include } = input;
79
+ const name = object_name.toUpperCase();
80
+ const uri = resolveSourceUri(object_type, name, class_include);
81
+ await (0, adt_client_js_1.ensureSession)();
82
+ const response = await adt_client_js_1.http.get("/repository/informationsystem/elementinfo", {
83
+ params: { uri: `/sap/bc/adt${uri}`, line: String(line), column: String(column) },
84
+ headers: { Accept: "application/xml" },
85
+ responseType: "text",
86
+ validateStatus: (status) => status < 500,
87
+ });
88
+ if (response.status === 404) {
89
+ throw new Error("Endpoint elementinfo não disponível neste sistema SAP. Verifique o serviço /sap/bc/adt/repository/informationsystem/elementinfo.");
90
+ }
91
+ const detail = parseElementInfo(response.data);
92
+ return formatElementInfo(detail);
93
+ }
@@ -0,0 +1,186 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapEnhancementSpot = abapEnhancementSpot;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function parseBoolAttr(element, ...attrNames) {
6
+ for (const attr of attrNames) {
7
+ const match = element.match(new RegExp(`${attr}\\s*=\\s*"([^"]*)"`, "i"));
8
+ if (match) {
9
+ const val = match[1].toLowerCase();
10
+ return val === "true" || val === "x" || val === "1";
11
+ }
12
+ }
13
+ return null;
14
+ }
15
+ async function abapEnhancementSpot(input) {
16
+ const { name, type = "spot" } = input;
17
+ const objName = name.toUpperCase();
18
+ const path = type === "implementation"
19
+ ? `/enhancements/implementations/${objName}`
20
+ : `/enhancements/spots/${objName}`;
21
+ const xml = await (0, adt_client_js_1.adtGetXml)(path);
22
+ // Parse BAdI definitions / Enhancement options
23
+ const badis = [];
24
+ const badiRegex = /<(?:enh:)?(?:badi|enhancementOption|badiDefinition)[^>]*\/?>/gi;
25
+ let match;
26
+ while ((match = badiRegex.exec(xml)) !== null) {
27
+ const el = match[0];
28
+ const nameMatch = el.match(/(?:adtcore:)?name\s*=\s*"([^"]*)"/i);
29
+ const descMatch = el.match(/(?:adtcore:)?description\s*=\s*"([^"]*)"/i);
30
+ const intfMatch = el.match(/(?:interface|fallbackClass|badiInterface)\s*=\s*"([^"]*)"/i);
31
+ // Detectar single-use vs multi-use
32
+ const multipleUse = parseBoolAttr(el, "multipleUse", "multiple_use", "isMultipleUse");
33
+ const filterDependent = parseBoolAttr(el, "filterDependent", "filter_dependent", "isFilterDependent", "usesFilter");
34
+ if (nameMatch) {
35
+ badis.push({
36
+ name: nameMatch[1],
37
+ description: descMatch?.[1] ?? "",
38
+ interface: intfMatch?.[1] ?? "",
39
+ multipleUse,
40
+ filterDependent,
41
+ implementations: [],
42
+ });
43
+ }
44
+ }
45
+ // Parse implementing classes
46
+ const impls = [];
47
+ const implRegex = /<(?:enh:)?(?:implementation|badiImplementation|implClass)[^>]*\/?>/gi;
48
+ while ((match = implRegex.exec(xml)) !== null) {
49
+ const el = match[0];
50
+ const nameMatch = el.match(/(?:adtcore:)?name\s*=\s*"([^"]*)"/i);
51
+ const descMatch = el.match(/(?:adtcore:)?description\s*=\s*"([^"]*)"/i);
52
+ const badiMatch = el.match(/(?:badi|badiName|badiDefinition)\s*=\s*"([^"]*)"/i);
53
+ const activeMatch = parseBoolAttr(el, "active", "isActive");
54
+ if (nameMatch) {
55
+ impls.push({
56
+ name: nameMatch[1],
57
+ description: descMatch?.[1] ?? "",
58
+ badiName: badiMatch?.[1] ?? "",
59
+ active: activeMatch !== false, // default true if not specified
60
+ });
61
+ }
62
+ }
63
+ // Associar implementações aos BAdIs
64
+ for (const impl of impls) {
65
+ const badi = badis.find((b) => b.name === impl.badiName);
66
+ if (badi) {
67
+ badi.implementations.push({ name: impl.name, description: impl.description, active: impl.active });
68
+ }
69
+ }
70
+ // Se é um spot, tentar buscar implementações existentes via search
71
+ if (type === "spot" && badis.length > 0) {
72
+ await tryLoadExistingImplementations(badis);
73
+ }
74
+ // Format output
75
+ const lines = [];
76
+ const typeLabel = type === "implementation" ? "Enhancement Implementation" : "Enhancement Spot";
77
+ lines.push(`${typeLabel}: ${objName}`);
78
+ lines.push("═".repeat(60));
79
+ const rootDesc = xml.match(/adtcore:description\s*=\s*"([^"]*)"/i);
80
+ if (rootDesc)
81
+ lines.push(`Descrição: ${rootDesc[1]}`);
82
+ if (badis.length > 0) {
83
+ lines.push(`\nBAdIs / Enhancement Options (${badis.length}):`);
84
+ lines.push("─".repeat(55));
85
+ for (const b of badis) {
86
+ const desc = b.description ? ` — ${b.description}` : "";
87
+ const intf = b.interface ? `\n Interface: ${b.interface}` : "";
88
+ // Uso: single vs multiple
89
+ let usageInfo = "";
90
+ if (b.multipleUse === true) {
91
+ usageInfo = "\n Uso: MÚLTIPLAS implementações permitidas";
92
+ }
93
+ else if (b.multipleUse === false) {
94
+ usageInfo = "\n Uso: SINGLE-USE (apenas UMA implementação permitida)";
95
+ }
96
+ if (b.filterDependent === true) {
97
+ usageInfo += "\n Filtro: sim (filter-dependent)";
98
+ }
99
+ // Implementações existentes
100
+ let implInfo = "";
101
+ if (b.implementations.length > 0) {
102
+ implInfo = `\n Implementações existentes (${b.implementations.length}):`;
103
+ for (const impl of b.implementations) {
104
+ const status = impl.active ? "ativa" : "inativa";
105
+ const idesc = impl.description ? ` — ${impl.description}` : "";
106
+ implInfo += `\n • ${impl.name} (${status})${idesc}`;
107
+ }
108
+ // ALERTA para single-use com implementação existente
109
+ if (b.multipleUse === false && b.implementations.length > 0) {
110
+ const activeImpl = b.implementations.find((i) => i.active);
111
+ if (activeImpl) {
112
+ implInfo += `\n\n ⛔ BLOQUEIO: BAdI "${b.name}" é SINGLE-USE e já possui implementação ativa "${activeImpl.name}".`;
113
+ implInfo += `\n NÃO é possível criar uma nova implementação. Modifique a existente.`;
114
+ implInfo += `\n → abap_read(object_type:'CLAS/OC', object_name:'${activeImpl.name}') para ver o código atual.`;
115
+ }
116
+ }
117
+ }
118
+ else {
119
+ implInfo = "\n Implementações existentes: nenhuma encontrada";
120
+ if (b.multipleUse === false) {
121
+ implInfo += " (single-use — pode criar UMA implementação)";
122
+ }
123
+ }
124
+ lines.push(` ${b.name}${desc}${intf}${usageInfo}${implInfo}`);
125
+ lines.push("");
126
+ }
127
+ }
128
+ // Implementações não associadas a BAdIs
129
+ const unlinked = impls.filter((i) => !badis.some((b) => b.name === i.badiName));
130
+ if (unlinked.length > 0) {
131
+ lines.push(`\nImplementações (${unlinked.length}):`);
132
+ lines.push("─".repeat(50));
133
+ for (const i of unlinked) {
134
+ const desc = i.description ? ` — ${i.description}` : "";
135
+ const badi = i.badiName ? ` (BAdI: ${i.badiName})` : "";
136
+ const status = i.active ? "" : " [INATIVA]";
137
+ lines.push(` ${i.name}${status}${desc}${badi}`);
138
+ }
139
+ }
140
+ if (badis.length === 0 && impls.length === 0 && unlinked.length === 0) {
141
+ lines.push(`\nConteúdo do XML (primeiros 1000 chars):\n${xml.slice(0, 1000)}`);
142
+ }
143
+ return lines.join("\n");
144
+ }
145
+ /** Best-effort: tenta buscar implementações existentes de cada BAdI */
146
+ async function tryLoadExistingImplementations(badis) {
147
+ try {
148
+ await (0, adt_client_js_1.ensureSession)();
149
+ for (const badi of badis) {
150
+ if (badi.implementations.length > 0)
151
+ continue; // já tem do XML
152
+ try {
153
+ // Tentar ler o BAdI definition que pode listar implementações
154
+ const response = await adt_client_js_1.http.get(`/enhancements/spots/${badi.name.toLowerCase()}`, {
155
+ headers: { Accept: "application/xml" },
156
+ responseType: "text",
157
+ validateStatus: (s) => s < 500,
158
+ });
159
+ if (response.status < 400) {
160
+ const badiXml = response.data;
161
+ const implRegex = /<(?:enh:)?(?:implementation|badiImplementation|implClass)[^>]*\/?>/gi;
162
+ let m;
163
+ while ((m = implRegex.exec(badiXml)) !== null) {
164
+ const el = m[0];
165
+ const nameMatch = el.match(/(?:adtcore:)?name\s*=\s*"([^"]*)"/i);
166
+ const descMatch = el.match(/(?:adtcore:)?description\s*=\s*"([^"]*)"/i);
167
+ const activeMatch = parseBoolAttr(el, "active", "isActive");
168
+ if (nameMatch) {
169
+ badi.implementations.push({
170
+ name: nameMatch[1],
171
+ description: descMatch?.[1] ?? "",
172
+ active: activeMatch !== false,
173
+ });
174
+ }
175
+ }
176
+ }
177
+ }
178
+ catch {
179
+ // Silenciar — não bloquear por falha na busca de implementações
180
+ }
181
+ }
182
+ }
183
+ catch {
184
+ // Silenciar
185
+ }
186
+ }
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapExtractMethod = abapExtractMethod;
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 abapExtractMethod(input) {
14
+ const { object_type, object_name, start_line, end_line, new_method_name, class_include, transport_request } = input;
15
+ const uri = resolveSourceUri(object_type, object_name, class_include);
16
+ const body = `<?xml version="1.0" encoding="UTF-8"?>
17
+ <extractMethod:extractMethodRefactoring
18
+ xmlns:extractMethod="http://www.sap.com/adt/ris/extractmethod"
19
+ xmlns:adtcore="http://www.sap.com/adt/core">
20
+ <extractMethod:newMethodName>${new_method_name.toUpperCase()}</extractMethod:newMethodName>
21
+ <extractMethod:selection startLine="${start_line}" endLine="${end_line}"/>
22
+ <adtcore:objectReference adtcore:uri="${uri}"/>
23
+ </extractMethod:extractMethodRefactoring>`;
24
+ const params = {};
25
+ if (transport_request)
26
+ params.corrNr = transport_request;
27
+ const { data, status } = await (0, adt_client_js_1.adtPostXml)("/refactorings/extractmethod", body, params);
28
+ if (status >= 400) {
29
+ // Extrair mensagem de erro do XML
30
+ const msgMatch = data.match(/<(?:message|shortText)[^>]*>([\s\S]*?)<\/(?:message|shortText)>/i);
31
+ const errorMsg = msgMatch?.[1] ?? data.slice(0, 500);
32
+ throw new Error(`Extract Method falhou (HTTP ${status}): ${errorMsg}`);
33
+ }
34
+ // Contar mudanças aplicadas
35
+ const changes = [];
36
+ const changeRegex = /adtcore:uri\s*=\s*"([^"]*)"/gi;
37
+ let match;
38
+ while ((match = changeRegex.exec(data)) !== null) {
39
+ changes.push(match[1]);
40
+ }
41
+ return `Extract Method concluído com sucesso!\n` +
42
+ `Método "${new_method_name.toUpperCase()}" criado em ${object_name} (linhas ${start_line}-${end_line}).\n` +
43
+ `${changes.length} arquivo(s) afetado(s).`;
44
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapFunctionGroup = abapFunctionGroup;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function parseFunctionModules(xml) {
6
+ const modules = [];
7
+ // Formato ADT: <abapsource:objectStructureElement adtcore:name="FM_NAME" adtcore:type="FUGR/FF">
8
+ const regex = /<abapsource:objectStructureElement[^>]*adtcore:name="([^"]*)"[^>]*adtcore:type="([^"]*)"[^>]*>/gi;
9
+ let match;
10
+ while ((match = regex.exec(xml)) !== null) {
11
+ const name = match[1];
12
+ const type = match[2];
13
+ // Ignorar o grupo em si (type FUGR/F)
14
+ if (type === "FUGR/F")
15
+ continue;
16
+ modules.push({ name, type });
17
+ }
18
+ return modules;
19
+ }
20
+ function formatFunctionModules(groupName, modules) {
21
+ if (modules.length === 0) {
22
+ return `Grupo de funções ${groupName}: nenhum function module encontrado.`;
23
+ }
24
+ const fms = modules.filter((m) => m.type === "FUGR/FF");
25
+ const includes = modules.filter((m) => m.type !== "FUGR/FF");
26
+ const lines = [
27
+ `Grupo de funções ${groupName} (${fms.length} function modules, ${includes.length} includes)`,
28
+ "─".repeat(60),
29
+ ];
30
+ if (fms.length > 0) {
31
+ lines.push("Function Modules:");
32
+ for (const fm of fms) {
33
+ lines.push(` ${fm.name}`);
34
+ }
35
+ }
36
+ if (includes.length > 0) {
37
+ lines.push("");
38
+ lines.push("Includes:");
39
+ for (const inc of includes) {
40
+ lines.push(` ${inc.name.padEnd(40)} ${inc.type}`);
41
+ }
42
+ }
43
+ return lines.join("\n");
44
+ }
45
+ async function abapFunctionGroup(input) {
46
+ const { group_name } = input;
47
+ const name = group_name.toUpperCase();
48
+ await (0, adt_client_js_1.ensureSession)();
49
+ const response = await adt_client_js_1.http.get(`/functions/groups/${name.toLowerCase()}/objectstructure`, {
50
+ headers: { Accept: "application/vnd.sap.adt.objectstructure.v2+xml" },
51
+ responseType: "text",
52
+ validateStatus: (status) => status < 500,
53
+ });
54
+ if (response.status === 404) {
55
+ throw new Error(`Grupo de funções ${name} não encontrado.`);
56
+ }
57
+ const modules = parseFunctionModules(response.data);
58
+ return formatFunctionModules(name, modules);
59
+ }