@sap/cds-dk 9.7.0 → 9.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,17 @@ This project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  The format is based on [Keep a Changelog](https://keepachangelog.com/).
8
8
 
9
+ ## Version 9.7.1 - 2026-02-05
10
+
11
+ ### Fixed
12
+
13
+ - `cds add completion` now works without specifying the project runtime.
14
+
15
+ - `cds add xsuaa` correctly adds the the binding for the `html5-apps-deployer` on Kyma.
16
+ - `cds version` prints an older format in a legacy situation.
17
+ - `cds add nodejs` is automatically added in BAS scenarios for compatibility if no other runtime is specified.
18
+ - `cds add data -n` works correctly for `Composition of one` scenarios.
19
+
9
20
  ## Version 9.7.0 - 2026-02-02
10
21
 
11
22
  ### Added
package/bin/version.js CHANGED
@@ -203,9 +203,10 @@ function print_versions (rows, o, cwd = o.root+'/') {
203
203
  if (!rows || rows.length === 0) return console.error (YELLOW, ' No CAP packages found.', RESET)
204
204
  const local = o.abs ? p => p : p => !p ? '' : p.startsWith(cwd) ? p.replace(cwd,'./') : p.replace(home,'~')
205
205
 
206
- if (cds.env['project-nature'] === 'java') { // cds10: remove
207
- console.log(rows.map(([name,version,location]) => `${GREEN}${name}:${RESET} ${version??location}`).join('\n'))
208
- return
206
+ // cds10: remove and offer --json option instead
207
+ if (cds.env['project-nature'] === 'java' || process.env.WS_BASE_URL) {
208
+ console.log(rows.map(([name,version,location]) => `${GREEN}${name === 'cds.home'?'home':name}:${RESET} ${version??location}`).join('\n'))
209
+ return
209
210
  }
210
211
 
211
212
  // compute column widths for tabular printing
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  const cds = require('../cds')
3
3
  const BuildTaskProviderFactory = require('./buildTaskProviderFactory')
4
- const { hasJavaNature, getProperty, getDefaultModelPaths, hasOptionValue, BuildError } = require('./util')
4
+ const { hasJavaNature, getDefaultModelPaths, hasOptionValue, BuildError } = require('./util')
5
5
  const { OPTION_WS, IGNORE_DEFAULT_MODELS, NODEJS_MODEL_EXCLUDE_LIST, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF } = require("./constants")
6
6
  const DEBUG = cds.debug('cli|build')
7
7
 
@@ -74,7 +74,7 @@ module.exports = class BuildTaskFactory {
74
74
  }
75
75
 
76
76
  static _getExistingTasks() {
77
- return Array.isArray(getProperty(cds.env, 'build.tasks')) ? JSON.parse(JSON.stringify(cds.env.build.tasks)) : []
77
+ return Array.isArray(cds.env.build?.tasks) ? structuredClone(cds.env.build.tasks) : []
78
78
  }
79
79
 
80
80
  static async _applyCommonTaskDefaults(tasks) {
@@ -7,7 +7,7 @@ const IS_WIN = os.platform() === 'win32';
7
7
  const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, SEVERITY_INFO, SEVERITY_WARNING, SEVERITY_ERROR } = require('./constants')
8
8
 
9
9
  const { find } = require('../util/fs')
10
- const { hasOptionValue, getProperty, relativePaths, BuildMessage, filterFeaturePaths } = require('./util')
10
+ const { hasOptionValue, relativePaths, BuildMessage, filterFeaturePaths } = require('./util')
11
11
 
12
12
  const DEBUG = cds.debug('cli|build')
13
13
 
@@ -286,9 +286,9 @@ class Plugin {
286
286
  // Returns the value of the given build option defined for this build task.
287
287
  _getBuildOption(qualifiedName) {
288
288
  // build task options overwriting other settings
289
- let value = getProperty(this.context.options, qualifiedName) // command line
289
+ let value = this.context.options[qualifiedName] // command line
290
290
  if (value === undefined) {
291
- value = getProperty(this.task.options, qualifiedName) // task options
291
+ value = this.task.options[qualifiedName] // task options
292
292
  }
293
293
  return value
294
294
  }
@@ -1,7 +1,7 @@
1
1
  const path = require('path')
2
2
  const cds = require('../../../cds')
3
3
  const EdmxBuildPlugin = require('../edmxBuildPlugin')
4
- const { getProperty, relativePaths } = require('../../util')
4
+ const { relativePaths } = require('../../util')
5
5
  const { OUTPUT_MODE, OUTPUT_MODE_RESULT, BUILD_TASK_FIORI, CDS_CONFIG_PATH_SEP, OUTPUT_MODE_FILESYSTEM } = require('../../constants')
6
6
  const DEBUG = cds.debug('cli|build')
7
7
 
@@ -105,14 +105,14 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
105
105
  return
106
106
  }
107
107
 
108
- const mainService = getProperty(manifest, ['sap.app', 'dataSources', 'mainService'])
108
+ const mainService = manifest?.['sap.app']?.dataSources?.mainService
109
109
  if (!mainService) {
110
110
  // no mainService defined - not supported
111
111
  DEBUG?.(`UI module does not have a datasource [mainService], [${relativePaths(cds.root, manifestPath)}], skipping build`)
112
112
  return
113
113
  }
114
114
 
115
- const localUri = getProperty(mainService, ['settings', 'localUri'])
115
+ const localUri = mainService?.settings?.localUri
116
116
  const uri = mainService.uri
117
117
 
118
118
  if (!localUri || !uri) {
package/lib/build/util.js CHANGED
@@ -21,32 +21,6 @@ const FLATTEN_MAX_DEPTH = 20 // should suffice, was infinite in earlier versions
21
21
  /** @typedef {object[] | object} Credentials */
22
22
  /** @typedef {(string | NestedStringArray)[]} NestedStringArray */
23
23
 
24
- /**
25
- * @param {object} src - object to get property from
26
- * @param {string | string[]} segments - property path
27
- */
28
- function getProperty(src, segments) {
29
- segments = Array.isArray(segments) ? segments : segments.split('.')
30
- return segments.reduce((p, n) => p && p[n], src)
31
- }
32
-
33
- /**
34
- * @param {object} src - object to set property on
35
- * @param {string | string[]} segments - property path
36
- * @param {unknown} value - value to set
37
- */
38
- function setProperty(src, segments, value) {
39
- segments = Array.isArray(segments) ? segments : segments.split('.')
40
- segments.reduce((p, n, idx) => {
41
- if (segments.length === idx + 1) {
42
- p[n] = value
43
- } else if (p[n] === undefined) {
44
- p[n] = {}
45
- }
46
- return p[n]
47
- }, src)
48
- }
49
-
50
24
  /**
51
25
  * Returns whether this project is a java project or not.
52
26
  */
@@ -510,8 +484,6 @@ class BuildError extends Error {
510
484
  }
511
485
 
512
486
  module.exports = {
513
- getProperty,
514
- setProperty,
515
487
  hasJavaNature,
516
488
  hasOptionValue,
517
489
  relativePaths,
@@ -5,7 +5,7 @@ module.exports = {
5
5
  COMMAND_ADD: 'add',
6
6
 
7
7
  JAVA_LTS_VERSIONS: [17, 21],
8
- MAVEN_ARCHETYPE_VERSION: '4.6.2',
8
+ MAVEN_ARCHETYPE_VERSION: '4.7.0',
9
9
 
10
10
  OPTIONS: Object.freeze({
11
11
  COMPLETION: 'completion',
package/lib/init/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  const { readdirSync } = require('node:fs')
3
3
  const { basename, join, relative, resolve } = require('node:path')
4
- const { OPTIONS, COMMAND_INIT } = require('./constants'), { JAVA } = OPTIONS
4
+ const { OPTIONS, COMMAND_INIT } = require('./constants'), { JAVA, COMPLETION } = OPTIONS
5
5
  const validate = require('./validate')
6
6
  const cmd = require('../util/command')
7
7
 
@@ -91,7 +91,7 @@ module.exports = class CDSGenerator {
91
91
  command: COMMAND_INIT,
92
92
  // keep caller independent from internal names
93
93
  options: {
94
- cwd: options.cwd,
94
+ ...options,
95
95
  add: new Set(options.add)
96
96
  },
97
97
  argv:[]
@@ -143,8 +143,9 @@ module.exports = class CDSGenerator {
143
143
  const cmds = Object.values(OPTIONS)
144
144
  const byPriority = (a, b) => cmds.indexOf(a) - cmds.indexOf(b)
145
145
  const sorted = Array.from(plugins).sort(byPriority)
146
+ const skipLogFacets = ['initial', COMPLETION]
146
147
  for (const [i, facet] of Object.entries(sorted)) {
147
- if (!cds.cli.options.dry && facet !== 'initial')
148
+ if (!cds.cli.options.dry && !skipLogFacets.includes(facet))
148
149
  console.log(`Adding facet: ${BOLD + facet + RESET}`)
149
150
  const template = this.templateList[i]
150
151
  await template.run()
@@ -243,7 +244,7 @@ module.exports = class CDSGenerator {
243
244
  _alias('kibana', 'application-logging')
244
245
  _alias('kibana-logging', 'application-logging')
245
246
 
246
- const runtimeAgnostic = { initial:1, 'tiny-sample':1, data:1 }
247
+ const runtimeAgnostic = { initial:1, 'tiny-sample':1, data:1, completion: 1 }
247
248
  if (!(plugin in runtimeAgnostic)) {
248
249
  const creating = ['java', 'nodejs', 'typescript', 'esm', 'extension']
249
250
  const { command, options, argv } = cds.cli
@@ -324,6 +325,10 @@ module.exports = class CDSGenerator {
324
325
 
325
326
  if (cds.cli.command === COMMAND_INIT && !options.add.has(JAVA)) {
326
327
  options.add.add('initial')
328
+
329
+ // cds10: remove
330
+ const { isBas } = require('./projectReader').readProject()
331
+ if (isBas) options.add.add('nodejs')
327
332
  }
328
333
  }
329
334
  }
@@ -331,4 +331,5 @@ function _normalizeSpringBootCfg(obj) {
331
331
  * @property {String} githubSlug GitHub org/repo.
332
332
  * @property {boolean} isMonorepoMicroservice Indicates if the project is a monorepo microservice.
333
333
  * @property {String} npmWorkspaceRoot The root path of the monorepo workspace.
334
+ * @property {String} isBas Indicates if the project is running in Business Application Studio (BAS).
334
335
  */
@@ -90,7 +90,7 @@ module.exports = new class CompletionSetup {
90
90
  profileFile = '.config/fish/config.fish';
91
91
  break;
92
92
  default:
93
- throw `Completion is only supported for ${SUPPORTED_LINUX_SHELLS.join(', ')}.`;
93
+ throw `Current shell is '${shell}'. Completion is only supported for ${SUPPORTED_LINUX_SHELLS.join(', ')}.`;
94
94
  }
95
95
 
96
96
  profileFile = path.join(os.homedir(), profileFile);
@@ -28,7 +28,10 @@ module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) =>
28
28
  if (value === undefined)
29
29
  continue
30
30
  if (element._type === 'cds.Composition') {
31
- data[element.target] = value // Add object for a new entity. Next pass will process it.
31
+ const t = element.target
32
+ if (data[t] === undefined) {
33
+ data[t] = value // Add object for a new entity. Next pass will process it.
34
+ }
32
35
  }
33
36
  else if (element._type === 'cds.Association') {
34
37
  if (element.on) {
@@ -37,8 +37,8 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
37
37
  const project = readProject()
38
38
  const {
39
39
  isJava, srvPath, appPath, apps,
40
- hasApprouter, addApprouter, addContainerize, addKyma, addHelm, addHelmUnifiedRuntime, addMultitenancy, addWorkzoneStandard, addXsuaa,
41
- addSample, hasMta, addMta, hasXsuaa, hasMultitenancy, hasUI5
40
+ hasApprouter, hasMta, addMta, hasKyma, hasXsuaa, hasMultitenancy, hasUI5,
41
+ addSample, addApprouter, addContainerize, addKyma, addHelm, addHelmUnifiedRuntime, addMultitenancy, addWorkzoneStandard, addXsuaa, addIas
42
42
  } = project
43
43
 
44
44
  await Promise.all(apps.map(async ({ app }) => {
@@ -65,7 +65,8 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
65
65
  await merge({ cds: { requires: { 'html5-repo': true } } }).into('mtx/sidecar/package.json')
66
66
  }
67
67
 
68
- if (addMta || (addXsuaa || addApprouter || addWorkzoneStandard || addMultitenancy || addSample) && hasMta) {
68
+ const affected = addXsuaa || addApprouter || addWorkzoneStandard || addMultitenancy || addSample || addIas
69
+ if (addMta || affected && hasMta) {
69
70
  const srv = srv4(srvPath)
70
71
  project.apps = apps
71
72
  const relationships = [{
@@ -109,7 +110,7 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
109
110
  })
110
111
  }
111
112
 
112
- // cds10
113
+ // cds10: change to if (addKyma)
113
114
  // needed because of adding kyma to cli options in case of helm
114
115
  if (addContainerize || (addKyma && !addHelm && !addHelmUnifiedRuntime)) {
115
116
  const additions = [{
@@ -119,7 +120,7 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
119
120
  await merge(__dirname, '/files/containerize.yaml.hbs').into('containerize.yaml', { with: project, additions })
120
121
  }
121
122
 
122
- if (addKyma) {
123
+ if (addKyma || affected && hasKyma) {
123
124
  await renderAndCopy(join(__dirname, 'files/html5-deployer.package.json.hbs'), 'app/html5-deployer/package.json', project)
124
125
  await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project })
125
126
  }
@@ -83,7 +83,7 @@ module.exports = class XsuaaTemplate extends require('../../plugin') {
83
83
  await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { project, additions, overwrites, relationships })
84
84
  }
85
85
 
86
- if (addKyma || (addMultitenancy && hasKyma)) {
86
+ if (addKyma || addMultitenancy && hasKyma) {
87
87
  const overwrites = addMultitenancy ? [{ item: 'xsuaa.parameters.tenant-mode', withValue: 'shared' }] : []
88
88
  await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project, overwrites })
89
89
  await merge({
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "9.7.0",
3
+ "version": "9.7.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sap/cds-dk",
9
- "version": "9.7.0",
9
+ "version": "9.7.1",
10
10
  "license": "SEE LICENSE IN LICENSE",
11
11
  "dependencies": {
12
12
  "@cap-js/asyncapi": "^1.0.0",
@@ -41,8 +41,8 @@
41
41
  }
42
42
  },
43
43
  "node_modules/@cap-js/db-service": {
44
- "version": "2.8.1",
45
- "integrity": "sha512-p2MHv97d+yiUBJYSAI/qusZzdEtOVfv6GZH51mkfxNXLeOGpV1wjr6UhLDmZrt6h7gTfqJA6cR1WUrrVOq38Ag==",
44
+ "version": "2.8.2",
45
+ "integrity": "sha512-5BUWnoRX7LQBEWvEZmq0urEkxWPIIUnV9v2uFYop19W10jtmK6bxKqk+oUGD/7o6C9GNiFcZoLpja7SFohfKOg==",
46
46
  "devOptional": true,
47
47
  "license": "Apache-2.0",
48
48
  "dependencies": {
@@ -64,12 +64,12 @@
64
64
  }
65
65
  },
66
66
  "node_modules/@cap-js/sqlite": {
67
- "version": "2.1.2",
68
- "integrity": "sha512-q8fQuIzwCfUF+l36BoL3LP32JYw389cmsZzE0Ec3JVz7k1sL+WzZ1XIbL1Ua/we3cHrDV+U3E9iAd0FOlcFumw==",
67
+ "version": "2.1.3",
68
+ "integrity": "sha512-JkIAR8khPEW0jgw440JrtOzsj+TacZmACJsifGnCWpgrC17f2q8r15pzrCnvvCmkLXTqUW1kRg5/B3nLbaO86Q==",
69
69
  "license": "Apache-2.0",
70
70
  "optional": true,
71
71
  "dependencies": {
72
- "@cap-js/db-service": "^2.8.1",
72
+ "@cap-js/db-service": "^2.8.2",
73
73
  "better-sqlite3": "^12.0.0"
74
74
  },
75
75
  "peerDependencies": {
@@ -116,8 +116,8 @@
116
116
  }
117
117
  },
118
118
  "node_modules/@sap/cds-compiler": {
119
- "version": "6.7.1",
120
- "integrity": "sha512-vfPhfLoT5sy73LBo8fGwYJ030tXY/ZY+1PSnVxLsghycg3/eMt06HrnI8Pt6vc7ia57x3/QGcHYXa+06SF3pZA==",
119
+ "version": "6.7.2",
120
+ "integrity": "sha512-5UpDA7boOmwtTBWjhEDbpXKgxjqz+0zObBr12P3g5D7QIMF+hPrPG+J0Bm2AQRPE/lv8VcnzFEaMdibRgmGtUw==",
121
121
  "license": "SEE LICENSE IN LICENSE",
122
122
  "bin": {
123
123
  "cdsc": "bin/cdsc.js",
@@ -935,8 +935,8 @@
935
935
  }
936
936
  },
937
937
  "node_modules/hdb": {
938
- "version": "2.26.4",
939
- "integrity": "sha512-v0uIr9mD9iw2Ws+H6+iLNO6W+uIqeXwt8Mwe1c0CZQOn1Sk631Uy4zgdz1wOz4IY3WgxdVjBAYWZ9AS8A/dLIQ==",
938
+ "version": "2.27.1",
939
+ "integrity": "sha512-xYL/W+fq2TyGHyzm8muolQnw8tdh4+2NQ8mQP2FpLSuhfJ8l0jQNSUZoAXic7NfMEan1Jvf8V1L4blwkgTc6+A==",
940
940
  "license": "Apache-2.0",
941
941
  "dependencies": {
942
942
  "iconv-lite": "0.7.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "9.7.0",
3
+ "version": "9.7.1",
4
4
  "description": "Command line client and development toolkit for the SAP Cloud Application Programming Model",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [