@sap/cds 6.8.4 → 7.0.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 (217) hide show
  1. package/CHANGELOG.md +66 -4
  2. package/README.md +0 -1
  3. package/bin/cds-serve.js +50 -3
  4. package/bin/deploy/to-hana.js +1 -0
  5. package/bin/serve.js +16 -20
  6. package/lib/auth/basic-auth.js +6 -4
  7. package/lib/auth/index.js +4 -3
  8. package/lib/auth/jwt-auth.js +2 -5
  9. package/lib/compile/cds-compile.js +34 -89
  10. package/lib/compile/cdsc.js +11 -0
  11. package/lib/compile/etc/properties.js +2 -2
  12. package/lib/compile/for/lean_drafts.js +36 -69
  13. package/lib/compile/for/nodejs.js +2 -1
  14. package/lib/compile/load.js +3 -3
  15. package/lib/compile/minify.js +2 -0
  16. package/lib/compile/to/csn.js +74 -0
  17. package/{bin/build/provider/hana/2tabledata.js → lib/compile/to/hdbtabledata.js} +4 -6
  18. package/lib/compile/to/json.js +1 -1
  19. package/lib/compile/to/sql.js +8 -6
  20. package/lib/dbs/cds-deploy.js +174 -114
  21. package/lib/env/cds-env.js +64 -79
  22. package/lib/env/cds-requires.js +11 -28
  23. package/lib/env/defaults.js +13 -3
  24. package/lib/env/plugins.js +1 -12
  25. package/lib/env/presets.js +25 -21
  26. package/lib/index.js +121 -147
  27. package/lib/{core/reflect.js → linked/models.js} +2 -2
  28. package/lib/{core/infer.js → linked/queries.js} +2 -0
  29. package/lib/{core/index.js → linked/types.js} +2 -1
  30. package/lib/log/cds-error.js +13 -7
  31. package/lib/log/format/cf.js +1 -1
  32. package/lib/plugins.js +49 -0
  33. package/lib/ql/Query.js +0 -9
  34. package/lib/ql/STREAM.js +0 -1
  35. package/lib/req/context.js +2 -7
  36. package/lib/req/request.js +6 -2
  37. package/lib/req/response.js +23 -10
  38. package/lib/srv/middlewares/ctx-model.js +2 -2
  39. package/lib/srv/middlewares/errors.js +1 -1
  40. package/lib/srv/protocols/_legacy.js +1 -0
  41. package/lib/srv/protocols/graphql.js +7 -16
  42. package/lib/srv/protocols/index.js +59 -45
  43. package/lib/srv/protocols/odata-v2-proxy.js +2 -70
  44. package/lib/srv/protocols/odata-v4.js +9 -4
  45. package/lib/srv/srv-api.js +9 -3
  46. package/lib/srv/srv-dispatch.js +12 -9
  47. package/lib/srv/srv-models.js +4 -21
  48. package/lib/srv/srv-tx.js +15 -12
  49. package/lib/utils/cds-test.js +14 -9
  50. package/lib/utils/cds-utils.js +2 -12
  51. package/lib/utils/check-version.js +17 -0
  52. package/{bin/build → lib/utils}/csv-reader.js +23 -24
  53. package/libx/_runtime/auth/index.js +27 -23
  54. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  56. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
  57. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
  58. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
  59. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
  61. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
  62. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
  63. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
  64. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
  65. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/uri/UriTokenizer.js +5 -8
  66. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
  67. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
  68. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  69. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
  70. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
  71. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
  72. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
  73. package/libx/_runtime/cds-services/services/Service.js +79 -107
  74. package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
  75. package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
  76. package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
  77. package/libx/_runtime/cds-services/util/assert.js +65 -2
  78. package/libx/_runtime/common/composition/data.js +1 -0
  79. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  80. package/libx/_runtime/common/generic/auth/restrict.js +5 -10
  81. package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
  82. package/libx/_runtime/common/generic/auth/utils.js +1 -2
  83. package/libx/_runtime/common/generic/crud.js +32 -16
  84. package/libx/_runtime/common/generic/etag.js +133 -104
  85. package/libx/_runtime/common/generic/input.js +6 -21
  86. package/libx/_runtime/common/generic/put.js +1 -1
  87. package/libx/_runtime/common/generic/stream.js +52 -0
  88. package/libx/_runtime/common/generic/temporal.js +25 -8
  89. package/libx/_runtime/common/i18n/messages.properties +0 -2
  90. package/libx/_runtime/common/utils/cqn.js +1 -1
  91. package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
  92. package/libx/_runtime/common/utils/csn.js +0 -51
  93. package/libx/_runtime/common/utils/etag.js +30 -0
  94. package/libx/_runtime/common/utils/keys.js +1 -1
  95. package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
  96. package/libx/_runtime/common/utils/path.js +1 -1
  97. package/libx/_runtime/common/utils/resolveView.js +2 -1
  98. package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
  99. package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
  100. package/libx/_runtime/common/utils/stream.js +140 -0
  101. package/libx/_runtime/common/utils/streamProp.js +29 -12
  102. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
  103. package/libx/_runtime/db/generic/index.js +0 -2
  104. package/libx/_runtime/db/query/delete.js +2 -2
  105. package/libx/_runtime/db/query/insert.js +2 -2
  106. package/libx/_runtime/db/query/read.js +2 -2
  107. package/libx/_runtime/db/query/run.js +2 -2
  108. package/libx/_runtime/db/query/update.js +2 -2
  109. package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
  110. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
  111. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
  112. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
  113. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
  114. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
  115. package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
  116. package/libx/_runtime/fiori/draft.js +2 -0
  117. package/libx/_runtime/fiori/generic/activate.js +8 -9
  118. package/libx/_runtime/fiori/generic/before.js +30 -20
  119. package/libx/_runtime/fiori/generic/cancel.js +5 -3
  120. package/libx/_runtime/fiori/generic/delete.js +5 -3
  121. package/libx/_runtime/fiori/generic/edit.js +7 -7
  122. package/libx/_runtime/fiori/generic/index.js +10 -16
  123. package/libx/_runtime/fiori/generic/new.js +5 -3
  124. package/libx/_runtime/fiori/generic/patch.js +11 -8
  125. package/libx/_runtime/fiori/generic/prepare.js +13 -6
  126. package/libx/_runtime/fiori/generic/read.js +12 -6
  127. package/libx/_runtime/fiori/lean-draft.js +207 -152
  128. package/libx/_runtime/fiori/utils/delete.js +10 -5
  129. package/libx/_runtime/fiori/utils/req.js +17 -5
  130. package/libx/_runtime/fiori/utils/stream.js +36 -0
  131. package/libx/_runtime/hana/Service.js +12 -9
  132. package/libx/_runtime/hana/conversion.js +10 -15
  133. package/libx/_runtime/hana/driver.js +2 -0
  134. package/libx/_runtime/hana/execute.js +28 -6
  135. package/libx/_runtime/hana/pool.js +36 -122
  136. package/libx/_runtime/hana/search2cqn4sql.js +34 -36
  137. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
  138. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
  139. package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
  140. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  141. package/libx/_runtime/remote/Service.js +20 -1
  142. package/libx/_runtime/remote/utils/client.js +3 -5
  143. package/libx/_runtime/sqlite/Service.js +4 -6
  144. package/libx/_runtime/sqlite/conversion.js +3 -13
  145. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
  146. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
  147. package/libx/_runtime/sqlite/execute.js +5 -16
  148. package/libx/odata/afterburner.js +22 -6
  149. package/libx/odata/grammar.pegjs +6 -1
  150. package/libx/odata/parser.js +1 -1
  151. package/libx/rest/RestAdapter.js +16 -9
  152. package/libx/rest/RestRequest.js +1 -1
  153. package/libx/rest/middleware/input.js +2 -1
  154. package/libx/rest/middleware/operation.js +1 -0
  155. package/libx/rest/middleware/parse.js +3 -2
  156. package/libx/rest/middleware/payload.js +9 -8
  157. package/libx/rest/middleware/read.js +1 -0
  158. package/package.json +9 -16
  159. package/server.js +1 -1
  160. package/app/fiori/preview.js +0 -270
  161. package/app/fiori/routes.js +0 -59
  162. package/bin/build/buildTaskEngine.js +0 -360
  163. package/bin/build/buildTaskFactory.js +0 -283
  164. package/bin/build/buildTaskHandler.js +0 -241
  165. package/bin/build/buildTaskProvider.js +0 -22
  166. package/bin/build/buildTaskProviderFactory.js +0 -175
  167. package/bin/build/cds.js +0 -5
  168. package/bin/build/constants.js +0 -66
  169. package/bin/build/index.js +0 -58
  170. package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
  171. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
  172. package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
  173. package/bin/build/provider/buildTaskProviderInternal.js +0 -383
  174. package/bin/build/provider/fiori/index.js +0 -171
  175. package/bin/build/provider/hana/2migration.js +0 -179
  176. package/bin/build/provider/hana/index.js +0 -505
  177. package/bin/build/provider/hana/migrationtable.js +0 -472
  178. package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
  179. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
  180. package/bin/build/provider/hana/template/.hdinamespace +0 -4
  181. package/bin/build/provider/hana/template/package.json +0 -12
  182. package/bin/build/provider/hana/template/undeploy.json +0 -5
  183. package/bin/build/provider/java/index.js +0 -111
  184. package/bin/build/provider/java-cf/index.js +0 -1
  185. package/bin/build/provider/mtx/index.js +0 -268
  186. package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
  187. package/bin/build/provider/mtx-extension/index.js +0 -131
  188. package/bin/build/provider/mtx-sidecar/index.js +0 -137
  189. package/bin/build/provider/node-cf/index.js +0 -1
  190. package/bin/build/provider/nodejs/index.js +0 -192
  191. package/bin/build/util.js +0 -299
  192. package/bin/cds.js +0 -125
  193. package/bin/deploy/to-hana/cfUtil.js +0 -355
  194. package/bin/deploy/to-hana/gitUtil.js +0 -57
  195. package/bin/deploy/to-hana/hana.js +0 -306
  196. package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
  197. package/bin/deploy/to-hana/index.js +0 -16
  198. package/bin/deploy/to-hana/mtaUtil.js +0 -170
  199. package/bin/mtx/in-cds.js +0 -17
  200. package/bin/plugins.js +0 -32
  201. package/bin/run.js +0 -24
  202. package/bin/utils/log.js +0 -24
  203. package/bin/version.js +0 -178
  204. package/libx/_runtime/audit/Service.js +0 -222
  205. package/libx/_runtime/audit/generic/personal/access.js +0 -61
  206. package/libx/_runtime/audit/generic/personal/index.js +0 -56
  207. package/libx/_runtime/audit/generic/personal/modification.js +0 -132
  208. package/libx/_runtime/audit/generic/personal/utils.js +0 -186
  209. package/libx/_runtime/audit/utils/log.js +0 -23
  210. package/libx/_runtime/audit/utils/v2.js +0 -176
  211. package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
  212. package/libx/_runtime/db/generic/integrity.js +0 -455
  213. package/srv/audit-log.cds +0 -87
  214. package/srv/mtx.cds +0 -2
  215. package/srv/mtx.js +0 -8
  216. /package/lib/{core → linked}/classes.js +0 -0
  217. /package/lib/{core → linked}/entities.js +0 -0
