@sap/cds-dk 9.0.4 → 9.0.5
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 +20 -0
- package/bin/cds.js +1 -1
- package/bin/debug.js +1 -1
- package/bin/help.js +3 -3
- package/lib/build/provider/fiori/index.js +4 -4
- package/lib/build/provider/mtx-extension/index.js +12 -0
- package/lib/init/constants.js +1 -1
- package/lib/init/template/data/as-csv.js +24 -8
- package/lib/init/template/data/as-json.js +3 -3
- package/lib/init/template/hana/index.js +2 -2
- package/lib/init/template/handler/index.js +16 -12
- package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +1 -1
- package/lib/init/template/nodejs/files/package.json.hbs +2 -2
- package/lib/init/template/postgres/files/package.json.hbs +1 -1
- package/lib/init/template/sample/files/app/admin-books/fiori-service.cds +6 -0
- package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +1 -0
- package/lib/init/template/sample/files/app/browse/fiori-service.cds +3 -2
- package/lib/init/template/sample/files/app/common.cds +0 -11
- package/lib/init/template/typescript/files/package.json +1 -1
- package/npm-shrinkwrap.json +174 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ 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.0.5 - 2025-06-06
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- `cds init` uses latest Maven Java archetype version 4.0.2 for creating Java projects.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- `cds build` for extensions now filters built-in entities such as `cds.outbox.Messages` to fix the extension upload with `cds push`.
|
|
18
|
+
- `cds add data` now correctly works for nested structured properties.
|
|
19
|
+
- `cds add data/http` no longer create decimal numbers with too many precision places
|
|
20
|
+
|
|
9
21
|
## Version 9.0.4 - 2025-05-28
|
|
10
22
|
|
|
11
23
|
### Changed
|
|
@@ -95,6 +107,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
|
|
|
95
107
|
- `cds add multitenancy` requires the `srv-api` instead of the `mtx-api` for Java projects.
|
|
96
108
|
|
|
97
109
|
|
|
110
|
+
## Version 8.9.5 - 2025-06-05
|
|
111
|
+
|
|
112
|
+
### Fixed
|
|
113
|
+
|
|
114
|
+
- Bump `tar-fs` to address CVE-2024-12905.
|
|
115
|
+
- `cds add data` now correctly works for nested structured properties.
|
|
116
|
+
- Help text of `cds debug`.
|
|
117
|
+
|
|
98
118
|
## Version 8.9.4 - 2025-05-26
|
|
99
119
|
|
|
100
120
|
### Changed
|
package/bin/cds.js
CHANGED
|
@@ -106,7 +106,7 @@ const cli = {
|
|
|
106
106
|
},
|
|
107
107
|
|
|
108
108
|
load (cmd,_default) {
|
|
109
|
-
return /[
|
|
109
|
+
return /[\\/.\-@]/.test(cmd) && _default && _default(true) // like `cds ./srv` or `cds @capire/bookshop`
|
|
110
110
|
|| /cds/i.test(cmd) && _dieForUnknownCommand (cmd) // cds cds
|
|
111
111
|
|| _require ('./'+cmd) // cds-dk commands
|
|
112
112
|
|| _default && _default()
|
package/bin/debug.js
CHANGED
|
@@ -15,7 +15,7 @@ module.exports = Object.assign(debug, {
|
|
|
15
15
|
Cloud Foundry space (check with 'cf target').
|
|
16
16
|
SSH access to the app is required (check with 'cf ssh-enabled').
|
|
17
17
|
|
|
18
|
-
If no <app> is given, the app in the current working is started
|
|
18
|
+
If no <app> is given, the app in the current working directory is started
|
|
19
19
|
(with 'cds watch --debug' for Node.js and 'mvn spring-boot:run' for Java).
|
|
20
20
|
|
|
21
21
|
# OPTIONS
|
package/bin/help.js
CHANGED
|
@@ -13,7 +13,6 @@ module.exports = exports = Object.assign (help, {formatHelp, handleCompletion, h
|
|
|
13
13
|
*i* | *init* jump-start cds-based projects
|
|
14
14
|
*a* | *add* add a feature to an existing project
|
|
15
15
|
* * | *gen* generate models/data using a descriptive prompt [beta]
|
|
16
|
-
*y* | *bind* bind application to remote services
|
|
17
16
|
*m* | *import* add models from external sources
|
|
18
17
|
*c* | *compile* compile cds models to different outputs
|
|
19
18
|
*p* | *parse* parses given cds models
|
|
@@ -23,8 +22,9 @@ module.exports = exports = Object.assign (help, {formatHelp, handleCompletion, h
|
|
|
23
22
|
*r* | *repl* read-eval-event loop
|
|
24
23
|
*e* | *env* inspect effective configuration
|
|
25
24
|
*b* | *build* prepare for deployment
|
|
26
|
-
*d* | *deploy* deploy to databases
|
|
27
|
-
* * | *up* build and deploy your application
|
|
25
|
+
*d* | *deploy* deploy to databases
|
|
26
|
+
* * | *up* build and deploy your application to the cloud
|
|
27
|
+
*y* | *bind* bind application to remote services
|
|
28
28
|
* * | *debug* debug your application
|
|
29
29
|
* * | *subscribe* subscribe a tenant to a multitenant SaaS app
|
|
30
30
|
* * | *unsubscribe* unsubscribe a tenant from a multitenant SaaS app
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const path = require('path')
|
|
2
2
|
const cds = require('../../../cds')
|
|
3
3
|
const EdmxBuildPlugin = require('../edmxBuildPlugin')
|
|
4
|
-
const URL = require('url')
|
|
4
|
+
const { URL } = require('node:url')
|
|
5
5
|
const { getProperty, relativePaths } = require('../../util')
|
|
6
6
|
const { OUTPUT_MODE, OUTPUT_MODE_RESULT, BUILD_TASK_FIORI, CDS_CONFIG_PATH_SEP, OUTPUT_MODE_FILESYSTEM } = require('../../constants')
|
|
7
7
|
const DEBUG = cds.debug('cli|build')
|
|
@@ -52,7 +52,7 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
52
52
|
appModelGroups.set(appFolder, appModels)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
// ensure edmx is cached as build result
|
|
55
|
+
// ensure edmx is cached as build result
|
|
56
56
|
const buildOption = this.context.options[OUTPUT_MODE]
|
|
57
57
|
this.context.options[OUTPUT_MODE] |= OUTPUT_MODE_RESULT
|
|
58
58
|
|
|
@@ -159,8 +159,8 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
_strippedUrlPath(urlString) {
|
|
162
|
-
const url = URL
|
|
163
|
-
return url.pathname.replace(/^(\/|\\)/, '').replace(/(\/|\\)$/, '') // strip leading and trailing slash or backslash
|
|
162
|
+
const url = new URL(urlString, 'http://dummy.base') // need dummy base to parse relative URLs correctly
|
|
163
|
+
return url.pathname.replace(/^(\/|\\)/, '').replace(/(\/|\\)$/, '') // strip leading and trailing slash or backslash
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
|
|
@@ -8,6 +8,8 @@ const { FOLDER_GEN, EXTENSION_POINT_VALIDATION } = require('../../constants')
|
|
|
8
8
|
const { BuildError, BuildMessage } = require('../../util')
|
|
9
9
|
const DEBUG = cds.debug('cli|build')
|
|
10
10
|
|
|
11
|
+
const BUILT_IN_NAMESPACES = ['cds.core', 'cds.outbox', 'cds.xt']
|
|
12
|
+
|
|
11
13
|
class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
12
14
|
init() {
|
|
13
15
|
super.init()
|
|
@@ -48,6 +50,16 @@ class MtxExtensionBuildPlugin extends InternalBuildPlugin {
|
|
|
48
50
|
if (extensionModel.requires) {
|
|
49
51
|
extensionModel.requires.length = 0
|
|
50
52
|
}
|
|
53
|
+
if (extensionModel.definitions) {
|
|
54
|
+
for (const [name] of Object.entries(extensionModel.definitions)) {
|
|
55
|
+
for (const namespace of BUILT_IN_NAMESPACES) {
|
|
56
|
+
if (name.startsWith(`${namespace}.`)) {
|
|
57
|
+
delete extensionModel.definitions[name]
|
|
58
|
+
break
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
51
63
|
}
|
|
52
64
|
}
|
|
53
65
|
|
package/lib/init/constants.js
CHANGED
|
@@ -40,10 +40,11 @@ module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) =>
|
|
|
40
40
|
record.push(...Object.values(value))
|
|
41
41
|
}
|
|
42
42
|
else if (element.is_struct && element.type !== 'cds.Map') {
|
|
43
|
+
const {headers: structHeaders, records: structRecords} = resolveStruct(value, name);
|
|
43
44
|
if (i === 0) {
|
|
44
|
-
header.push(...
|
|
45
|
+
header.push(...structHeaders)
|
|
45
46
|
}
|
|
46
|
-
record.push(...
|
|
47
|
+
record.push(...structRecords)
|
|
47
48
|
}
|
|
48
49
|
else {
|
|
49
50
|
if (i === 0) header.push(name)
|
|
@@ -62,13 +63,28 @@ module.exports = async (data={}, csn, { headerOnly=false, separator=',' }={}) =>
|
|
|
62
63
|
|
|
63
64
|
data[entity.name] = res
|
|
64
65
|
|
|
65
|
-
function escape(value) {
|
|
66
|
-
if (typeof value === 'string' && (value.includes('"') || value.includes(separator))) {
|
|
67
|
-
return `"${value.replace(/"/g, '""')}"` // escape double quotes, then quote the value
|
|
68
|
-
}
|
|
69
|
-
return value
|
|
70
|
-
}
|
|
71
66
|
})
|
|
67
|
+
function escape(value) {
|
|
68
|
+
if (typeof value === 'string' && (value.includes('"') || value.includes(separator))) {
|
|
69
|
+
return `"${value.replace(/"/g, '""')}"` // escape double quotes, then quote the value
|
|
70
|
+
}
|
|
71
|
+
return value
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function resolveStruct(v, prefix) {
|
|
75
|
+
return Object.entries(v).reduce((acc, [key, val]) => {
|
|
76
|
+
//structs can be within structs
|
|
77
|
+
if (typeof val === 'object') {
|
|
78
|
+
const {headers, records} = resolveStruct(val, prefix + '_' + key);
|
|
79
|
+
acc.headers = acc.headers.concat(headers);
|
|
80
|
+
acc.records = acc.records.concat(records);
|
|
81
|
+
} else {
|
|
82
|
+
acc.headers.push(prefix + '_' + key);
|
|
83
|
+
acc.records.push(val);
|
|
84
|
+
}
|
|
85
|
+
return acc;
|
|
86
|
+
}, {headers: [], records: []});
|
|
87
|
+
}
|
|
72
88
|
}
|
|
73
89
|
return data
|
|
74
90
|
}
|
|
@@ -228,10 +228,10 @@ function dataForField(element, artifact, csn, record, data, parent, depth, refer
|
|
|
228
228
|
return randomIntInRange(range)
|
|
229
229
|
}
|
|
230
230
|
case 'cds.hana.REAL':
|
|
231
|
-
case 'cds.Decimal': {
|
|
232
|
-
const prec = element.precision ? Math.min(Math.pow(10, element.precision), Number.MAX_SAFE_INTEGER) : 100
|
|
233
|
-
const range = { from: 0, to: prec }
|
|
231
|
+
case 'cds.Decimal': { // Decimal(9,5), Decimal(9), Decimal(precision:5)
|
|
234
232
|
const scale = element.scale ?? (element.precision ? 0 : 2) // scale is 0 if only precision is given
|
|
233
|
+
const prec = element.precision ? Math.min(Math.pow(10, element.precision-scale), Number.MAX_SAFE_INTEGER) : 100
|
|
234
|
+
const range = { from: 0, to: prec }
|
|
235
235
|
annotatedIntRange(element, range)
|
|
236
236
|
return +(randomDecimalInRange(range).toFixed(scale))
|
|
237
237
|
}
|
|
@@ -13,8 +13,8 @@ module.exports = class HanaTemplate extends require('../../plugin') {
|
|
|
13
13
|
return 'database support for SAP HANA'
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
static hasInProduction(
|
|
17
|
-
return
|
|
16
|
+
static hasInProduction() {
|
|
17
|
+
return readProject().dependencies?.['@cap-js/hana']
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
async run() {
|
|
@@ -145,7 +145,7 @@ async function createExtCodeHandler(service, proj, out, force) {
|
|
|
145
145
|
// package.json
|
|
146
146
|
const pkgJson = await read('package.json')
|
|
147
147
|
const pkgJsonDelta = require('./files/extension/package.json')
|
|
148
|
-
|
|
148
|
+
cds.utils.merge ? cds.utils.merge(pkgJson, pkgJsonDelta) : merge(pkgJson, pkgJsonDelta)
|
|
149
149
|
await write('package.json', pkgJson, { spaces: 2 })
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -161,15 +161,19 @@ async function loadModel() {
|
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
164
|
+
// TODO remove w/ cds 10, copied from cds-utils.js
|
|
165
|
+
/**
|
|
166
|
+
* Polyfill for cds.utils.merge
|
|
167
|
+
* Simple helper to deep-merge two or more objects.
|
|
168
|
+
* Entries from `xs` overwrite entries in `o`.
|
|
169
|
+
* @example cds.utils.merge({foo:1},{bar:2},{baz:3})
|
|
170
|
+
* @returns `o` with entries from `xs` merged in.
|
|
171
|
+
*/
|
|
172
|
+
function merge (o,...xs) {
|
|
173
|
+
let v; for (let x of xs) for (let k in x)
|
|
174
|
+
if (k === '__proto__' || k === 'constructor') continue //> avoid prototype pollution
|
|
175
|
+
else o[k] = is_object(v=x[k]) ? merge(o[k]??={},v) : v
|
|
176
|
+
return o
|
|
175
177
|
}
|
|
178
|
+
const is_object = x => typeof x === 'object' && x !== null && !is_array(x)
|
|
179
|
+
const is_array = Array.isArray
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"express": "^4"
|
|
11
11
|
},
|
|
12
12
|
"engines": {
|
|
13
|
-
"node": "
|
|
13
|
+
"node": ">=20"
|
|
14
14
|
},
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"@cap-js/sqlite": "^2",
|
|
17
|
-
"@cap-js/cds-types": "^0.
|
|
17
|
+
"@cap-js/cds-types": "^0.11.0"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
20
|
"start": "cds-serve"
|
|
@@ -7,6 +7,12 @@ using { sap.capire.bookshop } from '../../db/schema';
|
|
|
7
7
|
//
|
|
8
8
|
|
|
9
9
|
annotate AdminService.Books with @(UI: {
|
|
10
|
+
HeaderInfo : {
|
|
11
|
+
TypeName : '{i18n>Book}',
|
|
12
|
+
TypeNamePlural: '{i18n>Books}',
|
|
13
|
+
Title : {Value: title},
|
|
14
|
+
Description : {Value: author.name}
|
|
15
|
+
},
|
|
10
16
|
Facets: [
|
|
11
17
|
{
|
|
12
18
|
$Type : 'UI.ReferenceFacet',
|
|
@@ -6,8 +6,9 @@ using { CatalogService } from '../../srv/cat-service.cds';
|
|
|
6
6
|
//
|
|
7
7
|
annotate CatalogService.Books with @(UI : {
|
|
8
8
|
HeaderInfo: {
|
|
9
|
-
TypeName : 'Book',
|
|
10
|
-
TypeNamePlural: 'Books',
|
|
9
|
+
TypeName : '{i18n>Book}',
|
|
10
|
+
TypeNamePlural: '{i18n>Books}',
|
|
11
|
+
Title : {Value: title},
|
|
11
12
|
Description : {Value : author}
|
|
12
13
|
},
|
|
13
14
|
HeaderFacets: [{
|
|
@@ -41,17 +41,6 @@ annotate Currencies with {
|
|
|
41
41
|
symbol @Common.Label: '{i18n>Currency}';
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
////////////////////////////////////////////////////////////////////////////
|
|
45
|
-
//
|
|
46
|
-
// Books Details
|
|
47
|
-
//
|
|
48
|
-
annotate my.Books with @(UI : {HeaderInfo : {
|
|
49
|
-
TypeName : '{i18n>Book}',
|
|
50
|
-
TypeNamePlural: '{i18n>Books}',
|
|
51
|
-
Title : { Value: title },
|
|
52
|
-
Description : { Value: author.name }
|
|
53
|
-
}, });
|
|
54
|
-
|
|
55
44
|
|
|
56
45
|
////////////////////////////////////////////////////////////////////////////
|
|
57
46
|
//
|