@sap/cds 5.9.0 → 5.9.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 +12 -0
- package/app/fiori/routes.js +15 -8
- package/lib/compile/cdsc.js +1 -19
- package/lib/compile/etc/_localized.js +2 -2
- package/lib/compile/for/java.js +1 -1
- package/lib/compile/for/nodejs.js +1 -1
- package/lib/compile/for/odata.js +1 -1
- package/libx/_runtime/cds-services/adapter/odata-v4/utils/dispatcherUtils.js +6 -5
- package/libx/_runtime/common/utils/cqn2cqn4sql.js +2 -2
- package/libx/_runtime/db/data-conversion/post-processing.js +5 -0
- package/libx/_runtime/db/sql-builder/FunctionBuilder.js +8 -8
- package/libx/_runtime/remote/utils/client.js +4 -6
- package/libx/odata/cqn2odata.js +24 -27
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@
|
|
|
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 5.9.1 - 2022-03-31
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Function arguments might be escaped too often
|
|
12
|
+
- URL encoding for remote services for CQN queries
|
|
13
|
+
- `cds serve` during development again redirects URLs with for UI apps in a folder with the same name as a service, so `/foo/webapp` would redirect to `/foo`. This got broken in 5.8.3.
|
|
14
|
+
- Endless loop in localization handling
|
|
15
|
+
- Ensure service impl while extending entity from the service
|
|
16
|
+
- Post-processing of custom draft queries
|
|
17
|
+
- No minifying of CSN artifacts for Java build
|
|
18
|
+
|
|
7
19
|
## Version 5.9.0 - 2022-03-25
|
|
8
20
|
|
|
9
21
|
### Added
|
package/app/fiori/routes.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
const cds = require('../../lib')
|
|
2
|
+
const DEBUG = cds.debug('fiori/routes')
|
|
3
|
+
const {dirname, relative, join} = require('path')
|
|
2
4
|
|
|
3
5
|
// Only for local cds runs w/o approuter:
|
|
4
6
|
// If there is a relative URL in UI5's manifest.json for the datasource,
|
|
@@ -11,16 +13,20 @@ cds.on ('bootstrap', app => {
|
|
|
11
13
|
const v2Prefix = (env.odata.v2proxy && env.odata.v2proxy.urlpath) || '/v2'
|
|
12
14
|
const serviceForUri = {}
|
|
13
15
|
|
|
14
|
-
dataSourceURIs (env.folders.app).forEach(
|
|
15
|
-
|
|
16
|
+
dataSourceURIs (env.folders.app).forEach(({appPath, dataSourceUri}) => {
|
|
17
|
+
const uiRoutes = [
|
|
18
|
+
join('/', appPath, dataSourceUri, '*'), // /uiApp/webapp/browse/*
|
|
19
|
+
join('/', appPath, '*', dataSourceUri, '*') // /uiApp/webapp/*/browse/*
|
|
20
|
+
].map(r => r.replace(/\\/g, '/')) // handle Windows \
|
|
21
|
+
DEBUG && DEBUG ('Register routes', uiRoutes)
|
|
22
|
+
|
|
23
|
+
app.use(uiRoutes, ({originalUrl}, res, next)=> {
|
|
16
24
|
// any of our special URLs ($fiori-, $api-docs) ? -> next
|
|
17
25
|
if (originalUrl.startsWith('/$')) return next()
|
|
18
|
-
// is there a service starting with the URL? -> next
|
|
19
|
-
if (cds.service.providers.find (srv => originalUrl.startsWith(srv.path))) return next()
|
|
20
26
|
|
|
21
27
|
// is there a service for '[prefix]/browse' ?
|
|
22
|
-
const srv = serviceForUri[
|
|
23
|
-
cds.service.providers.find (srv => ('/'+
|
|
28
|
+
const srv = serviceForUri[dataSourceUri] || (serviceForUri[dataSourceUri] =
|
|
29
|
+
cds.service.providers.find (srv => ('/'+dataSourceUri).lastIndexOf(srv.path) >=0))
|
|
24
30
|
if (srv) {
|
|
25
31
|
let redirectUrl
|
|
26
32
|
// odata-proxy may be in the line with its /v2 prefix. Make sure we retain it.
|
|
@@ -30,7 +36,7 @@ cds.on ('bootstrap', app => {
|
|
|
30
36
|
else // --> /browse/webapp[/prefix]/browse/ -> /browse
|
|
31
37
|
redirectUrl = originalUrl.substring(originalUrl.lastIndexOf(srv.path+'/'))
|
|
32
38
|
if (originalUrl !== redirectUrl) {// safeguard to prevent running in loops
|
|
33
|
-
|
|
39
|
+
DEBUG && DEBUG ('Redirecting', {src: originalUrl}, '~>', {target: redirectUrl})
|
|
34
40
|
return res.redirect (308, redirectUrl)
|
|
35
41
|
}
|
|
36
42
|
}
|
|
@@ -41,10 +47,11 @@ cds.on ('bootstrap', app => {
|
|
|
41
47
|
function dataSourceURIs (dir) {
|
|
42
48
|
const uris = new Set()
|
|
43
49
|
find (dir, ['*/manifest.json', '*/*/manifest.json']).forEach(file => {
|
|
50
|
+
const appPath = relative(join(cds.root, dir), dirname(file))
|
|
44
51
|
const {dataSources: ds} = JSON.parse(fs.readFileSync(file))['sap.app'] || {}
|
|
45
52
|
Object.keys (ds||[])
|
|
46
53
|
.filter (k => ds[k].uri && !ds[k].uri.startsWith('/')) // only consider relative URLs)
|
|
47
|
-
.forEach(k => uris.add(ds[k].uri))
|
|
54
|
+
.forEach(k => uris.add({ appPath, dataSourceUri: ds[k].uri }))
|
|
48
55
|
})
|
|
49
56
|
return uris
|
|
50
57
|
}
|
package/lib/compile/cdsc.js
CHANGED
|
@@ -105,25 +105,7 @@ const _options = {for: Object.assign (_options4, {
|
|
|
105
105
|
*/
|
|
106
106
|
module.exports = exports = {__proto__:compile, _options,
|
|
107
107
|
for: {__proto__: compile.for,
|
|
108
|
-
odata: (csn,o) =>
|
|
109
|
-
if (features.ucsn) {
|
|
110
|
-
const { cloneCsn } = require('@sap/cds-compiler/lib/model/csnUtils') // REVISIT: This should be done by the compiler
|
|
111
|
-
if (compile.version() >= "2.12.1") {
|
|
112
|
-
const generateDrafts = require('@sap/cds-compiler/lib/transform/draft/odata')
|
|
113
|
-
const compiled = generateDrafts(cloneCsn(csn, {}), { messages: [] })
|
|
114
|
-
compiled.meta._4odata = true
|
|
115
|
-
return compiled
|
|
116
|
-
} else {
|
|
117
|
-
// not yet in compiler branch, can't add drafts
|
|
118
|
-
const cloned = cloneCsn(csn, {})
|
|
119
|
-
cloned.meta._4odata = true
|
|
120
|
-
return cloned
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
const compiled = compile.for.odata (csn, _options.for.odata(o))
|
|
124
|
-
compiled.meta._4odata = true
|
|
125
|
-
return compiled
|
|
126
|
-
},
|
|
108
|
+
odata: (csn,o) => compile.for.odata (csn, _options.for.odata(o)),
|
|
127
109
|
},
|
|
128
110
|
to: {__proto__: compile.to,
|
|
129
111
|
edmx: Object.assign ((csn,o) => compile.to.edmx (csn, _options.for.edm(o)), {
|
|
@@ -96,13 +96,13 @@ function unfold_csn (m) { // NOSONAR
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
|
|
99
|
-
const $localized = '$$localized', _is_localized = (d,_path) => {
|
|
99
|
+
const $localized = '$$localized', _is_localized = (d,_path={}) => {
|
|
100
100
|
if (d.own($localized)) return true
|
|
101
101
|
if (!d.elements || d.name.endsWith('.texts')) return false
|
|
102
102
|
// if (d.elements.texts && d.elements.texts.target === `${d.name}.texts`) return d.set($localized,true)
|
|
103
103
|
for (let each in d.elements) {
|
|
104
104
|
const e = d.elements [each]
|
|
105
|
-
if (e.localized || e._target && !(_path && e._target.name in _path) && _is_localized(e._target,
|
|
105
|
+
if (e.localized || e._target && !(_path && e._target.name in _path) && _is_localized(e._target,Object.assign(_path, { [d.name]:1 }))) {
|
|
106
106
|
return d.set($localized,true)
|
|
107
107
|
}
|
|
108
108
|
}
|
package/lib/compile/for/java.js
CHANGED
|
@@ -4,7 +4,7 @@ const _cached = Symbol('for Java')
|
|
|
4
4
|
module.exports = function cds_compile_for_java (csn,o) {
|
|
5
5
|
if (!csn) return
|
|
6
6
|
const cached = csn[_cached]; if (cached) return cached
|
|
7
|
-
csn = cds.minify (csn)
|
|
7
|
+
// csn = cds.minify (csn)
|
|
8
8
|
csn = cds.compile.for.drafts (csn,o)
|
|
9
9
|
// Add a parsed _where clause for @restrict.{grant,where} annotations
|
|
10
10
|
if (csn.definitions) for (let {'@restrict':rr} of Object.values(csn.definitions)) if (rr) {
|
|
@@ -4,7 +4,7 @@ const _cached = Symbol('for Node.js')
|
|
|
4
4
|
module.exports = function cds_compile_for_nodejs (csn,o) {
|
|
5
5
|
if (!csn) return
|
|
6
6
|
const cached = csn[_cached]; if (cached) return cached
|
|
7
|
-
csn = cds.minify (csn)
|
|
7
|
+
// csn = cds.minify (csn)
|
|
8
8
|
csn = cds.compile.for.drafts (csn,o) //> creates a partial copy -> avoid any cds.linked() before
|
|
9
9
|
csn = cds.compile._localized.unfold_csn (csn)
|
|
10
10
|
csn = cds.linked (csn)
|
package/lib/compile/for/odata.js
CHANGED
|
@@ -17,12 +17,13 @@ function createOdataService(service) {
|
|
|
17
17
|
return odataService
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
const { Service } = require('../../../../../../lib/serve/factory')
|
|
20
21
|
async function createNewService(name, csn, defaultOptions) {
|
|
21
|
-
const options = Object.assign({}, defaultOptions
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
await service.init
|
|
25
|
-
if (options.impl) service.
|
|
22
|
+
const options = Object.assign({}, defaultOptions)
|
|
23
|
+
const service = new Service(name, csn, options)
|
|
24
|
+
if (!service.path) service.path = cds.service.path4(service)
|
|
25
|
+
if (service.init) await service.prepend(service.init)
|
|
26
|
+
if (options.impl) await service.prepend(options.impl)
|
|
26
27
|
|
|
27
28
|
return createOdataService(service)
|
|
28
29
|
}
|
|
@@ -783,8 +783,8 @@ const _convertSelect = (query, model, _options) => {
|
|
|
783
783
|
if (target && target._unresolved && typeof target.name === 'string') {
|
|
784
784
|
target = model.definitions[ensureNoDraftsSuffix(target.name)] || target
|
|
785
785
|
}
|
|
786
|
-
if (target && !target
|
|
787
|
-
const cols = getColumns(target, { onlyNames: true })
|
|
786
|
+
if (target && !Object.prototype.hasOwnProperty.call(target, '_unresolved')) {
|
|
787
|
+
const cols = getColumns(target, { onlyNames: true, filterVirtual: true })
|
|
788
788
|
query.columns(cols)
|
|
789
789
|
if (target._isDraftEnabled && query._target._unresolved) {
|
|
790
790
|
query.SELECT.columns.push(...getDraftColumnsCQNForDraft(target))
|
|
@@ -192,6 +192,11 @@ const _getMapperForListedElements = (conversionMap, csn, cqn) => {
|
|
|
192
192
|
* @private
|
|
193
193
|
*/
|
|
194
194
|
const getPostProcessMapper = (conversionMap, csn = {}, cqn = {}) => {
|
|
195
|
+
// No mapper defined or irrelevant as no READ request
|
|
196
|
+
if (!Object.prototype.hasOwnProperty.call(cqn, 'SELECT')) {
|
|
197
|
+
return new Map()
|
|
198
|
+
}
|
|
199
|
+
|
|
195
200
|
return cqn.SELECT.columns ? _getMapperForListedElements(conversionMap, csn, cqn) : new Map()
|
|
196
201
|
}
|
|
197
202
|
|
|
@@ -56,12 +56,13 @@ class FunctionBuilder extends BaseBuilder {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
_escapeLikeParameters(parameters) {
|
|
59
|
-
|
|
60
|
-
if (parameter.val) parameter
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
59
|
+
return parameters.map(parameter => {
|
|
60
|
+
if (parameter.val) return { ...parameter, val: parameter.val.replace(/(\^|_|%)/g, '^$1') }
|
|
61
|
+
if (parameter.func) {
|
|
62
|
+
return { ...parameter, args: this._escapeLikeParameters(parameter.args) }
|
|
63
|
+
}
|
|
64
|
+
return parameter
|
|
65
|
+
})
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
_handleFunction() {
|
|
@@ -117,8 +118,7 @@ class FunctionBuilder extends BaseBuilder {
|
|
|
117
118
|
const functionName = this._functionName()
|
|
118
119
|
const not = functionName.startsWith('not') ? 'NOT ' : ''
|
|
119
120
|
const columns = this._columns(args)
|
|
120
|
-
const params = args.slice(1)
|
|
121
|
-
this._escapeLikeParameters(params)
|
|
121
|
+
const params = this._escapeLikeParameters(args.slice(1))
|
|
122
122
|
|
|
123
123
|
const _pattern = (() => {
|
|
124
124
|
if (functionName.includes('contains')) return _ => ["'%'", _, "'%'"]
|
|
@@ -339,12 +339,10 @@ const _cqnToReqOptions = (query, kind, model, target) => {
|
|
|
339
339
|
const queryObject = cds.odata.urlify(query, { kind, model })
|
|
340
340
|
const reqOptions = {
|
|
341
341
|
method: queryObject.method,
|
|
342
|
-
url:
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
.replace(/ \)/g, ')')
|
|
347
|
-
)
|
|
342
|
+
url: queryObject.path
|
|
343
|
+
// ugly workaround for Okra not allowing spaces in ( x eq 1 )
|
|
344
|
+
.replace(/\( /g, '(')
|
|
345
|
+
.replace(/ \)/g, ')')
|
|
348
346
|
}
|
|
349
347
|
if (queryObject.method !== 'GET' && queryObject.method !== 'HEAD') {
|
|
350
348
|
reqOptions.data = kind === 'odata-v2' ? convertV2PayloadData(queryObject.body, target) : queryObject.body
|
package/libx/odata/cqn2odata.js
CHANGED
|
@@ -83,14 +83,10 @@ function _args(args) {
|
|
|
83
83
|
|
|
84
84
|
if (hasValidProps(cur, 'func', 'args')) {
|
|
85
85
|
res.push(`${cur.func}(${_args(cur.args)})`)
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (hasValidProps(cur, '
|
|
89
|
-
res.push(cur
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (hasValidProps(cur, 'val')) {
|
|
93
|
-
res.push(formatVal(cur.val))
|
|
86
|
+
} else if (hasValidProps(cur, 'ref')) {
|
|
87
|
+
res.push(_format(cur))
|
|
88
|
+
} else if (hasValidProps(cur, 'val')) {
|
|
89
|
+
res.push(_format(cur))
|
|
94
90
|
}
|
|
95
91
|
}
|
|
96
92
|
|
|
@@ -98,13 +94,13 @@ function _args(args) {
|
|
|
98
94
|
}
|
|
99
95
|
|
|
100
96
|
const _in = (column, /* in */ collection, target, kind, isLambda) => {
|
|
101
|
-
const ref =
|
|
97
|
+
const ref = _format(column, null, target, kind, isLambda)
|
|
102
98
|
// { val: [ 1, 2, 3 ] } or { list: [ { val: 1}, { val: 2}, { val: 3} ] }
|
|
103
99
|
const values = collection.val || collection.list
|
|
104
100
|
if (values && values.length) {
|
|
105
101
|
// REVISIT: what about OData `in` operator?
|
|
106
|
-
const expressions = values.map(value => `${ref}
|
|
107
|
-
return expressions.join('
|
|
102
|
+
const expressions = values.map(value => `${ref}%20eq%20${_format(value, ref, target, kind, isLambda)}`)
|
|
103
|
+
return expressions.join('%20or%20')
|
|
108
104
|
}
|
|
109
105
|
}
|
|
110
106
|
|
|
@@ -119,9 +115,10 @@ const _odataV2Func = (func, args) => {
|
|
|
119
115
|
}
|
|
120
116
|
|
|
121
117
|
const _format = (cur, element, target, kind, isLambda) => {
|
|
122
|
-
if (typeof cur !== 'object') return formatVal(cur, element, target, kind)
|
|
123
|
-
if (hasValidProps(cur, 'ref'))
|
|
124
|
-
|
|
118
|
+
if (typeof cur !== 'object') return encodeURIComponent(formatVal(cur, element, target, kind))
|
|
119
|
+
if (hasValidProps(cur, 'ref'))
|
|
120
|
+
return encodeURIComponent(isLambda ? [LAMBDA_VARIABLE, ...cur.ref].join('/') : cur.ref.join('/'))
|
|
121
|
+
if (hasValidProps(cur, 'val')) return encodeURIComponent(formatVal(cur.val, element, target, kind))
|
|
125
122
|
if (hasValidProps(cur, 'xpr')) return `(${_xpr(cur.xpr, target, kind, isLambda)})`
|
|
126
123
|
// REVISIT: How to detect the types for all functions?
|
|
127
124
|
if (hasValidProps(cur, 'func', 'args')) {
|
|
@@ -156,7 +153,7 @@ function _xpr(expr, target, kind, isLambda) {
|
|
|
156
153
|
} else if (isOrIsNotValue) {
|
|
157
154
|
// REVISIT: "is" only used for null values?
|
|
158
155
|
const operator = isOrIsNotValue[1] /* 'is not' */ ? 'ne' : 'eq'
|
|
159
|
-
res.push(...[operator,
|
|
156
|
+
res.push(...[operator, _format({ val: isOrIsNotValue[2] })])
|
|
160
157
|
} else if (cur === 'between') {
|
|
161
158
|
// ref gt low.val and ref lt high.val
|
|
162
159
|
const between = [expr[i - 1], 'gt', expr[i + 1], 'and', expr[i - 1], 'lt', expr[i + 3]]
|
|
@@ -188,7 +185,7 @@ function _xpr(expr, target, kind, isLambda) {
|
|
|
188
185
|
}
|
|
189
186
|
}
|
|
190
187
|
|
|
191
|
-
return res.join('
|
|
188
|
+
return res.join('%20')
|
|
192
189
|
}
|
|
193
190
|
|
|
194
191
|
const _keysOfWhere = (where, kind, target) => {
|
|
@@ -202,11 +199,11 @@ const _keysOfWhere = (where, kind, target) => {
|
|
|
202
199
|
const res = []
|
|
203
200
|
for (const cur of where) {
|
|
204
201
|
if (hasValidProps(cur, 'ref')) {
|
|
205
|
-
res.push(cur
|
|
202
|
+
res.push(_format(cur))
|
|
206
203
|
} else if (hasValidProps(cur, 'val')) {
|
|
207
204
|
// find previous ref
|
|
208
205
|
const element = res[res.length - 2]
|
|
209
|
-
res.push(
|
|
206
|
+
res.push(_format(cur, element, target, kind))
|
|
210
207
|
} else if (cur === 'and') {
|
|
211
208
|
res.push(',')
|
|
212
209
|
} else {
|
|
@@ -267,15 +264,15 @@ const _parseColumnsV2 = (columns, prefix = []) => {
|
|
|
267
264
|
|
|
268
265
|
if (hasValidProps(column, 'expand')) {
|
|
269
266
|
const parsed = _parseColumnsV2(column.expand, [refName])
|
|
270
|
-
expand.push(refName, ...parsed.expand)
|
|
267
|
+
expand.push(encodeURIComponent(refName), ...parsed.expand)
|
|
271
268
|
select.push(...parsed.select)
|
|
272
269
|
} else {
|
|
273
|
-
select.push(refName)
|
|
270
|
+
select.push(encodeURIComponent(refName))
|
|
274
271
|
}
|
|
275
272
|
}
|
|
276
273
|
|
|
277
274
|
if (column === '*') {
|
|
278
|
-
select.push(`${prefix.join('/')}/*`)
|
|
275
|
+
select.push(encodeURIComponent(`${prefix.join('/')}/*`))
|
|
279
276
|
}
|
|
280
277
|
}
|
|
281
278
|
|
|
@@ -288,7 +285,7 @@ const _parseColumns = columns => {
|
|
|
288
285
|
|
|
289
286
|
for (const column of columns) {
|
|
290
287
|
if (hasValidProps(column, 'ref')) {
|
|
291
|
-
let refName = column
|
|
288
|
+
let refName = _format(column)
|
|
292
289
|
if (hasValidProps(column, 'expand')) {
|
|
293
290
|
// REVISIT: incomplete, see test Foo?$expand=invoices($count=true;$expand=item($search="some"))
|
|
294
291
|
if (!columns.some(c => !c.expand)) select.push(refName)
|
|
@@ -350,16 +347,16 @@ function $orderBy(orderBy) {
|
|
|
350
347
|
|
|
351
348
|
for (const cur of orderBy) {
|
|
352
349
|
if (hasValidProps(cur, 'ref', 'sort')) {
|
|
353
|
-
res.push(cur
|
|
350
|
+
res.push(_format(cur) + '%20' + cur.sort)
|
|
354
351
|
continue
|
|
355
352
|
}
|
|
356
353
|
|
|
357
354
|
if (hasValidProps(cur, 'ref')) {
|
|
358
|
-
res.push(cur
|
|
355
|
+
res.push(_format(cur))
|
|
359
356
|
}
|
|
360
357
|
|
|
361
358
|
if (hasValidProps(cur, 'func', 'sort')) {
|
|
362
|
-
res.push(`${cur.func}(${_args(cur.args)})` + '
|
|
359
|
+
res.push(`${cur.func}(${_args(cur.args)})` + '%20' + cur.sort)
|
|
363
360
|
continue
|
|
364
361
|
}
|
|
365
362
|
|
|
@@ -382,7 +379,7 @@ function parseSearch(search) {
|
|
|
382
379
|
|
|
383
380
|
if (hasValidProps(cur, 'val')) {
|
|
384
381
|
// search term must not be formatted
|
|
385
|
-
res.push(`"${cur.val}"`)
|
|
382
|
+
res.push(`"${encodeURIComponent(cur.val)}"`)
|
|
386
383
|
}
|
|
387
384
|
|
|
388
385
|
if (typeof cur === 'string') {
|
|
@@ -398,7 +395,7 @@ function parseSearch(search) {
|
|
|
398
395
|
}
|
|
399
396
|
|
|
400
397
|
function $search(search, kind) {
|
|
401
|
-
const expr = parseSearch(search).join('
|
|
398
|
+
const expr = parseSearch(search).join('%20').replace('(%20', '(').replace('%20)', ')')
|
|
402
399
|
|
|
403
400
|
if (expr) {
|
|
404
401
|
// odata-v2 may support custom query option "search"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sap/cds",
|
|
3
|
-
"version": "5.9.
|
|
3
|
+
"version": "5.9.1",
|
|
4
4
|
"description": "SAP Cloud Application Programming Model - CDS for Node.js",
|
|
5
5
|
"homepage": "https://cap.cloud.sap/",
|
|
6
6
|
"keywords": [
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@sap-cloud-sdk/core": "^1.41",
|
|
34
34
|
"@sap-cloud-sdk/util": "^1.41",
|
|
35
|
-
"@sap/cds-compiler": "^2.
|
|
35
|
+
"@sap/cds-compiler": "^2.13.0",
|
|
36
36
|
"@sap/cds-foss": "^3"
|
|
37
37
|
},
|
|
38
38
|
"husky": {
|