@sap/cds 5.4.6 → 5.5.0

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 (228) hide show
  1. package/CHANGELOG.md +208 -2
  2. package/apis/ql.d.ts +17 -15
  3. package/app/index.js +1 -1
  4. package/bin/build/buildTaskEngine.js +26 -42
  5. package/bin/build/buildTaskFactory.js +6 -10
  6. package/bin/build/buildTaskHandler.js +2 -4
  7. package/bin/build/buildTaskProvider.js +3 -1
  8. package/bin/build/buildTaskProviderFactory.js +9 -15
  9. package/bin/build/constants.js +15 -3
  10. package/bin/build/index.js +5 -4
  11. package/bin/build/mtaUtil.js +8 -11
  12. package/bin/build/provider/buildTaskHandlerEdmx.js +63 -6
  13. package/bin/build/provider/buildTaskHandlerInternal.js +2 -34
  14. package/bin/build/provider/buildTaskProviderInternal.js +16 -42
  15. package/bin/build/provider/fiori/index.js +13 -24
  16. package/bin/build/provider/hana/2migration.js +17 -15
  17. package/bin/build/provider/hana/2tabledata.js +52 -48
  18. package/bin/build/provider/hana/index.js +27 -25
  19. package/bin/build/provider/hana/migrationtable.js +91 -67
  20. package/bin/build/provider/java-cf/index.js +14 -24
  21. package/bin/build/provider/mtx/index.js +12 -14
  22. package/bin/build/provider/node-cf/index.js +18 -32
  23. package/bin/cds.js +5 -5
  24. package/bin/serve.js +29 -23
  25. package/bin/version.js +0 -1
  26. package/lib/compile/etc/_localized.js +4 -9
  27. package/lib/compile/for/sql.js +5 -2
  28. package/lib/compile/parse.js +25 -17
  29. package/lib/compile/to/srvinfo.js +2 -1
  30. package/lib/connect/bindings.js +2 -1
  31. package/lib/connect/index.js +48 -49
  32. package/lib/core/classes.js +1 -1
  33. package/lib/core/reflect.js +10 -2
  34. package/lib/deploy.js +26 -23
  35. package/lib/env/defaults.js +13 -6
  36. package/lib/env/index.js +73 -78
  37. package/lib/env/requires.js +38 -19
  38. package/lib/index.js +9 -10
  39. package/lib/lazy.js +2 -2
  40. package/lib/log/index.js +33 -45
  41. package/lib/log/service/index.js +2 -2
  42. package/lib/ql/CREATE.js +14 -9
  43. package/lib/ql/DELETE.js +6 -5
  44. package/lib/ql/DROP.js +12 -9
  45. package/lib/ql/INSERT.js +40 -16
  46. package/lib/ql/Query.js +67 -40
  47. package/lib/ql/SELECT.js +162 -127
  48. package/lib/ql/UPDATE.js +74 -42
  49. package/lib/ql/Whereable.js +77 -87
  50. package/lib/ql/index.js +36 -24
  51. package/lib/ql/parse.js +35 -0
  52. package/lib/req/context.js +44 -8
  53. package/lib/req/locale.js +7 -7
  54. package/lib/serve/Service-api.js +21 -14
  55. package/lib/serve/Service-dispatch.js +28 -12
  56. package/lib/serve/Transaction.js +22 -10
  57. package/lib/serve/index.js +16 -11
  58. package/lib/utils/axios.js +23 -16
  59. package/lib/utils/data.js +35 -0
  60. package/lib/utils/tests.js +27 -18
  61. package/libx/_runtime/audit/generic/personal/access.js +81 -0
  62. package/libx/_runtime/audit/generic/personal/constants.js +4 -0
  63. package/libx/_runtime/audit/generic/personal/index.js +50 -0
  64. package/libx/_runtime/audit/generic/personal/modification.js +138 -0
  65. package/libx/_runtime/audit/generic/personal/utils.js +186 -0
  66. package/libx/_runtime/audit/utils/v2.js +10 -4
  67. package/libx/_runtime/cds-services/adapter/odata-v4/Dispatcher.js +5 -5
  68. package/libx/_runtime/cds-services/adapter/odata-v4/OData.js +6 -7
  69. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/action.js +5 -7
  70. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +5 -7
  71. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/delete.js +2 -3
  72. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/error.js +4 -0
  73. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +7 -4
  74. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +59 -8
  75. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +11 -1
  76. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +6 -10
  77. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +3 -46
  78. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/applyToCQN.js +2 -5
  79. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/createToCQN.js +2 -2
  80. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/deleteToCQN.js +4 -3
  81. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/expandToCQN.js +1 -2
  82. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +0 -1
  83. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/selectHelper.js +1 -1
  84. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +2 -2
  85. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +16 -18
  86. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/edm/EdmEntityType.js +6 -3
  87. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/format/RepresentationKind.js +4 -1
  88. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/core/OdataRequest.js +1 -0
  89. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/serializer/SerializerFactory.js +15 -2
  90. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/validator/OperationValidator.js +1 -0
  91. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  92. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +8 -1
  93. package/libx/_runtime/cds-services/adapter/odata-v4/utils/handlerUtils.js +6 -1
  94. package/libx/_runtime/cds-services/adapter/odata-v4/utils/omitValues.js +12 -5
  95. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +1 -7
  96. package/libx/_runtime/cds-services/adapter/odata-v4/utils/request.js +7 -7
  97. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +14 -18
  98. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +13 -13
  99. package/libx/_runtime/cds-services/adapter/rest/handlers/create.js +0 -1
  100. package/libx/_runtime/cds-services/adapter/rest/handlers/operation.js +2 -1
  101. package/libx/_runtime/cds-services/adapter/rest/handlers/read.js +2 -2
  102. package/libx/_runtime/cds-services/adapter/rest/rest-to-cqn/index.js +2 -4
  103. package/libx/_runtime/cds-services/adapter/rest/utils/result.js +4 -2
  104. package/libx/_runtime/cds-services/services/Service.js +40 -5
  105. package/libx/_runtime/cds-services/services/utils/columns.js +13 -7
  106. package/libx/_runtime/cds-services/services/utils/compareJson.js +88 -4
  107. package/libx/_runtime/cds-services/services/utils/differ.js +24 -6
  108. package/libx/_runtime/cds-services/services/utils/handlerUtils.js +2 -2
  109. package/libx/_runtime/common/composition/data.js +44 -55
  110. package/libx/_runtime/common/composition/delete.js +97 -71
  111. package/libx/_runtime/common/composition/index.js +2 -1
  112. package/libx/_runtime/common/composition/insert.js +34 -11
  113. package/libx/_runtime/common/composition/tree.js +119 -92
  114. package/libx/_runtime/common/composition/update.js +4 -1
  115. package/libx/_runtime/common/composition/utils.js +1 -3
  116. package/libx/_runtime/common/constants/draft.js +12 -1
  117. package/libx/_runtime/common/generic/auth.js +6 -22
  118. package/libx/_runtime/common/generic/crud.js +14 -13
  119. package/libx/_runtime/common/generic/input.js +23 -26
  120. package/libx/_runtime/common/generic/put.js +1 -1
  121. package/libx/_runtime/common/generic/sorting.js +16 -16
  122. package/libx/_runtime/common/i18n/index.js +1 -1
  123. package/libx/_runtime/common/i18n/messages.properties +4 -0
  124. package/libx/_runtime/common/utils/backlinks.js +12 -5
  125. package/libx/_runtime/common/utils/cqn.js +6 -1
  126. package/libx/_runtime/common/utils/cqn2cqn4sql.js +102 -101
  127. package/libx/_runtime/common/utils/csn.js +47 -4
  128. package/libx/_runtime/common/utils/data.js +0 -37
  129. package/libx/_runtime/common/utils/enrichWithKeysFromWhere.js +1 -1
  130. package/libx/_runtime/common/utils/entityFromCqn.js +7 -24
  131. package/libx/_runtime/common/utils/foreignKeyPropagations.js +39 -7
  132. package/libx/_runtime/common/utils/generateOnCond.js +11 -12
  133. package/libx/_runtime/common/utils/onlyKeysRemain.js +10 -0
  134. package/libx/_runtime/common/utils/path.js +35 -0
  135. package/libx/_runtime/common/utils/postProcessing.js +86 -0
  136. package/libx/_runtime/common/utils/quotingStyles.js +37 -26
  137. package/libx/_runtime/common/utils/resolveView.js +223 -171
  138. package/libx/_runtime/common/utils/rewriteAsterisk.js +46 -26
  139. package/libx/_runtime/common/utils/structured.js +6 -12
  140. package/libx/_runtime/common/utils/template.js +10 -5
  141. package/libx/_runtime/common/utils/templateDelimiter.js +1 -0
  142. package/libx/_runtime/common/utils/templateProcessor.js +22 -30
  143. package/libx/_runtime/common/utils/union.js +31 -0
  144. package/libx/_runtime/common/utils/unionCqnTemplate.js +184 -0
  145. package/libx/_runtime/db/Service.js +1 -1
  146. package/libx/_runtime/db/data-conversion/timestamp.js +2 -9
  147. package/libx/_runtime/db/expand/expandCQNToJoin.js +204 -297
  148. package/libx/_runtime/db/expand/index.js +3 -3
  149. package/libx/_runtime/db/expand/rawToExpanded.js +36 -7
  150. package/libx/_runtime/db/generic/index.js +1 -1
  151. package/libx/_runtime/db/generic/input.js +5 -7
  152. package/libx/_runtime/db/generic/integrity.js +1 -1
  153. package/libx/_runtime/db/generic/rewrite.js +2 -10
  154. package/libx/_runtime/db/generic/update.js +13 -5
  155. package/libx/_runtime/db/generic/virtual.js +22 -58
  156. package/libx/_runtime/db/query/delete.js +7 -4
  157. package/libx/_runtime/db/query/insert.js +6 -4
  158. package/libx/_runtime/db/query/read.js +13 -20
  159. package/libx/_runtime/db/query/run.js +4 -1
  160. package/libx/_runtime/db/query/update.js +5 -4
  161. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +35 -2
  162. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +17 -2
  163. package/libx/_runtime/db/sql-builder/InsertBuilder.js +6 -5
  164. package/libx/_runtime/db/sql-builder/ReferenceBuilder.js +10 -0
  165. package/libx/_runtime/db/sql-builder/SelectBuilder.js +35 -24
  166. package/libx/_runtime/db/sql-builder/UpdateBuilder.js +14 -4
  167. package/libx/_runtime/db/sql-builder/arrayed.js +4 -0
  168. package/libx/_runtime/db/utils/deep.js +8 -0
  169. package/libx/_runtime/db/utils/generateAliases.js +2 -1
  170. package/libx/_runtime/fiori/generic/activate.js +19 -15
  171. package/libx/_runtime/fiori/generic/before.js +3 -11
  172. package/libx/_runtime/fiori/generic/cancel.js +1 -1
  173. package/libx/_runtime/fiori/generic/delete.js +3 -1
  174. package/libx/_runtime/fiori/generic/edit.js +12 -2
  175. package/libx/_runtime/fiori/generic/new.js +5 -5
  176. package/libx/_runtime/fiori/generic/patch.js +0 -18
  177. package/libx/_runtime/fiori/generic/read.js +241 -189
  178. package/libx/_runtime/fiori/utils/delete.js +36 -7
  179. package/libx/_runtime/fiori/utils/handler.js +43 -44
  180. package/libx/_runtime/fiori/utils/where.js +30 -15
  181. package/libx/_runtime/hana/customBuilder/CustomSelectBuilder.js +4 -6
  182. package/libx/_runtime/hana/execute.js +2 -2
  183. package/libx/_runtime/hana/localized.js +4 -4
  184. package/libx/_runtime/hana/pool.js +29 -14
  185. package/libx/_runtime/hana/search2cqn4sql.js +2 -1
  186. package/libx/_runtime/hana/searchToContains.js +18 -14
  187. package/libx/_runtime/index.js +0 -5
  188. package/libx/_runtime/messaging/AMQPWebhookMessaging.js +13 -5
  189. package/libx/_runtime/messaging/common-utils/naming-conventions.js +4 -1
  190. package/libx/_runtime/messaging/enterprise-messaging-utils/EMManagement.js +31 -19
  191. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +1 -2
  192. package/libx/_runtime/messaging/enterprise-messaging.js +6 -4
  193. package/libx/_runtime/messaging/service.js +7 -6
  194. package/libx/_runtime/odata/cqn2odata.js +110 -43
  195. package/libx/_runtime/odata/index.js +26 -48
  196. package/libx/_runtime/odata/odata2cqn.js +1 -6154
  197. package/libx/_runtime/odata/odata2cqn.pegjs +559 -0
  198. package/libx/_runtime/odata/readToCqn.js +94 -64
  199. package/libx/_runtime/remote/Service.js +74 -21
  200. package/libx/_runtime/remote/cqn2odata/index.js +1 -5
  201. package/libx/_runtime/remote/utils/client.js +24 -101
  202. package/libx/_runtime/remote/utils/dataConversion.js +27 -12
  203. package/libx/_runtime/sqlite/Service.js +3 -5
  204. package/libx/_runtime/sqlite/execute.js +23 -24
  205. package/libx/_runtime/sqlite/localized.js +12 -7
  206. package/libx/_runtime/types/api.js +10 -0
  207. package/package.json +1 -1
  208. package/server.js +16 -2
  209. package/lib/ql/grammar.pegjs +0 -208
  210. package/lib/ql/parser.js +0 -1
  211. package/lib/ql/rt/DELETE.js +0 -29
  212. package/lib/ql/rt/INSERT.js +0 -23
  213. package/lib/ql/rt/Query.js +0 -84
  214. package/lib/ql/rt/SELECT.js +0 -174
  215. package/lib/ql/rt/UPDATE.js +0 -119
  216. package/lib/ql/rt/_helpers.js +0 -91
  217. package/lib/ql/rt/index.js +0 -32
  218. package/libx/_runtime/audit/generic/personal.js +0 -260
  219. package/libx/_runtime/cds-services/statements/BaseStatement.js +0 -72
  220. package/libx/_runtime/cds-services/statements/Create.js +0 -57
  221. package/libx/_runtime/cds-services/statements/Delete.js +0 -33
  222. package/libx/_runtime/cds-services/statements/Drop.js +0 -42
  223. package/libx/_runtime/cds-services/statements/Insert.js +0 -201
  224. package/libx/_runtime/cds-services/statements/Select.js +0 -826
  225. package/libx/_runtime/cds-services/statements/Update.js +0 -181
  226. package/libx/_runtime/cds-services/statements/Where.js +0 -726
  227. package/libx/_runtime/cds-services/statements/index.js +0 -25
  228. package/libx/_runtime/common/generic/resolve-mock.js +0 -9
