@sap/cds-dk 9.6.1 → 9.7.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.
- package/CHANGELOG.md +39 -0
- package/bin/add.js +5 -2
- package/bin/cds.js +10 -25
- package/bin/data-products/import.js +3 -0
- package/bin/debug.js +76 -16
- package/bin/env.js +2 -1
- package/bin/export.js +18 -13
- package/bin/help/export.md +2 -1
- package/bin/import.js +21 -18
- package/bin/init.js +8 -1
- package/bin/minify.js +11 -12
- package/bin/mock.js +17 -9
- package/bin/repl.js +2 -2
- package/bin/up.js +34 -4
- package/bin/version.js +202 -131
- package/lib/build/buildTaskEngine.js +4 -0
- package/lib/build/buildTaskFactory.js +5 -35
- package/lib/build/index.js +10 -10
- package/lib/build/plugin.js +6 -3
- package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +3 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/_helpers.tpl +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/job.yaml +8 -0
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.schema.json +18 -0
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +11 -1
- package/lib/build/plugins.js +8 -16
- package/lib/build/provider/hana/index.js +16 -19
- package/lib/build/provider/internalBuildPlugin.js +5 -4
- package/lib/build/provider/internalBuildTaskProvider.js +26 -88
- package/lib/build/provider/mtx/index.js +0 -8
- package/lib/build/provider/mtx-sidecar/index.js +88 -80
- package/lib/build/provider/nodejs/index.js +3 -8
- package/lib/build/util.js +52 -87
- package/lib/deploy/to-hana/hana.js +117 -109
- package/lib/env/schemas/cds-rc.js +0 -4
- package/lib/import/odata/v4parser.js +80 -56
- package/lib/init/constants.js +5 -2
- package/lib/init/index.js +42 -40
- package/lib/init/merge.js +7 -2
- package/lib/init/projectReader.js +2 -8
- package/lib/init/template/ams/index.js +1 -4
- package/lib/init/template/attachments/files/package.json.hbs +1 -1
- package/lib/init/template/data/index.js +1 -1
- package/lib/init/template/extension/index.js +4 -4
- package/lib/init/template/hana/files/package.json.hbs +3 -3
- package/lib/init/template/handler/index.js +1 -1
- package/lib/init/template/helm/index.js +3 -3
- package/lib/init/template/helm-unified-runtime/index.js +5 -1
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +1 -1
- package/lib/init/template/ias/files/mta.yaml.hbs +3 -3
- package/lib/init/template/initial/files/.vscode/tasks.json +10 -0
- package/lib/init/template/{nodejs/files/README.md → initial/files/readme.md} +2 -3
- package/lib/init/template/initial/index.js +15 -0
- package/lib/init/template/java/index.js +4 -11
- package/lib/init/template/kyma/index.js +21 -20
- package/lib/init/template/lint/index.js +3 -1
- package/lib/init/template/mta/index.js +0 -5
- package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +1 -2
- package/lib/init/template/multitenancy/files/values.yaml.hbs +30 -0
- package/lib/init/template/nodejs/files/.vscode/tasks.json +1 -14
- package/lib/init/template/nodejs/files/package.json.hbs +2 -4
- package/lib/init/template/nodejs/index.js +8 -12
- package/lib/init/template/sample/index.js +5 -6
- package/lib/init/template/sqlite/files/package.json.hbs +7 -1
- package/lib/init/template/test/index.js +1 -1
- package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +6 -0
- package/lib/init/template/tiny-sample/files/nodejs/srv/cat-service.cds +5 -0
- package/lib/init/template/tiny-sample/index.js +2 -2
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +6 -0
- package/lib/init/template/workzone-standard/index.js +13 -3
- package/lib/init/validate.js +11 -6
- package/lib/util/checksum.js +2 -2
- package/lib/util/fs.js +109 -53
- package/lib/util/glob.js +2 -1
- package/lib/util/term.js +1 -7
- package/lib/util/write.js +2 -4
- package/lib/watch/watched.js +1 -1
- package/npm-shrinkwrap.json +226 -259
- package/package.json +2 -2
- package/lib/init/template/nodejs/files/.vscode/settings.json +0 -11
- package/lib/init/template/tiny-sample/files/nodejs/db/data/my.bookshop-Books.csv +0 -3
- package/lib/init/template/tiny-sample/files/nodejs/db/schema.cds +0 -7
- package/lib/init/template/tiny-sample/files/nodejs/srv/cat-service.cds.hbs +0 -5
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,40 @@ 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.0 - 2026-02-02
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `cds debug` is now supported for Kubernetes/Kyma deployments.
|
|
14
|
+
- `cds init --nodejs` as a shortcut for `cds init --add nodejs`.
|
|
15
|
+
- Support for express 5 (in addition to express 4).
|
|
16
|
+
- `cds deploy --to hana` now supports `--out` to specify the output directory for generated files.
|
|
17
|
+
- `cds mock <service>` as a shortcut for `cds serve --mocked --project <service> --in-memory? --port 0`.
|
|
18
|
+
- `cds add ias` adds a URL for local approuter testing to `redirect-uris` if approuter is configured.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- `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.
|
|
23
|
+
- `cds deploy --to k8s` increased the timeout to wait for the HDI container creation from 120 to 180 seconds.
|
|
24
|
+
- `cds add` facets now abort when executed in a folder that is neither a Node.js nor a Java project.
|
|
25
|
+
- `cds add lint` now also adds the .java extension to the files that are linted within VSCode.
|
|
26
|
+
- `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 `-`.
|
|
27
|
+
- `cds import` now generates an on condition for associations if the navigation property in an imported OData v4 service has a referential constraint.
|
|
28
|
+
- `cds build` does not ignore wildcarded folders like `app/*` any more.
|
|
29
|
+
- `cds env --resolve-bindings/-b` also considers local service bindings.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- `cds add sqlite --for production` adds `@cap-js/sqlite` to `dependencies`.
|
|
34
|
+
- `cds build --ws` fixes a race condition.
|
|
35
|
+
- `cds build` now places the `i18n` folder in the generated output in nested locations.
|
|
36
|
+
- `cds build --for mtx-sidecar` loads CAP plugins from the MTX sidecar instead of the main app for generating the sidecar CSN.
|
|
37
|
+
- `cds add ias` uses a matching `IASDependencyName` for the application content deployer.
|
|
38
|
+
- `cds add ias` uses a more generic `redirect-uris` pattern.
|
|
39
|
+
- `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.
|
|
40
|
+
- `cds add multitenancy` for Java correctly creates a `package-lock.json` in _mtx/sidecar_.
|
|
41
|
+
- `cds add xsuaa` works properly when executed after `cds add workzone`.
|
|
42
|
+
|
|
9
43
|
## Version 9.6.1 - 2026-01-09
|
|
10
44
|
|
|
11
45
|
### Changed
|
|
@@ -415,6 +449,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
415
449
|
- `cds add ams` for Java adds a custom builder to the `mta.yaml` to circumvent the missing `srv/src/gen/policies`.
|
|
416
450
|
- `cds add multitenancy` requires the `srv-api` instead of the `mtx-api` for Java projects.
|
|
417
451
|
|
|
452
|
+
## Version 8.9.13 - 2029-01-09
|
|
453
|
+
|
|
454
|
+
### Fixed
|
|
455
|
+
|
|
456
|
+
- CVE-2025-15284: update `express` to fix vulnerability with `qs` <6.14.1
|
|
418
457
|
|
|
419
458
|
## Version 8.9.12 - 2025-12-16
|
|
420
459
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
//
|
|
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
|
|
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
|
|
177
|
-
cds.requires = cds.env.requires
|
|
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
|
|
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 (
|
|
233
|
-
|
|
234
|
-
|
|
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 */
|
package/bin/debug.js
CHANGED
|
@@ -1,53 +1,67 @@
|
|
|
1
1
|
module.exports = Object.assign(debug, {
|
|
2
|
-
options: ['--port', '--host', '--
|
|
3
|
-
shortcuts: ['-p', '-h', '-f'],
|
|
4
|
-
flags: [
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
29
|
+
The debug host (default: '127.0.0.1').
|
|
27
30
|
|
|
28
31
|
*-p* | *--port*
|
|
29
32
|
|
|
30
|
-
|
|
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
|
-
|
|
45
|
+
Don't open developer tools automatically (Node.js only).
|
|
35
46
|
|
|
36
47
|
*-f* | *--force*
|
|
37
48
|
|
|
38
|
-
|
|
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 (
|
|
75
|
-
|
|
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
|
|
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
|
-
|
|
26
|
-
texts:
|
|
27
|
-
data:
|
|
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
|
|
112
|
-
if (this.options.to === '-') return super.
|
|
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
|
|
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)
|
|
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
|
|
package/bin/help/export.md
CHANGED
|
@@ -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'
|
|
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
|
|
100
|
-
cds import ~/Downloads/API_BUSINESS_PARTNER.edmx --
|
|
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
|
|
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
|
-
|
|
38
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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', '
|
|
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', '
|
|
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')
|