@sap/cds 7.5.2 → 7.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
- The format is based on [Keep a Changelog](http://keepachangelog.com/).
|
|
5
5
|
- This project adheres to [Semantic Versioning](http://semver.org/).
|
|
6
6
|
|
|
7
|
+
## Version 7.5.3 - 2024-01-23
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `cds.localize` and `cds build` produce `i18n.json` again with keys from all base languages
|
|
12
|
+
- `cds.compile.to.serviceinfo` now correctly parses SpringBoot config with nested objects, e.g. for `cds.odata-v4.endpoint.path`
|
|
13
|
+
- Recommend to use `chai` 4 for the time being, as `chai` 5 doesn't properly work yet (requires ESM, `chai-as-promised` not working)
|
|
14
|
+
- View resolving for entities using property names that are identical to entity names
|
|
15
|
+
- Direct modifications with `cds.fiori.bypass_draft` if `cds.fiori.draft_compat` is not enabled
|
|
16
|
+
- Draft: Field validation error message does not display the name of the field
|
|
17
|
+
|
|
7
18
|
## Version 7.5.2 - 2024-01-05
|
|
8
19
|
|
|
9
20
|
### Fixed
|
|
@@ -37,7 +48,7 @@
|
|
|
37
48
|
"csrf": { // this configuration implies `csrf: true`
|
|
38
49
|
"method": "get",
|
|
39
50
|
"url": "..."
|
|
40
|
-
}
|
|
51
|
+
}
|
|
41
52
|
}
|
|
42
53
|
}
|
|
43
54
|
}
|
|
@@ -79,10 +79,12 @@ module.exports = (model, options={}) => {
|
|
|
79
79
|
if (file) {
|
|
80
80
|
const yaml = cds.load.yaml(file)
|
|
81
81
|
for (let yamlDoc of Array.isArray(yaml) ? yaml : [yaml]) {
|
|
82
|
-
|
|
82
|
+
let cds = yamlDoc?.cds;
|
|
83
83
|
if (!cds) continue
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
cds = _normalizeSpringBootCfg(cds)
|
|
85
|
+
// https://cap.cloud.sap/docs/java/application-services#configure-base-path
|
|
86
|
+
return cds.odataV4?.endpoint?.path || cds.odataV2?.endpoint?.path
|
|
87
|
+
|| cds['odata-v4']?.endpoint?.path || cds['odata-v2']?.endpoint?.path // alternative config
|
|
86
88
|
|| javaPrefixDefault
|
|
87
89
|
}
|
|
88
90
|
return javaPrefixDefault
|
|
@@ -92,4 +94,24 @@ module.exports = (model, options={}) => {
|
|
|
92
94
|
return is_java && javaPrefixDefault
|
|
93
95
|
}
|
|
94
96
|
|
|
97
|
+
// SpringBoot allows dots in keys to express nested objects, so we need to split them
|
|
98
|
+
function _normalizeSpringBootCfg(obj) {
|
|
99
|
+
if (typeof obj !== 'object') return obj
|
|
100
|
+
Object.keys(obj).forEach(k => {
|
|
101
|
+
const prop = k.split('.')
|
|
102
|
+
const last = prop.pop()
|
|
103
|
+
// and define the object if not already defined
|
|
104
|
+
const res = prop.reduce((o, key) => {
|
|
105
|
+
// define the object if not defined and return
|
|
106
|
+
return o[key] = o[key] ?? {}
|
|
107
|
+
}, obj)
|
|
108
|
+
res[last] = obj[k]
|
|
109
|
+
// recursively normalize
|
|
110
|
+
_normalizeSpringBootCfg(obj[k])
|
|
111
|
+
// delete the original property from object if it was rewritten
|
|
112
|
+
if (prop.length) delete obj[k]
|
|
113
|
+
})
|
|
114
|
+
return obj
|
|
115
|
+
}
|
|
116
|
+
|
|
95
117
|
}
|
package/lib/i18n/localize.js
CHANGED
|
@@ -140,7 +140,10 @@ function bundle4 (model, locale) {
|
|
|
140
140
|
if (!folders.length) return bundles[locale] = {}
|
|
141
141
|
|
|
142
142
|
const {i18n} = cds.env
|
|
143
|
-
let bundle = null
|
|
143
|
+
let bundle = Object.create(null)
|
|
144
|
+
bundle.toJSON = jsonWithAllProps // allows JSON.stringify with all inherited props
|
|
145
|
+
|
|
146
|
+
let locales = (
|
|
144
147
|
locale === i18n.fallback_bundle ? [ i18n.fallback_bundle ] :
|
|
145
148
|
locale === i18n.default_language ? [ i18n.fallback_bundle, i18n.default_language ] :
|
|
146
149
|
[ i18n.fallback_bundle, i18n.default_language, locale ]
|
|
@@ -158,6 +161,7 @@ function bundle4 (model, locale) {
|
|
|
158
161
|
Object.assign (b, next)
|
|
159
162
|
}
|
|
160
163
|
}
|
|
164
|
+
|
|
161
165
|
return bundles[locale] = bundle
|
|
162
166
|
}
|
|
163
167
|
|
|
@@ -255,3 +259,13 @@ function escapeXmlAttr (str) {
|
|
|
255
259
|
}
|
|
256
260
|
|
|
257
261
|
const escapeJson = str => str.replace(/"/g, '\\"')
|
|
262
|
+
|
|
263
|
+
function jsonWithAllProps() {
|
|
264
|
+
const res = {}
|
|
265
|
+
for (let key in this) {
|
|
266
|
+
if (typeof this[key] !== 'function') {
|
|
267
|
+
res[key] = this[key]
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return res
|
|
271
|
+
}
|
package/lib/utils/cds-test.js
CHANGED
|
@@ -168,7 +168,7 @@ class Test extends require('./axios') {
|
|
|
168
168
|
function require (mod) { try { return module.require(mod) } catch(e) {
|
|
169
169
|
if (e.code === 'MODULE_NOT_FOUND') throw new Error (`
|
|
170
170
|
Failed to load required package '${mod}'. Please add it thru:
|
|
171
|
-
npm add -D chai chai-as-promised chai-subset
|
|
171
|
+
npm add -D chai@4 chai-as-promised chai-subset
|
|
172
172
|
`)}}
|
|
173
173
|
}
|
|
174
174
|
get assert() { return this.chai.assert }
|
|
@@ -237,28 +237,13 @@ const _newInsertColumns = (columns = [], transition) => {
|
|
|
237
237
|
const _newWhereRef = (newWhereElement, transition, alias, tableName, isSubSelect) => {
|
|
238
238
|
const newRef = Array.isArray(newWhereElement.ref) ? [...newWhereElement.ref] : [newWhereElement.ref]
|
|
239
239
|
|
|
240
|
-
if (newRef[0] === alias) {
|
|
240
|
+
if (newRef.length > 1 && newRef[0] === alias) {
|
|
241
241
|
const mapped = transition.mapping.get(newRef[1])
|
|
242
|
-
if (mapped)
|
|
243
|
-
|
|
244
|
-
transition.queryTarget.query?.SELECT?.from.as ??
|
|
245
|
-
transition.queryTarget.query?.SELECT?.from.ref.at(-1).split('.').pop()
|
|
246
|
-
const newMapped = []
|
|
247
|
-
|
|
248
|
-
if (tableAlias && mapped.ref[0] === tableAlias) {
|
|
249
|
-
// remove table alias from mapped array
|
|
250
|
-
newMapped.push(...mapped.ref.slice(1))
|
|
251
|
-
} else {
|
|
252
|
-
newMapped.push(...mapped.ref)
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// we assume it's a foreign key or single element
|
|
256
|
-
newRef[1] = newMapped.join('_')
|
|
257
|
-
}
|
|
258
|
-
} else if (newRef[0] === tableName) {
|
|
242
|
+
if (mapped) newRef[1] = mapped.ref.join('_')
|
|
243
|
+
} else if (newRef.length > 1 && newRef[0] === tableName) {
|
|
259
244
|
newRef[0] = transition.target.name
|
|
260
245
|
const mapped = transition.mapping.get(newRef[1])
|
|
261
|
-
if (mapped) newRef[1] = mapped.ref
|
|
246
|
+
if (mapped) newRef[1] = mapped.ref.join('_')
|
|
262
247
|
} else {
|
|
263
248
|
const mapped = transition.mapping.get(newRef[0])
|
|
264
249
|
if (isSubSelect && mapped && newRef.length === 1) {
|
|
@@ -28,6 +28,13 @@ const DRAFT_ADMIN_ELEMENTS = [
|
|
|
28
28
|
'DraftIsProcessedByMe'
|
|
29
29
|
]
|
|
30
30
|
|
|
31
|
+
const reject_bypassed_draft = req => {
|
|
32
|
+
const msg =
|
|
33
|
+
!cds.profiles?.includes('production') &&
|
|
34
|
+
'`cds.env.fiori.bypass_draft` must be enabled to support the directly modification of active instances.'
|
|
35
|
+
return req.reject(501, msg)
|
|
36
|
+
}
|
|
37
|
+
|
|
31
38
|
const _fillIsActiveEntity = (row, IsActiveEntity, target) => {
|
|
32
39
|
if (target.drafts) row.IsActiveEntity = IsActiveEntity
|
|
33
40
|
for (const key in target.associations) {
|
|
@@ -203,10 +210,11 @@ cds.ApplicationService.prototype.handle = async function (req) {
|
|
|
203
210
|
}
|
|
204
211
|
|
|
205
212
|
if (req.event === 'NEW' || req.event === 'CANCEL' || req.event === 'draftPrepare') {
|
|
206
|
-
if (
|
|
207
|
-
if (req.
|
|
213
|
+
if (req.event === 'draftPrepare' && draftParams.IsActiveEntity) req.reject(400)
|
|
214
|
+
if (req.event === 'NEW' && req.data?.IsActiveEntity === true) {
|
|
215
|
+
if (!cds.env.fiori.bypass_draft) return reject_bypassed_draft(req)
|
|
208
216
|
const containsDraftRoot =
|
|
209
|
-
this.model.
|
|
217
|
+
this.model.definitions[query.INSERT.into?.ref?.[0]?.id || query.INSERT.into?.ref?.[0] || query.INSERT.into][
|
|
210
218
|
'@Common.DraftRoot.ActivationAction'
|
|
211
219
|
]
|
|
212
220
|
|
|
@@ -380,16 +388,11 @@ cds.ApplicationService.prototype.handle = async function (req) {
|
|
|
380
388
|
|
|
381
389
|
LOG.debug('patch active')
|
|
382
390
|
|
|
383
|
-
if (!cds.env.fiori.bypass_draft)
|
|
384
|
-
const msg =
|
|
385
|
-
!cds.profiles?.includes('production') &&
|
|
386
|
-
'`cds.env.fiori.bypass_draft` must be enabled to support updating active instances.'
|
|
387
|
-
return req.reject(403, msg)
|
|
388
|
-
}
|
|
391
|
+
if (!cds.env.fiori.bypass_draft) return reject_bypassed_draft(req)
|
|
389
392
|
|
|
390
393
|
const entityRef = query.UPDATE.entity.ref
|
|
391
394
|
|
|
392
|
-
if (!this.model.
|
|
395
|
+
if (!this.model.definitions[entityRef[0].id]['@Common.DraftRoot.ActivationAction']) {
|
|
393
396
|
req.reject(403, 'DRAFT_MODIFICATION_ONLY_VIA_ROOT')
|
|
394
397
|
}
|
|
395
398
|
|
|
@@ -716,7 +719,7 @@ function _cleanseParams(params, target) {
|
|
|
716
719
|
if (key === 'IsActiveEntity') {
|
|
717
720
|
const value = params[key]
|
|
718
721
|
delete params[key]
|
|
719
|
-
|
|
722
|
+
Object.defineProperty(params, key, { value, enumerable: false })
|
|
720
723
|
}
|
|
721
724
|
}
|
|
722
725
|
}
|