@sap-ux/adp-tooling 0.19.11 → 1.0.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/dist/abap/client.d.ts +1 -1
- package/dist/abap/client.js +8 -13
- package/dist/abap/config.js +5 -8
- package/dist/abap/index.d.ts +3 -3
- package/dist/abap/index.js +3 -19
- package/dist/abap/provider.js +5 -8
- package/dist/base/abap/manifest-service.d.ts +1 -1
- package/dist/base/abap/manifest-service.js +9 -18
- package/dist/base/cf.js +8 -11
- package/dist/base/change-utils.d.ts +1 -1
- package/dist/base/change-utils.js +49 -62
- package/dist/base/constants/index.js +12 -15
- package/dist/base/credentials.d.ts +2 -2
- package/dist/base/credentials.js +6 -9
- package/dist/base/helper.d.ts +1 -1
- package/dist/base/helper.js +40 -57
- package/dist/base/project-builder.js +3 -6
- package/dist/base/prompt.d.ts +1 -1
- package/dist/base/prompt.js +19 -25
- package/dist/btp/api.d.ts +1 -1
- package/dist/btp/api.js +10 -18
- package/dist/btp/index.d.ts +1 -1
- package/dist/btp/index.js +1 -17
- package/dist/cf/app/discovery.d.ts +1 -1
- package/dist/cf/app/discovery.js +11 -18
- package/dist/cf/app/html5-repo.d.ts +1 -1
- package/dist/cf/app/html5-repo.js +24 -32
- package/dist/cf/app/index.d.ts +2 -2
- package/dist/cf/app/index.js +2 -18
- package/dist/cf/core/auth.d.ts +1 -1
- package/dist/cf/core/auth.js +4 -8
- package/dist/cf/core/config.d.ts +1 -1
- package/dist/cf/core/config.js +9 -15
- package/dist/cf/core/index.d.ts +2 -2
- package/dist/cf/core/index.js +2 -18
- package/dist/cf/deploy.d.ts +1 -1
- package/dist/cf/deploy.js +33 -44
- package/dist/cf/index.d.ts +6 -6
- package/dist/cf/index.js +6 -22
- package/dist/cf/project/index.d.ts +3 -3
- package/dist/cf/project/index.js +3 -19
- package/dist/cf/project/mta.d.ts +1 -1
- package/dist/cf/project/mta.js +23 -66
- package/dist/cf/project/yaml-loader.d.ts +1 -1
- package/dist/cf/project/yaml-loader.js +8 -16
- package/dist/cf/project/yaml.d.ts +2 -2
- package/dist/cf/project/yaml.js +28 -72
- package/dist/cf/services/api.d.ts +1 -1
- package/dist/cf/services/api.js +46 -93
- package/dist/cf/services/cli.d.ts +1 -1
- package/dist/cf/services/cli.js +31 -42
- package/dist/cf/services/destinations.js +12 -48
- package/dist/cf/services/index.d.ts +5 -5
- package/dist/cf/services/index.js +5 -21
- package/dist/cf/services/manifest.d.ts +1 -1
- package/dist/cf/services/manifest.js +9 -13
- package/dist/cf/services/ssh.js +14 -22
- package/dist/cf/utils/index.d.ts +1 -1
- package/dist/cf/utils/index.js +1 -17
- package/dist/cf/utils/validation.d.ts +1 -1
- package/dist/cf/utils/validation.js +12 -18
- package/dist/common/flp-parameters.d.ts +1 -1
- package/dist/common/flp-parameters.js +1 -4
- package/dist/common/index.d.ts +1 -1
- package/dist/common/index.js +1 -17
- package/dist/i18n.js +8 -16
- package/dist/index.d.ts +23 -23
- package/dist/index.js +23 -46
- package/dist/preview/adp-preview.d.ts +1 -1
- package/dist/preview/adp-preview.js +41 -39
- package/dist/preview/change-handler.d.ts +1 -1
- package/dist/preview/change-handler.js +51 -59
- package/dist/preview/descriptor-change-handler.d.ts +1 -1
- package/dist/preview/descriptor-change-handler.js +18 -21
- package/dist/preview/ovp-routes-handler.js +11 -13
- package/dist/preview/routes-handler.js +36 -71
- package/dist/preview/utils.d.ts +1 -1
- package/dist/preview/utils.js +5 -8
- package/dist/prompts/add-annotations-to-odata/index.d.ts +1 -1
- package/dist/prompts/add-annotations-to-odata/index.js +24 -26
- package/dist/prompts/add-component-usages/index.d.ts +1 -1
- package/dist/prompts/add-component-usages/index.js +41 -43
- package/dist/prompts/add-new-model/index.d.ts +1 -1
- package/dist/prompts/add-new-model/index.js +75 -80
- package/dist/prompts/change-data-source/index.d.ts +1 -1
- package/dist/prompts/change-data-source/index.js +19 -22
- package/dist/prompts/change-inbound/index.d.ts +1 -1
- package/dist/prompts/change-inbound/index.js +11 -14
- package/dist/prompts/index.d.ts +5 -5
- package/dist/prompts/index.js +5 -15
- package/dist/source/applications.d.ts +2 -2
- package/dist/source/applications.js +7 -11
- package/dist/source/index.d.ts +3 -3
- package/dist/source/index.js +3 -19
- package/dist/source/manifest.d.ts +1 -1
- package/dist/source/manifest.js +15 -25
- package/dist/source/systems.d.ts +1 -1
- package/dist/source/systems.js +20 -27
- package/dist/types.d.ts +1 -1
- package/dist/types.js +64 -17
- package/dist/ui5/fetch.d.ts +1 -1
- package/dist/ui5/fetch.js +8 -12
- package/dist/ui5/format.d.ts +1 -1
- package/dist/ui5/format.js +17 -29
- package/dist/ui5/index.d.ts +4 -4
- package/dist/ui5/index.js +4 -20
- package/dist/ui5/network.d.ts +1 -1
- package/dist/ui5/network.js +1 -4
- package/dist/ui5/validator.js +14 -20
- package/dist/ui5/version-info.d.ts +1 -1
- package/dist/ui5/version-info.js +25 -36
- package/dist/writer/cf.d.ts +1 -1
- package/dist/writer/cf.js +35 -43
- package/dist/writer/changes/writer-factory.d.ts +2 -2
- package/dist/writer/changes/writer-factory.js +10 -13
- package/dist/writer/changes/writers/annotations-writer.d.ts +1 -1
- package/dist/writer/changes/writers/annotations-writer.js +11 -46
- package/dist/writer/changes/writers/component-usages-writer.d.ts +1 -1
- package/dist/writer/changes/writers/component-usages-writer.js +9 -12
- package/dist/writer/changes/writers/data-source-writer.d.ts +1 -1
- package/dist/writer/changes/writers/data-source-writer.js +7 -10
- package/dist/writer/changes/writers/inbound-writer.d.ts +1 -1
- package/dist/writer/changes/writers/inbound-writer.js +10 -13
- package/dist/writer/changes/writers/index.d.ts +5 -5
- package/dist/writer/changes/writers/index.js +5 -21
- package/dist/writer/changes/writers/new-model-writer.d.ts +1 -1
- package/dist/writer/changes/writers/new-model-writer.js +16 -20
- package/dist/writer/editors.d.ts +1 -1
- package/dist/writer/editors.js +6 -9
- package/dist/writer/i18n/index.d.ts +1 -1
- package/dist/writer/i18n/index.js +13 -17
- package/dist/writer/i18n/key-user-translations.js +9 -14
- package/dist/writer/inbound-navigation.d.ts +1 -1
- package/dist/writer/inbound-navigation.js +18 -27
- package/dist/writer/index.d.ts +1 -1
- package/dist/writer/index.js +36 -37
- package/dist/writer/manifest/descriptor-content.d.ts +2 -2
- package/dist/writer/manifest/descriptor-content.js +9 -15
- package/dist/writer/manifest/index.d.ts +1 -1
- package/dist/writer/manifest/index.js +1 -17
- package/dist/writer/options.d.ts +1 -1
- package/dist/writer/options.js +16 -27
- package/dist/writer/project-utils.d.ts +1 -1
- package/dist/writer/project-utils.js +49 -57
- package/dist/writer/writer-config.d.ts +2 -2
- package/dist/writer/writer-config.js +25 -30
- package/package.json +19 -17
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const node_path_1 = require("node:path");
|
|
13
|
-
const ejs_1 = require("ejs");
|
|
14
|
-
const node_crypto_1 = require("node:crypto");
|
|
15
|
-
const manifest_service_1 = require("../base/abap/manifest-service");
|
|
16
|
-
const helper_1 = require("../base/helper");
|
|
17
|
-
const odata_service_writer_1 = require("@sap-ux/odata-service-writer");
|
|
18
|
-
const editors_1 = require("../writer/editors");
|
|
19
|
-
const project_access_1 = require("@sap-ux/project-access");
|
|
1
|
+
import { ChangeType, TemplateFileName } from '../types.js';
|
|
2
|
+
import { basename, dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { render } from 'ejs';
|
|
5
|
+
import { randomBytes } from 'node:crypto';
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
import { ManifestService } from '../base/abap/manifest-service.js';
|
|
8
|
+
import { getVariant, isTypescriptSupported } from '../base/helper.js';
|
|
9
|
+
import { getAnnotationNamespaces } from '@sap-ux/odata-service-writer';
|
|
10
|
+
import { generateChange } from '../writer/editors.js';
|
|
11
|
+
import { DirName } from '@sap-ux/project-access';
|
|
20
12
|
const OBJECT_PAGE_CUSTOM_SECTION = 'OBJECT_PAGE_CUSTOM_SECTION';
|
|
21
13
|
const CUSTOM_ACTION = 'CUSTOM_ACTION';
|
|
22
14
|
const OBJECT_PAGE_HEADER_FIELD = 'OBJECT_PAGE_HEADER_FIELD';
|
|
@@ -26,11 +18,11 @@ const V4_MDC_TABLE_COLUMN = 'V4_MDC_TABLE_COLUMN';
|
|
|
26
18
|
const ANALYTICAL_TABLE_COLUMN = 'ANALYTICAL_TABLE_COLUMN';
|
|
27
19
|
const GRID_TREE_TABLE_COLUMN = 'GRID_TREE_TABLE_COLUMN';
|
|
28
20
|
const TABLE_ACTION = 'TABLE_ACTION';
|
|
29
|
-
|
|
21
|
+
export const fragmentTemplateDefinitions = {
|
|
30
22
|
[OBJECT_PAGE_CUSTOM_SECTION]: {
|
|
31
23
|
path: 'common/op-custom-section.xml',
|
|
32
24
|
getData: () => {
|
|
33
|
-
const uuid =
|
|
25
|
+
const uuid = randomBytes(4).toString('hex');
|
|
34
26
|
return {
|
|
35
27
|
ids: {
|
|
36
28
|
objectPageSection: `op-section-${uuid}`,
|
|
@@ -43,7 +35,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
43
35
|
[CUSTOM_ACTION]: {
|
|
44
36
|
path: 'common/custom-action.xml',
|
|
45
37
|
getData: () => {
|
|
46
|
-
const uuid =
|
|
38
|
+
const uuid = randomBytes(4).toString('hex');
|
|
47
39
|
return {
|
|
48
40
|
ids: {
|
|
49
41
|
toolbarActionButton: `btn-${uuid}`
|
|
@@ -54,7 +46,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
54
46
|
[TABLE_ACTION]: {
|
|
55
47
|
path: 'common/v4-table-action.xml',
|
|
56
48
|
getData: () => {
|
|
57
|
-
const uuid =
|
|
49
|
+
const uuid = randomBytes(4).toString('hex');
|
|
58
50
|
return {
|
|
59
51
|
ids: {
|
|
60
52
|
customToolbarAction: `toolbarAction-${uuid}`,
|
|
@@ -66,7 +58,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
66
58
|
[OBJECT_PAGE_HEADER_FIELD]: {
|
|
67
59
|
path: 'common/header-field.xml',
|
|
68
60
|
getData: () => {
|
|
69
|
-
const uuid =
|
|
61
|
+
const uuid = randomBytes(4).toString('hex');
|
|
70
62
|
return {
|
|
71
63
|
ids: {
|
|
72
64
|
vBoxContainer: `vBox-${uuid}`,
|
|
@@ -78,7 +70,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
78
70
|
[V2_SMART_TABLE_COLUMN]: {
|
|
79
71
|
path: 'v2/m-table-custom-column.xml',
|
|
80
72
|
getData: (change) => {
|
|
81
|
-
const uuid =
|
|
73
|
+
const uuid = randomBytes(4).toString('hex');
|
|
82
74
|
const columnIndex = change.content.index;
|
|
83
75
|
return {
|
|
84
76
|
ids: {
|
|
@@ -93,7 +85,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
93
85
|
[V2_SMART_TABLE_CELL]: {
|
|
94
86
|
path: 'v2/m-table-custom-column-cell.xml',
|
|
95
87
|
getData: () => {
|
|
96
|
-
const uuid =
|
|
88
|
+
const uuid = randomBytes(4).toString('hex');
|
|
97
89
|
return {
|
|
98
90
|
ids: {
|
|
99
91
|
text: `cell-text-${uuid}`
|
|
@@ -104,7 +96,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
104
96
|
[V4_MDC_TABLE_COLUMN]: {
|
|
105
97
|
path: 'v4/mdc-custom-column.xml',
|
|
106
98
|
getData: () => {
|
|
107
|
-
const uuid =
|
|
99
|
+
const uuid = randomBytes(4).toString('hex');
|
|
108
100
|
return {
|
|
109
101
|
ids: {
|
|
110
102
|
column: `column-${uuid}`,
|
|
@@ -116,7 +108,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
116
108
|
[GRID_TREE_TABLE_COLUMN]: {
|
|
117
109
|
path: 'common/grid-tree-custom-column.xml',
|
|
118
110
|
getData: (change) => {
|
|
119
|
-
const uuid =
|
|
111
|
+
const uuid = randomBytes(4).toString('hex');
|
|
120
112
|
const columnIndex = change.content.index;
|
|
121
113
|
return {
|
|
122
114
|
ids: {
|
|
@@ -132,7 +124,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
132
124
|
[ANALYTICAL_TABLE_COLUMN]: {
|
|
133
125
|
path: 'common/analytical-custom-column.xml',
|
|
134
126
|
getData: (change) => {
|
|
135
|
-
const uuid =
|
|
127
|
+
const uuid = randomBytes(4).toString('hex');
|
|
136
128
|
const columnIndex = change.content.index;
|
|
137
129
|
return {
|
|
138
130
|
ids: {
|
|
@@ -149,7 +141,7 @@ exports.fragmentTemplateDefinitions = {
|
|
|
149
141
|
/**
|
|
150
142
|
* A mapping object that defines how to extract change content data from changes based on their type.
|
|
151
143
|
*/
|
|
152
|
-
|
|
144
|
+
export const moduleNameContentMap = {
|
|
153
145
|
codeExt: (change) => (change.content?.codeRef ?? '').replace('.js', ''),
|
|
154
146
|
addXML: (change) => change.content?.fragmentPath ?? ''
|
|
155
147
|
};
|
|
@@ -166,10 +158,10 @@ exports.moduleNameContentMap = {
|
|
|
166
158
|
* @param {CommonChangeProperties} change - The change object to be fixed.
|
|
167
159
|
* @param {Logger} logger - An instance for logging warnings, errors, or informational messages.
|
|
168
160
|
*/
|
|
169
|
-
function tryFixChange(change, logger) {
|
|
161
|
+
export function tryFixChange(change, logger) {
|
|
170
162
|
try {
|
|
171
163
|
const prefix = change.reference.replace(/\./g, '/');
|
|
172
|
-
change.moduleName = `${prefix}/changes/${
|
|
164
|
+
change.moduleName = `${prefix}/changes/${moduleNameContentMap[change.changeType](change)}`;
|
|
173
165
|
}
|
|
174
166
|
catch (error) {
|
|
175
167
|
logger.warn('Could not fix missing module name.');
|
|
@@ -182,7 +174,7 @@ function tryFixChange(change, logger) {
|
|
|
182
174
|
* @returns {boolean} `true` if the `changeType` is either 'addXML' or 'addXMLAtExtensionPoint',
|
|
183
175
|
* indicating the change is of type `AddXMLChange`.
|
|
184
176
|
*/
|
|
185
|
-
function isAddXMLChange(change) {
|
|
177
|
+
export function isAddXMLChange(change) {
|
|
186
178
|
return change.changeType === 'addXML' || change.changeType === 'addXMLAtExtensionPoint';
|
|
187
179
|
}
|
|
188
180
|
/**
|
|
@@ -191,7 +183,7 @@ function isAddXMLChange(change) {
|
|
|
191
183
|
* @param {CommonChangeProperties} change - The change object to check.
|
|
192
184
|
* @returns {boolean} `true` if the `changeType` is `codeExt`, indicating the change is of type `codeExtChange`.
|
|
193
185
|
*/
|
|
194
|
-
function isCodeExtChange(change) {
|
|
186
|
+
export function isCodeExtChange(change) {
|
|
195
187
|
return change.changeType === 'codeExt';
|
|
196
188
|
}
|
|
197
189
|
/**
|
|
@@ -201,7 +193,7 @@ function isCodeExtChange(change) {
|
|
|
201
193
|
* @returns {boolean} `true` if the `changeType` is either 'appdescr_app_addAnnotationsToOData',
|
|
202
194
|
* indicating the change is of type `AnnotationFileChange`.
|
|
203
195
|
*/
|
|
204
|
-
function isAddAnnotationChange(change) {
|
|
196
|
+
export function isAddAnnotationChange(change) {
|
|
205
197
|
return change.changeType === 'appdescr_app_addAnnotationsToOData';
|
|
206
198
|
}
|
|
207
199
|
/**
|
|
@@ -211,7 +203,7 @@ function isAddAnnotationChange(change) {
|
|
|
211
203
|
* @returns {boolean} `true` if the `changeType` is either 'appdescr_fe_changePageConfiguration',
|
|
212
204
|
* indicating the change is of type `V4 Descriptor Change`.
|
|
213
205
|
*/
|
|
214
|
-
function isV4DescriptorChange(change) {
|
|
206
|
+
export function isV4DescriptorChange(change) {
|
|
215
207
|
return change.changeType === 'appdescr_fe_changePageConfiguration';
|
|
216
208
|
}
|
|
217
209
|
/**
|
|
@@ -223,13 +215,13 @@ function isV4DescriptorChange(change) {
|
|
|
223
215
|
* @param {Logger} logger - The logging instance.
|
|
224
216
|
* @param {CommonAdditionalChangeInfoProperties} additionalChangeInfo - Optional extended change properties.
|
|
225
217
|
*/
|
|
226
|
-
function addXmlFragment(basePath, change, fs, logger, additionalChangeInfo) {
|
|
218
|
+
export function addXmlFragment(basePath, change, fs, logger, additionalChangeInfo) {
|
|
227
219
|
const { fragmentPath } = change.content;
|
|
228
|
-
const fullPath =
|
|
229
|
-
const templateConfig =
|
|
220
|
+
const fullPath = join(basePath, DirName.Changes, fragmentPath);
|
|
221
|
+
const templateConfig = fragmentTemplateDefinitions[additionalChangeInfo?.templateName ?? ''];
|
|
230
222
|
try {
|
|
231
223
|
if (templateConfig) {
|
|
232
|
-
const fragmentTemplatePath =
|
|
224
|
+
const fragmentTemplatePath = join(__dirname, '../../templates/rta', templateConfig.path);
|
|
233
225
|
const text = fs.read(fragmentTemplatePath);
|
|
234
226
|
const changeTemplate = {
|
|
235
227
|
...templateConfig.getData(change),
|
|
@@ -237,15 +229,15 @@ function addXmlFragment(basePath, change, fs, logger, additionalChangeInfo) {
|
|
|
237
229
|
targetAggregation: additionalChangeInfo?.targetAggregation,
|
|
238
230
|
controlType: additionalChangeInfo?.controlType
|
|
239
231
|
};
|
|
240
|
-
const template =
|
|
232
|
+
const template = render(text, changeTemplate);
|
|
241
233
|
fs.write(fullPath, template);
|
|
242
234
|
}
|
|
243
235
|
else {
|
|
244
236
|
// use default fragment template
|
|
245
237
|
const templateName = 'fragment.xml'; /* TemplateFileName.Fragment */
|
|
246
|
-
const fragmentTemplatePath =
|
|
238
|
+
const fragmentTemplatePath = join(__dirname, '../../templates/rta', templateName);
|
|
247
239
|
const text = fs.read(fragmentTemplatePath);
|
|
248
|
-
const template =
|
|
240
|
+
const template = render(text, {
|
|
249
241
|
viewName: additionalChangeInfo?.viewName,
|
|
250
242
|
targetAggregation: additionalChangeInfo?.targetAggregation,
|
|
251
243
|
controlType: additionalChangeInfo?.controlType
|
|
@@ -267,20 +259,20 @@ function addXmlFragment(basePath, change, fs, logger, additionalChangeInfo) {
|
|
|
267
259
|
* @param {Editor} fs - The mem-fs-editor instance.
|
|
268
260
|
* @param {Logger} logger - The logging instance.
|
|
269
261
|
*/
|
|
270
|
-
async function addControllerExtension(rootPath, basePath, change, fs, logger) {
|
|
262
|
+
export async function addControllerExtension(rootPath, basePath, change, fs, logger) {
|
|
271
263
|
const { codeRef } = change.content;
|
|
272
|
-
const isTsSupported =
|
|
273
|
-
const fileName =
|
|
264
|
+
const isTsSupported = isTypescriptSupported(rootPath, fs);
|
|
265
|
+
const fileName = basename(codeRef, '.js');
|
|
274
266
|
const fullName = `${fileName}.${isTsSupported ? 'ts' : 'js'}`;
|
|
275
|
-
const tmplFileName = isTsSupported ?
|
|
276
|
-
const tmplPath =
|
|
267
|
+
const tmplFileName = isTsSupported ? TemplateFileName.TSController : TemplateFileName.Controller;
|
|
268
|
+
const tmplPath = join(__dirname, '../../templates/rta', tmplFileName);
|
|
277
269
|
try {
|
|
278
270
|
const text = fs.read(tmplPath);
|
|
279
|
-
const id = (await
|
|
271
|
+
const id = (await getVariant(rootPath))?.id;
|
|
280
272
|
const extensionPath = `${id}.${fileName}`;
|
|
281
273
|
const templateData = isTsSupported ? { name: fileName, ns: id } : { extensionPath };
|
|
282
|
-
const template =
|
|
283
|
-
fs.write(
|
|
274
|
+
const template = render(text, templateData);
|
|
275
|
+
fs.write(join(basePath, DirName.Changes, DirName.Coding, fullName), template);
|
|
284
276
|
}
|
|
285
277
|
catch (error) {
|
|
286
278
|
logger.error(`Failed to create controller extension "${codeRef}": ${error}`);
|
|
@@ -297,26 +289,26 @@ async function addControllerExtension(rootPath, basePath, change, fs, logger) {
|
|
|
297
289
|
* @param {Logger} logger - The logging instance.
|
|
298
290
|
*@param {AbapServiceProvider} provider - abap provider.
|
|
299
291
|
*/
|
|
300
|
-
async function addAnnotationFile(webappPath, projectRoot, change, fs, logger, provider) {
|
|
292
|
+
export async function addAnnotationFile(webappPath, projectRoot, change, fs, logger, provider) {
|
|
301
293
|
const { dataSourceId, annotations, dataSource } = change.content;
|
|
302
294
|
const annotationDataSourceKey = annotations[0];
|
|
303
295
|
const annotationUriSegments = dataSource[annotationDataSourceKey].uri.split('/');
|
|
304
296
|
annotationUriSegments.shift();
|
|
305
|
-
const fullPath =
|
|
297
|
+
const fullPath = join(webappPath, DirName.Changes, ...annotationUriSegments);
|
|
306
298
|
try {
|
|
307
|
-
const variant = await
|
|
308
|
-
const manifestService = await
|
|
299
|
+
const variant = await getVariant(projectRoot);
|
|
300
|
+
const manifestService = await ManifestService.initMergedManifest(provider, projectRoot, variant, logger);
|
|
309
301
|
const metadata = await manifestService.getDataSourceMetadata(dataSourceId);
|
|
310
302
|
const dataSources = manifestService.getManifestDataSources();
|
|
311
|
-
const namespaces =
|
|
312
|
-
await
|
|
303
|
+
const namespaces = getAnnotationNamespaces({ metadata });
|
|
304
|
+
await generateChange(projectRoot, ChangeType.ADD_ANNOTATIONS_TO_ODATA, {
|
|
313
305
|
annotation: {
|
|
314
306
|
dataSource: dataSourceId,
|
|
315
307
|
namespaces,
|
|
316
308
|
serviceUrl: dataSources[dataSourceId].uri,
|
|
317
|
-
fileName:
|
|
309
|
+
fileName: basename(dataSource[annotationDataSourceKey].uri)
|
|
318
310
|
},
|
|
319
|
-
variant: await
|
|
311
|
+
variant: await getVariant(projectRoot),
|
|
320
312
|
isCommand: false
|
|
321
313
|
}, fs);
|
|
322
314
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Editor } from 'mem-fs-editor';
|
|
2
|
-
import { type AppDescriptorV4Change } from '../types';
|
|
2
|
+
import { type AppDescriptorV4Change } from '../types.js';
|
|
3
3
|
import type { Logger } from '@sap-ux/logger';
|
|
4
4
|
export declare const customFragmentConfig: {
|
|
5
5
|
path: string;
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const node_crypto_1 = require("node:crypto");
|
|
9
|
-
const ejs_1 = require("ejs");
|
|
10
|
-
exports.customFragmentConfig = {
|
|
1
|
+
import { dirname, join } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { getFragmentPathFromTemplate } from './utils.js';
|
|
4
|
+
import { randomBytes } from 'node:crypto';
|
|
5
|
+
import { render } from 'ejs';
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
export const customFragmentConfig = {
|
|
11
8
|
path: 'v4/custom-section.xml',
|
|
12
9
|
getData: () => {
|
|
13
|
-
const uuid =
|
|
10
|
+
const uuid = randomBytes(4).toString('hex');
|
|
14
11
|
return {
|
|
15
12
|
ids: {
|
|
16
13
|
hBox: `hbox-${uuid}`
|
|
@@ -18,10 +15,10 @@ exports.customFragmentConfig = {
|
|
|
18
15
|
};
|
|
19
16
|
}
|
|
20
17
|
};
|
|
21
|
-
|
|
18
|
+
export const customColumnFragmentConfig = {
|
|
22
19
|
path: 'v4/mdc-custom-column-config.xml',
|
|
23
20
|
getData: () => {
|
|
24
|
-
const uuid =
|
|
21
|
+
const uuid = randomBytes(4).toString('hex');
|
|
25
22
|
return {
|
|
26
23
|
ids: {
|
|
27
24
|
text: `text-${uuid}`
|
|
@@ -35,7 +32,7 @@ exports.customColumnFragmentConfig = {
|
|
|
35
32
|
* @param obj - The object to check.
|
|
36
33
|
* @returns True if the object has a 'template' property of type string, false otherwise.
|
|
37
34
|
*/
|
|
38
|
-
function hasTemplate(obj) {
|
|
35
|
+
export function hasTemplate(obj) {
|
|
39
36
|
return typeof obj === 'object' && obj !== null && 'template' in obj && typeof obj.template === 'string';
|
|
40
37
|
}
|
|
41
38
|
/**
|
|
@@ -57,10 +54,10 @@ function getConfig(change) {
|
|
|
57
54
|
// annotation term, optional qualifier, "/columns/", and column ID - no nested quantifiers.
|
|
58
55
|
const isCustomColumnPropertyPath = /^controlConfiguration\/(?:[^/@]+\/)?@[^/]+\.LineItem(?:#[^/]+)?\/columns\/[^/]+$/.test(propertyPath);
|
|
59
56
|
if (isCustomSectionPropertyPath) {
|
|
60
|
-
return
|
|
57
|
+
return customFragmentConfig;
|
|
61
58
|
}
|
|
62
59
|
else if (isCustomColumnPropertyPath) {
|
|
63
|
-
return
|
|
60
|
+
return customColumnFragmentConfig;
|
|
64
61
|
}
|
|
65
62
|
return undefined;
|
|
66
63
|
}
|
|
@@ -72,24 +69,24 @@ function getConfig(change) {
|
|
|
72
69
|
* @param fs - The mem-fs-editor instance for file operations.
|
|
73
70
|
* @param logger - The logger instance for logging information and errors.
|
|
74
71
|
*/
|
|
75
|
-
function addCustomFragment(basePath, change, fs, logger) {
|
|
72
|
+
export function addCustomFragment(basePath, change, fs, logger) {
|
|
76
73
|
const propertyValue = change.content.entityPropertyChange.propertyValue;
|
|
77
74
|
const config = getConfig(change);
|
|
78
75
|
if (hasTemplate(propertyValue) && config) {
|
|
79
76
|
const { template } = propertyValue;
|
|
80
|
-
const path =
|
|
77
|
+
const path = getFragmentPathFromTemplate(template, change);
|
|
81
78
|
try {
|
|
82
79
|
if (!path) {
|
|
83
80
|
throw new Error('Fragment Path could not be determined');
|
|
84
81
|
}
|
|
85
82
|
const fragmentPath = `${path}.fragment.xml`;
|
|
86
|
-
const fullPath =
|
|
87
|
-
const fragmentTemplatePath =
|
|
83
|
+
const fullPath = join(basePath, fragmentPath);
|
|
84
|
+
const fragmentTemplatePath = join(__dirname, '../../templates/rta', config.path);
|
|
88
85
|
const text = fs.read(fragmentTemplatePath);
|
|
89
86
|
// Safe: Template files are from our own codebase (templates/rta/), config.path is from getConfig()
|
|
90
87
|
// which only returns predefined paths (customFragmentConfig or customColumnFragmentConfig).
|
|
91
88
|
// Template data comes from controlled config.getData() which only generates UUIDs for IDs.
|
|
92
|
-
const template =
|
|
89
|
+
const template = render(text, {
|
|
93
90
|
viewName: undefined,
|
|
94
91
|
controlType: undefined,
|
|
95
92
|
targetAggregation: undefined,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const axios_extension_1 = require("@sap-ux/axios-extension");
|
|
1
|
+
import { ODataVersion } from '@sap-ux/axios-extension';
|
|
2
|
+
import { HttpStatusCodes } from '../types.js';
|
|
4
3
|
/**
|
|
5
4
|
* Converts an absolute URL to a relative path.
|
|
6
5
|
* Annotation URIs from the catalog service are absolute (e.g. https://host/sap/opu/...).
|
|
@@ -22,7 +21,7 @@ function toRelativePath(uri) {
|
|
|
22
21
|
* Provides data source catalog and service metadata endpoints
|
|
23
22
|
* consumed by the client-side OVP bridge functions.
|
|
24
23
|
*/
|
|
25
|
-
class OvpRoutesHandler {
|
|
24
|
+
export default class OvpRoutesHandler {
|
|
26
25
|
provider;
|
|
27
26
|
logger;
|
|
28
27
|
/**
|
|
@@ -44,17 +43,17 @@ class OvpRoutesHandler {
|
|
|
44
43
|
*/
|
|
45
44
|
handleGetDataSources = async (_req, res, next) => {
|
|
46
45
|
try {
|
|
47
|
-
const catalogService = this.provider.catalog(
|
|
46
|
+
const catalogService = this.provider.catalog(ODataVersion.v2);
|
|
48
47
|
const response = await catalogService.get('/ServiceCollection', {
|
|
49
48
|
params: { $format: 'json' }
|
|
50
49
|
});
|
|
51
50
|
const services = response.odata();
|
|
52
|
-
res.status(
|
|
51
|
+
res.status(HttpStatusCodes.OK).json({ results: services });
|
|
53
52
|
this.logger.debug(`OVP: Fetched ${services.length} data sources from catalog`);
|
|
54
53
|
}
|
|
55
54
|
catch (e) {
|
|
56
55
|
this.logger.error(`OVP: Failed to fetch data sources: ${e.message}`);
|
|
57
|
-
res.status(
|
|
56
|
+
res.status(HttpStatusCodes.INTERNAL_SERVER_ERROR).json({
|
|
58
57
|
message: `Failed to fetch data sources: ${e.message}`
|
|
59
58
|
});
|
|
60
59
|
next(e);
|
|
@@ -74,19 +73,19 @@ class OvpRoutesHandler {
|
|
|
74
73
|
const { dataSource } = req.body;
|
|
75
74
|
this.logger.debug(`OVP: getMetaModel called for service ${dataSource?.Title ?? 'unknown'}`);
|
|
76
75
|
if (!dataSource?.Title) {
|
|
77
|
-
res.status(
|
|
76
|
+
res.status(HttpStatusCodes.BAD_REQUEST).json({ message: 'dataSource with Title is required' });
|
|
78
77
|
return;
|
|
79
78
|
}
|
|
80
|
-
const catalogService = this.provider.catalog(
|
|
79
|
+
const catalogService = this.provider.catalog(ODataVersion.v2);
|
|
81
80
|
const filterOptions = dataSource.ID ? { id: dataSource.ID } : { title: dataSource.Title };
|
|
82
81
|
const annotations = await catalogService.getAnnotations(filterOptions);
|
|
83
82
|
if (annotations.length === 0) {
|
|
84
|
-
res.status(
|
|
83
|
+
res.status(HttpStatusCodes.OK).json(null);
|
|
85
84
|
this.logger.debug(`OVP: No annotations found for service ${dataSource.Title}`);
|
|
86
85
|
return;
|
|
87
86
|
}
|
|
88
87
|
const serviceURI = `/sap/opu/odata/sap/${dataSource.Title}`;
|
|
89
|
-
res.status(
|
|
88
|
+
res.status(HttpStatusCodes.OK).json({
|
|
90
89
|
serviceUrl: `${serviceURI}/`,
|
|
91
90
|
annotations: annotations.map((a) => ({
|
|
92
91
|
TechnicalName: a.TechnicalName,
|
|
@@ -102,12 +101,11 @@ class OvpRoutesHandler {
|
|
|
102
101
|
}
|
|
103
102
|
catch (e) {
|
|
104
103
|
this.logger.error(`OVP: Failed to fetch metamodel: ${e.message}`);
|
|
105
|
-
res.status(
|
|
104
|
+
res.status(HttpStatusCodes.INTERNAL_SERVER_ERROR).json({
|
|
106
105
|
message: `Failed to fetch metamodel: ${e.message}`
|
|
107
106
|
});
|
|
108
107
|
next(e);
|
|
109
108
|
}
|
|
110
109
|
};
|
|
111
110
|
}
|
|
112
|
-
exports.default = OvpRoutesHandler;
|
|
113
111
|
//# sourceMappingURL=ovp-routes-handler.js.map
|
|
@@ -1,54 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
13
|
-
|
|
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
|
-
const fs = __importStar(require("node:fs"));
|
|
40
|
-
const os = __importStar(require("node:os"));
|
|
41
|
-
const path = __importStar(require("node:path"));
|
|
42
|
-
const ejs_1 = require("ejs");
|
|
43
|
-
const sanitize_filename_1 = __importDefault(require("sanitize-filename"));
|
|
44
|
-
const btp_utils_1 = require("@sap-ux/btp-utils");
|
|
45
|
-
const project_access_1 = require("@sap-ux/project-access");
|
|
46
|
-
const manifest_service_1 = require("../base/abap/manifest-service");
|
|
47
|
-
const helper_1 = require("../base/helper");
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import { renderFile } from 'ejs';
|
|
6
|
+
import { dirname } from 'node:path';
|
|
7
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
+
import sanitize from 'sanitize-filename';
|
|
9
|
+
import { isAppStudio } from '@sap-ux/btp-utils';
|
|
10
|
+
import { TemplateFileName, HttpStatusCodes } from '../types.js';
|
|
11
|
+
import { DirName } from '@sap-ux/project-access';
|
|
12
|
+
import { ManifestService } from '../base/abap/manifest-service.js';
|
|
13
|
+
import { getVariant, isTypescriptSupported } from '../base/helper.js';
|
|
48
14
|
/**
|
|
49
15
|
* @description Handles API Routes
|
|
50
16
|
*/
|
|
51
|
-
class RoutesHandler {
|
|
17
|
+
export default class RoutesHandler {
|
|
52
18
|
project;
|
|
53
19
|
util;
|
|
54
20
|
provider;
|
|
@@ -89,7 +55,7 @@ class RoutesHandler {
|
|
|
89
55
|
* @param contentType Content type, defaults to json
|
|
90
56
|
*/
|
|
91
57
|
sendFilesResponse(res, data, contentType = 'application/json') {
|
|
92
|
-
res.status(
|
|
58
|
+
res.status(HttpStatusCodes.OK).contentType(contentType).send(data);
|
|
93
59
|
}
|
|
94
60
|
/**
|
|
95
61
|
* Sanitizes and handles error messages.
|
|
@@ -100,9 +66,9 @@ class RoutesHandler {
|
|
|
100
66
|
* @param e.message Error message
|
|
101
67
|
*/
|
|
102
68
|
handleErrorMessage(res, next, e) {
|
|
103
|
-
const sanitizedMsg = (
|
|
69
|
+
const sanitizedMsg = sanitize(e.message);
|
|
104
70
|
this.logger.error(sanitizedMsg);
|
|
105
|
-
res.status(
|
|
71
|
+
res.status(HttpStatusCodes.INTERNAL_SERVER_ERROR).send({ message: sanitizedMsg });
|
|
106
72
|
next(e);
|
|
107
73
|
}
|
|
108
74
|
/**
|
|
@@ -173,8 +139,8 @@ class RoutesHandler {
|
|
|
173
139
|
const sourcePath = project.getSourcePath();
|
|
174
140
|
const rootPath = this.util.getProject().getRootPath();
|
|
175
141
|
const projectName = project.getName();
|
|
176
|
-
const isTsSupported =
|
|
177
|
-
const getPath = (projectPath, fileName, folder =
|
|
142
|
+
const isTsSupported = isTypescriptSupported(rootPath);
|
|
143
|
+
const getPath = (projectPath, fileName, folder = DirName.Coding) => path.join(projectPath, DirName.Changes, folder, fileName).split(path.sep).join(path.posix.sep);
|
|
178
144
|
for (const file of codeExtFiles) {
|
|
179
145
|
const fileStr = await file.getString();
|
|
180
146
|
const change = JSON.parse(fileStr);
|
|
@@ -191,10 +157,10 @@ class RoutesHandler {
|
|
|
191
157
|
if (controllerExists && !fs.existsSync(controllerPath)) {
|
|
192
158
|
const errorMsg = `Please delete the change file at "${changeFilePath}" and retry creating the controller extension.`;
|
|
193
159
|
this.logger.debug(errorMsg);
|
|
194
|
-
res.status(
|
|
160
|
+
res.status(HttpStatusCodes.NOT_FOUND).send({ message: errorMsg });
|
|
195
161
|
return;
|
|
196
162
|
}
|
|
197
|
-
const isRunningInBAS =
|
|
163
|
+
const isRunningInBAS = isAppStudio();
|
|
198
164
|
this.sendFilesResponse(res, {
|
|
199
165
|
controllerExists,
|
|
200
166
|
controllerPath: os.platform() === 'win32' ? `/${controllerPath}` : controllerPath,
|
|
@@ -220,34 +186,34 @@ class RoutesHandler {
|
|
|
220
186
|
handleWriteControllerExt = async (req, res, next) => {
|
|
221
187
|
try {
|
|
222
188
|
const data = req.body;
|
|
223
|
-
const name = (
|
|
189
|
+
const name = sanitize(data.controllerName);
|
|
224
190
|
const sourcePath = this.util.getProject().getSourcePath();
|
|
225
191
|
const rootPath = this.util.getProject().getRootPath();
|
|
226
192
|
if (!name) {
|
|
227
|
-
res.status(
|
|
193
|
+
res.status(HttpStatusCodes.BAD_REQUEST).send('Controller extension name was not provided!');
|
|
228
194
|
this.logger.debug('Bad request. Controller extension name was not provided!');
|
|
229
195
|
return;
|
|
230
196
|
}
|
|
231
|
-
const isTsSupported =
|
|
232
|
-
const fullPath = path.join(sourcePath,
|
|
197
|
+
const isTsSupported = isTypescriptSupported(rootPath);
|
|
198
|
+
const fullPath = path.join(sourcePath, DirName.Changes, DirName.Coding);
|
|
233
199
|
const filePath = path.join(fullPath, `${name}.${isTsSupported ? 'ts' : 'js'}`);
|
|
234
200
|
if (!fs.existsSync(fullPath)) {
|
|
235
201
|
fs.mkdirSync(fullPath, { recursive: true });
|
|
236
202
|
}
|
|
237
203
|
if (fs.existsSync(filePath)) {
|
|
238
|
-
res.status(
|
|
204
|
+
res.status(HttpStatusCodes.CONFLICT).send(`Controller extension with name "${name}" already exists`);
|
|
239
205
|
this.logger.debug(`Controller extension with name "${name}" already exists`);
|
|
240
206
|
return;
|
|
241
207
|
}
|
|
242
208
|
await generateControllerFile(rootPath, filePath, name);
|
|
243
209
|
const message = 'Controller extension created!';
|
|
244
|
-
res.status(
|
|
210
|
+
res.status(HttpStatusCodes.CREATED).send(message);
|
|
245
211
|
this.logger.debug(`Controller extension with name "${name}" was created`);
|
|
246
212
|
}
|
|
247
213
|
catch (e) {
|
|
248
|
-
const sanitizedMsg = (
|
|
214
|
+
const sanitizedMsg = sanitize(e.message);
|
|
249
215
|
this.logger.error(sanitizedMsg);
|
|
250
|
-
res.status(
|
|
216
|
+
res.status(HttpStatusCodes.INTERNAL_SERVER_ERROR).send(sanitizedMsg);
|
|
251
217
|
next(e);
|
|
252
218
|
}
|
|
253
219
|
};
|
|
@@ -260,7 +226,7 @@ class RoutesHandler {
|
|
|
260
226
|
*/
|
|
261
227
|
handleGetAllAnnotationFilesMappedByDataSource = async (_req, res, next) => {
|
|
262
228
|
try {
|
|
263
|
-
const isRunningInBAS =
|
|
229
|
+
const isRunningInBAS = isAppStudio();
|
|
264
230
|
if (this.isBuildPathMode) {
|
|
265
231
|
// In build path mode (CF ADP), skip ManifestService as it requires ABAP backend
|
|
266
232
|
const apiResponse = {
|
|
@@ -352,11 +318,10 @@ class RoutesHandler {
|
|
|
352
318
|
async getManifestService() {
|
|
353
319
|
const project = this.util.getProject();
|
|
354
320
|
const basePath = project.getRootPath();
|
|
355
|
-
const variant = await
|
|
356
|
-
return await
|
|
321
|
+
const variant = await getVariant(basePath);
|
|
322
|
+
return await ManifestService.initMergedManifest(this.provider, basePath, variant, this.logger);
|
|
357
323
|
}
|
|
358
324
|
}
|
|
359
|
-
exports.default = RoutesHandler;
|
|
360
325
|
/**
|
|
361
326
|
* Generates a controller file for the Adaptation Project based on the project's TypeScript support.
|
|
362
327
|
*
|
|
@@ -369,13 +334,13 @@ exports.default = RoutesHandler;
|
|
|
369
334
|
* @throws {Error} Throws an error if rendering the template fails.
|
|
370
335
|
*/
|
|
371
336
|
async function generateControllerFile(rootPath, filePath, name) {
|
|
372
|
-
const id = (await
|
|
373
|
-
const isTsSupported =
|
|
374
|
-
const tmplFileName = isTsSupported ?
|
|
337
|
+
const id = (await getVariant(rootPath))?.id;
|
|
338
|
+
const isTsSupported = isTypescriptSupported(rootPath);
|
|
339
|
+
const tmplFileName = isTsSupported ? TemplateFileName.TSController : TemplateFileName.Controller;
|
|
375
340
|
const tmplPath = path.join(__dirname, '../../templates/rta', tmplFileName);
|
|
376
341
|
const extensionPath = `${id}.${name}`;
|
|
377
342
|
const templateData = isTsSupported ? { name, ns: id } : { extensionPath };
|
|
378
|
-
|
|
343
|
+
renderFile(tmplPath, templateData, {}, (err, str) => {
|
|
379
344
|
if (err) {
|
|
380
345
|
throw new Error(`Error rendering ${isTsSupported ? 'TypeScript' : 'JavaScript'} template: ${err.message}`);
|
|
381
346
|
}
|
package/dist/preview/utils.d.ts
CHANGED