@st-gr/abap-adt-skill 1.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.
package/dist/index.js ADDED
@@ -0,0 +1,336 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ process.env.MSYS_NO_PATHCONV = "1";
5
+ const commander_1 = require("commander");
6
+ const error_handler_1 = require("./util/error-handler");
7
+ const search_1 = require("./commands/search");
8
+ const structure_1 = require("./commands/structure");
9
+ const read_1 = require("./commands/read");
10
+ const write_1 = require("./commands/write");
11
+ const create_1 = require("./commands/create");
12
+ const activate_1 = require("./commands/activate");
13
+ const transport_1 = require("./commands/transport");
14
+ const test_1 = require("./commands/test");
15
+ const syntax_1 = require("./commands/syntax");
16
+ const atc_1 = require("./commands/atc");
17
+ const pretty_print_1 = require("./commands/pretty-print");
18
+ const debug_1 = require("./commands/debug");
19
+ const table_1 = require("./commands/table");
20
+ const delete_1 = require("./commands/delete");
21
+ const whereused_1 = require("./commands/whereused");
22
+ const run_1 = require("./commands/run");
23
+ const users_1 = require("./commands/users");
24
+ const package_1 = require("./commands/package");
25
+ const exec_1 = require("./commands/exec");
26
+ const definition_1 = require("./commands/definition");
27
+ const classinfo_1 = require("./commands/classinfo");
28
+ const completion_1 = require("./commands/completion");
29
+ const quickfix_1 = require("./commands/quickfix");
30
+ const rename_1 = require("./commands/rename");
31
+ const systems_1 = require("./commands/systems");
32
+ const program = new commander_1.Command();
33
+ program
34
+ .name("abap-adt")
35
+ .description("CLI for SAP ABAP ADT operations")
36
+ .version("1.0.0");
37
+ // Search
38
+ program
39
+ .command("search <query>")
40
+ .description("Search for ABAP objects by name")
41
+ .option("-t, --type <type>", "Object type filter (e.g. PROG/P, CLAS/OC)")
42
+ .option("-m, --max <n>", "Maximum results", "100")
43
+ .option("--json", "Output as JSON")
44
+ .action((query, opts) => (0, error_handler_1.handleErrors)(() => (0, search_1.searchCommand)(query, opts)));
45
+ // Structure
46
+ program
47
+ .command("structure <objectUrl>")
48
+ .description("Get object structure and metadata")
49
+ .option("--json", "Output as JSON")
50
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, structure_1.structureCommand)(url, opts)));
51
+ // Read
52
+ program
53
+ .command("read <objectUrl>")
54
+ .description("Read source code of an ABAP object")
55
+ .option("-v, --version <version>", "Version: active or inactive")
56
+ .option("-i, --include <include>", "Class include: main, definitions, implementations, testclasses")
57
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, read_1.readCommand)(url, opts)));
58
+ // Write
59
+ program
60
+ .command("write <objectUrl>")
61
+ .description("Write source code (handles lock/unlock cycle)")
62
+ .requiredOption("-s, --source-file <path>", "Path to source file")
63
+ .option("-r, --transport <trkorr>", "Transport request number")
64
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, write_1.writeCommand)(url, opts)));
65
+ // Create
66
+ program
67
+ .command("create <type> <name>")
68
+ .description("Create a new ABAP object")
69
+ .requiredOption("-p, --package <package>", "Package name")
70
+ .requiredOption("-d, --description <desc>", "Object description")
71
+ .option("-r, --transport <trkorr>", "Transport request number")
72
+ .option("--parent-path <path>", "Parent path (auto-detected if omitted)")
73
+ .option("--responsible <user>", "Responsible user")
74
+ .option("-g, --function-group <fugr>", "Function group (for function-module type)")
75
+ .action((type, name, opts) => (0, error_handler_1.handleErrors)(() => (0, create_1.createCommand)(type, name, opts)));
76
+ // Activate
77
+ program
78
+ .command("activate <objectName> <objectUrl>")
79
+ .description("Activate an ABAP object")
80
+ .option("--json", "Output as JSON")
81
+ .action((name, url, opts) => (0, error_handler_1.handleErrors)(() => (0, activate_1.activateCommand)(name, url, opts)));
82
+ // Inactive objects
83
+ program
84
+ .command("inactive-objects")
85
+ .description("List all inactive objects")
86
+ .option("--json", "Output as JSON")
87
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, activate_1.inactiveObjectsCommand)(opts)));
88
+ // Transport commands
89
+ const transport = program.command("transport").description("Transport management");
90
+ transport
91
+ .command("info <objectUrl>")
92
+ .description("Get transport info for an object")
93
+ .option("--devclass <pkg>", "Development class/package")
94
+ .option("--json", "Output as JSON")
95
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, transport_1.transportInfoCommand)(url, opts)));
96
+ transport
97
+ .command("create <objectUrl>")
98
+ .description("Create a new transport request")
99
+ .requiredOption("-d, --description <desc>", "Transport description")
100
+ .requiredOption("--devclass <pkg>", "Development class/package")
101
+ .option("--json", "Output as JSON")
102
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, transport_1.transportCreateCommand)(url, opts)));
103
+ transport
104
+ .command("release <transportNumber>")
105
+ .description("Release a transport request")
106
+ .option("--ignore-locks", "Ignore locks")
107
+ .option("--ignore-atc", "Ignore ATC checks")
108
+ .option("--json", "Output as JSON")
109
+ .action((num, opts) => (0, error_handler_1.handleErrors)(() => (0, transport_1.transportReleaseCommand)(num, opts)));
110
+ transport
111
+ .command("list")
112
+ .description("List user transports")
113
+ .option("-u, --user <user>", "User (defaults to current)")
114
+ .option("--json", "Output as JSON")
115
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, transport_1.transportListCommand)(opts)));
116
+ transport
117
+ .command("delete <transportNumber>")
118
+ .description("Delete a transport request")
119
+ .option("--json", "Output as JSON")
120
+ .action((num, opts) => (0, error_handler_1.handleErrors)(() => (0, transport_1.transportDeleteCommand)(num, opts)));
121
+ // Test
122
+ program
123
+ .command("test <objectUrl>")
124
+ .description("Run ABAP unit tests")
125
+ .option("--risk <level>", "Risk level: harmless, dangerous, critical")
126
+ .option("--duration <level>", "Duration: short, medium, long")
127
+ .option("--json", "Output as JSON")
128
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, test_1.testCommand)(url, opts)));
129
+ // Syntax check
130
+ program
131
+ .command("syntax-check <objectUrl>")
132
+ .description("Run syntax check on ABAP source")
133
+ .requiredOption("-s, --source-file <path>", "Path to source file")
134
+ .option("--main-url <url>", "Main program URL")
135
+ .option("--main-program <name>", "Main program name")
136
+ .option("--json", "Output as JSON")
137
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, syntax_1.syntaxCheckCommand)(url, opts)));
138
+ // ATC
139
+ program
140
+ .command("atc <objectUrl>")
141
+ .description("Run ATC checks")
142
+ .option("--variant <name>", "Check variant", "DEFAULT")
143
+ .option("--max <n>", "Maximum findings")
144
+ .option("--json", "Output as JSON")
145
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, atc_1.atcRunCommand)(url, opts)));
146
+ // Pretty print
147
+ program
148
+ .command("pretty-print")
149
+ .description("Pretty-print ABAP source code")
150
+ .requiredOption("-s, --source-file <path>", "Path to source file")
151
+ .option("-o, --output <path>", "Output file (prints to stdout if omitted)")
152
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, pretty_print_1.prettyPrintCommand)(opts)));
153
+ // Debug commands
154
+ const debug = program.command("debug").description("Debugger operations");
155
+ debug
156
+ .command("listen")
157
+ .description("Start debug listener (blocks until breakpoint hit)")
158
+ .option("--mode <mode>", "Debugging mode: user or terminal", "user")
159
+ .option("-u, --user <user>", "Request user")
160
+ .option("--timeout <ms>", "Timeout in milliseconds")
161
+ .option("--json", "Output as JSON")
162
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, debug_1.debugListenCommand)(opts)));
163
+ debug
164
+ .command("attach <debuggeeId>")
165
+ .description("Attach to a debuggee")
166
+ .option("--mode <mode>", "Debugging mode: user or terminal", "user")
167
+ .option("-u, --user <user>", "Request user")
168
+ .option("--json", "Output as JSON")
169
+ .action((id, opts) => (0, error_handler_1.handleErrors)(() => (0, debug_1.debugAttachCommand)(id, opts)));
170
+ debug
171
+ .command("breakpoints <uri>")
172
+ .description("Set breakpoints (URI format: /sap/bc/adt/.../source/main#start=LINE)")
173
+ .option("--mode <mode>", "Debugging mode", "user")
174
+ .option("-u, --user <user>", "Request user")
175
+ .option("--terminal-id <id>", "Terminal ID")
176
+ .option("--ide-id <id>", "IDE ID")
177
+ .option("--client-id <id>", "Client ID")
178
+ .option("--json", "Output as JSON")
179
+ .action((uri, opts) => (0, error_handler_1.handleErrors)(() => (0, debug_1.debugBreakpointsCommand)(uri, opts)));
180
+ debug
181
+ .command("step <stepType>")
182
+ .description("Debug step: stepInto, stepOver, stepReturn, stepContinue, terminateDebuggee")
183
+ .option("--uri <uri>", "Target URI for stepRunToLine/stepJumpToLine")
184
+ .option("--json", "Output as JSON")
185
+ .action((type, opts) => (0, error_handler_1.handleErrors)(() => (0, debug_1.debugStepCommand)(type, opts)));
186
+ debug
187
+ .command("stack")
188
+ .description("Get current debug call stack")
189
+ .option("--json", "Output as JSON")
190
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, debug_1.debugStackCommand)(opts)));
191
+ debug
192
+ .command("variables <vars...>")
193
+ .description("Inspect debug variables by ID")
194
+ .option("--json", "Output as JSON")
195
+ .action((vars, opts) => (0, error_handler_1.handleErrors)(() => (0, debug_1.debugVariablesCommand)(vars, opts)));
196
+ debug
197
+ .command("children <parents...>")
198
+ .description("Get child variables (use @ROOT for top-level)")
199
+ .option("--json", "Output as JSON")
200
+ .action((parents, opts) => (0, error_handler_1.handleErrors)(() => (0, debug_1.debugChildVariablesCommand)(parents, opts)));
201
+ // Table
202
+ program
203
+ .command("table <tableName>")
204
+ .description("Read table contents")
205
+ .option("--rows <n>", "Maximum rows", "100")
206
+ .option("--json", "Output as JSON")
207
+ .action((name, opts) => (0, error_handler_1.handleErrors)(() => (0, table_1.tableCommand)(name, opts)));
208
+ // SQL
209
+ program
210
+ .command("sql <query>")
211
+ .description("Run freestyle SQL query")
212
+ .option("--rows <n>", "Maximum rows", "100")
213
+ .option("--json", "Output as JSON")
214
+ .action((query, opts) => (0, error_handler_1.handleErrors)(() => (0, table_1.sqlCommand)(query, opts)));
215
+ // Delete
216
+ program
217
+ .command("delete <objectUrl>")
218
+ .description("Delete an ABAP object (handles lock/unlock)")
219
+ .option("-r, --transport <trkorr>", "Transport request number")
220
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, delete_1.deleteCommand)(url, opts)));
221
+ // Where-used
222
+ program
223
+ .command("whereused <objectUrl>")
224
+ .description("Find where an object is used (usage references)")
225
+ .option("-l, --line <n>", "Source line number")
226
+ .option("-c, --column <n>", "Source column number")
227
+ .option("--json", "Output as JSON")
228
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, whereused_1.whereusedCommand)(url, opts)));
229
+ // Run class (IF_OO_ADT_CLASSRUN)
230
+ program
231
+ .command("classrun <className>")
232
+ .description("Run an ABAP class implementing IF_OO_ADT_CLASSRUN")
233
+ .option("--json", "Output as JSON")
234
+ .action((name, opts) => (0, error_handler_1.handleErrors)(() => (0, run_1.runCommand)(name, opts)));
235
+ // Users
236
+ program
237
+ .command("users")
238
+ .description("List system users")
239
+ .option("--json", "Output as JSON")
240
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, users_1.usersCommand)(opts)));
241
+ // Package contents
242
+ program
243
+ .command("package <name>")
244
+ .description("List package contents")
245
+ .option("--json", "Output as JSON")
246
+ .action((name, opts) => (0, error_handler_1.handleErrors)(() => (0, package_1.packageContentsCommand)(name, opts)));
247
+ // Exec (arbitrary ABAP execution)
248
+ program
249
+ .command("exec")
250
+ .description("Execute arbitrary ABAP code via temp IF_OO_ADT_CLASSRUN class")
251
+ .option("-s, --source-file <path>", "Path to ABAP source file")
252
+ .option("-c, --code <code>", "Inline ABAP code (placed inside IF_OO_ADT_CLASSRUN~MAIN)")
253
+ .option("--json", "Output as JSON")
254
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, exec_1.execCommand)(opts)));
255
+ // Definition (go-to-definition)
256
+ program
257
+ .command("definition <objectUrl>")
258
+ .description("Find definition of a symbol at a given position")
259
+ .requiredOption("-l, --line <n>", "Source line number")
260
+ .requiredOption("--start-col <n>", "Start column of the symbol")
261
+ .requiredOption("--end-col <n>", "End column of the symbol")
262
+ .option("-s, --source-file <path>", "Source file (fetched from server if omitted)")
263
+ .option("--implementation", "Find implementation instead of definition")
264
+ .option("--main-program <name>", "Main program context")
265
+ .option("--json", "Output as JSON")
266
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, definition_1.definitionCommand)(url, opts)));
267
+ // Class info (component listing)
268
+ program
269
+ .command("classinfo <objectUrl>")
270
+ .description("List class components (methods, attributes, types, events)")
271
+ .option("--json", "Output as JSON")
272
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, classinfo_1.classinfoCommand)(url, opts)));
273
+ // Code completion
274
+ program
275
+ .command("completion <sourceUrl>")
276
+ .description("Get code completion proposals at a position")
277
+ .requiredOption("-s, --source-file <path>", "Path to source file")
278
+ .requiredOption("-l, --line <n>", "Source line number")
279
+ .requiredOption("-c, --column <n>", "Source column number")
280
+ .option("--json", "Output as JSON")
281
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, completion_1.completionCommand)(url, opts)));
282
+ // Quick fix
283
+ program
284
+ .command("quickfix <objectUrl>")
285
+ .description("Get fix proposals for a code issue at a position")
286
+ .requiredOption("-s, --source-file <path>", "Path to source file")
287
+ .requiredOption("-l, --line <n>", "Source line number")
288
+ .requiredOption("-c, --column <n>", "Source column number")
289
+ .option("--apply <index>", "Apply fix at given index")
290
+ .option("--json", "Output as JSON")
291
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, quickfix_1.quickfixCommand)(url, opts)));
292
+ // Rename
293
+ program
294
+ .command("rename <objectUrl>")
295
+ .description("Rename a symbol (evaluate → preview → execute)")
296
+ .requiredOption("-l, --line <n>", "Source line number")
297
+ .requiredOption("--start-col <n>", "Start column of the symbol")
298
+ .requiredOption("--end-col <n>", "End column of the symbol")
299
+ .requiredOption("-n, --new-name <name>", "New name for the symbol")
300
+ .option("-r, --transport <trkorr>", "Transport request number")
301
+ .option("--json", "Output as JSON")
302
+ .action((url, opts) => (0, error_handler_1.handleErrors)(() => (0, rename_1.renameCommand)(url, opts)));
303
+ // Systems (landscape file)
304
+ const systems = program.command("systems").description("SAP system landscape management");
305
+ systems
306
+ .command("list")
307
+ .description("List all systems from SAPUILandscape.xml")
308
+ .option("-l, --landscape <path>", "Path to landscape file")
309
+ .option("--urls", "Show HTTP URLs")
310
+ .action(opts => (0, error_handler_1.handleErrors)(() => (0, systems_1.systemsListCommand)(opts)));
311
+ systems
312
+ .command("search <query>")
313
+ .description("Search systems by SID or name")
314
+ .option("-l, --landscape <path>", "Path to landscape file")
315
+ .action((query, opts) => (0, error_handler_1.handleErrors)(() => (0, systems_1.systemsSearchCommand)(query, opts)));
316
+ systems
317
+ .command("status")
318
+ .description("Show active connection")
319
+ .action(() => (0, systems_1.systemsStatusCommand)());
320
+ systems
321
+ .command("connect <sid> [client]")
322
+ .description("Connect to a system and store credentials")
323
+ .option("-l, --landscape <path>", "Path to landscape file")
324
+ .option("--no-https", "Force HTTP instead of auto-detecting HTTPS")
325
+ .option("-u, --user <user>", "Username")
326
+ .option("-p, --password <password>", "Password")
327
+ .action((sid, client, opts) => (0, error_handler_1.handleErrors)(() => (0, systems_1.systemsConnectCommand)(sid, client, opts)));
328
+ systems
329
+ .command("switch <key>")
330
+ .description("Switch active connection (e.g. SE1/600)")
331
+ .action((key) => (0, systems_1.systemsSwitchCommand)(key));
332
+ systems
333
+ .command("remove <key>")
334
+ .description("Remove a stored connection")
335
+ .action((key) => (0, systems_1.systemsRemoveCommand)(key));
336
+ program.parse();
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const abap_adt_api_1 = require("abap-adt-api");
4
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
5
+ const axios = require("abap-adt-api/node_modules/axios").default || require("abap-adt-api/node_modules/axios");
6
+ async function main() {
7
+ const baseUrl = process.env.ADT_URL;
8
+ const user = process.env.ADT_USER;
9
+ const pass = process.env.ADT_PASS;
10
+ const sapClient = process.env.ADT_CLIENT || "";
11
+ const language = process.env.ADT_LANGUAGE || "EN";
12
+ const options = (0, abap_adt_api_1.createSSLConfig)(true);
13
+ const c = new abap_adt_api_1.ADTClient(baseUrl, user, pass, sapClient, language, options);
14
+ const objectUrl = "/sap/bc/adt/programs/programs/zsgr_test_42";
15
+ const sourceUrl = "/sap/bc/adt/programs/programs/zsgr_test_42/source/main";
16
+ const source = `REPORT zsgr_test_42.\n\nDATA lv_value TYPE i.\n\nBREAK-POINT.\nlv_value = 42.\nBREAK-POINT.\n\nWRITE: / 'Value of lv_value:', lv_value.\n`;
17
+ console.log("Login...");
18
+ await c.login();
19
+ console.log("CSRF token:", c.csrfToken);
20
+ console.log("Stateful...");
21
+ c.stateful = abap_adt_api_1.session_types.stateful;
22
+ console.log("Lock...");
23
+ const lock = await c.lock(objectUrl);
24
+ console.log("Lock:", lock.LOCK_HANDLE);
25
+ // Extract cookies and token from the library's internal state
26
+ const h = c.h;
27
+ const cookies = h.ascookies();
28
+ const csrf = h.csrfToken;
29
+ console.log("Cookies:", cookies);
30
+ console.log("CSRF:", csrf);
31
+ // Make the PUT using raw axios - bypass the entire library
32
+ console.log("\n--- Raw axios PUT ---");
33
+ try {
34
+ const resp = await axios({
35
+ method: "PUT",
36
+ url: `${baseUrl}${sourceUrl}`,
37
+ params: { lockHandle: lock.LOCK_HANDLE },
38
+ headers: {
39
+ "Content-Type": "text/plain; charset=utf-8",
40
+ "Cookie": cookies,
41
+ "x-csrf-token": csrf,
42
+ "X-sap-adt-sessiontype": "stateful"
43
+ },
44
+ data: source,
45
+ auth: { username: user, password: pass },
46
+ httpsAgent: options.httpsAgent,
47
+ validateStatus: () => true // Don't throw on errors
48
+ });
49
+ console.log("Status:", resp.status, resp.statusText);
50
+ console.log("Response headers:", JSON.stringify(resp.headers, null, 2).substring(0, 500));
51
+ if (resp.status >= 400) {
52
+ console.log("Body:", typeof resp.data === "string" ? resp.data.substring(0, 800) : JSON.stringify(resp.data).substring(0, 800));
53
+ }
54
+ else {
55
+ console.log("SUCCESS!");
56
+ }
57
+ }
58
+ catch (e) {
59
+ console.log("AXIOS ERROR:", e.message);
60
+ }
61
+ console.log("\nUnlock...");
62
+ try {
63
+ await c.unLock(objectUrl, lock.LOCK_HANDLE);
64
+ }
65
+ catch (_a) { }
66
+ c.stateful = abap_adt_api_1.session_types.stateless;
67
+ await c.dropSession();
68
+ }
69
+ main().catch(e => { console.error(e); process.exit(1); });
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isWindows = isWindows;
4
+ exports.encryptDPAPI = encryptDPAPI;
5
+ exports.decryptDPAPI = decryptDPAPI;
6
+ const child_process_1 = require("child_process");
7
+ function isWindows() {
8
+ return process.platform === "win32";
9
+ }
10
+ /**
11
+ * Encrypt a plaintext string using Windows DPAPI via PowerShell.
12
+ * The resulting blob is only decryptable by the same Windows user on the same machine.
13
+ * Password is passed via environment variable to avoid appearing in process list.
14
+ */
15
+ function encryptDPAPI(plaintext) {
16
+ if (!isWindows()) {
17
+ throw new Error("DPAPI encryption is only available on Windows");
18
+ }
19
+ const script = `ConvertFrom-SecureString (ConvertTo-SecureString -String $env:_DPAPI_INPUT -AsPlainText -Force)`;
20
+ const result = (0, child_process_1.execSync)(`powershell -NoProfile -Command "${script}"`, {
21
+ env: { ...process.env, _DPAPI_INPUT: plaintext },
22
+ encoding: "utf-8",
23
+ windowsHide: true,
24
+ });
25
+ return result.trim();
26
+ }
27
+ /**
28
+ * Decrypt a DPAPI-encrypted hex blob back to plaintext via PowerShell.
29
+ * Only works for the same Windows user who encrypted it.
30
+ */
31
+ function decryptDPAPI(blob) {
32
+ if (!isWindows()) {
33
+ throw new Error("DPAPI decryption is only available on Windows");
34
+ }
35
+ const script = `$s = $env:_DPAPI_INPUT | ConvertTo-SecureString; [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($s))`;
36
+ const result = (0, child_process_1.execSync)(`powershell -NoProfile -Command "${script}"`, {
37
+ env: { ...process.env, _DPAPI_INPUT: blob },
38
+ encoding: "utf-8",
39
+ windowsHide: true,
40
+ });
41
+ return result.trim();
42
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleErrors = handleErrors;
4
+ async function handleErrors(fn) {
5
+ var _a;
6
+ try {
7
+ await fn();
8
+ }
9
+ catch (e) {
10
+ if ((_a = e === null || e === void 0 ? void 0 : e.response) === null || _a === void 0 ? void 0 : _a.status) {
11
+ const status = e.response.status;
12
+ const statusText = e.response.statusText || "";
13
+ console.error(`HTTP Error ${status} ${statusText}`);
14
+ if (status === 401 || status === 403) {
15
+ console.error("Authentication failed. Check ADT_USER and ADT_PASS.");
16
+ }
17
+ if (e.response.data) {
18
+ const body = typeof e.response.data === "string"
19
+ ? e.response.data
20
+ : JSON.stringify(e.response.data);
21
+ // Extract meaningful error from XML response
22
+ const match = body.match(/<message[^>]*>([^<]+)<\/message>/i);
23
+ if (match) {
24
+ console.error(`SAP Error: ${match[1]}`);
25
+ }
26
+ else if (body.length < 1000) {
27
+ console.error(body);
28
+ }
29
+ }
30
+ }
31
+ else if (e === null || e === void 0 ? void 0 : e.message) {
32
+ console.error(`Error: ${e.message}`);
33
+ }
34
+ else {
35
+ console.error("Unknown error:", e);
36
+ }
37
+ process.exit(1);
38
+ }
39
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatTable = formatTable;
4
+ exports.output = output;
5
+ function formatTable(rows, columns) {
6
+ if (rows.length === 0)
7
+ return "(no results)";
8
+ const cols = columns || Object.keys(rows[0]);
9
+ const widths = cols.map(c => Math.max(c.length, ...rows.map(r => { var _a; return String((_a = r[c]) !== null && _a !== void 0 ? _a : "").length; })));
10
+ const header = cols.map((c, i) => c.padEnd(widths[i])).join(" | ");
11
+ const separator = widths.map(w => "-".repeat(w)).join("-+-");
12
+ const body = rows
13
+ .map(r => cols.map((c, i) => { var _a; return String((_a = r[c]) !== null && _a !== void 0 ? _a : "").padEnd(widths[i]); }).join(" | "))
14
+ .join("\n");
15
+ return `${header}\n${separator}\n${body}`;
16
+ }
17
+ function output(data, json) {
18
+ if (json) {
19
+ console.log(JSON.stringify(data, null, 2));
20
+ }
21
+ else if (typeof data === "string") {
22
+ console.log(data);
23
+ }
24
+ else {
25
+ console.log(JSON.stringify(data, null, 2));
26
+ }
27
+ }
@@ -0,0 +1,121 @@
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.findLandscapeFile = findLandscapeFile;
37
+ exports.parseLandscape = parseLandscape;
38
+ exports.resolveHostnameFQDN = resolveHostnameFQDN;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const dns = __importStar(require("dns"));
42
+ function findLandscapeFile(override) {
43
+ if (override) {
44
+ if (!fs.existsSync(override)) {
45
+ throw new Error(`Landscape file not found: ${override}`);
46
+ }
47
+ return override;
48
+ }
49
+ const candidates = [];
50
+ // Windows: %APPDATA%\SAP\Common\SAPUILandscape.xml
51
+ const appdata = process.env.APPDATA;
52
+ if (appdata) {
53
+ candidates.push(path.join(appdata, "SAP", "Common", "SAPUILandscape.xml"));
54
+ }
55
+ // Linux/Mac: ~/.sap/SAPUILandscape.xml
56
+ const home = process.env.HOME || process.env.USERPROFILE;
57
+ if (home) {
58
+ candidates.push(path.join(home, ".sap", "SAPUILandscape.xml"));
59
+ }
60
+ for (const candidate of candidates) {
61
+ if (fs.existsSync(candidate))
62
+ return candidate;
63
+ }
64
+ throw new Error(`SAPUILandscape.xml not found. Searched:\n${candidates.map(c => ` ${c}`).join("\n")}\nUse --landscape <path> to specify the file.`);
65
+ }
66
+ function parseLandscape(filePath) {
67
+ const xml = fs.readFileSync(filePath, "utf-8");
68
+ const systems = [];
69
+ // Parse <Service> elements with type="SAPGUI"
70
+ const serviceRegex = /<Service\s[^>]*type="SAPGUI"[^>]*\/>/g;
71
+ let match;
72
+ while ((match = serviceRegex.exec(xml)) !== null) {
73
+ const tag = match[0];
74
+ const sid = attr(tag, "systemid");
75
+ const name = attr(tag, "name");
76
+ const server = attr(tag, "server");
77
+ const uuid = attr(tag, "uuid");
78
+ if (!sid || !server)
79
+ continue;
80
+ const [hostname, diagPort] = server.split(":");
81
+ const instanceNr = diagPort ? diagPort.slice(-2) : "00";
82
+ const httpPort = `80${instanceNr}`;
83
+ const httpsPort = `443${instanceNr}`;
84
+ systems.push({
85
+ sid,
86
+ name: name || sid,
87
+ server,
88
+ hostname,
89
+ instanceNr,
90
+ httpUrl: `http://${hostname}:${httpPort}`,
91
+ httpsUrl: `https://${hostname}:${httpsPort}`,
92
+ uuid: uuid || ""
93
+ });
94
+ }
95
+ return systems.sort((a, b) => a.sid.localeCompare(b.sid));
96
+ }
97
+ function attr(tag, name) {
98
+ const m = tag.match(new RegExp(`${name}="([^"]*)"`, "i"));
99
+ return m ? m[1] : "";
100
+ }
101
+ /**
102
+ * Resolve a short hostname (e.g. "sapdev01") to its FQDN (e.g. "sapdev01.corp.example.com")
103
+ * via DNS forward + reverse lookup. The resolved FQDN gets baked into the URL
104
+ * stored in ~/.sap/adt-connection.json, so reverse DNS only happens once per connect.
105
+ * Falls back to the original hostname on failure.
106
+ */
107
+ async function resolveHostnameFQDN(hostname) {
108
+ // Already looks fully qualified (has dots)
109
+ if (hostname.includes("."))
110
+ return hostname;
111
+ try {
112
+ const { address } = await dns.promises.lookup(hostname);
113
+ const fqdns = await dns.promises.reverse(address);
114
+ if (fqdns.length > 0)
115
+ return fqdns[0];
116
+ }
117
+ catch (_a) {
118
+ // DNS resolution failed — fall back to original
119
+ }
120
+ return hostname;
121
+ }