@sap/cds-dk 4.8.1 → 4.9.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.
Files changed (83) hide show
  1. package/CHANGELOG.md +55 -0
  2. package/bin/activate.js +8 -7
  3. package/bin/bind.js +12 -12
  4. package/bin/build/all.js +3 -5
  5. package/bin/build/index.js +1 -1
  6. package/bin/cds.js +1 -1
  7. package/bin/deploy/index.js +7 -1
  8. package/bin/deploy/to-hana.js +5 -4
  9. package/bin/deploy/to-sqlite.js +2 -1
  10. package/bin/extend.js +5 -5
  11. package/bin/help.js +1 -0
  12. package/bin/import.js +45 -31
  13. package/bin/login.js +5 -6
  14. package/bin/logout.js +2 -2
  15. package/bin/parse.js +19 -0
  16. package/lib/bind/bindingUtil.js +41 -49
  17. package/lib/bind/cfKeyProvider.js +9 -17
  18. package/lib/bind/userCdsrcJsonStorageProvider.js +1 -0
  19. package/lib/client/activate.js +3 -2
  20. package/lib/client/extend.js +5 -6
  21. package/lib/client/helper/fs_helper.js +8 -8
  22. package/lib/client/settings_manager.js +12 -9
  23. package/lib/compile/openapi/csdl2openapi.js +213 -165
  24. package/lib/compile/openapi/index.js +1 -2
  25. package/lib/compile/to-xsuaa.js +1 -1
  26. package/lib/import/index.js +22 -15
  27. package/lib/import/message.js +3 -1
  28. package/lib/import/utils/MetadataConverter.js +1 -1
  29. package/lib/import/v2parser.js +112 -56
  30. package/lib/import/v4parser.js +152 -99
  31. package/lib/init/constants.js +6 -2
  32. package/lib/init/index.js +3 -2
  33. package/lib/init/template/_merging/existences.js +80 -4
  34. package/lib/init/template/approuter/files/cds.cdsrc.json +7 -0
  35. package/lib/init/template/approuter/files/cds.cdsrc.json.hbs +9 -0
  36. package/lib/init/template/approuter/files/cds.package.json +9 -0
  37. package/lib/init/template/approuter/files/cds.package.json.hbs +11 -0
  38. package/lib/init/template/approuter/files/index.html +1 -0
  39. package/lib/init/template/approuter/files/mta.yaml.hbs +35 -21
  40. package/lib/init/template/approuter/files/package.json +3 -0
  41. package/lib/init/template/approuter/files/xs-app.json.hbs +19 -0
  42. package/lib/init/template/approuter/index.js +47 -18
  43. package/lib/init/template/auditlog/index.js +5 -5
  44. package/lib/init/template/hana/files/java/cdsrc.json.hbs +7 -0
  45. package/lib/init/template/hana/files/java/{package.json → db/package.json} +0 -0
  46. package/lib/init/template/hana/files/java/profile.cdsrc.json.hbs +12 -0
  47. package/lib/init/template/hana/files/mta.yaml.hbs +10 -17
  48. package/lib/init/template/hana/files/nodejs/cds.package.json.hbs +9 -0
  49. package/lib/init/template/hana/files/nodejs/cds.profile.package.json.hbs +14 -0
  50. package/lib/init/template/hana/files/nodejs/dependencies.package.json +1 -1
  51. package/lib/init/template/hana/index.js +60 -86
  52. package/lib/init/template/java/index.js +5 -2
  53. package/lib/init/template/kibana-logging/files/cds.package.json +7 -0
  54. package/lib/init/template/kibana-logging/files/cds.profile.package.json.hbs +9 -0
  55. package/lib/init/template/kibana-logging/files/mta.yaml.hbs +13 -0
  56. package/lib/init/template/kibana-logging/index.js +64 -0
  57. package/lib/init/template/mta/files/mta.yaml.hbs +3 -8
  58. package/lib/init/template/mta/index.js +8 -2
  59. package/lib/init/template/mtx/files/cds.package.json +0 -12
  60. package/lib/init/template/mtx/files/cds.package.json.hbs +14 -0
  61. package/lib/init/template/mtx/files/java/.cdsrc.json +17 -0
  62. package/lib/init/template/mtx/files/java/package.json +43 -0
  63. package/lib/init/template/mtx/files/java/server.js +30 -0
  64. package/lib/init/template/mtx/files/mta.yaml.hbs +6 -6
  65. package/lib/init/template/mtx/index.js +41 -22
  66. package/lib/init/template/templateBase.js +4 -1
  67. package/lib/init/template/xsuaa/files/cds.cdsrc.json +7 -0
  68. package/lib/init/template/xsuaa/files/cds.cdsrc.json.hbs +9 -0
  69. package/lib/init/template/xsuaa/files/cds.package.json +1 -1
  70. package/lib/init/template/xsuaa/files/cds.package.json.hbs +11 -0
  71. package/lib/init/template/xsuaa/files/mta.yaml.hbs +2 -2
  72. package/lib/init/template/xsuaa/index.js +43 -27
  73. package/lib/init/types.d.ts +43 -19
  74. package/lib/init/util/fsUtil.js +15 -4
  75. package/lib/init/util/projectReader.js +21 -18
  76. package/lib/init/util/templateUtil.js +78 -28
  77. package/lib/util/exec.js +2 -2
  78. package/lib/watch/livereload-server.js +3 -0
  79. package/lib/watch/node-watch.js +8 -1
  80. package/npm-shrinkwrap.json +604 -286
  81. package/package.json +3 -3
  82. package/lib/init/template/approuter/files/xs-app.json +0 -8
  83. package/lib/init/template/nodejs/files/.vscode/settings.json +0 -7
