sap-adt-mcp 0.7.1
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/LICENSE +21 -0
- package/README.md +527 -0
- package/config.example.json +32 -0
- package/package.json +55 -0
- package/src/adt-client.js +278 -0
- package/src/adt-error.js +135 -0
- package/src/config.js +78 -0
- package/src/data-preview.js +148 -0
- package/src/diff.js +123 -0
- package/src/dump-feed.js +251 -0
- package/src/lock.js +52 -0
- package/src/node-structure.js +56 -0
- package/src/object-create.js +244 -0
- package/src/object-references.js +28 -0
- package/src/object-uris.js +156 -0
- package/src/prompts.js +533 -0
- package/src/result.js +23 -0
- package/src/server.js +206 -0
- package/src/tools/_shared.js +11 -0
- package/src/tools/cds.js +157 -0
- package/src/tools/connection.js +46 -0
- package/src/tools/cross-system.js +191 -0
- package/src/tools/data.js +86 -0
- package/src/tools/discovery.js +520 -0
- package/src/tools/jobs.js +107 -0
- package/src/tools/lifecycle.js +314 -0
- package/src/tools/notes.js +147 -0
- package/src/tools/quality.js +407 -0
- package/src/tools/rap.js +287 -0
- package/src/tools/request.js +103 -0
- package/src/tools/runtime.js +244 -0
- package/src/tools/source.js +622 -0
- package/src/tools/transports.js +163 -0
- package/src/tools/versions.js +154 -0
- package/src/tools/worklist.js +112 -0
- package/src/xml.js +8 -0
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// Build the POST request needed to create a new ABAP object via ADT.
|
|
2
|
+
//
|
|
3
|
+
// Returns { path, contentType, body } so the server handler just dispatches it.
|
|
4
|
+
//
|
|
5
|
+
// Each ADT object kind has its own collection endpoint, content-type, and XML
|
|
6
|
+
// shape. The shapes here cover the common modern (NW 7.5x+ / S/4) on-prem
|
|
7
|
+
// surface; older systems may reject some content-types. If yours does, fall
|
|
8
|
+
// back to adt_request and craft the POST manually.
|
|
9
|
+
|
|
10
|
+
import { normalizeType } from "./object-uris.js";
|
|
11
|
+
|
|
12
|
+
export function buildCreateRequest({
|
|
13
|
+
type,
|
|
14
|
+
name,
|
|
15
|
+
package: pkg,
|
|
16
|
+
description,
|
|
17
|
+
group,
|
|
18
|
+
programType,
|
|
19
|
+
responsible,
|
|
20
|
+
}) {
|
|
21
|
+
if (!name || typeof name !== "string") {
|
|
22
|
+
throw new Error("Object create: `name` is required");
|
|
23
|
+
}
|
|
24
|
+
if (!pkg || typeof pkg !== "string") {
|
|
25
|
+
throw new Error("Object create: `package` is required");
|
|
26
|
+
}
|
|
27
|
+
const t = normalizeType(type);
|
|
28
|
+
const upperName = name.toUpperCase();
|
|
29
|
+
const upperPkg = pkg.toUpperCase();
|
|
30
|
+
const desc = (description ?? upperName).slice(0, 60);
|
|
31
|
+
const respAttr = responsible
|
|
32
|
+
? ` adtcore:responsible="${escapeXml(responsible.toUpperCase())}"`
|
|
33
|
+
: "";
|
|
34
|
+
|
|
35
|
+
switch (t) {
|
|
36
|
+
case "PROG":
|
|
37
|
+
return {
|
|
38
|
+
path: "/sap/bc/adt/programs/programs",
|
|
39
|
+
contentType: "application/vnd.sap.adt.programs.programs.v2+xml",
|
|
40
|
+
body: xmlDecl() +
|
|
41
|
+
`<program:abapProgram xmlns:program="http://www.sap.com/adt/programs/programs"` +
|
|
42
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
43
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="PROG/P"` +
|
|
44
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}` +
|
|
45
|
+
// programType is whitelisted to known ADT values; anything else
|
|
46
|
+
// would either be rejected by SAP or, if it contained a stray
|
|
47
|
+
// double-quote, let the caller close the attribute and inject
|
|
48
|
+
// arbitrary XML attributes / elements (e.g. a second packageRef
|
|
49
|
+
// pointing at a different package than the one the user asked for).
|
|
50
|
+
` program:programType="${escapeXml(validateProgramType(programType))}">` +
|
|
51
|
+
packageRef(upperPkg) +
|
|
52
|
+
`</program:abapProgram>`,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
case "CLAS":
|
|
56
|
+
return {
|
|
57
|
+
path: "/sap/bc/adt/oo/classes",
|
|
58
|
+
contentType: "application/vnd.sap.adt.oo.classes.v3+xml",
|
|
59
|
+
body: xmlDecl() +
|
|
60
|
+
`<class:abapClass xmlns:class="http://www.sap.com/adt/oo/classes"` +
|
|
61
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
62
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="CLAS/OC"` +
|
|
63
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}` +
|
|
64
|
+
` class:final="true" class:visibility="public" class:abstract="false"` +
|
|
65
|
+
` class:category="generalObjectType">` +
|
|
66
|
+
packageRef(upperPkg) +
|
|
67
|
+
`</class:abapClass>`,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
case "INTF":
|
|
71
|
+
return {
|
|
72
|
+
path: "/sap/bc/adt/oo/interfaces",
|
|
73
|
+
contentType: "application/vnd.sap.adt.oo.interfaces.v2+xml",
|
|
74
|
+
body: xmlDecl() +
|
|
75
|
+
`<intf:abapInterface xmlns:intf="http://www.sap.com/adt/oo/interfaces"` +
|
|
76
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
77
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="INTF/OI"` +
|
|
78
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
79
|
+
packageRef(upperPkg) +
|
|
80
|
+
`</intf:abapInterface>`,
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
case "INCL":
|
|
84
|
+
return {
|
|
85
|
+
path: "/sap/bc/adt/programs/includes",
|
|
86
|
+
contentType: "application/vnd.sap.adt.programs.includes.v2+xml",
|
|
87
|
+
body: xmlDecl() +
|
|
88
|
+
`<include:abapInclude xmlns:include="http://www.sap.com/adt/programs/includes"` +
|
|
89
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
90
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="PROG/I"` +
|
|
91
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
92
|
+
packageRef(upperPkg) +
|
|
93
|
+
`</include:abapInclude>`,
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
case "FUGR":
|
|
97
|
+
return {
|
|
98
|
+
path: "/sap/bc/adt/functions/groups",
|
|
99
|
+
contentType: "application/vnd.sap.adt.functions.groups.v3+xml",
|
|
100
|
+
body: xmlDecl() +
|
|
101
|
+
`<group:abapFunctionGroup xmlns:group="http://www.sap.com/adt/functions/groups"` +
|
|
102
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
103
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="FUGR/F"` +
|
|
104
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
105
|
+
packageRef(upperPkg) +
|
|
106
|
+
`</group:abapFunctionGroup>`,
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
case "FUGR/FF": {
|
|
110
|
+
if (!group) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
"Function module create: `group` (function group name) is required"
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
const upperGroup = group.toUpperCase();
|
|
116
|
+
const lowerGroup = group.toLowerCase();
|
|
117
|
+
return {
|
|
118
|
+
path: `/sap/bc/adt/functions/groups/${encodeURIComponent(lowerGroup)}/fmodules`,
|
|
119
|
+
contentType: "application/vnd.sap.adt.functions.fmodules.v3+xml",
|
|
120
|
+
body: xmlDecl() +
|
|
121
|
+
`<fm:abapFunctionModule xmlns:fm="http://www.sap.com/adt/functions/fmodules"` +
|
|
122
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
123
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="FUGR/FF"` +
|
|
124
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
125
|
+
`<fm:containerRef adtcore:uri="/sap/bc/adt/functions/groups/${escapeXml(lowerGroup)}"` +
|
|
126
|
+
` adtcore:type="FUGR/F" adtcore:name="${escapeXml(upperGroup)}"/>` +
|
|
127
|
+
`</fm:abapFunctionModule>`,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
case "DDLS":
|
|
132
|
+
return {
|
|
133
|
+
path: "/sap/bc/adt/ddic/ddl/sources",
|
|
134
|
+
contentType: "application/vnd.sap.adt.ddlsource.v2+xml",
|
|
135
|
+
body: xmlDecl() +
|
|
136
|
+
`<ddl:source xmlns:ddl="http://www.sap.com/adt/ddic/ddlsources"` +
|
|
137
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
138
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="DDLS/DF"` +
|
|
139
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
140
|
+
packageRef(upperPkg) +
|
|
141
|
+
`</ddl:source>`,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
case "DCLS":
|
|
145
|
+
return {
|
|
146
|
+
path: "/sap/bc/adt/acm/dcls",
|
|
147
|
+
contentType: "application/vnd.sap.adt.acm.dcls.v2+xml",
|
|
148
|
+
body: xmlDecl() +
|
|
149
|
+
`<dcl:source xmlns:dcl="http://www.sap.com/adt/acm/dcls"` +
|
|
150
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
151
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="DCLS/DL"` +
|
|
152
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
153
|
+
packageRef(upperPkg) +
|
|
154
|
+
`</dcl:source>`,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
case "DDLX":
|
|
158
|
+
return {
|
|
159
|
+
path: "/sap/bc/adt/ddic/ddlx/sources",
|
|
160
|
+
contentType: "application/vnd.sap.adt.ddlxsource.v2+xml",
|
|
161
|
+
body: xmlDecl() +
|
|
162
|
+
`<ddlx:source xmlns:ddlx="http://www.sap.com/adt/ddic/ddlxsources"` +
|
|
163
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
164
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="DDLX/EX"` +
|
|
165
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
166
|
+
packageRef(upperPkg) +
|
|
167
|
+
`</ddlx:source>`,
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
case "BDEF":
|
|
171
|
+
return {
|
|
172
|
+
path: "/sap/bc/adt/bo/behaviordefinitions",
|
|
173
|
+
contentType: "application/vnd.sap.adt.bo.bdef.v2+xml",
|
|
174
|
+
body: xmlDecl() +
|
|
175
|
+
`<bdef:behaviorDefinition xmlns:bdef="http://www.sap.com/adt/bo/bdef"` +
|
|
176
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
177
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="BDEF/BO"` +
|
|
178
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
179
|
+
packageRef(upperPkg) +
|
|
180
|
+
`</bdef:behaviorDefinition>`,
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
case "MSAG":
|
|
184
|
+
return {
|
|
185
|
+
path: "/sap/bc/adt/messageclasses",
|
|
186
|
+
contentType: "application/vnd.sap.adt.messageclass.v2+xml",
|
|
187
|
+
body: xmlDecl() +
|
|
188
|
+
`<msag:messageClass xmlns:msag="http://www.sap.com/adt/messageclasses"` +
|
|
189
|
+
` xmlns:adtcore="http://www.sap.com/adt/core"` +
|
|
190
|
+
` adtcore:name="${escapeXml(upperName)}" adtcore:type="MSAG/N"` +
|
|
191
|
+
` adtcore:description="${escapeXml(desc)}"${respAttr}>` +
|
|
192
|
+
packageRef(upperPkg) +
|
|
193
|
+
`</msag:messageClass>`,
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
default:
|
|
197
|
+
throw new Error(
|
|
198
|
+
`Object create not supported for type: ${type} (normalized: ${t}). ` +
|
|
199
|
+
"Use adt_request to POST to the relevant ADT collection endpoint."
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function xmlDecl() {
|
|
205
|
+
return `<?xml version="1.0" encoding="UTF-8"?>`;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function packageRef(pkg) {
|
|
209
|
+
return `<adtcore:packageRef adtcore:name="${escapeXml(pkg)}"/>`;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function escapeXml(s) {
|
|
213
|
+
return String(s)
|
|
214
|
+
.replace(/&/g, "&")
|
|
215
|
+
.replace(/</g, "<")
|
|
216
|
+
.replace(/>/g, ">")
|
|
217
|
+
.replace(/"/g, """)
|
|
218
|
+
.replace(/'/g, "'");
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// SAP's published ADT values for program:programType. Anything outside this
|
|
222
|
+
// set is rejected so a caller can't smuggle XML attribute terminators into
|
|
223
|
+
// the attribute value (defense in depth — escapeXml at the call site already
|
|
224
|
+
// handles quoting).
|
|
225
|
+
const ALLOWED_PROGRAM_TYPES = new Set([
|
|
226
|
+
"executableProgram",
|
|
227
|
+
"modulePool",
|
|
228
|
+
"subroutinePool",
|
|
229
|
+
"functionGroup",
|
|
230
|
+
"interfacePool",
|
|
231
|
+
"classPool",
|
|
232
|
+
"typeGroup",
|
|
233
|
+
"include",
|
|
234
|
+
]);
|
|
235
|
+
|
|
236
|
+
function validateProgramType(programType) {
|
|
237
|
+
if (programType == null) return "executableProgram";
|
|
238
|
+
if (typeof programType !== "string" || !ALLOWED_PROGRAM_TYPES.has(programType)) {
|
|
239
|
+
throw new Error(
|
|
240
|
+
`Invalid programType: ${programType}. Allowed: ${[...ALLOWED_PROGRAM_TYPES].join(", ")}`
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
return programType;
|
|
244
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Parse <adtcore:objectReference .../> entries that appear in many ADT responses
|
|
2
|
+
// (search results, where-used, transport contents, etc.).
|
|
3
|
+
|
|
4
|
+
const REF_RE = /<adtcore:objectReference\b([\s\S]*?)\/>/gi;
|
|
5
|
+
const ATTR_RE = /(\w[\w:-]*)\s*=\s*"([^"]*)"/g;
|
|
6
|
+
|
|
7
|
+
export function parseObjectReferences(xml) {
|
|
8
|
+
if (typeof xml !== "string") return [];
|
|
9
|
+
const out = [];
|
|
10
|
+
for (const m of xml.matchAll(REF_RE)) {
|
|
11
|
+
const attrs = {};
|
|
12
|
+
for (const a of m[1].matchAll(ATTR_RE)) {
|
|
13
|
+
const key = a[1].replace(/^adtcore:/, "");
|
|
14
|
+
attrs[key] = decodeEntities(a[2]);
|
|
15
|
+
}
|
|
16
|
+
if (attrs.name || attrs.uri) out.push(attrs);
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function decodeEntities(s) {
|
|
22
|
+
return s
|
|
23
|
+
.replace(/</g, "<")
|
|
24
|
+
.replace(/>/g, ">")
|
|
25
|
+
.replace(/"/g, '"')
|
|
26
|
+
.replace(/'/g, "'")
|
|
27
|
+
.replace(/&/g, "&");
|
|
28
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// Map ABAP object identifiers (name + type) to ADT URIs.
|
|
2
|
+
//
|
|
3
|
+
// Accepts either friendly type aliases (program / class / interface / ...) or
|
|
4
|
+
// raw TADIR-style codes (PROG / CLAS / INTF / FUGR / FUGR/FF / INCL).
|
|
5
|
+
// Function modules need a function group: pass `{ type: "function", name, group }`.
|
|
6
|
+
//
|
|
7
|
+
// Object URI = the ADT object resource (used for lock/unlock and metadata GET).
|
|
8
|
+
// Source URI = the editable source document (used for source GET/PUT).
|
|
9
|
+
// Some objects (classes) have multiple source includes — `include` selects which.
|
|
10
|
+
|
|
11
|
+
const TYPE_ALIASES = {
|
|
12
|
+
program: "PROG",
|
|
13
|
+
prog: "PROG",
|
|
14
|
+
report: "PROG",
|
|
15
|
+
include: "INCL",
|
|
16
|
+
incl: "INCL",
|
|
17
|
+
class: "CLAS",
|
|
18
|
+
clas: "CLAS",
|
|
19
|
+
interface: "INTF",
|
|
20
|
+
intf: "INTF",
|
|
21
|
+
function: "FUGR/FF",
|
|
22
|
+
functionmodule: "FUGR/FF",
|
|
23
|
+
fm: "FUGR/FF",
|
|
24
|
+
functiongroup: "FUGR",
|
|
25
|
+
fugr: "FUGR",
|
|
26
|
+
table: "TABL",
|
|
27
|
+
tabl: "TABL",
|
|
28
|
+
structure: "TABL",
|
|
29
|
+
dataelement: "DTEL",
|
|
30
|
+
dtel: "DTEL",
|
|
31
|
+
domain: "DOMA",
|
|
32
|
+
doma: "DOMA",
|
|
33
|
+
cds: "DDLS",
|
|
34
|
+
ddls: "DDLS",
|
|
35
|
+
accesscontrol: "DCLS",
|
|
36
|
+
dcls: "DCLS",
|
|
37
|
+
metadataextension: "DDLX",
|
|
38
|
+
metadataext: "DDLX",
|
|
39
|
+
ddlx: "DDLX",
|
|
40
|
+
behaviordef: "BDEF",
|
|
41
|
+
behaviordefinition: "BDEF",
|
|
42
|
+
bdef: "BDEF",
|
|
43
|
+
servicedefinition: "SRVD",
|
|
44
|
+
servicedef: "SRVD",
|
|
45
|
+
srvd: "SRVD",
|
|
46
|
+
servicebinding: "SRVB",
|
|
47
|
+
srvb: "SRVB",
|
|
48
|
+
messageclass: "MSAG",
|
|
49
|
+
msag: "MSAG",
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const CLASS_INCLUDES = {
|
|
53
|
+
main: "main",
|
|
54
|
+
definitions: "definitions",
|
|
55
|
+
defs: "definitions",
|
|
56
|
+
implementations: "implementations",
|
|
57
|
+
imps: "implementations",
|
|
58
|
+
macros: "macros",
|
|
59
|
+
testclasses: "testclasses",
|
|
60
|
+
tests: "testclasses",
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export function normalizeType(input) {
|
|
64
|
+
if (typeof input !== "string" || input.length === 0) {
|
|
65
|
+
throw new Error("Object type is required");
|
|
66
|
+
}
|
|
67
|
+
const upper = input.toUpperCase();
|
|
68
|
+
if (upper.includes("/")) return upper;
|
|
69
|
+
const aliased = TYPE_ALIASES[input.toLowerCase()];
|
|
70
|
+
return aliased ?? upper;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function objectUri({ type, name, group }) {
|
|
74
|
+
const t = normalizeType(type);
|
|
75
|
+
const n = name.toLowerCase();
|
|
76
|
+
switch (t) {
|
|
77
|
+
case "PROG":
|
|
78
|
+
return `/sap/bc/adt/programs/programs/${enc(n)}`;
|
|
79
|
+
case "INCL":
|
|
80
|
+
return `/sap/bc/adt/programs/includes/${enc(n)}`;
|
|
81
|
+
case "CLAS":
|
|
82
|
+
return `/sap/bc/adt/oo/classes/${enc(n)}`;
|
|
83
|
+
case "INTF":
|
|
84
|
+
return `/sap/bc/adt/oo/interfaces/${enc(n)}`;
|
|
85
|
+
case "FUGR":
|
|
86
|
+
return `/sap/bc/adt/functions/groups/${enc(n)}`;
|
|
87
|
+
case "FUGR/FF": {
|
|
88
|
+
if (!group) {
|
|
89
|
+
throw new Error(
|
|
90
|
+
`Function module '${name}': pass 'group' (the function group name)`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
return `/sap/bc/adt/functions/groups/${enc(group.toLowerCase())}/fmodules/${enc(n)}`;
|
|
94
|
+
}
|
|
95
|
+
case "FUGR/I": {
|
|
96
|
+
if (!group) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
`Function group include '${name}': pass 'group' (the function group name)`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return `/sap/bc/adt/functions/groups/${enc(group.toLowerCase())}/includes/${enc(n)}`;
|
|
102
|
+
}
|
|
103
|
+
case "TABL":
|
|
104
|
+
return `/sap/bc/adt/ddic/tables/${enc(n)}`;
|
|
105
|
+
case "DTEL":
|
|
106
|
+
return `/sap/bc/adt/ddic/dataelements/${enc(n)}`;
|
|
107
|
+
case "DOMA":
|
|
108
|
+
return `/sap/bc/adt/ddic/domains/${enc(n)}`;
|
|
109
|
+
case "DDLS":
|
|
110
|
+
return `/sap/bc/adt/ddic/ddl/sources/${enc(n)}`;
|
|
111
|
+
case "DCLS":
|
|
112
|
+
return `/sap/bc/adt/acm/dcls/${enc(n)}`;
|
|
113
|
+
case "DDLX":
|
|
114
|
+
return `/sap/bc/adt/ddic/ddlx/sources/${enc(n)}`;
|
|
115
|
+
case "BDEF":
|
|
116
|
+
return `/sap/bc/adt/bo/behaviordefinitions/${enc(n)}`;
|
|
117
|
+
case "SRVD":
|
|
118
|
+
return `/sap/bc/adt/ddic/srvd/sources/${enc(n)}`;
|
|
119
|
+
case "SRVB":
|
|
120
|
+
return `/sap/bc/adt/businessservices/bindings/${enc(n)}`;
|
|
121
|
+
case "MSAG":
|
|
122
|
+
return `/sap/bc/adt/messageclasses/${enc(n)}`;
|
|
123
|
+
default:
|
|
124
|
+
throw new Error(`Unsupported object type: ${type} (normalized: ${t})`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function sourceUri({ type, name, group, include }) {
|
|
129
|
+
const t = normalizeType(type);
|
|
130
|
+
const base = objectUri({ type: t, name, group });
|
|
131
|
+
|
|
132
|
+
if (t === "CLAS") {
|
|
133
|
+
const inc = include ? CLASS_INCLUDES[include.toLowerCase()] : "main";
|
|
134
|
+
if (!inc) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Unknown class include '${include}'. Use one of: ${Object.keys(CLASS_INCLUDES).join(", ")}`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
return inc === "main"
|
|
140
|
+
? `${base}/source/main`
|
|
141
|
+
: `${base}/includes/${inc}`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// DDIC primitives have no separate source endpoint in the form X/source/main.
|
|
145
|
+
// Tables, data elements, domains and message classes expose object metadata
|
|
146
|
+
// via the object URI directly, returned as XML. CDS / DCLS / DDLX / BDEF do
|
|
147
|
+
// use /source/main.
|
|
148
|
+
if (t === "DTEL" || t === "DOMA" || t === "MSAG") return base;
|
|
149
|
+
if (t === "TABL") return `${base}/source/main`;
|
|
150
|
+
|
|
151
|
+
return `${base}/source/main`;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function enc(s) {
|
|
155
|
+
return encodeURIComponent(s);
|
|
156
|
+
}
|