@sap/cds 6.8.4 → 7.0.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 (214) hide show
  1. package/CHANGELOG.md +58 -5
  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 +1 -1
  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 +1 -1
  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/srv-api.js +9 -3
  45. package/lib/srv/srv-dispatch.js +12 -9
  46. package/lib/srv/srv-models.js +4 -21
  47. package/lib/srv/srv-tx.js +15 -12
  48. package/lib/utils/cds-test.js +14 -9
  49. package/lib/utils/cds-utils.js +2 -12
  50. package/lib/utils/check-version.js +17 -0
  51. package/{bin/build → lib/utils}/csv-reader.js +23 -24
  52. package/libx/_runtime/auth/index.js +27 -23
  53. package/libx/_runtime/cds-services/adapter/odata-v4/ODataRequest.js +15 -72
  54. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/create.js +1 -1
  55. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/metadata.js +0 -2
  56. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +33 -63
  57. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/request.js +14 -18
  58. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/update.js +15 -5
  59. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/ExpressionToCQN.js +5 -4
  60. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/readToCQN.js +37 -40
  61. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/updateToCQN.js +7 -1
  62. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/utils.js +101 -38
  63. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/errors/AbstractError.js +5 -1
  64. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-commons/utils/ValueConverter.js +2 -1
  65. package/libx/_runtime/cds-services/adapter/odata-v4/okra/odata-server/deserializer/ResourceJsonDeserializer.js +9 -8
  66. package/libx/_runtime/cds-services/adapter/odata-v4/to.js +1 -1
  67. package/libx/_runtime/cds-services/adapter/odata-v4/utils/data.js +15 -11
  68. package/libx/_runtime/cds-services/adapter/odata-v4/utils/readAfterWrite.js +4 -0
  69. package/libx/_runtime/cds-services/adapter/odata-v4/utils/result.js +5 -2
  70. package/libx/_runtime/cds-services/adapter/odata-v4/utils/stream.js +1 -123
  71. package/libx/_runtime/cds-services/services/Service.js +79 -107
  72. package/libx/_runtime/cds-services/services/utils/columns.js +23 -19
  73. package/libx/_runtime/cds-services/services/utils/compareJson.js +11 -1
  74. package/libx/_runtime/cds-services/services/utils/differ.js +7 -2
  75. package/libx/_runtime/cds-services/util/assert.js +65 -2
  76. package/libx/_runtime/common/composition/data.js +1 -0
  77. package/libx/_runtime/common/generic/auth/expand.js +1 -1
  78. package/libx/_runtime/common/generic/auth/restrict.js +5 -10
  79. package/libx/_runtime/common/generic/auth/restrictions.js +40 -0
  80. package/libx/_runtime/common/generic/auth/utils.js +1 -2
  81. package/libx/_runtime/common/generic/crud.js +32 -16
  82. package/libx/_runtime/common/generic/etag.js +133 -104
  83. package/libx/_runtime/common/generic/input.js +6 -21
  84. package/libx/_runtime/common/generic/put.js +1 -1
  85. package/libx/_runtime/common/generic/stream.js +52 -0
  86. package/libx/_runtime/common/generic/temporal.js +25 -8
  87. package/libx/_runtime/common/i18n/messages.properties +0 -2
  88. package/libx/_runtime/common/utils/cqn.js +1 -1
  89. package/libx/_runtime/common/utils/cqn2cqn4sql.js +5 -2
  90. package/libx/_runtime/common/utils/csn.js +0 -51
  91. package/libx/_runtime/common/utils/etag.js +30 -0
  92. package/libx/_runtime/common/utils/keys.js +1 -1
  93. package/libx/_runtime/common/utils/normalizeTimestamp.js +25 -0
  94. package/libx/_runtime/common/utils/path.js +1 -1
  95. package/libx/_runtime/common/utils/resolveView.js +2 -1
  96. package/libx/_runtime/common/utils/rewriteAsterisks.js +6 -4
  97. package/libx/_runtime/common/utils/search2cqn4sql.js +12 -16
  98. package/libx/_runtime/common/utils/stream.js +140 -0
  99. package/libx/_runtime/common/utils/streamProp.js +29 -12
  100. package/libx/_runtime/common/utils/templateProcessorPathSerializer.js +0 -2
  101. package/libx/_runtime/db/generic/index.js +0 -2
  102. package/libx/_runtime/db/query/delete.js +2 -2
  103. package/libx/_runtime/db/query/insert.js +2 -2
  104. package/libx/_runtime/db/query/read.js +2 -2
  105. package/libx/_runtime/db/query/run.js +2 -2
  106. package/libx/_runtime/db/query/update.js +2 -2
  107. package/libx/_runtime/db/sql-builder/BaseBuilder.js +0 -6
  108. package/libx/_runtime/db/sql-builder/ExpressionBuilder.js +23 -12
  109. package/libx/_runtime/db/sql-builder/FunctionBuilder.js +18 -6
  110. package/libx/_runtime/db/sql-builder/InsertBuilder.js +1 -0
  111. package/libx/_runtime/db/sql-builder/SelectBuilder.js +3 -7
  112. package/libx/_runtime/db/sql-builder/UpsertBuilder.js +1 -0
  113. package/libx/_runtime/db/utils/normalizeTimeData.js +7 -3
  114. package/libx/_runtime/fiori/draft.js +2 -0
  115. package/libx/_runtime/fiori/generic/activate.js +8 -9
  116. package/libx/_runtime/fiori/generic/before.js +30 -20
  117. package/libx/_runtime/fiori/generic/cancel.js +5 -3
  118. package/libx/_runtime/fiori/generic/delete.js +5 -3
  119. package/libx/_runtime/fiori/generic/edit.js +7 -7
  120. package/libx/_runtime/fiori/generic/index.js +10 -16
  121. package/libx/_runtime/fiori/generic/new.js +5 -3
  122. package/libx/_runtime/fiori/generic/patch.js +11 -8
  123. package/libx/_runtime/fiori/generic/prepare.js +13 -6
  124. package/libx/_runtime/fiori/generic/read.js +12 -6
  125. package/libx/_runtime/fiori/lean-draft.js +207 -152
  126. package/libx/_runtime/fiori/utils/delete.js +10 -5
  127. package/libx/_runtime/fiori/utils/req.js +17 -5
  128. package/libx/_runtime/fiori/utils/stream.js +36 -0
  129. package/libx/_runtime/hana/Service.js +12 -9
  130. package/libx/_runtime/hana/conversion.js +10 -15
  131. package/libx/_runtime/hana/driver.js +2 -0
  132. package/libx/_runtime/hana/execute.js +28 -6
  133. package/libx/_runtime/hana/pool.js +36 -122
  134. package/libx/_runtime/hana/search2cqn4sql.js +34 -36
  135. package/libx/_runtime/messaging/enterprise-messaging-utils/getTenantInfo.js +2 -6
  136. package/libx/_runtime/messaging/enterprise-messaging-utils/registerEndpoints.js +3 -1
  137. package/libx/_runtime/messaging/enterprise-messaging.js +10 -58
  138. package/libx/_runtime/messaging/outbox/utils.js +1 -1
  139. package/libx/_runtime/remote/Service.js +20 -1
  140. package/libx/_runtime/remote/utils/client.js +3 -5
  141. package/libx/_runtime/sqlite/Service.js +4 -6
  142. package/libx/_runtime/sqlite/conversion.js +3 -13
  143. package/libx/_runtime/sqlite/customBuilder/CustomFunctionBuilder.js +9 -6
  144. package/libx/_runtime/sqlite/customBuilder/CustomUpsertBuilder.js +6 -1
  145. package/libx/_runtime/sqlite/execute.js +5 -16
  146. package/libx/odata/afterburner.js +22 -6
  147. package/libx/odata/grammar.pegjs +6 -1
  148. package/libx/odata/parser.js +1 -1
  149. package/libx/rest/RestAdapter.js +16 -9
  150. package/libx/rest/RestRequest.js +1 -1
  151. package/libx/rest/middleware/input.js +2 -1
  152. package/libx/rest/middleware/operation.js +1 -0
  153. package/libx/rest/middleware/parse.js +3 -2
  154. package/libx/rest/middleware/payload.js +9 -8
  155. package/libx/rest/middleware/read.js +1 -0
  156. package/package.json +9 -16
  157. package/app/fiori/preview.js +0 -270
  158. package/app/fiori/routes.js +0 -59
  159. package/bin/build/buildTaskEngine.js +0 -360
  160. package/bin/build/buildTaskFactory.js +0 -283
  161. package/bin/build/buildTaskHandler.js +0 -241
  162. package/bin/build/buildTaskProvider.js +0 -22
  163. package/bin/build/buildTaskProviderFactory.js +0 -175
  164. package/bin/build/cds.js +0 -5
  165. package/bin/build/constants.js +0 -66
  166. package/bin/build/index.js +0 -58
  167. package/bin/build/provider/buildTaskHandlerEdmx.js +0 -82
  168. package/bin/build/provider/buildTaskHandlerFeatureToggles.js +0 -131
  169. package/bin/build/provider/buildTaskHandlerInternal.js +0 -254
  170. package/bin/build/provider/buildTaskProviderInternal.js +0 -383
  171. package/bin/build/provider/fiori/index.js +0 -171
  172. package/bin/build/provider/hana/2migration.js +0 -179
  173. package/bin/build/provider/hana/index.js +0 -505
  174. package/bin/build/provider/hana/migrationtable.js +0 -472
  175. package/bin/build/provider/hana/template/.hdiconfig-haas +0 -163
  176. package/bin/build/provider/hana/template/.hdiconfig-hanacloud +0 -137
  177. package/bin/build/provider/hana/template/.hdinamespace +0 -4
  178. package/bin/build/provider/hana/template/package.json +0 -12
  179. package/bin/build/provider/hana/template/undeploy.json +0 -5
  180. package/bin/build/provider/java/index.js +0 -111
  181. package/bin/build/provider/java-cf/index.js +0 -1
  182. package/bin/build/provider/mtx/index.js +0 -268
  183. package/bin/build/provider/mtx/resourcesTarBuilder.js +0 -95
  184. package/bin/build/provider/mtx-extension/index.js +0 -131
  185. package/bin/build/provider/mtx-sidecar/index.js +0 -137
  186. package/bin/build/provider/node-cf/index.js +0 -1
  187. package/bin/build/provider/nodejs/index.js +0 -192
  188. package/bin/build/util.js +0 -299
  189. package/bin/cds.js +0 -125
  190. package/bin/deploy/to-hana/cfUtil.js +0 -355
  191. package/bin/deploy/to-hana/gitUtil.js +0 -57
  192. package/bin/deploy/to-hana/hana.js +0 -306
  193. package/bin/deploy/to-hana/hdiDeployUtil.js +0 -153
  194. package/bin/deploy/to-hana/index.js +0 -16
  195. package/bin/deploy/to-hana/mtaUtil.js +0 -170
  196. package/bin/mtx/in-cds.js +0 -17
  197. package/bin/plugins.js +0 -32
  198. package/bin/run.js +0 -24
  199. package/bin/utils/log.js +0 -24
  200. package/bin/version.js +0 -178
  201. package/libx/_runtime/audit/Service.js +0 -222
  202. package/libx/_runtime/audit/generic/personal/access.js +0 -61
  203. package/libx/_runtime/audit/generic/personal/index.js +0 -56
  204. package/libx/_runtime/audit/generic/personal/modification.js +0 -132
  205. package/libx/_runtime/audit/generic/personal/utils.js +0 -186
  206. package/libx/_runtime/audit/utils/log.js +0 -23
  207. package/libx/_runtime/audit/utils/v2.js +0 -176
  208. package/libx/_runtime/db/data-conversion/timestamp.js +0 -9
  209. package/libx/_runtime/db/generic/integrity.js +0 -455
  210. package/srv/audit-log.cds +0 -87
  211. package/srv/mtx.cds +0 -2
  212. package/srv/mtx.js +0 -8
  213. /package/lib/{core → linked}/classes.js +0 -0
  214. /package/lib/{core → linked}/entities.js +0 -0
