@sap/cds 6.1.3 → 6.2.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.
Files changed (206) hide show
  1. package/CHANGELOG.md +77 -8
  2. package/apis/cds.d.ts +18 -6
  3. package/apis/connect.d.ts +1 -1
  4. package/apis/cqn.d.ts +1 -1
  5. package/apis/log.d.ts +23 -5
  6. package/apis/ql.d.ts +128 -61
  7. package/apis/services.d.ts +11 -0
  8. package/apis/test.d.ts +61 -0
  9. package/apis/utils.d.ts +15 -0
  10. package/app/fiori/preview.js +1 -0
  11. package/bin/build/buildTaskEngine.js +70 -22
  12. package/bin/build/buildTaskFactory.js +18 -11
  13. package/bin/build/buildTaskHandler.js +1 -1
  14. package/bin/build/buildTaskProviderFactory.js +3 -13
  15. package/bin/build/constants.js +0 -1
  16. package/bin/build/index.js +14 -6
  17. package/bin/build/provider/buildTaskHandlerEdmx.js +2 -3
  18. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +2 -2
  19. package/bin/build/provider/buildTaskHandlerInternal.js +3 -6
  20. package/bin/build/provider/buildTaskProviderInternal.js +51 -39
  21. package/bin/build/provider/fiori/index.js +3 -3
  22. package/bin/build/provider/hana/2migration.js +1 -1
  23. package/bin/build/provider/hana/index.js +34 -27
  24. package/bin/build/provider/java/index.js +6 -7
  25. package/bin/build/provider/mtx/index.js +20 -18
  26. package/bin/build/provider/mtx/resourcesTarBuilder.js +8 -11
  27. package/bin/build/provider/mtx-sidecar/index.js +13 -17
  28. package/bin/build/provider/nodejs/index.js +8 -7
  29. package/bin/build/util.js +22 -4
  30. package/bin/cds.js +8 -4
  31. package/bin/deploy/to-hana/cfUtil.js +53 -18
  32. package/bin/mtx/in-cds.js +1 -0
  33. package/bin/serve.js +37 -30
  34. package/lib/auth/basic-auth.js +33 -0
  35. package/lib/auth/dummy-auth.js +7 -0
  36. package/lib/auth/ias-auth.js +2 -0
  37. package/lib/auth/index.js +31 -0
  38. package/lib/auth/jwt-auth.js +3 -0
  39. package/lib/auth/mocked-users.js +72 -0
  40. package/lib/auth/passport-basic.js +12 -0
  41. package/lib/auth/passport-digest.js +14 -0
  42. package/lib/auth/xsuaa-auth.js +3 -0
  43. package/lib/compile/cds-compile.js +3 -3
  44. package/lib/compile/to/cdl.js +5 -1
  45. package/lib/compile/to/edm.js +8 -0
  46. package/lib/compile/to/gql.js +1 -0
  47. package/lib/compile/to/json.js +30 -5
  48. package/lib/compile/to/sql.js +3 -1
  49. package/lib/core/index.js +5 -1
  50. package/lib/dbs/cds-deploy.js +36 -6
  51. package/lib/env/cds-env.js +15 -5
  52. package/lib/env/cds-requires.js +51 -58
  53. package/lib/env/defaults.js +1 -0
  54. package/lib/env/schemas/cds-package.json +4 -0
  55. package/lib/env/schemas/cds-rc.json +63 -77
  56. package/lib/i18n/localize.js +16 -5
  57. package/lib/index.js +9 -4
  58. package/lib/log/cds-error.js +4 -6
  59. package/lib/log/cds-log.js +89 -53
  60. package/lib/log/service/index.js +1 -0
  61. package/lib/ql/CREATE.js +2 -5
  62. package/lib/ql/DELETE.js +1 -1
  63. package/lib/ql/DROP.js +1 -3
  64. package/lib/ql/INSERT.js +3 -3
  65. package/lib/ql/Query.js +10 -23
  66. package/lib/ql/SELECT.js +1 -2
  67. package/lib/ql/UPDATE.js +2 -2
  68. package/lib/ql/Whereable.js +7 -15
  69. package/lib/ql/cds-ql.js +9 -3
  70. package/lib/req/cds-context.js +11 -3
  71. package/lib/req/context.js +29 -23
  72. package/lib/req/locale.js +9 -5
  73. package/lib/req/request.js +1 -0
  74. package/lib/req/user.js +2 -1
  75. package/lib/srv/cds-connect.js +1 -1
  76. package/lib/srv/cds-serve.js +21 -14
  77. package/lib/srv/middlewares/cds-context.js +29 -0
  78. package/lib/srv/middlewares/ctx-model.js +24 -0
  79. package/lib/srv/middlewares/errors.js +9 -0
  80. package/lib/srv/middlewares/index.js +22 -0
  81. package/lib/srv/middlewares/sap-statistics.js +13 -0
  82. package/lib/srv/middlewares/trace.js +102 -0
  83. package/lib/srv/protocols/_legacy.js +42 -0
  84. package/lib/srv/protocols/graphql.js +39 -0
  85. package/lib/srv/protocols/hcql.js +37 -0
  86. package/lib/srv/protocols/index.js +86 -0
  87. package/lib/srv/protocols/odata-v2-proxy.js +3767 -0
  88. package/lib/srv/protocols/odata-v2.js +26 -0
  89. package/lib/srv/protocols/odata-v4.js +16 -0
  90. package/lib/srv/protocols/rest.js +13 -0
  91. package/lib/srv/srv-api.js +5 -0
  92. package/lib/srv/srv-models.js +4 -6
  93. package/lib/utils/axios.js +3 -2
  94. package/lib/utils/cds-test.js +27 -21
  95. package/lib/utils/cds-utils.js +19 -20
  96. package/lib/utils/tar.js +175 -0
  97. package/libx/_runtime/audit/generic/personal/utils.js +18 -7
  98. package/libx/_runtime/audit/utils/v2.js +1 -0
  99. package/libx/_runtime/auth/index.js +4 -0
  100. package/libx/_runtime/auth/strategies/ias-auth.js +76 -0
  101. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +8 -3
  102. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +15 -4
  103. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -1
  104. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/orderByToCQN.js +1 -1
  105. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +1 -1
  106. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/ResourcePathParser.js +9 -0
  107. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriInfo.js +5 -1
  108. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriParser.js +12 -0
  109. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/utils/BufferedWriter.js +6 -2
  110. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/RequestValidator.js +47 -7
  111. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  112. package/libx/_runtime/cds-services/util/assert.js +4 -0
  113. package/libx/_runtime/common/aspects/relation.js +1 -1
  114. package/libx/_runtime/common/composition/data.js +61 -15
  115. package/libx/_runtime/common/composition/delete.js +0 -1
  116. package/libx/_runtime/common/composition/insert.js +0 -1
  117. package/libx/_runtime/common/composition/tree.js +4 -10
  118. package/libx/_runtime/common/composition/update.js +44 -21
  119. package/libx/_runtime/common/generic/auth/capabilities.js +8 -10
  120. package/libx/_runtime/common/generic/crud.js +1 -2
  121. package/libx/_runtime/common/generic/etag.js +4 -4
  122. package/libx/_runtime/common/generic/input.js +4 -4
  123. package/libx/_runtime/common/generic/paging.js +3 -3
  124. package/libx/_runtime/common/generic/put.js +3 -3
  125. package/libx/_runtime/common/generic/sorting.js +4 -4
  126. package/libx/_runtime/common/generic/temporal.js +3 -3
  127. package/libx/_runtime/common/i18n/messages.properties +0 -7
  128. package/libx/_runtime/common/utils/cqn2cqn4sql.js +11 -6
  129. package/libx/_runtime/common/utils/csn.js +0 -28
  130. package/libx/_runtime/common/utils/draft.js +8 -1
  131. package/libx/_runtime/common/utils/path.js +7 -1
  132. package/libx/_runtime/common/utils/resolveView.js +2 -3
  133. package/libx/_runtime/db/data-conversion/post-processing.js +3 -44
  134. package/libx/_runtime/db/generic/input.js +3 -3
  135. package/libx/_runtime/db/sql-builder/dataTypes.js +4 -0
  136. package/libx/_runtime/fiori/generic/activate.js +2 -2
  137. package/libx/_runtime/fiori/generic/before.js +40 -72
  138. package/libx/_runtime/fiori/generic/cancel.js +2 -2
  139. package/libx/_runtime/fiori/generic/delete.js +2 -2
  140. package/libx/_runtime/fiori/generic/edit.js +2 -2
  141. package/libx/_runtime/fiori/generic/new.js +2 -2
  142. package/libx/_runtime/fiori/generic/patch.js +49 -37
  143. package/libx/_runtime/fiori/generic/prepare.js +2 -2
  144. package/libx/_runtime/fiori/generic/read.js +27 -37
  145. package/libx/_runtime/fiori/utils/where.js +4 -2
  146. package/libx/_runtime/hana/Service.js +1 -3
  147. package/libx/_runtime/hana/conversion.js +3 -0
  148. package/libx/_runtime/hana/driver.js +33 -3
  149. package/libx/_runtime/hana/dynatrace.js +1 -0
  150. package/libx/_runtime/hana/search2Contains.js +12 -1
  151. package/libx/_runtime/hana/search2cqn4sql.js +10 -27
  152. package/libx/_runtime/hana/streaming.js +1 -0
  153. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +4 -2
  154. package/libx/_runtime/messaging/common-utils/AMQPClient.js +1 -0
  155. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +5 -2
  156. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +2 -0
  157. package/libx/_runtime/messaging/enterprise-messaging.js +62 -3
  158. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  159. package/libx/_runtime/messaging/redis-messaging.js +1 -0
  160. package/libx/_runtime/remote/Service.js +2 -2
  161. package/libx/_runtime/remote/utils/client.js +8 -3
  162. package/libx/_runtime/remote/utils/data.js +7 -2
  163. package/libx/_runtime/sqlite/Service.js +18 -7
  164. package/libx/_runtime/sqlite/conversion.js +3 -0
  165. package/libx/_runtime/sqlite/convertAssocToOneManaged.js +3 -3
  166. package/libx/_runtime/sqlite/localized.js +8 -8
  167. package/libx/odata/afterburner.js +39 -7
  168. package/libx/odata/cqn2odata.js +6 -3
  169. package/libx/odata/grammar.pegjs +66 -18
  170. package/libx/odata/index.js +3 -2
  171. package/libx/odata/parser.js +1 -1
  172. package/libx/odata/utils.js +2 -0
  173. package/libx/rest/RestAdapter.js +62 -43
  174. package/libx/rest/middleware/parse.js +2 -1
  175. package/libx/rest/middleware/update.js +1 -1
  176. package/package.json +2 -2
  177. package/server.js +5 -4
  178. package/srv/mtx.cds +1 -1
  179. package/srv/mtx.js +4 -33
  180. package/lib/srv/adapters.js +0 -85
  181. package/lib/utils/resources/index.js +0 -48
  182. package/lib/utils/resources/tar.js +0 -49
  183. package/lib/utils/resources/utils.js +0 -11
  184. package/libx/_runtime/extensibility/activate.js +0 -69
  185. package/libx/_runtime/extensibility/add.js +0 -50
  186. package/libx/_runtime/extensibility/addExtension.js +0 -72
  187. package/libx/_runtime/extensibility/defaults.js +0 -34
  188. package/libx/_runtime/extensibility/handler/transformREAD.js +0 -121
  189. package/libx/_runtime/extensibility/handler/transformRESULT.js +0 -51
  190. package/libx/_runtime/extensibility/handler/transformWRITE.js +0 -64
  191. package/libx/_runtime/extensibility/linter/allowlist_checker.js +0 -373
  192. package/libx/_runtime/extensibility/linter/annotations_checker.js +0 -113
  193. package/libx/_runtime/extensibility/linter/checker_base.js +0 -20
  194. package/libx/_runtime/extensibility/linter/namespace_checker.js +0 -180
  195. package/libx/_runtime/extensibility/linter.js +0 -32
  196. package/libx/_runtime/extensibility/push.js +0 -118
  197. package/libx/_runtime/extensibility/service.js +0 -38
  198. package/libx/_runtime/extensibility/token.js +0 -57
  199. package/libx/_runtime/extensibility/utils.js +0 -131
  200. package/libx/_runtime/extensibility/validation.js +0 -50
  201. package/libx/_runtime/extensibility/views.js +0 -12
  202. package/srv/extensibility-service.cds +0 -60
  203. package/srv/extensibility-service.js +0 -1
  204. package/srv/extensions.cds +0 -8
  205. package/srv/model-provider.cds +0 -61
  206. package/srv/model-provider.js +0 -143