package/CHANGELOG.md CHANGED
@@ -6,6 +6,60 @@ 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.9.1 - 2022-04-01
10
+
11
+ ### Changed
12
+
13
+ - `cds init` uses latest Maven Java archetype version 1.23.0 for creating Java projects.
14
+ - Include `@sap/cds` 5.9.1
15
+ - Include `@sap/cds-compiler` 2.13.8
16
+ - Include `@sap/eslint-plugin` 2.3.4
17
+
18
+ ## Version 4.9.0 - 2022-03-28
19
+
20
+ ### Added
21
+
22
+ - `cds parse` as convenient shortcut to `cds compile --flavor parsed`.
23
+ - `cds compile --to openapi` uses value of annotation `@Common.Label` on entities, actions, and functions for operation tags, diagram includes non-primitive action and function import parameters.
24
+ - `cds add` now accepts `--for <profile>` argument to create Node,js project configuration for a given profile
25
+ - `cds add approuter` allows for serving your application’s UI using SAP approuter.
26
+ - `cds add kibana-logging` adds Kibana-friendly logging in a more convenient way than having to manually alter the package.json.
27
+
28
+ ### Changed
29
+
30
+ - `cds init` does not create `VS Code` file exclusions anymore, so that `.vscode/` and `.gitignore` are visible by default, allowing easier editing of these files.
31
+ - `cds init` reports Maven archetype version in console if called with `--add java`.
32
+ - `cds init` uses latest Maven Java archetype version 1.22.2 for creating Java projects.
33
+ - `cds import` modified documentation for namespace option.
34
+ - `cds import` does not create bound function imports key parameters in CSN for OData V2.
35
+ - `cds import` now when `--keep-namespace` option is not given validates the file name and then converts it to complier supported format as service name .
36
+ - add new methods from `FsUtil` to typescript interface.
37
+
38
+ ### Fixed
39
+ - `cds compile --to openapi` now correctly treats `null` and the empty string as function parameters.
40
+ - `cds bind --exec` no command output (STDOUT) displayed on Windows.
41
+ - `cds watch` now gracefully shuts down the live reload server before exiting
42
+ - `cds import` now generates correct csn for both OData V2 and V4 EDMX files where the EntityType has a BaseType entry.
43
+ - `cds import` now throws an error in case of missing Association Sets.
44
+ - `cds import` bug fixed for `--force` flag. Now overwrites the correct file content.
45
+ - `cds import` fix will no longer capture unwanted annotations in the CSN for OData V4.
46
+ - `cds import` now support annotations for properties of type `Type Definition`
47
+ - `cds import` fix for supporting valid datatypes in unbounded function imports for OData V4.
48
+ - `cds import` bug fixed for missing data imports for parameters with entity type not mapped to an entity set.
49
+ - `cds import` now supports properties with complex type for OData V4.
50
+ - `cds import` fix will now throw error if the key property of an entity is of type `Collection` for both OData V2 and V4 edmx.
51
+ - `cds bind --to hana` provides more comprehensive error message in case Cloud Foundry `org` or `space` are not set.
52
+
53
+ ## Version 4.8.2 - 2022-03-07
54
+
55
+ ### Fixed
56
+
57
+ - `cds import` can now capture the data for any given `EntityContainer Name` for OData V4. Earlier it only worked when the name was `EntityContainer`.
58
+
59
+ ### Changed
60
+
61
+ - `cds init` uses latest Maven Java archetype version 1.22.1 for creating Java projects.
62
+
9
63
  ## Version 4.8.1 - 2022-02-15