@@ -4,10 +4,8 @@ const path = require('path')
4
4
  const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
5
5
  const { isOldJavaStack, BuildError } = require('../../util')
6
6
 
7
- const { BUILD_OPTION_OUTPUT_MODE, ODATA_VERSION, ODATA_VERSION_V2,
8
- OUTPUT_MODE_RESULT_ONLY, FILE_EXT_CDS, SKIP_ASSERT_COMPILER_V2 } = require('../../constants')
7
+ const { BUILD_OPTION_OUTPUT_MODE, ODATA_VERSION, ODATA_VERSION_V2, OUTPUT_MODE_RESULT_ONLY, FILE_EXT_CDS, SKIP_ASSERT_COMPILER_V2, CONTENT_LANGUAGE_BUNDLES, CONTENT_DEFAULT_CSN } = require('../../constants')
9
8
  const { INFO } = require('../../buildTaskHandler')
10
- const DEBUG = process.env.DEBUG
11
9
 
12
10
  const DEFAULT_COMPILE_DEST_FOLDER = path.normalize('src/main/resources/edmx')
13
11
 
@@ -45,9 +43,13 @@ class JavaCfModuleBuilder extends BuildTaskHandlerEdmx {
45
43
  return this._result
46
44
  }
47
45
 
48
- const odata = await this._compileCsn(model, this.task.options.compileDest, odataOptions)
49
- await this.compileEdmx(odata, this.task.options.compileDest, odataOptions)
46
+ const odata = await this._compileForOdata(model, this.task.options.compileDest, odataOptions)
47
+ await this.compileToEdmx(odata, this.task.options.compileDest, odataOptions)
50
48
 
