@sap/cds-dk 9.6.1 → 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.
Files changed (87) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/bin/add.js +5 -2
  3. package/bin/cds.js +10 -25
  4. package/bin/data-products/import.js +3 -0
  5. package/bin/debug.js +76 -16
  6. package/bin/env.js +2 -1
  7. package/bin/export.js +18 -13
  8. package/bin/help/export.md +2 -1
  9. package/bin/import.js +21 -18
  10. package/bin/init.js +8 -1
  11. package/bin/minify.js +11 -12
  12. package/bin/mock.js +17 -9
  13. package/bin/repl.js +2 -2
  14. package/bin/up.js +34 -4
  15. package/bin/version.js +203 -131
  16. package/lib/build/buildTaskEngine.js +4 -0
  17. package/lib/build/buildTaskFactory.js +6 -36
  18. package/lib/build/index.js +10 -10
  19. package/lib/build/plugin.js +8 -5
  20. package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +3 -1
  21. package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/_helpers.tpl +1 -1
  22. package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/job.yaml +8 -0
  23. package/lib/build/plugins/helm/files/subcharts/content-deployment/values.schema.json +18 -0
  24. package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +11 -1
  25. package/lib/build/plugins.js +8 -16
  26. package/lib/build/provider/fiori/index.js +3 -3
  27. package/lib/build/provider/hana/index.js +16 -19
  28. package/lib/build/provider/internalBuildPlugin.js +5 -4
  29. package/lib/build/provider/internalBuildTaskProvider.js +26 -88
  30. package/lib/build/provider/mtx/index.js +0 -8
  31. package/lib/build/provider/mtx-sidecar/index.js +88 -80
  32. package/lib/build/provider/nodejs/index.js +3 -8
  33. package/lib/build/util.js +52 -115
  34. package/lib/deploy/to-hana/hana.js +117 -109
  35. package/lib/env/schemas/cds-rc.js +0 -4
  36. package/lib/import/odata/v4parser.js +80 -56
  37. package/lib/init/constants.js +5 -2
  38. package/lib/init/index.js +48 -41
  39. package/lib/init/merge.js +7 -2
  40. package/lib/init/projectReader.js +3 -8
  41. package/lib/init/template/ams/index.js +1 -4
  42. package/lib/init/template/attachments/files/package.json.hbs +1 -1
  43. package/lib/init/template/completion/completionSetup.js +1 -1
  44. package/lib/init/template/data/as-csv.js +4 -1
  45. package/lib/init/template/data/index.js +1 -1
  46. package/lib/init/template/extension/index.js +4 -4
  47. package/lib/init/template/hana/files/package.json.hbs +3 -3
  48. package/lib/init/template/handler/index.js +1 -1
  49. package/lib/init/template/helm/index.js +3 -3
  50. package/lib/init/template/helm-unified-runtime/index.js +5 -1
  51. package/lib/init/template/html5-repo/files/mta.yaml.hbs +1 -1
  52. package/lib/init/template/html5-repo/index.js +6 -5
  53. package/lib/init/template/ias/files/mta.yaml.hbs +3 -3
  54. package/lib/init/template/initial/files/.vscode/tasks.json +10 -0
  55. package/lib/init/template/{nodejs/files/README.md → initial/files/readme.md} +2 -3
  56. package/lib/init/template/initial/index.js +15 -0
  57. package/lib/init/template/java/index.js +4 -11
  58. package/lib/init/template/kyma/index.js +21 -20
  59. package/lib/init/template/lint/index.js +3 -1
  60. package/lib/init/template/mta/index.js +0 -5
  61. package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +1 -2
  62. package/lib/init/template/multitenancy/files/values.yaml.hbs +30 -0
  63. package/lib/init/template/nodejs/files/.vscode/tasks.json +1 -14
  64. package/lib/init/template/nodejs/files/package.json.hbs +2 -4
  65. package/lib/init/template/nodejs/index.js +8 -12
  66. package/lib/init/template/sample/index.js +5 -6
  67. package/lib/init/template/sqlite/files/package.json.hbs +7 -1
  68. package/lib/init/template/test/index.js +1 -1
  69. package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +6 -0
  70. package/lib/init/template/tiny-sample/files/nodejs/srv/cat-service.cds +5 -0
  71. package/lib/init/template/tiny-sample/index.js +2 -2
  72. package/lib/init/template/workzone-standard/files/mta.yaml.hbs +6 -0
  73. package/lib/init/template/workzone-standard/index.js +13 -3
  74. package/lib/init/template/xsuaa/index.js +1 -1
  75. package/lib/init/validate.js +11 -6
  76. package/lib/util/checksum.js +2 -2
  77. package/lib/util/fs.js +109 -53
  78. package/lib/util/glob.js +2 -1
  79. package/lib/util/term.js +1 -7
  80. package/lib/util/write.js +2 -4
  81. package/lib/watch/watched.js +1 -1
  82. package/npm-shrinkwrap.json +233 -266
  83. package/package.json +2 -2
  84. package/lib/init/template/nodejs/files/.vscode/settings.json +0 -11
  85. package/lib/init/template/tiny-sample/files/nodejs/db/data/my.bookshop-Books.csv +0 -3
  86. package/lib/init/template/tiny-sample/files/nodejs/db/schema.cds +0 -7
  87. package/lib/init/template/tiny-sample/files/nodejs/srv/cat-service.cds.hbs +0 -5
package/CHANGELOG.md CHANGED
@@ -6,6 +6,51 @@ 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
+
20
+ ## Version 9.7.0 - 2026-02-02
21
+
22
+ ### Added
23
+
24
+ - `cds debug` is now supported for Kubernetes/Kyma deployments.
25
+ - `cds init --nodejs` as a shortcut for `cds init --add nodejs`.
26
+ - Support for express 5 (in addition to express 4).
27
+ - `cds deploy --to hana` now supports `--out` to specify the output directory for generated files.
28
+ - `cds mock <service>` as a shortcut for `cds serve --mocked --project <service> --in-memory? --port 0`.
29
+ - `cds add ias` adds a URL for local approuter testing to `redirect-uris` if approuter is configured.
30
+
31
+ ### Changed
32
+
33
+ - `cds version` received major enhancements: It's now fully based on the `npm ls` command and always prints a tabular output. Also some new flags were added; check `cds version --help` for details.
34
+ - `cds deploy --to k8s` increased the timeout to wait for the HDI container creation from 120 to 180 seconds.
35
+ - `cds add` facets now abort when executed in a folder that is neither a Node.js nor a Java project.
36
+ - `cds add lint` now also adds the .java extension to the files that are linted within VSCode.
37
+ - `cds init` now restricts project names to 64 characters maximum, requiring them to start with an alphanumeric character or `_`, and contain only alphanumeric characters, `_`, and `-`.
38
+ - `cds import` now generates an on condition for associations if the navigation property in an imported OData v4 service has a referential constraint.
39
+ - `cds build` does not ignore wildcarded folders like `app/*` any more.
40
+ - `cds env --resolve-bindings/-b` also considers local service bindings.
41
+
42
+ ### Fixed
43
+
44
+ - `cds add sqlite --for production` adds `@cap-js/sqlite` to `dependencies`.
45
+ - `cds build --ws` fixes a race condition.
46
+ - `cds build` now places the `i18n` folder in the generated output in nested locations.
47
+ - `cds build --for mtx-sidecar` loads CAP plugins from the MTX sidecar instead of the main app for generating the sidecar CSN.
48
+ - `cds add ias` uses a matching `IASDependencyName` for the application content deployer.
49
+ - `cds add ias` uses a more generic `redirect-uris` pattern.
50
+ - `cds import` no longer generates a managed association for navigation properties of imported OData v4 services if the foreign key, the managed association would generate, already exists.
51
+ - `cds add multitenancy` for Java correctly creates a `package-lock.json` in _mtx/sidecar_.
52
+ - `cds add xsuaa` works properly when executed after `cds add workzone`.
53
+
9
54
  ## Version 9.6.1 - 2026-01-09
10
55
 
11
56
  ### Changed
@@ -415,6 +460,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
415
460
  - `cds add ams` for Java adds a custom builder to the `mta.yaml` to circumvent the missing `srv/src/gen/policies`.
416
461
  - `cds add multitenancy` requires the `srv-api` instead of the `mtx-api` for Java projects.
417
462
 
463
+ ## Version 8.9.13 - 2029-01-09
464
+
465
+ ### Fixed
466
+
467
+ - CVE-2025-15284: update `express` to fix vulnerability with `qs` <6.14.1
418
468
 
419
469
  ## Version 8.9.12 - 2025-12-16
420
470
 
package/bin/add.js CHANGED
@@ -48,9 +48,9 @@ ${cds.cli.command !== 'completion' && require('../lib/init').help({ exclude: ['j
48
48
 
49
49
  Overwrite all files in case the target files already exist.
50
50
 
51
- *--package* <name>
51
+ *--package | -p* <name>
52
52
 
53
- Pull a package from your npm registry.
53
+ Pull a package from your configured npm registry.
54
54
 
55
55
 
56
56
  # FEATURE OPTIONS
@@ -102,8 +102,11 @@ async function handleCompletion(currentWord, previousWord, argv, util) {
102
102
  }
103
103
 
104
104
  async function add(args) {
105
+ const cds = require('../lib/cds')
106
+ if (!cds.cli.options.dry) console.log()
105
107
  const CDSGenerator = require('../lib/init')
106
108
  const generator = new CDSGenerator()
107
109
  const features = args.map(f => f.split(/[,\s]/)).flat()
108
110
  await generator.add(features)
111
+ if (!cds.cli.options.dry) console.log()
109
112
  }
package/bin/cds.js CHANGED
@@ -41,20 +41,14 @@ const cli = {
41
41
  DEBUG?.(`[cds] - @sap/cds ${cds.version} loaded: ${cds.home}`)
42
42
 
43
43
  try {
44
- const allCmds = getCommands();
45
-
46
- //TODO: make better; only POC for cds help
47
- Object.assign(module.exports, { cmds: allCmds })
48
-
49
- // const { handleCompletion } = require('./util/completion');
50
- // await handleCompletion(process.argv, allCmds, this);
44
+ Object.assign(module.exports, { cmds: getCommands() })
51
45
 
52
46
  const task = this.load(cmd, /*else*/(f) => argv.unshift(cmd) && (cmd = 'compile') && _isDefaultCompile(argv, f))
53
47
  if (task) {
54
48
 
55
49
  if (task._is_new_cmd) return await task.exec (this)
56
50
 
57
- // REVISIT bind: '--' handling for cds bind --exec. Should be moved to cds_cli
51
+ // '--' handling for cds bind --exec
58
52
  const endOfOptions = argv.indexOf('--')
59
53
  let appendArgs = []
60
54
  if (endOfOptions >= 0) {
@@ -62,7 +56,7 @@ const cli = {
62
56
  argv = argv.slice(0, endOfOptions)
63
57
  }
64
58
 
65
- // REVISIT: Have to load plugins to allow for plugin-contributed flags!
59
+ // Have to load plugins to allow for cds add plugin-contributed flags!
66
60
  if (cmd === 'add') {
67
61
  cds.cli = { command: 'add' }
68
62
  if (argv.includes('-p') || argv.includes('--package')) {
@@ -118,7 +112,6 @@ const cli = {
118
112
  || _dieForUnknownCommand (cmd)
119
113
  },
120
114
 
121
- // TODO replace w/ common arg parser from node
122
115
  args (task, argv) {
123
116
 
124
117
  const { options:o=[], flags:f=[], shortcuts:s=[] } = task
@@ -151,15 +144,13 @@ const cli = {
151
144
  }
152
145
 
153
146
  // always use 'plain' log format for cds-dk logging
154
- // by default 'plain' log format is used for development while 'json' format is used for production, see cap/cds/blob/main/lib/env/defaults.js#L97
147
+ // by default 'plain' log format is used for development while 'json' format is used for production
155
148
  // the json formatter logs stringified JSON which causing any line breaks to get replaced by '\n'
156
149
  // using the env variable ensures that cds.env isn't loaded too early
157
150
  env ??= {}
158
151
  env.log ??= {}
159
152
  env.log.format = 'plain'
160
153
 
161
- // if (env) require('../lib/cds').env.add (env) //> avoid loading env
162
- // unless it has already explicitly been set by the user
163
154
  if (env) process.env.CDS_CONFIG ??= JSON.stringify(env)
164
155
  return [ args, options ]
165
156
  },
@@ -173,8 +164,8 @@ async function _resolveBindings(options) {
173
164
  const cds = require('../lib/cds')
174
165
  const { env: bindingEnv } = require('../lib/bind/shared')
175
166
  Object.assign(process.env, await bindingEnv(options))
176
- cds.env = cds.env.for('cds') // reload env // FIXME: This is too early!
177
- cds.requires = cds.env.requires // REVISIT: We should clean this up!
167
+ cds.env = cds.env.for('cds') // reload env
168
+ cds.requires = cds.env.requires
178
169
  }
179
170
 
180
171
  function _isDefaultCompile (argv, _force) {
@@ -221,18 +212,14 @@ function _dieForUnknownCommand(cmd) {
221
212
  }
222
213
 
223
214
  function getCommands() {
224
- const fs = require('node:fs');
225
- const path = require('node:path');
226
-
227
- const excludeList = ['cds.js', 'cds-ts.js', 'fix-redirects.js'];
215
+ const excludeList = new Set(['cds.js', 'cds-ts.js', 'fix-redirects.js']);
228
216
 
229
217
  const files = fs.readdirSync(__dirname, { withFileTypes: true, encoding: 'utf8' })
230
218
  const result = new Set()
231
219
  for (const f of files) {
232
- if (!excludeList.includes(f.name)) {
233
- if (f.isDirectory() && fs.existsSync(path.join(__dirname, f.name, 'index.js')) || f.isFile() && f.name.endsWith('.js')) {
234
- result.add(path.parse(f.name).name)
235
- }
220
+ if (excludeList.has(f.name)) continue;
221
+ if ((f.isDirectory() && fs.existsSync(path.join(__dirname, f.name, 'index.js'))) || (f.isFile() && f.name.endsWith('.js'))) {
222
+ result.add(path.parse(f.name).name)
236
223
  }
237
224
  }
238
225
  return Array.from(result).sort()
@@ -277,5 +264,3 @@ function _prepareTsIfNeeded(cds) {
277
264
  }
278
265
 
279
266
  }
280
-
281
- /* eslint no-console:off */
@@ -97,6 +97,9 @@ class Import extends Export {
97
97
  }
98
98
  }
99
99
  }
100
+ }, {
101
+ // we want to use the plugin option by default for data products
102
+ ...o, plugin: o.plugin !== false && o.plugin !== 'false'
100
103
  })
101
104
 
102
105
  return this.update_package_json();
package/bin/debug.js CHANGED
@@ -1,53 +1,67 @@
1
1
  module.exports = Object.assign(debug, {
2
- options: ['--port', '--host', '--force', '--no-devtools'],
3
- shortcuts: ['-p', '-h', '-f'],
4
- flags: [/*'--vscode', '--k8s'*/],
2
+ options: ['--port', '--host', '--no-devtools'],
3
+ shortcuts: ['-p', '-h', undefined, '-f'],
4
+ flags: ['--force', '--k8s', '--cf'],
5
5
  help: `
6
6
  # SYNOPSIS
7
7
 
8
8
  *cds debug* [<app>]
9
9
 
10
- Debug applications running locally or remotely on Cloud Foundry.
11
- Local applications will be started in debug mode, while remote applications
12
- are put into debug mode.
10
+ Debug applications running locally or remotely on Cloud Foundry or Kubernetes.
13
11
 
14
- If <app> is given, it's assumed to be running on the currently logged-in
15
- Cloud Foundry space (check with 'cf target').
16
- SSH access to the app is required (check with 'cf ssh-enabled').
17
- Chrome DevTools are opened automatically for Node.js applications.
12
+ If <app> is given, it's assumed to be running on a remote system. The command defaults
13
+ to Kubernetes if Helm deployment descriptors are present, otherwise Cloud Foundry.
14
+
15
+ For Cloud Foundry, the currently targeted space is used (check with 'cf target').
16
+ For Kubernetes, the current context and namespace are used (check with 'kubectl config get-contexts').
17
+
18
+ SSH access to the app is required (check with 'cf ssh-enabled' on Cloud Foundry).
18
19
 
19
20
  If no <app> is given, the app in the current working directory is started
20
21
  (with 'cds watch --debug' for Node.js and 'mvn spring-boot:run' for Java).
21
22
 
23
+ For Node.js, Chrome DevTools are opened automatically unless *--no-devtools* is set.
24
+
22
25
  # OPTIONS
23
26
 
24
27
  *-h* | *--host*
25
28
 
26
- the debug host (default: '127.0.0.1')
29
+ The debug host (default: '127.0.0.1').
27
30
 
28
31
  *-p* | *--port*
29
32
 
30
- the debug port (default: '9229' for Node.js, '8000' for Java)
33
+ The debug port (default: '9229' for Node.js, '8000' for Java).
34
+
35
+ *--cf*
36
+
37
+ Force Cloud Foundry mode.
38
+
39
+ *--k8s*
40
+
41
+ Force Kubernetes mode. Use env vars KUBE_NAMESPACE or NAMESPACE to select a namespace.
31
42
 
32
43
  *--no-devtools*
33
44
 
34
- don't open developer tools automatically
45
+ Don't open developer tools automatically (Node.js only).
35
46
 
36
47
  *-f* | *--force*
37
48
 
38
- if necessary, automatically enable ssh for the app and restart it
49
+ If necessary, automatically enable SSH for the app and restart it.
39
50
 
40
51
  # EXAMPLES
41
52
 
42
53
  *cds debug*
43
54
  *cds debug* bookshop-srv --port 8001
44
55
  *cds debug* bookshop-srv --host 0.0.0.0
56
+ *cds debug* --k8s bookshop-srv
45
57
  `})
46
58
 
47
59
  async function debug() {
48
60
  const { fork, spawn, execSync, exec } = require('node:child_process')
49
61
  const os = require('node:os').platform()
50
62
  const cds = require('../lib/cds')
63
+ const { BOLD, RESET } = cds.utils.colors
64
+ const { readProject } = require('../lib/init/projectReader')
51
65
  const DEBUG = /\b(y|all|debug)\b/.test(process.env.DEBUG) ? console.debug : undefined
52
66
 
53
67
  const [appName] = cds.cli.argv
@@ -56,6 +70,9 @@ async function debug() {
56
70
  const maxAttempts = 15
57
71
  let attempts = 0
58
72
 
73
+ const { hasKyma, hasMta } = readProject()
74
+ const onKyma = cds.cli.options.k8s || hasKyma && !hasMta && !cds.cli.options.cf
75
+
59
76
  if (!appName) { // local app
60
77
  if (cds.env['project-nature'] === 'java') {
61
78
  const portLocal = port || 8000
@@ -71,8 +88,50 @@ async function debug() {
71
88
  fork(script, ['watch', '--debug', hostport]).on('error', e => { throw 'Failed to start debug process:' + e.message })
72
89
  }
73
90
  }
74
- else if (cds.cli.options.k8s) { // Kyma/Kubernetes
75
- // to be implemented
91
+ else if (onKyma) { // Kyma/Kubernetes (Node.js only)
92
+ if (!appName) throw `pass a deployment name, for example 'cds debug --k8s bookshop-srv'`
93
+
94
+ const namespace = process.env.KUBE_NAMESPACE || process.env.NAMESPACE || '' // optional
95
+ const ns = namespace ? `-n ${namespace}` : ''
96
+ const portLocal = port || 9229
97
+ const k = (cmd, opts) => _execSync(`kubectl ${ns} ${cmd}`, opts)
98
+
99
+ // Ensure deployment exists
100
+ k(`get deploy ${appName}`, { stdio: 'inherit' })
101
+
102
+ if (force) {
103
+ console.log(`\nEnabling Node inspector on deployment/${appName} at 0.0.0.0:${portLocal} ...`)
104
+ _execSyncSafe(`kubectl ${ns} set env deployment/${appName} NODE_OPTIONS="--inspect=0.0.0.0:${portLocal}"`, { stdio: 'inherit' })
105
+ _execSyncSafe(`kubectl ${ns} rollout restart deployment/${appName}`, { stdio: 'inherit' })
106
+ k(`rollout status deployment/${appName} --timeout=180s`, { stdio: 'inherit' })
107
+ } else {
108
+ // Bail out early if inspector isn't already enabled
109
+ const nodeOpts = _execSyncSafe(`kubectl ${ns} get deploy ${appName} -o jsonpath="{.spec.template.spec.containers[0].env[?(@.name=='NODE_OPTIONS')].value}"`)
110
+ if (!nodeOpts || !/--inspect/.test(nodeOpts)) {
111
+ throw (
112
+ `Node inspector not enabled on deployment/${appName}.\n` +
113
+ `Run ${BOLD}cds debug ${appName} --force${RESET} to set NODE_OPTIONS="--inspect=0.0.0.0:${portLocal}" and restart.`
114
+ )
115
+ }
116
+ }
117
+
118
+ const podsJson = _execSync(`kubectl ${ns} get pods -o json`)
119
+ const items = JSON.parse(podsJson).items || []
120
+ const candidates = items.filter(i => (i.metadata?.name || '').startsWith(`${appName}-`))
121
+ if (!candidates.length) throw `no Pod for deployment/${appName} found (namespace: ${namespace || '<current>'}).`
122
+ candidates.sort((a, b) => new Date(a.metadata.creationTimestamp) - new Date(b.metadata.creationTimestamp))
123
+ const pod = `pod/${candidates[candidates.length - 1].metadata.name}`
124
+
125
+ console.log(`\nusing ${pod}`)
126
+
127
+ console.log(`\nopening port-forward: localhost:${portLocal} -> ${pod}:${portLocal}`)
128
+ const args = []
129
+ if (namespace) args.push('-n', namespace)
130
+ args.push('port-forward', pod, `${portLocal}:${portLocal}`)
131
+ spawn('kubectl', args, { stdio: 'inherit' })
132
+
133
+ if (!cds.cli.options['no-devtools']) openDevTools(portLocal)
134
+ printHints(portLocal)
76
135
  }
77
136
  else { // Cloud Foundry
78
137
  const [pid, kind] = processInfo(appName, force)
@@ -129,6 +188,7 @@ async function debug() {
129
188
  function processInfo(appName, force) {
130
189
  if (force !== false) {
131
190
  const enabled = _execSyncSafe(`cf ssh-enabled ${appName}`)
191
+ if (!enabled) throw `Make sure the application is visible in your targeted Cloud Foundry space.`
132
192
  if (enabled.match(/disabled/i)) {
133
193
  if (force) {
134
194
  console.log(`Trying to enable SSH for app '${appName}'...`)
package/bin/env.js CHANGED
@@ -66,7 +66,8 @@ async function env ([cmd, key, value], options={}) {
66
66
  // REVISIT: Currently only read in env.test.js
67
67
  env['_home_cds-dk'] = path.resolve(__dirname, '..') // to help tools find the DK
68
68
 
69
- if (!options.for && options.mocked) await cds.service.bindings
69
+ if (!options.for && options.mocked || options["resolve-bindings"])
70
+ await cds.service.bindings
70
71
  options.colors = cds.utils.colors.enabled === true
71
72
  return fn (env, key, value, options)
72
73
  }
package/bin/export.js CHANGED
@@ -14,6 +14,7 @@ class Export extends Minify {
14
14
  '@restrict': true,
15
15
  '@requires': true,
16
16
  '@cds.api.': true,
17
+ '@cds.on.': true,
17
18
  '@UI.': true,
18
19
  includes: true,
19
20
  ignored: true,
@@ -22,11 +23,12 @@ class Export extends Minify {
22
23
  views: true,
23
24
  },
24
25
  reuse: [ '@sap/cds/common' ],
25
- force: false,
26
- texts: true,
27
- data: true,
26
+ plugin: false,
27
+ texts: false,
28
+ data: false,
28
29
  as: 'csn',
29
30
  for: 'npm',
31
+ force: false,
30
32
  }
31
33
  static shortcuts = { ...super.shortcuts,
32
34
  to:'2',
@@ -38,7 +40,7 @@ class Export extends Minify {
38
40
  parseArgs (conf) {
39
41
  if (!process.stdout.isTTY) this.options.to = '-'
40
42
  let [sources,o] = super.parseArgs (conf)
41
- // -----------------------------------------------------------------------
43
+ // -----------------------------------------------------------------------
42
44
  // Java-specific adjustments -> shall this stay for GA?
43
45
  if (o.for === 'mvn' && !o.to.startsWith('./') && !o.to.startsWith('/'))
44
46
  o.to = './src/main/resources/cds/' + o.to
@@ -108,8 +110,8 @@ class Export extends Minify {
108
110
  return super.cleanse (csn,o)
109
111
  }
110
112
 
111
- async export (minified,o) {
112
- if (this.options.to === '-') return super.print (minified)
113
+ async output (minified,o) {
114
+ if (this.options.to === '-') return super.output (minified)
113
115
  if (this.options.to.endsWith('/*')) this.options.to = this.export_to()
114
116
  console.log(`\n${this.name}ing APIs to`, cds.utils.local(this.options.to), '...\n')
115
117
  const exports = []; exports.push(...this.export_models (minified))
@@ -117,6 +119,7 @@ class Export extends Minify {
117
119
  if (o.data) exports.push (this.export_data (minified))
118
120
  if (o.for === 'npm') exports.push (this.export_package_json())
119
121
  await Promise.all (exports)
122
+ console.log()
120
123
  }
121
124
 
122
125
  export_to() {
@@ -133,16 +136,19 @@ class Export extends Minify {
133
136
  }
134
137
 
135
138
  async export_package_json (pkg, o = this.options) {
136
- await this.write ('// just a tag file for plug & play') .to ('cds-plugin.js', false)
137
139
  if (!o.force && exists (path.join (this.options.to, 'package.json'))) return null
138
140
  if (!pkg) {
139
141
  let { name, version } = await read ('package.json')
140
- let requires = Object.fromEntries (Object.entries(this.min.definitions)
141
- .filter (([,d]) => d.kind === 'service')
142
- .map (([name]) => [ name, true ]))
143
142
  name += '-' + cds.utils.path.basename (this.options.to)
144
- pkg = { name, version, cds:{requires} }
143
+ pkg = { name, version }
144
+ if (o.plugin) {
145
+ let requires = Object.fromEntries (Object.entries(this.min.definitions)
146
+ .filter (([,d]) => d.kind === 'service')
147
+ .map (([name]) => [ name, true ]))
148
+ pkg.cds = {requires}
149
+ }
145
150
  }
151
+ if (o.plugin) await this.write ('// just a tag file for plug & play') .to ('cds-plugin.js', false)
146
152
  return this.write (pkg) .to ('package.json')
147
153
  }
148
154
 
@@ -202,7 +208,7 @@ class Export extends Minify {
202
208
  async function _export (e) {
203
209
  if (!e || e['@cds.persistence.skip']) return
204
210
  const file = path.join (out, `${e.name}.csv`)
205
- const columns = Object.keys(e.elements).filter(k => !e.elements[k]['@Core.Computed'])
211
+ const columns = Object.keys(e.elements) //.filter(k => !e.elements[k]['@Core.Computed'])
206
212
  const rows = await SELECT.from(e).columns(columns)
207
213
  let csv = fs.createWriteStream (file), i=0
208
214
  for (let r of await rows) {
@@ -230,7 +236,6 @@ class Export extends Minify {
230
236
  return write(x).to (file)
231
237
  }}}
232
238
 
233
- print = undefined // tells the base class to use this.export()
234
239
  }
235
240
 
236
241
 
@@ -9,12 +9,13 @@
9
9
  *-s | --services* <patterns>
10
10
  *-f | --from* <sources>
11
11
  *-2 | --to* <folder>
12
- *-4 | --for* <npm|mvn>
13
12
  *-a | --as* <csn|cdl>
13
+ *-4 | --for* <npm|mvn>
14
14
 
15
15
  *-c | --cleanse* <properties>
16
16
  *-k | --keep* <kinds>
17
17
  *-x | --skip* <kinds>
18
+ *-p | --plugin*
18
19
  *-d | --data*
19
20
  *-t | --texts*
20
21
 
package/bin/import.js CHANGED
@@ -1,6 +1,6 @@
1
1
  module.exports = Object.assign(_import, {
2
2
  _name: 'import',
3
- options: [ '--services', '--for', '--out', '--as', '--name', '--include-namespaces', '--dependencies', '--from', '--config', '--destination', '--group', '--into-namespace', '--data-product' ],
3
+ options: [ '--services', '--for', '--out', '--as', '--name', '--include-namespaces', '--dependencies', '--from', '--config', '--destination', '--group', '--into-namespace' ],
4
4
  shortcuts: [ '-s', '-4', '-o', '-as', '-n', '-ns', '-d',undefined, '-c', undefined, undefined, '-2', '-', '-f'],
5
5
  flags: [ '--dry', '--force', '--no-copy', '--no-save', '--keep-namespace', '--data-product', '--edmx', '--rfc', '--odata', '--openapi', '--asyncapi' ],
6
6
  help: `
@@ -20,6 +20,22 @@ module.exports = Object.assign(_import, {
20
20
 
21
21
  # OPTIONS
22
22
 
23
+ *--odata*
24
+ *--edmx*
25
+ *--openapi*
26
+ *--asyncapi*
27
+ *--rfc*
28
+ Imports the model from the one of the API formats OData EDMX, OpenAPI, AsyncAPI or RFC.
29
+
30
+ *--data-product*
31
+ Tells cds import to import a data product. The source must be a valid
32
+ data product CSN file, e.g. as found on http://api.sap.com/dataproducts.
33
+ (Not released with general availability yet)
34
+
35
+
36
+ *--dry*
37
+ Writes the converted csn to stdout only.
38
+
23
39
  *--no-copy*
24
40
  Skips copying to ./srv/external.
25
41
 
@@ -29,9 +45,6 @@ module.exports = Object.assign(_import, {
29
45
  *-o | --out* <filename/dirname>
30
46
  Skips copying to ./srv/external and writes to the specified location.
31
47
 
32
- *- | --dry*
33
- Writes the converted csn to stdout only.
34
-
35
48
  *-as | --as <output_file_format>*
36
49
  Converts the input file into one of these supported formats "cds", "csn"
37
50
  or "json".
@@ -40,10 +53,6 @@ module.exports = Object.assign(_import, {
40
53
  Forcefully overwrites the contents in the CDS file and updates the
41
54
  checksum
42
55
 
43
- *--from*
44
- Imports the model from the one of the given options "edmx", "openapi" or
45
- "asyncapi".
46
-
47
56
  *-c | --config* <JSON string | comma-separated key-value pairs>
48
57
  Adds the provided JSON or key-value pairs to the configuration.
49
58
 
@@ -55,11 +64,6 @@ module.exports = Object.assign(_import, {
55
64
  Destination name under which the remote service can be reached.
56
65
  Not supported by import types "edmx", "openapi" or "asyncapi".
57
66
 
58
- *--data-product*
59
- Tells cds import to import a data product. The source must be a valid
60
- data product CSN file, e.g. as found on http://api.sap.com/dataproducts.
61
- (Not released with general availability yet)
62
-
63
67
  *-2 | --into-namespace* <string>
64
68
  Specifies a custom namespace to be used for the imported service.
65
69
  This will override the namespace that was specified via the the
@@ -96,15 +100,14 @@ module.exports = Object.assign(_import, {
96
100
  # EXAMPLES
97
101
 
98
102
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx
99
- cds import - ~/Downloads/API_BUSINESS_PARTNER.edmx
100
- cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --from edmx --as cds
103
+ cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --dry
104
+ cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --as cds
101
105
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "sap,c4c"
102
106
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --include-namespaces "\x2A"
103
107
  cds import ~/Downloads/sap.graph.edmx -d ./sap.c4c.edmx,./sap.s4.edmx --as cds -o ./graph
104
108
  cds import ~/Downloads/Petstore_OpenAPI.json
105
- cds import ~/Downloads/Petstore_OpenAPI.json --from openapi
106
- cds import ~/Downloads/BookStore_AsyncAPI.json
107
- cds import ~/Downloads/BookStore_AsyncAPI.json --from asyncapi
109
+ cds import --openapi ~/Downloads/Petstore_OpenAPI.json
110
+ cds import --asyncapi ~/Downloads/BookStore_AsyncAPI.json
108
111
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx -c "{\\"[production]\\":{\\"credentials\\":{\\"destination\\":\\"UI3_noauth\\",\\"path\\":\\"/sap/cap/odata\\"}}}"
109
112
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --for sandbox -c "destination.properties.url=https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap"
110
113
  cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --for production -c "http.suffix=/sap/opu/odata/sap,http.csrf.enabled=true"
package/bin/init.js CHANGED
@@ -9,7 +9,7 @@ module.exports = Object.assign(init, {
9
9
  handleCompletion,
10
10
  options: ['--add', '--java:mvn', '--java:package', '--lint:custom', '--lint:custom:example', '--no-db', '--base'],
11
11
  shortcuts: ['-a'],
12
- flags: ['--java', '--force', '--verbose'],
12
+ flags: ['--nodejs', '--java', '--force', '--verbose'],
13
13
  help: `
14
14
  # SYNOPSIS
15
15
 
@@ -27,6 +27,10 @@ module.exports = Object.assign(init, {
27
27
 
28
28
  ${require('../lib/init').help()}
29
29
 
30
+ *--nodejs*
31
+
32
+ Create a CAP Node.js project.
33
+
30
34
  *--java*
31
35
 
32
36
  Create a CAP Java project.
@@ -44,6 +48,7 @@ ${require('../lib/init').help()}
44
48
  # EXAMPLES
45
49
 
46
50
  *cds init* bookshop
51
+ *cds init* bookshop --nodejs
47
52
  *cds init* bookshop --java
48
53
  *cds init* bookshop --add hana
49
54
  *cds init* bookshop --add multitenancy,mta
@@ -80,7 +85,9 @@ async function handleCompletion(currentWord, previousWord, argv, util) {
80
85
  }
81
86
 
82
87
  async function init(args) {
88
+ console.log()
83
89
  const CDSGenerator = require('../lib/init')
84
90
  const generator = new CDSGenerator()
85
91
  await generator.init(args[0])
92
+ console.log()
86
93
  }
package/bin/minify.js CHANGED
@@ -34,13 +34,11 @@ class Minify extends Command {
34
34
  async exec ( args, options ) {
35
35
  let [sources,o] = this.parseArgs ({ args, options })
36
36
  try {
37
- let csn = await this.load (sources,o); this.csn = csn
38
- let min = await this.minify (csn,o); this.min = min
37
+ this.csn = await this.load (sources,o)
38
+ this.min = await this.minify (this.csn,o)
39
39
  if (o.dry) return
40
- if (o.inspect) return this.inspect (min,o)
41
- if (this.print) return this.print (min)
42
- else await this.export (min,o)
43
- console.log()
40
+ if (o.inspect) return this.inspect (this.min,o)
41
+ else return this.output (this.min,o)
44
42
  } catch (e) {
45
43
  if (typeof e === 'string') return console.error (e)
46
44
  if (e.code) return console.error (e.message)
@@ -66,7 +64,7 @@ class Minify extends Command {
66
64
  * Subclasses override this method to provide custom minification behavior.
67
65
  */
68
66
  async minify (csn,o) {
69
- let m = this.minifier ??= o.dry ? new Dryifier(csn) : new Minifier()
67
+ let m = this.minifier ??= o.dry ? (new Dryifier).for(csn) : new Minifier
70
68
  csn = await this.cleanse (csn,o)
71
69
  return m.minify (csn,o)
72
70
  }
@@ -79,7 +77,7 @@ class Minify extends Command {
79
77
  /**
80
78
  * Subclasses override this method to provide custom print behavior.
81
79
  */
82
- print (csn,o) { // eslint-disable-line no-unused-vars
80
+ output (csn,o) { // eslint-disable-line no-unused-vars
83
81
  console.log (cds.compile.to.json (csn))
84
82
  }
85
83
 
@@ -95,12 +93,13 @@ class Minify extends Command {
95
93
  */
96
94
  class Dryifier extends Minifier {
97
95
 
98
- constructor(csn) { super(); this.all = Object.keys (csn.definitions) }
96
+ for (csn) { this.all = Object.keys (csn.definitions); return this }
99
97
  capture = {}
100
98
  level = 0
101
99
 
102
100
  keep (each,d) {
103
- if (each in this.kept) return; else this.capture[each] = ++this.level
101
+ if (each in this.kept) return
102
+ if (each in this.defs) this.capture[each] = ++this.level
104
103
  super.keep (each, d)
105
104
  this.level--
106
105
  }
@@ -109,10 +108,10 @@ class Dryifier extends Minifier {
109
108
  const { GREEN, GRAY, DIMMED, RESET } = cds.utils.colors
110
109
  const min = super.minify (csn, o)
111
110
  const kept = Object.keys(this.capture)
112
- console.log (RESET+'\n', 'Keep:', kept.length, '\n')
111
+ console.log (RESET+'\n', 'Kept:', kept.length, '\n')
113
112
  for (let [ each, level ] of Object.entries(this.capture))
114
113
  console.log (' '+GRAY,'•'.repeat(level)+GREEN, each, RESET)
115
- console.log (RESET+'\n', 'Skip:', this.all.length - kept.length, '\n')
114
+ console.log (RESET+'\n', 'Skipped:', this.all.length - kept.length, '\n')
116
115
  for (let each of this.all)
117
116
  each in this.capture || console.log (DIMMED, ' -', each, RESET)
118
117
  console.log (RESET+'\n', 'Total:', this.all.length, '\n')