@@ -1,254 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const cds = require('../cds')
4
- const BuildTaskHandler = require('../buildTaskHandler')
5
- const { hasOptionValue } = require('../util')
6
- const { FOLDER_GEN, BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY } = require('../constants')
7
-
8
- class BuildTaskHandlerInternal extends BuildTaskHandler {
9
- /**
10
- * Returns the logger that has been passed the build task engine.
11
- * @returns {object}
12
- */
13
- get logger() {
14
- //injected by framework
15
- return this._logger;
16
- }
17
- /**
18
- * Returns the build options used for this CDS build execution
19
- * @returns {object}
20
- */
21
- get buildOptions() {
22
- return this._buildOptions
23
- }
24
- /**
25
- * Custom build handlers are executed before internal handlers in order
26
- * ensure and content cannot be overwritten by mistake.
27
- */
28
- get priority() {
29
- return BuildTaskHandlerInternal.PRIORITY_MAX_VALUE
30
- }
31
-
32
- async clean() {
33
- // the build results have already been deleted by the BuildTaskEngine if the build.target !== '.'
34
- // make sure that src is not a subfolder of dest
35
- if (this._buildOptions.root === this._buildOptions.target && this.task.src !== this.task.dest && !this._isSubDirectory(this.task.dest, this.task.src)) {
36
- await fs.promises.rm(this.task.dest, { force: true, recursive: true })
37
- }
38
- }
39
-
40
- /**
41
- * Used by the framework to initialize the logger implementation.
42
- * @param {object} logger
43
- */
44
- set logger(logger) {
45
- super.logger = logger;
46
- }
47
- /**
48
- * Sets the build options used for this CDS build execution
49
- * @param {object} options
50
- */
51
- set buildOptions(options) {
52
- super.buildOptions = options
53
- }
54
- /**
55
- * Maximum allowed priority for internal build tasks.
56
- */
57
- static get PRIORITY_MAX_VALUE() {
58
- return 0;
59
- }
60
- /**
61
- * Minimum allowed priority for custom build tasks.
62
- */
63
- static get PRIORITY_MIN_VALUE() {
64
- return Number.MIN_SAFE_INTEGER;
65
- }
66
-
67
- /**
68
- * Called by the framework after {@link #init()}. Handlers may want to perform more elaborate preparation.
69
- * E.g. caching some pre-calculated data that can be used across multiple build tasks. This kind of data
70
- * has to be stored in the handler type specific buildOptions section.
71
- * @returns {Promise<boolean>} A value 'false' indicates that {@link #prepare()} will not be called for other instances
72
- * of this handler type.
73
- * True indicates that {@link #prepare()} will be called for other instances of this of this handler type.
74
- * @deprecated
75
- */
76
- async prepare() {
77
- // cancel subsequent prepare calls for other handlers of the same type by default
78
- return false
79
- }
80
-
81
- /**
82
- * Returns whether cds env has a property with the specified value.
83
- * If the value is omitted the existence of the given property name is checked.
84
- * @param {string} qualifiedName
85
- * @param {any=} value
86
- */
87
- hasCdsEnvOption(qualifiedName, value) {
88
- return hasOptionValue(cds.env.get(qualifiedName), value)
89
- }
90
-
91
- /**
92
- * Determines whether the given build option value has been set for this build task.
93
- * If the value is omitted, the existence of the given property name is checked.
94
- * @param {string} qualifiedName
95
- * @param {any=} value
96
- */
97
- hasBuildOption(qualifiedName, value) {
98
- return hasOptionValue(this._getBuildOption(qualifiedName), value)
99
- }
100
-
101
- /**
102
- * Returns the value of the given build option defined for this build task.
103
- * @param {string} qualifiedName
104
- */
105
- getBuildOption(qualifiedName) {
106
- return super._getBuildOption(qualifiedName)
107
- }
108
-
109
- /**
110
- * Returns a list of CDS model files defining the transitive closure of the CDS model based on the model options
111
- * defined for this build task.
112
- */
113
- resolveModel() {
114
- return this._resolveModel()
115
- }
116
-
117
- /**
118
- * Returns whether the build results of this build plugin are created inplace
119
- * or in a separate staging folder which is not part of the build tasks src folder.
120
- */
121
- isStagingBuild() {
122
- return !this.task.src.startsWith(this.task.dest)
123
- }
124
-
125
- async copyNativeContent(srcDir, destDir, customFilter) {
126
- const files = BuildTaskHandlerInternal._find(srcDir, (src) => {
127
- // do not copy files that:
128
- // - are contained in the 'buildOptions.target' folder
129
- // - are contained in this modules 'dest' folder
130
- // - are contained in some generation folder
131
- // - do NOT fulfill additional specific filter criteria
132
- return this._commonStagingBuildFilter(src, destDir) && (!customFilter || customFilter.call(this, src))
133
- })
134
- return Promise.all(
135
- files.map((srcFile) => {
136
- let relFile = path.relative(srcDir, srcFile)
137
- let destFile = path.join(destDir, relFile)
138
- return this.copy(srcFile).to(destFile)
139
- })
140
- )
141
- }
142
-
143
- async compileToJson(model, csnFile) {
144
- // This will als add a @source prop containing the relative path to the origin .cds source file
145
- // and a parsed _where clause for @restrict.{grant,where} annotations.
146
- // The @source annotation is required for correct custom handler resolution if no @impl annotation has been defined as
147
- // custom service handler implementations are relative to the origin .cds source files.
148
- // For staging builds (task.src !== task.dest) the csn.json file that is served at runtime is copied into a corresponding srv subfolder.
149
- // 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.
150
- // This ensures that the paths are relative to the cwd when executing cds run.
151
- const jsonOptions = {
152
- cwd: this.buildOptions.root,
153
- src: this.task.src === this.task.dest ? this.task.src : this.buildOptions.root
154
- }
155
- const csnStr = cds.compile.to.json(model, jsonOptions)
156
- if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
157
- await this.write(csnStr).to(csnFile)
158
- }
159
- return csnStr
160
- }
161
-
162
- /**
163
- * Collect and write language bundles into a single i18n.json file.
164
- * @param {Object} model
165
- * @param {string} bundleDest
166
- */
167
- async collectLanguageBundles(model, bundleDest) {
168
- // collect effective i18n properties...
169
- let bundles = {}
170
- const bundleGenerator = cds.localize.bundles4(model)
171
- if (bundleGenerator && bundleGenerator[Symbol.iterator]) {
172
- for (let [locale, bundle] of bundleGenerator) {
173
- // fallback bundle has the name ""
174
- if (typeof locale === 'string') {
175
- bundles[locale] = bundle
176
- }
177
- }
178
- }
179
-
180
- // omit bundles in case the fallback bundle is the only existing entry
181
- const keys = Object.keys(bundles)
182
- if (keys.length === 1 && keys[0] === "" && Object.keys(bundles[keys[0]]).length === 0) {
183
- bundles = {}
184
- }
185
- // copied from ../compile/i18n.js
186
- const { file: base = 'i18n' } = cds.env.i18n
187
- const file = path.join(bundleDest, base + '.json')
188
-
189
- // bundleDest might be null
190
- if (bundleDest && Object.keys(bundles).length > 0) {
191
- if (!this.hasBuildOption(BUILD_OPTION_OUTPUT_MODE, OUTPUT_MODE_RESULT_ONLY)) {
192
- await this.write(bundles).to(file)
193
- }
194
- return { file, bundles }
195
- }
196
- return null
197
- }
198
-
199
- _isSubDirectory(parent, child) {
200
- return !path.relative(parent, child).startsWith('..')
201
- }
202
-
203
- _commonStagingBuildFilter(src, destDir) {
204
- if (typeof src !== "string" || typeof destDir !== "string") {
205
- return false
206
- }
207
- if (!fs.statSync(src).isDirectory()) {
208
- return true //file
209
- }
210
- if (src === destDir) {
211
- return false
212
- }
213
- const regex = new RegExp(FOLDER_GEN + "\\b")
214
- if (src === this.buildOptions.target) {
215
- return false
216
- }
217
- return !regex.exec(path.basename(src))
218
- }
219
-
220
- static _find(srcDir, filter) {
221
- const files = []
222
- this._traverseFileSystem(srcDir, files, filter)
223
- return files;
224
- }
225
-
226
- static _traverseFileSystem(srcDir, files, filter) {
227
- let entries = []
228
- try {
229
- entries = fs.readdirSync(srcDir)
230
- } catch (e) {
231
- // ignore if not existing
232
- }
233
- entries.map(subDirEntry => path.join(srcDir, subDirEntry)).forEach((entry) => {
234
- this._handleResource(entry, files, filter)
235
- })
236
- }
237
-
238
- static _handleResource(entry, files, filter) {
239
- if (!filter || filter.call(this, entry)) {
240
- var stats = this._getResourceStatus(entry)
241
- if (stats.isDirectory()) {
242
- this._traverseFileSystem(entry, files, filter)
243
- } else if (stats.isFile() || stats.isSymbolicLink()) {
244
- files.push(entry)
245
- }
246
- }
247
- }
248
-
249
- // for testing purposes
250
- static _getResourceStatus(entry) {
251
- return fs.lstatSync(entry)
252
- }
253
- }
254
- module.exports = BuildTaskHandlerInternal
@@ -1,383 +0,0 @@
1
- const fs = require('fs')
2
- const path = require('path')
3
- const cds = require('../cds')
4
- const { hasJavaNature, getProperty, isStreamlinedMtx, getDefaultModelOptions, BuildError, hasOptionValue } = require('../util')
5
- const BuildTaskProvider = require('../buildTaskProvider')
6
-
7
- const { FILE_EXT_CDS, BUILD_TASK_HANA, BUILD_TASK_FIORI, BUILD_TASK_JAVA, BUILD_TASK_JAVA_CF, BUILD_TASK_NODEJS, BUILD_TASK_NODE_CF, BUILD_TASK_MTX,
8
- BUILD_TASK_PREFIX, BUILD_TASKS, BUILD_TASK_MTX_SIDECAR, MTX_SIDECAR_FOLDER, BUILD_TASK_MTX_EXTENSION, NODEJS_MODEL_EXCLUDE_LIST,
9
- DEFAULT_BUILT_IN_MODELS } = require("../constants")
10
-
11
- class BuildTaskProviderInternal extends BuildTaskProvider {
12
- constructor(logger) {
13
- super()
14
- this._logger = logger
15
- }
16
- get logger() {
17
- return this._logger
18
- }
19
-
20
- canHandleTask(task) {
21
- return BUILD_TASKS.includes(task.for)
22
- || task.use && task.use.startsWith(BUILD_TASK_PREFIX)
23
- // support different build task implementations of the same build task ID defined by 'for'
24
- //return (BUILD_TASKS.includes(task.for) && !task.use) || (task.use && task.use.startsWith(BUILD_TASK_PREFIX))
25
- }
26
-
27
- loadHandler(task) {
28
- return require(`./${BuildTaskProviderInternal._getForValueFromTask(task)}`)
29
- }
30
-
31
- async lookupTasks(tasks, buildOptions) {
32
- return this._createTasks(tasks, buildOptions, tasks.length > 0)
33
- }
34
-
35
- async applyTaskDefaults(task, buildOptions) {
36
- const taskFor = BuildTaskProviderInternal._getForValueFromTask(task)
37
- const { root: projectPath } = buildOptions
38
- task.for = task.for || taskFor
39
- task.use = task.use || `${BUILD_TASK_PREFIX}/${taskFor}`
40
-
41
- BuildTaskProviderInternal._setDefaultSrcFolder(task)
42
-
43
- // src folder needs to be initialized first
44
- BuildTaskProviderInternal._setDefaultModel(task, projectPath)
45
- }
46
-
47
- async _createTasks(tasks, buildOptions, addRequiredTasks) {
48
- const { root: projectPath } = buildOptions
49
- let db = typeof cds.env.folders.db === "string" ? [BuildTaskProviderInternal._normalizePath(cds.env.folders.db)] : cds.env.folders.db
50
- let srv = typeof cds.env.folders.srv === "string" ? [BuildTaskProviderInternal._normalizePath(cds.env.folders.srv)] : cds.env.folders.srv
51
-
52
- const dbOptions = {
53
- model: []
54
- }
55
- const srvOptions = {
56
- model: []
57
- }
58
- if (Array.isArray(db) && db.length > 0) {
59
- db = BuildTaskProviderInternal._getModuleFolder(projectPath, db) || null
60
- if (!db && !addRequiredTasks) { // log once
61
- this.logger.debug("No database module found")
62
- }
63
- }
64
- if (Array.isArray(srv) && srv.length > 0) {
65
- srv = BuildTaskProviderInternal._getModuleFolder(projectPath, srv) || null
66
- if (!srv && !addRequiredTasks) { // log once
67
- this.logger.debug("No service module found")
68
- }
69
- }
70
- // create required build tasks
71
- if (addRequiredTasks) {
72
- const mtxTask = tasks.find(task => task.for === BUILD_TASK_MTX || task.for === BUILD_TASK_MTX_SIDECAR)
73
- if (mtxTask) {
74
- //restore used tasks as they might have been filtered by 'cds build --for mtx'
75
- if (mtxTask._uses) {
76
- mtxTask._uses.map(use => use.task).forEach(task => {
77
- if (!tasks.includes(task)) {
78
- tasks.push(task)
79
- }
80
- })
81
- }
82
- let dbTask = tasks.find(task => task.for === BUILD_TASK_HANA)
83
- if (!dbTask) {
84
- // db task might be missing if mtx task is enforced by 'cds build --for mtx'
85
- dbTask = this._createDbTask(projectPath, db, dbOptions)
86
- if (dbTask) {
87
- tasks.push(dbTask)
88
- }
89
- }
90
- if (dbTask && (!mtxTask._uses || !mtxTask._uses.map(use => use.task).includes(dbTask))) {
91
- const use = { task: dbTask }
92
- mtxTask._uses ? mtxTask._uses.push(use) : mtxTask._uses = [use]
93
- }
94
- }
95
- } else {
96
- !db && this.logger._debug && this.logger.debug(`project doesn't have a database module '${cds.env.folders.db}'`)
97
- !srv && this.logger._debug && this.logger.debug(`project doesn't have a service module '${cds.env.folders.srv}'`)
98
-
99
- // create hana build task
100
- const dbTask = this._createDbTask(projectPath, db, dbOptions, buildOptions)
101
- if (dbTask) {
102
- tasks.push(dbTask)
103
- }
104
- // create java or node build task
105
- const srvTask = this._createSrvTask(projectPath, srv, srvOptions)
106
- if (srvTask) {
107
- tasks.push(srvTask)
108
- }
109
-
110
- // REVISIT: disable for cds-dk projectReader - causing error due to inconsistent state during project creation
111
- if (buildOptions.resolve !== false) {
112
- // create mtx build task
113
- const mtxTask = this._createMtxTask(projectPath, srv, srv, tasks)
114
- if (mtxTask) {
115
- tasks.push(mtxTask)
116
- }
117
- }
118
- }
119
- }
120
-
121
- _createDbTask(projectPath, src, taskOptions, buildOptions) {
122
- this.logger.debug("determining database kind.")
123
- if (!src || BuildTaskProviderInternal._isMtxExtension()) {
124
- return null
125
- }
126
- let task = null
127
- if (this._useHana(projectPath, buildOptions)) {
128
- this.logger.debug("found HANA database.")
129
- // legacy build supports dest property
130
- const compileDest = cds.env.data?.dest
131
- if (compileDest) {
132
- //../db/src/gen
133
- // compileDest is relative to src folder in modular build - resolve correctly
134
- taskOptions.compileDest = path.relative(path.resolve(projectPath, src), path.resolve(projectPath, compileDest))
135
- }
136
- task = {
137
- src: src,
138
- for: BUILD_TASK_HANA,
139
- options: taskOptions
140
- }
141
- } else {
142
- this.logger.debug("found sqlite database - skipping HANA build task")
143
- }
144
- return task
145
- }
146
-
147
- _useHana(projectPath, buildOptions) {
148
- if (getProperty(buildOptions, "for.hana.skipManifestGeneration") // deprecated fallback for webide fullstack and mtx
149
- || getProperty(buildOptions, "for.hana.contentManifest") === false // fallback for webide fullstack and mtx
150
- || cds.env.requires.db?.kind === "hana"
151
- || cds.env.requires.db?.dialect === "hana") {
152
-
153
- return true
154
- }
155
- // false if other db has been defined
156
- if (cds.env.requires.db?.kind) {
157
- return false
158
- }
159
- // check whether cds config represents a legacy build system config for which requires.db was not configured
160
- // Note: compat layer sets requires.db: {}
161
- const userEnv = cds.env.for("cds", projectPath, false)
162
- return userEnv && (userEnv.data?.model || userEnv.service?.model)
163
- }
164
-
165
- _createMtxTask(projectPath, src, dest, tasks) {
166
- this.logger.debug("determining mtx version of nodejs project")
167
-
168
- // preserve order of creation
169
- if (BuildTaskProviderInternal._isMtxExtension()) {
170
- this.logger.debug("MTX extension app")
171
- return { for: BUILD_TASK_MTX_EXTENSION }
172
- }
173
-
174
- if (isStreamlinedMtx()) {
175
- const sidecarPath = path.join(projectPath, MTX_SIDECAR_FOLDER)
176
- let sidecarEnv
177
- if (fs.existsSync(sidecarPath)) {
178
- sidecarEnv = cds.env.for("cds", sidecarPath)
179
- }
180
- if (
181
- cds.env.profiles?.includes('with-mtx-sidecar') || // new presets
182
- cds.env.requires["cds.xt.ModelProviderService"]?.external // for compatibility with former mtxs presets
183
- ) {
184
- this.logger.debug("MTX app with sidecar")
185
- if (!sidecarEnv) {
186
- throw new BuildError(`MTX sidecar directory '${sidecarPath}' not existing. Custom build task configuration required if the folder is named differently.`)
187
- }
188
- if (!sidecarEnv.requires["cds.xt.ModelProviderService"]?._in_sidecar) {
189
- // correct profile might have been set, but couldn't be resolved
190
- if (sidecarEnv.profiles?.includes('mtx-sidecar')) {
191
- throw new BuildError('MTX configuration cannot be resolved. Make sure an up-to-date version of @sap/cds-mtxs is installed.')
192
- }
193
- throw new BuildError(`Invalid MTX sidecar configuration - profile 'mtx-sidecar' not set.`)
194
- }
195
- return { for: BUILD_TASK_MTX_SIDECAR }
196
- }
197
- if (sidecarEnv?.requires["cds.xt.ModelProviderService"]?._in_sidecar || sidecarEnv?.profiles?.includes('mtx-sidecar')) {
198
- throw new BuildError(`MTX sidecar requires profile 'with-mtx-sidecar' in project root configuration.`)
199
- }
200
-
201
- if (cds.env.requires["cds.xt.ModelProviderService"]?._in_sidecar || cds.env.profiles?.includes('mtx-sidecar')) {
202
- // cds build is executed in sidecar folder
203
- throw new BuildError(`Seems that you are executing 'cds build' in the 'mtx/sidecar' folder. Execute 'cds build' in the project root folder instead.`)
204
- }
205
-
206
- // without sidecar
207
- if (!tasks.some(task => task.for === BUILD_TASK_JAVA || task.for === BUILD_TASK_JAVA_CF)) {
208
- this.logger.debug("Nodejs MTX app without sidecar")
209
- return {
210
- for: BUILD_TASK_MTX,
211
- src
212
- }
213
- }
214
- }
215
- if (!tasks.some(task => task.for === BUILD_TASK_JAVA || task.for === BUILD_TASK_JAVA_CF)) {
216
- if (cds.env.requires.multitenancy) {
217
- this.logger.debug("Nodejs Classic MTX app without sidecar")
218
- return {
219
- src: ".",
220
- for: BUILD_TASK_MTX,
221
- dest
222
- }
223
- }
224
- }
225
- }
226
-
227
- _createSrvTask(projectPath, src, taskOptions) {
228
- this.logger.debug("determining implementation technology")
229
- if (!src || BuildTaskProviderInternal._isMtxExtension()) {
230
- return null
231
- }
232
- let task = null
233
- if (BuildTaskProviderInternal._hasJavaNature(projectPath, src)) {
234
- task = this._createJavaTask(projectPath, src, taskOptions)
235
- } else {
236
- task = this._createNodeTask(src, taskOptions)
237
- }
238
- return task
239
- }
240
-
241
- _createJavaTask(projectPath, src, taskOptions) {
242
- this.logger.debug("found implementation technology java")
243
- // legacy build supports dest property
244
- const compileDest = cds.env.service?.dest
245
- if (compileDest) {
246
- // compileDest is relative to src folder in modular build - resolve correctly
247
- taskOptions.compileDest = path.relative(path.resolve(projectPath, src), path.resolve(projectPath, compileDest))
248
- }
249
- return {
250
- src: src,
251
- for: BUILD_TASK_JAVA,
252
- options: taskOptions
253
- }
254
- }
255
-
256
- _createNodeTask(src, taskOptions) {
257
- this.logger.debug("found implementation technology node")
258
- return {
259
- src: src,
260
- for: BUILD_TASK_NODEJS,
261
- options: taskOptions
262
- }
263
- }
264
-
265
- static _isMtxExtension() {
266
- return !!cds.env.extends
267
- }
268
-
269
- static _setDefaultSrcFolder(task) {
270
- switch (task.for) {
271
- case BUILD_TASK_HANA:
272
- task.src = task.src || this._normalizePath(cds.env.folders.db)
273
- break
274
- case BUILD_TASK_JAVA:
275
- case BUILD_TASK_JAVA_CF:
276
- case BUILD_TASK_NODEJS:
277
- case BUILD_TASK_NODE_CF:
278
- task.src = task.src || this._normalizePath(cds.env.folders.srv)
279
- break
280
- case BUILD_TASK_FIORI:
281
- task.src = task.src || this._normalizePath(cds.env.folders.app)
282
- break
283
- case BUILD_TASK_MTX_SIDECAR:
284
- task.src = task.src || MTX_SIDECAR_FOLDER
285
- break
286
- case BUILD_TASK_MTX_EXTENSION:
287
- task.src = task.src || "."
288
- break
289
- case BUILD_TASK_MTX:
290
- if (isStreamlinedMtx()) {
291
- task.src = task.src || this._normalizePath(cds.env.folders.srv)
292
- } else {
293
- task.src = task.src || "."
294
- }
295
- break
296
- default:
297
- throw new Error(`Unknown build task '${task.use || task.for}'`)
298
- }
299
- }
300
-
301
- static _setDefaultModel(task, projectPath) {
302
- let taskModelPaths = task.options?.model
303
- if (taskModelPaths && !Array.isArray(taskModelPaths)) {
304
- taskModelPaths = [taskModelPaths]
305
- }
306
- task.options = task.options || {}
307
- let defaultModelPaths = []
308
- // add default models to custom build tasks if this hasn't been disabled
309
- if (taskModelPaths?.length) {
310
- if (!hasOptionValue(task.options?.[DEFAULT_BUILT_IN_MODELS], false)) {
311
- // get the built-in models
312
- defaultModelPaths = getDefaultModelOptions(projectPath).filter(p => p.match('@sap/cds'))
313
- }
314
- } else {
315
- defaultModelPaths = getDefaultModelOptions(projectPath)
316
- defaultModelPaths.push(task.src)
317
- if (hasOptionValue(task.options?.[DEFAULT_BUILT_IN_MODELS], false)) {
318
- // all default models except the built-in models
319
- defaultModelPaths = defaultModelPaths.filter(p => !p.match('@sap/cds'))
320
- }
321
- }
322
-
323
- // REVISIT: filter nodejs bootstrap service models for Java - issues/12770#issuecomment-1805719
324
- if (this._hasJavaNature(projectPath, cds.env.folders.srv)) {
325
- defaultModelPaths = defaultModelPaths.filter(p => !NODEJS_MODEL_EXCLUDE_LIST.includes(p))
326
- }
327
- // also add built-in models to custom build tasks already containing model options
328
- if (!taskModelPaths || defaultModelPaths.length) {
329
- task.options.model = [...new Set(taskModelPaths?.length ? taskModelPaths.concat(defaultModelPaths) : defaultModelPaths)]
330
- }
331
- }
332
-
333
- /**
334
- * Returns whether this project is a java project or not.
335
- * @param {string} projectPath - the absolute project path
336
- * @param {string} srv - the folder name of the service module
337
- */
338
- static _hasJavaNature(projectPath, srv) {
339
- srv = this._getModuleFolder(projectPath, Array.isArray(srv) ? srv : [srv])
340
- return hasJavaNature([projectPath, srv && path.join(projectPath, srv)])
341
- }
342
-
343
- static _getForValueFromTask(task) {
344
- return task.for ? task.for : task.use && task.use.substring(BUILD_TASK_PREFIX.length + 1)
345
- }
346
-
347
- /**
348
- * For valid paths remove trailing '/'. Otherwise return as is - important!!
349
- * @param {*} dir
350
- */
351
- static _normalizePath(dir) {
352
- return typeof dir === "string" ? dir.replace(/\/$/, '') : dir
353
- }
354
-
355
- /**
356
- * Determines the module folder from the past list that may represent files or folders w or w/o .cds file extension.
357
- * @param {string} projectPath
358
- * @param {Array} filesOrFolders
359
- */
360
- static _getModuleFolder(projectPath, filesOrFolders) {
361
- const resources = [...filesOrFolders]
362
- filesOrFolders.forEach(fileOrFolder => {
363
- if (path.extname(fileOrFolder) !== FILE_EXT_CDS) {
364
- resources.push(fileOrFolder + FILE_EXT_CDS)
365
- }
366
- })
367
- return resources.reduce((acc, resource) => {
368
- if (!acc) {
369
- let resourcePath = path.resolve(projectPath, resource)
370
- if (fs.existsSync(resourcePath)) {
371
- if (fs.lstatSync(resourcePath).isDirectory()) {
372
- acc = resource
373
- } else {
374
- // represents file
375
- acc = path.dirname(resource)
376
- }
377
- }
378
- }
379
- return acc
380
- }, null)
381
- }
382
- }
383
- module.exports = BuildTaskProviderInternal