10
64
 
11
65
  ### Changed
@@ -28,6 +82,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
28
82
 
29
83
  - 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`.
30
84
  - [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`.
85
+ - Use `cds bind` during `cds deploy` to store connection information in file `.cdsrc-private.json`.
31
86
 
32
87
  ### Fixed
33
88
 
package/bin/activate.js CHANGED
@@ -8,7 +8,7 @@ module.exports = Object.assign(activate, {
8
8
  *cds activate* [ <extension-project-directory> ]
9
9
 
10
10
  Activate an extension project.
11
- Unless given as an argument, the current working directory is used as project directory.
11
+ By default, the current working directory is used as project directory.
12
12
 
13
13
  To facilitate running this multiple times against the same app, refer to the *cds login* command.
14
14
 
@@ -16,16 +16,17 @@ module.exports = Object.assign(activate, {
16
16
  # OPTIONS
17
17
 
18
18
  *--to* <url>
19
- Specify the URL of the extension project that you want to activate.
20
19
 
21
- *-s* | *--subdomain* <subdomain>
20
+ Specify the URL of the extensible SaaS app. By default, it's determined from project settings.
22
21
 
23
- Specify the subdomain of the subaccount where you activate the extension.
22
+ *-s* | *--subdomain* <tenant-subdomain>
23
+
24
+ Specify your tenant's subdomain. By default, it's determined from project settings.
24
25
 
25
26
  *-p* | *--passcode* <passcode>
26
27
 
27
- Add the passcode used for authentication.
28
- Also see cds login --help or https://cap.cloud.sap/docs/guides/extensibility#save-authentication-token-for-simplified-workflow
28
+ Tenant-specific passcode for authentication.
29
+ Also see cds login --help or https://cap.cloud.sap/docs/guides/extensibility/#save-an-authentication-token-for-a-simplified-workflow
29
30
 
30
31
  *-u* | *--username* <name>
31
32
 
@@ -37,7 +38,7 @@ module.exports = Object.assign(activate, {
37
38
 
38
39
  *--undeploy*
39
40
 
40
- Undeploy a previously deployed extension.
41
+ Undeploy a previously deployed extension, e.g. to remove a renamed or otherwise obsolete extension.
41
42
 
42
43
  *--sync*
43
44
 
package/bin/bind.js CHANGED
@@ -60,7 +60,7 @@ const { determineKinds, getRequiresNameFromKind, execAndExit, checkIsJavaProject
60
60
 
61
61
  const VCAP_LABEL_PLACEHOLDER = '<replace with service label>';
62
62
 
63
- async function cds_bind(args, options) {
63
+ async function cds_bind(args, options, logger = LOG) {
64
64
  options.profile = parseProfile(options.profile);
65
65
  setProfile(options.profile);
66
66
 
@@ -92,7 +92,7 @@ async function cds_bind(args, options) {
92
92
  throw new Error(`The option '--kind' cannot be specified together with multiple targets ('--to') services. Use one service per call or omit the '--kind' option.`);
93
93
  }
94
94
 
95
- const spinner = new Spinner(LOG);
95
+ const spinner = new Spinner(logger);
96
96
 
97
97
  let on;
98
98
  if (options.on === 'k8s' || options.on === 'kubernetes') {
@@ -105,7 +105,7 @@ async function cds_bind(args, options) {
105
105
 
106
106
  const onText = { 'cf': 'Cloud Foundry', 'k8s': 'Kubernetes' }[on];
107
107
  const resolvedServices = await spinner.run(`Retrieving data from ${onText}...`, async () => { // NOSONAR
108
- return await Promise.all( targets.map( async target => {
108
+ return await Promise.all(targets.map(async target => {
109
109
 
110
110
  let binding;
111
111
  if (on === 'k8s') {
@@ -126,9 +126,9 @@ async function cds_bind(args, options) {
126
126
  });
127
127
 
128
128
  if (options.kind) {
129
- resolvedServices.forEach( service => service.kind = options.kind );
129
+ resolvedServices.forEach(service => service.kind = options.kind);
130
130
  } else {
131
- determineKinds(resolvedServices);
131
+ determineKinds(resolvedServices, LOG);
132
132
  }
133
133
 
134
134
  for (const resolvedService of resolvedServices) {
@@ -152,11 +152,11 @@ async function cds_bind(args, options) {
152
152
  const kindText = kind && `with kind ${highlight(kind)}`;
153
153
  const nameText = !isJavaProject && highlight(name);
154
154
 
155
- LOG.log(['Binding', nameText, 'to', platformText(binding), bindingText(binding, highlight), kindText].filter( t => t ).join(' '));
155
+ logger.log(['Binding', nameText, 'to', platformText(binding), bindingText(binding, highlight), kindText].filter(t => t).join(' '));
156
156
 
157
157
  if (isJavaProject && !hasVcapLabel(binding) && !hasVcapLabel(env.requires[resolvedService.name]) && !(kind && hasVcapLabel(env.requires[kind]))) {
158
158
  resolvedService.vcap = { label: VCAP_LABEL_PLACEHOLDER };
159
- LOG.log(`${info('INFO:')} Please add a "vcap.label" property to the binding for consumption in CAP Java projects`);
159
+ logger.log(`${info('INFO:')} Please add a "vcap.label" property to the binding for consumption in CAP Java projects`);
160
160
  }
161
161
  }
162
162
 
@@ -165,18 +165,18 @@ async function cds_bind(args, options) {
165
165
 
166
166
  await userCdsrcJsonStorageProvider.storeServices(resolvedServices, {
167
167
  ...options,
168
- logger: LOG
168
+ logger
169
169
  });
170
170
 
171
- LOG.log();
172
- LOG.log(`${info('TIP:')} Run with cloud bindings: ${bold(runCmd(options, isJavaProject))}`);
171
+ logger.log();
172
+ logger.log(`${info('TIP:')} Run with cloud bindings: ${bold(runCmd(options, isJavaProject))}`);
173
173
  }
174
174
 
175
175
  async function cds_bind_exec(command) { // eslint-disable-lint
176
176
  const cds = require('@sap/cds/lib');
177
177
  const env = cds.env.for('cds', process.cwd());
178
178
  env._emulate_vcap_services();
179
- await require('../lib/bind/bindingResolver').applyTo({env, output: 'info'});
179
+ await require('../lib/bind/bindingResolver').applyTo({ env, output: 'info' });
180
180
  execAndExit(...command);
181
181
  }
182
182
 
@@ -184,7 +184,7 @@ function hasVcapLabel(service) {
184
184
  return service && service.vcap && service.vcap.label && service.vcap.label != VCAP_LABEL_PLACEHOLDER;
185
185
  }
186
186
 
187
- function runCmd({profile}, isJavaProject) {
187
+ function runCmd({ profile }, isJavaProject) {
188
188
  if (isJavaProject) {
189
189
  const p = profile === 'hybrid' ? '' : ` --profile ${profile}`;
190
190
  return `cds bind exec${p} mvn spring-boot:run`;
package/bin/build/all.js CHANGED
@@ -1,5 +1,3 @@
1
- const _cds = require('@sap/cds/lib')
2
-
3
1
  module.exports = Object.assign(build, {
4
2
  options: ['--project', '--for', '--use', '--src', '--dest', '--options-model'],
5
3
  flags: ['--clean'],
@@ -34,8 +32,8 @@ module.exports = Object.assign(build, {
34
32
 
35
33
  *-o* | *--dest* <folder>
36
34
 
37
- writes output to the given folder of the project root directory.
38
- default = ${_cds.env.build.target}
35
+ writes output to the given folder. The folder is resolved based on "<project>/<cds.env.build.target>".
36
+
39
37
 
40
38
  *--options-model*
41
39
 
@@ -68,7 +66,7 @@ function build([project], options = {}, /* for unit tests only: */ _env = null)
68
66
  }
69
67
 
70
68
  try {
71
- return _cds.build.build(options, _env)
69
+ return require('@sap/cds').build.build(options, _env)
72
70
  } catch (error) {
73
71
  return Promise.reject(error.message)
74
72
  }
@@ -22,7 +22,7 @@ module.exports = Object.assign(build, {
22
22
  *--use* <qualified node module name>
23
23
 
24
24
  Fully qualified name of the build task that is applied to the source folder.
25
- For example, "@sap/cds/lib/build/hana" represents the fully qualified name of the "hana" build task.
25
+ For example, "@sap/cds/build/hana" represents the fully qualified name of the "hana" build task.
26
26
  The module folder can be defined using option "--src", a default is used otherwise.
27
27
 
28
28
  *-s* | *--src* <folder>
package/bin/cds.js CHANGED
@@ -8,6 +8,7 @@ const cli = { //NOSONAR
8
8
  y: 'bind',
9
9
  m: 'import',
10
10
  c: 'compile',
11
+ p: 'parse',
11
12
  s: 'serve',
12
13
  w: 'watch',
13
14
  e: 'env',
@@ -130,4 +131,3 @@ else { // TODO compat to cds 3 remove after a while.
130
131
  if (!module.parent) module.exports()
131
132
 
132
133
  /* eslint no-console:off */
133
-
@@ -1,5 +1,5 @@
1
1
  module.exports = Object.assign(deploy, {
2
- options: ['--to', '--tunnel-address', '--vcap-file'], flags: [ '--no-save', '--auto-undeploy', '--dry', '--with-mocks' ],
2
+ options: ['--to', '--tunnel-address', '--vcap-file'], flags: [ '--no-save', '--auto-undeploy', '--dry', '--with-mocks', '--bind' ],
3
3
  shortcuts: ['-2'],
4
4
  help: `
5
5
  # SYNOPSIS
@@ -47,6 +47,12 @@ module.exports = Object.assign(deploy, {
47
47
  creating new credentials. File must be in *default-env.json* format, with a root
48
48
  node *VCAP_SERVICES*.
49
49
 
50
+ *--bind* (beta feature, only in combination with *--to hana*)
51
+
52
+ Use *cds bind* to connect the created service after deployment.
53
+ This will no longer create default-env.json files. Instead, cds bind is used to
54
+ create and store connection information in file *.cdsrc-private.json*.
55
+
50
56
  # EXAMPLES
51
57
  cds deploy --to sqlite:db
52
58
  cds deploy --to hana:myService --auto-undeploy
@@ -1,9 +1,10 @@
1
- const {join} = require('path')
1
+ const { join } = require('path');
2
2
 
3
3
  exports.deploy = (_model, _db, options) => {
4
4
  // locate deployer relative to already located sap/cds -> local cds takes precedence
5
- const cdsHome = require('@sap/cds').home
6
- const deployer = require(join(cdsHome, 'bin/deploy/to-hana'))
5
+ const cdsHome = require('@sap/cds').home;
6
+ const deployer = require(join(cdsHome, 'bin/deploy/to-hana'));
7
7
 
8
- return deployer.deploy (_model, _db, options)
8
+ const bind = require('../bind');
9
+ return deployer.deploy(_model, _db, options, options.bind ? bind : null);
9
10
  }
@@ -2,7 +2,8 @@ exports.deploy = function deploy_to_sqlite (_model, _db, options) {
2
2
  const cds = require('@sap/cds/lib')
3
3
  const {to:_dbrl} = options
4
4
  const conf = cds.env.requires.db || {}
5
- const model = _model || conf.model || cds.resolve('*',false)
5
+ const fts = cds.env.features.folders
6
+ const model = _model || conf.model || cds.resolve(!fts ? '*' : ['*',fts], false)
6
7
  const file = _database4 (_db, _dbrl, conf)
7
8
  const dialect = _dbrl && _dbrl.match(/^(\w+)/) && RegExp.$1
8
9
  if (dialect) options.dialect = dialect === 'sql' ? 'plain' : dialect
package/bin/extend.js CHANGED
@@ -7,8 +7,8 @@ module.exports = Object.assign(extend, {
7
7
 
8
8
  *cds extend* <app-url>
9
9
 
10
- Create an extension project from an app URL.
11
- Obtain the URL from the SaaS application that you want to extend.
10
+ Create an extension project from an extensible SaaS app.
11
+ Obtain the app URL from the SaaS application provider.
12
12
 
13
13
  To facilitate running this multiple times against the same app, refer to the *cds login* command.
14
14
 
@@ -16,15 +16,15 @@ module.exports = Object.assign(extend, {
16
16
 
17
17
  *-d* | *--directory* <project-extension-directory>
18
18
 
19
- Specify the target directory of your extension project.
19
+ Specify the target directory of your extension project. By default, the current working directory is used.
20
20
 
21
21
  *-s* | *--subdomain* <tenant-subdomain>
22
22
 
23
- Specify the subdomain of the SaaS application you want to extend.
23
+ Specify your tenant's subdomain. By default, it's determined from the app URL.
24
24
 
25
25
  *-p* | *--passcode* <passcode>
26
26
 
27
- The tenant-specific passcode for authentication.
27
+ Tenant-specific passcode for authentication.
28
28
 
29
29
  *-u* | *--username* <name>
30
30
 
package/bin/help.js CHANGED
@@ -13,6 +13,7 @@ module.exports = exports = Object.assign (help, {help:`
13
13
  *y* | *bind* [beta] bind a service to a hana instance
14
14
  *m* | *import* add models from external sources
15
15
  *c* | *compile* compile cds models to different outputs
16
+ *p* | *parse* parses given cds models
16
17
  *s* | *serve* run your services in local server
17
18
  *w* | *watch* run and restart on file changes
18
19
  *r* | *repl* read-eval-event loop
package/bin/import.js CHANGED
@@ -44,11 +44,11 @@ module.exports = Object.assign(_import, {
44
44
  *-f | --force*
45
45
  Forcefully overwrites the contents in the CDS file and updates the checksum
46
46
 
47
- *-ns | --include-namespaces <string_of_namespaces> or* *
47
+ *-ns | --include-namespaces <string_of_namespaces> or* "\x2A"
48
48
  Imports only entities matching to the given list of namespaces.
49
+ For OData V2 attributes with the namespace "sap" & "m" are captured by default.
49
50
 
50
51
 
51
-
52
52
 
53
53
  # EXAMPLES
54
54
 
@@ -56,7 +56,7 @@ module.exports = Object.assign(_import, {
56
56
  cds import - ~/Downloads/API_BUSINESS_PARTNER.edmx
57
57
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --as cds
58
58
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "sap,c4c"
59
- cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "*"
59
+ cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "\x2A"
60
60
 
61
61
  `})
62
62
  const cds = require('@sap/cds/lib')
@@ -109,37 +109,51 @@ async function _import(file, { out, dry, into, as,
109
109
  }
110
110
 
111
111
  async function _generateChecksumValidate(dest, output, force) {
112
- let fileResolved = await exists(dest);
113
- if (fileResolved === false) {
114
- let checksum = md5(output);
115
- output = "/* checksum : " + checksum + " */\n" + output;
116
- return output;
112
+ let fileExists = await exists(dest);
113
+
114
+ // force flag disabled and cds file already exists, then throw error
115
+ if (!force && fileExists) {
116
+ throw new Error(messages.FILE_MODIFIED);
117
117
  }
118
- else {
119
- let existingFileContent = await read(dest, "utf-8");
120
- existingFileContent = String(existingFileContent);
121
- if (existingFileContent.indexOf("checksum") === -1){
122
- let checksum = md5(existingFileContent);
123
- output = "/* checksum : " + checksum + " */\n" + output;
124
- return output;
125
- }
126
- let fileChecksum = existingFileContent.substring(existingFileContent.indexOf("checksum") + 11, existingFileContent.indexOf(" */"));
127
- existingFileContent = existingFileContent.substring(existingFileContent.indexOf('*/') + 3);
128
- let checksum = md5(existingFileContent);
129
- if (fileChecksum === checksum) {
130
- output = "/* checksum : " + checksum + " */\n" + existingFileContent;
131
- return output;
132
- }
133
- else {
134
- if (force) {
135
- output = "/* checksum : " + md5(output) + " */\n" + output;
136
- return output;
137
- }
138
- else {
139
- throw new Error(messages.FILE_MODIFIED);
140
- }
118
+
119
+ const currentChecksum = md5(output);
120
+ let existingFileContent, existingFileContentWithoutChecksum;
121
+ let existingFileContentChecksum, existingChecksumValue;
122
+
123
+ if (fileExists) {
124
+ existingFileContent = await read(dest, "utf-8");
125
+ const checksumStartIndex = existingFileContent.indexOf(`/* checksum : `);
126
+ const checksumEndIndex = existingFileContent.indexOf(" */");
127
+
128
+ if (checksumStartIndex >= 0) {
129
+ existingFileContentWithoutChecksum = existingFileContent.substring(
130
+ checksumEndIndex + 4
131
+ );
132
+ existingChecksumValue = existingFileContent.substring(
133
+ checksumStartIndex + 14, checksumEndIndex
134
+ );
135
+ existingFileContentChecksum = md5(existingFileContentWithoutChecksum);
141
136
  }
142
137
  }
138
+
139
+ // if force flag enbabled
140
+ if (force) {
141
+ // current and existing file content are same, and the existing
142
+ // checksum is not modified, then return the existing file content
143
+ if (currentChecksum == existingFileContentChecksum &&
144
+ currentChecksum == existingChecksumValue) {
145
+ return existingFileContent;
146
+ }
147
+ }
148
+ /*
149
+ * 1. current and existing checksum are different.
150
+ * 2. checksum is missing in the existing file:
151
+ * a. existing and current file content are same.
152
+ * b. existing and current file content are different.
153
+ * 3. cds file doesn't exist.
154
+ * 4. checksum of the existing file is modified.
155
+ */
156
+ return "/* checksum : " + currentChecksum + " */\n" + output;
143
157
  }
144
158
 
145
159
  async function _getResult(output, service, as, dest, force) {
package/bin/login.js CHANGED
@@ -58,19 +58,18 @@ module.exports = Object.assign(login, {
58
58
 
59
59
  *-s* | *--subdomain* <tenant-subdomain>
60
60
 
61
- The subdomain to log in to. Can also be provided by project settings.
62
- Alternatively it will be determined by invoking the CF client and
63
- interpreting its output by reference to the <app-url>.
61
+ The subdomain to log in to. By default, it's determined from project settings.
62
+ If no such setting is saved, the CF client is invoked to determine the respective subdomain.
64
63
 
65
64
  *-d* | *--directory* <extension-project-directory>
66
65
 
67
66
  The extension-project folder (relevant for loading and saving settings).
68
- If omitted, a subdirectory named as the subdomain or the current working
69
- directory will be used.
67
+ If omitted, either an existing subdirectory named as the subdomain or the current
68
+ working directory will be used.
70
69
 
71
70
  *-p* | *--passcode* <passcode>
72
71
 
73
- The tenant-specific passcode for authentication.
72
+ Tenant-specific passcode for authentication.
74
73
 
75
74
  *-c* | *--clientid* <clientid>
76
75
 
package/bin/logout.js CHANGED
@@ -33,11 +33,11 @@ module.exports = Object.assign(logout, {
33
33
 
34
34
  *-l* | *--url* <app-url>
35
35
 
36
- The <app-url> to logout from. Can also be provided by project settings.
36
+ The <app-url> to logout from. By default, it's determined from project settings.
37
37
 
38
38
  *-s* | *--subdomain* <subdomain>
39
39
 
40
- The subdomain to logout from. Can also be provided by project settings.
40
+ The subdomain to logout from. By default, it's determined from project settings.
41
41
 
42
42
  *--delete-settings*
43
43
 
package/bin/parse.js ADDED
@@ -0,0 +1,19 @@
1
+ const compile = require('./compile')
2
+ module.exports = Object.assign (
3
+ cds_parse, compile, {help: `
4
+ # SYNOPSIS
5
+
6
+ *cds parse* ...
7
+
8
+ Convenient shortcut for 'cds compile --flavor parsed'.
9
+
10
+ # OPTIONS
11
+
12
+ - see _cds help compile_
13
+
14
+
15
+ `})
16
+
17
+ function cds_parse (projects, options) {
18
+ return compile (projects,{ flavor:'parsed', ...options })
19
+ }
@@ -4,6 +4,8 @@ const IS_WIN = os.platform() === 'win32';
4
4
 
5
5
  const KindToRequiresNameMap = {
6
6
  xsuaa: 'uaa',
7
+ 'xsuaa-auth': 'uaa',
8
+ 'hana-cloud': 'db',
7
9
  hana: 'db',
8
10
  destinations: 'destinations',
9
11
  connectivity: 'connectivity',
@@ -14,6 +16,11 @@ const KindToRequiresNameMap = {
14
16
  'enterprise-messaging-shared': 'messaging'
15
17
  }
16
18
 
19
+ const PreferredKinds = [
20
+ 'hana-cloud',
21
+ 'xsuaa'
22
+ ];
23
+
17
24
  function getRequiresNameFromKind(service, kind) {
18
25
  const requiresName = KindToRequiresNameMap[kind];
19
26
  if (!requiresName) throw new Error(`Unknown CDS service name for service "${service}". Please specify as argument for "cds bind".`)
@@ -25,64 +32,49 @@ function getRequiresNameFromKind(service, kind) {
25
32
  * information in the configuration.
26
33
  */
27
34
  function determineKinds(services) {
28
- const vcapServices = {}
35
+ const vcapServices = {}
29
36
 
30
- const getIndex = service => {
31
- const { credentials } = service;
32
- return credentials && credentials.binding && credentials.binding.index;
33
- }
37
+ // Build VCAP_SERVICES
38
+ for (const service of services) {
39
+ service.kindCandidates = [ ]
34
40
 
35
- // Build VCAP_SERVICES
36
- for (let index = 0; index<services.length; index++) {
37
- const service = services[index];
38
- service.kindCandidates = [ ]
39
- service.nameCandidates = [ ]
41
+ const { label, name, tags } = service.binding && service.binding.vcap || {};
42
+ if (!label) continue;
40
43
 
41
- const { label, name, tags } = service.binding && service.binding.vcap || {};
42
- if (!label) continue;
44
+ if (!vcapServices[label]) vcapServices[label] = [];
45
+ vcapServices[label].push({ credentials: { dummy: 'dummy' }, label, name, tags, service });
46
+ }
43
47
 
44
- if (!vcapServices[label]) vcapServices[label] = [];
45
- vcapServices[label].push({ credentials: { binding: { index } }, label, name, tags });
46
- }
48
+ // Auto configure services based on VCAP_SERVICES
47
49
 
48
- // Auto configure services based on VCAP_SERVICES
49
- const cds = require('@sap/cds/lib');
50
- const VCAP_SERVICES = process.env.VCAP_SERVICES;
51
- try {
52
- process.env.VCAP_SERVICES = JSON.stringify(vcapServices);
53
- const env = cds.env.for('cds', '.');
54
-
55
- // Extract "kind" from auto configured services
56
- for (const kind of Object.keys(env.requires)) {
57
- const requireService = env.requires[kind];
58
- const superKind = requireService.kind;
59
- const index = getIndex(requireService);
60
- if (!Number.isInteger(index)) continue;
61
-
62
- const superRequireService = env.requires[superKind];
63
- if (superRequireService) {
64
- const superIndex = getIndex(superRequireService);
65
- if (index === superIndex) continue;
66
- }
67
-
68
- services[index].kindCandidates.push(kind);
69
- }
50
+ const cds = require('@sap/cds/lib');
51
+ const env = cds.env.for('cds', process.cwd());
70
52
 
71
- // Check if one "kind" per service was found
72
- for (const service of services) {
73
- if (service.kindCandidates.length === 1) {
74
- service.kind = service.kindCandidates[0];
75
- }
53
+ if (!env._find_credentials_for_required_service) {
54
+ throwError `Please provide a service kind or update @sap/cds version to use the kind detection.`;
55
+ }
76
56
 
77
- delete service.kindCandidates;
78
- }
79
- } finally {
80
- if (VCAP_SERVICES)
81
- process.env.VCAP_SERVICES = VCAP_SERVICES;
82
- else
83
- delete process.env.VCAP_SERVICES;
57
+ const requires = env.requires.kinds || {};
58
+ for (const kind of Object.keys(requires)) {
59
+ const requireService = requires[kind];
60
+ const vcapService = env._find_credentials_for_required_service(kind, requireService, vcapServices);
61
+ if (!vcapService) continue;
62
+ if (!Object.values(requires).find( require => require !== requireService && require.kind == kind ))
63
+ vcapService.service.kindCandidates.push(kind);
64
+ }
65
+
66
+ // Check if one "kind" per service was found
67
+ for (const service of services) {
68
+ const preferredKind = service.kindCandidates.find( kind => PreferredKinds.indexOf(kind) >= 0);
69
+ if (preferredKind) {
70
+ service.kind = preferredKind;
71
+ } if (service.kindCandidates.length === 1) {
72
+ service.kind = service.kindCandidates[0];
84
73
  }
74
+
75
+ delete service.kindCandidates;
85
76
  }
77
+ }
86
78
 
87
79
  function execAndExit(command, ...args) {
88
80
  const { spawnSync } = require('child_process');