@sap-ux/odata-service-writer 0.27.1 → 0.27.2

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.
@@ -7,7 +7,7 @@ import type { Editor } from 'mem-fs-editor';
7
7
  * @param {string} basePath - the root path of an existing UI5 application
8
8
  * @param {OdataService} service - the OData service instance
9
9
  * @param {Editor} fs - the memfs editor instance
10
- * @param {boolean} update - whether the service update is running
10
+ * @param {boolean} update - whether the service update is running (if true, skips unique service name generation and makes sure that '' model is updated for the mainService)
11
11
  */
12
12
  export declare function enhanceData(basePath: string, service: OdataService, fs: Editor, update?: boolean): Promise<void>;
13
13
  //# sourceMappingURL=defaults.d.ts.map
@@ -16,15 +16,37 @@ const ui5_config_1 = require("@sap-ux/ui5-config");
16
16
  function setDefaultServicePath(service) {
17
17
  service.path = service.path?.endsWith('/') ? service.path : (service.path ?? '') + '/';
18
18
  }
19
+ /**
20
+ * Generates a unique name for the service.
21
+ *
22
+ * @param {OdataService} dataSources - dataSources from manifest.json.
23
+ * @param {string} serviceName - The service name whose name needs to be modified.
24
+ * @returns Unique service name.
25
+ */
26
+ function generateUniqueServiceName(dataSources, serviceName) {
27
+ let tmpSrvName = serviceName;
28
+ let uniqueNameCount = 1;
29
+ let doesExist = true; // Ensure data source name is unique
30
+ do {
31
+ if (dataSources?.[tmpSrvName]) {
32
+ tmpSrvName = `${serviceName}${uniqueNameCount++}`; // Try with a new name
33
+ }
34
+ else {
35
+ doesExist = false;
36
+ }
37
+ } while (doesExist);
38
+ return tmpSrvName;
39
+ }
19
40
  /**
20
41
  * Sets the default name for a given service.
21
42
  * Default serivce name is used only for first service.
22
43
  *
23
44
  * @param {string} basePath - the root path of an existing UI5 application
24
45
  * @param {OdataService} service - The service object whose name needs to be set or modified.
25
- * @param fs - the memfs editor instance
46
+ * @param {Editor} fs - the memfs editor instance
47
+ * @param {boolean} update - whether the service update is running
26
48
  */
