@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.
- package/README.md +384 -0
- package/dist/adt-client.js +364 -0
- package/dist/cli/activate.js +113 -0
- package/dist/cli/init.js +333 -0
- package/dist/cli/remove.js +80 -0
- package/dist/cli/status.js +229 -0
- package/dist/cli/systems.js +68 -0
- package/dist/cli.js +81 -0
- package/dist/index.js +1318 -0
- package/dist/knowledge/abap/abap-dictionary.md +199 -0
- package/dist/knowledge/abap/abap-sql.md +296 -0
- package/dist/knowledge/abap/amdp.md +273 -0
- package/dist/knowledge/abap/clean-code.md +293 -0
- package/dist/knowledge/abap/cloud-background-processing.md +250 -0
- package/dist/knowledge/abap/cloud-communication.md +265 -0
- package/dist/knowledge/abap/cloud-development.md +176 -0
- package/dist/knowledge/abap/cloud-extensibility.md +252 -0
- package/dist/knowledge/abap/cloud-released-apis.md +261 -0
- package/dist/knowledge/abap/constructor-expressions.md +289 -0
- package/dist/knowledge/abap/enhancements.md +232 -0
- package/dist/knowledge/abap/exceptions.md +271 -0
- package/dist/knowledge/abap/internal-tables.md +205 -0
- package/dist/knowledge/abap/object-orientation.md +298 -0
- package/dist/knowledge/abap/performance.md +216 -0
- package/dist/knowledge/abap/rap-abstract-entities.md +206 -0
- package/dist/knowledge/abap/rap-business-events.md +216 -0
- package/dist/knowledge/abap/rap-draft.md +191 -0
- package/dist/knowledge/abap/rap-eml.md +453 -0
- package/dist/knowledge/abap/rap-end-to-end.md +486 -0
- package/dist/knowledge/abap/rap-feature-control.md +185 -0
- package/dist/knowledge/abap/rap-numbering.md +280 -0
- package/dist/knowledge/abap/rap-service-exposure.md +163 -0
- package/dist/knowledge/abap/rap-unmanaged.md +468 -0
- package/dist/knowledge/abap/string-processing.md +180 -0
- package/dist/knowledge/abap/unit-testing.md +303 -0
- package/dist/knowledge/abap-cds/access-control.md +241 -0
- package/dist/knowledge/abap-cds/annotations.md +331 -0
- package/dist/knowledge/abap-cds/associations.md +254 -0
- package/dist/knowledge/abap-cds/expressions.md +230 -0
- package/dist/knowledge/abap-cds/functions.md +245 -0
- package/dist/knowledge/abap-cds/metadata-extensions.md +294 -0
- package/dist/knowledge/cap/authentication.md +278 -0
- package/dist/knowledge/cap/cdl-syntax.md +247 -0
- package/dist/knowledge/cap/cql-queries.md +266 -0
- package/dist/knowledge/cap/deployment.md +343 -0
- package/dist/knowledge/cap/event-handlers.md +287 -0
- package/dist/knowledge/cap/fiori-integration.md +303 -0
- package/dist/knowledge/cap/service-definitions.md +287 -0
- package/dist/knowledge/fiori/annotations.md +347 -0
- package/dist/knowledge/fiori/deployment.md +340 -0
- package/dist/knowledge/fiori/fiori-elements.md +332 -0
- package/dist/knowledge/fiori/fiori-side-effects.md +107 -0
- package/dist/knowledge/fiori/fiori-valuelist.md +144 -0
- package/dist/knowledge/fiori/ui5-controllers.md +358 -0
- package/dist/knowledge/fiori/ui5-data-binding.md +311 -0
- package/dist/knowledge/fiori/ui5-fragments-dialogs.md +330 -0
- package/dist/knowledge/fiori/ui5-manifest.md +411 -0
- package/dist/knowledge/fiori/ui5-routing.md +303 -0
- package/dist/knowledge/fiori/ui5-xml-views.md +294 -0
- package/dist/logger.js +114 -0
- package/dist/system-profile.js +207 -0
- package/dist/tools/abap-doc.js +72 -0
- package/dist/tools/abapgit.js +161 -0
- package/dist/tools/activate.js +68 -0
- package/dist/tools/atc-check.js +117 -0
- package/dist/tools/auth-object.js +56 -0
- package/dist/tools/breakpoints.js +76 -0
- package/dist/tools/call-hierarchy.js +84 -0
- package/dist/tools/cds-annotations.js +98 -0
- package/dist/tools/cds-dependencies.js +65 -0
- package/dist/tools/check.js +47 -0
- package/dist/tools/code-completion.js +70 -0
- package/dist/tools/code-coverage.js +111 -0
- package/dist/tools/create-amdp.js +111 -0
- package/dist/tools/create-dcl.js +81 -0
- package/dist/tools/create-transport.js +38 -0
- package/dist/tools/create.js +285 -0
- package/dist/tools/data-preview.js +37 -0
- package/dist/tools/delete.js +45 -0
- package/dist/tools/deploy-bsp.js +298 -0
- package/dist/tools/discovery.js +59 -0
- package/dist/tools/element-info.js +93 -0
- package/dist/tools/enhancements.js +186 -0
- package/dist/tools/extract-method.js +44 -0
- package/dist/tools/function-group.js +59 -0
- package/dist/tools/knowledge.js +275 -0
- package/dist/tools/lock-object.js +75 -0
- package/dist/tools/message-class.js +67 -0
- package/dist/tools/navigate.js +80 -0
- package/dist/tools/number-range.js +57 -0
- package/dist/tools/object-documentation.js +43 -0
- package/dist/tools/object-structure.js +78 -0
- package/dist/tools/object-versions.js +57 -0
- package/dist/tools/package-contents.js +60 -0
- package/dist/tools/pretty-printer.js +35 -0
- package/dist/tools/publish-binding.js +49 -0
- package/dist/tools/quick-fix.js +69 -0
- package/dist/tools/read.js +167 -0
- package/dist/tools/refactor-rename.js +60 -0
- package/dist/tools/release-transport.js +24 -0
- package/dist/tools/released-apis.js +51 -0
- package/dist/tools/repository-tree.js +90 -0
- package/dist/tools/scaffold-rap.js +642 -0
- package/dist/tools/search.js +73 -0
- package/dist/tools/shared/data-format.js +101 -0
- package/dist/tools/sql-console.js +17 -0
- package/dist/tools/system-info.js +270 -0
- package/dist/tools/traces.js +66 -0
- package/dist/tools/transport-contents.js +83 -0
- package/dist/tools/transports.js +67 -0
- package/dist/tools/unit-test.js +135 -0
- package/dist/tools/where-used.js +59 -0
- package/dist/tools/write.js +101 -0
- package/package.json +49 -0
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.abapCreateTool = void 0;
|
|
4
|
+
exports.abapCreate = abapCreate;
|
|
5
|
+
const adt_client_js_1 = require("../adt-client.js");
|
|
6
|
+
// Content-Types para criação — S/4HANA (v2/v3) com fallback para ECC (v1)
|
|
7
|
+
const CONTENT_TYPE = {
|
|
8
|
+
"PROG/P": ["application/vnd.sap.adt.programs.programs.v2+xml"],
|
|
9
|
+
"CLAS/OC": ["application/vnd.sap.adt.oo.classes.v2+xml"],
|
|
10
|
+
"INTF/OI": ["application/vnd.sap.adt.oo.interfaces.v2+xml"],
|
|
11
|
+
"FUGR/F": ["application/vnd.sap.adt.functions.groups.v3+xml", "application/vnd.sap.adt.functions.groups.v2+xml"],
|
|
12
|
+
"DOMA/D": ["application/vnd.sap.adt.domains.v2+xml"],
|
|
13
|
+
"DTEL/D": ["application/vnd.sap.adt.dataelements.v2+xml", "application/vnd.sap.adt.dataelements.v1+xml"],
|
|
14
|
+
"TABL/DT": ["application/vnd.sap.adt.tables.v2+xml"],
|
|
15
|
+
"TABL/DS": ["application/vnd.sap.adt.structures.v2+xml"],
|
|
16
|
+
"TTYP/TT": ["application/vnd.sap.adt.tabletype.v1+xml"],
|
|
17
|
+
"MSAG/N": ["application/vnd.sap.adt.messageclass.v2+xml", "application/vnd.sap.adt.messageclass.v1+xml"],
|
|
18
|
+
"DDLS/DF": ["application/vnd.sap.adt.ddlSource+xml"],
|
|
19
|
+
"DDLX/MX": ["application/vnd.sap.adt.ddic.ddlx.v1+xml"],
|
|
20
|
+
"SRVD/SRV": ["application/vnd.sap.adt.ddic.srvd.v1+xml"],
|
|
21
|
+
"BDEF/BDO": ["application/vnd.sap.adt.blues.v1+xml"],
|
|
22
|
+
"SRVB/SVB": ["application/vnd.sap.adt.businessservices.servicebinding.v2+xml"],
|
|
23
|
+
};
|
|
24
|
+
const PROGRAM_TYPE = {
|
|
25
|
+
"PROG/P": "executableProgram",
|
|
26
|
+
};
|
|
27
|
+
function buildPayload(input) {
|
|
28
|
+
const { object_type, object_name, description, package: pkg = "$TMP", srvd_name, binding_type = "ODATA;V4;UI" } = input;
|
|
29
|
+
const name = object_name.toUpperCase();
|
|
30
|
+
switch (object_type) {
|
|
31
|
+
case "PROG/P":
|
|
32
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
33
|
+
<program:abapProgram
|
|
34
|
+
xmlns:program="http://www.sap.com/adt/programs/programs"
|
|
35
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
36
|
+
adtcore:description="${description}"
|
|
37
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
38
|
+
adtcore:name="${name}"
|
|
39
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}"
|
|
40
|
+
program:programType="${PROGRAM_TYPE[object_type]}">
|
|
41
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
42
|
+
</program:abapProgram>`;
|
|
43
|
+
case "CLAS/OC":
|
|
44
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
45
|
+
<class:abapClass
|
|
46
|
+
xmlns:class="http://www.sap.com/adt/oo/classes"
|
|
47
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
48
|
+
adtcore:description="${description}"
|
|
49
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
50
|
+
adtcore:name="${name}"
|
|
51
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
52
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
53
|
+
</class:abapClass>`;
|
|
54
|
+
case "INTF/OI":
|
|
55
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
56
|
+
<intf:abapInterface
|
|
57
|
+
xmlns:intf="http://www.sap.com/adt/oo/interfaces"
|
|
58
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
59
|
+
adtcore:description="${description}"
|
|
60
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
61
|
+
adtcore:name="${name}"
|
|
62
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
63
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
64
|
+
</intf:abapInterface>`;
|
|
65
|
+
case "FUGR/F":
|
|
66
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
67
|
+
<group:abapFunctionGroup
|
|
68
|
+
xmlns:group="http://www.sap.com/adt/functions/groups"
|
|
69
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
70
|
+
adtcore:description="${description}"
|
|
71
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
72
|
+
adtcore:name="${name}"
|
|
73
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
74
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
75
|
+
</group:abapFunctionGroup>`;
|
|
76
|
+
case "DOMA/D":
|
|
77
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
78
|
+
<domain:domain
|
|
79
|
+
xmlns:domain="http://www.sap.com/dictionary/domain"
|
|
80
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
81
|
+
adtcore:description="${description}"
|
|
82
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
83
|
+
adtcore:name="${name}"
|
|
84
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
85
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
86
|
+
</domain:domain>`;
|
|
87
|
+
case "DTEL/D":
|
|
88
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
89
|
+
<dtel:wbobj
|
|
90
|
+
xmlns:dtel="http://www.sap.com/wbobj/dictionary/dtel"
|
|
91
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
92
|
+
adtcore:description="${description}"
|
|
93
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
94
|
+
adtcore:name="${name}"
|
|
95
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
96
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
97
|
+
</dtel:wbobj>`;
|
|
98
|
+
case "TABL/DT":
|
|
99
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
100
|
+
<blue:blueSource
|
|
101
|
+
xmlns:blue="http://www.sap.com/wbobj/blue"
|
|
102
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
103
|
+
adtcore:description="${description}"
|
|
104
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
105
|
+
adtcore:name="${name}"
|
|
106
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
107
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
108
|
+
</blue:blueSource>`;
|
|
109
|
+
case "TABL/DS":
|
|
110
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
111
|
+
<blue:blueSource
|
|
112
|
+
xmlns:blue="http://www.sap.com/wbobj/blue"
|
|
113
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
114
|
+
adtcore:description="${description}"
|
|
115
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
116
|
+
adtcore:name="${name}"
|
|
117
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
118
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
119
|
+
</blue:blueSource>`;
|
|
120
|
+
case "TTYP/TT":
|
|
121
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
122
|
+
<tabletype:tableType
|
|
123
|
+
xmlns:tabletype="http://www.sap.com/dictionary/tabletype"
|
|
124
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
125
|
+
adtcore:description="${description}"
|
|
126
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
127
|
+
adtcore:name="${name}"
|
|
128
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
129
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
130
|
+
</tabletype:tableType>`;
|
|
131
|
+
case "MSAG/N":
|
|
132
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
133
|
+
<mc:messageClass
|
|
134
|
+
xmlns:mc="http://www.sap.com/adt/MessageClass"
|
|
135
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
136
|
+
adtcore:description="${description}"
|
|
137
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
138
|
+
adtcore:name="${name}"
|
|
139
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
140
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
141
|
+
</mc:messageClass>`;
|
|
142
|
+
case "DDLS/DF":
|
|
143
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
144
|
+
<ddlSource:ddlSource
|
|
145
|
+
xmlns:ddlSource="http://www.sap.com/adt/ddic/ddlsources"
|
|
146
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
147
|
+
adtcore:description="${description}"
|
|
148
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
149
|
+
adtcore:name="${name}"
|
|
150
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
151
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
152
|
+
</ddlSource:ddlSource>`;
|
|
153
|
+
case "DDLX/MX":
|
|
154
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
155
|
+
<ddlxSource:ddlxSource
|
|
156
|
+
xmlns:ddlxSource="http://www.sap.com/adt/ddic/ddlxsources"
|
|
157
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
158
|
+
adtcore:description="${description}"
|
|
159
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
160
|
+
adtcore:name="${name}"
|
|
161
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
162
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
163
|
+
</ddlxSource:ddlxSource>`;
|
|
164
|
+
case "SRVD/SRV":
|
|
165
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
166
|
+
<srvdSource:srvdSource
|
|
167
|
+
xmlns:srvdSource="http://www.sap.com/adt/ddic/srvdsources"
|
|
168
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
169
|
+
adtcore:description="${description}"
|
|
170
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
171
|
+
adtcore:name="${name}"
|
|
172
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}"
|
|
173
|
+
srvdSource:srvdSourceType="S">
|
|
174
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
175
|
+
</srvdSource:srvdSource>`;
|
|
176
|
+
case "BDEF/BDO":
|
|
177
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
178
|
+
<blue:blueSource
|
|
179
|
+
xmlns:blue="http://www.sap.com/wbobj/blue"
|
|
180
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
181
|
+
adtcore:description="${description}"
|
|
182
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
183
|
+
adtcore:name="${name}"
|
|
184
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
185
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
186
|
+
</blue:blueSource>`;
|
|
187
|
+
case "SRVB/SVB": {
|
|
188
|
+
if (!srvd_name)
|
|
189
|
+
throw new Error("srvd_name é obrigatório para criar um Service Binding (SRVB/SVB).");
|
|
190
|
+
const [bindProto = "ODATA", bindVersion = "V4", bindCategory = "UI"] = (binding_type ?? "ODATA;V4;UI").split(";");
|
|
191
|
+
const category = bindCategory === "WEB_API" ? "1" : "0";
|
|
192
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
193
|
+
<srvb:serviceBinding
|
|
194
|
+
xmlns:srvb="http://www.sap.com/adt/ddic/ServiceBindings"
|
|
195
|
+
xmlns:adtcore="http://www.sap.com/adt/core"
|
|
196
|
+
adtcore:description="${description}"
|
|
197
|
+
adtcore:language="${adt_client_js_1.SAP_LANGUAGE}"
|
|
198
|
+
adtcore:name="${name}"
|
|
199
|
+
adtcore:responsible="${adt_client_js_1.SAP_USER}">
|
|
200
|
+
<adtcore:packageRef adtcore:name="${pkg}"/>
|
|
201
|
+
<srvb:services srvb:name="${name}">
|
|
202
|
+
<srvb:content>
|
|
203
|
+
<srvb:serviceDefinition adtcore:name="${srvd_name.toUpperCase()}" adtcore:type="SRVD/SRV"/>
|
|
204
|
+
</srvb:content>
|
|
205
|
+
</srvb:services>
|
|
206
|
+
<srvb:binding srvb:type="${bindProto}" srvb:version="${bindVersion}" srvb:category="${category}"/>
|
|
207
|
+
</srvb:serviceBinding>`;
|
|
208
|
+
}
|
|
209
|
+
default:
|
|
210
|
+
throw new Error(`Criação de objetos do tipo ${object_type} não suportada.`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
async function abapCreate(input) {
|
|
214
|
+
const { object_type, object_name, package: pkg = "$TMP", transport_request } = input;
|
|
215
|
+
const name = object_name.toUpperCase();
|
|
216
|
+
const adtPath = (0, adt_client_js_1.resolveAdtPath)(object_type);
|
|
217
|
+
const contentTypes = CONTENT_TYPE[object_type];
|
|
218
|
+
if (!contentTypes || contentTypes.length === 0) {
|
|
219
|
+
throw new Error(`Criação de objetos do tipo ${object_type} não suportada.`);
|
|
220
|
+
}
|
|
221
|
+
const csrf = await (0, adt_client_js_1.ensureSession)();
|
|
222
|
+
const payload = buildPayload(input);
|
|
223
|
+
// Tentar cada Content-Type (v2 primeiro, fallback para v1 no ECC)
|
|
224
|
+
let lastResponse = null;
|
|
225
|
+
for (const contentType of contentTypes) {
|
|
226
|
+
const response = await adt_client_js_1.http.post(`/${adtPath}`, payload, {
|
|
227
|
+
headers: {
|
|
228
|
+
"Content-Type": contentType,
|
|
229
|
+
"X-CSRF-Token": csrf,
|
|
230
|
+
},
|
|
231
|
+
params: { corrNr: transport_request ?? "" },
|
|
232
|
+
validateStatus: (status) => status >= 200 && status < 500,
|
|
233
|
+
});
|
|
234
|
+
if (response.status === 200 || response.status === 201) {
|
|
235
|
+
if (object_type === "SRVB/SVB") {
|
|
236
|
+
return `Service Binding ${name} criado com sucesso no pacote ${pkg}.\nUse abap_activate para ativar.`;
|
|
237
|
+
}
|
|
238
|
+
return `Objeto ${name} (${object_type}) criado com sucesso no pacote ${pkg}.\nUse abap_write para adicionar o código-fonte e abap_activate para ativar.`;
|
|
239
|
+
}
|
|
240
|
+
lastResponse = response;
|
|
241
|
+
// Se 415 (Unsupported Media Type) e temos mais Content-Types para tentar, continua
|
|
242
|
+
if (response.status === 415 && contentTypes.indexOf(contentType) < contentTypes.length - 1) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
const errorBody = typeof lastResponse?.data === "string" ? lastResponse.data : JSON.stringify(lastResponse?.data ?? "");
|
|
248
|
+
throw new Error(`Erro ao criar objeto (HTTP ${lastResponse?.status}): ${errorBody.slice(0, 500)}`);
|
|
249
|
+
}
|
|
250
|
+
exports.abapCreateTool = {
|
|
251
|
+
name: "abap_create",
|
|
252
|
+
description: "Cria um novo objeto ABAP no sistema SAP via ADT API. Suporta programas, classes, interfaces, objetos DDIC e objetos RAP/Fiori.",
|
|
253
|
+
inputSchema: {
|
|
254
|
+
type: "object",
|
|
255
|
+
properties: {
|
|
256
|
+
object_type: {
|
|
257
|
+
type: "string",
|
|
258
|
+
description: "Tipo do objeto SAP a criar.",
|
|
259
|
+
enum: ["PROG/P", "CLAS/OC", "INTF/OI", "FUGR/F", "DOMA/D", "DTEL/D", "TABL/DT", "TABL/DS", "TTYP/TT", "MSAG/N", "DDLS/DF", "DDLX/MX", "SRVD/SRV", "BDEF/BDO", "SRVB/SVB"],
|
|
260
|
+
},
|
|
261
|
+
object_name: {
|
|
262
|
+
type: "string",
|
|
263
|
+
description: "Nome do novo objeto ABAP (ex: ZR_SD_PEDIDOS). Deve seguir convenção de nomenclatura do projeto.",
|
|
264
|
+
},
|
|
265
|
+
description: {
|
|
266
|
+
type: "string",
|
|
267
|
+
description: "Descrição curta do objeto (aparece no SAP GUI).",
|
|
268
|
+
},
|
|
269
|
+
package: {
|
|
270
|
+
type: "string",
|
|
271
|
+
description: "Pacote SAP onde criar o objeto. Use '$TMP' para objetos locais (padrão) ou um pacote de desenvolvimento como 'ZDEV'.",
|
|
272
|
+
},
|
|
273
|
+
srvd_name: {
|
|
274
|
+
type: "string",
|
|
275
|
+
description: "Nome da Service Definition (SRVD/SRV) associada. Obrigatório para SRVB/SVB.",
|
|
276
|
+
},
|
|
277
|
+
binding_type: {
|
|
278
|
+
type: "string",
|
|
279
|
+
description: "Protocolo do Service Binding. Padrão: ODATA;V4;UI.",
|
|
280
|
+
enum: ["ODATA;V4;UI", "ODATA;V2;UI", "ODATA;V4;WEB_API"],
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
required: ["object_type", "object_name", "description"],
|
|
284
|
+
},
|
|
285
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.abapDataPreview = abapDataPreview;
|
|
4
|
+
const adt_client_js_1 = require("../adt-client.js");
|
|
5
|
+
const data_format_js_1 = require("./shared/data-format.js");
|
|
6
|
+
async function abapDataPreview(input) {
|
|
7
|
+
const { object_name, max_rows = 100, where_clause, order_by, columns } = input;
|
|
8
|
+
const name = object_name.toUpperCase();
|
|
9
|
+
const csrf = await (0, adt_client_js_1.ensureSession)();
|
|
10
|
+
const params = {
|
|
11
|
+
ddicEntityName: name,
|
|
12
|
+
maxRows: String(max_rows),
|
|
13
|
+
};
|
|
14
|
+
if (where_clause)
|
|
15
|
+
params.filterValue = where_clause;
|
|
16
|
+
if (order_by)
|
|
17
|
+
params.orderBy = order_by;
|
|
18
|
+
if (columns)
|
|
19
|
+
params.selectedColumns = columns;
|
|
20
|
+
const response = await adt_client_js_1.http.post("/datapreview/ddic", "", {
|
|
21
|
+
params,
|
|
22
|
+
headers: {
|
|
23
|
+
Accept: "application/vnd.sap.adt.datapreview.table.v1+xml",
|
|
24
|
+
"X-CSRF-Token": csrf,
|
|
25
|
+
},
|
|
26
|
+
responseType: "text",
|
|
27
|
+
validateStatus: (status) => status < 500,
|
|
28
|
+
});
|
|
29
|
+
if (response.status >= 400) {
|
|
30
|
+
const errMsg = typeof response.data === "string"
|
|
31
|
+
? (response.data.match(/<message[^>]*>([^<]+)<\/message>/i)?.[1] ?? response.data)
|
|
32
|
+
: `HTTP ${response.status}`;
|
|
33
|
+
throw new Error(errMsg);
|
|
34
|
+
}
|
|
35
|
+
const result = (0, data_format_js_1.parseDataPreview)(response.data);
|
|
36
|
+
return (0, data_format_js_1.formatDataPreview)(name, result);
|
|
37
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.abapDeleteObject = abapDeleteObject;
|
|
4
|
+
const adt_client_js_1 = require("../adt-client.js");
|
|
5
|
+
async function abapDeleteObject(input) {
|
|
6
|
+
const { object_type, object_name, transport_request } = input;
|
|
7
|
+
const name = object_name.toUpperCase();
|
|
8
|
+
const adtPath = (0, adt_client_js_1.resolveAdtPath)(object_type);
|
|
9
|
+
const objectPath = `/${adtPath}/${name}`;
|
|
10
|
+
const csrf = await (0, adt_client_js_1.ensureSession)();
|
|
11
|
+
// Lock — obter lockHandle
|
|
12
|
+
const lockResp = await adt_client_js_1.http.post(objectPath, "", {
|
|
13
|
+
headers: { "X-CSRF-Token": csrf },
|
|
14
|
+
params: { _action: "LOCK", accessMode: "MODIFY" },
|
|
15
|
+
validateStatus: (status) => status < 500,
|
|
16
|
+
responseType: "text",
|
|
17
|
+
});
|
|
18
|
+
const lockData = typeof lockResp.data === "string" ? lockResp.data : "";
|
|
19
|
+
const handleMatch = lockData.match(/<LOCK_HANDLE>([^<]+)<\/LOCK_HANDLE>/);
|
|
20
|
+
const lockHandle = handleMatch?.[1] ?? "";
|
|
21
|
+
if (!lockHandle) {
|
|
22
|
+
throw new Error(`Falha ao obter lock para ${name}. O objeto pode estar bloqueado por outro usuário.`);
|
|
23
|
+
}
|
|
24
|
+
// Delete com lockHandle
|
|
25
|
+
const params = { lockHandle };
|
|
26
|
+
if (transport_request)
|
|
27
|
+
params.corrNr = transport_request;
|
|
28
|
+
const delResp = await adt_client_js_1.http.delete(objectPath, {
|
|
29
|
+
headers: { "X-CSRF-Token": csrf },
|
|
30
|
+
params,
|
|
31
|
+
validateStatus: (status) => status < 500,
|
|
32
|
+
});
|
|
33
|
+
if (delResp.status >= 400) {
|
|
34
|
+
// Unlock em caso de erro
|
|
35
|
+
await adt_client_js_1.http.post(objectPath, "", {
|
|
36
|
+
headers: { "X-CSRF-Token": csrf },
|
|
37
|
+
params: { _action: "UNLOCK" },
|
|
38
|
+
validateStatus: () => true,
|
|
39
|
+
});
|
|
40
|
+
const data = typeof delResp.data === "string" ? delResp.data : "";
|
|
41
|
+
const msg = data.match(/<message[^>]*>([^<]+)<\/message>/i)?.[1] ?? `HTTP ${delResp.status}`;
|
|
42
|
+
throw new Error(`Erro ao excluir ${name}: ${msg}`);
|
|
43
|
+
}
|
|
44
|
+
return `Objeto ${name} (${object_type}) excluído com sucesso.`;
|
|
45
|
+
}
|
|
@@ -0,0 +1,298 @@
|
|
|
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
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
+
};
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.abapDeployBsp = abapDeployBsp;
|
|
40
|
+
const axios_1 = __importDefault(require("axios"));
|
|
41
|
+
const axios_cookiejar_support_1 = require("axios-cookiejar-support");
|
|
42
|
+
const tough_cookie_1 = require("tough-cookie");
|
|
43
|
+
const fs = __importStar(require("fs"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const zlib = __importStar(require("zlib"));
|
|
46
|
+
const system_profile_js_1 = require("../system-profile.js");
|
|
47
|
+
const SAP_URL = process.env.SAP_URL ?? "";
|
|
48
|
+
const SAP_USER = process.env.SAP_USER ?? "";
|
|
49
|
+
const SAP_PASS = process.env.SAP_PASS ?? "";
|
|
50
|
+
const SAP_CLIENT = process.env.SAP_CLIENT ?? "100";
|
|
51
|
+
const SAP_LANGUAGE = process.env.SAP_LANGUAGE ?? "PT";
|
|
52
|
+
// Cria cliente HTTP para o OData ABAP_REPOSITORY_SRV (separado do ADT)
|
|
53
|
+
function createRepoClient() {
|
|
54
|
+
const jar = new tough_cookie_1.CookieJar();
|
|
55
|
+
return (0, axios_cookiejar_support_1.wrapper)(axios_1.default.create({
|
|
56
|
+
baseURL: `${SAP_URL}/sap/opu/odata/UI5/ABAP_REPOSITORY_SRV`,
|
|
57
|
+
jar,
|
|
58
|
+
withCredentials: true,
|
|
59
|
+
auth: { username: SAP_USER, password: SAP_PASS },
|
|
60
|
+
params: { "sap-client": SAP_CLIENT, "sap-language": SAP_LANGUAGE },
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
// Fetch CSRF token via HEAD request
|
|
64
|
+
async function fetchCsrf(client) {
|
|
65
|
+
const response = await client.head("/", {
|
|
66
|
+
headers: { "X-CSRF-Token": "Fetch" },
|
|
67
|
+
validateStatus: (s) => s < 500,
|
|
68
|
+
});
|
|
69
|
+
const token = response.headers["x-csrf-token"];
|
|
70
|
+
if (!token)
|
|
71
|
+
throw new Error("Falha ao obter CSRF token do ABAP_REPOSITORY_SRV");
|
|
72
|
+
return token;
|
|
73
|
+
}
|
|
74
|
+
// Verifica se a BSP já existe
|
|
75
|
+
async function bspExists(client, name) {
|
|
76
|
+
try {
|
|
77
|
+
await client.get(`/Repositories('${encodeURIComponent(name)}')`, {
|
|
78
|
+
headers: { Accept: "application/json" },
|
|
79
|
+
});
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Cria ZIP em memória com os arquivos da pasta
|
|
87
|
+
function createZipFromFolder(folderPath) {
|
|
88
|
+
// Implementação simples de ZIP (deflate store) sem dependências externas
|
|
89
|
+
// Formato: local file headers + data + central directory + end of central directory
|
|
90
|
+
const files = [];
|
|
91
|
+
function walkDir(dir, prefix) {
|
|
92
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
93
|
+
for (const entry of entries) {
|
|
94
|
+
const fullPath = path.join(dir, entry.name);
|
|
95
|
+
const zipPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
96
|
+
if (entry.isDirectory()) {
|
|
97
|
+
walkDir(fullPath, zipPath);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
files.push({ name: zipPath, data: fs.readFileSync(fullPath) });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
walkDir(folderPath, "");
|
|
105
|
+
// Build ZIP binary
|
|
106
|
+
const localHeaders = [];
|
|
107
|
+
const centralHeaders = [];
|
|
108
|
+
let offset = 0;
|
|
109
|
+
for (const file of files) {
|
|
110
|
+
const nameBuffer = Buffer.from(file.name, "utf-8");
|
|
111
|
+
const compressed = zlib.deflateRawSync(file.data);
|
|
112
|
+
// CRC32
|
|
113
|
+
const crc = crc32(file.data);
|
|
114
|
+
// Local file header (30 bytes + name + compressed data)
|
|
115
|
+
const local = Buffer.alloc(30 + nameBuffer.length);
|
|
116
|
+
local.writeUInt32LE(0x04034b50, 0); // signature
|
|
117
|
+
local.writeUInt16LE(20, 4); // version needed
|
|
118
|
+
local.writeUInt16LE(0, 6); // flags
|
|
119
|
+
local.writeUInt16LE(8, 8); // compression: deflate
|
|
120
|
+
local.writeUInt16LE(0, 10); // mod time
|
|
121
|
+
local.writeUInt16LE(0, 12); // mod date
|
|
122
|
+
local.writeUInt32LE(crc, 14); // crc32
|
|
123
|
+
local.writeUInt32LE(compressed.length, 18); // compressed size
|
|
124
|
+
local.writeUInt32LE(file.data.length, 22); // uncompressed size
|
|
125
|
+
local.writeUInt16LE(nameBuffer.length, 26); // name length
|
|
126
|
+
local.writeUInt16LE(0, 28); // extra field length
|
|
127
|
+
nameBuffer.copy(local, 30);
|
|
128
|
+
localHeaders.push(local);
|
|
129
|
+
localHeaders.push(compressed);
|
|
130
|
+
// Central directory header (46 bytes + name)
|
|
131
|
+
const central = Buffer.alloc(46 + nameBuffer.length);
|
|
132
|
+
central.writeUInt32LE(0x02014b50, 0); // signature
|
|
133
|
+
central.writeUInt16LE(20, 4); // version made by
|
|
134
|
+
central.writeUInt16LE(20, 6); // version needed
|
|
135
|
+
central.writeUInt16LE(0, 8); // flags
|
|
136
|
+
central.writeUInt16LE(8, 10); // compression: deflate
|
|
137
|
+
central.writeUInt16LE(0, 12); // mod time
|
|
138
|
+
central.writeUInt16LE(0, 14); // mod date
|
|
139
|
+
central.writeUInt32LE(crc, 16); // crc32
|
|
140
|
+
central.writeUInt32LE(compressed.length, 20); // compressed size
|
|
141
|
+
central.writeUInt32LE(file.data.length, 24); // uncompressed size
|
|
142
|
+
central.writeUInt16LE(nameBuffer.length, 28); // name length
|
|
143
|
+
central.writeUInt16LE(0, 30); // extra field length
|
|
144
|
+
central.writeUInt16LE(0, 32); // comment length
|
|
145
|
+
central.writeUInt16LE(0, 34); // disk number start
|
|
146
|
+
central.writeUInt16LE(0, 36); // internal attrs
|
|
147
|
+
central.writeUInt32LE(0, 38); // external attrs
|
|
148
|
+
central.writeUInt32LE(offset, 42); // offset of local header
|
|
149
|
+
nameBuffer.copy(central, 46);
|
|
150
|
+
centralHeaders.push(central);
|
|
151
|
+
offset += local.length + compressed.length;
|
|
152
|
+
}
|
|
153
|
+
const centralDirOffset = offset;
|
|
154
|
+
const centralDirSize = centralHeaders.reduce((s, b) => s + b.length, 0);
|
|
155
|
+
// End of central directory (22 bytes)
|
|
156
|
+
const eocd = Buffer.alloc(22);
|
|
157
|
+
eocd.writeUInt32LE(0x06054b50, 0); // signature
|
|
158
|
+
eocd.writeUInt16LE(0, 4); // disk number
|
|
159
|
+
eocd.writeUInt16LE(0, 6); // disk with central dir
|
|
160
|
+
eocd.writeUInt16LE(files.length, 8); // entries on this disk
|
|
161
|
+
eocd.writeUInt16LE(files.length, 10); // total entries
|
|
162
|
+
eocd.writeUInt32LE(centralDirSize, 12); // central dir size
|
|
163
|
+
eocd.writeUInt32LE(centralDirOffset, 16); // central dir offset
|
|
164
|
+
eocd.writeUInt16LE(0, 20); // comment length
|
|
165
|
+
return Buffer.concat([...localHeaders, ...centralHeaders, eocd]);
|
|
166
|
+
}
|
|
167
|
+
// CRC32 implementation
|
|
168
|
+
function crc32(buf) {
|
|
169
|
+
let crc = 0xffffffff;
|
|
170
|
+
for (let i = 0; i < buf.length; i++) {
|
|
171
|
+
crc = (crc >>> 8) ^ crc32Table[(crc ^ buf[i]) & 0xff];
|
|
172
|
+
}
|
|
173
|
+
return (crc ^ 0xffffffff) >>> 0;
|
|
174
|
+
}
|
|
175
|
+
const crc32Table = (() => {
|
|
176
|
+
const table = new Uint32Array(256);
|
|
177
|
+
for (let i = 0; i < 256; i++) {
|
|
178
|
+
let c = i;
|
|
179
|
+
for (let j = 0; j < 8; j++) {
|
|
180
|
+
c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
|
|
181
|
+
}
|
|
182
|
+
table[i] = c;
|
|
183
|
+
}
|
|
184
|
+
return table;
|
|
185
|
+
})();
|
|
186
|
+
function escapeXml(str) {
|
|
187
|
+
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
188
|
+
}
|
|
189
|
+
async function abapDeployBsp(input) {
|
|
190
|
+
const { bsp_name, folder_path, package: pkg = "$TMP", description = `BSP ${bsp_name}`, transport_request = "", } = input;
|
|
191
|
+
const name = bsp_name.toUpperCase();
|
|
192
|
+
// Valida pasta
|
|
193
|
+
if (!fs.existsSync(folder_path)) {
|
|
194
|
+
throw new Error(`Pasta não encontrada: ${folder_path}`);
|
|
195
|
+
}
|
|
196
|
+
if (!fs.statSync(folder_path).isDirectory()) {
|
|
197
|
+
throw new Error(`Caminho não é uma pasta: ${folder_path}`);
|
|
198
|
+
}
|
|
199
|
+
// Cria ZIP e converte para base64
|
|
200
|
+
const zipBuffer = createZipFromFolder(folder_path);
|
|
201
|
+
const base64Data = zipBuffer.toString("base64");
|
|
202
|
+
// Cria cliente OData
|
|
203
|
+
const client = createRepoClient();
|
|
204
|
+
const csrf = await fetchCsrf(client);
|
|
205
|
+
// Verifica se BSP já existe
|
|
206
|
+
const exists = await bspExists(client, name);
|
|
207
|
+
// Payload Atom para ABAP_REPOSITORY_SRV
|
|
208
|
+
const publicUrl = `${SAP_URL}/sap/opu/odata/UI5/ABAP_REPOSITORY_SRV`;
|
|
209
|
+
const time = new Date().toISOString();
|
|
210
|
+
const escapedName = escapeXml(name);
|
|
211
|
+
const payload = `<entry xmlns="http://www.w3.org/2005/Atom" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xml:base="${publicUrl}">
|
|
212
|
+
<id>${publicUrl}/Repositories('${escapedName}')</id>
|
|
213
|
+
<title type="text">Repositories('${escapedName}')</title>
|
|
214
|
+
<updated>${time}</updated>
|
|
215
|
+
<category term="/UI5/ABAP_REPOSITORY_SRV.Repository" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme"/>
|
|
216
|
+
<link href="Repositories('${escapedName}')" rel="edit" title="Repository"/>
|
|
217
|
+
<content type="application/xml">
|
|
218
|
+
<m:properties>
|
|
219
|
+
<d:Name>${escapedName}</d:Name>
|
|
220
|
+
<d:Package>${escapeXml(pkg.toUpperCase())}</d:Package>
|
|
221
|
+
<d:Description>${escapeXml(description)}</d:Description>
|
|
222
|
+
<d:ZipArchive>${base64Data}</d:ZipArchive>
|
|
223
|
+
<d:Info/>
|
|
224
|
+
</m:properties>
|
|
225
|
+
</content>
|
|
226
|
+
</entry>`;
|
|
227
|
+
// Params
|
|
228
|
+
const params = {
|
|
229
|
+
CodePage: "UTF8",
|
|
230
|
+
SafeMode: "true",
|
|
231
|
+
};
|
|
232
|
+
if (transport_request) {
|
|
233
|
+
params.TransportRequest = transport_request;
|
|
234
|
+
}
|
|
235
|
+
// POST (criar) ou PUT (atualizar)
|
|
236
|
+
const method = exists ? "put" : "post";
|
|
237
|
+
const url = exists
|
|
238
|
+
? `/Repositories('${encodeURIComponent(name)}')`
|
|
239
|
+
: `/Repositories`;
|
|
240
|
+
const response = await client.request({
|
|
241
|
+
method,
|
|
242
|
+
url,
|
|
243
|
+
data: payload,
|
|
244
|
+
headers: {
|
|
245
|
+
"Content-Type": "application/atom+xml",
|
|
246
|
+
"Accept": "application/atom+xml,application/json",
|
|
247
|
+
"X-CSRF-Token": csrf,
|
|
248
|
+
},
|
|
249
|
+
params,
|
|
250
|
+
validateStatus: (s) => s >= 200 && s < 500,
|
|
251
|
+
});
|
|
252
|
+
if (response.status >= 200 && response.status < 300) {
|
|
253
|
+
// Extrai mensagens SAP do header sap-message
|
|
254
|
+
const sapMsg = response.headers["sap-message"];
|
|
255
|
+
let messages = "";
|
|
256
|
+
if (sapMsg) {
|
|
257
|
+
try {
|
|
258
|
+
const parsed = JSON.parse(sapMsg);
|
|
259
|
+
messages = parsed.message || "";
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
messages = sapMsg.slice(0, 200);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
const profile = (0, system_profile_js_1.getProfile)();
|
|
266
|
+
const bspPath = (0, system_profile_js_1.resolveBspUrl)(name);
|
|
267
|
+
const appUrl = bspPath ? `${SAP_URL}${bspPath}` : `${SAP_URL}/sap/bc/ui5_ui5/sap/${name.toLowerCase()}?sap-client=${SAP_CLIENT}`;
|
|
268
|
+
const infoLines = [
|
|
269
|
+
`BSP ${name} ${exists ? "atualizada" : "criada"} com sucesso.`,
|
|
270
|
+
`Pacote: ${pkg.toUpperCase()}`,
|
|
271
|
+
`Arquivos: ${countFiles(folder_path)}`,
|
|
272
|
+
`URL: ${appUrl}`,
|
|
273
|
+
`UI5 Bootstrap: ${profile.ui5.bootstrapPath}sap-ui-core.js`,
|
|
274
|
+
messages ? `Mensagens SAP: ${messages}` : "",
|
|
275
|
+
];
|
|
276
|
+
return infoLines.filter(Boolean).join("\n");
|
|
277
|
+
}
|
|
278
|
+
// Erro — extrair mensagem
|
|
279
|
+
const errorBody = typeof response.data === "string"
|
|
280
|
+
? response.data
|
|
281
|
+
: JSON.stringify(response.data);
|
|
282
|
+
const errorMsg = errorBody.match(/<message[^>]*>([^<]*)<\/message>/i)?.[1]
|
|
283
|
+
|| errorBody.slice(0, 500);
|
|
284
|
+
throw new Error(`Deploy falhou (HTTP ${response.status}): ${errorMsg}`);
|
|
285
|
+
}
|
|
286
|
+
function countFiles(dir) {
|
|
287
|
+
let count = 0;
|
|
288
|
+
function walk(d) {
|
|
289
|
+
for (const entry of fs.readdirSync(d, { withFileTypes: true })) {
|
|
290
|
+
if (entry.isDirectory())
|
|
291
|
+
walk(path.join(d, entry.name));
|
|
292
|
+
else
|
|
293
|
+
count++;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
walk(dir);
|
|
297
|
+
return count;
|
|
298
|
+
}
|