@sap/cds-dk 7.0.1 → 7.0.3

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 (90) hide show
  1. package/bin/add.js +36 -40
  2. package/bin/bind.js +0 -1
  3. package/bin/build.js +4 -0
  4. package/bin/cds.js +14 -8
  5. package/bin/compile/index.js +3 -3
  6. package/bin/deploy/to-hana.js +1 -1
  7. package/bin/help.js +2 -3
  8. package/bin/init.js +2 -2
  9. package/lib/bind/cfKeyProvider.js +1 -0
  10. package/lib/bind/index.js +3 -0
  11. package/lib/bind/userCdsrcJsonStorageProvider.js +2 -10
  12. package/lib/build/buildTaskEngine.js +1 -1
  13. package/lib/build/constants.js +16 -14
  14. package/lib/build/provider/buildTaskHandlerFeatureToggles.js +2 -1
  15. package/lib/build/provider/java/index.js +2 -2
  16. package/lib/build/provider/mtx/resourcesTarBuilder.js +2 -6
  17. package/lib/build/provider/mtx-sidecar/index.js +15 -11
  18. package/lib/build/util.js +8 -0
  19. package/lib/cds.js +2 -2
  20. package/lib/client/base_command.js +3 -6
  21. package/lib/compile/asyncapi/components/messages/index.js +41 -18
  22. package/lib/compile/asyncapi/index.js +23 -2
  23. package/lib/import/odata/metadataconverter/MetadataConverter.js +1 -0
  24. package/lib/init/constants.js +5 -5
  25. package/lib/init/index.js +68 -76
  26. package/lib/init/template/_merging/registry-mta.js +2 -2
  27. package/lib/init/template/approuter/index.js +10 -7
  28. package/lib/init/template/auditlog/index.js +3 -4
  29. package/lib/init/template/cf-manifest/files/manifest.yml.hbs +15 -23
  30. package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +22 -17
  31. package/lib/init/template/cf-manifest/index.js +5 -5
  32. package/lib/init/template/connectivity/index.js +2 -3
  33. package/lib/init/template/data/index.js +6 -6
  34. package/lib/init/template/destination/index.js +3 -5
  35. package/lib/init/template/enterprise-messaging/index.js +4 -5
  36. package/lib/init/template/enterprise-messaging-shared/index.js +3 -4
  37. package/lib/init/template/extensibility/index.js +2 -3
  38. package/lib/init/template/file-based-messaging/index.js +2 -2
  39. package/lib/init/template/hana/files/mta.yaml.hbs +1 -1
  40. package/lib/init/template/hana/index.js +39 -63
  41. package/lib/init/template/helm/index.js +15 -14
  42. package/lib/init/template/html5-repo/index.js +3 -7
  43. package/lib/init/template/java/index.js +6 -6
  44. package/lib/init/template/kibana/files/mta.yaml.hbs +29 -0
  45. package/lib/init/template/kibana/index.js +54 -0
  46. package/lib/init/template/lint/index.js +8 -7
  47. package/lib/init/template/mta/index.js +3 -2
  48. package/lib/init/template/multitenancy/files/package.json.hbs +0 -3
  49. package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +1 -1
  50. package/lib/init/template/multitenancy/index.js +25 -40
  51. package/lib/init/template/nodejs/index.js +4 -5
  52. package/lib/init/template/pipeline/index.js +3 -3
  53. package/lib/init/template/redis-messaging/index.js +3 -4
  54. package/lib/init/template/sample/files/app/_i18n/i18n.properties +3 -32
  55. package/lib/init/template/sample/files/app/_i18n/i18n_de.properties +2 -2
  56. package/lib/init/template/sample/files/app/admin-books/fiori-service.cds +6 -7
  57. package/lib/init/template/sample/files/app/admin-books/webapp/Component.js +3 -3
  58. package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n.properties +3 -11
  59. package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +117 -113
  60. package/lib/init/template/sample/files/app/appconfig/fioriSandboxConfig.json +38 -0
  61. package/lib/init/template/sample/files/app/browse/fiori-service.cds +56 -0
  62. package/lib/init/template/sample/files/app/browse/webapp/Component.js +7 -0
  63. package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n.properties +4 -0
  64. package/lib/init/template/sample/files/app/browse/webapp/manifest.json +139 -0
  65. package/lib/init/template/sample/files/app/common.cds +78 -81
  66. package/lib/init/template/sample/files/app/services.cds +1 -0
  67. package/lib/init/template/sample/files/srv/admin-service.cds +1 -1
  68. package/lib/init/template/sample/files/srv/cat-service.cds +1 -1
  69. package/lib/init/template/sample/index.js +6 -5
  70. package/lib/init/template/sqlite/index.js +1 -1
  71. package/lib/init/template/templateBase.js +9 -19
  72. package/lib/init/template/tiny-sample/index.js +6 -6
  73. package/lib/init/template/toggles/index.js +1 -2
  74. package/lib/init/template/typer/files/xsconfig.json +0 -1
  75. package/lib/init/template/typer/index.js +1 -1
  76. package/lib/init/template/xsuaa/index.js +3 -4
  77. package/lib/init/util/indent.js +57 -0
  78. package/lib/init/util/merge.js +71 -15
  79. package/lib/init/util/mvn.js +24 -10
  80. package/lib/init/util/projectReader.js +53 -169
  81. package/lib/init/util/template.js +12 -11
  82. package/lib/init/util/xml.js +6 -6
  83. package/lib/util/pruneAxiosErrors.js +22 -0
  84. package/lib/watch/open.js +6 -3
  85. package/npm-shrinkwrap.json +20 -37
  86. package/package.json +1 -2
  87. package/lib/init/template/kibana-logging/files/cds.package.json +0 -7
  88. package/lib/init/template/kibana-logging/files/mta.yaml.hbs +0 -14
  89. package/lib/init/template/kibana-logging/index.js +0 -45
  90. /package/lib/init/template/{kibana-logging → kibana}/files/package.json.hbs +0 -0
