@sap/cds-dk 8.0.3 → 8.1.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 +51 -1
- package/bin/bind.js +3 -3
- package/bin/cds.js +11 -15
- package/bin/init.js +3 -6
- package/bin/version.js +7 -6
- package/lib/build/buildTaskFactory.js +29 -12
- package/lib/build/constants.js +1 -1
- package/lib/build/provider/hana/index.js +5 -6
- package/lib/build/provider/internalBuildTaskProvider.js +2 -35
- package/lib/build/provider/mtx/resourcesTarBuilder.js +2 -2
- package/lib/build/provider/mtx-sidecar/index.js +10 -3
- package/lib/cds.js +1 -0
- package/lib/compile/to-mermaid.js +27 -12
- package/lib/compile/to_openapi.js +2 -1
- package/lib/deploy/to-hana/hana.js +10 -8
- package/lib/deploy/to-hana/hdiDeployUtil.js +10 -1
- package/lib/import/common.js +1 -1
- package/lib/import/message.js +2 -2
- package/lib/import/odata/v2parser.js +2 -2
- package/lib/init/bas.js +73 -32
- package/lib/init/constants.js +5 -2
- package/lib/init/index.js +6 -4
- package/lib/init/merge.js +5 -3
- package/lib/init/projectReader.js +3 -4
- package/lib/init/template/audit-logging/files/package.sidecar.json +7 -0
- package/lib/init/template/audit-logging/index.js +1 -1
- package/lib/init/template/cf-manifest/index.js +4 -0
- package/lib/init/template/data/as-json.js +22 -12
- package/lib/init/template/data/index.js +1 -1
- package/lib/init/template/helm-unified-runtime/index.js +3 -1
- package/lib/init/template/http/index.js +37 -28
- package/lib/init/template/multitenancy/index.js +9 -31
- package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +0 -1
- package/lib/init/template/sample/files/app/browse/webapp/manifest.json +0 -1
- package/lib/init/template/sample/files/nodejs/admin-service.js +13 -8
- package/lib/init/template/sample/files/nodejs/cat-service.js +27 -15
- package/lib/init/template/sample/files/srv/cat-service.cds +5 -1
- package/lib/init/template/typescript/files/package.json +3 -3
- package/lib/init/template/workzone/index.js +0 -3
- package/lib/init/template/xsuaa/index.js +10 -3
- package/lib/mtx/push.js +3 -1
- package/npm-shrinkwrap.json +19 -16
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,56 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
7
7
|
|
|
8
8
|
The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
9
9
|
|
|
10
|
+
## Version 8.1.1 - 2024-08-07
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Add more features to CAP project creation wizard in SAP Business Application Studio.
|
|
15
|
+
- `cds.add.merge` now you specify a `key` in its `deletions` semantics.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
|
|
19
|
+
- `cds init` uses latest Maven Java archetype version 3.1.0 for creating Java projects.
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- `cds import` now gives proper error message for OData import in case of invalid OData version or invalid encoding.
|
|
24
|
+
- `cds import` now able to ignore invalid escape sequence in the description of properties for OData V2.
|
|
25
|
+
- `cds add mta` does not error when the `app/router` folder was deleted.
|
|
26
|
+
- `cds version -i` does not show a globally installed version when none is installed or linked.
|
|
27
|
+
- `cds compile --to openapi` no longer fails with `Error: Unknown protocol: graphql`.
|
|
28
|
+
- `cds add data` can now correctly handle circular dependencies in entities that point to themselves via associations and compositions.
|
|
29
|
+
- `cds add` returns correct suggestions for shell completion.
|
|
30
|
+
- `cds version` reports correct `@sap/cds-compiler` version.
|
|
31
|
+
- `cds deploy` falls back correctly to `@sap/hana-client` when `HDI_DEPLOY_OPTIONS='{"use_hdb":false}'` is set.
|
|
32
|
+
|
|
33
|
+
## Version 8.1.0 - 2024-07-26
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- `cds compile --to mermaid` can be configured with a layout direction like `LR`.
|
|
38
|
+
- `cds deploy --to hana` now shows the `hdi-deploy` version when running.
|
|
39
|
+
|
|
40
|
+
### Changed
|
|
41
|
+
|
|
42
|
+
- Better generation of http files with `cds add http`, especially for draft requests.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- `cds add` recognizes `hasCfManifest` as inactive unless a `manifest.yml` file exists.
|
|
47
|
+
- `cds add` help and suggestions are only shown when the `help` method is implemented.
|
|
48
|
+
- `cds add sample` does not include the deprecated `synchronizationMode` property in `manifest.json` files any more.
|
|
49
|
+
- `cds compile --to mermaid` no longer produces empty `namespace` blocks that would lead to rendering errors.
|
|
50
|
+
- `cds compile --to mermaid` no longer fails for complex queries like joins.
|
|
51
|
+
- `cds build --for mtx-sidecar` now correctly supports different `srv` folder name.
|
|
52
|
+
- `cds add audit-log` in combination with `cds add multitenancy` correctly adds the audit-log dependency to the MTX sidecar.
|
|
53
|
+
- `cds build` adds the correct hdbtabledata file paths to the hana result set.
|
|
54
|
+
- `cds add` plugins can now correctly interpret `cds.cli` properties.
|
|
55
|
+
- `cds deploy --to hana --dry` now shows correct files with their content.
|
|
56
|
+
- `cds version` now reports the correct version of `@sap/cds` if this one is installed locally along with a local `@sap/cds-dk` installation.
|
|
57
|
+
- Shell completion now works correctly for `cds init --add`.
|
|
58
|
+
- `cds build --for mtx-sidecar` no longer fails if the severity of a compilation error has been downgraded from `Error` to `Warning`.
|
|
59
|
+
|
|
10
60
|
## Version 8.0.3 - 2024-07-20
|
|
11
61
|
|
|
12
62
|
### Fixed
|
|
@@ -36,6 +86,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
|
36
86
|
- `cds add helm` removed `saasRegistryParameters` key and moved parameters to `saas-registry`.
|
|
37
87
|
- `cds init` no longer creates a `.cdsrc.json` for Node.js projects.
|
|
38
88
|
- `cds build` configuration cleanup for `data.model` and `service.model` to only support configuration of a single model folder.
|
|
89
|
+
- `cds build` now fully supports default model definitions for custom build plugins.
|
|
39
90
|
|
|
40
91
|
## Version 8.0.1 - 2024-07-09
|
|
41
92
|
|
|
@@ -142,7 +193,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
|
142
193
|
|
|
143
194
|
- `cds add notebook` is removed. CAP Jupyter Notebooks have been replaced by custom CAP Notebooks for VS Code which are now part of the CDS Editor. See https://cap.cloud.sap/docs/tools/#add-cds-editor for more.
|
|
144
195
|
|
|
145
|
-
|
|
146
196
|
## Version 7.9.6 - 2024-07-19
|
|
147
197
|
|
|
148
198
|
### Fixed
|
package/bin/bind.js
CHANGED
|
@@ -46,7 +46,7 @@ module.exports = Object.assign(cds_bind, {
|
|
|
46
46
|
|
|
47
47
|
*-a | --to-app-services* <app>
|
|
48
48
|
|
|
49
|
-
Bind
|
|
49
|
+
Bind services of a given application (Cloud Foundry only).
|
|
50
50
|
|
|
51
51
|
*--no-create-service-key*
|
|
52
52
|
|
|
@@ -164,11 +164,11 @@ async function cds_bind(args, options) {
|
|
|
164
164
|
options.targets = options.to.split(/,/g);
|
|
165
165
|
|
|
166
166
|
if (options.targets.length >= 2 && options.serviceArg) {
|
|
167
|
-
throw `Service argument cannot be specified together with multiple
|
|
167
|
+
throw `Service argument cannot be specified together with multiple target (${term.bold('--to')}) services. Use one service per call or omit the service argument.`;
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
if (options.targets.length >= 2 && options.kind) {
|
|
171
|
-
throw `The option '--kind' cannot be specified together with multiple
|
|
171
|
+
throw `The option '--kind' cannot be specified together with multiple target (${term.bold('--to')}) services. Use one service per call or omit the ${term.bold('--kind')} option.`;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
174
|
const services = await bind({ ...options, out });
|
package/bin/cds.js
CHANGED
|
@@ -55,8 +55,15 @@ const cli = {
|
|
|
55
55
|
argv = argv.slice(0, endOfOptions)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
// REVISIT: Have to load plugins to allow for plugin-contributed flags!
|
|
59
|
+
if (cmd === 'add') {
|
|
60
|
+
cds.cli = { command: 'add' }
|
|
61
|
+
await cds.plugins
|
|
62
|
+
for (const [, Plugin] of cds.add.registered) {
|
|
63
|
+
task.options.push(...Object.keys((new Plugin).options()).map(key => '--'+key))
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
const args = this.args(task, argv)
|
|
60
67
|
args[0].push(...appendArgs)
|
|
61
68
|
cds.cli = {
|
|
62
69
|
command: cmd,
|
|
@@ -64,17 +71,6 @@ const cli = {
|
|
|
64
71
|
options: args[1],
|
|
65
72
|
}
|
|
66
73
|
|
|
67
|
-
if (cmd === 'add') { // cds add plugins allow additional custom options
|
|
68
|
-
await cds.plugins
|
|
69
|
-
for (const [, Plugin] of cds.add.registered) {
|
|
70
|
-
const options = Object.keys((new Plugin).options()).map(key => '--'+key)
|
|
71
|
-
task.options.push(options)
|
|
72
|
-
options.forEach(o => unknown.delete(o))
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (unknown.size === 1) throw 'Invalid option: ' + Array.from(unknown)[0]
|
|
76
|
-
if (unknown.size > 1) throw 'Invalid options: ' + Array.from(unknown).join(', ')
|
|
77
|
-
|
|
78
74
|
if (args[1]?.['resolve-bindings']) await _resolveBindings({ silent: cmd === 'env' })
|
|
79
75
|
|
|
80
76
|
// cds.root may for some subcommands not point to the correct directory (e.g. cds w where users can pass a project directory)
|
|
@@ -106,7 +102,7 @@ const cli = {
|
|
|
106
102
|
},
|
|
107
103
|
|
|
108
104
|
// TODO replace w/ common arg parser from node
|
|
109
|
-
args (task, argv
|
|
105
|
+
args (task, argv) {
|
|
110
106
|
|
|
111
107
|
const { options:o=[], flags:f=[], shortcuts:s=[] } = task
|
|
112
108
|
const _global = /^--(profile|production|sql|odata|add-.*|build-.*|cdsc-.*|odata-.*|folders-.*)$/
|
|
@@ -120,7 +116,7 @@ const cli = {
|
|
|
120
116
|
else if ((k = o.indexOf(a)) >= 0) add(o[k],argv[++i])
|
|
121
117
|
else if ((k = f.indexOf(a)) >= 0) add(f[k])
|
|
122
118
|
else if (_global.test(a)) add_global(a, _flags[a] || argv[++i])
|
|
123
|
-
else
|
|
119
|
+
else throw 'Invalid option: '+ a
|
|
124
120
|
}
|
|
125
121
|
// consistent production setting for NODE_ENV and CDS_ENV
|
|
126
122
|
// if (process.env.NODE_ENV !== 'production') process.env.NODE_ENV = process.env.CDS_ENV?.split(',').find(p => p === 'production') || process.env.NODE_ENV
|
package/bin/init.js
CHANGED
|
@@ -61,18 +61,15 @@ async function handleCompletion(currentWord, previousWord, argv, util) {
|
|
|
61
61
|
return allOptionsFlags;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
if (previousWord === '--add') {
|
|
65
|
-
return util.completionFs.readTemplates(argv);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
64
|
if (previousWord === '--java:package') {
|
|
69
65
|
const excludes = ['_merging'];
|
|
70
66
|
return (await util.completionFs.readdir(currentWord, { files: false }))
|
|
71
67
|
.filter(e => !excludes.includes(e));
|
|
72
68
|
}
|
|
73
69
|
|
|
74
|
-
|
|
75
|
-
|
|
70
|
+
const templates = await util.completionFs.readTemplates(argv);
|
|
71
|
+
if (previousWord === '--add' || argv.includes('--add') && previousWord.endsWith(',')) {
|
|
72
|
+
return templates;
|
|
76
73
|
}
|
|
77
74
|
|
|
78
75
|
return allOptionsFlags;
|
package/bin/version.js
CHANGED
|
@@ -61,7 +61,8 @@ function list_versions(args, options) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
function info({ root:cwd=process.cwd() }) {
|
|
64
|
-
const
|
|
64
|
+
const cds = require('../lib')
|
|
65
|
+
const env = cds.env.for('cds', cwd)
|
|
65
66
|
env.cli ??= {}; env.cli.version ??= {}
|
|
66
67
|
const javaInfo = !env.cli.version.skipjava && env['project-nature'] === 'java'
|
|
67
68
|
if (javaInfo && process.stderr.isTTY) {
|
|
@@ -70,14 +71,14 @@ function info({ root:cwd=process.cwd() }) {
|
|
|
70
71
|
|
|
71
72
|
const npmRoot = execSync('npm root -g').toString().trim()
|
|
72
73
|
let versions = {
|
|
73
|
-
..._versions_from(_pkg_path('@sap/cds-dk',
|
|
74
|
-
..._versions_from(_pkg_path('@sap/cds-dk', npmRoot), '@sap/cds-dk (global)'), // ... or installed globally
|
|
74
|
+
..._versions_from(_pkg_path('@sap/cds-dk', npmRoot), '@sap/cds-dk (global)'), // linked in cap/dev or installed globally
|
|
75
75
|
..._versions_from(_pkg_path('@sap/cds-dk', cwd)), // local dk, important for Java projects
|
|
76
76
|
..._versions_from(_pkg_path('@sap/cds', __dirname)), // @sap/cds from here
|
|
77
|
-
..._versions_from(
|
|
78
|
-
..._versions_from(
|
|
77
|
+
..._versions_from(_pkg_path('@sap/cds', cds.home)), // ... or local @sap/cds
|
|
78
|
+
..._versions_from(cwd), // ... more from local app dependencies
|
|
79
|
+
'@sap/cds-compiler': cds.compiler.version(),
|
|
79
80
|
'Node.js': process.version,
|
|
80
|
-
'home':
|
|
81
|
+
'home': cds.home, // effective cds home
|
|
81
82
|
}
|
|
82
83
|
// sort Node entries
|
|
83
84
|
versions = Object.keys(versions).sort().reduce((all, key) => { all[key] = versions[key]; return all }, {})
|
|
@@ -3,7 +3,7 @@ const path = require('path')
|
|
|
3
3
|
const cds = require('../cds')
|
|
4
4
|
const BuildTaskProviderFactory = require('./buildTaskProviderFactory')
|
|
5
5
|
const { hasJavaNature, getProperty, getDefaultModelOptions, hasOptionValue, BuildError } = require('./util')
|
|
6
|
-
const { FILE_EXT_CDS, OPTION_WS } = require("./constants")
|
|
6
|
+
const { FILE_EXT_CDS, OPTION_WS, IGNORE_DEFAULT_MODELS, NODEJS_MODEL_EXCLUDE_LIST, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF } = require("./constants")
|
|
7
7
|
const term = require('../util/term')
|
|
8
8
|
const DEBUG = cds.debug('cli|build')
|
|
9
9
|
|
|
@@ -95,11 +95,7 @@ class BuildTaskFactory {
|
|
|
95
95
|
task.options.model = [task.options.model]
|
|
96
96
|
}
|
|
97
97
|
})
|
|
98
|
-
|
|
99
|
-
if (!tasks.some(task => !task.options?.model?.length > 0)) {
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
const modelPaths = await getDefaultModelOptions()
|
|
98
|
+
const modelPaths = await getDefaultModelOptions(false)
|
|
103
99
|
let wsModelPaths
|
|
104
100
|
// calculate only once
|
|
105
101
|
if (cds.cli.options?.[OPTION_WS] || tasks.some(task => hasOptionValue(task.options?.[OPTION_WS], true))) {
|
|
@@ -107,10 +103,12 @@ class BuildTaskFactory {
|
|
|
107
103
|
}
|
|
108
104
|
// set default model options
|
|
109
105
|
tasks.forEach(task => {
|
|
110
|
-
this._setTaskModelOptions(task, cds.cli.options?.[OPTION_WS] || hasOptionValue(task.options?.[OPTION_WS], true) ? wsModelPaths : modelPaths)
|
|
111
106
|
if (!task.src) {
|
|
112
107
|
throw new BuildError(`Mandatory property 'src' not defined for build task '${task.for}'.`)
|
|
113
108
|
}
|
|
109
|
+
const optionWs = cds.cli.options?.[OPTION_WS] || hasOptionValue(task.options?.[OPTION_WS], true)
|
|
110
|
+
// shallow copy model paths
|
|
111
|
+
this._setTaskModelOptions(task, optionWs ? [...wsModelPaths] : [...modelPaths])
|
|
114
112
|
})
|
|
115
113
|
}
|
|
116
114
|
|
|
@@ -180,14 +178,33 @@ class BuildTaskFactory {
|
|
|
180
178
|
}
|
|
181
179
|
|
|
182
180
|
static _setTaskModelOptions(task, defaultModelPaths) {
|
|
181
|
+
// bootstrap service model is only required for Nodejs build task - issues/12770#issuecomment-1805719
|
|
182
|
+
if (task.for !== BUILD_TASK_NODEJS && task.for !== BUILD_TASK_NODE_CF) {
|
|
183
|
+
defaultModelPaths = defaultModelPaths.filter(p => !NODEJS_MODEL_EXCLUDE_LIST.includes(p))
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
let taskModelPaths = task.options?.model
|
|
187
|
+
if (taskModelPaths && !Array.isArray(taskModelPaths)) {
|
|
188
|
+
taskModelPaths = [taskModelPaths]
|
|
189
|
+
}
|
|
190
|
+
const allowList = new RegExp(`^@sap/cds${cds.env.requires.toggles ? '|^' + cds.env.features.folders.replace('*', '') : ''}`)
|
|
183
191
|
task.options = task.options || {}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if (task.
|
|
187
|
-
defaultModelPaths.
|
|
192
|
+
let modelPaths = []
|
|
193
|
+
if (taskModelPaths?.length) {
|
|
194
|
+
if (!hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
|
|
195
|
+
modelPaths = defaultModelPaths.filter(p => p.match(allowList))
|
|
196
|
+
}
|
|
197
|
+
} else {
|
|
198
|
+
modelPaths = [...defaultModelPaths]
|
|
199
|
+
if (!modelPaths.includes(task.src)) {
|
|
200
|
+
modelPaths.push(task.src)
|
|
201
|
+
}
|
|
202
|
+
if (hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
|
|
203
|
+
// all default models except the built-in models
|
|
204
|
+
modelPaths = modelPaths.filter(p => !p.match(allowList))
|
|
188
205
|
}
|
|
189
|
-
task.options.model = [...defaultModelPaths]
|
|
190
206
|
}
|
|
207
|
+
task.options.model = [...new Set(taskModelPaths?.length ? taskModelPaths.concat(modelPaths) : modelPaths)]
|
|
191
208
|
}
|
|
192
209
|
|
|
193
210
|
static _stringifyTask(task) {
|
package/lib/build/constants.js
CHANGED
|
@@ -48,7 +48,7 @@ exports.FILE_EXT_CDS = ".cds"
|
|
|
48
48
|
exports.MTX_SIDECAR_FOLDER = "mtx/sidecar" // default name of the mtx sidecar folder
|
|
49
49
|
exports.DEFAULT_CSN_FILE_NAME = "csn.json"
|
|
50
50
|
// REVISIT: the models are not required if a custom server.js file is used for MTX bootstrap
|
|
51
|
-
exports.NODEJS_MODEL_EXCLUDE_LIST = ['@sap/cds
|
|
51
|
+
exports.NODEJS_MODEL_EXCLUDE_LIST = ['@sap/cds-mtxs/srv/bootstrap']
|
|
52
52
|
|
|
53
53
|
exports.CDS_CONFIG_PATH_SEP = "/"
|
|
54
54
|
exports.SEVERITY_ERROR = "Error"
|
|
@@ -26,7 +26,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
26
26
|
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
27
27
|
this._result = {
|
|
28
28
|
dest: this.task.dest,
|
|
29
|
-
hana:
|
|
29
|
+
hana: new Set()
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
this.task.options.compileDest = path.resolve(this.task.dest, this.task.options.compileDest || DEFAULT_COMPILE_DEST_FOLDER)
|
|
@@ -228,7 +228,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
228
228
|
}
|
|
229
229
|
|
|
230
230
|
const promises = []
|
|
231
|
-
const relDest = path.relative(this.task.dest, this.task.options.compileDest)
|
|
232
231
|
const options = { ...this.options(), messages: this.messages, dirs: csvDirs, baseDir: this.task.options.compileDest }
|
|
233
232
|
|
|
234
233
|
const toHdbtabledata = cds.compile.to.hdbtabledata ?? require(path.join(cds.home, 'bin/build/provider/hana/2tabledata')) // cds@6 compatibility
|
|
@@ -240,7 +239,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
240
239
|
let tableDataPath = csvFolder.startsWith(this.task.options.compileDest) ? csvFolder : this.task.options.compileDest
|
|
241
240
|
tableDataPath = path.join(tableDataPath, file)
|
|
242
241
|
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
243
|
-
this._result.hana.
|
|
242
|
+
this._result.hana.add(path.relative(this.task.dest, tableDataPath))
|
|
244
243
|
}
|
|
245
244
|
promises.push(this.write(tableData).to(tableDataPath))
|
|
246
245
|
}
|
|
@@ -296,7 +295,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
296
295
|
|
|
297
296
|
hdiPlugins.add(suffix)
|
|
298
297
|
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
299
|
-
this._result.hana.
|
|
298
|
+
this._result.hana.add(path.join(relDest, file))
|
|
300
299
|
}
|
|
301
300
|
promises.push(this.write(content).to(path.join(this.task.options.compileDest, file)))
|
|
302
301
|
if (suffix === FILE_EXT_HDBTABLE) {
|
|
@@ -345,7 +344,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
345
344
|
migrationTableFiles.push(path.join(relDbSrcDir, fileName))
|
|
346
345
|
if (changed) {
|
|
347
346
|
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
348
|
-
this._result.hana.
|
|
347
|
+
this._result.hana.add(path.join("src", fileName))
|
|
349
348
|
}
|
|
350
349
|
promises.push(this.write(content).to(path.join(dbSrcDir, fileName)))
|
|
351
350
|
} else {
|
|
@@ -354,7 +353,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
354
353
|
}
|
|
355
354
|
} else {
|
|
356
355
|
if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
|
|
357
|
-
this._result.hana.
|
|
356
|
+
this._result.hana.add(path.join(relDestDir, fileName))
|
|
358
357
|
}
|
|
359
358
|
promises.push(this.write(content).to(path.join(this.task.options.compileDest, fileName)))
|
|
360
359
|
if (suffix === FILE_EXT_HDBTABLE) {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const cds = require('../../cds')
|
|
4
|
-
const { hasJavaNature,
|
|
4
|
+
const { hasJavaNature, BuildError, normalizePath } = require('../util')
|
|
5
5
|
const BuildTaskProvider = require('../buildTaskProvider')
|
|
6
6
|
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,
|
|
7
|
-
BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION
|
|
8
|
-
IGNORE_DEFAULT_MODELS, OPTION_WS } = require("../constants")
|
|
7
|
+
BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION } = require("../constants")
|
|
9
8
|
const ResourcesTarBuilder = require('./mtx/resourcesTarBuilder')
|
|
10
9
|
const DEBUG = cds.debug('cli|build')
|
|
11
10
|
|
|
@@ -19,10 +18,7 @@ class InternalBuildTaskProvider extends BuildTaskProvider {
|
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
async applyTaskDefaults(task) {
|
|
22
|
-
// src folder needs to be initialized first
|
|
23
21
|
InternalBuildTaskProvider._setDefaultSrcFolder(task)
|
|
24
|
-
|
|
25
|
-
await InternalBuildTaskProvider._setDefaultModel(task)
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
getPlugin(task) {
|
|
@@ -284,35 +280,6 @@ class InternalBuildTaskProvider extends BuildTaskProvider {
|
|
|
284
280
|
}
|
|
285
281
|
}
|
|
286
282
|
|
|
287
|
-
static async _setDefaultModel(task) {
|
|
288
|
-
const ws = hasOptionValue(task.options?.[OPTION_WS], true) || cds.cli.options?.[OPTION_WS]
|
|
289
|
-
// REVISIT: filter nodejs bootstrap service models for Java - issues/12770#issuecomment-1805719
|
|
290
|
-
const filter = hasJavaNature() ? (m) => !NODEJS_MODEL_EXCLUDE_LIST.includes(m) : null
|
|
291
|
-
let taskModelPaths = task.options?.model
|
|
292
|
-
if (taskModelPaths && !Array.isArray(taskModelPaths)) {
|
|
293
|
-
taskModelPaths = [taskModelPaths]
|
|
294
|
-
}
|
|
295
|
-
const allowList = new RegExp(`^@sap/cds${cds.env.requires.toggles ? '|^' + cds.env.features.folders.replace('*', '') : ''}`)
|
|
296
|
-
task.options = task.options || {}
|
|
297
|
-
let defaultModelPaths = []
|
|
298
|
-
if (taskModelPaths?.length) {
|
|
299
|
-
if (!hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
|
|
300
|
-
defaultModelPaths = await getDefaultModelOptions(ws, filter)
|
|
301
|
-
defaultModelPaths = defaultModelPaths.filter(p => p.match(allowList))
|
|
302
|
-
}
|
|
303
|
-
} else {
|
|
304
|
-
defaultModelPaths = await getDefaultModelOptions(ws, filter)
|
|
305
|
-
defaultModelPaths.push(task.src)
|
|
306
|
-
if (hasOptionValue(task.options?.[IGNORE_DEFAULT_MODELS], true)) {
|
|
307
|
-
// all default models except the built-in models
|
|
308
|
-
defaultModelPaths = defaultModelPaths.filter(p => !p.match(allowList))
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
if (defaultModelPaths.length) {
|
|
312
|
-
task.options.model = [...new Set(taskModelPaths?.length ? taskModelPaths.concat(defaultModelPaths) : defaultModelPaths)]
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
283
|
/**
|
|
317
284
|
* Determines the module folder from the given list that may represent files or folders w or w/o .cds file extension.
|
|
318
285
|
* @param {Array} filesOrFolders
|
|
@@ -92,10 +92,10 @@ class ResourcesTarBuilder {
|
|
|
92
92
|
|
|
93
93
|
return hanaTasks.find(hanaTask => {
|
|
94
94
|
// if called from internalBuildTaskProvider, the src folder for the tenant db task might still not set
|
|
95
|
-
// while an existing second shared db always requires src to be
|
|
95
|
+
// while an existing second shared db always requires src to be set
|
|
96
96
|
if (!hanaTask.src) return true
|
|
97
97
|
const srcFolder = path.isAbsolute(hanaTask.src) ? path.relative(cds.root, hanaTask.src) : hanaTask.src
|
|
98
|
-
return mtxTask.options?.model?.includes(srcFolder)
|
|
98
|
+
return mtxTask.options?.model?.includes(srcFolder) || srcFolder === cds.env.folders.db.replace('/', '')
|
|
99
99
|
})
|
|
100
100
|
}
|
|
101
101
|
}
|
|
@@ -45,7 +45,7 @@ class MtxSidecarBuildPlugin extends NodejsBuildPlugin {
|
|
|
45
45
|
*/
|
|
46
46
|
async _buildNodeApp(sidecarEnv) {
|
|
47
47
|
const destSidecar = this.task.dest
|
|
48
|
-
const destSidecarSrc = path.join(destSidecar,
|
|
48
|
+
const destSidecarSrc = path.join(destSidecar, sidecarEnv.folders.srv)
|
|
49
49
|
const model = this._compileSidecarSync(sidecarEnv)
|
|
50
50
|
await this.compileToJson(model, path.join(destSidecarSrc, DEFAULT_CSN_FILE_NAME))
|
|
51
51
|
await this.collectLanguageBundles(model, path.join(destSidecarSrc, getI18nDefaultFolder()))
|
|
@@ -129,8 +129,15 @@ class MtxSidecarBuildPlugin extends NodejsBuildPlugin {
|
|
|
129
129
|
this.pushMessage(`CDS models [${unresolved.join(', ')}] required by MTX sidecar cannot be resolved. Make sure up-to-date versions of the missing npm modules are installed.`, ERROR)
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
-
// synchronous compilation
|
|
133
|
-
|
|
132
|
+
// using synchronous compilation as cds.root and cds.env have been switched to mtx/sidecar
|
|
133
|
+
// using different messages array ensures that cds compilation doesn't fail because of
|
|
134
|
+
// existing compilation error messages that have been downgraded to warnings
|
|
135
|
+
// see cap/issues/issues/16401#issuecomment-7205397
|
|
136
|
+
const messages = []
|
|
137
|
+
const model = cds.load(modelFilePaths, { sync: true, messages })
|
|
138
|
+
messages.forEach(msg => this.messages.push(msg))
|
|
139
|
+
|
|
140
|
+
return model
|
|
134
141
|
} finally {
|
|
135
142
|
// restore project scope
|
|
136
143
|
cds.root = root
|
package/lib/cds.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** @type { import('@sap/cds/lib') } */
|
|
2
2
|
const cds = _local ('@sap/cds')
|
|
3
3
|
|
|
4
|
+
/** @type { import('@sap/cds/lib') & {_local: (id: string) => any} } */
|
|
4
5
|
module.exports = Object.defineProperties (cds, {
|
|
5
6
|
// for internal use in cds-dk only
|
|
6
7
|
_log: { value: _local ('../bin/util/log'), configurable: true },
|
|
@@ -2,12 +2,13 @@ const cds = require('../cds')
|
|
|
2
2
|
|
|
3
3
|
module.exports = function to_mermaid (model, options={}) {
|
|
4
4
|
options = Object.assign({
|
|
5
|
-
assocnames: false,
|
|
6
|
-
elements : false,
|
|
7
|
-
min : false,
|
|
8
|
-
namespaces: true,
|
|
9
|
-
queries : false,
|
|
10
|
-
service : undefined // filter service by name, available in CLI
|
|
5
|
+
assocnames: false, // include association names
|
|
6
|
+
elements : false, // include all elements { falsy | 'all'|true | 'keys' }
|
|
7
|
+
min : false, // minify the model, i.e. remove unused definitions, available in CLI
|
|
8
|
+
namespaces: true, // group entities by namespace/service
|
|
9
|
+
queries : false, // include relations for queries
|
|
10
|
+
service : undefined, // filter service by name, available in CLI
|
|
11
|
+
direction : undefined // direction of the graph
|
|
11
12
|
}, cds.env.mermaid ?? {}, options)
|
|
12
13
|
|
|
13
14
|
const elemOpts = options.elements === 'none' ? false : options.elements
|
|
@@ -27,6 +28,7 @@ module.exports = function to_mermaid (model, options={}) {
|
|
|
27
28
|
const entityFilter = e => !e.name.startsWith('cds.') && !e.name.endsWith('.texts')
|
|
28
29
|
|
|
29
30
|
let diag = ''
|
|
31
|
+
const direction = options.direction ? ` direction ${options.direction}\n` : ''
|
|
30
32
|
|
|
31
33
|
// if requested, filter by one service
|
|
32
34
|
model.all('service')
|
|
@@ -56,8 +58,10 @@ module.exports = function to_mermaid (model, options={}) {
|
|
|
56
58
|
})
|
|
57
59
|
|
|
58
60
|
// create namespace groups and classes
|
|
59
|
-
Object.keys(namespaces)
|
|
60
|
-
|
|
61
|
+
Object.keys(namespaces)
|
|
62
|
+
.filter (ns => namespaces[ns].length) // empty namespaces can cause rendering errors, so skip them
|
|
63
|
+
.forEach(ns => {
|
|
64
|
+
if (!diag.length) diag = `classDiagram\n${direction}`
|
|
61
65
|
diag += ` namespace ${ns.replaceAll('.','_')} {\n`
|
|
62
66
|
namespaces[ns].forEach (e => {
|
|
63
67
|
const simpleName = e.name.slice(e.name.lastIndexOf('.')+1)
|
|
@@ -65,7 +69,7 @@ module.exports = function to_mermaid (model, options={}) {
|
|
|
65
69
|
diag += `["${simpleName}"]` // simple name as label
|
|
66
70
|
if (elemOpts) {
|
|
67
71
|
diag += ` {\n`
|
|
68
|
-
e.elements
|
|
72
|
+
e.elements?.forEach (el => {
|
|
69
73
|
if ((elemOpts === 'all' || elemOpts === true) || (el.key && elemOpts == 'keys')) {
|
|
70
74
|
diag += ` +${el._type?.replace('cds.','')} ${el.name}`
|
|
71
75
|
diag += `\n`
|
|
@@ -85,8 +89,8 @@ module.exports = function to_mermaid (model, options={}) {
|
|
|
85
89
|
? Array.from(seenEntities).map(name => model.definitions[name])
|
|
86
90
|
: model.all('entity').filter (entityFilter) // if no grouping and no service filter is on
|
|
87
91
|
entities.forEach(e => {
|
|
88
|
-
if (!diag.length) diag = `classDiagram\n`
|
|
89
|
-
e.elements
|
|
92
|
+
if (!diag.length) diag = `classDiagram\n${direction}`
|
|
93
|
+
e.elements?.forEach (el => {
|
|
90
94
|
if (el instanceof cds.Association) {
|
|
91
95
|
if (el.target.endsWith('.texts')) return
|
|
92
96
|
const type = el.type === 'cds.Composition' ? '*-->' : '-->'
|
|
@@ -100,9 +104,20 @@ module.exports = function to_mermaid (model, options={}) {
|
|
|
100
104
|
})
|
|
101
105
|
// add relations for queries
|
|
102
106
|
if (e.query && options.queries) {
|
|
103
|
-
|
|
107
|
+
resolveTargets(e.query).forEach(t => {
|
|
108
|
+
diag += ` \`${e.name}\` ..> \`${t}\`\n`
|
|
109
|
+
})
|
|
104
110
|
}
|
|
105
111
|
})
|
|
106
112
|
|
|
107
113
|
return diag.trim()
|
|
108
114
|
}
|
|
115
|
+
|
|
116
|
+
function resolveTargets (query) {
|
|
117
|
+
if (query.target) return [ query.target.name ] // simple query, like projection on
|
|
118
|
+
|
|
119
|
+
// SELECT: { from: { args: [{ ref: ['t1'] }, { ref: ['t2'] }], join: ..., on: ... } }
|
|
120
|
+
const targets = query.SELECT?.from?.args?.filter(arg => arg.ref?.length).map (arg => arg.ref[0])
|
|
121
|
+
|
|
122
|
+
return targets
|
|
123
|
+
}
|
|
@@ -6,7 +6,6 @@ const cds = require('../../../lib/cds');
|
|
|
6
6
|
const { exists, read } = cds.utils;
|
|
7
7
|
|
|
8
8
|
const { build } = require('../../build');
|
|
9
|
-
const buildConstants = require('../../build/constants');
|
|
10
9
|
|
|
11
10
|
const hdi = require('./hdiDeployUtil');
|
|
12
11
|
const cfUtil = require('../../util/cf');
|
|
@@ -16,6 +15,7 @@ const mtaUtil = require('./mtaUtil');
|
|
|
16
15
|
const { bold, info, warn } = require('../../util/term');
|
|
17
16
|
|
|
18
17
|
const { bind, storeBindings } = require('../../bind');
|
|
18
|
+
const { BUILD_TASK_HANA, OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, OUTPUT_MODE_RESULT } = require('../../build/constants');
|
|
19
19
|
|
|
20
20
|
const DEBUG = cds.debug('cli');
|
|
21
21
|
|
|
@@ -73,13 +73,13 @@ Therefore, specifying the CDS model is not required when calling 'cds deploy'.`;
|
|
|
73
73
|
vcapEnv.TARGET_CONTAINER = process.env.TARGET_CONTAINER;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
for (const { task } of buildResults) {
|
|
76
|
+
for (const { task, result } of buildResults) {
|
|
77
77
|
if (dry) {
|
|
78
|
-
const
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
console.log(`-- ${
|
|
82
|
-
console.log(
|
|
78
|
+
const sortedResult = Array.from(result.hana).sort();
|
|
79
|
+
for (const file of sortedResult) {
|
|
80
|
+
const srcPath = path.join(result.dest, file);
|
|
81
|
+
console.log(`-- ${path.relative(cds.root, srcPath)}`);
|
|
82
|
+
console.log(await read(srcPath));
|
|
83
83
|
console.log();
|
|
84
84
|
}
|
|
85
85
|
} else {
|
|
@@ -221,7 +221,9 @@ Therefore, specifying the CDS model is not required when calling 'cds deploy'.`;
|
|
|
221
221
|
|
|
222
222
|
async _build() {
|
|
223
223
|
const buildTaskOptions = {
|
|
224
|
-
for:
|
|
224
|
+
for: BUILD_TASK_HANA,
|
|
225
|
+
src: cds.env.folders.db,
|
|
226
|
+
[OUTPUT_MODE]: OUTPUT_MODE_FILESYSTEM | OUTPUT_MODE_RESULT
|
|
225
227
|
}
|
|
226
228
|
|
|
227
229
|
console.log(`Running build`);
|
|
@@ -37,6 +37,7 @@ module.exports = new class HdiDeployUtil {
|
|
|
37
37
|
else throw e
|
|
38
38
|
}
|
|
39
39
|
if (options.use_hdb !== false) options.use_hdb = true
|
|
40
|
+
if (options.use_hdb === false) options.use_hdb = undefined
|
|
40
41
|
deployerEnv.HDI_DEPLOY_OPTIONS = JSON.stringify(options)
|
|
41
42
|
|
|
42
43
|
const asyncDeploy = util.promisify(deploy);
|
|
@@ -59,7 +60,15 @@ module.exports = new class HdiDeployUtil {
|
|
|
59
60
|
Add it either to ${bold('devDependencies')} using 'npm install -D ${HDI_DEPLOY_LIB}' or install it globally using 'npm install -g ${HDI_DEPLOY_LIB}'.`);
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
console.log(`
|
|
63
|
+
console.log(`HDI deployer path: ${libPath}`)
|
|
64
|
+
|
|
65
|
+
const libRoot = path.dirname(libPath);
|
|
66
|
+
try {
|
|
67
|
+
const libPackageJson = require(path.join(libRoot, 'package.json'));
|
|
68
|
+
console.log(`HDI deployer version: ${libPackageJson.version}`);
|
|
69
|
+
} catch {
|
|
70
|
+
// ignore
|
|
71
|
+
}
|
|
63
72
|
|
|
64
73
|
// let any error go through and abort deploy
|
|
65
74
|
return require(libPath);
|
package/lib/import/common.js
CHANGED
package/lib/import/message.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const messages = {
|
|
4
4
|
INVALID_EDMX_METADATA: 'The OData model is not valid. Specify the correct OData model.',
|
|
5
|
-
|
|
5
|
+
INVALID_ODATA_VERSION_OR_UNSUPPORTED_ENCODING: 'Either the OData version is not valid, or the encoding of the file is not utf-8. Please specify the supported OData version and file encoding. OData version is expected one of [1.0, 2.0, 4.0, 4.01] and the input file encoding is expected UTF-8.',
|
|
6
6
|
INVALID_OUTPUT_FILE: 'Please provide an output file with one of these [cds, csn, json] file extension.',
|
|
7
7
|
SPECIFY_INPUT_FILE: 'Specify an input file that exists.',
|
|
8
8
|
SPECIFY_OUTPUT_FILE: 'Specify an output file or correct the output file path provided.',
|
|
@@ -45,4 +45,4 @@ function getMessages() {
|
|
|
45
45
|
|
|
46
46
|
module.exports = {
|
|
47
47
|
getMessages
|
|
48
|
-
};
|
|
48
|
+
};
|