package/CHANGELOG.md CHANGED
@@ -4,11 +4,67 @@
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 6.8.4 - 2023-06-14
7
+ ## Version 7.0.1 - 2023-07-03
8
8
 
9
9
  ### Fixed
10
10
 
11
- - `$metadata` requests for multitenant applications
11
+ - Feature toggle detection in single tenant mode
12
+ - Log output for OData $batch requests
13
+ - Avoid "catastrophic backtracking" issue in okra's tokenizer
14
+ - Transaction marked as committed too early
15
+
16
+ ## Version 7.0.0 - 2023-06-21
17
+
18
+ ### Added
19
+
20
+ - Handling of expand with multiple `*` (e.g. $expand=*,*) in new parser. When using `*` in an expand the new OData parser now removes all unneeded `*`.
21
+ - Tests run with `cds.test()` now also load `cds-plugins`
22
+
23
+ ### Changed
24
+
25
+ - Result of `READ` events is now always an array. Previously, it could be `null/undefined` (now empty array), single object (now array with one entry) or array.
26
+ - OData: `PUT`/`PATCH` requests resulting in a new entity (i.e., the `UPSERT` effectively was an `INSERT`) return status code 201
27
+ - Draft: Draft activate requests resulting in an `UPDATE` return status code 200
28
+ - ETags are validated via `WHERE EXISTS` clause attached to query on `GET`, `PUT`/`PATCH`, and `DELETE`
29
+ - OData: `PUT`/`PATCH` with `if-match` header prevents `UPSERT`, i.e., only an existing entity can be updated by such a request
30
+ - Runtime support for `@sap/instance-manager` is removed in favor of the `cds-mtxs` Service Manager client.
31
+ - In multitenant mode, the HANA pool uses the `cds-mtxs` credentials cache
32
+ - Draft handlers are registered for all entities.
33
+ - Decimals in client input are validated in runtime's assert framework (previously OData adapter)
34
+ - `cds build` and `cds deploy --to hana` have moved to `@sap/cds-dk`. Upgrade `@sap/cds-dk` to version 7 to continue using these commands.
35
+ - Changed the behavior of `SELECT` queries for single entities to return `undefined` instead of `null` when no record is found.
36
+ - Fiori preview has moved to new `@sap/cds-fiori` module.
37
+ - Numbers are now always used as placeholders in SQL, except for `SELECT 1 From...`, `LIMIT` and the comparison of two numeric values (e.g. `1 eq 1`).
38
+ - Only new major version 3 of SAP Cloud SDK is from now on supported. Please make sure to upgrade. Version 2 is not maintained anymore.
39
+ - `@protocol` annotation can be used to serve multiple protocols per service.
40
+ - Per default, services are served with a protocol-specific prefix (for example '/odata/v4' for a service using the OData V4 protocol). To also serve without this prefix, as it was the case in older @sap/cds versions, the flag `cds.env.features.serve_on_root` can be set to `true`. Alternatively, the `@path` annotation can be used to explicitely specify an absolute path (with a leading `/`).
41
+ - `cds.requires.middlewares` is enabled by default.
42
+ - The order of csv files that `cds deploy --to sqlite` uses now reflects the dependency order of cds models. This is needed if `UPSERT` is used to create a logically correct deployment.
43
+ - `cds.fiori.lean_draft` is activated by default. You can still set it to `false` as fallback.
44
+
45
+ ### Fixed
46
+
47
+ - UUID typed key properties are no longer automatically filled during UPSERT
48
+ - OData: When undefined in the payload, requests for actions with not nullable array-type parameters result in a client-side error
49
+ - Missing `GROUP BY` in request with $apply in combination with aggregate on restricted entity
50
+ - When `@sap/cds` was not installed underneath project root, cds-plugins where not found
51
+ - Support for multiline texts in `properties` files
52
+ - Error when reading auth protected entities with infix filter in expand
53
+ - Glitch in transaction handling in case of concurrent async before handlers
54
+ - Detection of feature toggles in single-tenant mode
55
+
56
+ ### Removed
57
+
58
+ - Deprecated `req.run()` function, use `cds.run()` instead.
59
+ - Deprecated compat mode `cds.env.features.cds_tx_protection = false`
60
+ - Deprecated referential integrity checks at runtime
61
+ - Support for inofficial feature flag `cds.env.features.bigjs`
62
+ - Support for inofficial feature flag `cds.features.parameterized_numbers`
63
+ - Support for `cds-mtx`
64
+ - Support for Node 14
65
+ - Internal `req.getUriInfo()` and `req.getUrlObject()`
66
+ - `cds deploy --to hana` is now part of `@sap/cds-dk`.
67
+ - Beta `AuditLogService` and out-of-the-box audit logging. Use plugin `@cap-js/audit-logging` instead.
12
68
 