package/bin/add.js CHANGED
@@ -1,3 +1,4 @@
1
+ const term = require('../lib/util/term')
1
2
 
2
3
  module.exports = Object.assign(add, {
3
4
  options: ['--for', '--out', '--data:for'],
@@ -8,72 +9,68 @@ module.exports = Object.assign(add, {
8
9
 
9
10
  *cds add* <feature | comma-separated list of features>
10
11
 
11
- Adds one or more features to an existing project in the current working
12
- folder - Grow-as-you-go scenario.
12
+ Adds one or more features to an existing project - grow as you go.
13
13
 
14
- The following <features> are supported so far:
14
+ The following features are supported so far:
15
15
 
16
- *hana* - adds configuration for SAP HANA databases
16
+ *hana* - add support for SAP HANA
17
17
 
18
- *sqlite* - adds configuration for SQLite databases
18
+ *sqlite* - add support for SQLite databases
19
19
 
20
- *xsuaa* - adds configuration for authentication via XSUAA
20
+ *xsuaa* - add support for authentication via XSUAA
21
21
 
22
- *multitenancy* - adds configuration for multitenancy
22
+ *multitenancy* - add support for multitenancy
23
23
 
24
- *toggles* - adds configuration for feature toggles
24
+ *toggles* - add support for feature toggles
25
25
 
26
- *extensibility* - adds configuration for extensibility
26
+ *extensibility* - add support for extensibility
27
27
 
28
- *mtx* - adds configuration for multitenancy, feature toggles and
29
- extensibility
28
+ *approuter* - add support for application routing
30
29
 
31
- *approuter* - adds configuration for the Cloud Foundry approuter
30
+ *file-based-messaging* - add support for file-based messaging
32
31
 
33
- *mta* - adds an _mta.yaml_ file for MTA-based SAP Business
34
- Technology Platform deployment
32
+ *enterprise-messaging* - add support for SAP Event Mesh
35
33
 
36
- *cf-manifest* - adds _manifest.yml_ and _services-manifest.yml_ files for
37
- Cloud Foundry native deployment
34
+ *redis-messaging* - add support for Redis messaging
38
35
 
39
- This approach makes use of the 'Create-Service-Push
40
- Plugin' that has to be installed separately using
41
- _cf install-plugin Create-Service-Push_.
42
- _cf create-service-push_ creates the service(s) and pushes
43
- the application(s) to the SAP Business Technology
44
- Platform.
36
+ *kibana-logging* - add support for Kibana formatting
45
37
 
46
- *pipeline* - adds files for CI/CD pipeline integration
38
+ *mta* - add support for MTA-based deployment
47
39
 
48
- *sample* - adds sample files including Fiori UI
40
+ *cf-manifest* - add support for CF-native deployment
49
41
 
50
- *tiny-sample* - adds minimal sample files
42
+ *helm* - add support for Helm-based Kyma deployment
51
43
 
52
- *data* - adds data content for CSN model entities (as csv files)
44
+ *html5-repo* - add support for the HTML5 repository
53
45
 
54
- *helm* - adds helm chart folder that contains the files needed to
55
- deploy the application using Kyma.
46
+ *pipeline* - add files for CI/CD pipeline integration
56
47
 
57
- *html5-repo* - adds configuration for HTML5 Application Deployer to Helm
58
- Chart (Kyma Only).
48
+ *tiny-sample* - add minimal sample files
49
+
50
+ *sample* - add sample files including Fiori UI
51
+
52
+ *data* - add CSV headers for modeled entities
53
+
54
+ *typer* - add type generation for CDS models
55
+
56
+ *lint* - add support for CDS Lint
59
57
 
60
58
 
61
59
  # OPTIONS
62
60
 
63
61
  *--for* <profile>
64
62
 
65
- Writes configuration data, if any, under the given profile, like
66
- \`"[production]": { "db": "hana" }\`
63
+ Write configuration data for the given profile.
67
64
 
68
65
  *--data:for* <entity name or prefix>
69
66
 
70
- Adds data content for entities matching the given pattern. If it contains
67
+ Add data content for entities matching the given pattern. If it contains
71
68
  meta characters like '^' or '*', it is treated like a regular expression,
72
69
  otherwise as a prefix.
73
70
 
74
71
  *-o* | *--out* <target folder>
75
72
 
76
- Specifies output target folder (applicable to data feature only)
73
+ Specify output target folder (applicable to ${term.bold('data')} feature only).
77
74
 
78
75
  *--force*
79
76
 
@@ -81,11 +78,10 @@ module.exports = Object.assign(add, {
81
78
 
82
79
  # EXAMPLES
83
80
 
84
- *cds add* mta,pipeline
85
- *cds add* multitenancy
86
- *cds add* hana,xsuaa --for production
87
- *cds add* cf-manifest
81
+ *cds add* sample
82
+ *cds add* multitenancy,hana,xsuaa --for production
88
83
  *cds add* data --data:for my.namespace.MyEntity
84
+ *cds add* mta
89
85
  *cds add* helm
90
86
 
91
87
 
@@ -95,8 +91,8 @@ module.exports = Object.assign(add, {
95
91
 
96
92
  `});
97
93
 
98
- async function add(args, options = {}) {
94
+ async function add(args) {
99
95
  const CDSGenerator = require('../lib/init');
100
96
  const generator = new CDSGenerator();
101
- await generator.addCmd(args[0], options);
97
+ await generator.addCmd(args[0]);
102
98
  }
package/bin/bind.js CHANGED
@@ -72,7 +72,6 @@ async function cds_bind(args, options) {
72
72
  if (process.env.CDS_ENV && process.argv[2] === 'bind') {
73
73
  throw new CliError('Option --profile is no longer supported. Use --for instead to specify the profile to use when storing connection settings.');
74
74
  }
75
- options.for = options.for ?? 'hybrid';
76
75
 
77
76
  if (!options.to) {
78
77
  throw new CliError(`Use option --to or -2 to specify the target instance, e.g. cds bind --to myInstance:myService`);
package/bin/build.js CHANGED
@@ -101,6 +101,10 @@ async function build([project], options = {}) {
101
101
  const { CliError } = require('../lib/client/helper/errors')
102
102
  const { build } = require('../lib/build')
103
103
 
104
+ const [major] = cds.version.split('.')
105
+ if (Number(major) < 6) {
106
+ throw new CliError("This application uses @sap/cds version < 6, which is not compatible with the installed @sap/cds-dk version >= 7. Update @sap/cds to version >= 6.")
107
+ }
104
108
  if (options.clean === "false") {
105
109
  throw new CliError("cds build option '--clean' is deprecated - build output folders are always cleaned before build")
106
110
  }
package/bin/cds.js CHANGED
@@ -54,9 +54,13 @@ const cli = { //NOSONAR
54
54
  return await task.apply(this, args)
55
55
  }
56
56
  } catch (e) {
57
- process.exitCode = 1
58
- if (process.argv[1].endsWith('watched')) throw e // bin/watched.js handles errors
59
- cds._log(e.messages?.length ? e.messages : e.message ?? e, { 'log-level': cds.env.log.levels.cli })
57
+ const { BuildError } = require('../lib/build')
58
+ const { CliError } = require('../lib/client/helper/errors')
59
+ process.exitCode ??= 1
60
+ if (e.messages?.length) return cds._log(e.messages, { 'log-level': cds.env.log.levels.cli })
61
+ else if (e instanceof CliError || e instanceof BuildError) return console.error(e.message)
62
+ if (cds.watched) throw e // bin/watched.js handles errors
63
+ else return console.error(e)
60
64
  }
61
65
  },
62
66
 
@@ -148,13 +152,15 @@ function _dieForUnknownCommand(cmd) {
148
152
 
149
153
  let bestMatchText = '';
150
154
 
151
- const excludeList = ['cds.js', 'cds-ts.js', 'fix-redirects.js'];
155
+ const excludeList = ['cds.js', 'cds-ts.js', 'fix-redirects.js', 'util'];
152
156
  const { readdirSync } = require('fs');
153
157
  const { resolve } = require('path');
154
- const commands = readdirSync(__dirname, { withFileTypes: true })
158
+ let commands = readdirSync(__dirname, { withFileTypes: true })
155
159
  .concat(readdirSync(resolve(_local('@sap/cds'), '..', '..', 'bin'), { withFileTypes: true }))
156
- .filter((f) => f.isFile() && !excludeList.includes(f.name))
157
- .map((f) => f.name.split('.')[0]).sort();
160
+ .filter((f) => !excludeList.includes(f.name))
161
+ .map((f) => f.name.split('.')[0])
162
+ commands = [...new Set(commands)] // make unique
163
+ .sort();
158
164
 
159
165
  const bestMatches = fuzzySearch(cmd, commands, DEBUG);
160
166
 
@@ -180,7 +186,7 @@ function _dieForUnknownCommand(cmd) {
180
186
  `
181
187
  console.error(msg)
182
188
 
183
- process.exitCode = 1
189
+ process.exit(1)
184
190
  }
185
191
 
186
192
  function _require (id,o) {
@@ -175,7 +175,7 @@ function compile (models, options={}) {
175
175
  model = readModelFromStdin()
176
176
  src = 'stdin'
177
177
  } else { // no args, no stdin
178
- throw new Error (`You must specify a model to compile.\nRun 'cds c -?' to learn more.`)
178
+ throw `You must specify a model to compile.\nRun 'cds c -?' to learn more.`
179
179
  }
180
180
 
181
181
  let chain = model.then (m => model=m)
@@ -189,7 +189,7 @@ function compile (models, options={}) {
189
189
  if (typeof options.to === 'string') for (let each of options.to.split(',')) {
190
190
  chain = chain.then (next (processor ('to', _suffix=each)))
191
191
  } else if (options.to) {
192
- cds.error (`Specify a model processor`)
192
+ throw `Specify a model processor`
193
193
  }
194
194
 
195
195
  // add processor for i18n
@@ -235,7 +235,7 @@ function compile (models, options={}) {
235
235
  let p = cds.compile[kind]
236
236
  for (let each of tail.split('.')) {
237
237
  p = p[each]
238
- if (!p) throw new Error (`Unknown model processor: cds.compile.${kind}.${tail}`)
238
+ if (!p) throw `Unknown model processor: cds.compile.${kind}.${tail}`
239
239
  }
240
240
  return p
241
241
  }
@@ -8,6 +8,6 @@ exports.deploy = (model, serviceName, options) => {
8
8
  tunnelAddress: options['tunnel-address'],
9
9
  vcapFile: options['vcap-file'],
10
10
  hdiOptions: { autoUndeploy: options['auto-undeploy'] },
11
- storeCredentials: options['store-credentials']
11
+ storeCredentials: options['store-credentials'] // TODO: Remove with cds-dk 8
12
12
  });
13
13
  }
package/bin/help.js CHANGED
@@ -39,9 +39,8 @@ module.exports = exports = Object.assign (help, {formatHelp, help:`
39
39
 
40
40
  function help (topic) {
41
41
  if (Array.isArray(topic)) topic = topic[0]
42
- const task = !topic ? help : this.load && this.load (this.Shortcuts[topic] || topic)
43
- if (task && task.help) console.log (formatHelp (task.help))
44
- else throw new Error(`Didn't find a help topic for '${ topic.name || topic }'.`)
42
+ const task = !topic ? help : this.load?.(this.Shortcuts[topic] || topic)
43
+ if (task?.help) console.log (formatHelp (task.help))
45
44
  }
46
45
 
47
46
  function formatHelp (text) {
package/bin/init.js CHANGED
@@ -98,11 +98,11 @@ module.exports = Object.assign(init, {
98
98
 
99
99
  `})
100
100
 
101
- async function init (args, options = {}) {
101
+ async function init (args) {
102
102
  if (process.argv.some(a => legacyOptions.includes(a))) return _showWarningMessage()
103
103
  const CDSGenerator = require('../lib/init')
104
104
  const generator = new CDSGenerator()
105
- await generator.initCmd(args[0], options)
105
+ await generator.initCmd(args[0])
106
106
  }
107
107
 
108
108
 
@@ -4,6 +4,7 @@ const DEBUG = cds.debug('cli')
4
4
  const cfUtil = require('../util/cfUtil');
5
5
 
6
6
  const axios = require('axios');
7
+ require('../util/pruneAxiosErrors');
7
8
  const { URL } = require('url');
8
9
  const { bold, highlight } = require('../util/term');
9
10
  const { CliError } = require('../client/helper/errors');
package/lib/bind/index.js CHANGED
@@ -15,6 +15,9 @@ module.exports = { bind, parseProfile }
15
15
  * @param {object} options - command options as defined by build command.
16
16
  */
17
17
  async function bind(options) {
18
+
19
+ options.for = options.for || 'hybrid';
20
+
18
21
  let on;
19
22
  switch(options.on) {
20
23
  case 'k8s':
@@ -58,11 +58,7 @@ class UserCdsrcJsonStorageProvider {
58
58
 
59
59
  cdsRoot.requires = cdsRoot.requires || {};
60
60
  let section;
61
- if (options.for) {
62
- section = cdsRoot.requires[profileKey] = cdsRoot.requires[profileKey] || {};
63
- } else {
64
- section = cdsRoot.requires;
65
- }
61
+ section = cdsRoot.requires[profileKey] = cdsRoot.requires[profileKey] || {};
66
62
 
67
63
  for (const service of services) {
68
64
  const { name, kind, binding, credentials } = service;
@@ -72,11 +68,7 @@ class UserCdsrcJsonStorageProvider {
72
68
  }
73
69
 
74
70
  await this.writeJsonFile(jsonPath, jsonObject);
75
- if (options.for) {
76
- logger.log(`Saving bindings to ${highlight(jsonPath)} in profile ${highlight(options.for)}`);
77
- } else {
78
- logger.log(`Saving bindings to ${highlight(jsonPath)}`);
79
- }
71
+ logger.log(`Saving bindings to ${highlight(jsonPath)} in profile ${highlight(options.for)}`);
80
72
  }
81
73
 
82
74
  async readJsonSafely(filePath) {
@@ -30,7 +30,7 @@ class BuildTaskEngine {
30
30
  const messages = []
31
31
 
32
32
  this.logger.log(`building project [${cds.root}], clean [${this.buildOptions.clean}]`)
33
- this.logger.log(`cds [${cds.version}], compiler [${cds.compiler.version()}], home [${cds.home}]\n`)
33
+ this.logger.log(`cds-dk [${require('../../package.json').version}], cds [${cds.version}], compiler [${cds.compiler.version()}], home [${cds.home}]\n`)
34
34
 
35
35
  if (!tasks) {
36
36
  const buildTaskFactory = new BuildTaskFactory(this.buildOptions)
@@ -19,20 +19,22 @@ exports.BUILD_TASKS = [this.BUILD_TASK_JAVA, this.BUILD_TASK_JAVA_CF, this.BUILD
19
19
  exports.ODATA_VERSION_V2 = "v2"
20
20
  exports.ODATA_VERSION_V4 = "v4"
21
21
 
22
- exports.CONTENT_LANGUAGE_BUNDLES = "contentLanguageBundles" // create i18n.json language bundles
23
- exports.CONTENT_DEFAULT_CSN = "contentDefaultCsn" // create default CSN format flavor: "inferred"
24
- exports.CONTENT_EDMX = "contentEdmx" // create EDMX for required languages
25
- exports.CONTENT_PACKAGE_JSON = "contentPackageJson" // create package.json file if not existing, or modify existing package.json
26
- exports.CONTENT_PACKAGELOCK_JSON = "contentPackageLockJson" // copy package-lock.json file if existing into deployment folder
27
- exports.CONTENT_HDBTABLEDATA = "contentHdbtabledata" // create .hdbtabledata files for .csv files if not existing
28
- exports.CONTENT_NPMRC = "contentNpmrc" // copy .npmrc file if existing into deployment folder
29
- exports.CONTENT_CDSRC_JSON = "contentCdsrcJson" // copy .cdsrc.json file if existing into deployment folder
30
- exports.CONTENT_NODE_MODULES = "contentNodeModules" // copy node_modules folder if existing into deployment folder
31
- exports.CONTENT_ENV = "contentEnv" // copy .env file if existing into deployment folder
32
- exports.CONTENT_DEFAULT_ENV_JSON = "contentDefaultEnvJson" // copy default-env.json file if existing into deployment folder
33
- exports.CSV_FILE_DETECTION = "csvFileDetection" // detect CSV files based on CDS model location
34
- exports.EXTENSION_POINT_VALIDATION = "extensionPointValidation" // validate extension point restrictions defined by the extended SaaS app
35
- exports.DEFAULT_BUILT_IN_MODELS = "defaultBuiltInModels" // add @sap/cds* built-in models to build tasks
22
+ exports.CONTENT_LANGUAGE_BUNDLES = "contentLanguageBundles" // create i18n.json language bundles - build task specific
23
+ exports.CONTENT_DEFAULT_CSN = "contentDefaultCsn" // create default CSN format flavor: "inferred" - build task specific
24
+ exports.CONTENT_EDMX = "contentEdmx" // create EDMX for required languages - build task specific
25
+ exports.CONTENT_PACKAGE_JSON = "contentPackageJson" // create package.json file if not existing, or modify existing package.json - ENABLED by default
26
+ exports.CONTENT_PACKAGELOCK_JSON = "contentPackageLockJson" // copy package-lock.json file if existing into deployment folder - ENABLED by default
27
+ exports.CONTENT_HDBTABLEDATA = "contentHdbtabledata" // create .hdbtabledata files for .csv files if not existing - ENABLED by default
28
+ exports.CONTENT_NPMRC = "contentNpmrc" // copy .npmrc file if existing into deployment folder - ENABLED by default
29
+ exports.CONTENT_CDSRC_JSON = "contentCdsrcJson" // copy .cdsrc.json file if existing into deployment folder - ENABLED by default
30
+ exports.CONTENT_NODE_MODULES = "contentNodeModules" // copy node_modules folder if existing into deployment folder - DISABLED by default
31
+ exports.CONTENT_ENV = "contentEnv" // copy .env file if existing into deployment folder - DISABLED by default
32
+ exports.CONTENT_DEFAULT_ENV_JSON = "contentDefaultEnvJson" // copy default-env.json file if existing into deployment folder - DISABLED by default
33
+
34
+ exports.CSV_FILE_DETECTION = "csvFileDetection" // detect CSV files based on CDS model location - ENABLED by default
35
+ exports.EXTENSION_POINT_VALIDATION = "extensionPointValidation" // validate extension point restrictions defined by the extended SaaS app - ENABLED by default
36
+ exports.DEFAULT_BUILT_IN_MODELS = "defaultBuiltInModels" // add @sap/cds* built-in models to build tasks - ENABLED by default
37
+ exports.MTX_SIDECAR_DB_VALIDATION = "mtxSidecarDbValidation" // validate consistency of app and sidecar db configuration - ENABLED by default
36
38
 
37
39
  exports.FOLDER_GEN = "gen"
38
40
  exports.FILE_EXT_CDS = ".cds"
@@ -3,6 +3,7 @@ const path = require('path')
3
3
  const cds = require('../../cds')
4
4
  const { DEFAULT_CSN_FILE_NAME, OUTPUT_MODE, OUTPUT_MODE_RESULT } = require('../constants')
5
5
  const BuildTaskHandlerInternal = require('./buildTaskHandlerInternal')
6
+ const { getI18nDefaultFolder } = require('../util')
6
7
 
7
8
  class FeatureToggleBuilder extends BuildTaskHandlerInternal {
8
9
  init() {
@@ -46,7 +47,7 @@ class FeatureToggleBuilder extends BuildTaskHandlerInternal {
46
47
  }
47
48
 
48
49
  async collectAllLanguageBundles(dictionary, paths, destBase, destFts) {
49
- const i18nFolder = cds.env.i18n.folders?.[0] || 'i18n'
50
+ const i18nFolder = getI18nDefaultFolder()
50
51
  // create language bundle for base model
51
52
  const i18n = await this.collectLanguageBundles(dictionary.base, path.join(destBase, i18nFolder))
52
53
  if (i18n && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
@@ -3,6 +3,7 @@ const path = require('path')
3
3
  const cds = require('../../../cds')
4
4
  const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
5
5
  const { OUTPUT_MODE, OUTPUT_MODE_RESULT, FILE_EXT_CDS, CONTENT_LANGUAGE_BUNDLES, CONTENT_DEFAULT_CSN, DEFAULT_CSN_FILE_NAME } = require('../../constants')
6
+ const { getI18nDefaultFolder } = require('../../util')
6
7
  const DEFAULT_COMPILE_DEST_FOLDER = path.normalize('src/main/resources/edmx')
7
8
 
8
9
  class JavaModuleBuilder extends BuildTaskHandlerEdmx {
@@ -28,8 +29,7 @@ class JavaModuleBuilder extends BuildTaskHandlerEdmx {
28
29
 
29
30
  if (this.hasBuildOption(CONTENT_LANGUAGE_BUNDLES, true)) {
30
31
  // collect and write language bundles into single i18n.json file
31
- const i18nFolder = cds.env.i18n.folders?.[0] || 'i18n'
32
- const i18n = await this.collectLanguageBundles(model, path.join(this.task.dest, i18nFolder))
32
+ const i18n = await this.collectLanguageBundles(model, path.join(this.task.dest, getI18nDefaultFolder()))
33
33
  if (i18n && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
34
34
  this._result.languageBundles = i18n.bundles
35
35
  }
@@ -83,12 +83,8 @@ class ResourcesTarBuilder {
83
83
  }
84
84
 
85
85
  async _getHanaTenantDbDest() {
86
- let hanaTask = this.handler.context.tasks.find(task => task.for === BUILD_TASK_HANA)
87
- if (!hanaTask) {
88
- this.handler.pushMessage(`Found SQLite database configuration. Ensure that productive cloud deployments requiring SAP HANA database are built with 'production' profile.`, WARNING)
89
- return null
90
- }
91
- return hanaTask.dest
86
+ const hanaTask = this.handler.context.tasks.find(task => task.for === BUILD_TASK_HANA)
87
+ return hanaTask?.dest
92
88
  }
93
89
  }
94
90
  module.exports = ResourcesTarBuilder
@@ -1,11 +1,11 @@
1
1
  const path = require('path')
2
2
  const cds = require('../../../cds')
3
3
  const fs = require('fs')
4
- const { FOLDER_GEN, DEFAULT_CSN_FILE_NAME } = require('../../constants')
4
+ const { FOLDER_GEN, DEFAULT_CSN_FILE_NAME, MTX_SIDECAR_DB_VALIDATION } = require('../../constants')
5
5
  const NodeCfModuleBuilder = require('../nodejs')
6
6
  const ResourcesTarProvider = require('../mtx/resourcesTarBuilder')
7
- const { WARNING, ERROR } = NodeCfModuleBuilder
8
- const { relativePaths, BuildError, resolveRequiredSapModels } = require('../../util')
7
+ const { ERROR } = NodeCfModuleBuilder
8
+ const { relativePaths, BuildError, resolveRequiredSapModels, getI18nDefaultFolder } = require('../../util')
9
9
 
10
10
  const DEFAULT_MAIN_FOLDER = "_main"
11
11
 
@@ -45,11 +45,10 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
45
45
  async _buildNodeApp(sidecarEnv) {
46
46
  const destSidecar = this.task.dest
47
47
  const destSidecarSrc = path.join(destSidecar, cds.env.folders.srv)
48
- const i18nFolder = cds.env.i18n.folders?.[0] || 'i18n'
49
48
  const model = this._compileSidecarSync(sidecarEnv)
50
49
  await this.compileToJson(model, path.join(destSidecarSrc, DEFAULT_CSN_FILE_NAME))
51
50
 
52
- await this.collectLanguageBundles(model, path.join(destSidecarSrc, i18nFolder))
51
+ await this.collectLanguageBundles(model, path.join(destSidecarSrc, getI18nDefaultFolder()))
53
52
  await this.copySrvContent(this.task.src, destSidecar, destSidecar)
54
53
  }
55
54
 
@@ -62,13 +61,18 @@ class MtxSidecarModuleBuilder extends NodeCfModuleBuilder {
62
61
  if (!main) {
63
62
  throw new BuildError(`Invalid MTX sidecar configuration. Make sure that the profile 'mtx-sidecar' is configured and an up-to-date version of @sap/cds-mtxs is installed.`)
64
63
  }
65
- const profiles = cds.env.profiles || []
64
+ if (!this.hasBuildOption(MTX_SIDECAR_DB_VALIDATION, false)
65
+ && !cds.env.build.tasks?.length // disable if custom build tasks exist
66
+ && sidecarEnv.requires.db && cds.env.requires.db // ensure database is configured
67
+ && sidecarEnv.requires.db.kind !== cds.env.requires.db.kind) {
68
+ throw new BuildError(`Inconsistent database configuration found - application db '${cds.env.requires.db?.kind}', sidecar db '${sidecarEnv.requires.db?.kind}'`)
69
+ }
70
+ const profiles = cds.env.profiles ?? []
71
+ if (!profiles.includes("production") && !profiles.includes("prod")) {
72
+ // need to overwrite 'development' profile setting '../..' with '_main', although it is questionable why cds build is executed with development profile
73
+ main = DEFAULT_MAIN_FOLDER
74
+ }
66
75
 
67
- if (!profiles.includes("production") && !profiles.includes("prod")) {
68
- main = DEFAULT_MAIN_FOLDER
69
- // root should represent the production use case and not development
70
- this.pushMessage(`MTX sidecar build results are created in folder '${main}'. Enable 'production' or 'prod' profile if the folder is configured differently.`, WARNING)
71
- }
72
76
  const destRoot = this.task.dest
73
77
  const destMain = path.join(destRoot, main)
74
78
  const destMainSrv = path.join(destMain, cds.env.folders.srv)
package/lib/build/util.js CHANGED
@@ -170,6 +170,13 @@ async function copy(src, dest) {
170
170
  }
171
171
  }
172
172
 
173
+ function getI18nDefaultFolder() {
174
+ // keep '_i18n' as preferred folder for compatibility reasons
175
+ if (cds.env.i18n.folders.includes('_i18n')) return '_i18n'
176
+ if (cds.env.i18n.folders.includes('i18n')) return 'i18n'
177
+ return cds.env.i18n.folders[0] ?? 'i18n'
178
+ }
179
+
173
180
  /**
174
181
  * Return gnu-style error string for location `loc`:
175
182
  * - 'File:Line:Col' without `loc.end`
@@ -258,6 +265,7 @@ module.exports = {
258
265
  getDefaultModelOptions,
259
266
  flatten,
260
267
  copy,
268
+ getI18nDefaultFolder,
261
269
  BuildMessage,
262
270
  BuildError
263
271
  }
package/lib/cds.js CHANGED
@@ -3,8 +3,8 @@ const cds = _local ('@sap/cds')
3
3
 
4
4
  module.exports = Object.defineProperties (cds, {
5
5
  // for internal use in cds-dk only
6
- _log: { value: _local ('../bin/util/log') },
7
- _local: { value: _local },
6
+ _log: { value: _local ('../bin/util/log'), configurable: true },
7
+ _local: { value: _local, configurable: true },
8
8
  })
9
9
 
10
10
  function _local (id) {
@@ -1,6 +1,8 @@
1
1
  const path = require('path');
2
2
  const fs = require('fs').promises;
3
3
 
4
+ require('../util/pruneAxiosErrors');
5
+
4
6
  const { CliError } = require('./helper/errors');
5
7
 
6
8
  const MTX_URL_PATH_PREFIX = 'mtx/v1/model/';
@@ -26,17 +28,12 @@ module.exports = class BaseCommand {
26
28
  case 403:
27
29
  throw new CliError(prefix + ': insufficient authorization. Ensure client has all necessary roles.', { error, command });
28
30
  case 404:
29
- throw new CliError(prefix + ': resource not found.', { command });
31
+ throw new CliError(prefix + ': resource not found.', { error, command });
30
32
  case 422:
31
33
  // Compilation or native-extension error.
32
34
  throw new CliError(prefix + '.', { error, command });
33
35
  default:
34
36
  // Unexpected error should be transparent to user.
35
- if (!require('..').debug('axios')) {
36
- error.config?.auth && (error.config.auth = '...'); // TODO use &&= with Node > 14
37
- delete error.request;
38
- delete error.response;
39
- }
40
37
  throw error;
41
38
  }
42
39
  }
@@ -16,11 +16,31 @@ function getHeaderProperties(name) {
16
16
  return { type: { const: name } };
17
17
  }
18
18
 
19
+ function nestedAnnotation(resObj, asyncapiProperty, keys, value) {
20
+ if (resObj[asyncapiProperty] === undefined) {
21
+ resObj[asyncapiProperty] = {};
22
+ }
23
+
24
+ let node = resObj[asyncapiProperty];
25
+
26
+ // traverse the annotation property and define the objects if they're not defined
27
+ for (let nestedIndex = 1; nestedIndex < keys.length - 1; nestedIndex++) {
28
+ const nestedElement = keys[nestedIndex];
29
+ if (node[nestedElement] === undefined) {
30
+ node[nestedElement] = {};
31
+ }
32
+ node = node[nestedElement];
33
+ }
34
+
35
+ // set value annotation property
36
+ node[keys[keys.length - 1]] = value;
37
+ }
38
+
19
39
  function readAnnotations(definition, presets) {
20
40
  let resObj = {};
21
41
 
22
42
  for (const [key, value] of Object.entries(definition)) {
23
- if (key.startsWith('@AsyncAPI')) {
43
+ if (key.startsWith('@AsyncAPI') && !key.startsWith('@AsyncAPI.Extensions')) {
24
44
  // get annotation value after @AsyncAPI
25
45
  const annotationProperties = key.split('@AsyncAPI.')[1];
26
46
  const keys = annotationProperties.split('.');
@@ -35,23 +55,22 @@ function readAnnotations(definition, presets) {
35
55
  if (keys.length === 1) {
36
56
  resObj[asyncapiProperty] = value;
37
57
  } else {
38
- if (resObj[asyncapiProperty] === undefined) {
39
- resObj[asyncapiProperty] = {};
40
- }
41
-
42
- let node = resObj[asyncapiProperty];
58
+ nestedAnnotation(resObj, asyncapiProperty, keys, value)
59
+ }
60
+ }
43
61
 
44
- // traverse the annotation property and define the objects if they're not defined
45
- for (let nestedIndex = 1; nestedIndex < keys.length-1; nestedIndex++) {
46
- const nestedElement = keys[nestedIndex];
47
- if (node[nestedElement] === undefined) {
48
- node[nestedElement] = {};
49
- }
50
- node = node[nestedElement];
51
- }
62
+ else if (key.startsWith('@AsyncAPI.Extensions')) {
63
+ const annotationProperties = key.split('@AsyncAPI.Extensions.')[1];
64
+ const keys = annotationProperties.split('.');
65
+ keys[0] = "x-" + keys[0];
52
66
 
53
- // set value annotation property
54
- node[keys[keys.length-1]] = value;
67
+ if (keys.length === 1) {
68
+ // if the key is already present, that means, Annotations have already been considered
69
+ if (resObj[keys[0]]) continue;
70
+ // else we populate
71
+ resObj[keys[0]] = value;
72
+ } else {
73
+ nestedAnnotation(resObj, keys[0], keys, value);
55
74
  }
56
75
  }
57
76
  }
@@ -142,9 +161,13 @@ function entriesToMessages(definitions, events, presets) {
142
161
  /**
143
162
  * Combining the definition objects from CSN into one schema
144
163
  */
145
- module.exports = function definitionsToMessages(definitions, events, presets) {
164
+ function definitionsToMessages(definitions, events, presets) {
146
165
  const messages = {};
147
-
148
166
  Object.assign(messages, entriesToMessages(definitions, events, presets));
149
167
  return messages;
150
168
  }
169
+
170
+ module.exports = {
171
+ definitionsToMessages,
172
+ nestedAnnotation
173
+ }