@@ -1,64 +0,0 @@
1
- const { EXT_BACK_PACK, getTargetWrite, isExtendedEntity } = require('../utils')
2
-
3
- const getTemplate = require('../../common/utils/template')
4
- const templateProcessor = require('../../common/utils/templateProcessor')
5
-
6
- const _pick = element => {
7
- return element['@cds.extension']
8
- }
9
-
10
- const _processorFn = ({ row, key }) => {
11
- if (row[key] === undefined) return
12
-
13
- if (!row[EXT_BACK_PACK]) {
14
- row[EXT_BACK_PACK] = '{}'
15
- }
16
-
17
- const json = JSON.parse(row[EXT_BACK_PACK])
18
- json[key] = row[key]
19
- row[EXT_BACK_PACK] = JSON.stringify(json)
20
- delete row[key]
21
- }
22
-
23
- function transformExtendedFieldsCREATE(req) {
24
- if (!req.query) return // FIXME: the code below expects req.query to be defined
25
- if (!req.target) return
26
- if (!req.query.INSERT.entries) return // REVISIT: breaks at cds.deploy -> should anyways not kick in during cds.deploy
27
-
28
- const target = getTargetWrite(req.target, this.model)
29
- const template = getTemplate('transform-write', this, target, { pick: _pick })
30
-
31
- if (template && template.elements.size > 0) {
32
- for (const row of req.query.INSERT.entries) {
33
- const args = { processFn: _processorFn, row, template }
34
- templateProcessor(args)
35
- }
36
- }
37
- }
38
-
39
- async function transformExtendedFieldsUPDATE(req) {
40
- if (!req.target || !req.query.UPDATE.where) return
41
-
42
- const target = getTargetWrite(req.target, this.model)
43
- const template = getTemplate('transform-write', Object.assign(req, { model: this.model }), target, { pick: _pick })
44
-
45
- if (template && template.elements.size > 0) {
46
- // In patch case we first should obtain backpack from db.
47
- // Patch can be only applied to the root.
48
- if (isExtendedEntity(target.name, this.model)) {
49
- const current = await SELECT.from(req.query.UPDATE.entity).columns([EXT_BACK_PACK]).where(req.query.UPDATE.where)
50
-
51
- if (current[0]) {
52
- req.data[EXT_BACK_PACK] = JSON.stringify(current[0])
53
- }
54
- }
55
-
56
- const args = { processFn: _processorFn, row: req.data, template }
57
- templateProcessor(args)
58
- }
59
- }
60
-
61
- module.exports = {
62
- transformExtendedFieldsCREATE,
63
- transformExtendedFieldsUPDATE
64
- }
@@ -1,373 +0,0 @@
1
- const Checker = require('./checker_base')
2
-
3
- const LABELS = {
4
- service: 'Service',
5
- entity: 'Entity',
6
- aspect: 'Aspect',
7
- type: 'Type'
8
- }
9
-
10
- const LEGACY_ENTITY_WHITELIST = 'entity-whitelist'
11
- const LEGACY_SERVICE_WHITELIST = 'service-whitelist'
12
- const EXTENSION_ALLOWLIST = 'extension-allowlist'
13
- const NEW_FIELDS = 'new-fields'
14
- const NEW_ENTITIES = 'new-entities'
15
-
16
- class Allowlist {
17
- constructor(mtxConfig, fullCsn) {
18
- this.allowlist = Allowlist._setupPermissionList(mtxConfig, fullCsn)
19
- }
20
-
21
- get all() {
22
- return this.allowlist.all
23
- }
24
-
25
- get entity() {
26
- return this.allowlist.entity
27
- }
28
-
29
- get service() {
30
- return this.allowlist.service
31
- }
32
-
33
- getList(kind) {
34
- return this.allowlist[kind]
35
- }
36
-
37
- getPermission(kind, name) {
38
- function findInList(list, name) {
39
- if (list) {
40
- const splitName = name.split('.')
41
- while (splitName.length > 0) {
42
- const nameOrPrefix = splitName.join('.')
43
- if (list[nameOrPrefix]) {
44
- return list[nameOrPrefix]
45
- }
46
- splitName.pop()
47
- }
48
- return list['*'] ? list['*'] : null
49
- }
50
- return null
51
- }
52
-
53
- return findInList(this.allowlist[kind], name) || findInList(this.allowlist['all'], name)
54
- }
55
-
56
- isAllowed(kind, name) {
57
- return !!this.getPermission(kind, name)
58
- }
59
-
60
- static _setupPermissionList(mtxConfig, fullCsn) {
61
- // internal structure:
62
- // result[name] = { kind, new-fields | new-entities }
63
-
64
- const result = {}
65
-
66
- // create from legacy lists
67
- let { entityWhitelist, serviceWhitelist } = Allowlist._getLegacyLists(mtxConfig)
68
-
69
- // create from new lists
70
- const allowlistNewFormat = mtxConfig[EXTENSION_ALLOWLIST]
71
-
72
- Allowlist._addLegacyLists(result, serviceWhitelist, entityWhitelist)
73
-
74
- if (allowlistNewFormat) {
75
- // seperate into single entities /services for better processing
76
- for (const permission of allowlistNewFormat) {
77
- if (permission.for) {
78
- for (const name of permission.for) {
79
- if (permission.kind) {
80
- // kind is specfied
81
- result[permission.kind] = result[permission.kind] || {}
82
- result[permission.kind][name] = permission
83
- } else {
84
- // check kind
85
- if (fullCsn.definitions[name]) {
86
- result[fullCsn.definitions[name].kind] = result[fullCsn.definitions[name].kind] || {}
87
- result[fullCsn.definitions[name].kind][name] = permission
88
- } else {
89
- // allow all
90
- result.all = result.all || {}
91
- result.all[name] = permission
92
- }
93
- }
94
- }
95
- }
96
- }
97
- }
98
- return result
99
- }
100
-
101
- static _addLegacyLists(result, serviceWhitelist, entityWhitelist) {
102
- if (serviceWhitelist) {
103
- result.service = result.service || {}
104
- for (const service of serviceWhitelist) {
105
- result.service[service] = {}
106
- }
107
- }
108
-
109
- if (entityWhitelist) {
110
- result.entity = result.entity || {}
111
- for (const entity of entityWhitelist) {
112
- result.entity[entity] = {}
113
- }
114
- }
115
- return result
116
- }
117
-
118
- static _getLegacyLists(mtxConfig) {
119
- let entityWhitelist = mtxConfig[LEGACY_ENTITY_WHITELIST]
120
- let serviceWhitelist = mtxConfig[LEGACY_SERVICE_WHITELIST]
121
-
122
- if (entityWhitelist && !Array.isArray(entityWhitelist)) {
123
- entityWhitelist = [entityWhitelist]
124
- }
125
-
126
- if (serviceWhitelist && !Array.isArray(serviceWhitelist)) {
127
- serviceWhitelist = [serviceWhitelist]
128
- }
129
- return { entityWhitelist, serviceWhitelist }
130
- }
131
- }
132
-
133
- class AllowlistChecker extends Checker {
134
- static _setupPermissionList(mtxConfig, fullCsn) {
135
- return new Allowlist(mtxConfig, fullCsn)
136
- }
137
-
138
- static async check(reflectedExtensionCsn, fullCsn, extensionFiles, compileDir, mtxConfig) {
139
- const allowList = this._setupPermissionList(mtxConfig, fullCsn)
140
-
141
- const warnings = []
142
-
143
- // check entities
144
- if (reflectedExtensionCsn.extensions && allowList) {
145
- for (const extension of reflectedExtensionCsn.extensions) {
146
- this._checkEntity(extension, reflectedExtensionCsn, fullCsn, compileDir, allowList, warnings)
147
- }
148
- }
149
-
150
- // check services
151
- const foundServiceExt = {}
152
- reflectedExtensionCsn.forall(
153
- element => {
154
- return ['entity', 'element', 'function', 'action'].includes(element.kind)
155
- },
156
- (element, name, parent) => {
157
- if (allowList) {
158
- this._checkService(
159
- reflectedExtensionCsn,
160
- fullCsn,
161
- element,
162
- parent,
163
- { extensionFiles, compileDir },
164
- allowList,
165
- warnings,
166
- foundServiceExt
167
- ) // NOSONAR
168
- }
169
- }
170
- )
171
- this._addServiceLimitWarnings(foundServiceExt, allowList, compileDir, warnings)
172
-
173
- return warnings
174
- }
175
-
176
- static _checkEntity(extension, extCsn, fullCsn, compileDir, allowlist, warnings) {
177
- const extendedEntity = extension.extend
178
- if (extendedEntity) {
179
- if (
180
- fullCsn &&
181
- fullCsn.definitions &&
182
- (!extCsn.definitions[extendedEntity] || extCsn.definitions[extendedEntity].kind !== 'entity')
183
- ) {
184
- const kind = this._getExtendedKind(fullCsn, extendedEntity)
185
-
186
- if (!allowlist.isAllowed(kind, extendedEntity)) {
187
- // not allowed at all
188
- this._addColumnWarnings(extension, warnings, compileDir, allowlist.getList(kind), kind)
189
- this._addElementWarnings(extension, warnings, compileDir, allowlist.getList(kind), kind)
190
- } else {
191
- // might have limits
192
- this._addEntityLimitWarnings(extension, warnings, compileDir, allowlist, kind)
193
- }
194
- }
195
- }
196
- }
197
-
198
- static _getExtendedKind(fullCsn, extendedEntity) {
199
- const elementFromBase = fullCsn.definitions[extendedEntity]
200
- return elementFromBase ? elementFromBase.kind : null
201
- }
202
-
203
- static _addElementWarnings(extension, warnings, compileDir, allowlist, kind) {
204
- if (extension.elements) {
205
- for (const element in extension.elements) {
206
- warnings.push(
207
- this._createAllowlistWarning(
208
- extension.extend,
209
- extension.elements[element],
210
- compileDir,
211
- allowlist,
212
- LABELS[kind]
213
- )
214
- )
215
- }
216
- }
217
- }
218
-
219
- static _addColumnWarnings(extension, warnings, compileDir, allowlist, kind) {
220
- // loop columns + elements
221
- if (extension.columns) {
222
- for (const column of extension.columns) {
223
- warnings.push(this._createAllowlistWarning(extension.extend, column, compileDir, allowlist, LABELS[kind]))
224
- }
225
- }
226
- }
227
-
228
- static _addEntityLimitWarnings(extension, warnings, compileDir, allowlist, kind) {
229
- const limit = allowlist.getPermission(kind, extension.extend)[NEW_FIELDS]
230
-
231
- if (!limit) {
232
- return
233
- }
234
-
235
- if (
236
- (extension.columns ? extension.columns.length : 0) +
237
- (extension.elements ? Object.keys(extension.elements).length : 0) <=
238
- limit
239
- ) {
240
- return
241
- }
242
-
243
- // loop columns + elements
244
- if (extension.columns) {
245
- for (const column of extension.columns) {
246
- warnings.push(this._createLimitWarning(extension.extend, column, compileDir, limit, LABELS[kind]))
247
- }
248
- }
249
-
250
- if (extension.elements) {
251
- for (const element in extension.elements) {
252
- warnings.push(
253
- this._createLimitWarning(extension.extend, extension.elements[element], compileDir, limit, LABELS[kind])
254
- )
255
- }
256
- }
257
- }
258
-
259
- static _addServiceLimitWarnings(foundServiceExt, allowlist, compileDir, warnings) {
260
- if (!allowlist) {
261
- return
262
- }
263
-
264
- for (const service in foundServiceExt) {
265
- let extLimit = allowlist.getPermission('service', service)[NEW_ENTITIES]
266
- if (extLimit && extLimit <= foundServiceExt[service].length) {
267
- // loop all extension for one service
268
- for (const element of foundServiceExt[service]) {
269
- warnings.push(this._createLimitWarning(service, element, compileDir, extLimit, LABELS['service']))
270
- }
271
- }
272
- }
273
- }
274
-
275
- static _getParentName(element) {
276
- if (element.name) {
277
- const splitEntityName = element.name.split('.')
278
- if (splitEntityName.length > 1) {
279
- splitEntityName.pop()
280
- return splitEntityName.join('.')
281
- }
282
- }
283
- return null
284
- }
285
-
286
- static _isDefinedInExtension(reflectedCsn, name) {
287
- return reflectedCsn.definitions ? !!reflectedCsn.definitions[name] : false
288
- }
289
-
290
- static _isDefinedInBasemodel(fullCsn, name) {
291
- return !!this._getFromBasemodel(fullCsn, name)
292
- }
293
-
294
- static _getFromBasemodel(fullCsn, name) {
295
- return fullCsn.definitions[name]
296
- }
297
-
298
- static _checkService(reflectedExtensionCsn, fullCsn, element, parent, extension, allowlist, warnings, foundExt) {
299
- if (parent && parent.kind && parent.kind !== 'service') {
300
- return
301
- }
302
-
303
- let parentName
304
- if (!parent) {
305
- parentName = this._getParentName(element)
306
- } else {
307
- parentName = this._getEntityName(parent)
308
- }
309
-
310
- // definition of element in extension itself
311
- if (!parentName) {
312
- return
313
- }
314
-
315
- // check if parent is defined in extension itself
316
- if (this._isDefinedInExtension(reflectedExtensionCsn, parentName)) {
317
- return
318
- }
319
-
320
- // check if parent is defined in basemodel
321
- if (!this._isDefinedInBasemodel(fullCsn, parentName)) {
322
- return
323
- }
324
-
325
- if (allowlist.isAllowed('service', parentName)) {
326
- foundExt[parentName] = foundExt[parentName] || []
327
- foundExt[parentName].push(element)
328
- return
329
- }
330
-
331
- warnings.push(
332
- this._createAllowlistWarning(parentName, element, extension.compileDir, allowlist.service, LABELS['service'])
333
- )
334
- }
335
-
336
- static _createAllowlistWarning(entityName, element, compileDir, allowlist = {}, label) {
337
- const originFile = this._localizeFile(element.$location.file, compileDir)
338
-
339
- return (
340
- label +
341
- ' ' +
342
- entityName +
343
- ' must not be extended. See ' +
344
- '(line:' +
345
- element.$location.line +
346
- ', col:' +
347
- element.$location.col +
348
- ')' +
349
- ' in ' +
350
- originFile +
351
- '. Check ' +
352
- label +
353
- ' allowlist: ' +
354
- (Object.keys(allowlist).length > 0 ? Object.keys(allowlist) : '<empty list>')
355
- )
356
- }
357
-
358
- static _createLimitWarning(entityName, element, compileDir, limit, label) {
359
- const originFile = this._localizeFile(element.$location.file, compileDir)
360
-
361
- return (
362
- `Extension limit of ${limit} for ${label} ${entityName} has been exceeded` +
363
- `(line: ${element.$location.line}, col: ${element.$location.col})` +
364
- ` in ${originFile}`
365
- )
366
- }
367
-
368
- static _getEntityName(entity) {
369
- return entity.extend ? entity.extend : entity.name
370
- }
371
- }
372
-
373
- module.exports = AllowlistChecker
@@ -1,113 +0,0 @@
1
- const Checker = require('./checker_base')
2
-
3
- const AT_REQUIRES = '@requires'
4
- const AT_RESTRICT = '@restrict'
5
- const AT_CDS_PERSISTENCE_JOURNAL = '@cds.persistence.journal'
6
- const AT_SQL_APPEND = '@sql.append'
7
- const AT_SQL_PREPEND = '@sql.prepend'
8
-
9
- const checkedAnnotations = new Map([
10
- [AT_REQUIRES, _createSecurityAnnotationWarning],
11
- [AT_RESTRICT, _createSecurityAnnotationWarning],
12
- [AT_CDS_PERSISTENCE_JOURNAL, _createJournalAnnotationWarning],
13
- [AT_SQL_APPEND, _createSqlAnnotationWarning],
14
- [AT_SQL_PREPEND, _createSqlAnnotationWarning]
15
- ])
16
-
17
- function _createSqlAnnotationWarning(annotationName, originFile, annotation) {
18
- return (
19
- `Annotation ${annotationName} is not supported in extensions: ${originFile}` +
20
- `(line: ${annotation.$location.line}, col: ${annotation.$location.col})`
21
- )
22
- }
23
-
24
- function _createSecurityAnnotationWarning(annotationName, originFile, annotation) {
25
- return (
26
- `Security relevant annotation ${annotationName} cannot be overwritten: ${originFile}` +
27
- `(line: ${annotation.$location.line}, col: ${annotation.$location.col})`
28
- )
29
- }
30
-
31
- function _createJournalAnnotationWarning(journalAnnotationName, originFile, annotation) {
32
- return (
33
- `Enabling schema evolution in extensions using ${journalAnnotationName} not yet supported: ${originFile}` +
34
- ` (line: ${annotation.$location.line}, col: ${annotation.$location.col})`
35
- )
36
- }
37
-
38
- class AnnotationsChecker extends Checker {
39
- static async check(reflectedCsn, extensionFiles, compileDir) {
40
- if (!reflectedCsn.extensions) {
41
- return []
42
- }
43
-
44
- // annotations via annotate - applies for all
45
- const annotationExtensions = Object.values(reflectedCsn.extensions).filter(
46
- value => value.annotate && Object.getOwnPropertyNames(value).filter(property => checkedAnnotations.get(property))
47
- )
48
-
49
- // check annotations for extensions including fields
50
- reflectedCsn.forall(
51
- () => true,
52
- element => {
53
- if (element[AT_SQL_PREPEND] || element[AT_SQL_APPEND]) {
54
- if (!element.annotate) {
55
- // do not add annotation extensions again
56
- annotationExtensions.push(element)
57
- }
58
- }
59
- },
60
- reflectedCsn.extensions
61
- )
62
-
63
- // check entities and fields from definitions
64
- const annotatedDefinitions = []
65
- reflectedCsn.forall(
66
- () => true,
67
- element => {
68
- if (element[AT_SQL_PREPEND] || element[AT_SQL_APPEND] || element[AT_CDS_PERSISTENCE_JOURNAL]) {
69
- annotatedDefinitions.push(element)
70
- }
71
- },
72
- reflectedCsn.definitions
73
- )
74
-
75
- const warnings = []
76
-
77
- for (const annotationExtension of annotationExtensions) {
78
- const warning = this._checkAnnotation(annotationExtension, reflectedCsn.definitions, compileDir)
79
- if (warning) {
80
- warnings.push(warning)
81
- }
82
- }
83
-
84
- for (const annotatedDefinition of annotatedDefinitions) {
85
- const warning = this._checkAnnotation(annotatedDefinition, reflectedCsn.definitions, compileDir)
86
- if (warning) {
87
- warnings.push(warning)
88
- }
89
- }
90
-
91
- return warnings
92
- }
93
-
94
- static _checkAnnotation(annotation, definitions, compileDir) {
95
- if (!definitions[annotation.annotate]) {
96
- return this._createAnnotationsWarning(annotation, compileDir)
97
- }
98
-
99
- return null
100
- }
101
-
102
- static _createAnnotationsWarning(annotation, compileDir) {
103
- const annotationName = Object.getOwnPropertyNames(annotation).filter(property => checkedAnnotations.get(property))
104
-
105
- const originFile = this._localizeFile(annotation.$location.file, compileDir)
106
-
107
- if (annotationName.length) {
108
- return checkedAnnotations.get(annotationName[0])(annotationName, originFile, annotation)
109
- }
110
- }
111
- }
112
-
113
- module.exports = AnnotationsChecker
@@ -1,20 +0,0 @@
1
- const path = require('path')
2
-
3
- class Checker {
4
- static _isFromExtension(element, extensionFiles, compileDir) {
5
- if (!element.$location) {
6
- return false
7
- }
8
- const originFile = this._localizeFile(element.$location.file, compileDir)
9
- return extensionFiles.includes(originFile)
10
- }
11
-
12
- static _localizeFile(filename, compileDir) {
13
- if (path.isAbsolute(filename) || filename.startsWith('..')) {
14
- filename = path.relative(compileDir, filename)
15
- }
16
- return filename.replace(/\\/g, '/')
17
- }
18
- }
19
-
20
- module.exports = Checker