49
+ if (this.hasBuildOption(CONTENT_LANGUAGE_BUNDLES, true)) {
50
+ // collect and write language bundles into single i18n.json file
51
+ await this.collectLanguageBundles(model, this.task.dest)
52
+ }
51
53
  if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
52
54
  await this._copyNativeContent(src, dest)
53
55
  }
@@ -59,9 +61,7 @@ class JavaCfModuleBuilder extends BuildTaskHandlerEdmx {
59
61
  await super.clean()
60
62
  return
61
63
  }
62
- if (DEBUG) {
63
- this.logger.log(`Deleting build target folder ${this.task.options.compileDest}`)
64
- }
64
+ this.logger._debug && this.logger.debug(`Deleting build target folder ${this.task.options.compileDest}`)
65
65
  await fs.remove(this.task.options.compileDest)
66
66
  }
67
67
 
@@ -76,7 +76,7 @@ class JavaCfModuleBuilder extends BuildTaskHandlerEdmx {
76
76
  })
77
77
  }
78
78
 
79
- async _compileCsn(model, csnDest, compileOptions) {
79
+ async _compileForOdata(model, csnDest, compileOptions) {
80
80
  // csn for service providers
81
81
  const odataOptions = {
82
82
  ...this._options4odata(),
@@ -84,21 +84,11 @@ class JavaCfModuleBuilder extends BuildTaskHandlerEdmx {
84
84
  }
85
85
  const odataModel = this.cds.compile.for.odata(model, odataOptions)
86
86
 
87
- // This will als add a @source annotation containing the relative path to the origin .cds source file.
88
- // The @source annotation is required for correct custom handler resolution if no @impl annotation has been defined as
89
- // custom service handler implementations are relative to the origin .cds source files.
90
- // For staging builds (task.src !== task.dest) the csn.json file that is served at runtime is copied into a corresponding srv subfolder.
91
- // As a consequence the src folder name has to be included in the @source file name while for inplace builds (task.src === task.dest) this is not the case.
92
- // This ensures that the paths are relative to the cwd when executing cds run.
93
- const jsonOptions = {
94
- cwd: this.buildOptions.root,
95
- src: this.task.src === this.task.dest ? this.task.src : this.buildOptions.root
96
- }
97
- const extCsn = this.cds.compile.to.json(odataModel, jsonOptions)
98
- this._result.csn = JSON.parse(extCsn)
99
-
100
- if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
101
- await this.write(extCsn).to(path.join(csnDest, 'csn.json'))
87
+ // adding csn to build result containing @source and _where persisted properties
88
+ if (this.hasBuildOption(CONTENT_DEFAULT_CSN, true)) { //default true or undefined
89
+ await this.compileToJson(model, csnDest)
90
+ } else {
91
+ await this.compileToJson(odataModel, csnDest)
102
92
  }
103
93
  return odataModel
104
94
  }
@@ -1,22 +1,22 @@
1
1
  /* eslint-disable no-empty */
2
2
  const { fs } = require('@sap/cds-foss')
3
3
  const path = require('path')
4
- const BuildTaskHandlerInternal = require('../buildTaskHandlerInternal')
5
- const BuildTaskProviderInternal = require('../buildTaskProviderInternal')
6
4
  const { BUILD_TASK_HANA, FOLDER_GEN } = require('../../constants')
7
5
  const { WARNING } = require('../../buildTaskHandler')
8
- const DEBUG = process.env.DEBUG
6
+ const BuildTaskProviderInternal = require("../buildTaskProviderInternal")
7
+ const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
9
8
 
10
9
  const FOLDER_SDC = "sdc"
11
10
  const FOLDER_NODE_MODULES = "node_modules"
12
11
  const FOLDER_TEMPLATES = "tpl"
13
12
 
14
- class MtxModuleBuilder extends BuildTaskHandlerInternal {
13
+ class MtxModuleBuilder extends BuildTaskHandlerEdmx {
15
14
  get priority() {
16
15
  // should be scheduled after all other build tasks are finished
17
- return BuildTaskHandlerInternal.PRIORITY_MIN_VALUE
16
+ return BuildTaskHandlerEdmx.PRIORITY_MIN_VALUE
18
17
  }
19
18
  init() {
19
+ super.init()
20
20
  if (this.buildOptions.root === this.buildOptions.target) {
21
21
  this.task.dest = path.join(this.task.dest, FOLDER_GEN, FOLDER_SDC)
22
22
  } else {
@@ -38,19 +38,19 @@ class MtxModuleBuilder extends BuildTaskHandlerInternal {
38
38
  // copy base model sources
39
39
  await Promise.all(model.$sources.map(src => {
40
40
  if (src.includes(FOLDER_NODE_MODULES)) {
41
- return this.copy(src).to(path.join(this.task.dest, src.substr(src.indexOf(FOLDER_NODE_MODULES))))
41
+ return this.copy(src).to(src.substr(src.indexOf(FOLDER_NODE_MODULES)))
42
42
  } else {
43
43
  const relSrc = path.relative(this.buildOptions.root, src)
44
44
  if (relSrc.startsWith("..")) {
45
- this.logger.warn(`[cds] - model file is out of project scope, skipping file ${src}`)
45
+ this.logger.warn(`model file is out of project scope, skipping file ${src}`)
46
46
  return Promise.resolve()
47
47
  }
48
- return this.copy(src).to(path.join(this.task.dest, relSrc))
48
+ return this.copy(src).to(relSrc)
49
49
  }
50
50
  }))
51
51
 
52
52
  // collect and write language bundles into single i18n.json file
53
- await this.copyLanguageBundles(model, this.task.dest)
53
+ await this.collectLanguageBundles(model, this.task.dest)
54
54
 
55
55
  // copy native hana content and templates
56
56
  await this._copyNativeContent(this.task.src, this.task.dest, tenantDbPath)
@@ -62,9 +62,7 @@ class MtxModuleBuilder extends BuildTaskHandlerInternal {
62
62
  // delete entire folder 'gen'
63
63
  const genDest = path.dirname(this.task.dest)
64
64
  if (path.basename(genDest) === FOLDER_GEN) {
65
- if (DEBUG) {
66
- this.logger.log(`Deleting build target folder ${genDest}`)
67
- }
65
+ this.logger._debug && this.logger.debug(`Deleting build target folder ${genDest}`)
68
66
  await fs.remove(genDest)
69
67
  }
70
68
  }
@@ -207,9 +205,9 @@ class MtxModuleBuilder extends BuildTaskHandlerInternal {
207
205
  if (!tenantDbPath) {
208
206
  tenantDbPath = path.join(this.buildOptions.root, this.env.folders.db)
209
207
  if (hanaDbPaths.length === 0) {
210
- this.pushMessage(`[cds] - no 'hana' build task found, use default location '${tenantDbPath}'`, WARNING)
208
+ this.pushMessage(`no 'hana' build task found, use default location '${tenantDbPath}'`, WARNING)
211
209
  } else {
212
- this.pushMessage(`[cds] - no 'hana' build task found matching model scope '${this.task.options.model}', use default location '${tenantDbPath}'`, WARNING)
210
+ this.pushMessage(`no 'hana' build task found matching model scope '${this.task.options.model}', use default location '${tenantDbPath}'`, WARNING)
213
211
  }
214
212
  }
215
213
  return tenantDbPath
@@ -4,15 +4,19 @@ const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
4
4
  const { getHanaDbModuleDescriptor, getServiceModuleDescriptor } = require('../../mtaUtil')
5
5
  const { BuildError } = require('../../util')
6
6
  const { BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY, ODATA_VERSION, ODATA_VERSION_V2,
7
- BUILD_NODEJS_EDMX_GENERAION, BUILD_TASK_HANA, FOLDER_GEN } = require('../../constants')
7
+ BUILD_TASK_HANA, FOLDER_GEN, BUILD_NODEJS_EDMX_GENERAION, EDMX_GENERATION, SKIP_PACKAGE_JSON_GENERATION, SKIP_MANIFEST_GENERATION, CONTENT_EDMX, CONTENT_MANIFEST, CONTENT_PACKAGE_JSON } = require('../../constants')
8
8
  const { WARNING } = require('../../buildTaskHandler')
9
9
 
10
- const DEBUG = process.env.DEBUG
11
10
  const FILE_NAME_MANIFEST_YML = "manifest.yml"
12
11
 
13
12
  class NodeCfModuleBuilder extends BuildTaskHandlerEdmx {
14
13
  init() {
15
14
  super.init()
15
+ // set unified option values in order to easy access later on
16
+ this.task.options[CONTENT_EDMX] = this.hasBuildOption(CONTENT_EDMX, true) || this.hasCdsEnvOption(BUILD_NODEJS_EDMX_GENERAION, true) || this.hasBuildOption(EDMX_GENERATION, true) ? true : false
17
+ this.task.options[CONTENT_MANIFEST] = !this.hasBuildOption(CONTENT_MANIFEST, false) && !this.hasBuildOption(SKIP_MANIFEST_GENERATION, true) ? true : false
18
+ this.task.options[CONTENT_PACKAGE_JSON] = !this.hasBuildOption(CONTENT_PACKAGE_JSON, false) && !this.hasBuildOption(SKIP_PACKAGE_JSON_GENERATION, true) ? true : false
19
+
16
20
  if (this.task.options.compileDest) {
17
21
  throw new BuildError("Option not supported - compileDest")
18
22
  }
@@ -31,36 +35,20 @@ class NodeCfModuleBuilder extends BuildTaskHandlerEdmx {
31
35
  return this._result
32
36
  }
33
37
 
34
- // This will als add a @source annotation containing the relative path to the origin .cds source file.
35
- // The @source annotation is required for correct custom handler resolution if no @impl annotation has been defined as
36
- // custom service handler implementations are relative to the origin .cds source files.
37
- // For staging builds (task.src !== task.dest) the csn.json file that is served at runtime is copied into a corresponding srv subfolder.
38
- // As a consequence the src folder name has to be included in the @source file name while for inplace builds (task.src === task.dest) this is not the case.
39
- // This ensures that the paths are relative to the cwd when executing cds run.
40
- const jsonOptions = {
41
- cwd: this.buildOptions.root,
42
- src: this.task.src === this.task.dest ? this.task.src : this.buildOptions.root
43
- }
44
- const extCsn = this.cds.compile.to.json(model, jsonOptions)
45
-
46
- const extModel = JSON.parse(extCsn)
47
- this._result.csn = extModel
48
-
49
- if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
50
- await this.write(extCsn).to(path.join(this.destGen, "csn.json"))
51
- }
38
+ // adding csn to build result containing @source and _where persisted properties
39
+ await this.compileToJson(model, this.destGen)
52
40
 
53
41
  // collect and write language bundles into single i18n.json file
54
- await this.copyLanguageBundles(model, this.destGen)
42
+ await this.collectLanguageBundles(model, this.destGen)
55
43
 
56
- if (this.hasCdsEnvOption(BUILD_NODEJS_EDMX_GENERAION, true) || this.hasBuildOption('edmxGeneration', true)) {
57
- await this.compileEdmx(model, this.destGen)
44
+ if (this.hasBuildOption(CONTENT_EDMX, true)) {
45
+ await this.compileToEdmx(model, this.destGen)
58
46
  }
59
47
 
60
48
  if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
61
49
  await this._copyNativeContent(this.task.src, this.isStagingBuild() ? this.destGen : path.dirname(this.destGen))
62
50
 
63
- if (!this.task.options.skipManifestGeneration) {
51
+ if (this.hasBuildOption(CONTENT_MANIFEST, true)) {
64
52
  await Promise.all([this._writeManifestYml(), this._writeCfIgnore()])
65
53
  }
66
54
  }
@@ -72,9 +60,7 @@ class NodeCfModuleBuilder extends BuildTaskHandlerEdmx {
72
60
  if (this.buildOptions.target === this.buildOptions.root) {
73
61
  // delete the entire 'task.dest' folder otherwise, for details see #constructor
74
62
  // - the value of the folder 'src' has been appended to the origin 'task.dest' dir
75
- if (DEBUG) {
76
- this.logger.log(`Deleting build target folder ${this.destGen}`)
77
- }
63
+ this.logger._debug && this.logger.debug(`Deleting build target folder ${this.destGen}`)
78
64
  await fs.remove(this.isStagingBuild() ? this.task.dest : this.destGen)
79
65
  }
80
66
  }
@@ -102,7 +88,7 @@ class NodeCfModuleBuilder extends BuildTaskHandlerEdmx {
102
88
  if (/\.js$|\.properties$/.test(entry)) {
103
89
  return true
104
90
  }
105
- if (/package\.json$/.test(entry) && !this.task.options.skipPackageJsonGeneration) {
91
+ if (/package\.json$/.test(entry) && this.hasBuildOption(CONTENT_PACKAGE_JSON, true)) {
106
92
  packageJsonCopy = true
107
93
  return true
108
94
  }
@@ -126,7 +112,7 @@ class NodeCfModuleBuilder extends BuildTaskHandlerEdmx {
126
112
  let changed = false
127
113
  Object.keys(deps).forEach(key => {
128
114
  if (typeof deps[key] === 'string' && deps[key].startsWith('.') || deps[key].startsWith('file:')) {
129
- this.logger.log(`[cds] - ${this.task.for}: removing file dependency '${deps[key]}' from ${path.relative(this.buildOptions.root, file)}`)
115
+ this.logger.log(`${this.task.for}: removing file dependency '${deps[key]}' from ${path.relative(this.buildOptions.root, file)}`)
130
116
  delete deps[key]
131
117
  changed = true
132
118
  }
@@ -136,8 +122,8 @@ class NodeCfModuleBuilder extends BuildTaskHandlerEdmx {
136
122
  function _addEnginesField(content) {
137
123
  if (!content.engines || !content.engines.node) {
138
124
  const { engines } = require('../../../../package.json')
139
- this.logger.log(`[cds] - ${this.task.for}: adding node engines version to package.json ${engines}`)
140
125
  if (engines && engines.node) {
126
+ this.logger.log(`${this.task.for}: adding node engines version to package.json ${engines.node}`)
141
127
  content.engines = content.engines || {}
142
128
  content.engines.node = engines.node
143
129
  return true
@@ -193,8 +179,8 @@ class NodeCfModuleBuilder extends BuildTaskHandlerEdmx {
193
179
  if (hanaBuildTask) {
194
180
  const dbModuleDescriptor = await getHanaDbModuleDescriptor(this.buildOptions.root, path.basename(hanaBuildTask.src), this.logger)
195
181
  hanaServiceBinding = ` - ${dbModuleDescriptor.hdiServiceName}`
196
- } else if (DEBUG) {
197
- this.logger.log("[cds] - generating manifest.yml without HANA service binding, using sqlite database")
182
+ } else {
183
+ this.logger.debug("generating manifest.yml without HANA service binding, using sqlite database")
198
184
  }
199
185
 
200
186
  try {
package/bin/cds.js CHANGED
@@ -40,9 +40,9 @@ const cli = { //NOSONAR
40
40
  }
41
41
 
42
42
  function add (k,v) { options[k.slice(2)] = v || true }
43
- function add_global (k,v) {
43
+ function add_global (k,v='') {
44
44
  if (k === '--production') return process.env.NODE_ENV = 'production'
45
- if (k === '--profile') return process.env.NODE_ENV = v.split(',')
45
+ if (k === '--profile') return process.env.CDS_ENV = v.split(',')
46
46
  if (k === '--odata') v = { flavor:v }
47
47
  let e=env || (env={}), path = k.slice(2).split('-')
48
48
  while (path.length > 1) { let p = path.shift(); e = e[p]||(e[p]={}) }
@@ -54,10 +54,10 @@ const cli = { //NOSONAR
54
54
  },
55
55
 
56
56
  errorHandlers () {
57
- const _error = (e) => { cli.log(e.errors || e, { 'log-level': (cds.env.log && cds.env.log.levels && cds.env.log.levels.cli) || 'warn' }); _exit(1) }
57
+ const _error = (e) => { cli.log(e.errors || e, { 'log-level': cds.env.log.levels.cli }); _exit(1) }
58
58
  const _exit = (c) => { console.log(); process.exit(c) }
59
- process.on ('unhandledRejection', _error)
60
- process.on ('uncaughtException', _error)
59
+ cds.repl || process.on ('unhandledRejection', _error)
60
+ cds.repl || process.on ('uncaughtException', _error)
61
61
  process.on ('SIGTERM',_exit)
62
62
  process.on ('SIGHUP',_exit)
63
63
  process.on ('SIGINT',_exit)
package/bin/serve.js CHANGED
@@ -124,7 +124,7 @@ module.exports = Object.assign ( serve, {
124
124
 
125
125
 
126
126
  const cds = require('../lib'), { exists, isfile, local, path } = cds.utils
127
-
127
+ let log = console.log // provisional logger, see _prepareLogging
128
128
 
129
129
  /**
130
130
  * The main function which dispatches into the respective usage variants.
@@ -145,7 +145,7 @@ async function serve (all=[], o={}) { // NOSONAR
145
145
  // handle --watch and --project
146
146
  if (o.watch) return _watch (o.project,o) // cds serve --watch <project>
147
147
  if (o.project) _chdir_to (o.project) // cds run --project <project>
148
- if (!o.silent) _prepare_logging (o)
148
+ if (!o.silent) _prepare_logging ()
149
149
 
150
150
  // The following things are meant for dev mode, which can be overruled by feature flagse...
151
151
  const {features} = cds.env
@@ -192,43 +192,46 @@ function _local_server_js() {
192
192
  const _local = file => isfile(file) || isfile (path.join(cds.env.folders.srv,file))
193
193
  let server_js = process.env.CDS_TYPESCRIPT && _local('server.ts') || _local('server.js')
194
194
  if (server_js) {
195
- console.log ('[cds] - Loading server from', { file: local(server_js) })
195
+ log && log ('Loading server from', { file: local(server_js) })
196
196
  const fn = require (server_js)
197
197
  return typeof fn === 'function' ? fn : cds.error `${local(server_js)} must export a function`
198
198
  }
199
199
  }
200
200
 
201
201
 
202
- function _prepare_logging (o) { // NOSONAR
202
+ function _prepare_logging () { // NOSONAR
203
+ // change `log` function to cds.log
204
+ const LOG = cds.log('serve', { prefix:'cds' })
205
+ log = LOG._info && LOG.info
203
206
 
204
- const _timer = '[cds] - launched in'
205
- console.time (_timer)
206
- console.log()
207
+ const _timer = log && `[cds] - launched at ${new Date().toLocaleString()}, in`
208
+ _timer && console.time (_timer)
207
209
 
208
210
  // print information when model is loaded
209
211
  cds.on ('loaded', (model)=>{
210
- console.log (`[cds] - model loaded from ${model.$sources.length} file(s):\n\x1b[2m`)
211
- for (let each of model.$sources) console.log (' ', local(each))
212
- console.log ('\x1b[0m')
212
+ log && log (`model loaded from ${model.$sources.length} file(s):\n\x1b[2m`)
213
+ for (let each of model.$sources) log && console.log (' ', local(each))
214
+ log && console.log ('\x1b[0m')
213
215
  })
214
216
 
215
217
  // print information about each connected service
216
218
  cds.on ('connect', ({name,kind,options:{use,credentials}})=>{
217
- console.log (`[cds] - connect to ${name} > ${use||kind}`, _redacted(credentials))
219
+ log && log (`connect to ${name} > ${use||kind}`, _redacted(credentials))
218
220
  })
219
221
 
220
222
  // print information about each provided service
221
223
  cds.on ('serving', (srv) => {
222
224
  const details = { at: srv.path }
223
225
  if (srv._source) details.impl = local(srv._source)
224
- console.log (`[cds] - ${srv.mocked ? 'mocking' : 'serving'} ${srv.name}`, details)
226
+ log && log (`${srv.mocked ? 'mocking' : 'serving'} ${srv.name}`, details)
225
227
  })
226
228
 
227
229
  // print info when we are finally on air
228
230
  cds.once ('listening', ({url})=>{
229
- console.log ('\n[cds] - server listening on',{url})
230
- console.timeEnd (_timer)
231
- if (process.stdin.isTTY) console.log (`[ terminate with ^C ]\n`)
231
+ log && console.log ()
232
+ log && log ('server listening on',{url})
233
+ _timer && console.timeEnd (_timer)
234
+ if (process.stdin.isTTY) log && log (`[ terminate with ^C ]\n`)
232
235
  })
233
236
 
234
237
  return cds
@@ -264,7 +267,7 @@ function _in_memory (o) {
264
267
  }}})
265
268
  return true
266
269
  }
267
- if (db && db.credentials && db.credentials.database === ':memory:') {
270
+ if (db && db.credentials && (db.credentials.database || db.credentials.url) === ':memory:') {
268
271
  return true
269
272
  }
270
273
  }
@@ -277,7 +280,7 @@ function _with_mocks (o) {
277
280
  cds.on ('loaded', model => cds.deploy.include_external_entities_in(model))
278
281
  const mocks = cds.env.features.test_mocks && isfile ('test/mocked.js')
279
282
  if (mocks) cds.once ('served', ()=> {
280
- console.log ('[cds] - adding mock behaviours from', { file: local(mocks) })
283
+ log && log ('adding mock behaviours from', { file: local(mocks) })
281
284
  require(mocks)
282
285
  })
283
286
  return true
@@ -285,14 +288,17 @@ function _with_mocks (o) {
285
288
  }
286
289
 
287
290
 
291
+ const SECRETS = /(password)|(certificate)|(ca)|(clientsecret)/i // 'certificate' and 'ca' on HANA
288
292
  /** mascades password-like strings, also reducing clutter in output */
289
293
  function _redacted(cred) {
290
- const secrets = /(password)|(certificate)|(ca)/i // 'certificate' and 'ca' on HANA
291
- const newCred = Object.assign({}, cred)
292
- Object.keys(newCred)
293
- .filter((k) => typeof newCred[k] === 'string' && secrets.test(k))
294
- .forEach((k) => (newCred[k] = '...'))
295
- return newCred
294
+ if (cred === null) return cred
295
+ if (Array.isArray(cred)) return cred.map(_redacted)
296
+ if (typeof cred === 'object') {
297
+ const newCred = Object.assign({}, cred)
298
+ Object.keys(newCred).forEach(k => (typeof newCred[k] === 'string' && SECRETS.test(k)) ? (newCred[k] = '...') : (newCred[k] = _redacted(newCred[k])))
299
+ return newCred
300
+ }
301
+ return cred
296
302
  }
297
303
 
298
304
  /* eslint no-console:off */
package/bin/version.js CHANGED
@@ -54,7 +54,6 @@ function info(o) {
54
54
  const main = _findPackage (require.main.filename)
55
55
  return {
56
56
  ..._versions4(main, {}, true), // usually sap/cds-dk or sap/cds
57
- ..._versions4(o.all && '@sap/cds-sidecar-client', {}, null, o),
58
57
  ..._versions4('@sap/eslint-plugin-cds', {}, null, o),
59
58
  ..._versions4(process.cwd(), {}, null, o),
60
59
  ..._versions4('..', {}, null, o),
@@ -6,12 +6,7 @@ const _locales_4sql = {
6
6
  }
7
7
 
8
8
  // FIXME: we reliably need to now if we'll be on sqlite even before the connect happened
9
- const _on_sqlite = () => {
10
- const db = env.requires.db
11
- if (db) return db.kind === 'sqlite' || (db.kind === 'sql' && db.use === 'sqlite')
12
- return env.env === 'development'
13
- }
14
-
9
+ const _on_sqlite = (env.requires.db || env.requires.sql).dialect === 'sqlite'
15
10
  const { _texts_entries, _localized_entries } = env.cdsc.cv2 || {}
16
11
  const _been_here = Symbol('is _localized')
17
12
 
@@ -50,17 +45,17 @@ function unfold_csn (m) { // NOSONAR
50
45
  DEBUG && console.trace ('unfolding csn...')
51
46
  const pass2 = []
52
47
 
53
- const _locales = _on_sqlite() && _locales_4sql.sqlite
48
+ const _locales = _on_sqlite && _locales_4sql.sqlite
54
49
 
55
50
  // Pass 1 - add localized.<locale> entities and views
56
51
  for (let each in m.definitions) {
57
52
  const d = m.definitions [each]
58
53
  // Add <entry>_texts proxies for all <entry>.texts entities
59
- if (_texts_entries && each.endsWith('.texts')) {
54
+ if (_texts_entries !== false && each.endsWith('.texts')) {
60
55
  _add_proxy4 (d, each.slice(0,-6)+'_texts')
61
56
  }
62
57
  // Add localized.<entry> for all entities marked as .$localized
63
- if (_localized_entries && d.own('$localized')) {
58
+ if (_localized_entries !== false && d.own('$localized')) {
64
59
  let x = _add_proxy4 (d,`localized.${each}`)
65
60
  if (x) pass2.push ([x])
66
61
  // if running on sqlite add additional localized.<locale>. views
@@ -1,7 +1,10 @@
1
1
  /** REVISIT: uses internal APIs to restore compile.for.sql in SNAPI */
2
2
  const compile = require ('@sap/cds-compiler/lib/backends')
3
+ let _compile
3
4
 
4
5
  module.exports = function cds_compile_for_sql (src,o) {
5
- const {csn} = compile.toSqlWithCsn (src,{...o,csn:true})
6
- return csn
6
+ _compile = _compile || compile.toSqlWithCsn || compile.for_sql
7
+ // for_sql directly returns a CSN and not an object with a csn property
8
+ const res = _compile(src,{...o,csn:true})
9
+ return res.csn || res
7
10
  }
@@ -1,32 +1,39 @@
1
1
  const cdsc = require ('@sap/cds-compiler')
2
2
  const cds = require ('../index')
3
3
 
4
-
5
4
  /** cds.parse is both, a namespace and a shortcut for cds.parse.cdl */
6
5
  const cds_parse = (src,o) => cds.compile (src,o,'parsed')
7
6
  const parse = module.exports = Object.assign (cds_parse, {
8
7
 
9
- CDL: (...args) => tagged(cds.parse.cdl, ...args),
10
- CQL: (...args) => tagged(cds.parse.cql, ...args),
11
- CXL: (...args) => tagged(cds.parse.expr, ...args),
8
+ CDL: (...args) => tagged(parse.cdl, ...args),
9
+ CQL: (...args) => tagged(parse.cql, ...args),
10
+ CXL: (...args) => tagged(parse.expr, ...args),
12
11
 
13
12
  cdl: cds_parse,
14
- cql: x => { try { return cdsc.parse.cql(x,undefined,{messages:[]}) }
15
- catch(e) { // improve error message
16
- e.message = e.message.replace('<query>.cds:',`In '${e.cql = x}' at `)
17
- throw e
18
- }
19
- },
13
+ cql: x => { try { return cdsc.parse.cql(x,undefined,{messages:[]}) } catch(e) {
14
+ e.message = e.message.replace('<query>.cds:',`In '${e.cql = x}' at `)
15
+ throw e // with improved error message
16
+ }},
20
17
  path: (x,...values) => {
21
- if (x && x.raw) return tagged (cds.parse.path,x,...values)
22
- if (/^[A-Za-z_0-9.$]+$/.test(x)) return {ref:[x]}
23
- let {SELECT} = cds.parse.cql('SELECT from '+x)
18
+ if (x && x.raw) return tagged (parse.path,x,...values)
19
+ if (/^[A-Za-z_$][A-Za-z_0-9.$]*$/.test(x)) return {ref:[x]}
20
+ let {SELECT} = parse.cql('SELECT from '+x)
24
21
  return SELECT.from
25
22
  },
26
- expr: x => { try { return cdsc.parse.expr(x,undefined,{messages:[]}) }
27
- catch(e) { // improve error message
23
+ column: x => {
24
+ let as = /\s+as\s+(\w+)$/i.exec(x)
25
+ if (as) {
26
+ let col = parse.expr(x.slice(0,as.index)); col.as = as[1]
27
+ return col
28
+ }
29
+ else return parse.expr(x)
30
+ },
31
+ expr: x => {
32
+ if (typeof x !== 'string') throw cds.error.expected `${{x}} to be an expression string`
33
+ if (x in keywords) return {ref:[x]}
34
+ try { return cdsc.parse.expr(x,undefined,{messages:[]}) } catch(e) {
28
35
  e.message = e.message.replace('<expr>.cds:1:',`In '${e.expr = x}' at `)
29
- throw e
36
+ throw e // with improved error message
30
37
  }
31
38
  },
32
39
  xpr: x => { const y = parse.expr(x); return y.xpr || [y] },
@@ -68,4 +75,5 @@ const merge = (o,values) => {
68
75
  return o
69
76
  }
70
77
 
71
- const cxn4 = x => x.SELECT || x.ref || x.xpr || x.val || x.list || x.func ? x : {val:x}
78
+ const cxn4 = x => x.SELECT || x.ref || x.xpr || x.val !== undefined|| x.list || x.func ? x : {val:x}
79
+ const keywords = { KEY:1, key:1, SELECT:1, select:1 }
@@ -74,7 +74,8 @@ module.exports = (model, options={}) => {
74
74
  if (file) {
75
75
  const yaml = cds.load.yaml(file)
76
76
  for (let {cds} of Array.isArray(yaml) ? yaml : [yaml]) {
77
- if (cds) return cds['odata-v4.endpoint.path'] || cds['odata-v2.endpoint.path']
77
+ if (cds && cds['odata-v4.endpoint.path']) return cds['odata-v4.endpoint.path']
78
+ if (cds && cds['odata-v2.endpoint.path']) return cds['odata-v2.endpoint.path']
78
79
  }
79
80
  return 'odata/v4/'
80
81
  }
@@ -12,8 +12,9 @@ module.exports = class Bindings {
12
12
  static get registry(){ return registry }
13
13
 
14
14
  static then(r,e) {
15
+ const LOG = cds.log('serve', { prefix:'cds' })
15
16
  const bindings = new Bindings
16
- cds.prependOnceListener ('connect', ()=> console.log ('[cds] - connect using bindings from:', { registry }))
17
+ cds.prependOnceListener ('connect', ()=> LOG._info && LOG.info ('connect using bindings from:', { registry }))
17
18
  cds.once('listening', ({url})=> bindings.export (cds.service.providers, url))
18
19
  return bindings.import() .then (r,e)
19
20
  }