@sap/cds-dk 7.1.0 → 7.2.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 (56) hide show
  1. package/bin/build.js +3 -3
  2. package/bin/cds.js +2 -1
  3. package/bin/compile/index.js +5 -1
  4. package/bin/gen.js +27 -0
  5. package/bin/help.js +2 -1
  6. package/bin/watch.js +3 -4
  7. package/bin/watched.js +2 -3
  8. package/lib/bind/bindingUtil.js +1 -0
  9. package/lib/build/buildTaskEngine.js +13 -17
  10. package/lib/build/buildTaskFactory.js +23 -27
  11. package/lib/build/buildTaskHandler.js +6 -12
  12. package/lib/build/buildTaskProviderFactory.js +9 -12
  13. package/lib/build/constants.js +2 -1
  14. package/lib/build/index.js +1 -1
  15. package/lib/build/provider/buildTaskHandlerInternal.js +2 -2
  16. package/lib/build/provider/buildTaskProviderInternal.js +15 -25
  17. package/lib/build/provider/fiori/index.js +4 -3
  18. package/lib/build/provider/hana/index.js +14 -7
  19. package/lib/build/provider/java/index.js +2 -2
  20. package/lib/build/provider/nodejs/index.js +51 -18
  21. package/lib/build/util.js +11 -19
  22. package/lib/compile/openapi/csdl2openapi.js +30 -21
  23. package/lib/compile/openapi/index.js +7 -3
  24. package/lib/import/common.js +1 -1
  25. package/lib/import/message.js +6 -1
  26. package/lib/import/odata/metadataconverter/MetadataConverter.js +13 -9
  27. package/lib/import/odata/v4parser.js +26 -12
  28. package/lib/init/constants.js +6 -11
  29. package/lib/init/index.js +84 -71
  30. package/lib/init/template/_merging/registry-mta.js +0 -12
  31. package/lib/init/template/approuter/files/mta.yaml.hbs +1 -1
  32. package/lib/init/template/approuter/index.js +7 -6
  33. package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +0 -5
  34. package/lib/init/template/cf-manifest/index.js +2 -2
  35. package/lib/init/template/h2/index.js +16 -0
  36. package/lib/init/template/hana/index.js +2 -3
  37. package/lib/init/template/helm/chart/values.root.schema.json +0 -5
  38. package/lib/init/template/helm/chart/values.schema.json +0 -4
  39. package/lib/init/template/helm/index.js +1 -1
  40. package/lib/init/template/lint/index.js +3 -7
  41. package/lib/init/template/multitenancy/files/package.json.hbs +0 -3
  42. package/lib/init/template/multitenancy/index.js +2 -0
  43. package/lib/init/template/nodejs/index.js +3 -3
  44. package/lib/init/template/pipeline/index.js +2 -4
  45. package/lib/init/template/sample/index.js +5 -7
  46. package/lib/init/template/sqlite/index.js +8 -3
  47. package/lib/init/template/tiny-sample/index.js +16 -30
  48. package/lib/init/util/mvn.js +25 -1
  49. package/lib/init/util/projectReader.js +3 -7
  50. package/lib/init/util/template.js +7 -6
  51. package/lib/watch/node-watch.js +6 -1
  52. package/npm-shrinkwrap.json +46 -84
  53. package/package.json +5 -4
  54. package/lib/init/template/auditlog/files/mta.yaml.hbs +0 -14
  55. package/lib/init/template/auditlog/files/package.json.hbs +0 -27
  56. package/lib/init/template/auditlog/index.js +0 -74
