@sap/cds-dk 4.7.3 → 4.8.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/CHANGELOG.md +22 -1
- package/bin/activate.js +5 -1
- package/bin/add.js +2 -2
- package/lib/client/activate.js +8 -3
- package/lib/client/base_command.js +5 -1
- package/lib/client/helper/cf_helper.js +5 -2
- package/lib/client/params.js +16 -2
- package/lib/client/settings_manager.js +15 -8
- package/lib/compile/openapi/csdl2openapi.js +6 -8
- package/lib/compile/to-xsuaa.js +0 -14
- package/lib/import/utils/MetadataConverter.js +6 -4
- package/lib/import/v2parser.js +59 -35
- package/lib/import/v4parser.js +70 -47
- package/lib/init/constants.js +9 -3
- package/lib/init/index.js +13 -7
- package/lib/init/template/_merging/existences.js +161 -0
- package/lib/init/template/approuter/files/default-env.json +9 -0
- package/lib/init/template/approuter/files/mta.yaml.hbs +48 -0
- package/lib/init/template/approuter/files/package.json +9 -0
- package/lib/init/template/approuter/files/xs-app.json +8 -0
- package/lib/init/template/approuter/index.js +66 -0
- package/lib/init/template/auditlog/files/dependencies.package.json +5 -0
- package/lib/init/template/auditlog/files/mta.yaml.hbs +13 -0
- package/lib/init/template/auditlog/index.js +38 -0
- package/lib/init/template/cf-manifest/index.js +1 -1
- package/lib/init/template/hana/files/mta.yaml.hbs +42 -0
- package/lib/init/template/hana/files/nodejs/dependencies.package.json +5 -0
- package/lib/init/template/hana/index.js +53 -24
- package/lib/init/template/java/index.js +1 -5
- package/lib/init/template/mta/files/mta.yaml.hbs +24 -220
- package/lib/init/template/mta/index.js +25 -17
- package/lib/init/template/mtx/files/cds.package.json +24 -0
- package/lib/init/template/mtx/files/dependencies.package.json +5 -0
- package/lib/init/template/mtx/files/mta.yaml.hbs +74 -0
- package/lib/init/template/mtx/files/xs-security.json.hbs +23 -9
- package/lib/init/template/mtx/index.js +126 -29
- package/lib/init/template/templateBase.js +14 -0
- package/lib/init/template/xsuaa/files/cds.package.json +9 -0
- package/lib/init/template/xsuaa/files/dependencies.package.json +6 -0
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +17 -0
- package/lib/init/template/xsuaa/index.js +75 -0
- package/lib/init/util/fsUtil.js +17 -3
- package/lib/init/util/logger.js +3 -1
- package/lib/init/{template/mta → util}/projectReader.js +26 -11
- package/lib/init/util/templateUtil.js +267 -3
- package/lib/util/exec.d.ts +54 -0
- package/lib/util/exec.js +210 -0
- package/lib/watch/livereload-server.js +43 -31
- package/lib/watch/open.js +1 -1
- package/npm-shrinkwrap.json +4089 -15628
- package/package.json +7 -8
- package/readme.md +1 -1
- package/lib/import/internalDoc/edm2cdsTypeMapping.md +0 -38
- package/lib/init/template/mtx/package/cds.package.json +0 -29
- package/lib/init/template/mtx/package/dependencies.package.json +0 -9
package/CHANGELOG.md
CHANGED
|
@@ -6,13 +6,34 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
8
8
|
|
|
9
|
+
## Version 4.8.0 - 2022-01-28
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `cds import` now reflects the entity set and entity container level annotations in the csn.
|
|
14
|
+
- `cds activate --sync` allows to use the synchronous server API for extension upload.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
|
|
18
|
+
- The forked package `@mendix/sqlite3` is now used instead of `sqlite3` to overcome CVE-2021-32804. No code changes in applications are needed, as the new package installed by `npm` with the same name `sqlite3`.
|
|
19
|
+
- [beta] The templating for `cds init` and `cds add` has been rewritten from scratch. This will allow for some new, more complex commands, such as `cds add mtx` or `cds add xsuaa`.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `cds import` now omits function imports with `put/delete` kind.
|
|
24
|
+
- `cds import` has fixed the entity type to entity set mapping in OData V2.
|
|
25
|
+
- `cds import` now supports collection type.
|
|
26
|
+
- `cds watch` now picks a free livereload port if the standard port 35729 is already bound
|
|
27
|
+
- `cds extend`, `cds activate`, `cds login`, and `cds logout` now prioritize command-line options over saved settings
|
|
28
|
+
- MTX client now logs fewer characters of secrets in debug output
|
|
29
|
+
- MTX client now handles incomplete error responses better
|
|
30
|
+
|
|
9
31
|
## Version 4.7.3 - 2022-01-14
|
|
10
32
|
|
|
11
33
|
### Changed
|
|
12
34
|
|
|
13
35
|
- Bump `follow-redirects` package to 1.14.7 (CVE-2022-0155)
|
|
14
36
|
|
|
15
|
-
|
|
16
37
|
## Version 4.7.2 - 2021-12-15
|
|
17
38
|
|
|
18
39
|
### Fixed
|
package/bin/activate.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module.exports = Object.assign(activate, {
|
|
2
|
-
options: ['--subdomain', '--passcode', '--username', '--clientid', '--to'],
|
|
2
|
+
options: ['--subdomain', '--passcode', '--username', '--clientid', '--to', '--sync'],
|
|
3
3
|
flags: ['--undeploy', '--wsdl'],
|
|
4
4
|
shortcuts: ['-s', '-p', '-u', '-c'],
|
|
5
5
|
help: `
|
|
@@ -39,6 +39,10 @@ module.exports = Object.assign(activate, {
|
|
|
39
39
|
|
|
40
40
|
Undeploy a previously deployed extension.
|
|
41
41
|
|
|
42
|
+
*--sync*
|
|
43
|
+
|
|
44
|
+
Use the synchronous server API to upload extensions.
|
|
45
|
+
|
|
42
46
|
`})
|
|
43
47
|
|
|
44
48
|
|
package/bin/add.js
CHANGED
|
@@ -36,8 +36,8 @@ module.exports = Object.assign(add, {
|
|
|
36
36
|
|
|
37
37
|
*-4* | *--for* <entity name or prefix>
|
|
38
38
|
|
|
39
|
-
Filters entity names with the given string.
|
|
40
|
-
it is treated like a regular expression, otherwise as a prefix.
|
|
39
|
+
Filters entity names with the given string. If it contains meta characters like
|
|
40
|
+
'^' or '*', it is treated like a regular expression, otherwise as a prefix.
|
|
41
41
|
|
|
42
42
|
*-o* | *--out* <target folder>
|
|
43
43
|
|
package/lib/client/activate.js
CHANGED
|
@@ -8,6 +8,7 @@ const { collectFileContent, collectFiles, toUnixPath } = require('./helper/fs_he
|
|
|
8
8
|
const Logger = require('./helper/logging');
|
|
9
9
|
|
|
10
10
|
const COMMAND_URL_SUFFIX = 'asyncActivate';
|
|
11
|
+
const COMMAND_URL_SUFFIX_SYNC = 'activate';
|
|
11
12
|
const UPDATE_CUSTOM_FILE_URL_SUFFIX = 'updateCustomTenantContent';
|
|
12
13
|
|
|
13
14
|
const I18N_WHITELIST = ['.properties', '.csv'];
|
|
@@ -36,6 +37,7 @@ async function checkFinished(jobId, statusUrl, params, finisher) {
|
|
|
36
37
|
module.exports = class Activate extends BaseCommand {
|
|
37
38
|
|
|
38
39
|
static get COMMAND_URL_SUFFIX() { return COMMAND_URL_SUFFIX; }
|
|
40
|
+
static get COMMAND_URL_SUFFIX_SYNC() { return COMMAND_URL_SUFFIX_SYNC; }
|
|
39
41
|
static get UPDATE_CUSTOM_FILE_URL_SUFFIX() { return UPDATE_CUSTOM_FILE_URL_SUFFIX; }
|
|
40
42
|
|
|
41
43
|
static async run(injection, paramValues) {
|
|
@@ -46,7 +48,8 @@ module.exports = class Activate extends BaseCommand {
|
|
|
46
48
|
Logger.log('Activating extension with parameters ' + JSON.stringify({
|
|
47
49
|
appUrl: params.get('appUrl'),
|
|
48
50
|
projectFolder: params.get('projectFolder'),
|
|
49
|
-
undeploy: params.get('undeploy')
|
|
51
|
+
undeploy: params.get('undeploy'),
|
|
52
|
+
sync: params.get('sync')
|
|
50
53
|
}));
|
|
51
54
|
} else {
|
|
52
55
|
Logger.log(`Activating extension located at ${params.get('projectFolder')} to URL ${params.get('appUrl')}`);
|
|
@@ -155,6 +158,7 @@ module.exports = class Activate extends BaseCommand {
|
|
|
155
158
|
|
|
156
159
|
static async runActivate(cds, params) {
|
|
157
160
|
let activationUrl;
|
|
161
|
+
const isSync = params.get('sync');
|
|
158
162
|
|
|
159
163
|
return Activate.collectExtensionFiles(cds, params.get('projectFolder'))
|
|
160
164
|
.then(allFiles => {
|
|
@@ -164,7 +168,8 @@ module.exports = class Activate extends BaseCommand {
|
|
|
164
168
|
|
|
165
169
|
Logger.log('Activating extension...');
|
|
166
170
|
|
|
167
|
-
|
|
171
|
+
const urlSuffix = isSync ? Activate.COMMAND_URL_SUFFIX_SYNC : Activate.COMMAND_URL_SUFFIX;
|
|
172
|
+
activationUrl = Activate.getMtxApiUrl(params.get('appUrl'), urlSuffix);
|
|
168
173
|
const requestOptions = Object.assign({
|
|
169
174
|
headers: {}
|
|
170
175
|
}, params.get('reqAuth'));
|
|
@@ -176,7 +181,7 @@ module.exports = class Activate extends BaseCommand {
|
|
|
176
181
|
}, requestOptions);
|
|
177
182
|
})
|
|
178
183
|
.then(response => {
|
|
179
|
-
if (response === null) {
|
|
184
|
+
if (isSync || response === null) {
|
|
180
185
|
return;
|
|
181
186
|
}
|
|
182
187
|
|
|
@@ -19,7 +19,7 @@ module.exports = class BaseCommand {
|
|
|
19
19
|
throw error;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
switch (error.response.status) {
|
|
22
|
+
switch (error.response && error.response.status) {
|
|
23
23
|
case 401:
|
|
24
24
|
Logger.error('Request failed: authorization might have expired. Please retry with valid passcode' +
|
|
25
25
|
(params.has('passcodeUrl') ? ` from ${params.get('passcodeUrl')}` : ''), error);
|
|
@@ -52,4 +52,8 @@ module.exports = class BaseCommand {
|
|
|
52
52
|
static getMtxApiUrl(url, action) {
|
|
53
53
|
return BaseCommand.concatUrls(url, MTX_URL_PATH_PREFIX, action);
|
|
54
54
|
}
|
|
55
|
+
|
|
56
|
+
static getMtxApiUrlSync(url, action) {
|
|
57
|
+
return BaseCommand.concatUrls(url, MTX_URL_PATH_PREFIX, action);
|
|
58
|
+
}
|
|
55
59
|
}
|
|
@@ -154,12 +154,13 @@ async function getSubdomain(appName) {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
Logger.debug(`Subdomain determined from CF app environment: ${value}`);
|
|
157
158
|
return resolve(value);
|
|
158
159
|
});
|
|
159
160
|
});
|
|
160
161
|
|
|
161
162
|
function errorResult(message) {
|
|
162
|
-
Logger.debug(message);
|
|
163
|
+
Logger.debug(`Failed to get subdomain: ${message}`);
|
|
163
164
|
return undefined;
|
|
164
165
|
}
|
|
165
166
|
}
|
|
@@ -174,8 +175,10 @@ async function getAppName(appUrl) {
|
|
|
174
175
|
const app = apps.find(app => equalIgnoringTls(app.url, appUrl));
|
|
175
176
|
if (!app) {
|
|
176
177
|
Logger.debug(`Failed to find app with URL ${appUrl}. Running apps: ${apps.map(app => app.name)}`);
|
|
178
|
+
return;
|
|
177
179
|
}
|
|
178
|
-
|
|
180
|
+
Logger.debug(`App name determined from CF: ${app.name}`);
|
|
181
|
+
return app.name;
|
|
179
182
|
}
|
|
180
183
|
|
|
181
184
|
module.exports = {
|
package/lib/client/params.js
CHANGED
|
@@ -20,7 +20,7 @@ const ObfuscationLevel = Object.freeze({
|
|
|
20
20
|
full: 1,
|
|
21
21
|
partial: 2 // Allows a few start and end characters displayed in DEBUG output; only use with string-type params
|
|
22
22
|
});
|
|
23
|
-
const DISCLOSURE_LENGTH =
|
|
23
|
+
const DISCLOSURE_LENGTH = 2;
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Parameters hold a name and a value and can only be set to compatible values.
|
|
@@ -205,6 +205,7 @@ class AllParams extends BasicParams {
|
|
|
205
205
|
// `activate` PARAMS
|
|
206
206
|
this.undeploy = new Param('undeploy', false);
|
|
207
207
|
this.wsdl = new Param('wsdl', false);
|
|
208
|
+
this.sync = new Param('sync', false);
|
|
208
209
|
|
|
209
210
|
// `logout` PARAMS
|
|
210
211
|
this.deleteSettings = new Param('deleteSettings', false);
|
|
@@ -331,7 +332,7 @@ class ParamCollection {
|
|
|
331
332
|
}
|
|
332
333
|
|
|
333
334
|
/**
|
|
334
|
-
* Add all params contained in another collection to this.
|
|
335
|
+
* Add all params contained in another collection to this, replacing existing params.
|
|
335
336
|
* @param params the other `ParamCollection`
|
|
336
337
|
*/
|
|
337
338
|
merge(params) {
|
|
@@ -341,6 +342,19 @@ class ParamCollection {
|
|
|
341
342
|
}
|
|
342
343
|
}
|
|
343
344
|
|
|
345
|
+
/**
|
|
346
|
+
* Add all params contained in another collection to this, not replacing existing params.
|
|
347
|
+
* @param params the other `ParamCollection`
|
|
348
|
+
*/
|
|
349
|
+
mergeLower(params) {
|
|
350
|
+
this.checkFrozen();
|
|
351
|
+
for (const param of params) {
|
|
352
|
+
if (!this.has(param.name)) {
|
|
353
|
+
this.set(param.name, param.val);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
344
358
|
/**
|
|
345
359
|
* Iterate through all contained param objects.
|
|
346
360
|
*/
|
|
@@ -71,13 +71,18 @@ async function getAppUrlAndSubdomainFromSuggestions(params) {
|
|
|
71
71
|
params.set('appUrl', app.url);
|
|
72
72
|
|
|
73
73
|
if (!params.has('subdomain')) {
|
|
74
|
-
params.set('subdomain', await
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
params.set('subdomain', await getSubdomainFromCfAndNotify(app.name));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async function getSubdomainFromCfAndNotify(appName) {
|
|
79
|
+
const subdomain = await getSubdomain(appName);
|
|
80
|
+
if (subdomain) {
|
|
81
|
+
Logger.log(`Subdomain determined from CF app environment: ${subdomain}`);
|
|
82
|
+
} else {
|
|
83
|
+
Logger.log('Failed to determine subdomain from CF app environment');
|
|
80
84
|
}
|
|
85
|
+
return subdomain;
|
|
81
86
|
}
|
|
82
87
|
|
|
83
88
|
function getTokenBaseUrl(params, renewUrl) {
|
|
@@ -156,7 +161,7 @@ class SettingsManager {
|
|
|
156
161
|
const loadedSettings = await this._loadFromFile(projectFolder);
|
|
157
162
|
Logger.debug(`Loaded project settings: ${loadedSettings.format()}`);
|
|
158
163
|
|
|
159
|
-
params.
|
|
164
|
+
params.mergeLower(loadedSettings);
|
|
160
165
|
|
|
161
166
|
await this.updateUrls(params, logout);
|
|
162
167
|
await this.checkKeytar(params, logout);
|
|
@@ -172,12 +177,13 @@ class SettingsManager {
|
|
|
172
177
|
}
|
|
173
178
|
if (!logout) {
|
|
174
179
|
if (!params.has('appUrl')) {
|
|
180
|
+
Logger.debug('App URL not given');
|
|
175
181
|
await getAppUrlAndSubdomainFromSuggestions(params);
|
|
176
182
|
} else if (!params.has('subdomain')) {
|
|
177
183
|
Logger.debug('Subdomain not given');
|
|
178
184
|
const appName = await getAppName(params.get('appUrl'));
|
|
179
185
|
if (appName) {
|
|
180
|
-
params.set('subdomain', await
|
|
186
|
+
params.set('subdomain', await getSubdomainFromCfAndNotify(appName));
|
|
181
187
|
}
|
|
182
188
|
}
|
|
183
189
|
}
|
|
@@ -189,6 +195,7 @@ class SettingsManager {
|
|
|
189
195
|
if (!params.has('subdomain')) {
|
|
190
196
|
throw new Error('Subdomain not given');
|
|
191
197
|
}
|
|
198
|
+
Logger.log(`Subdomain determined from app URL: ${params.get('subdomain')}`);
|
|
192
199
|
}
|
|
193
200
|
}
|
|
194
201
|
function renewTokenUrl() {
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Converts OData CSDL JSON to OpenAPI 3.0.2
|
|
3
|
-
*
|
|
4
|
-
* Latest version: https://github.wdf.sap.corp/d037427/odata-openapi/blob/master/lib/csdl2openapi.js
|
|
5
3
|
*/
|
|
6
4
|
|
|
7
5
|
var pluralize = require('pluralize')
|
|
@@ -776,7 +774,7 @@ module.exports.csdl2openapi = function (
|
|
|
776
774
|
|
|
777
775
|
/**
|
|
778
776
|
* Unpack EnumMember value if it uses CSDL JSON CS01 style, like CAP does
|
|
779
|
-
* @param {string or object} path Qualified name of referenced type
|
|
777
|
+
* @param {string or object} path Qualified name of referenced type
|
|
780
778
|
* @return {object} Reference Object
|
|
781
779
|
*/
|
|
782
780
|
function enumMember(member) {
|
|
@@ -788,7 +786,7 @@ module.exports.csdl2openapi = function (
|
|
|
788
786
|
|
|
789
787
|
/**
|
|
790
788
|
* Unpack NavigationPropertyPath value if it uses CSDL JSON CS01 style, like CAP does
|
|
791
|
-
* @param {string or object} path Qualified name of referenced type
|
|
789
|
+
* @param {string or object} path Qualified name of referenced type
|
|
792
790
|
* @return {object} Reference Object
|
|
793
791
|
*/
|
|
794
792
|
function navigationPropertyPath(path) {
|
|
@@ -800,7 +798,7 @@ module.exports.csdl2openapi = function (
|
|
|
800
798
|
|
|
801
799
|
/**
|
|
802
800
|
* Unpack PropertyPath value if it uses CSDL JSON CS01 style, like CAP does
|
|
803
|
-
* @param {string or object} path Qualified name of referenced type
|
|
801
|
+
* @param {string or object} path Qualified name of referenced type
|
|
804
802
|
* @return {object} Reference Object
|
|
805
803
|
*/
|
|
806
804
|
function propertyPath(path) {
|
|
@@ -2147,7 +2145,7 @@ module.exports.csdl2openapi = function (
|
|
|
2147
2145
|
|
|
2148
2146
|
/**
|
|
2149
2147
|
* Augment OpenAPI document with Security Requirements Object
|
|
2150
|
-
* @param {object} openapi OpenAPI document to augment
|
|
2148
|
+
* @param {object} openapi OpenAPI document to augment
|
|
2151
2149
|
* @param {object} entityContainer Entity Container object
|
|
2152
2150
|
*/
|
|
2153
2151
|
function security(openapi, entityContainer) {
|
|
@@ -2162,7 +2160,7 @@ module.exports.csdl2openapi = function (
|
|
|
2162
2160
|
|
|
2163
2161
|
/**
|
|
2164
2162
|
* a qualified name consists of a namespace or alias, a dot, and a simple name
|
|
2165
|
-
* @param {string} qualifiedName
|
|
2163
|
+
* @param {string} qualifiedName
|
|
2166
2164
|
* @return {string} namespace-qualified name
|
|
2167
2165
|
*/
|
|
2168
2166
|
function namespaceQualifiedName(qualifiedName) {
|
|
@@ -2172,7 +2170,7 @@ module.exports.csdl2openapi = function (
|
|
|
2172
2170
|
|
|
2173
2171
|
/**
|
|
2174
2172
|
* a qualified name consists of a namespace or alias, a dot, and a simple name
|
|
2175
|
-
* @param {string} qualifiedName
|
|
2173
|
+
* @param {string} qualifiedName
|
|
2176
2174
|
* @return {object} with components qualifier and name
|
|
2177
2175
|
*/
|
|
2178
2176
|
function nameParts(qualifiedName) {
|
package/lib/compile/to-xsuaa.js
CHANGED
|
@@ -107,8 +107,6 @@ module.exports = function compile_to_xsuaa (model, options) {
|
|
|
107
107
|
|
|
108
108
|
function mergeConfig(base, generated) {
|
|
109
109
|
const result = base
|
|
110
|
-
result.xsappname = base.xsappname || appName()
|
|
111
|
-
result['tenant-mode'] = base['tenant-mode'] || 'dedicated'
|
|
112
110
|
|
|
113
111
|
const mergeByName = (type) => {
|
|
114
112
|
if (!generated[type]) return
|
|
@@ -140,15 +138,3 @@ function getBaseModel(options = {}) {
|
|
|
140
138
|
}
|
|
141
139
|
return options.base || {}
|
|
142
140
|
}
|
|
143
|
-
|
|
144
|
-
function appName() {
|
|
145
|
-
const cwd = cds.root || process.cwd()
|
|
146
|
-
let name
|
|
147
|
-
try {
|
|
148
|
-
name = require(path.resolve(cwd,'package.json')).name
|
|
149
|
-
} catch (err) { // no package.json
|
|
150
|
-
name = path.basename(cwd)
|
|
151
|
-
}
|
|
152
|
-
// remove any @foo/ from @foo/bar, truncate to max length
|
|
153
|
-
return name.split('/').pop().substring(0, 100)
|
|
154
|
-
}
|
|
@@ -396,7 +396,6 @@ class Expression {
|
|
|
396
396
|
const target = this.getTarget();
|
|
397
397
|
const element = this.getElement();
|
|
398
398
|
const attribs = element.attributes;
|
|
399
|
-
let custom_namespace = MetadataConverter.custom_namespace;
|
|
400
399
|
if (attribs == null) return;
|
|
401
400
|
let realType = attribs.Type || attribs.EntityType || attribs.UnderlyingType;
|
|
402
401
|
const propertyName = attribs.UnderlyingType == null ? '$Type' : '$UnderlyingType';
|
|
@@ -574,6 +573,9 @@ class Expression {
|
|
|
574
573
|
!(target.$Kind === 'NavigationProperty' && target.$Collection === true)) {
|
|
575
574
|
target.$Nullable = true;
|
|
576
575
|
}
|
|
576
|
+
this.includeExternalAnnotations(element,target);
|
|
577
|
+
}
|
|
578
|
+
includeExternalAnnotations(element,target){
|
|
577
579
|
const nonStdAttributes = this.getNonStdAttributes(element.attributes);
|
|
578
580
|
for (let i = 0; i < nonStdAttributes.length; i++) {
|
|
579
581
|
let attr = nonStdAttributes[i];
|
|
@@ -581,7 +583,7 @@ class Expression {
|
|
|
581
583
|
if(attrName)
|
|
582
584
|
attrName = attrName.replace(/-/g,'.');
|
|
583
585
|
let attribute;
|
|
584
|
-
if ((custom_namespace.includes(prefix) && attrName !== undefined) || custom_namespace.includes(true))
|
|
586
|
+
if ((MetadataConverter.custom_namespace.includes(prefix) && attrName !== undefined) || MetadataConverter.custom_namespace.includes(true))
|
|
585
587
|
attribute = "@" + prefix + "." + attrName;
|
|
586
588
|
else if (attrName === undefined)
|
|
587
589
|
attribute = "$" + prefix;
|
|
@@ -2221,10 +2223,10 @@ class EntityContainerExpression extends Expression {
|
|
|
2221
2223
|
interpret() {
|
|
2222
2224
|
const element = this.getElement();
|
|
2223
2225
|
const target = { $Kind: 'EntityContainer' };
|
|
2226
|
+
this.includeExternalAnnotations(element,target);
|
|
2224
2227
|
this.setTarget(target);
|
|
2225
2228
|
super.interpret();
|
|
2226
|
-
|
|
2227
|
-
return { [element.attributes.Name]: target };
|
|
2229
|
+
return { [element.attributes.Name]: target};
|
|
2228
2230
|
}
|
|
2229
2231
|
}
|
|
2230
2232
|
|
package/lib/import/v2parser.js
CHANGED
|
@@ -9,6 +9,7 @@ let allEntities = [];
|
|
|
9
9
|
let allEntitiesMC = [];
|
|
10
10
|
let allEntitySetMap = {};
|
|
11
11
|
let allEntitySetMapMC = {};
|
|
12
|
+
let allEntitySetNamespaces = {};
|
|
12
13
|
let allFunctionImports = [];
|
|
13
14
|
let allFunctionImportsMap = {};
|
|
14
15
|
let allAssociations = {};
|
|
@@ -248,6 +249,9 @@ function _extractEntityFromEntitySet(entitySet) {
|
|
|
248
249
|
allEntitySetMapMC[entitySet[key].EntityType] = [];
|
|
249
250
|
allEntitySetMapMC[entitySet[key].EntityType].push(entitySet[key].Name);
|
|
250
251
|
entityName = _extractEntityFromNamespace(entitySet[key].EntityType);
|
|
252
|
+
let namespaces = namespaceAttributeFilter(entitySet[key]);
|
|
253
|
+
if(namespaces.length)
|
|
254
|
+
allEntitySetNamespaces[entitySet[key].Name] = namespaces;
|
|
251
255
|
allEntities.push(entityName);
|
|
252
256
|
allEntitiesMC.push(entitySet[key].Name);
|
|
253
257
|
}
|
|
@@ -414,9 +418,16 @@ function _getServiceEntityProperty(
|
|
|
414
418
|
displayFormat,
|
|
415
419
|
isKey,
|
|
416
420
|
documentation,
|
|
417
|
-
isCollection,
|
|
418
421
|
allowedNamespaceAttributes = -1
|
|
419
422
|
) {
|
|
423
|
+
let isCollection = -1;
|
|
424
|
+
//preprocessing of datatype in case it is a collection
|
|
425
|
+
if(dataType.substring(0,10) === 'Collection')
|
|
426
|
+
{
|
|
427
|
+
dataType = dataType.substring(11,dataType.length-1);
|
|
428
|
+
isCollection = 1;
|
|
429
|
+
}
|
|
430
|
+
|
|
420
431
|
let cdsDataType = null;
|
|
421
432
|
let hasInvalidPrecision = false;
|
|
422
433
|
let propertyJson='';
|
|
@@ -452,7 +463,7 @@ function _getServiceEntityProperty(
|
|
|
452
463
|
|
|
453
464
|
//Possibility of entity type or entity set as the data type
|
|
454
465
|
if (!cdsDataType && allEntitySetMapMC[dataType]) {
|
|
455
|
-
cdsDataType = serviceNamespace + "." + allEntitySetMapMC[dataType];
|
|
466
|
+
cdsDataType = serviceNamespace + "." + allEntitySetMapMC[dataType][0];
|
|
456
467
|
} else if(!cdsDataType && allEntitySetMap[_extractEntityFromNamespace(dataType)]) {
|
|
457
468
|
cdsDataType = dataType;
|
|
458
469
|
}
|
|
@@ -553,7 +564,6 @@ function _getServiceComplexType(complexTypeKey, complexType) {
|
|
|
553
564
|
complexTypeProperty["sap:display-format"],
|
|
554
565
|
false,
|
|
555
566
|
complexTypeProperty.doc,
|
|
556
|
-
-1,
|
|
557
567
|
complexTypePropertyNamespace
|
|
558
568
|
);
|
|
559
569
|
complexTypeCSN = complexTypeCSN + complexProperty;
|
|
@@ -583,7 +593,6 @@ function _getServiceComplexType(complexTypeKey, complexType) {
|
|
|
583
593
|
complexTypeProperty["sap:display-format"],
|
|
584
594
|
false,
|
|
585
595
|
complexTypeProperty.doc,
|
|
586
|
-
-1,
|
|
587
596
|
complexTypePropertyNamespace
|
|
588
597
|
);
|
|
589
598
|
}
|
|
@@ -630,28 +639,20 @@ function _parseParameter(parameter)
|
|
|
630
639
|
{
|
|
631
640
|
let csn = "";
|
|
632
641
|
let doc;
|
|
633
|
-
let isCollection = -1;
|
|
634
642
|
if(parameter.Documentation)
|
|
635
643
|
doc = _parseDocumentationTag(parameter.Documentation);
|
|
636
644
|
|
|
637
645
|
let namespaceAttributes = namespaceAttributeFilter(parameter._attributes);
|
|
638
646
|
const parameterNamespaceAttributes = namespaceAttributes.length ? namespaceAttributes : -1;
|
|
639
647
|
|
|
640
|
-
let type = parameter["_attributes"].Type;
|
|
641
|
-
if(type.substring(0,10) === 'Collection')
|
|
642
|
-
{
|
|
643
|
-
type = type.substring(11,type.length-1);
|
|
644
|
-
isCollection = 1;
|
|
645
|
-
}
|
|
646
648
|
csn = csn + _getServiceEntityProperty(parameter["_attributes"].Name,
|
|
647
|
-
|
|
649
|
+
parameter["_attributes"].Type,
|
|
648
650
|
parameter["_attributes"].MaxLength,
|
|
649
651
|
parameter["_attributes"].Precision,
|
|
650
652
|
parameter["_attributes"].Scale,
|
|
651
653
|
parameter["_attributes"]["sap:display-format"],
|
|
652
654
|
false,
|
|
653
655
|
doc,
|
|
654
|
-
isCollection,
|
|
655
656
|
parameterNamespaceAttributes);
|
|
656
657
|
return csn;
|
|
657
658
|
}
|
|
@@ -693,6 +694,10 @@ function _getFunctionImport(functionImport,isBounded) {
|
|
|
693
694
|
} else if(functionImport[1] === "POST")
|
|
694
695
|
{
|
|
695
696
|
csn = csn + "action";
|
|
697
|
+
} else {
|
|
698
|
+
let message = functionImport[0].substring(functionImport[0].lastIndexOf(".") + 1) + " has kind " + functionImport[1] + " which is not supported.";
|
|
699
|
+
console.log(warn(message));
|
|
700
|
+
return "";
|
|
696
701
|
}
|
|
697
702
|
csn = csn + '"';
|
|
698
703
|
if(functionImport[3] !== -1)
|
|
@@ -711,19 +716,13 @@ function _getFunctionImport(functionImport,isBounded) {
|
|
|
711
716
|
}
|
|
712
717
|
if(functionImport[2] !== -1)
|
|
713
718
|
{
|
|
714
|
-
let
|
|
715
|
-
if(functionImport[2].substring(0,10) === 'Collection')
|
|
716
|
-
{
|
|
717
|
-
functionImport[2] = functionImport[2].substring(11,functionImport[2].length-1);
|
|
718
|
-
isCollection = 1;
|
|
719
|
-
}
|
|
720
|
-
let returnCsn = _getServiceEntityProperty(noValue,functionImport[2],noValue,noValue,noValue,noValue,noValue,noValue,isCollection);
|
|
719
|
+
let returnCsn = _getServiceEntityProperty(noValue,functionImport[2],noValue,noValue,noValue,noValue,noValue,noValue);
|
|
721
720
|
if(returnCsn != "")
|
|
722
721
|
{
|
|
723
722
|
csn = csn + ", \n";
|
|
724
723
|
csn = csn + '"returns": { \n';
|
|
725
724
|
//return type
|
|
726
|
-
csn = csn +
|
|
725
|
+
csn = csn + returnCsn;
|
|
727
726
|
csn = csn + '\n }';
|
|
728
727
|
}
|
|
729
728
|
}
|
|
@@ -737,21 +736,25 @@ function _getFunctionImport(functionImport,isBounded) {
|
|
|
737
736
|
}
|
|
738
737
|
|
|
739
738
|
function _getAllFunctionImports(functionImports,isBounded) {
|
|
740
|
-
let
|
|
739
|
+
let functionImportsCSN = "";
|
|
741
740
|
let i;
|
|
741
|
+
let functionImportCSN = "";
|
|
742
742
|
for(i=0; i<functionImports.length;i++)
|
|
743
743
|
{
|
|
744
|
-
functionImportCSN =
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
functionImportCSN = functionImportCSN + ",\n";
|
|
744
|
+
functionImportCSN = _getFunctionImport(functionImports[i],isBounded);
|
|
745
|
+
functionImportsCSN = functionImportsCSN + functionImportCSN;
|
|
746
|
+
if(i!== functionImports.length - 1 && functionImportCSN !== "" ) {
|
|
747
|
+
functionImportsCSN = functionImportsCSN + ",\n";
|
|
749
748
|
} else {
|
|
750
|
-
|
|
749
|
+
functionImportsCSN = functionImportsCSN + "\n";
|
|
751
750
|
}
|
|
752
751
|
}
|
|
753
752
|
|
|
754
|
-
|
|
753
|
+
//if last function import is omitted, remove the extra characters
|
|
754
|
+
if (functionImportsCSN && (functionImportsCSN.endsWith(",\n") || functionImportsCSN.endsWith(",\n\n"))) {
|
|
755
|
+
functionImportsCSN= functionImportsCSN.substring(0, functionImportsCSN.lastIndexOf(",\n")) + "\n";
|
|
756
|
+
}
|
|
757
|
+
return functionImportsCSN;
|
|
755
758
|
}
|
|
756
759
|
|
|
757
760
|
function _getEntityName(entity) {
|
|
@@ -893,7 +896,6 @@ function _generateCSNEntityKeys(entityKeysList, entityPropertiesMap) {
|
|
|
893
896
|
propAttributes[4],
|
|
894
897
|
true,
|
|
895
898
|
propAttributes[5],
|
|
896
|
-
-1,
|
|
897
899
|
propAttributes[6]
|
|
898
900
|
);
|
|
899
901
|
csnEntity = csnEntity + keyCsn;
|
|
@@ -935,7 +937,6 @@ function _generateCSNEntityProperties(entityKeysList, entityPropertiesMap) {
|
|
|
935
937
|
propAttributes[4],
|
|
936
938
|
false,
|
|
937
939
|
propAttributes[5],
|
|
938
|
-
-1,
|
|
939
940
|
propAttributes[6]
|
|
940
941
|
);
|
|
941
942
|
csnEntity = csnEntity + propertyString;
|
|
@@ -1306,6 +1307,8 @@ function _constructServiceEntity(
|
|
|
1306
1307
|
mockServerUc,
|
|
1307
1308
|
documentation
|
|
1308
1309
|
) {
|
|
1310
|
+
let filteredNamespaces = {};
|
|
1311
|
+
let namespaces = [];
|
|
1309
1312
|
let serviceEntityName = serviceNamespaceParam + "." + entityName;
|
|
1310
1313
|
let csnEntity = '"' + serviceEntityName + '": {\n';
|
|
1311
1314
|
let csnKeys;
|
|
@@ -1322,10 +1325,29 @@ function _constructServiceEntity(
|
|
|
1322
1325
|
csnEntity = csnEntity + '"abstract": true,\n';
|
|
1323
1326
|
}
|
|
1324
1327
|
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
+
/* Merging the namespace list from entity set and entity type
|
|
1329
|
+
And in case of same label, entity set's value will have precedence */
|
|
1330
|
+
if(allEntitySetNamespaces[entityName]){
|
|
1331
|
+
allEntitySetNamespaces[entityName].forEach((item) => {
|
|
1332
|
+
filteredNamespaces[Object.keys(item)[0]] = Object.values(item)[0];
|
|
1333
|
+
});
|
|
1328
1334
|
}
|
|
1335
|
+
if(entityAttributes.allowedNamespaceAttributes.length){
|
|
1336
|
+
entityAttributes.allowedNamespaceAttributes.forEach((item) => {
|
|
1337
|
+
if(!filteredNamespaces[Object.keys(item)[0]]){
|
|
1338
|
+
filteredNamespaces[Object.keys(item)[0]] = Object.values(item)[0];
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
}
|
|
1342
|
+
Object.keys(filteredNamespaces).forEach((item) => {
|
|
1343
|
+
let obj = {};
|
|
1344
|
+
obj[item] = filteredNamespaces[item];
|
|
1345
|
+
namespaces.push(obj)
|
|
1346
|
+
});
|
|
1347
|
+
|
|
1348
|
+
if(namespaces)
|
|
1349
|
+
csnEntity += _generateNamespaceAttributes(namespaces, false);
|
|
1350
|
+
|
|
1329
1351
|
// if documentation exists for the entity
|
|
1330
1352
|
if (documentation) {
|
|
1331
1353
|
csnEntity = csnEntity + `"doc": "${documentation}",` + '\n';
|
|
@@ -1563,13 +1585,15 @@ function _generateEDMXJSON2CSN(
|
|
|
1563
1585
|
|
|
1564
1586
|
if (mockServerUc) {
|
|
1565
1587
|
let def = '"' + serviceNamespaceParam + '": {"kind": "service"' + ',\n' + '"@cds.external": true';
|
|
1566
|
-
|
|
1567
1588
|
let serviceDoc = jsonObj["edmx:Edmx"]["edmx:DataServices"]["Schema"].EntityContainer.Documentation;
|
|
1589
|
+
let namespaceAttributes = namespaceAttributeFilter(jsonObj["edmx:Edmx"]["edmx:DataServices"]["Schema"].EntityContainer["_attributes"]);
|
|
1568
1590
|
// if documentation exists for service
|
|
1569
1591
|
if (serviceDoc) {
|
|
1570
1592
|
let doc = _parseDocumentationTag(serviceDoc);
|
|
1571
1593
|
if (doc) def += ',\n' + `"doc": "${doc}"`;
|
|
1572
1594
|
}
|
|
1595
|
+
if(namespaceAttributes.length)
|
|
1596
|
+
def += _generateNamespaceAttributes(namespaceAttributes,true);
|
|
1573
1597
|
def += "}";
|
|
1574
1598
|
definitions.push(def);
|
|
1575
1599
|
}
|