@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/client.js +79 -0
- package/dist/commands/activate.js +58 -0
- package/dist/commands/atc.js +39 -0
- package/dist/commands/classinfo.js +33 -0
- package/dist/commands/completion.js +57 -0
- package/dist/commands/create.js +69 -0
- package/dist/commands/debug.js +217 -0
- package/dist/commands/definition.js +66 -0
- package/dist/commands/delete.js +36 -0
- package/dist/commands/exec.js +112 -0
- package/dist/commands/package.js +24 -0
- package/dist/commands/pretty-print.js +57 -0
- package/dist/commands/quickfix.js +78 -0
- package/dist/commands/read.js +31 -0
- package/dist/commands/rename.js +40 -0
- package/dist/commands/run.js +16 -0
- package/dist/commands/search.js +25 -0
- package/dist/commands/structure.js +39 -0
- package/dist/commands/syntax.js +75 -0
- package/dist/commands/systems.js +514 -0
- package/dist/commands/table.js +65 -0
- package/dist/commands/test.js +100 -0
- package/dist/commands/transport.js +110 -0
- package/dist/commands/users.js +19 -0
- package/dist/commands/whereused.js +30 -0
- package/dist/commands/write.js +131 -0
- package/dist/diag-debug.js +47 -0
- package/dist/diag-raw.js +144 -0
- package/dist/diag-write.js +42 -0
- package/dist/index.js +336 -0
- package/dist/test-write.js +69 -0
- package/dist/util/credentials.js +42 -0
- package/dist/util/error-handler.js +39 -0
- package/dist/util/formatter.js +27 -0
- package/dist/util/landscape.js +121 -0
- package/dist/util/network.js +112 -0
- package/package.json +24 -0
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
|
+
}
|