27
- async function setDefaultServiceName(basePath, service, fs) {
49
+ async function setDefaultServiceName(basePath, service, fs, update) {
28
50
  const manifestPath = (0, path_1.join)(await (0, project_access_1.getWebappPath)(basePath, fs), project_access_1.FileName.Manifest);
29
51
  const manifest = fs.readJSON(manifestPath);
30
52
  // Check if manifest has already any dataSources defined, DEFAULT_DATASOURCE_NAME should be used for the first service
@@ -35,6 +57,9 @@ async function setDefaultServiceName(basePath, service, fs) {
35
57
  if (oDataSources.length === 0) {
36
58
  service.name = constants_1.DEFAULT_DATASOURCE_NAME;
37
59
  }
60
+ else if (service.name && !update) {
61
+ service.name = generateUniqueServiceName(dataSources, service.name);
62
+ }
38
63
  }
39
64
  else {
40
65
  // No existing dataSources - no existing services, use default name
@@ -48,9 +73,10 @@ async function setDefaultServiceName(basePath, service, fs) {
48
73
  *
49
74
  * @param {string} basePath - the root path of an existing UI5 application
50
75
  * @param {OdataService} service - The service object whose model needs to be set or modified
51
- * @param fs - the memfs editor instance
76
+ * @param {Editor} fs - the memfs editor instance
77
+ * @param {boolean} update - whether the service update is running (if true, makes sure that '' model is updated for the mainService)
52
78
  */
53
- async function setDefaultServiceModel(basePath, service, fs) {
79
+ async function setDefaultServiceModel(basePath, service, fs, update) {
54
80
  const manifestPath = (0, path_1.join)(await (0, project_access_1.getWebappPath)(basePath, fs), 'manifest.json');
55
81
  const manifest = fs.readJSON(manifestPath);
56
82
  if (!service.model) {
@@ -59,12 +85,15 @@ async function setDefaultServiceModel(basePath, service, fs) {
59
85
  if (models) {
60
86
  // Filter dataSource models by dataSource property
61
87
  const servicesModels = Object.values(models).filter((model) => model.dataSource);
62
- service.model =
63
- servicesModels.length === 0 ||
64
- (servicesModels.find((serviceModel) => serviceModel.dataSource === constants_1.DEFAULT_DATASOURCE_NAME) &&
65
- service.name === constants_1.DEFAULT_DATASOURCE_NAME) // model for mainService is ""
66
- ? ''
67
- : service.name;
88
+ if (servicesModels.length === 0 ||
89
+ (update &&
90
+ servicesModels.find((serviceModel) => serviceModel.dataSource === constants_1.DEFAULT_DATASOURCE_NAME) &&
91
+ service.name === constants_1.DEFAULT_DATASOURCE_NAME)) {
92
+ service.model = '';
93
+ }
94
+ else if (service.name) {
95
+ service.model = service.name;
96
+ }
68
97
  }
69
98
  else {
70
99
  // No models defined, that means first one is being added, set model to ''
@@ -147,14 +176,14 @@ async function setDefaultPreviewSettings(basePath, service, fs) {
147
176
  * @param {string} basePath - the root path of an existing UI5 application
148
177
  * @param {OdataService} service - the OData service instance
149
178
  * @param {Editor} fs - the memfs editor instance
150
- * @param {boolean} update - whether the service update is running
179
+ * @param {boolean} update - whether the service update is running (if true, skips unique service name generation and makes sure that '' model is updated for the mainService)
151
180
  */
152
181
  async function enhanceData(basePath, service, fs, update = false) {
153
182
  if (!update) {
154
183
  setDefaultServicePath(service);
155
184
  }
156
- await setDefaultServiceName(basePath, service, fs);
157
- await setDefaultServiceModel(basePath, service, fs);
185
+ await setDefaultServiceName(basePath, service, fs, update);
186
+ await setDefaultServiceModel(basePath, service, fs, update);
158
187
  // set service type to EDMX if not defined
159
188
  service.type = service.type ?? types_1.ServiceType.EDMX;
160
189
  /**
@@ -403,17 +403,26 @@ async function updateManifest(basePath, service, fs, forceServiceUpdate = false)
403
403
  const manifest = fs.readJSON(manifestPath);
404
404
  const appProp = 'sap.app';
405
405
  const appid = manifest?.[appProp]?.id;
406
+ const dataSources = manifest[appProp]?.dataSources ?? {};
406
407
  // Throw if required property is not found manifest.json
407
408
  if (!appid) {
408
409
  throw new Error((0, i18n_1.t)('error.requiredProjectPropertyNotFound', { property: `'${appProp}'.id`, path: manifestPath }));
409
410
  }
410
411
  // Throw if only update is required and service is not found in manifest.json
411
- if (forceServiceUpdate && service.name && !manifest[appProp]?.dataSources?.[service.name]) {
412
+ if (forceServiceUpdate && service.name && !dataSources?.[service.name]) {
412
413
  throw new Error((0, i18n_1.t)('error.requiredProjectPropertyNotFound', {
413
414
  property: `'${appProp}.dataSources.${service.name}'`,
414
415
  path: manifestPath
415
416
  }));
416
417
  }
418
+ // Throw if service is being added, but service with the same URI already exists
419
+ if (!forceServiceUpdate &&
420
+ service.path &&
421
+ Object.values(dataSources).find((dataSource) => dataSource.uri === service.path)) {
422
+ throw new Error((0, i18n_1.t)('error.requiredServiceAlreadyExists', {
423
+ uri: service.path
424
+ }));
425
+ }
417
426
  // Check and update existing services in a way that is supported by multiple services
418
427
  const convertedManifest = await addMultipleServiceSupportToManifest(webappPath, manifest, fs);
419
428
  // Update manifest.json services
@@ -2,6 +2,7 @@
2
2
  "error": {
3
3
  "requiredProjectFileNotFound": "Invalid project structure. Cannot find required file {{-path}}",
4
4
  "requiredProjectPropertyNotFound": "Required project property: {{-property}} was not found in file: {{-path}}",
5
+ "requiredServiceAlreadyExists": "A service with the {{-uri}} URI already exists. Choose another service.",
5
6
  "unparseableXML": "Unparseable XML was specified: {{-error}}"
6
7
  }
7
8
  }
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { ManifestNamespace } from '@sap-ux/project-access';
1
2
  import type { FioriToolsProxyConfigBackend as ProxyBackend } from '@sap-ux/ui5-config';
2
3
  export declare enum OdataVersion {
3
4
  v2 = "2",
@@ -82,4 +83,7 @@ export interface ProjectPaths {
82
83
  ui5LocalYaml?: string;
83
84
  ui5MockYaml?: string;
84
85
  }
86
+ export type DataSources = {
87
+ [k: string]: ManifestNamespace.DataSource;
88
+ };
85
89
  //# sourceMappingURL=types.d.ts.map
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "bugs": {
10
10
  "url": "https://github.com/SAP/open-ux-tools/issues?q=is%3Aopen+is%3Aissue+label%3Abug+label%3Aodata-service-writer"
11
11
  },
12
- "version": "0.27.1",
12
+ "version": "0.27.2",
13
13
  "license": "Apache-2.0",
14
14
  "main": "dist/index.js",
15
15
  "files": [