package/bin/build.js CHANGED
@@ -1,6 +1,6 @@
1
1
  module.exports = Object.assign(build, {
2
- options: ['--project', '--src', '--dest', '--for', '--use', '--opts', '--log-level', '--options-model', '--clean'],
3
- shortcuts: ['-in', '-s', '-o', '-4'],
2
+ options: ['--project', '--src', '--dest', '--for', '--workspaces', '--use', '--opts', '--log-level', '--options-model', '--clean'],
3
+ shortcuts: ['-in', '-s', '-o', '-4', '-ws'],
4
4
  help: `
5
5
  # SYNOPSIS
6
6
 
@@ -92,7 +92,7 @@ async function build([project], options = {}) {
92
92
  // IMPORTANT: call plugins before subsequent access to cds.env
93
93
  await cds.plugins
94
94
 
95
- cds.root = path.resolve(process.cwd(), project || options.project || '.')
95
+ cds.root = path.resolve(process.cwd(), project || options.project || '.')
96
96
  cds.env = cds.env.for('cds', cds.root);
97
97
  delete options.project // avoid that relative project paths are resolved twice
98
98
 
package/bin/cds.js CHANGED
@@ -102,7 +102,8 @@ const cli = { //NOSONAR
102
102
  }
103
103
 
104
104
  // if (env) require('../lib/cds').env.add (env) //> avoid loading env
105
- process.env.CDS_CONFIG = JSON.stringify(env)
105
+ // unless it has already explicitly been set by the user
106
+ process.env.CDS_CONFIG ??= JSON.stringify(env)
106
107
  return [ args, options ]
107
108
  },
108
109
 
@@ -2,7 +2,7 @@ const path = require("path");
2
2
 
3
3
  module.exports = Object.assign ( compile, {
4
4
  options: [
5
- '--from', '--service', '--lang', '--for', '--to', '--dest', '--log-level', '--flavor', '--dialect', '--sql-dialect', '--openapi:url', '--openapi:servers'
5
+ '--from', '--service', '--lang', '--for', '--to', '--dest', '--log-level', '--flavor', '--dialect', '--sql-dialect', '--openapi:url', '--openapi:servers', '--odata-version'
6
6
  ],
7
7
  shortcuts: [
8
8
  undefined, '-s', '-l', '-4', '-2', '-o', undefined, '-f'
@@ -114,6 +114,10 @@ module.exports = Object.assign ( compile, {
114
114
  The servers definition used in the generated OpenAPI document. *--openapi:url* is
115
115
  ignored when this option is specified.
116
116
 
117
+ *--odata-version* 4.0|4.01
118
+
119
+ Adds the OData version's functionality of the input CDS/CSN file to the generated OpenAPI document.
120
+
117
121
  *--openapi:diagram*
118
122
 
119
123
  Include YUML diagram in the generated OpenAPI document, default: *false*.
package/bin/gen.js ADDED
@@ -0,0 +1,27 @@
1
+ const { join } = require('path')
2
+ const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) ? console.debug : undefined
3
+
4
+ module.exports = require(global('@sap/cds-gen', 'bin/cds-gen'))
5
+
6
+ function global (id, subpath) {
7
+ const pkgPath = join(id, 'package.json') // package.json gives a stable entry path
8
+ let mod
9
+ try {
10
+ mod = require.resolve (pkgPath, { paths: [ process.cwd(), __dirname ] })
11
+ } catch (err) { // one more try w/ NPM global paths
12
+ const paths = [ process.cwd(), __dirname, npmGlobalModules() ]
13
+ try {
14
+ mod = require.resolve (pkgPath, { paths })
15
+ } catch (error) {
16
+ DEBUG?.(error)
17
+ throw `\nNo '${id}' package found. Install it with\n\n npm i -g ${id}\n`
18
+ }
19
+ }
20
+ return join(mod, '..', subpath)
21
+ }
22
+
23
+ function npmGlobalModules() {
24
+ try {
25
+ return require ('child_process').execSync('npm root -g').toString().trim()
26
+ } catch (err) { DEBUG?.(err); return '' }
27
+ }
package/bin/help.js CHANGED
@@ -10,6 +10,7 @@ module.exports = exports = Object.assign (help, {formatHelp, help:`
10
10
 
11
11
  *i* | *init* jump-start cds-based projects
12
12
  *a* | *add* add a feature to an existing project
13
+ * * | *gen* generate models/data using a descriptive prompt [beta]
13
14
  *y* | *bind* bind application to remote services
14
15
  *m* | *import* add models from external sources
15
16
  *c* | *compile* compile cds models to different outputs
@@ -27,7 +28,7 @@ module.exports = exports = Object.assign (help, {formatHelp, help:`
27
28
  * * | *logout* logout from extensible multitenant SaaS app
28
29
  * * | *pull* pull base model of extensible SaaS app
29
30
  * * | *push* push extension to extensible SaaS app
30
- *t* | *lint* [beta] run linter for env or model checks
31
+ *t* | *lint* run linter for env or model checks [beta]
31
32
  *v* | *version* get detailed version information
32
33
  *?* | *help* get detailed usage information
33
34
 
package/bin/watch.js CHANGED
@@ -60,7 +60,7 @@ const t = module.exports.codes = {
60
60
  }
61
61
  const extDefaults = 'cds,csn,csv,ts,mjs,cjs,js,json,properties,edmx,xml,env'
62
62
  const fioriIncludes = /_?(change|variant)$/ // according to fiori: change,variant,ctrl_variant,ctrl_variant_change,ctrl_variant_management_change.
63
- let ignore = /node_modules|target|\.cds-services\.json$/
63
+ const ignore = RegExp(`app${sep}.*${sep}?webapp${sep}|node_modules|target|\\.cds-services\\.json$`)
64
64
 
65
65
  async function watch ([cwd], {
66
66
  args = ['serve', 'all'],
@@ -99,8 +99,6 @@ async function watch ([cwd], {
99
99
  env.CDS_LIVERELOAD_PATH = require.resolve ('../lib/watch/livereload-connect')
100
100
  env.CDS_LIVERELOAD_URL = await liveReload.start (options['livereload'])
101
101
  .catch(err => { console.log(`Error starting live reload: ${err.message}`); liveReload = null })
102
- } else {
103
- ignore = RegExp(`app${sep}.*\\.(js|ts)|`+ignore.source) // exclude more frontend stuff
104
102
  }
105
103
 
106
104
  const log = (first,...more) => console.log (t.yellow + (first||''), ...more, t.reset)
@@ -115,7 +113,8 @@ async function watch ([cwd], {
115
113
  log ()
116
114
  log (`${t.bold}cds ${args.join(' ')}`)
117
115
  DEBUG && log (process.pid, 'watching:', ext, '...')
118
- if (includes) DEBUG && log (`also watching: ${includes.source}`)
116
+ includes && DEBUG && log (`also watching: ${includes.source}`)
117
+ DEBUG && log ('ignoring:', ignore.source)
119
118
  if (liveReload) log (`live reload enabled for browsers`)
120
119
 
121
120
  const BindingManager = require('../lib/bind/bindingManager')
package/bin/watched.js CHANGED
@@ -21,9 +21,8 @@
21
21
  case 'NO_SERVICES_FOUND': return _no_services_found(e)
22
22
  case 'MODEL_NOT_FOUND': return _no_models_found(e)
23
23
  case 'EADDRINUSE': return process.send(e) //> tell cds watch
24
- default: if (!e.messages) { // compiler messages have been written by cli already
25
- console.error('\n❗️ ERROR on server start: ❗️\n\n', e)
26
- }
24
+ default: if (e.messages?.length) return cds._log(e.messages, { 'log-level': cds.env.log.levels.cli }) // REVISIT: no special handling for compiler messages
25
+ else console.error('\n❗️ ERROR on server start: ❗️\n\n', e)
27
26
  }}
28
27
 
29
28
  function _no_models_found(e) { console.log (`
@@ -1,6 +1,7 @@
1
1
 
2
2
  const KindToRequiresNameMap = {
3
3
  xsuaa: 'auth',
4
+ 'ias-auth': 'auth',
4
5
  'hana-cloud': 'db',
5
6
  hana: 'db',
6
7
  'hana-mt': 'db', // For compatibility only
@@ -5,7 +5,6 @@ const { sortMessagesSeverityAware, deduplicateMessages, CompilationError } = cds
5
5
  const { relativePaths, BuildError, resolveRequiredSapModels } = require('./util')
6
6
  const { SEVERITIES, LOG_LEVELS } = require('./constants')
7
7
  const BuildTaskFactory = require('./buildTaskFactory')
8
- const BuildTaskProviderFactory = require('./buildTaskProviderFactory')
9
8
  const BuildTaskHandlerInternal = require('./provider/buildTaskHandlerInternal')
10
9
 
11
10
  const COMPILATION_ERROR = 'CompilationError'
@@ -13,27 +12,26 @@ const COMPILE_MESSAGE = 'CompileMessage'
13
12
 
14
13
  class BuildTaskEngine {
15
14
  constructor(options) {
16
- this._providerFactory = new BuildTaskProviderFactory(options)
15
+ this._taskFactory = new BuildTaskFactory(options)
17
16
  }
18
- get providerFactory() {
19
- return this._providerFactory
17
+ get taskFactory() {
18
+ return this._taskFactory
20
19
  }
21
20
  get logger() {
22
- return this.providerFactory.logger
21
+ return this.taskFactory.logger
23
22
  }
24
- get buildOptions() {
25
- return this.providerFactory.buildOptions
23
+ get options() {
24
+ return this.taskFactory.options
26
25
  }
27
26
 
28
27
  async processTasks(tasks) {
29
28
  const startTime = Date.now()
30
29
 
31
- this.logger.log(`building project [${cds.root}], clean [${this.buildOptions.clean}]`)
30
+ this.logger.log(`building project [${cds.root}], clean [${this.options.clean}]`)
32
31
  this.logger.log(`cds-dk [${require('../../package.json').version}], cds [${cds.version}], compiler [${cds.compiler.version()}], home [${cds.home}]\n`)
33
32
 
34
33
  if (!tasks) {
35
- const buildTaskFactory = new BuildTaskFactory(this.buildOptions)
36
- tasks = await buildTaskFactory.getTasks()
34
+ tasks = await this.taskFactory.getTasks()
37
35
  }
38
36
 
39
37
  // validate required @sap namespace models - log only
@@ -51,9 +49,6 @@ class BuildTaskEngine {
51
49
  }
52
50
  })
53
51
 
54
- // use resolved tasks
55
- this.providerFactory.context.tasks = handlers.map(handler => handler.task)
56
-
57
52
  try {
58
53
  await this._executePrepare(handlers)
59
54
  await this._executeCleanBuildTasks(handlers)
@@ -113,7 +108,7 @@ class BuildTaskEngine {
113
108
  }
114
109
 
115
110
  async _executeCleanBuildTasks(handlers) {
116
- if (this.buildOptions.clean) {
111
+ if (this.options.clean) {
117
112
  // clean entire build staging folder once
118
113
  if (cds.env.build.target !== '.') {
119
114
  const target = path.resolve(cds.root, cds.env.build.target)
@@ -208,7 +203,7 @@ class BuildTaskEngine {
208
203
  }
209
204
 
210
205
  _createHandler(task) {
211
- const handler = this.providerFactory.createHandler(task)
206
+ const handler = this.taskFactory.createHandler(task)
212
207
  handler.init()
213
208
 
214
209
  if (!(handler instanceof BuildTaskHandlerInternal) && handler.priority !== 1) {
@@ -269,6 +264,7 @@ class BuildTaskEngine {
269
264
  "log-level": this._getLogLevel() // ensures that for tests the correct cds.env is used
270
265
  }
271
266
  deduplicateMessages(messages)
267
+ sortMessagesSeverityAware(messages)
272
268
  log(messages, options)
273
269
  }
274
270
  }
@@ -317,7 +313,7 @@ class BuildTaskEngine {
317
313
  /**
318
314
  * Sort and filter the given errors of type CompileMessage or BuildMessage according to their severity and location,
319
315
  * but leave any other errors untouched as part of the result array.<br>
320
- * The log level passed as 'buildOptions.log-level' or defined in 'cds.env' is used to filter the given messages.
316
+ * The log level ('command line' or 'cds.env' option) is used to filter the given messages.
321
317
  * @param {...Error} messages
322
318
  */
323
319
  _sortMessagesUnique(...messages) {
@@ -336,7 +332,7 @@ class BuildTaskEngine {
336
332
  * Return user defined log level or default value 'warn'
337
333
  */
338
334
  _getLogLevel() {
339
- return this.buildOptions["log-level"] || cds.env["log-level"]
335
+ return this.options["log-level"] || cds.env["log-level"]
340
336
  }
341
337
  }
342
338
  module.exports = BuildTaskEngine
@@ -15,8 +15,8 @@ class BuildTaskFactory {
15
15
  get logger() {
16
16
  return this.providerFactory.logger
17
17
  }
18
- get buildOptions() {
19
- return this.providerFactory.buildOptions
18
+ get options() {
19
+ return this.providerFactory.options
20
20
  }
21
21
 
22
22
  // the following order for determining build tasks is used
@@ -41,12 +41,16 @@ class BuildTaskFactory {
41
41
 
42
42
  // always resolve tasks for input validation
43
43
  const resolvedTasks = this.providerFactory.resolveTasks(tasks)
44
- if (this.buildOptions.resolve) {
44
+ if (this.options.resolve) {
45
45
  return resolvedTasks
46
46
  }
47
47
  return tasks
48
48
  }
49
49
 
50
+ createHandler(task) {
51
+ return this.providerFactory.createHandler(task)
52
+ }
53
+
50
54
  async _createTasks() {
51
55
  this.logger.debug(`determining build tasks for project [${cds.root}].`)
52
56
 
@@ -148,24 +152,24 @@ class BuildTaskFactory {
148
152
  }
149
153
 
150
154
  _applyCliOptionsFilter(tasks) {
151
- const buildOptions = this.buildOptions
155
+ const options = this.options
152
156
  // filter tasks using either option for, use, src
153
157
  let resultTasks = tasks.filter(task => {
154
- return (!buildOptions.use || buildOptions.use === task.use)
155
- && (!buildOptions.for || buildOptions.for === task.for)
156
- && (!buildOptions.src || buildOptions.src === task.src)
158
+ return (!options.use || options.use === task.use)
159
+ && (!options.for || options.for === task.for)
160
+ && (!options.src || options.src === task.src)
157
161
  })
158
162
  if (resultTasks.length === 0) {
159
- if (buildOptions.for || buildOptions.use) {
163
+ if (options.for || options.use) {
160
164
  const task = {}
161
- if ((buildOptions.for)) {
162
- task.for = buildOptions.for
165
+ if ((options.for)) {
166
+ task.for = options.for
163
167
  }
164
- if ((buildOptions.use)) {
165
- task.use = buildOptions.use
168
+ if ((options.use)) {
169
+ task.use = options.use
166
170
  }
167
- if (buildOptions.src) {
168
- task.src = buildOptions.src
171
+ if (options.src) {
172
+ task.src = options.src
169
173
  }
170
174
  resultTasks.push(task)
171
175
  }
@@ -180,14 +184,14 @@ class BuildTaskFactory {
180
184
  }
181
185
 
182
186
  _applyCliOptions(tasks) {
183
- const buildOptions = this.buildOptions
187
+ const options = this.options
184
188
  // apply remaining cli options to filtered tasks
185
189
  tasks.forEach(task => {
186
- if (buildOptions.dest) {
187
- task.dest = buildOptions.dest
190
+ if (options.dest) {
191
+ task.dest = options.dest
188
192
  }
189
- if (buildOptions.opts) {
190
- const opts = BuildTaskFactory._scanTaskOptionParams(buildOptions.opts)
193
+ if (options.opts) {
194
+ const opts = BuildTaskFactory._scanTaskOptionParams(options.opts)
191
195
  task.options = task.options ? Object.assign(task.options, opts) : opts
192
196
  }
193
197
  })
@@ -237,14 +241,6 @@ class BuildTaskFactory {
237
241
  return taskOptions
238
242
  }
239
243
 
240
- /**
241
- * For valid paths remove trailing '/'. Otherwise return as is - important!!
242
- * @param {*} dir
243
- */
244
- static _normalizePath(dir) {
245
- return typeof dir === "string" ? dir.replace(/\/$/, '') : dir
246
- }
247
-
248
244
  /**
249
245
  * Determines the module folder from the past list that may represent files or folders w or w/o .cds file extension.
250
246
  * @param {Array} filesOrFolders
@@ -3,7 +3,7 @@ const fs = require('fs').promises
3
3
  const cds = require('../cds')
4
4
 
5
5
  const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, SEVERITY_INFO, SEVERITY_WARNING, SEVERITY_ERROR, OVERRIDE_METHOD_MSG } = require('./constants')
6
- const { hasOptionValue, getProperty, relativePaths, copy, BuildMessage } = require('./util')
6
+ const { hasOptionValue, getProperty, relativePaths, BuildMessage } = require('./util')
7
7
 
8
8
  /**
9
9
  * The build task handler creates the build output for a dedicated build task. It is uniquely identified
@@ -155,10 +155,7 @@ class BuildTaskHandler {
155
155
  dest = path.resolve(this.task.dest, dest)
156
156
  }
157
157
  this.pushFile(dest)
158
- if (fs.cp) { // Node.js >= 16.7
159
- return fs.cp(src, dest, { recursive: true })
160
- }
161
- return copy(src, dest)
158
+ return fs.cp(src, dest, { recursive: true })
162
159
  }
163
160
  return dest
164
161
  }
@@ -227,14 +224,11 @@ class BuildTaskHandler {
227
224
  // Returns the value of the given build option defined for this build task.
228
225
  _getBuildOption(qualifiedName) {
229
226
  // build task options overwriting other settings
230
- let value = getProperty(this.task.options, qualifiedName)
231
- if (value !== undefined) {
232
- return value
233
- }
234
- value = getProperty(this.context.options, qualifiedName)
235
- if (value !== undefined) {
236
- return value
227
+ let value = getProperty(this.context.options, qualifiedName) // command line
228
+ if (value === undefined) {
229
+ value = getProperty(this.task.options, qualifiedName) // task options
237
230
  }
231
+ return value
238
232
  }
239
233
  }
240
234
  module.exports = BuildTaskHandler
@@ -13,12 +13,12 @@ class BuildTaskProviderFactory {
13
13
  options.clean = true
14
14
  }
15
15
  this._buildOptions = options
16
- this._context = { options }
16
+ this._context = { options, tasks: [] } // resolved tasks
17
17
  }
18
18
  get logger() {
19
- return this.buildOptions.logger
19
+ return this.options.logger
20
20
  }
21
- get buildOptions() {
21
+ get options() {
22
22
  return this._context.options
23
23
  }
24
24
  get context() {
@@ -83,6 +83,7 @@ class BuildTaskProviderFactory {
83
83
  handler._task = resolvedTask
84
84
  handler._logger = this.logger
85
85
  handler._context = this.context
86
+ this.context.tasks.push(resolvedTask)
86
87
  this.logger._debug && this.logger.debug(`created BuildTaskHandler [${resolvedTask.use}]`)
87
88
  return handler
88
89
  }
@@ -147,15 +148,11 @@ class BuildTaskProviderFactory {
147
148
  }
148
149
 
149
150
  _loadProviders() {
150
- // order is important - the DefaultBuildTaskProvider has to be the last provider in the list
151
- return [this._createProvider(BuildTaskProviderInternal), this._createProvider(DefaultBuildTaskProvider)]
152
- }
153
-
154
- _createProvider(clazz, plugin) {
155
- const provider = new clazz()
156
- provider._logger = this.logger
157
- provider._plugin = plugin
158
- return provider
151
+ // DefaultBuildTaskProvider must be last entry
152
+ return [
153
+ new BuildTaskProviderInternal(this.logger),
154
+ new DefaultBuildTaskProvider()
155
+ ]
159
156
  }
160
157
  }
161
158
 
@@ -33,8 +33,9 @@ exports.CONTENT_DEFAULT_ENV_JSON = "contentDefaultEnvJson" // copy default-
33
33
 
34
34
  exports.CSV_FILE_DETECTION = "csvFileDetection" // detect CSV files based on CDS model location - ENABLED by default
35
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
36
  exports.MTX_SIDECAR_DB_VALIDATION = "mtxSidecarDbValidation" // validate consistency of app and sidecar db configuration - ENABLED by default
37
+ exports.CONTINUE_UNRESOLVED_SCHEMA_CHANGES = "continueUnresolvedSchemaChanges" // build doesn't fail if unresolved HANA schema changes are detected
38
+ exports.IGNORE_DEFAULT_MODELS = "ignoreDefaultModels" // do not add default models (@sap/cds-*, fts/*) to existing build task model options
38
39
 
39
40
  exports.FOLDER_GEN = "gen"
40
41
  exports.FILE_EXT_CDS = ".cds"
@@ -20,7 +20,7 @@ async function build(options = {}) {
20
20
  return await new BuildTaskEngine(options).processTasks()
21
21
  } catch (e) {
22
22
  if (e instanceof BuildError || e.constructor.name === 'CompilationError') {
23
- cds._log(e.messages.length ? [...e.messages, ''] : e.message + '\n', { 'log-level': options['log-level'] || cds.env['log-level'] })
23
+ cds._log(e.messages.length ? e.messages : e.message, { 'log-level': options['log-level'] || cds.env['log-level'] })
24
24
  // CompilationError.message also includes the detail messages - do not log twice
25
25
  const message = e.constructor.name === 'CompilationError' ? 'CDS compilation failed' : e.messages.length ? e.message : 'CDS build failed'
26
26
  throw message
@@ -43,9 +43,9 @@ 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 handler type specific options section.
49
49
  * @returns {Promise<boolean>} A value 'false' indicates that {@link #prepare()} will not be called for other instances
50
50
  * of this handler type.
51
51
  * True indicates that {@link #prepare()} will be called for other instances of this of this handler type.
@@ -1,12 +1,12 @@
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
11
  class BuildTaskProviderInternal extends BuildTaskProvider {
12
12
  constructor(logger) {
@@ -49,8 +49,8 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
49
49
  }
50
50
 
51
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
52
+ let db = typeof cds.env.folders.db === "string" ? [normalizePath(cds.env.folders.db)] : cds.env.folders.db
53
+ let srv = typeof cds.env.folders.srv === "string" ? [normalizePath(cds.env.folders.srv)] : cds.env.folders.srv
54
54
 
55
55
  const dbOptions = {
56
56
  model: []
@@ -269,16 +269,16 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
269
269
  static _setDefaultSrcFolder(task) {
270
270
  switch (task.for) {
271
271
  case BUILD_TASK_HANA:
272
- task.src = task.src || this._normalizePath(cds.env.folders.db)
272
+ task.src = task.src || normalizePath(cds.env.folders.db)
273
273
  break
274
274
  case BUILD_TASK_JAVA:
275
275
  case BUILD_TASK_JAVA_CF:
276
276
  case BUILD_TASK_NODEJS:
277
277
  case BUILD_TASK_NODE_CF:
278
- task.src = task.src || this._normalizePath(cds.env.folders.srv)
278
+ task.src = task.src || normalizePath(cds.env.folders.srv)
279
279
  break
280
280
  case BUILD_TASK_FIORI:
281
- task.src = task.src || this._normalizePath(cds.env.folders.app)
281
+ task.src = task.src || normalizePath(cds.env.folders.app)
282
282
  break
283
283
  case BUILD_TASK_MTX_SIDECAR:
284
284
  task.src = task.src || MTX_SIDECAR_FOLDER
@@ -288,7 +288,7 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
288
288
  break
289
289
  case BUILD_TASK_MTX:
290
290
  // mtxs with nodejs, but without sidecar
291
- task.src = task.src || this._normalizePath(cds.env.folders.srv)
291
+ task.src = task.src || normalizePath(cds.env.folders.srv)
292
292
  break
293
293
  default:
294
294
  throw new Error(`Unknown build task '${task.use || task.for}'`)
@@ -300,29 +300,27 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
300
300
  if (taskModelPaths && !Array.isArray(taskModelPaths)) {
301
301
  taskModelPaths = [taskModelPaths]
302
302
  }
303
+ const toggles = cds.env.features.folders
304
+ const allowList = new RegExp(`^@sap/cds${toggles ? '|^' + toggles.replace('*', '') : ''}`)
303
305
  task.options = task.options || {}
304
306
  let defaultModelPaths = []
305
- // add default models to custom build tasks if this hasn't been disabled
306
307
  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'))
308
+ if (!hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
309
+ defaultModelPaths = getDefaultModelOptions().filter(p => p.match(allowList))
310
310
  }
311
311
  } else {
312
312
  defaultModelPaths = getDefaultModelOptions()
313
313
  defaultModelPaths.push(task.src)
314
- if (hasOptionValue(task.options?.[DEFAULT_BUILT_IN_MODELS], false)) {
314
+ if (hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
315
315
  // all default models except the built-in models
316
- defaultModelPaths = defaultModelPaths.filter(p => !p.match('@sap/cds'))
316
+ defaultModelPaths = defaultModelPaths.filter(p => !p.match(allowList))
317
317
  }
318
318
  }
319
-
320
319
  // REVISIT: filter nodejs bootstrap service models for Java - issues/12770#issuecomment-1805719
321
320
  if (this._hasJavaNature()) {
322
321
  defaultModelPaths = defaultModelPaths.filter(p => !NODEJS_MODEL_EXCLUDE_LIST.includes(p))
323
322
  }
324
- // also add built-in models to custom build tasks already containing model options
325
- if (!taskModelPaths || defaultModelPaths.length) {
323
+ if (defaultModelPaths.length) {
326
324
  task.options.model = [...new Set(taskModelPaths?.length ? taskModelPaths.concat(defaultModelPaths) : defaultModelPaths)]
327
325
  }
328
326
  }
@@ -340,14 +338,6 @@ Upgrade to @sap/cds-mtxs following the migration guide https://cap.cloud.sap/doc
340
338
  return task.for ? task.for : task.use && task.use.substring(BUILD_TASK_PREFIX.length + 1)
341
339
  }
342
340
 
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
341
  /**
352
342
  * Determines the module folder from the past list that may represent files or folders w or w/o .cds file extension.
353
343
  * @param {Array} filesOrFolders
@@ -52,8 +52,9 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
52
52
  appModelGroups.set(appFolder, appModels)
53
53
  }
54
54
 
55
- const originFioriBuildOption = fioriBuildOptions[OUTPUT_MODE]
56
- fioriBuildOptions[OUTPUT_MODE] = OUTPUT_MODE_RESULT
55
+ // ensure edmx is cached as build result
56
+ const buildOption = this.context.options[OUTPUT_MODE]
57
+ this.context.options[OUTPUT_MODE] |= OUTPUT_MODE_RESULT
57
58
 
58
59
  try {
59
60
  const edmxOptions = { version: cds.env.odata?.version }
@@ -76,7 +77,7 @@ class FioriAppModuleBuilder extends BuildTaskHandlerEdmx {
76
77
  fioriBuildOptions.appEdmx.set(appFolder, this._result.edmx)
77
78
  }
78
79
  } finally {
79
- fioriBuildOptions[OUTPUT_MODE] = originFioriBuildOption
80
+ this.context.options[OUTPUT_MODE] = buildOption
80
81
  }
81
82
  return false
82
83
  }
@@ -3,11 +3,11 @@ const path = require('path')
3
3
  const cds = require('../../../cds')
4
4
  const to_hdbmigration = require('./2migration')
5
5
  const BuildTaskHandlerInternal = require('../buildTaskHandlerInternal')
6
- const { BuildError, relativePaths } = require('../../util')
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 } = BuildTaskHandlerInternal
11
11
 
12
12
  const DEFAULT_COMPILE_DEST_FOLDER = path.normalize("src/gen")
13
13
 
@@ -15,13 +15,11 @@ 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
25
  class HanaModuleBuilder extends BuildTaskHandlerInternal {
@@ -478,18 +476,27 @@ class HanaModuleBuilder extends BuildTaskHandlerInternal {
478
476
  })
479
477
  if (migrationTableFiles.length > 0) {
480
478
  const parser = require('./migrationtable')
479
+ const resolutionMessages = []
481
480
 
482
481
  await Promise.all(migrationTableFiles.map(async file => {
483
482
  try {
484
483
  const tableModel = await parser.read(file)
485
484
  if (/^>>>>>/m.test(tableModel.migrations.toString())) {
486
485
  // 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)
486
+ resolutionMessages.push(new BuildMessage(`Manual resolution required for file ${path.relative(cds.root, file)}. Check migration version content for further details.`))
488
487
  }
489
488
  } catch (e) {
490
- throw new Error(`${path.relative(cds.root, file)}: ${e.toString()}`, ERROR)
489
+ throw new Error(`${path.relative(cds.root, file)}: ${e.toString()}`)
491
490
  }
492
491
  }))
492
+ if (resolutionMessages.length) {
493
+ // REVISIT: undocumented, we may want to delete in future versions
494
+ if (!this.hasBuildOption(CONTINUE_UNRESOLVED_SCHEMA_CHANGES, true)) {
495
+ throw new BuildError('Current model changes require manual resolution', resolutionMessages)
496
+ }
497
+ // adding to the task's message list
498
+ resolutionMessages.forEach(m => this._messages.push(m))
499
+ }
493
500
  }
494
501
  }
495
502