@sap/cds-dk 7.1.1 → 7.3.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.
Files changed (84) hide show
  1. package/bin/activate.js +2 -2
  2. package/bin/build.js +5 -2
  3. package/bin/compile/index.js +13 -5
  4. package/bin/env.js +0 -3
  5. package/bin/extend.js +25 -3
  6. package/bin/gen.js +27 -0
  7. package/bin/help.js +2 -1
  8. package/bin/import.js +7 -3
  9. package/bin/push.js +10 -6
  10. package/bin/watch.js +3 -4
  11. package/bin/watched.js +2 -3
  12. package/lib/bind/bindingUtil.js +1 -0
  13. package/lib/build/{buildTaskHandler.js → buildPlugin.js} +25 -30
  14. package/lib/build/buildTaskEngine.js +84 -89
  15. package/lib/build/buildTaskFactory.js +23 -44
  16. package/lib/build/buildTaskProvider.js +24 -19
  17. package/lib/build/buildTaskProviderFactory.js +176 -66
  18. package/lib/build/constants.js +6 -5
  19. package/lib/build/index.js +4 -3
  20. package/lib/build/provider/{buildTaskHandlerEdmx.js → edmxBuildPlugin.js} +6 -6
  21. package/lib/build/provider/{buildTaskHandlerFeatureToggles.js → featureToggleBuildPlugin.js} +3 -3
  22. package/lib/build/provider/fiori/index.js +5 -6
  23. package/lib/build/provider/hana/index.js +67 -36
  24. package/lib/build/provider/{buildTaskHandlerInternal.js → internalBuildPlugin.js} +11 -11
  25. package/lib/build/provider/{buildTaskProviderInternal.js → internalBuildTaskProvider.js} +42 -53
  26. package/lib/build/provider/java/index.js +24 -24
  27. package/lib/build/provider/mtx/index.js +4 -4
  28. package/lib/build/provider/mtx/resourcesTarBuilder.js +8 -8
  29. package/lib/build/provider/mtx-extension/index.js +17 -9
  30. package/lib/build/provider/mtx-sidecar/index.js +17 -11
  31. package/lib/build/provider/nodejs/index.js +63 -29
  32. package/lib/build/util.js +11 -19
  33. package/lib/client/auth_manager.js +6 -12
  34. package/lib/client/base_command.js +1 -1
  35. package/lib/client/download_legacy.js +48 -0
  36. package/lib/client/params.js +5 -0
  37. package/lib/client/push.js +41 -1
  38. package/lib/client/settings_manager.js +12 -3
  39. package/lib/compile/openapi/csdl2openapi.js +30 -21
  40. package/lib/compile/openapi/index.js +7 -3
  41. package/lib/env/schema.js +36 -0
  42. package/lib/env/schemas/cds-rc.json +101 -0
  43. package/lib/import/common.js +24 -11
  44. package/lib/import/importapi.js +2 -2
  45. package/lib/import/message.js +3 -1
  46. package/lib/import/odata/v4parser.js +23 -7
  47. package/lib/index.js +5 -0
  48. package/lib/init/constants.js +9 -12
  49. package/lib/init/index.js +86 -74
  50. package/lib/init/template/_merging/registry-mta.js +21 -12
  51. package/lib/init/template/approuter/files/mta.yaml.hbs +1 -1
  52. package/lib/init/template/approuter/index.js +3 -2
  53. package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +0 -5
  54. package/lib/init/template/cf-manifest/index.js +2 -2
  55. package/lib/init/template/connectivity/index.js +5 -4
  56. package/lib/init/template/destination/index.js +2 -5
  57. package/lib/init/template/h2/index.js +16 -0
  58. package/lib/init/template/hana/index.js +2 -3
  59. package/lib/init/template/helm/chart/values.root.schema.json +0 -5
  60. package/lib/init/template/helm/chart/values.schema.json +0 -4
  61. package/lib/init/template/helm/index.js +1 -1
  62. package/lib/init/template/html5-repo/index.js +27 -3
  63. package/lib/init/template/lint/index.js +3 -7
  64. package/lib/init/template/mta/index.js +9 -3
  65. package/lib/init/template/multitenancy/files/package.json.hbs +0 -3
  66. package/lib/init/template/multitenancy/index.js +2 -0
  67. package/lib/init/template/nodejs/index.js +3 -3
  68. package/lib/init/template/pipeline/index.js +2 -4
  69. package/lib/init/template/postgres/files/mta.yaml.hbs +27 -0
  70. package/lib/init/template/postgres/files/package.json.hbs +5 -0
  71. package/lib/init/template/postgres/index.js +52 -0
  72. package/lib/init/template/sample/index.js +5 -7
  73. package/lib/init/template/sqlite/index.js +8 -3
  74. package/lib/init/template/tiny-sample/index.js +16 -30
  75. package/lib/init/util/mvn.js +25 -1
  76. package/lib/init/util/projectReader.js +2 -7
  77. package/lib/init/util/template.js +7 -6
  78. package/lib/util/pruneAxiosErrors.js +22 -8
  79. package/lib/watch/node-watch.js +6 -1
  80. package/npm-shrinkwrap.json +2207 -384
  81. package/package.json +3 -3
  82. package/lib/init/template/auditlog/files/mta.yaml.hbs +0 -14
  83. package/lib/init/template/auditlog/files/package.json.hbs +0 -27
  84. package/lib/init/template/auditlog/index.js +0 -74
