@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,275 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.abapKnowledge = abapKnowledge;
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ // Domain display labels
40
+ const DOMAIN_LABELS = {
41
+ abap: "ABAP Core",
42
+ "abap-cds": "ABAP CDS",
43
+ fiori: "Fiori / UI5",
44
+ cap: "CAP (Node.js)",
45
+ };
46
+ // ---------------------------------------------------------------------------
47
+ // Knowledge Store (loaded once at module init)
48
+ // ---------------------------------------------------------------------------
49
+ const topics = [];
50
+ let loaded = false;
51
+ function resolveKnowledgeDir() {
52
+ // In dist/tools/knowledge.js → ../../knowledge (if copied to dist/)
53
+ const fromDist = path.join(__dirname, "..", "knowledge");
54
+ if (fs.existsSync(fromDist))
55
+ return fromDist;
56
+ // Fallback: project root src/knowledge/
57
+ return path.join(process.cwd(), "src", "knowledge");
58
+ }
59
+ function extractHeaders(content) {
60
+ return content
61
+ .split("\n")
62
+ .filter((l) => l.startsWith("## "))
63
+ .map((l) => l.replace(/^#+\s*/, "").toLowerCase())
64
+ .join(" ");
65
+ }
66
+ function loadKnowledgeBase() {
67
+ if (loaded)
68
+ return;
69
+ const baseDir = resolveKnowledgeDir();
70
+ if (!fs.existsSync(baseDir)) {
71
+ loaded = true;
72
+ return;
73
+ }
74
+ const domains = fs
75
+ .readdirSync(baseDir, { withFileTypes: true })
76
+ .filter((d) => d.isDirectory())
77
+ .map((d) => d.name);
78
+ for (const domain of domains) {
79
+ const domainDir = path.join(baseDir, domain);
80
+ const files = fs
81
+ .readdirSync(domainDir)
82
+ .filter((f) => f.endsWith(".md"))
83
+ .sort();
84
+ for (const file of files) {
85
+ const id = file.replace(/\.md$/, "");
86
+ const content = fs.readFileSync(path.join(domainDir, file), "utf-8");
87
+ const firstLine = content.split("\n")[0] || "";
88
+ // Parse: "# Title — scope description"
89
+ const match = firstLine.match(/^#\s+(.+?)\s+—\s+(.+)$/);
90
+ const title = match ? match[1].trim() : id;
91
+ const scope = match ? match[2].trim() : "";
92
+ const headers = extractHeaders(content);
93
+ const keywords = `${title} ${scope} ${headers} ${id.replace(/-/g, " ")}`.toLowerCase();
94
+ topics.push({ id, domain, title, scope, content, keywords });
95
+ }
96
+ }
97
+ loaded = true;
98
+ }
99
+ // Auto-load on module import
100
+ loadKnowledgeBase();
101
+ // ---------------------------------------------------------------------------
102
+ // Actions
103
+ // ---------------------------------------------------------------------------
104
+ function knowledgeList(domain) {
105
+ const filtered = domain ? topics.filter((t) => t.domain === domain) : topics;
106
+ if (filtered.length === 0) {
107
+ return domain
108
+ ? `Nenhum tópico encontrado no domínio "${domain}".`
109
+ : "Base de conhecimento vazia.";
110
+ }
111
+ // Group by domain
112
+ const grouped = new Map();
113
+ for (const t of filtered) {
114
+ const list = grouped.get(t.domain) || [];
115
+ list.push(t);
116
+ grouped.set(t.domain, list);
117
+ }
118
+ const lines = [];
119
+ lines.push(`📚 Base de Conhecimento SAP — ${filtered.length} guias disponíveis\n`);
120
+ for (const [dom, items] of grouped) {
121
+ const label = DOMAIN_LABELS[dom] || dom;
122
+ lines.push(`## ${label} (${items.length})`);
123
+ for (const t of items) {
124
+ const scopePart = t.scope ? ` — ${t.scope}` : "";
125
+ lines.push(` • ${t.domain}/${t.id}: ${t.title}${scopePart}`);
126
+ }
127
+ lines.push("");
128
+ }
129
+ lines.push("💡 Use action='get' com topics=['domain/id'] para ler o conteúdo completo.");
130
+ lines.push("💡 Use action='search' com query='palavra-chave' para buscar por assunto.");
131
+ return lines.join("\n");
132
+ }
133
+ function knowledgeGet(topicIds) {
134
+ if (!topicIds || topicIds.length === 0) {
135
+ return "Erro: informe ao menos um tópico. Use action='list' para ver os disponíveis.";
136
+ }
137
+ if (topicIds.length > 5) {
138
+ return "Erro: máximo 5 tópicos por chamada para não sobrecarregar o contexto. Selecione os mais relevantes.";
139
+ }
140
+ const results = [];
141
+ const notFound = [];
142
+ for (const rawId of topicIds) {
143
+ const topic = resolveTopic(rawId);
144
+ if (topic) {
145
+ results.push(topic.content);
146
+ }
147
+ else {
148
+ notFound.push(rawId);
149
+ }
150
+ }
151
+ if (notFound.length > 0) {
152
+ const suggestions = notFound.map((id) => {
153
+ const similar = findSimilar(id, 3);
154
+ if (similar.length > 0) {
155
+ return ` "${id}" → você quis dizer: ${similar.map((s) => s.domain + "/" + s.id).join(", ")}?`;
156
+ }
157
+ return ` "${id}" → não encontrado`;
158
+ });
159
+ results.push(`\n⚠️ Tópicos não encontrados:\n${suggestions.join("\n")}`);
160
+ }
161
+ return results.join("\n\n---\n\n");
162
+ }
163
+ function knowledgeSearch(query, domain) {
164
+ if (!query || query.trim().length === 0) {
165
+ return "Erro: informe um termo de busca. Ex: query='draft', query='annotations', query='BAPI'.";
166
+ }
167
+ const queryLower = query.toLowerCase();
168
+ const queryWords = queryLower.split(/\s+/).filter((w) => w.length > 1);
169
+ const candidates = domain ? topics.filter((t) => t.domain === domain) : topics;
170
+ // Score each topic
171
+ const scored = candidates.map((t) => {
172
+ let score = 0;
173
+ for (const word of queryWords) {
174
+ // Exact ID match (highest weight)
175
+ if (t.id === word || t.id.includes(word))
176
+ score += 10;
177
+ // Title match
178
+ if (t.title.toLowerCase().includes(word))
179
+ score += 8;
180
+ // Scope match
181
+ if (t.scope.toLowerCase().includes(word))
182
+ score += 6;
183
+ // Keyword/header match
184
+ if (t.keywords.includes(word))
185
+ score += 3;
186
+ // Content match (count occurrences, capped)
187
+ const contentLower = t.content.toLowerCase();
188
+ const occurrences = contentLower.split(word).length - 1;
189
+ score += Math.min(occurrences, 5) * 1;
190
+ }
191
+ return { topic: t, score };
192
+ });
193
+ // Filter and sort
194
+ const matches = scored
195
+ .filter((s) => s.score > 0)
196
+ .sort((a, b) => b.score - a.score)
197
+ .slice(0, 10);
198
+ if (matches.length === 0) {
199
+ return `Nenhum resultado para "${query}". Use action='list' para ver todos os tópicos disponíveis.`;
200
+ }
201
+ const lines = [];
202
+ lines.push(`🔍 Busca: "${query}" — ${matches.length} resultado(s)\n`);
203
+ for (const { topic: t, score } of matches) {
204
+ const relevance = score >= 15 ? "🟢" : score >= 8 ? "🟡" : "⚪";
205
+ const scopePart = t.scope ? ` — ${t.scope}` : "";
206
+ lines.push(`${relevance} ${t.domain}/${t.id}: ${t.title}${scopePart}`);
207
+ // Show first relevant snippet (first ## section that matches)
208
+ const snippet = extractSnippet(t.content, queryWords);
209
+ if (snippet) {
210
+ lines.push(` 📎 ${snippet}`);
211
+ }
212
+ lines.push("");
213
+ }
214
+ lines.push("💡 Use action='get' com topics=['domain/id'] para ler o conteúdo completo.");
215
+ return lines.join("\n");
216
+ }
217
+ // ---------------------------------------------------------------------------
218
+ // Helpers
219
+ // ---------------------------------------------------------------------------
220
+ function resolveTopic(rawId) {
221
+ // Try domain-qualified: "abap/rap-eml"
222
+ if (rawId.includes("/")) {
223
+ const [domain, id] = rawId.split("/", 2);
224
+ return topics.find((t) => t.domain === domain && t.id === id);
225
+ }
226
+ // Bare ID: try exact match (unique across domains)
227
+ const exactMatches = topics.filter((t) => t.id === rawId);
228
+ if (exactMatches.length === 1)
229
+ return exactMatches[0];
230
+ // Multiple matches (e.g. "annotations" exists in abap-cds and fiori)
231
+ // Return first but this is ambiguous — search would have shown domain-qualified IDs
232
+ if (exactMatches.length > 1)
233
+ return exactMatches[0];
234
+ return undefined;
235
+ }
236
+ function findSimilar(rawId, max) {
237
+ const search = rawId.replace(/^[^/]+\//, "").toLowerCase();
238
+ return topics
239
+ .filter((t) => t.id.includes(search) || t.keywords.includes(search))
240
+ .slice(0, max);
241
+ }
242
+ function extractSnippet(content, queryWords) {
243
+ const lines = content.split("\n");
244
+ for (const line of lines) {
245
+ const lower = line.toLowerCase();
246
+ if (line.startsWith("#"))
247
+ continue;
248
+ if (line.startsWith("```"))
249
+ continue;
250
+ if (line.trim().length < 10)
251
+ continue;
252
+ if (queryWords.some((w) => lower.includes(w))) {
253
+ const cleaned = line.replace(/^\s*[-*•]\s*/, "").trim();
254
+ return cleaned.length > 120 ? cleaned.substring(0, 117) + "..." : cleaned;
255
+ }
256
+ }
257
+ return "";
258
+ }
259
+ // ---------------------------------------------------------------------------
260
+ // Main dispatcher
261
+ // ---------------------------------------------------------------------------
262
+ async function abapKnowledge(input) {
263
+ // Ensure loaded (no-op if already loaded)
264
+ loadKnowledgeBase();
265
+ switch (input.action) {
266
+ case "list":
267
+ return knowledgeList(input.domain);
268
+ case "get":
269
+ return knowledgeGet(input.topics || []);
270
+ case "search":
271
+ return knowledgeSearch(input.query || "", input.domain);
272
+ default:
273
+ return `Ação "${input.action}" inválida. Use: list, get ou search.`;
274
+ }
275
+ }
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapLockObject = abapLockObject;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapLockObject(input) {
6
+ const { object_name } = input;
7
+ const name = object_name.toUpperCase();
8
+ await (0, adt_client_js_1.ensureSession)();
9
+ const response = await adt_client_js_1.http.get(`/ddic/lockobjects/sources/${name.toLowerCase()}`, {
10
+ headers: { Accept: "application/vnd.sap.adt.lockobjects.v1+xml" },
11
+ responseType: "text",
12
+ validateStatus: (status) => status < 500,
13
+ });
14
+ if (response.status === 404) {
15
+ throw new Error(`Lock object ${name} não encontrado.`);
16
+ }
17
+ const xml = response.data;
18
+ // Parse lock object details
19
+ const descMatch = xml.match(/adtcore:description\s*=\s*"([^"]*)"/i);
20
+ const modeMatch = xml.match(/(?:lock:)?lockMode\s*=\s*"([^"]*)"/i);
21
+ // Parse lock parameters
22
+ const params = [];
23
+ const paramRegex = /<(?:lock:)?(?:parameter|lockParameter)[^>]*>/gi;
24
+ let match;
25
+ while ((match = paramRegex.exec(xml)) !== null) {
26
+ const el = match[0];
27
+ const nameMatch = el.match(/(?:adtcore:)?name\s*=\s*"([^"]*)"/i);
28
+ const typeMatch = el.match(/(?:adtcore:)?(?:type|dataType)\s*=\s*"([^"]*)"/i);
29
+ const descMatch2 = el.match(/(?:adtcore:)?description\s*=\s*"([^"]*)"/i);
30
+ if (nameMatch) {
31
+ params.push({
32
+ name: nameMatch[1],
33
+ type: typeMatch?.[1] ?? "",
34
+ description: descMatch2?.[1] ?? "",
35
+ });
36
+ }
37
+ }
38
+ // Parse tables
39
+ const tables = [];
40
+ const tableRegex = /<(?:lock:)?(?:table|lockTable)[^>]*>/gi;
41
+ while ((match = tableRegex.exec(xml)) !== null) {
42
+ const el = match[0];
43
+ const nameMatch = el.match(/(?:adtcore:)?name\s*=\s*"([^"]*)"/i);
44
+ const modeMatch2 = el.match(/(?:lock:)?(?:lockMode|mode)\s*=\s*"([^"]*)"/i);
45
+ if (nameMatch) {
46
+ tables.push({
47
+ name: nameMatch[1],
48
+ lockMode: modeMatch2?.[1] ?? "",
49
+ });
50
+ }
51
+ }
52
+ const lines = [];
53
+ lines.push(`Lock Object: ${name}`);
54
+ lines.push("═".repeat(50));
55
+ if (descMatch)
56
+ lines.push(`Descrição: ${descMatch[1]}`);
57
+ if (modeMatch)
58
+ lines.push(`Modo: ${modeMatch[1]}`);
59
+ if (tables.length > 0) {
60
+ lines.push(`\nTabelas (${tables.length}):`);
61
+ for (const t of tables) {
62
+ const mode = t.lockMode ? ` (modo: ${t.lockMode})` : "";
63
+ lines.push(` ${t.name}${mode}`);
64
+ }
65
+ }
66
+ if (params.length > 0) {
67
+ lines.push(`\nParâmetros (${params.length}):`);
68
+ for (const p of params) {
69
+ const type = p.type ? ` [${p.type}]` : "";
70
+ const desc = p.description ? ` — ${p.description}` : "";
71
+ lines.push(` ${p.name}${type}${desc}`);
72
+ }
73
+ }
74
+ return lines.join("\n");
75
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapMessageClass = abapMessageClass;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function parseMessages(xml) {
6
+ const messages = [];
7
+ // Formato ADT: elementos com número e texto
8
+ const msgRegex = /<(?:[a-zA-Z0-9_:]*)?message[^>]*?(?:number|msgno)\s*=\s*"([^"]*)"[^>]*>/gi;
9
+ let match;
10
+ while ((match = msgRegex.exec(xml)) !== null) {
11
+ const element = match[0];
12
+ const number = match[1];
13
+ const textMatch = element.match(/(?:shortText|text|description)\s*=\s*"([^"]*)"/i);
14
+ messages.push({
15
+ number,
16
+ shortText: textMatch?.[1] ?? "",
17
+ });
18
+ }
19
+ // Fallback: tentar formato alternativo com sub-elementos
20
+ if (messages.length === 0) {
21
+ const altRegex = /<(?:[a-zA-Z0-9_:]*)?message[^>]*>([\s\S]*?)<\/(?:[a-zA-Z0-9_:]*)?message>/gi;
22
+ while ((match = altRegex.exec(xml)) !== null) {
23
+ const content = match[0] + match[1];
24
+ const numMatch = content.match(/(?:number|msgno)\s*=\s*"([^"]*)"/i);
25
+ const textMatch = content.match(/(?:shortText|text)[^>]*>([^<]*)</i);
26
+ if (numMatch) {
27
+ messages.push({
28
+ number: numMatch[1],
29
+ shortText: textMatch?.[1]?.trim() ?? "",
30
+ });
31
+ }
32
+ }
33
+ }
34
+ return messages;
35
+ }
36
+ function formatMessages(className, messages) {
37
+ if (messages.length === 0) {
38
+ return `Classe de mensagem ${className}: nenhuma mensagem encontrada.`;
39
+ }
40
+ const lines = [
41
+ `Classe de mensagem ${className} (${messages.length} mensagens)`,
42
+ "─".repeat(60),
43
+ `${"Nº".padEnd(8)} Texto`,
44
+ "─".repeat(60),
45
+ ];
46
+ // Ordenar por número
47
+ const sorted = [...messages].sort((a, b) => a.number.localeCompare(b.number));
48
+ for (const msg of sorted) {
49
+ lines.push(`${msg.number.padEnd(8)} ${msg.shortText}`);
50
+ }
51
+ return lines.join("\n");
52
+ }
53
+ async function abapMessageClass(input) {
54
+ const { message_class_name } = input;
55
+ const name = message_class_name.toUpperCase();
56
+ await (0, adt_client_js_1.ensureSession)();
57
+ const response = await adt_client_js_1.http.get(`/messageclass/${name}`, {
58
+ headers: { Accept: "application/vnd.sap.adt.mc.messageclass+xml" },
59
+ responseType: "text",
60
+ validateStatus: (status) => status < 500,
61
+ });
62
+ if (response.status === 404) {
63
+ throw new Error(`Classe de mensagem ${name} não encontrada.`);
64
+ }
65
+ const messages = parseMessages(response.data);
66
+ return formatMessages(name, messages);
67
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapNavigate = abapNavigate;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapNavigate(input) {
6
+ const { uri } = input;
7
+ const csrf = await (0, adt_client_js_1.ensureSession)();
8
+ const response = await adt_client_js_1.http.post("/navigation/target", "", {
9
+ params: { uri },
10
+ headers: {
11
+ Accept: "application/xml",
12
+ "Content-Type": "text/plain",
13
+ "X-CSRF-Token": csrf,
14
+ },
15
+ responseType: "text",
16
+ validateStatus: (s) => s < 500,
17
+ });
18
+ if (response.status >= 400) {
19
+ const msg = typeof response.data === "string"
20
+ ? (response.data.match(/<message[^>]*>([^<]+)<\/message>/i)?.[1] ?? `HTTP ${response.status}`)
21
+ : `HTTP ${response.status}`;
22
+ throw new Error(msg);
23
+ }
24
+ const xml = response.data;
25
+ // Parse navigation targets
26
+ const targets = [];
27
+ const targetRegex = /<(?:adtcore:)?objectReference[^>]*>/gi;
28
+ let match;
29
+ while ((match = targetRegex.exec(xml)) !== null) {
30
+ const element = match[0];
31
+ const nameMatch = element.match(/adtcore:name\s*=\s*"([^"]*)"/i);
32
+ const typeMatch = element.match(/adtcore:type\s*=\s*"([^"]*)"/i);
33
+ const uriMatch = element.match(/adtcore:uri\s*=\s*"([^"]*)"/i);
34
+ const lineMatch = element.match(/line\s*=\s*"([^"]*)"/i);
35
+ const colMatch = element.match(/column\s*=\s*"([^"]*)"/i);
36
+ if (nameMatch || uriMatch) {
37
+ targets.push({
38
+ name: nameMatch?.[1] ?? "",
39
+ type: typeMatch?.[1] ?? "",
40
+ uri: uriMatch?.[1] ?? "",
41
+ line: lineMatch?.[1] ?? "",
42
+ column: colMatch?.[1] ?? "",
43
+ });
44
+ }
45
+ }
46
+ // Fallback: parse generic target elements
47
+ if (targets.length === 0) {
48
+ const fallbackRegex = /<(?:navigation:)?target[^>]*>/gi;
49
+ while ((match = fallbackRegex.exec(xml)) !== null) {
50
+ const element = match[0];
51
+ const uriMatch = element.match(/uri\s*=\s*"([^"]*)"/i);
52
+ const nameMatch = element.match(/name\s*=\s*"([^"]*)"/i);
53
+ const typeMatch = element.match(/type\s*=\s*"([^"]*)"/i);
54
+ const lineMatch = element.match(/line\s*=\s*"([^"]*)"/i);
55
+ const colMatch = element.match(/column\s*=\s*"([^"]*)"/i);
56
+ if (uriMatch || nameMatch) {
57
+ targets.push({
58
+ name: nameMatch?.[1] ?? "",
59
+ type: typeMatch?.[1] ?? "",
60
+ uri: uriMatch?.[1] ?? "",
61
+ line: lineMatch?.[1] ?? "",
62
+ column: colMatch?.[1] ?? "",
63
+ });
64
+ }
65
+ }
66
+ }
67
+ if (targets.length === 0) {
68
+ return "Nenhum alvo de navegação encontrado para o URI informado.";
69
+ }
70
+ const lines = [];
71
+ lines.push(`Navegação: ${targets.length} alvo(s) encontrado(s)`);
72
+ lines.push("─".repeat(60));
73
+ for (const t of targets) {
74
+ const pos = t.line ? ` (linha ${t.line}${t.column ? `:${t.column}` : ""})` : "";
75
+ lines.push(` ${t.name || t.uri} [${t.type}]${pos}`);
76
+ if (t.uri)
77
+ lines.push(` URI: ${t.uri}`);
78
+ }
79
+ return lines.join("\n");
80
+ }
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapNumberRange = abapNumberRange;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapNumberRange(input) {
6
+ const { object_name } = input;
7
+ const name = object_name.toUpperCase();
8
+ await (0, adt_client_js_1.ensureSession)();
9
+ const response = await adt_client_js_1.http.get(`/numberranges/objects/${name.toLowerCase()}`, {
10
+ headers: { Accept: "text/html" },
11
+ responseType: "text",
12
+ validateStatus: (status) => status < 500,
13
+ });
14
+ if (response.status === 404) {
15
+ throw new Error(`Number range ${name} não encontrado.`);
16
+ }
17
+ const xml = response.data;
18
+ // Parse number range header
19
+ const descMatch = xml.match(/adtcore:description\s*=\s*"([^"]*)"/i);
20
+ const domainMatch = xml.match(/(?:nr:)?(?:domain|numberLength)\s*=\s*"([^"]*)"/i);
21
+ // Parse intervals
22
+ const intervals = [];
23
+ const intRegex = /<(?:nr:)?(?:interval|numberRangeInterval)[^>]*>/gi;
24
+ let match;
25
+ while ((match = intRegex.exec(xml)) !== null) {
26
+ const el = match[0];
27
+ const subMatch = el.match(/(?:subObject|number|nr)\s*=\s*"([^"]*)"/i);
28
+ const fromMatch = el.match(/(?:from|fromNumber|lowValue)\s*=\s*"([^"]*)"/i);
29
+ const toMatch = el.match(/(?:to|toNumber|highValue)\s*=\s*"([^"]*)"/i);
30
+ const curMatch = el.match(/(?:current|currentNumber)\s*=\s*"([^"]*)"/i);
31
+ const extMatch = el.match(/(?:external|isExternal)\s*=\s*"([^"]*)"/i);
32
+ intervals.push({
33
+ subObject: subMatch?.[1] ?? "",
34
+ from: fromMatch?.[1] ?? "",
35
+ to: toMatch?.[1] ?? "",
36
+ current: curMatch?.[1] ?? "",
37
+ external: extMatch?.[1] === "true" || extMatch?.[1] === "X",
38
+ });
39
+ }
40
+ const lines = [];
41
+ lines.push(`Number Range: ${name}`);
42
+ lines.push("═".repeat(50));
43
+ if (descMatch)
44
+ lines.push(`Descrição: ${descMatch[1]}`);
45
+ if (domainMatch)
46
+ lines.push(`Domínio/Comprimento: ${domainMatch[1]}`);
47
+ if (intervals.length > 0) {
48
+ lines.push(`\nIntervalos (${intervals.length}):`);
49
+ lines.push("─".repeat(50));
50
+ for (const i of intervals) {
51
+ const ext = i.external ? " [EXTERNO]" : " [INTERNO]";
52
+ const cur = i.current ? ` (atual: ${i.current})` : "";
53
+ lines.push(` ${i.subObject || "-"}: ${i.from} → ${i.to}${cur}${ext}`);
54
+ }
55
+ }
56
+ return lines.join("\n");
57
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapObjectDocumentation = abapObjectDocumentation;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ async function abapObjectDocumentation(input) {
6
+ const { object_type, object_name } = input;
7
+ const name = object_name.toUpperCase();
8
+ const adtPath = (0, adt_client_js_1.resolveAdtPath)(object_type);
9
+ const objectUri = `/sap/bc/adt/${adtPath}/${name}`;
10
+ const xml = await (0, adt_client_js_1.adtGetXmlWithParams)("/documentation/objectDocumentation", {
11
+ uri: objectUri,
12
+ });
13
+ // Extract documentation content
14
+ let docText = "";
15
+ // Try structured documentation
16
+ const longTextMatch = xml.match(/<(?:documentation:)?longText[^>]*>([\s\S]*?)<\/(?:documentation:)?longText>/i);
17
+ const shortTextMatch = xml.match(/<(?:documentation:)?shortText[^>]*>([\s\S]*?)<\/(?:documentation:)?shortText>/i);
18
+ const descMatch = xml.match(/<(?:documentation:)?description[^>]*>([\s\S]*?)<\/(?:documentation:)?description>/i);
19
+ if (longTextMatch) {
20
+ docText = longTextMatch[1].replace(/<[^>]+>/g, "").trim();
21
+ }
22
+ else if (shortTextMatch) {
23
+ docText = shortTextMatch[1].replace(/<[^>]+>/g, "").trim();
24
+ }
25
+ else if (descMatch) {
26
+ docText = descMatch[1].replace(/<[^>]+>/g, "").trim();
27
+ }
28
+ // Fallback: extract any readable text from HTML-like content
29
+ if (!docText) {
30
+ const htmlContent = xml.replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
31
+ if (htmlContent.length > 10) {
32
+ docText = htmlContent.slice(0, 2000);
33
+ }
34
+ }
35
+ if (!docText) {
36
+ return `Nenhuma documentação encontrada para ${name} (${object_type}).`;
37
+ }
38
+ const lines = [];
39
+ lines.push(`Documentação: ${name} (${object_type})`);
40
+ lines.push("═".repeat(60));
41
+ lines.push(docText);
42
+ return lines.join("\n");
43
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.abapObjectStructure = abapObjectStructure;
4
+ const adt_client_js_1 = require("../adt-client.js");
5
+ function parseObjectStructure(xml) {
6
+ const elements = [];
7
+ // Formato ADT: <objectStructureElement ... adtcore:name="X" adtcore:type="Y" ... visibility="Z" />
8
+ const regex = /<[^>]*?(?:objectStructureElement|include)[^>]*?adtcore:name\s*=\s*"([^"]*)"[^>]*?adtcore:type\s*=\s*"([^"]*)"[^>]*>/gi;
9
+ let match;
10
+ while ((match = regex.exec(xml)) !== null) {
11
+ const element = match[0];
12
+ const name = match[1];
13
+ const type = match[2];
14
+ const visMatch = element.match(/visibility\s*=\s*"([^"]*)"/i);
15
+ const visibility = visMatch?.[1] ?? "";
16
+ elements.push({ name, type, visibility });
17
+ }
18
+ // Fallback: tentar extrair de elementos com atributos diferentes
19
+ if (elements.length === 0) {
20
+ const fallbackRegex = /<[^>]*?adtcore:name\s*=\s*"([^"]*)"[^>]*?adtcore:type\s*=\s*"([^"]*)"[^>]*>/gi;
21
+ while ((match = fallbackRegex.exec(xml)) !== null) {
22
+ const element = match[0];
23
+ const name = match[1];
24
+ const type = match[2];
25
+ // Ignorar o próprio objeto raiz
26
+ if (type === "CLAS/OC" || type === "INTF/OI")
27
+ continue;
28
+ const visMatch = element.match(/visibility\s*=\s*"([^"]*)"/i);
29
+ elements.push({
30
+ name,
31
+ type,
32
+ visibility: visMatch?.[1] ?? "",
33
+ });
34
+ }
35
+ }
36
+ return elements;
37
+ }
38
+ function formatStructure(objectName, elements) {
39
+ if (elements.length === 0) {
40
+ return `${objectName}: nenhum elemento encontrado na estrutura.`;
41
+ }
42
+ // Agrupar por tipo
43
+ const groups = {};
44
+ for (const el of elements) {
45
+ const key = el.type || "other";
46
+ if (!groups[key])
47
+ groups[key] = [];
48
+ groups[key].push(el);
49
+ }
50
+ const lines = [`Estrutura de ${objectName} (${elements.length} elementos)`, "─".repeat(60)];
51
+ for (const [type, items] of Object.entries(groups)) {
52
+ lines.push("");
53
+ lines.push(`▸ ${type} (${items.length})`);
54
+ for (const item of items) {
55
+ const vis = item.visibility ? `[${item.visibility}]` : "";
56
+ lines.push(` ${item.name.padEnd(40)} ${vis}`);
57
+ }
58
+ }
59
+ return lines.join("\n");
60
+ }
61
+ async function abapObjectStructure(input) {
62
+ const { object_type, object_name } = input;
63
+ const name = object_name.toUpperCase();
64
+ let basePath;
65
+ if (object_type === "CLAS/OC") {
66
+ basePath = "oo/classes";
67
+ }
68
+ else if (object_type === "INTF/OI") {
69
+ basePath = "oo/interfaces";
70
+ }
71
+ else {
72
+ throw new Error("abap_object_structure suporta apenas CLAS/OC e INTF/OI.");
73
+ }
74
+ const path = `/${basePath}/${name}/objectstructure`;
75
+ const xml = await (0, adt_client_js_1.adtGetXml)(path);
76
+ const elements = parseObjectStructure(xml);
77
+ return formatStructure(name, elements);
78
+ }