13
69
  ## Version 6.8.3 - 2023-06-13
14
70
 
@@ -48,6 +104,9 @@ For example, similar OData requests `Entity?$expand=items($expand=item($expand=t
48
104
  - `cds build` ignores invalid entries in `undeploy.json`
49
105
  - New `minorUnit` element in `sap.common.Currencies` for how many fractions the minor unit takes (e.g. `0`, or `2`). See https://www.npmjs.com/package/@sap/cds-common-content for matching content.
50
106
  - Support for `$user.<attr> is null` and `$user.<attr> is not null` in `@restrict.where`. `is null` matches `null` and `[]`, `is not null` matches arrays with at least one entry as well as `!= null` if no array.
107
+ - Plugins are now also fetched from `devDependencies`, unless `NODE_ENV === 'production'`
108
+ - Plugins can now provide `cds` configurations in their package.json.
109
+ - Support in OData entities with special letters (like ó,â,ü) in names.
51
110
 
52
111
  ### Changed
53
112
 
@@ -66,6 +125,10 @@ The fix relies on the `@sap-cloud-sdk/connectivity` npm package to be installed.
66
125
  - Fixes in lean-draft
67
126
  - Fixed an issue where the combined `$search` and `$expand` query and localized data was returning empty results on SAP HANA
68
127
  - Tests using `cds.test` no longer crash with a segmentation fault if `injectGlobals: false` is set in the Jest configuration.
128
+ - Handlers registered with `cds.on('shutdown')` are now called with an `err` argument in case the shutdown happened in response to uncaught exceptions or unhandled rejected Promises.
129
+ - Log output on uncaught exceptions or unhandled rejected Promises now is done via `cds.log` instead of `console`.
130
+ - New config option `cds.env.server.force_exit_timeout` allows to configure the timeout in ms after which we force-exit the server (default: 1111) if it didn't do so as expected after a prior `server.close()`. Values `false` or `0` disable force-exit.
131
+ - Require custom auth relative to project root when using pluggable middlewares
69
132
 
70
133
  ## Version 6.7.2 - 2023-04-24
71
134
 
@@ -273,6 +336,7 @@ cds env requires/cds.xt.ModelProviderService
273
336
  - `cds.context.http` is now available for webhook-based requests
274
337
  - `cds build` for SAP HANA migration tables now only saves model entities annotated with `@cds.persistence.journal` as `last-dev` version.
275
338
  - `cds deploy` now uses the `VCAP_SERVICES` environment variable (if set), and skips `cf` operations in this case
339
+ - Support for timestamp precision greater than 3 digits of fractional seconds
276
340
 
277
341
  ### Changed
278
342
 
@@ -489,8 +553,6 @@ Content-Length: 145
489
553
  - `cds deploy` and `cds run/serve/watch` no longer print terminal escape sequences (`x1b...`) if they run non-interactively.
490
554
  - Some fields in entities like `path` generated invalid sql
491
555
 
492
- ### Removed
493
-
494
556
  ## Version 6.1.3 - 2022-09-13
495
557
 
496
558
  ### Added
package/README.md CHANGED
@@ -11,4 +11,3 @@ In case you find a bug, please report an [incident](https://cap.cloud.sap/docs/r
11
11
  ## License
12
12
 
13
13
  This package is provided under the terms of the [SAP Developer License Agreement](https://tools.hana.ondemand.com/developer-license-3.1.txt).
14
-
package/bin/cds-serve.js CHANGED
@@ -1,6 +1,53 @@
1
1
  #!/usr/bin/env node
2
+ const cds = require('../lib') //> ensure we are the first to load @sap/cds locally
3
+ const cli = {
2
4
 
3
- const cds = require('./cds')
4
- const args = process.argv.slice(2)
5
+ exec (...argv) {
6
+ if (!argv.length) argv = process.argv.slice(2)
7
+ const task = require ('./serve')
5
8
 
6
- cds.exec ('serve', ...args)
9
+ let args = []
10
+ try {
11
+ args = this.args(task, argv)
12
+ } catch (err) { process.exitCode = 1; return console.error(err) }
13
+
14
+ return task.apply (this, args)
15
+ },
16
+
17
+ // TODO replace w/ common arg parser from node
18
+ args (task, argv) {
19
+
20
+ const { options:o=[], flags:f=[], shortcuts:s=[] } = task
21
+ const _global = /^--(profile|production|sql|odata|build-.*|cdsc-.*|odata-.*|folders-.*)$/
22
+ const _flags = { '--production':true }
23
+ const options = {}, args = []
24
+ let k,a, env = null
25
+
26
+ if (argv.length) for (let i=0; i < argv.length; ++i) {
27
+ if ((a = argv[i])[0] !== '-') args.push(a)
28
+ else if ((k = s.indexOf(a)) >= 0) k < o.length ? add(o[k],argv[++i]) : add(f[k-o.length])
29
+ else if ((k = o.indexOf(a)) >= 0) add(o[k],argv[++i])
30
+ else if ((k = f.indexOf(a)) >= 0) add(f[k])
31
+ else if (_global.test(a)) add_global(a, _flags[a] || argv[++i])
32
+ else throw 'Invalid option: '+ a
33
+ }
34
+
35
+ function add (k,v) { options[k.slice(2)] = v || true }
36
+ function add_global (k,v='') {
37
+ if (k === '--production') return process.env.NODE_ENV = 'production'
38
+ if (k === '--profile') return process.env.CDS_ENV = v.split(',')
39
+ if (k === '--odata') v = { flavor:v }
40
+ let e=env || (env={}), path = k.slice(2).split('-')
41
+ while (path.length > 1) { let p = path.shift(); e = e[p]||(e[p]={}) }
42
+ add (k, e[path[0]] = v)
43
+ }
44
+
45
+ if (env) cds.env.add (env)
46
+ return [ args, options ]
47
+ },
48
+ }
49
+
50
+ module.exports = Object.assign ((..._) => cli.exec(..._), cli)
51
+ if (!module.parent) cli.exec()
52
+
53
+ /* eslint no-console:off */
@@ -0,0 +1 @@
1
+ throw new Error('This application uses @sap/cds version >= 7, which is not compatible with the installed @sap/cds-dk version 6. Either update @sap/cds-dk to version 7 or downgrade @sap/cds to version 6 instead.')
package/bin/serve.js CHANGED
@@ -154,6 +154,9 @@ async function serve (all=[], o={}) {
154
154
  if (o.watch) return _watch.call(this, o.project,o) // cds serve --watch <project>
155
155
  if (o.project) _chdir_to (o.project) // cds run --project <project>
156
156
 
157
+ // Ensure loading plugins before calling cds.env!
158
+ await cds.plugins
159
+
157
160
  const TRACE = cds.debug('trace')
158
161
  // if (TRACE) {
159
162
  // TRACE?.time('load express '); require('express') // eslint-disable-line cds/no-missing-dependencies
@@ -166,7 +169,7 @@ async function serve (all=[], o={}) {
166
169
  if (!o.silent) _prepare_logging ()
167
170
 
168
171
  // The following things are meant for dev mode, which can be overruled by feature flagse...
169
- const {features,fiori} = cds.env
172
+ const {features} = cds.env
170
173
  {
171
174
  // handle --with-mocks resp. --mocked
172
175
  if (features.with_mocks) o.mocked = _with_mocks(o)
@@ -180,16 +183,8 @@ async function serve (all=[], o={}) {
180
183
  // live reload, in cooperation with cds watch
181
184
  if (features.live_reload) require('../app/etc/livereload')
182
185
 
183
- // add dev helper for Fiori URLs
184
- if (fiori.routes) require('../app/fiori/routes')
185
-
186
- // add fiori preview links to default index.html
187
- if (fiori.preview) require('../app/fiori/preview')
188
-
189
186
  }
190
187
 
191
- // activate plugins
192
- await require("./plugins")(log)
193
188
  TRACE?.timeEnd('cds bootstrap ')
194
189
 
195
190
  // bootstrap server from project-local server.js or from @sap/cds/server.js
@@ -209,27 +204,28 @@ async function serve (all=[], o={}) {
209
204
  _resolve (server)
210
205
  }
211
206
 
207
+ const LOG = cds.log('cli|server')
212
208
  cds.shutdown = _shutdown //> for programmatic invocation
213
- process.on('unhandledRejection', (_,p) => _shutdown (console.error('❗️Uncaught',p)))
214
- process.on('uncaughtException', (e) => _shutdown (console.error('❗️Uncaught',e)))
209
+ process.on('unhandledRejection', (e,p) => _shutdown (e, LOG.error('❗️Uncaught',p)))
210
+ process.on('uncaughtException', (e) => _shutdown (e, LOG.error('❗️Uncaught',e)))
215
211
  process.on('SIGINT', cds.watched ? _shutdown : (s,n)=>_shutdown(s,n,console.log())) //> newline after ^C
216
212
  process.on('SIGHUP', _shutdown)
217
213
  process.on('SIGHUP2', _shutdown)
218
214
  process.on('SIGTERM', _shutdown)
219
215
 
220
216
  async function _shutdown (signal,n) {
221
- if (signal) DEBUG?.('⚡️',signal,n, 'received by cds serve')
222
- await Promise.all(cds.listeners('shutdown').map(fn => fn()))
217
+ let err = typeof signal === 'object' ? signal : LOG.debug('⚡️',signal,n, 'received by cds serve')
218
+ await Promise.all(cds.listeners('shutdown').map(fn => fn(err)))
223
219
  server.close(()=>{/* it's ok if closed already */}) // first, we try stopping server and process the nice way
224
- if (!global.it) setTimeout(process.exit,1111).unref() // after ~1 sec, we force-exit it, unless in test mode
220
+ let { force_exit_timeout: force_exit } = cds.env.server // after ~1 sec, we force-exit it, unless in test mode
221
+ if (force_exit && !global.it) setTimeout(process.exit,force_exit).unref()
225
222
  }
226
223
 
227
- const DEBUG = cds.debug('cli')
228
- if (DEBUG) {
229
- cds.on('shutdown', () => DEBUG ('⚡️','cds serve - cds.shutdown'))
230
- server.on('close', () => DEBUG ('⚡️','cds serve - server.close(d)'))
231
- process.on('exit', () => DEBUG ('⚡️','cds serve - process.exit'))
232
- process.on('beforeExit', ()=> DEBUG ('⚡️','cds serve - process.beforeExit'))
224
+ if (LOG._debug) {
225
+ cds.on('shutdown', () => LOG.debug ('⚡️','cds serve - cds.shutdown'))
226
+ server.on('close', () => LOG.debug ('⚡️','cds serve - server.close(d)'))
227
+ process.on('exit', () => LOG.debug ('⚡️','cds serve - process.exit'))
228
+ process.on('beforeExit', ()=> LOG.debug ('⚡️','cds serve - process.beforeExit'))
233
229
  }
234
230
 
235
231
  if (process.platform === 'win32') {
@@ -6,18 +6,19 @@ module.exports = function basic_auth (options) {
6
6
 
7
7
  /** @type { import('express').Handler } express_handler */
8
8
  return async function basic_auth (req, res, next) {
9
+ // REVISIT: passport also adds a login function with different meaning -> we need to be able to recognize ours -> req._login for now
9
10
  // allow subsequent code to request a user login
10
- req.login = login
11
+ req._login = login
11
12
  // get basic authorization header
12
13
  let auth = req.headers.authorization
13
14
  // enforce login if requested
14
- if (!auth) return login_required ? req.login('Logged in user required!') : next()
15
+ if (!auth || !auth.match(/^basic/i)) return login_required ? req._login('Logged in user required!') : next()
15
16
  // decode user credentials from autorization header
16
17
  let [id,pwd] = Buffer.from(auth.slice(6),'base64').toString().split(':')
17
18
  // verify user credentials and set req.user
18
19
  let u = req.user = await users.verify (id, pwd)
19
20
  // re-request login in case of wrong credentials
20
- if (u.failed) return req.login (u)
21
+ if (u.failed) return req._login (u)
21
22
  // support for feature toggles via req.headers.features
22
23
  if (req.headers.features) u = req.user = { ...u, features: req.headers.features } // NOTE: need to clone u
23
24
  // done...
@@ -27,7 +28,8 @@ module.exports = function basic_auth (options) {
27
28
 
28
29
  function login (reason='') {
29
30
  const req=this, res=req.res
30
- res.set ('WWW-Authenticate', `Basic realm="Users"`) .sendStatus (401)
31
+ // REVISIT: this json response is needed to be OData compliant. however, we should probably throw an error anyway so that a custom error middleware can get invoked.
32
+ res.set('WWW-Authenticate', `Basic realm="Users"`).status(401).json({ error: { code: '401', message: 'Unauthorized' } })
31
33
  LOG.info (req.method, decodeURIComponent(req.path), '>', res.statusCode, res.statusMessage, ...(!reason ? [] : ['-', reason]))
32
34
  }
33
35
  }
package/lib/auth/index.js CHANGED
@@ -18,14 +18,15 @@ require = _require // eslint-disable-line no-global-assign
18
18
  */
19
19
  function auth_factory (options) {
20
20
  const o = { ...options, ...cds.requires.auth }
21
- let kind = o.kind || o.strategy
21
+ let kind = o.impl ? 'custom' : o.kind || o.strategy
22
22
  let middleware = cds.auth[kind]
23
23
  if (middleware) {
24
24
  cds.log().info ('using auth strategy:', { kind }, '\n')
25
25
  } else {
26
- let impl = o.impl || path.resolve (__dirname, kind)
26
+ let impl = kind === 'custom' ? cds.resolve (o.impl)?.[0] : path.resolve (__dirname, kind)
27
27
  try { impl = require.resolve (impl) } catch {
28
- throw cds.error `Cannot find auth impl: ${impl}`
28
+ const e = o.impl ? `Cannot find custom impl at: ${o.impl}` : `Cannot find unknown auth kind: ${o.kind}`
29
+ throw cds.error(e)
29
30
  }
30
31
  cds.log().info ('using auth strategy:', { kind, impl: local(impl) }, '\n')
31
32
  middleware = require(impl)
@@ -10,11 +10,8 @@ module.exports = function jwt_auth(config) {
10
10
  // warn if no credentials
11
11
  if (!config.credentials) {
12
12
  LOG._warn &&
13
- LOG.warn(`
14
- No XSUAA instance bound to application, but "${config.kind}" configured.
15
- This is NOT recommended in production!
16
- `)
17
-
13
+ LOG.warn(`Authentication kind "${config.kind}" configured, but no XSUAA instance bound to application.
14
+ This is NOT recommended in production!`)
18
15
  return (req,res,next) => next()
19
16
  }
20
17
 
@@ -1,41 +1,38 @@
1
- const cds = require ('../index')
2
- const cdsc = require ('./cdsc')
3
- const {lazified} = require ('../lazy'); require = lazified (module) // eslint-disable-line
4
-
5
-
6
1
  /**
7
2
  * This is the central API facade to call compiler functions.
8
3
  */
9
4
  const compile = module.exports = Object.assign (cds_compile, {
10
5
 
11
- for: lazified ({
12
- java: require('./for/java'),
13
- nodejs: require('./for/nodejs'),
14
- drafts: require('./for/drafts'),
15
- lean_drafts: require('./for/lean_drafts'),
16
- odata: require('./for/odata'),
17
- sql: require('./for/sql'),
18
- }),
6
+ for: new class {
7
+ get java(){ return super.java = require('./for/java') }
8
+ get nodejs() { return super.nodejs = require('./for/nodejs') }
9
+ get drafts() { return super.drafts = require('./for/drafts') }
10
+ get lean_drafts() { return super.lean_drafts = require('./for/lean_drafts') }
11
+ get odata() { return super.odata = require('./for/odata') }
12
+ get sql() { return super.sql = require('./for/sql') }
13
+ },
14
+
15
+ to: new class {
16
+ get csn() { return super.csn = require('./to/csn') }
17
+ get cdl() { return super.cdl = require('./to/cdl') }
18
+ get gql() { return super.gql = require('./to/gql') }
19
+ get yml() { return super.yml = require('./to/yaml') }
20
+ get yaml() { return super.yaml = require('./to/yaml') }
21
+ get json() { return super.json = require('./to/json') }
22
+ get edm() { return super.edm = require('./to/edm') }
23
+ get edmx() { return super.edmx = compile.to.edm.x }
24
+ get sql() { return super.sql = require('./to/sql') }
25
+ get hdbcds() { return super.hdbcds = compile.to.sql.hdbcds }
26
+ get hdbtable() { return super.hdbtable = compile.to.sql.hdbtable }
27
+ get hdbtabledata() { return super.hdbtabledata = require('./to/hdbtabledata') }
28
+ get serviceinfo() { return super.serviceinfo = require('./to/srvinfo') } //> REVISIT: move to CLI
29
+ get graphql() { return super.graphql = require('./to/gql') } //> REVISIT: move to gql CLI plugin
30
+ },
19
31
 
20
- to: lazified ({
21
- csn: cds_compile,
22
- cdl: require('./to/cdl'),
23
- gql: require('./to/gql'),
24
- graphql: require('./to/gql'),
25
- yml: require('./to/yaml'),
26
- yaml: require('./to/yaml'),
27
- json: require('./to/json'),
28
- edm: require('./to/edm'), edmx: lazy => compile.to.edm.x,
29
- sql: require('./to/sql'),
30
- hdbcds: lazy => compile.to.sql.hdbcds,
31
- hdbtable: lazy => compile.to.sql.hdbtable,
32
- serviceinfo: require('./to/srvinfo'), //> REVISIT: move to CLI
33
- }),
34
-
35
- _localized: require('./etc/_localized'),
36
32
  })
37
33
 
38
34
 
35
+
39
36
  /**
40
37
  * This is the central frontend function to compile sources to CSN.
41
38
  * @param {string|string[]|{}} model one of:
@@ -49,70 +46,18 @@ const compile = module.exports = Object.assign (cds_compile, {
49
46
  * @returns {{ namespace?:string, definitions:{}, extensions?:[], meta:{ flavor:_flavor }}} CSN
50
47
  */
51
48
  function cds_compile (model, options, _flavor) {
52
- if (!model) throw cds.error (`Argument 'model' must be specified`)
53
- if (_is_csn(model) && _assert_flavor(model,_flavor,options)) return _fluent(model) //> already parsed csn
54
- const o = _options4 (options,_flavor)
55
- const cwd = o.cwd || cds.root
56
- const files = _is_files (model,cwd)
57
- if (files) {
58
- if (o.sync) return _fluent (_finalize (cdsc.compileSync(files,cwd,o))) //> compile files synchroneously
59
- else return _fluent (cdsc.compile(files,cwd,o) .then (_finalize)) //> compile files asynchroneously
60
- }
61
- else return _fluent (_finalize (cdsc.compileSources(model,o))) //> compile CDL sources
62
- function _finalize (csn) {
63
- if (o.min) csn = cds.minify(csn)
64
- // REVISIT: experimental implementation to detect external APIs
65
- for (let each in csn.definitions) {
66
- const d = csn.definitions[each]
67
- if (d.kind === 'service' && cds.requires[each]?.external && (!o.mocked || cds.requires[each].credentials)) {
68
- Object.defineProperty (d,'@cds.external', { value: cds.requires[each].kind || true })
69
- }
70
- }
71
- if (!csn.meta) csn.meta = {}
72
- csn.meta.flavor = o.flavor
73
- return csn
74
- }
49
+ const csn = compile.to.csn (model, options, _flavor)
50
+ return Object.defineProperties (csn, { // fluent
51
+ for : {configurable:true, get:()=> new Proxy ({api:compile.for,csn},_handlers)},
52
+ to : {configurable:true, get:()=> new Proxy ({api:compile.to, csn},_handlers)},
53
+ })
75
54
  }
76
55
 
77
-
78
- const _is_csn = (x) => (x.definitions || x.extensions) && !x.$builtins
79
- const _is_files = (m,root) => {
80
- if (Array.isArray(m) || /^file:/.test(m) && (m = m.slice(5)))
81
- return cds.resolve(m,{root}) || cds.error ( `Couldn't find a CDS model for '${m}' in ${root||cds.root}`,{ code:'MODEL_NOT_FOUND', model: m })
82
- }
83
- const _assert_flavor = (m,_flavor,options) => {
84
- if (!m.meta) return true; const f = _flavor || _flavor4 (options)
85
- return !f || f === m.meta.flavor || cds.error (`cds.compile(...,{flavor:'${f}'}) called on csn with different meta.flavor='${m.meta.flavor}'`)
86
- }
87
-
88
- const _flavors = {
89
- 'parsed': { level:1, cdsc_options: { parseCdl:true } },
90
- 'xtended': { level:2, cdsc_options: { csnFlavor:'gensrc' } },
91
- 'inferred': { level:3 },
92
- }
93
- const _flavor4 = (o) => {
94
- const f = typeof o === 'string' ? o : o && o.flavor
95
- return !f || f in _flavors ? f : cds.error (`Option 'flavor' must be one of ${Object.keys(_flavors)}; got: '${f}'`)
96
- }
97
- const _options4 = (_o, _flavor) => {
98
- const flavor = _flavor ? _flavor4(_flavor) : _flavor4(_o) || 'inferred'
99
- const spec = _flavors[flavor]
100
- const o = { ..._o, flavor, ...spec.cdsc_options, ...cds.env.cdsc, cdsHome: cds.home } // cdsHome is for the compiler resolving @sap/cds/... files
101
- if (o.docs) o.docComment = true
102
- if (o.locations) o.withLocations = true
103
- if (!o.messages) o.messages = []
104
- return o
105
- }
106
-
107
- const _fluent = (x) => Object.defineProperties (x, {
108
- 'for' : {configurable:true, get:()=> new Proxy ({api:compile.for,x},_handlers)},
109
- 'to' : {configurable:true, get:()=> new Proxy ({api:compile.to, x},_handlers)},
110
- })
111
56
  const _handlers = {
112
57
  ownKeys: ({api}) => Reflect.ownKeys (api),
113
- get: ({api,x},p) => {
58
+ get: ({api,csn},p) => {
59
+ delete csn.for; delete csn.to //> cleanup the decorated CSN or Promise
114
60
  let fn = api[p]; if (!fn) return
115
- delete x.for; delete x.to //> cleanup the decorated CSN or Promise
116
- return o => 'then' in x ? x.then(m => api[p](m,o)) : api[p](x,o)
61
+ return o => 'then' in csn ? csn.then(m => fn(m,o)) : fn(csn,o)
117
62
  }
118
63
  }
@@ -101,6 +101,17 @@ const _options = {for: Object.assign (_options4, {
101
101
 
102
102
  })}
103
103
 
104
+
105
+ const { inspect } = require('util')
106
+ compile.CompilationError.prototype [inspect.custom] = function() {
107
+ // return this.stack
108
+ return 'Errors by cds.compile ...'+ this.messages.map (e => {
109
+ let {file,line,col} = e.$location
110
+ return `\nin ${file}:${line}:${col} — ${e.severity}: ${e.message}`
111
+ }).join('') + this.stack.slice(this.message.length+7)
112
+ }
113
+
114
+
104
115
  /**
105
116
  * Return a derivate of cdsc, with the most prominent
106
117
  * @type { import('@sap/cds-compiler') }
@@ -17,8 +17,8 @@ function read (res, ext = '.properties') {
17
17
  }
18
18
 
19
19
  function parse (props) {
20
- const lines = props.split(/\r?\n/)
21
- const rows = lines.filter(each => !!each.trim()).map(each => {
20
+ const lines = props.split(/(?<![\\\r])\r?\n/)
21
+ const rows = lines.filter(each => !!each.trim()).map(each => each.replace(/\\\r?\n/, '')).map(each => {
22
22
  const index = each.indexOf('=')
23
23
  if (index < 0) return [each, '']
24
24
  return [each.slice(0, index).trim(), each.slice(index + 1).trim()]
@@ -19,58 +19,10 @@ function _isCompositionBacklink(e) {
19
19
  }
20
20
  }
21
21
 
22
- const IGNORED_ENTITY_ANNOTATIONS = new Set([
23
- '@readonly',
24
- '@insertonly',
25
- '@restrict',
26
- ])
27
-
28
- const IGNORED_ELEMENT_ANNOTATIONS = [
29
- '@assert.range',
30
- '@assert.enum',
31
- '@assert.format',
32
- '@assert.target',
33
- '@mandatory',
34
- '@Core.Immutable',
35
- '@readonly',
36
- '@Core.Computed',
37
- '@Common.FieldControl.Readonly',
38
- '@Common.FieldControl.Mandatory',
39
- '@FieldControl.Mandatory',
40
- '@FieldControl.ReadOnly',
41
- '@Common.FieldControl',
42
- '@PersonalData.DataSubjectRole',
43
- '@PersonalData.EntitySemantics',
44
- '@PersonalData.IsPotentiallyPersonal',
45
- '@PersonalData.IsPotentiallySensitive',
46
- '@PersonalData.FieldSemantics'
47
- // These are still needed:
48
- // '@odata.etag',
49
- // '@cds.on.update',
50
- // '@cds.on.insert',
51
- ]
52
-
53
22
  module.exports = function cds_compile_for_lean_drafts(csn) {
54
- const DRAFT_ELEMENTS = new Set([
55
- 'IsActiveEntity',
56
- 'HasDraftEntity',
57
- 'HasActiveEntity',
58
- 'DraftAdministrativeData',
59
- 'DraftAdministrativeData_DraftUUID',
60
- 'SiblingEntity'
61
- ])
62
- function _redirect(assoc, target, keys) {
23
+ function _redirect(assoc, target) {
63
24
  assoc.target = target.name
64
25
  assoc._target = target
65
- if (keys) assoc.on = _onCondition(assoc.name, keys)
66
- }
67
-
68
- function _onCondition(left, keys, right) {
69
- const on = []
70
- for (let k in keys)
71
- DRAFT_ELEMENTS.has(k) || on.push({ ref: [left, k] }, '=', { ref: right ? [right, k] : [k] }, 'and')
72
- on.pop()
73
- return on
74
26
  }
75
27
 
76
28
  function _isDraft(def) {
@@ -99,33 +51,52 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
99
51
  DraftIsProcessedByMe : Boolean; // REVISIT: these are calculated fields, aren't they?
100
52
  }
101
53
  `).definitions
102
- function draftEntity(active, model) {
54
+ function addDraftEntity(active, model) {
103
55
  const _draftEntity = active.name + '.drafts'
104
56
  const d = model.definitions[_draftEntity]
105
57
  if (d) return d
106
58
  // We need to construct a fake draft entity definition
107
- const draft = { __proto__: active, name: _draftEntity, elements: { ...active.elements, ...Draft.elements } }
59
+ // We cannot use new cds.entity because runtime aspects would be missing
60
+ const draft = {
61
+ __proto__: active,
62
+ name: _draftEntity,
63
+ elements: { ...active.elements, ...Draft.elements },
64
+ query: undefined
65
+ }
108
66
  Object.defineProperty(model.definitions, _draftEntity, { value: draft })
109
67
  Object.defineProperty(active, 'drafts', { value: draft })
110
68
  Object.defineProperty(draft, 'actives', { value: active })
111
69
  Object.defineProperty(draft, 'isDraft', { value: true })
112
- draft['@cds.persistence.table'] = _draftEntity
113
70
 
114
- for (const key in draft) {
115
- if (IGNORED_ENTITY_ANNOTATIONS.has(key) || key.startsWith('@Capabilities') || key.startsWith('@PersonalData')) draft[key] = undefined
116
- }
71
+ // Positive list would be bigger (search, requires, fiori, ...)
72
+ if (draft['@readonly']) draft['@readonly'] = undefined
73
+ if (draft['@insertonly']) draft['@insertonly'] = undefined
74
+ if (draft['@restrict']) draft['@restrict'] = undefined
75
+
117
76
  // Recursively add drafts for compositions
118
77
  for (const each in draft.elements) {
119
78
  const e = draft.elements[each]
120
79
  const newEl = Object.create(e)
121
- if (e.isComposition || (e.isAssociation && e['@odata.draft.enclosed']) || _isCompositionBacklink(e)) {
80
+ if (e.isComposition || (e.isAssociation && e['@odata.draft.enclosed']) || ((!active['@Common.DraftRoot.ActivationAction'] || e._target === active) && _isCompositionBacklink(e))) {
122
81
  if (e._target['@odata.draft.enabled'] === false) continue // happens for texts if @fiori.draft.enabled is not set
123
- _redirect(newEl, draftEntity(e._target, model))
82
+ _redirect(newEl, addDraftEntity(e._target, model))
124
83
  }
125
84
  newEl.parent = draft
126
- for (const ignoredAnno of IGNORED_ELEMENT_ANNOTATIONS) {
127
- if (newEl[ignoredAnno]) newEl[ignoredAnno] = undefined
85
+
86
+ for (const key in newEl) {
87
+ if (
88
+ key.startsWith('@assert') ||
89
+ key.startsWith('@FieldControl') ||
90
+ key.startsWith('@Common.FieldControl') ||
91
+ key.startsWith('@PersonalData') ||
92
+ key === '@mandatory' ||
93
+ key === '@readonly' ||
94
+ key === '@Core.Computed' ||
95
+ key === '@Core.Immutable'
96
+ )
97
+ newEl[key] = undefined
128
98
  }
99
+
129
100
  draft.elements[each] = newEl
130
101
  }
131
102
  return draft
@@ -133,16 +104,12 @@ module.exports = function cds_compile_for_lean_drafts(csn) {
133
104
  for (const name in csn.definitions) {
134
105
  const def = csn.definitions[name]
135
106
  if (!_isDraft(def)) continue
136
- ;[
137
- 'IsActiveEntity',
138
- 'HasDraftEntity',
139
- 'HasActiveEntity',
140
- 'DraftAdministrativeData_DraftUUID',
141
- 'DraftAdministrativeData'
142
- ].forEach(s => {
143
- def.elements[s].virtual = true
144
- })
107
+ def.elements.IsActiveEntity.virtual = true
108
+ def.elements.HasDraftEntity.virtual = true
109
+ def.elements.HasActiveEntity.virtual = true
110
+ def.elements.DraftAdministrativeData_DraftUUID.virtual = true
111
+ def.elements.DraftAdministrativeData.virtual = true
145
112
  // will insert drafts entities, so that others can use `.drafts` even without incoming draft requests
146
- draftEntity(def, csn, Draft)
113
+ addDraftEntity(def, csn)
147
114
  }
148
115
  }