@@ -2,12 +2,12 @@ const fs = require('fs')
2
2
  const path = require('path')
3
3
  const cds = require('../../../cds')
4
4
  const to_hdbmigration = require('./2migration')
5
- const BuildTaskHandlerInternal = require('../buildTaskHandlerInternal')
6
- const { BuildError, relativePaths } = require('../../util')
5
+ const InternalBuildPlugin = require('../internalBuildPlugin')
6
+ const { BuildError, relativePaths, BuildMessage } = require('../../util')
7
7
 
8
8
  const { OUTPUT_MODE_NONE, OUTPUT_MODE, CONTENT_PACKAGE_JSON, CONTENT_HDBTABLEDATA, CSV_FILE_DETECTION,
9
- CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES, OUTPUT_MODE_RESULT } = require('../../constants')
10
- const { ERROR, WARNING } = BuildTaskHandlerInternal
9
+ CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES, OUTPUT_MODE_RESULT, CONTINUE_UNRESOLVED_SCHEMA_CHANGES } = require('../../constants')
10
+ const { WARNING } = InternalBuildPlugin
11
11
 
12
12
  const DEFAULT_COMPILE_DEST_FOLDER = path.normalize("src/gen")
13
13
 
@@ -15,16 +15,14 @@ const FILE_EXT_CSV = ".csv"
15
15
  const FILE_EXT_HDBTABLEDATA = ".hdbtabledata"
16
16
  const FILE_EXT_HDBTABLE = ".hdbtable"
17
17
  const FILE_EXT_HDBMIGRATIONTABLE = ".hdbmigrationtable"
18
-
19
18
  const FILE_NAME_HDICONFIG = ".hdiconfig"
20
19
  const FILE_NAME_HDINAMESPACE = ".hdinamespace"
21
20
  const FILE_NAME_PACKAGE_JSON = "package.json"
22
21
  const PATH_LAST_DEV_CSN = "last-dev/csn.json"
23
22
  const FILE_NAME_UNDEPLOY_JSON = "undeploy.json"
24
-
25
23
  const DEPLOY_FORMAT = "deploy-format"
26
24
 
