@sap-ux/odata-service-writer 0.24.2 → 0.25.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.
@@ -113,7 +113,7 @@ async function enhanceData(basePath, service, fs) {
113
113
  // set service type to EDMX if not defined
114
114
  service.type = service.type ?? types_1.ServiceType.EDMX;
115
115
  /**
116
- * In the manifest EJS template, annotation names are used to add annotations to the manifest.json.
116
+ * In the manifest annotation names are used to add annotations to the manifest.json.
117
117
  * For CAP projects, annotations are added to the annotations.cds file instead of the manifest.json.
118
118
  * If the service type is EDMX, this function sets the default annotation names to be included in the manifest.json.
119
119
  */
package/dist/index.js CHANGED
@@ -219,7 +219,7 @@ async function generate(basePath, service, fs) {
219
219
  // Prepare template folder for manifest and xml updates
220
220
  const templateRoot = (0, path_1.join)(__dirname, '../templates');
221
221
  // Update manifest.json
222
- await (0, updates_1.updateManifest)(basePath, service, fs, templateRoot);
222
+ await (0, updates_1.updateManifest)(basePath, service, fs);
223
223
  // Dont extend backend and mockserver middlewares if service type is CDS
224
224
  if (isServiceTypeEdmx) {
225
225
  await writeEDMXServiceFiles(fs, basePath, paths, templateRoot, service);
package/dist/updates.d.ts CHANGED
@@ -6,9 +6,8 @@ import type { OdataService, CdsAnnotationsInfo, EdmxAnnotationsInfo } from './ty
6
6
  * @param basePath - the root path of an existing UI5 application
7
7
  * @param service - the OData service instance
8
8
  * @param fs - the memfs editor instance
9
- * @param templateRoot - root folder contain the ejs templates
10
9
  */
11
- export declare function updateManifest(basePath: string, service: OdataService, fs: Editor, templateRoot: string): Promise<void>;
10
+ export declare function updateManifest(basePath: string, service: OdataService, fs: Editor): Promise<void>;
12
11
  /**
13
12
  * Writes annotation XML files for EDMX service annotations.
14
13
  *
package/dist/updates.js CHANGED
@@ -7,19 +7,175 @@ exports.updateManifest = updateManifest;
7
7
  exports.writeAnnotationXmlFiles = writeAnnotationXmlFiles;
8
8
  exports.updateCdsFilesWithAnnotations = updateCdsFilesWithAnnotations;
9
9
  exports.updatePackageJson = updatePackageJson;
10
- const ejs_1 = require("ejs");
11
10
  const path_1 = require("path");
12
11
  const i18n_1 = require("./i18n");
13
12
  const semver_1 = __importDefault(require("semver"));
14
13
  const prettify_xml_1 = __importDefault(require("prettify-xml"));
15
14
  const project_access_1 = require("@sap-ux/project-access");
15
+ /**
16
+ * Enhances manifest.json models with given service data.
17
+ *
18
+ * @param {string} serviceName - name of the OData service instance
19
+ * @param {string} serviceVersion - version of the OData service instance
20
+ * @param {string} serviceModel - model of the OData service instance
21
+ * @param {boolean} includeSynchronizationMode - whether to include synchronizationMode for model settings
22
+ * @param {Manifest} manifest - the manifest.json of the application
23
+ */
24
+ function enhanceManifestModels(serviceName, serviceVersion, serviceModel, includeSynchronizationMode, manifest) {
25
+ const models = manifest?.['sap.ui5']?.models ?? {};
26
+ let modelSettings = {};
27
+ if (serviceVersion === '4') {
28
+ if (includeSynchronizationMode) {
29
+ modelSettings['synchronizationMode'] = 'None';
30
+ }
31
+ modelSettings['operationMode'] = 'Server';
32
+ modelSettings['autoExpandSelect'] = true;
33
+ modelSettings['earlyRequests'] = true;
34
+ }
35
+ if (models[serviceModel]?.settings) {
36
+ // Merge settings for existing model
37
+ modelSettings = {
38
+ ...models[serviceModel].settings,
39
+ ...modelSettings
40
+ };
41
+ models[serviceModel] = {
42
+ ...models[serviceModel],
43
+ dataSource: serviceName,
44
+ preload: true,
45
+ settings: modelSettings
46
+ };
47
+ }
48
+ else {
49
+ models[serviceModel] = {
50
+ dataSource: serviceName,
51
+ preload: true,
52
+ settings: modelSettings
53
+ };
54
+ }
55
+ if (manifest['sap.ui5']) {
56
+ manifest['sap.ui5'] = {
57
+ ...manifest['sap.ui5'],
58
+ models
59
+ };
60
+ }
61
+ else {
62
+ Object.assign(manifest, { 'sap.ui5': { models: { ...models } } });
63
+ }
64
+ }
65
+ /**
66
+ * Enhances manifest.json dataSources with given service data.
67
+ *
68
+ * @param {string} serviceName - name of the OData service instance
69
+ * @param {string} servicePath - path of the OData service instance
70
+ * @param {string} serviceVersion - version of the OData service instance
71
+ * @param {Manifest} manifest - the manifest.json of the application
72
+ * @param {string} serviceMetadata - metdata of the OData service instance
73
+ * @param {EdmxAnnotationsInfo | EdmxAnnotationsInfo[]} serviceRemoteAnnotations - remote annotations of the OData service instance
74
+ * @param {string | string[]} serviceLocalAnnotations - local annotations of the OData service instance
75
+ */
76
+ function enhanceManifestDatasources(serviceName, servicePath, serviceVersion, manifest, serviceMetadata, serviceRemoteAnnotations, serviceLocalAnnotations) {
77
+ const dataSources = manifest?.['sap.app'].dataSources ?? {};
78
+ // Service annotation names to be stored in service settings of dataSource
79
+ const annotations = [];
80
+ // Annotation dataSources used by service - remote and local annotations are handled differently
81
+ const annotationDataSources = {};
82
+ // Handle remote annotations used by service
83
+ if (Array.isArray(serviceRemoteAnnotations)) {
84
+ serviceRemoteAnnotations.forEach((remoteAnnotation) => {
85
+ if (remoteAnnotation.name) {
86
+ annotations.push(remoteAnnotation.name);
87
+ annotationDataSources[remoteAnnotation.name] = {
88
+ uri: `/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='${encodeURIComponent(remoteAnnotation.technicalName)}',Version='0001')/$value/`,
89
+ type: 'ODataAnnotation',
90
+ settings: {
91
+ localUri: `localService/${serviceName}/${remoteAnnotation.technicalName}.xml`
92
+ }
93
+ };
94
+ }
95
+ });
96
+ }
97
+ else if (serviceRemoteAnnotations?.name) {
98
+ annotations.push(serviceRemoteAnnotations.name);
99
+ annotationDataSources[serviceRemoteAnnotations.name] = {
100
+ uri: `/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='${encodeURIComponent(serviceRemoteAnnotations.technicalName)}',Version='0001')/$value/`,
101
+ type: 'ODataAnnotation',
102
+ settings: {
103
+ localUri: `localService/${serviceName}/${serviceRemoteAnnotations.technicalName}.xml`
104
+ }
105
+ };
106
+ }
107
+ // Handle local annotations used by service
108
+ if (Array.isArray(serviceLocalAnnotations)) {
109
+ serviceLocalAnnotations.forEach((localAnnotation) => {
110
+ annotations.push(localAnnotation);
111
+ annotationDataSources[localAnnotation] = {
112
+ type: 'ODataAnnotation',
113
+ uri: `annotations/${localAnnotation}.xml`,
114
+ settings: {
115
+ localUri: `annotations/${localAnnotation}.xml`
116
+ }
117
+ };
118
+ });
119
+ }
120
+ else if (serviceLocalAnnotations) {
121
+ annotations.push(serviceLocalAnnotations);
122
+ annotationDataSources[serviceLocalAnnotations] = {
123
+ type: 'ODataAnnotation',
124
+ uri: `annotations/${serviceLocalAnnotations}.xml`,
125
+ settings: {
126
+ localUri: `annotations/${serviceLocalAnnotations}.xml`
127
+ }
128
+ };
129
+ }
130
+ const settings = {
131
+ annotations
132
+ };
133
+ if (serviceMetadata) {
134
+ settings['localUri'] = `localService/${serviceName}/metadata.xml`;
135
+ }
136
+ if (serviceVersion === '4') {
137
+ settings['odataVersion'] = '4.0';
138
+ }
139
+ else if (serviceVersion === '2') {
140
+ settings['odataVersion'] = '2.0';
141
+ }
142
+ // Create or update service dataSource in manifest.json for service
143
+ dataSources[serviceName] = {
144
+ uri: servicePath,
145
+ type: 'OData',
146
+ settings
147
+ };
148
+ // Create or update service annotation dataSources in manifest.json for service
149
+ for (const name in annotationDataSources) {
150
+ const annotationDataSource = annotationDataSources[name];
151
+ dataSources[name] = annotationDataSource;
152
+ }
153
+ // Update manifest.json dataSources
154
+ manifest['sap.app'].dataSources = dataSources;
155
+ }
156
+ /**
157
+ * Enhances (creates or updates existing) manifest.json with service data.
158
+ *
159
+ * @param {OdataService} service - the OData service instance
160
+ * @param {Manifest} manifest - the manifest.json of the application
161
+ */
162
+ function enhanceManifest(service, manifest) {
163
+ const minimumUi5Version = (0, project_access_1.getMinimumUI5Version)(manifest);
164
+ // Enhance model settings for service
165
+ const serviceSettings = Object.assign(service, getModelSettings(minimumUi5Version));
166
+ if (serviceSettings.name && serviceSettings.path && serviceSettings.model !== undefined) {
167
+ enhanceManifestDatasources(serviceSettings.name, serviceSettings.path, serviceSettings.version, manifest, serviceSettings.metadata, serviceSettings.annotations, serviceSettings.localAnnotationsName);
168
+ // Add or update existing service model settings for manifest.json
169
+ enhanceManifestModels(serviceSettings.name, serviceSettings.version, serviceSettings.model, serviceSettings.includeSynchronizationMode, manifest);
170
+ }
171
+ }
16
172
  /**
17
173
  * Modifies service in manifest.json and service files in a way that is supported by multiple services.
18
174
  * If service files are defined in 'localService' folder then those files are moved to respective service folder and service configuration URI are modified in manifest.json.
19
175
  *
20
176
  * @param {string} webappPath - the webapp path of an existing UI5 application
21
177
  * @param {string} dataSourceKey - dataSource key in manifest.json
22
- * @param {Manifest} dataSource - dataSource configuration from manifest.json
178
+ * @param {ManifestNamespace.DataSource} dataSource - dataSource configuration from manifest.json
23
179
  * @param {Editor} fs - the memfs editor instance
24
180
  */
25
181
  function updateExistingService(webappPath, dataSourceKey, dataSource, fs) {
@@ -47,6 +203,7 @@ function updateExistingService(webappPath, dataSourceKey, dataSource, fs) {
47
203
  * @param {string} webappPath - the webapp path of an existing UI5 application
48
204
  * @param {Manifest} manifest - the manifest.json of the application
49
205
  * @param {Editor} fs - the memfs editor instance
206
+ * @returns modified manifest object.
50
207
  */
51
208
  async function updateExistingServices(webappPath, manifest, fs) {
52
209
  const dataSources = manifest?.['sap.app']?.dataSources;
@@ -63,7 +220,7 @@ async function updateExistingServices(webappPath, manifest, fs) {
63
220
  }
64
221
  }
65
222
  }
66
- fs.writeJSON((0, path_1.join)(webappPath, 'manifest.json'), manifest);
223
+ return manifest;
67
224
  }
68
225
  /**
69
226
  * Internal function that updates the manifest.json based on the given service configuration.
@@ -71,27 +228,23 @@ async function updateExistingServices(webappPath, manifest, fs) {
71
228
  * @param basePath - the root path of an existing UI5 application
72
229
  * @param service - the OData service instance
73
230
  * @param fs - the memfs editor instance
74
- * @param templateRoot - root folder contain the ejs templates
75
231
  */
76
- async function updateManifest(basePath, service, fs, templateRoot) {
232
+ async function updateManifest(basePath, service, fs) {
77
233
  const webappPath = await (0, project_access_1.getWebappPath)(basePath, fs);
78
234
  const manifestPath = (0, path_1.join)(webappPath, 'manifest.json');
79
235
  // Get component app id
80
236
  const manifest = fs.readJSON(manifestPath);
81
237
  const appProp = 'sap.app';
82
238
  const appid = manifest?.[appProp]?.id;
83
- // Check and update existing services
84
- await updateExistingServices(webappPath, manifest, fs);
85
- const modifiedManifest = fs.readJSON(manifestPath);
86
239
  // Throw if required property is not found manifest.json
87
240
  if (!appid) {
88
241
  throw new Error((0, i18n_1.t)('error.requiredProjectPropertyNotFound', { property: `'${appProp}'.id`, path: manifestPath }));
89
242
  }
90
- const manifestJsonExt = fs.read((0, path_1.join)(templateRoot, 'extend', `manifest.json`));
91
- const manifestSettings = Object.assign(service, getModelSettings((0, project_access_1.getMinimumUI5Version)(modifiedManifest)));
92
- // If the service object includes ejs options, for example 'client' (see: https://ejs.co/#docs),
93
- // resulting in unexpected behaviour and problems when webpacking. Passing an empty options object prevents this.
94
- fs.extendJSON(manifestPath, JSON.parse((0, ejs_1.render)(manifestJsonExt, manifestSettings, {})));
243
+ // Check and update existing services
244
+ const modifiedManifest = await updateExistingServices(webappPath, manifest, fs);
245
+ // Add or update manifest.json with service
246
+ enhanceManifest(service, modifiedManifest);
247
+ fs.writeJSON(manifestPath, modifiedManifest);
95
248
  }
96
249
  /**
97
250
  * Updates the cds index or service file with the provided annotations.
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.24.2",
12
+ "version": "0.25.1",
13
13
  "license": "Apache-2.0",
14
14
  "main": "dist/index.js",
15
15
  "files": [
@@ -38,7 +38,7 @@
38
38
  "@types/semver": "7.5.2",
39
39
  "fs-extra": "10.0.0",
40
40
  "lodash": "4.17.21",
41
- "@sap-ux/project-access": "1.28.9"
41
+ "@sap-ux/project-access": "1.28.10"
42
42
  },
43
43
  "engines": {
44
44
  "node": ">=18.x"
@@ -1,98 +0,0 @@
1
- {
2
- "sap.app": {
3
- "dataSources": {
4
- "<%=name%>": {
5
- "uri": "<%=path%>",
6
- "type": "OData",
7
- "settings": {
8
- "annotations": [
9
- <% if (locals.annotations && typeof annotations !== 'undefined') { %>
10
- <% if (annotations.length) { %>
11
- <% annotations.forEach(function(annotation, index) { %>
12
- <% if (annotation.technicalName) { %>
13
- "<%= annotation.name %>"<% if (index < annotations.length - 1 || locals.localAnnotationsName && (!locals.localAnnotationsName.length || locals.localAnnotationsName.length > 0)) { %>,<% } %>
14
- <% } %>
15
- <% }); %>
16
- <% } else if (annotations.technicalName) { %>
17
- "<%= annotations.name %>"<% if (locals.localAnnotationsName && (!locals.localAnnotationsName.length || locals.localAnnotationsName.length > 0)) {%>,<%}%><% } %>
18
- <% } %>
19
- <% if (locals.localAnnotationsName && typeof localAnnotationsName !== 'undefined') { %>
20
- <% if (Array.isArray(localAnnotationsName)) { %>
21
- <% localAnnotationsName.forEach(function(localAnnotation, index) { %>
22
- "<%- localAnnotation %>"<% if (index < localAnnotationsName.length - 1){ %>,<% } %>
23
- <% }); %>
24
- <% } else if (localAnnotationsName) { %>
25
- "<%- localAnnotationsName %>"
26
- <% } %>
27
- <% } %>
28
- ]
29
- <% if (locals.metadata) { %>,
30
- "localUri": "localService/<%- name %>/metadata.xml" <% } %><%if (version === '4') {%>,
31
- "odataVersion": "4.0"<% } %><%if (version === '2') {%>,
32
- "odataVersion": "2.0"<% } %>
33
- }
34
- }
35
- <% if (locals.annotations && typeof annotations !== 'undefined') { %>
36
- <% if (annotations.length && annotations.length > 0) { %>
37
- <% annotations.forEach(function(annotation, index) { %>
38
- <% if (annotation.technicalName) { %>,
39
- "<%= annotation.name %>": {
40
- "uri": "/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='<%- encodeURIComponent(annotation.technicalName) %>',Version='0001')/$value/",
41
- "type": "ODataAnnotation",
42
- "settings": {
43
- "localUri": "localService/<%- name %>/<%- annotation.technicalName %>.xml"
44
- }
45
- }
46
- <% } %>
47
- <% }); %>
48
- <% } else if (annotations.technicalName) { %>,
49
- "<%= annotations.name %>": {
50
- "uri": "/sap/opu/odata/IWFND/CATALOGSERVICE;v=2/Annotations(TechnicalName='<%- encodeURIComponent(annotations.technicalName) %>',Version='0001')/$value/",
51
- "type": "ODataAnnotation",
52
- "settings": {
53
- "localUri": "localService/<%- name %>/<%- annotations.technicalName %>.xml"
54
- }
55
- }
56
- <% } %>
57
- <% } %>
58
- <% if (locals.localAnnotationsName && typeof localAnnotationsName !== 'undefined') { %>,
59
- <% if (locals.localAnnotationsName && typeof localAnnotationsName !== 'undefined') { %>
60
- <% if (Array.isArray(localAnnotationsName)) { %>
61
- <% localAnnotationsName.forEach(function(localAnnotation, index) { %>
62
- "<%- localAnnotation %>": {
63
- "type": "ODataAnnotation",
64
- "uri": "annotations/<%- localAnnotation %>.xml",
65
- "settings": {
66
- "localUri": "annotations/<%- localAnnotation %>.xml"
67
- }
68
- }<% if (index < localAnnotationsName.length - 1){ %>,<% } %>
69
- <% }); %>
70
- <% } else if (localAnnotationsName) { %>
71
- "<%- localAnnotationsName %>": {
72
- "type": "ODataAnnotation",
73
- "uri": "annotations/<%- localAnnotationsName %>.xml",
74
- "settings": {
75
- "localUri": "annotations/<%- localAnnotationsName %>.xml"
76
- }
77
- } <% } %>
78
- <% } %>
79
- <% } %>
80
- }
81
- },
82
- "sap.ui5": {
83
- "models": {
84
- "<%=model%>": {
85
- "dataSource": "<%=name%>",
86
- "preload": true,
87
- "settings": {<%if (version === '4') {%>
88
- <% if (locals.includeSynchronizationMode) { %>
89
- "synchronizationMode": "None",
90
- <% } %>
91
- "operationMode": "Server",
92
- "autoExpandSelect": true,
93
- "earlyRequests": true<% } %>
94
- }
95
- }
96
- }
97
- }
98
- }