27
- class HanaModuleBuilder extends BuildTaskHandlerInternal {
25
+ class HanaBuildPlugin extends InternalBuildPlugin {
28
26
  init() {
29
27
  if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
30
28
  this._result = {
@@ -155,7 +153,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
155
153
 
156
154
  // handle *.csv and *.hdbtabledata located in '<dbSrc>/data' and '<dbSrc>/csv' folder
157
155
  const allFiles = csvDirs.reduce((acc, csvDir) => {
158
- return acc.concat(BuildTaskHandlerInternal._find(csvDir, (entry) => {
156
+ return acc.concat(InternalBuildPlugin._find(csvDir, (entry) => {
159
157
  if (fs.statSync(entry).isDirectory()) {
160
158
  return false
161
159
  }
@@ -183,7 +181,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
183
181
  const tableDataDirs = new Set()
184
182
  const destSrcDir = path.join(this.task.dest, "src")
185
183
 
186
- const allCsvFiles = BuildTaskHandlerInternal._find(destSrcDir, (entry) => {
184
+ const allCsvFiles = InternalBuildPlugin._find(destSrcDir, (entry) => {
187
185
  if (fs.statSync(entry).isDirectory()) {
188
186
  return true
189
187
  }
@@ -250,7 +248,8 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
250
248
  return Promise.reject(new Error(`Invalid deploy-format defined: ${format}`))
251
249
  }
252
250
 
253
- if (this.hasCdsEnvOption('features.journal', false) || format === 'hdbcds') {
251
+ let no_migration = cds.env.features.journal === false || format === 'hdbcds' || Object.values(model.definitions).every(def => !def['@cds.persistence.journal'])
252
+ if (no_migration) {
254
253
  return await this._compileToHdb(model, format)
255
254
  } else {
256
255
  return await this._compileToHdbmigration(model, format)
@@ -266,12 +265,24 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
266
265
  const promises = []
267
266
 
268
267
  for (const [content, key] of result) {
269
- hdiPlugins.add(key.suffix || path.extname(key.file))
268
+ const suffix = key.suffix || path.extname(key.file)
270
269
  const file = key.file ? key.file : key.name + key.suffix
270
+
271
+ hdiPlugins.add(suffix)
271
272
  if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
272
273
  this._result.hana.push(path.join(relDest, file))
273
274
  }
274
275
  promises.push(this.write(content).to(path.join(this.task.options.compileDest, file)))
276
+ if (suffix === FILE_EXT_HDBTABLE) {
277
+ const name = key.name || path.parse(key.file).name
278
+ const dbSrcDir = path.join(this.task.src, "src")
279
+ // issue an error in case a .hdbmigrationtable file already exists
280
+ if (fs.existsSync(path.join(dbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE))) {
281
+ const relDbSrcDir = path.relative(cds.root, dbSrcDir)
282
+ const relDbDestDir = path.relative(cds.root, this.task.options.compileDest)
283
+ throw new BuildError(`Multiple files exist defining the same HANA artifact - [${path.join(relDbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE)}, ${path.join(relDbDestDir, file)}].\nEither annotate the model entity using @cds.persistence.journal or undeploy the file [${path.join('src', name + FILE_EXT_HDBMIGRATIONTABLE)}] using an undeploy.json file.`)
284
+ }
285
+ }
275
286
  }
276
287
  await Promise.all(promises)
277
288
  return hdiPlugins
@@ -298,6 +309,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
298
309
  const compilationResult = await to_hdbmigration(model, lastDev, dbSrcDir, options)
299
310
  const definitions = compilationResult.definitions
300
311
  const afterImage = compilationResult.afterImage
312
+ let validationError
301
313
 
302
314
  for (const { name, suffix, content, changed } of definitions) {
303
315
  hdiPlugins.add(suffix)
@@ -320,28 +332,38 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
320
332
  if (suffix === FILE_EXT_HDBTABLE) {
321
333
  // issue an error in case a .hdbmigrationtable file already exists
322
334
  if (fs.existsSync(path.join(dbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE))) {
323
- throw new BuildError(`Multiple files exist defining the same HANA artifact - [${path.join(relDbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE)}, ${path.join(relDbDestDir, file)}].\nEither annotate the model entity using @cds.persistence.journal or undeploy the file [${path.join('src', name + FILE_EXT_HDBMIGRATIONTABLE)}] using an undeploy.json file.`)
335
+ validationError = new BuildError(`Multiple files exist defining the same HANA artifact - [${path.join(relDbSrcDir, name + FILE_EXT_HDBMIGRATIONTABLE)}, ${path.join(relDbDestDir, file)}].\nEither annotate the model entity using @cds.persistence.journal or undeploy the file [${path.join('src', name + FILE_EXT_HDBMIGRATIONTABLE)}] using an undeploy.json file.`)
324
336
  }
325
337
  }
326
338
  }
327
339
  }
340
+ // the last-dev CSN shall only be updated, if all .hdbmigrationtable files could be successfully updated
341
+ // of course, .hdbmigrationtable files already written would need to be manually reverted before the
342
+ // cds build command is again executed
328
343
  await Promise.all(promises)
329
- await this._validateMigrationTableFiles()
330
-
331
- // update last development version
332
- if (afterImage) {
333
- if (migrationTableFiles.length > 0) {
334
- if (!HanaModuleBuilder._toEqualIgnoreMeta(lastDev, afterImage)) {
335
- await this.write(afterImage).to(lastDevCsnDir)
336
- }
337
344
 
338
- // add src/.hdiconfig if not existing
339
- if (!fs.existsSync(path.join(dbSrcDir, FILE_NAME_HDICONFIG))) {
340
- const template = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-cloud')
341
- await this.write(template).to(path.join(dbSrcDir, FILE_NAME_HDICONFIG))
345
+ // ensure
346
+ try {
347
+ if (validationError) {
348
+ throw validationError
349
+ }
350
+ await this._validateMigrationTableFiles()
351
+ } finally {
352
+ // update last-dev CSN version
353
+ if (afterImage) {
354
+ if (migrationTableFiles.length > 0) {
355
+ if (!HanaBuildPlugin._toEqualIgnoreMeta(lastDev, afterImage)) {
356
+ await this.write(afterImage).to(lastDevCsnDir)
357
+ }
358
+ // add src/.hdiconfig if not existing
359
+ if (!fs.existsSync(path.join(dbSrcDir, FILE_NAME_HDICONFIG))) {
360
+ const template = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-cloud')
361
+ await this.write(template).to(path.join(dbSrcDir, FILE_NAME_HDICONFIG))
362
+ }
342
363
  }
343
364
  }
344
- } else {
365
+ }
366
+ if (!afterImage) {
345
367
  throw new BuildError(`Inconsistent CDS compilation results - file ${lastDevCsnFolder} missing`)
346
368
  }
347
369
  return hdiPlugins
@@ -355,7 +377,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
355
377
  this.logger._debug && this.logger.debug(`skip create [${relativePaths(cds.root, packageJson)}], already existing`)
356
378
  }
357
379
  if (this.isStagingBuild() && !exists) {
358
- const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
380
+ const content = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
359
381
  await this.write(content).to(path.join(this.task.dest, FILE_NAME_PACKAGE_JSON))
360
382
  }
361
383
  }
@@ -374,11 +396,11 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
374
396
  // && !fs.existsSync(path.join(this.task.dest, FILE_NAME_HDICONFIG))
375
397
  // && !fs.existsSync(path.join(this.task.dest, 'cfg', FILE_NAME_HDICONFIG))) {
376
398
  // // in 'gen/db' if none exists
377
- // // ensures correct deployment of all artifacts including HANA native artifacts
399
+ // // ensures correct deployment of all artifacts including HANA native artifacts
378
400
  // // without the need of creating a static .hdiconfig file in the 'db' folder
379
401
 
380
402
  // // add all known plugins
381
- // const defaultHdiConfig = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-cloud')
403
+ // const defaultHdiConfig = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-cloud')
382
404
  // for (const plugin in defaultHdiConfig['file_suffixes']) {
383
405
  // hdiPlugins.add('.' + plugin)
384
406
  // }
@@ -390,7 +412,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
390
412
  hdiConfigPath = path.join(this.task.options.compileDest, FILE_NAME_HDICONFIG)
391
413
  // }
392
414
 
393
- const template = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-all')
415
+ const template = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-all')
394
416
  let content = {
395
417
  'file_suffixes': {}
396
418
  }
@@ -412,7 +434,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
412
434
  async _writeHdiNamespace() {
413
435
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
414
436
  const hdiNamespace = path.join(this.task.options.compileDest, FILE_NAME_HDINAMESPACE)
415
- const content = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
437
+ const content = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
416
438
  return await this.write(content).to(hdiNamespace)
417
439
  }
418
440
 
@@ -424,7 +446,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
424
446
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
425
447
  const undeployJsonDest = path.join(this.task.dest, FILE_NAME_UNDEPLOY_JSON)
426
448
  const undeployJsonSrc = path.join(this.task.src, FILE_NAME_UNDEPLOY_JSON)
427
- const templateEntries = await HanaModuleBuilder._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
449
+ const templateEntries = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
428
450
  let newEntries = []
429
451
  if (fs.existsSync(undeployJsonSrc)) {
430
452
  newEntries = await JSON.parse((await fs.promises.readFile(undeployJsonSrc, 'utf-8')).toString())
@@ -454,7 +476,7 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
454
476
  if (fs.existsSync(file)) {
455
477
  const undeployList = JSON.parse((await fs.promises.readFile(file)).toString(), 'utf-8')
456
478
  if (Array.isArray(undeployList)) {
457
- const hdiconfig = await HanaModuleBuilder._readTemplateAsJson('.hdiconfig-all')
479
+ const hdiconfig = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-all')
458
480
  const keys = new Set(Object.keys(hdiconfig['file_suffixes']).map(key => '.' + key))
459
481
  undeployList.forEach(entry => {
460
482
  const extName = path.extname(entry)
@@ -473,23 +495,32 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
473
495
 
474
496
  async _validateMigrationTableFiles() {
475
497
  const dbSrcDir = path.join(this.task.src, "src")
476
- const migrationTableFiles = BuildTaskHandlerInternal._find(dbSrcDir, (res) => {
498
+ const migrationTableFiles = InternalBuildPlugin._find(dbSrcDir, (res) => {
477
499
  return fs.statSync(res).isFile() && path.extname(res) === FILE_EXT_HDBMIGRATIONTABLE
478
500
  })
479
501
  if (migrationTableFiles.length > 0) {
480
502
  const parser = require('./migrationtable')
503
+ const resolutionMessages = []
481
504
 
482
505
  await Promise.all(migrationTableFiles.map(async file => {
483
506
  try {
484
507
  const tableModel = await parser.read(file)
485
508
  if (/^>>>>>/m.test(tableModel.migrations.toString())) {
486
509
  // as this is not a build error, we do not abort cds build, instead only log as error
487
- this.pushMessage(`Current model changes require manual resolution. See migration file ${path.relative(cds.root, file)} for further details.`, ERROR)
510
+ resolutionMessages.push(new BuildMessage(`Manual resolution required for file ${path.relative(cds.root, file)}. Check migration version content for further details.`))
488
511
  }
489
512
  } catch (e) {
490
- throw new Error(`${path.relative(cds.root, file)}: ${e.toString()}`, ERROR)
513
+ throw new Error(`${path.relative(cds.root, file)}: ${e.toString()}`)
491
514
  }
492
515
  }))
516
+ if (resolutionMessages.length) {
517
+ // REVISIT: undocumented, we may want to delete in future versions
518
+ if (!this.hasBuildOption(CONTINUE_UNRESOLVED_SCHEMA_CHANGES, true)) {
519
+ throw new BuildError('Current model changes require manual resolution', resolutionMessages)
520
+ }
521
+ // adding to the task's message list
522
+ resolutionMessages.forEach(m => this._messages.push(m))
523
+ }
493
524
  }
494
525
  }
495
526
 
@@ -519,4 +550,4 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
519
550
  return toString(csn1) === toString(csn2)
520
551
  }
521
552
  }
522
- module.exports = HanaModuleBuilder
553
+ module.exports = HanaBuildPlugin
@@ -1,11 +1,11 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
  const cds = require('../../cds')
4
- const BuildTaskHandler = require('../buildTaskHandler')
4
+ const BuildPlugin = require('../buildPlugin')
5
5
  const { hasOptionValue } = require('../util')
6
6
  const { FOLDER_GEN } = require('../constants')
7
7
 
8
- class BuildTaskHandlerInternal extends BuildTaskHandler {
8
+ class InternalBuildPlugin extends BuildPlugin {
9
9
  /**
10
10
  * Returns the logger that has been passed the build task engine.
11
11
  * @returns {object}
@@ -15,11 +15,11 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
15
15
  return this._logger;
16
16
  }
17
17
  /**
18
- * Custom build handlers are executed before internal handlers in order
18
+ * Custom build plugins are executed before internal build plugins in order
19
19
  * ensure and content cannot be overwritten by mistake.
20
20
  */
21
21
  get priority() {
22
- return BuildTaskHandlerInternal.PRIORITY_MAX_VALUE
22
+ return InternalBuildPlugin.PRIORITY_MAX_VALUE
23
23
  }
24
24
 
25
25
  async clean() {
@@ -43,16 +43,16 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
43
43
  }
44
44
 
45
45
  /**
46
- * Called by the framework after {@link #init()}. Handlers may want to perform more elaborate preparation.
46
+ * Called by the framework after {@link #init()}, used to perform more elaborate preparation.
47
47
  * E.g. caching some pre-calculated data that can be used across multiple build tasks. This kind of data
48
- * has to be stored in the handler type specific buildOptions section.
48
+ * has to be stored in the plugin type specific options section.
49
49
  * @returns {Promise<boolean>} A value 'false' indicates that {@link #prepare()} will not be called for other instances
50
- * of this handler type.
51
- * True indicates that {@link #prepare()} will be called for other instances of this of this handler type.
50
+ * of this plugin type.
51
+ * True indicates that {@link #prepare()} will be called for other instances of this of this plugin type.
52
52
  * @deprecated
53
53
  */
54
54
  async prepare() {
55
- // cancel subsequent prepare calls for other handlers of the same type by default
55
+ // cancel subsequent prepare calls for other plugins of the same type by default
56
56
  return false
57
57
  }
58
58
 
@@ -101,7 +101,7 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
101
101
  }
102
102
 
103
103
  async copyNativeContent(srcDir, destDir, customFilter) {
104
- const files = BuildTaskHandlerInternal._find(srcDir, (src) => {
104
+ const files = InternalBuildPlugin._find(srcDir, (src) => {
105
105
  // do not copy files that:
106
106
  // - from 'cds.env.build.target'
107
107
  // - from 'dest'
@@ -225,4 +225,4 @@ class BuildTaskHandlerInternal extends BuildTaskHandler {
225
225
  return fs.lstatSync(entry)
226
226
  }
227
227
  }
228
- module.exports = BuildTaskHandlerInternal
228
+ module.exports = InternalBuildPlugin
@@ -1,14 +1,14 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
  const cds = require('../../cds')
4
- const { hasJavaNature, getDefaultModelOptions, BuildError, hasOptionValue, isClassicMtx } = require('../util')
4
+ const { hasJavaNature, getDefaultModelOptions, BuildError, hasOptionValue, isClassicMtx, normalizePath } = require('../util')
5
5
  const BuildTaskProvider = require('../buildTaskProvider')
6
6
 
7
7
  const { FILE_EXT_CDS, BUILD_TASK_HANA, BUILD_TASK_FIORI, BUILD_TASK_JAVA, BUILD_TASK_JAVA_CF, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF, BUILD_TASK_MTX,
8
8
  BUILD_TASK_PREFIX, BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION, NODEJS_MODEL_EXCLUDE_LIST,
9
- DEFAULT_BUILT_IN_MODELS } = require("../constants")
9
+ IGNORE_DEFAULT_MODELS } = require("../constants")
10
10
 
11
- class BuildTaskProviderInternal extends BuildTaskProvider {
11
+ class InternalBuildTaskProvider extends BuildTaskProvider {
12
12
  constructor(logger) {
13
13
  super()
14
14
  this._logger = logger
@@ -22,35 +22,34 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
22
22
  return this._logger
23
23
  }
24
24
 
25
- canHandleTask(task) {
26
- return BUILD_TASKS.includes(task.for)
27
- || task.use && task.use.startsWith(BUILD_TASK_PREFIX)
28
- // support different build task implementations of the same build task ID defined by 'for'
29
- //return (BUILD_TASKS.includes(task.for) && !task.use) || (task.use && task.use.startsWith(BUILD_TASK_PREFIX))
25
+ providesTask(key) {
26
+ return BUILD_TASKS.includes(key.for) || key.use && key.use.startsWith(BUILD_TASK_PREFIX)
27
+ // REVISIT: do not support different build task implementations of the same build task ID defined by 'for'
28
+ // return (BUILD_TASKS.includes(key.for) && !key.use) || (key.use && key.use.startsWith(BUILD_TASK_PREFIX))
30
29
  }
31
30
 
32
- loadHandler(task) {
33
- return require(`./${BuildTaskProviderInternal._getForValueFromTask(task)}`)
34
- }
35
-
36
- async lookupTasks(tasks) {
37
- return this._createTasks(tasks, tasks.length > 0)
31
+ async lookupTasks(tasks, dependencies) {
32
+ return this._createTasks(tasks, dependencies)
38
33
  }
39
34
 
40
35
  async applyTaskDefaults(task) {
41
- const taskFor = BuildTaskProviderInternal._getForValueFromTask(task)
36
+ const taskFor = InternalBuildTaskProvider._getForValueFromTask(task)
42
37
  task.for = task.for || taskFor
43
38
  task.use = task.use || `${BUILD_TASK_PREFIX}/${taskFor}`
44
39
 
45
40
  // src folder needs to be initialized first
46
- BuildTaskProviderInternal._setDefaultSrcFolder(task)
41
+ InternalBuildTaskProvider._setDefaultSrcFolder(task)
47
42
 
48
- BuildTaskProviderInternal._setDefaultModel(task)
43
+ InternalBuildTaskProvider._setDefaultModel(task)
49
44
  }
50
45
 
51
- async _createTasks(tasks, addRequiredTasks) {
52
- let db = typeof cds.env.folders.db === "string" ? [BuildTaskProviderInternal._normalizePath(cds.env.folders.db)] : cds.env.folders.db
53
- let srv = typeof cds.env.folders.srv === "string" ? [BuildTaskProviderInternal._normalizePath(cds.env.folders.srv)] : cds.env.folders.srv
46
+ loadPlugin(task) {
47
+ return require(`./${InternalBuildTaskProvider._getForValueFromTask(task)}`)
48
+ }
49
+
50
+ async _createTasks(tasks, dependencies) {
51
+ let db = typeof cds.env.folders.db === "string" ? [normalizePath(cds.env.folders.db)] : cds.env.folders.db
52
+ let srv = typeof cds.env.folders.srv === "string" ? [normalizePath(cds.env.folders.srv)] : cds.env.folders.srv
54
53
 
55
54
  const dbOptions = {
56
55
  model: []
@@ -59,20 +58,20 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
59
58
  model: []
60
59
  }
61
60
  if (Array.isArray(db) && db.length > 0) {
62
- db = BuildTaskProviderInternal._getModuleFolder(db) || null
63
- if (!db && !addRequiredTasks) { // log once
61
+ db = InternalBuildTaskProvider._getModuleFolder(db) || null
62
+ if (!db && !dependencies) { // log once
64
63
  this.logger.debug("No database module found")
65
64
  }
66
65
  }
67
66
  if (Array.isArray(srv) && srv.length > 0) {
68
- srv = BuildTaskProviderInternal._getModuleFolder(srv) || null
69
- if (!srv && !addRequiredTasks) { // log once
67
+ srv = InternalBuildTaskProvider._getModuleFolder(srv) || null
68
+ if (!srv && !dependencies) { // log once
70
69
  this.logger.debug("No service module found")
71
70
  }
72
71
  }
73
72
 
74
73
  // order of creation is relevant
75
- if (addRequiredTasks) {
74
+ if (dependencies) {
76
75
  const mtxTask = tasks.find(task => task.for === BUILD_TASK_MTX || task.for === BUILD_TASK_MTX_SIDECAR)
77
76
  if (mtxTask) {
78
77
  //restore used tasks as they might have been filtered by 'cds build --for mtx'
@@ -124,7 +123,7 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
124
123
 
125
124
  _createDbTask(src, taskOptions) {
126
125
  this.logger.debug("determining database kind")
127
- if (!src || BuildTaskProviderInternal._isMtxExtension()) {
126
+ if (!src || InternalBuildTaskProvider._isMtxExtension()) {
128
127
  return null
129
128
  }
130
129
  let task = null
@@ -166,12 +165,12 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
166
165
  this.logger.debug("determining MTX architecture")
167
166
 
168
167
  // preserve order of creation
169
- if (BuildTaskProviderInternal._isMtxExtension()) {
168
+ if (InternalBuildTaskProvider._isMtxExtension()) {
170
169
  this.logger.debug("MTX extension app")
171
170
  return { for: BUILD_TASK_MTX_EXTENSION }
172
171
  }
173
172
 
174
- if (BuildTaskProviderInternal._isMtxs()) {
173
+ if (InternalBuildTaskProvider._isMtxs()) {
175
174
  const sidecarPath = path.join(cds.root, MTX_SIDECAR_FOLDER)
176
175
  let sidecarEnv
177
176
  if (fs.existsSync(sidecarPath)) {
@@ -204,7 +203,7 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
204
203
  }
205
204
 
206
205
  // mtxs nodejs app without sidecar
207
- if (!BuildTaskProviderInternal._hasJavaNature(src)) {
206
+ if (!InternalBuildTaskProvider._hasJavaNature(src)) {
208
207
  this.logger.debug("MTX Nodejs app without sidecar")
209
208
  return {
210
209
  for: BUILD_TASK_MTX,
@@ -216,11 +215,11 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
216
215
 
217
216
  _createSrvTask(src, taskOptions) {
218
217
  this.logger.debug("determining implementation technology")
219
- if (!src || BuildTaskProviderInternal._isMtxExtension()) {
218
+ if (!src || InternalBuildTaskProvider._isMtxExtension()) {
220
219
  return null
221
220
  }
222
221
  let task = null
223
- if (BuildTaskProviderInternal._hasJavaNature(src)) {
222
+ if (InternalBuildTaskProvider._hasJavaNature(src)) {
224
223
  task = this._createJavaTask(src, taskOptions)
225
224
  } else {
226
225
  task = this._createNodeTask(src, taskOptions)
@@ -269,16 +268,16 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
269
268
  static _setDefaultSrcFolder(task) {
270
269
  switch (task.for) {
271
270
  case BUILD_TASK_HANA:
272
- task.src = task.src || this._normalizePath(cds.env.folders.db)
271
+ task.src = task.src || normalizePath(cds.env.folders.db)
273
272
  break
274
273
  case BUILD_TASK_JAVA:
275
274
  case BUILD_TASK_JAVA_CF:
276
275
  case BUILD_TASK_NODEJS:
277
276
  case BUILD_TASK_NODE_CF:
278
- task.src = task.src || this._normalizePath(cds.env.folders.srv)
277
+ task.src = task.src || normalizePath(cds.env.folders.srv)
279
278
  break
280
279
  case BUILD_TASK_FIORI:
281
- task.src = task.src || this._normalizePath(cds.env.folders.app)
280
+ task.src = task.src || normalizePath(cds.env.folders.app)
282
281
  break
283
282
  case BUILD_TASK_MTX_SIDECAR:
284
283
  task.src = task.src || MTX_SIDECAR_FOLDER
@@ -288,7 +287,7 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
288
287
  break
289
288
  case BUILD_TASK_MTX:
290
289
  // mtxs with nodejs, but without sidecar
291
- task.src = task.src || this._normalizePath(cds.env.folders.srv)
290
+ task.src = task.src || normalizePath(cds.env.folders.srv)
292
291
  break
293
292
  default:
294
293
  throw new Error(`Unknown build task '${task.use || task.for}'`)
@@ -300,29 +299,27 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
300
299
  if (taskModelPaths && !Array.isArray(taskModelPaths)) {
301
300
  taskModelPaths = [taskModelPaths]
302
301
  }
302
+ const toggles = cds.env.features.folders
303
+ const allowList = new RegExp(`^@sap/cds${toggles ? '|^' + toggles.replace('*', '') : ''}`)
303
304
  task.options = task.options || {}
304
305
  let defaultModelPaths = []
305
- // add default models to custom build tasks if this hasn't been disabled
306
306
  if (taskModelPaths?.length) {
307
- if (!hasOptionValue(task.options?.[DEFAULT_BUILT_IN_MODELS], false)) {
308
- // get the built-in models
309
- defaultModelPaths = getDefaultModelOptions().filter(p => p.match('@sap/cds'))
307
+ if (!hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
308
+ defaultModelPaths = getDefaultModelOptions().filter(p => p.match(allowList))
310
309
  }
311
310
  } else {
312
311
  defaultModelPaths = getDefaultModelOptions()
313
312
  defaultModelPaths.push(task.src)
314
- if (hasOptionValue(task.options?.[DEFAULT_BUILT_IN_MODELS], false)) {
313
+ if (hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
315
314
  // all default models except the built-in models
316
- defaultModelPaths = defaultModelPaths.filter(p => !p.match('@sap/cds'))
315
+ defaultModelPaths = defaultModelPaths.filter(p => !p.match(allowList))
317
316
  }
318
317
  }
319
-
320
318
  // REVISIT: filter nodejs bootstrap service models for Java - issues/12770#issuecomment-1805719
321
319
  if (this._hasJavaNature()) {
322
320
  defaultModelPaths = defaultModelPaths.filter(p => !NODEJS_MODEL_EXCLUDE_LIST.includes(p))
323
321
  }
324
- // also add built-in models to custom build tasks already containing model options
325
- if (!taskModelPaths || defaultModelPaths.length) {
322
+ if (defaultModelPaths.length) {
326
323
  task.options.model = [...new Set(taskModelPaths?.length ? taskModelPaths.concat(defaultModelPaths) : defaultModelPaths)]
327
324
  }
328
325
  }
@@ -340,14 +337,6 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
340
337
  return task.for ? task.for : task.use && task.use.substring(BUILD_TASK_PREFIX.length + 1)
341
338
  }
342
339
 
343
- /**
344
- * For valid paths remove trailing '/'. Otherwise return as is - important!!
345
- * @param {*} dir
346
- */
347
- static _normalizePath(dir) {
348
- return typeof dir === "string" ? dir.replace(/\/$/, '') : dir
349
- }
350
-
351
340
  /**
352
341
  * Determines the module folder from the past list that may represent files or folders w or w/o .cds file extension.
353
342
  * @param {Array} filesOrFolders
@@ -375,4 +364,4 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
375
364
  }, null)
376
365
  }
377
366
  }
378
- module.exports = BuildTaskProviderInternal
367
+ module.exports = InternalBuildTaskProvider
@@ -1,35 +1,34 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
3
  const cds = require('../../../cds')
4
- const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
5
- const { OUTPUT_MODE, OUTPUT_MODE_RESULT, FILE_EXT_CDS, CONTENT_LANGUAGE_BUNDLES, CONTENT_DEFAULT_CSN, DEFAULT_CSN_FILE_NAME, OUTPUT_MODE_FILESYSTEM } = require('../../constants')
4
+ const EdmxBuildPlugin = require('../edmxBuildPlugin')
5
+ const { OUTPUT_MODE, OUTPUT_MODE_RESULT, FILE_EXT_CDS, CONTENT_LANGUAGE_BUNDLES, CONTENT_DEFAULT_CSN, DEFAULT_CSN_FILE_NAME,
6
+ OUTPUT_MODE_FILESYSTEM, FLAVOR_LOCALIZED_EDMX } = require('../../constants')
6
7
  const { getI18nDefaultFolder } = require('../../util')
7
8
  const DEFAULT_COMPILE_DEST_FOLDER = path.normalize('src/main/resources/edmx')
8
9
 
9
- class JavaModuleBuilder extends BuildTaskHandlerEdmx {
10
+ class JavaBuildPlugin extends EdmxBuildPlugin {
10
11
  init() {
11
12
  super.init()
12
13
  this.task.options.compileDest = path.resolve(this.task.dest, this.task.options.compileDest || DEFAULT_COMPILE_DEST_FOLDER)
13
14
  }
14
15
 
15
16
  async build() {
17
+ const compileDest = this.task.options.compileDest
16
18
  const { src, dest } = this.task
17
-
18
- const odataOptions = {
19
- version: cds.env.odata?.version
20
- }
21
-
22
19
  const model = await this.model()
23
20
  if (!model) {
24
21
  return
25
22
  }
26
23
 
27
- const odata = await this._compileForOdata(model, this.task.options.compileDest, odataOptions)
28
- await this.compileToEdmx(odata, this.task.options.compileDest, odataOptions)
24
+ // generate edmx files containing all features
25
+ const odata = await this._compileForOdata(model, compileDest)
26
+ await this.compileToEdmx(odata, compileDest) // localized edmx for backward compatibility
27
+ await this.compileToEdmx(odata, path.join(compileDest, 'odata', cds.env.odata.version), { [FLAVOR_LOCALIZED_EDMX]: false }) // non-localized edmx
29
28
 
30
- if (this.hasBuildOption(CONTENT_LANGUAGE_BUNDLES, true)) {
31
- // collect and write language bundles into single i18n.json file
32
- const i18n = await this.collectLanguageBundles(model, path.join(this.task.dest, getI18nDefaultFolder()))
29
+ if (!this.hasBuildOption(CONTENT_LANGUAGE_BUNDLES, false)) {
30
+ // collect and write language bundles containing all features
31
+ const i18n = await this.collectLanguageBundles(model, path.join(compileDest, getI18nDefaultFolder()))
33
32
  if (i18n && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
34
33
  this._result.languageBundles = i18n.bundles
35
34
  }
@@ -59,28 +58,29 @@ class JavaModuleBuilder extends BuildTaskHandlerEdmx {
59
58
  })
60
59
  }
61
60
 
62
- async _compileForOdata(model, csnDest, compileOptions) {
61
+ async _compileForOdata(model, csnDest, compileOptions = {}) {
63
62
  // csn for service providers
64
63
  const m = cds.compile.for.java(model, {
65
64
  ...this._options4odata(),
66
65
  ...compileOptions
67
66
  })
68
67
  const csnFile = path.join(csnDest, DEFAULT_CSN_FILE_NAME)
69
- let csnModel
70
68
  // adding csn to build result containing @source and _where persisted properties
71
69
  if (this.hasBuildOption(CONTENT_DEFAULT_CSN, true)) { //default true or undefined
72
70
  const csnStr = await this.compileToJson(model, csnFile)
73
- csnModel = JSON.parse(csnStr)
74
- csnModel.meta = model.meta
71
+ if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
72
+ const csnModel = JSON.parse(csnStr)
73
+ csnModel.meta = model.meta
74
+ this._result.csn = csnModel
75
+ }
75
76
  } else {
76
77
  const csnStr = await this.compileToJson(m, csnFile)
77
- csnModel = JSON.parse(csnStr)
78
- csnModel.meta = m.meta
79
- }
80
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
81
- this._result.csn = csnModel
78
+ if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
79
+ const csnModel = JSON.parse(csnStr)
80
+ csnModel.meta = m.meta
81
+ this._result.csn = csnModel
82
+ }
82
83
  }
83
-
84
84
  return m
85
85
  }
86
86
 
@@ -90,4 +90,4 @@ class JavaModuleBuilder extends BuildTaskHandlerEdmx {
90
90
  return match && match[1] === 1
91
91
  }
92
92
  }
93
- module.exports = JavaModuleBuilder
93
+ module.exports = JavaBuildPlugin