@sap/cds-dk 6.8.2 → 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 (218) hide show
  1. package/bin/activate.js +15 -7
  2. package/bin/add.js +29 -15
  3. package/bin/bind.js +49 -116
  4. package/bin/build.js +114 -0
  5. package/bin/cds.js +67 -24
  6. package/bin/compile/index.js +2 -2
  7. package/bin/deploy/index.js +46 -39
  8. package/bin/deploy/to-hana.js +11 -8
  9. package/bin/deploy/to-postgres.js +8 -2
  10. package/bin/deploy/to-sqlite.js +0 -1
  11. package/bin/env.js +75 -41
  12. package/bin/eval.js +3 -3
  13. package/bin/extend.js +17 -10
  14. package/bin/help.js +22 -21
  15. package/bin/import.js +10 -7
  16. package/bin/init.js +38 -17
  17. package/bin/login.js +69 -55
  18. package/bin/logout.js +12 -9
  19. package/bin/migrate.js +10 -4
  20. package/bin/pull.js +12 -5
  21. package/bin/push.js +24 -13
  22. package/bin/repl.js +1 -0
  23. package/bin/run.js +25 -0
  24. package/bin/subscribe.js +13 -8
  25. package/bin/unsubscribe.js +15 -8
  26. package/bin/upgrade.js +15 -9
  27. package/bin/util/log.js +24 -0
  28. package/bin/version.js +124 -0
  29. package/bin/watch.js +1 -35
  30. package/bin/watched.js +39 -0
  31. package/lib/bind/KubernetesApiAccessor.js +2 -2
  32. package/lib/bind/bindingManager.js +1 -1
  33. package/lib/bind/bindingUtil.js +0 -9
  34. package/lib/bind/cfKeyProvider.js +10 -72
  35. package/lib/bind/index.js +114 -0
  36. package/lib/bind/kubernetesCredentialsProvider.js +2 -2
  37. package/lib/bind/userCdsrcJsonStorageProvider.js +7 -44
  38. package/lib/build/buildTaskEngine.js +355 -0
  39. package/lib/build/buildTaskFactory.js +284 -0
  40. package/lib/build/buildTaskHandler.js +240 -0
  41. package/lib/build/buildTaskProvider.js +22 -0
  42. package/lib/build/buildTaskProviderFactory.js +182 -0
  43. package/lib/build/constants.js +56 -0
  44. package/lib/build/index.js +21 -0
  45. package/lib/build/provider/buildTaskHandlerEdmx.js +83 -0
  46. package/lib/build/provider/buildTaskHandlerFeatureToggles.js +132 -0
  47. package/lib/build/provider/buildTaskHandlerInternal.js +228 -0
  48. package/lib/build/provider/buildTaskProviderInternal.js +370 -0
  49. package/lib/build/provider/fiori/index.js +167 -0
  50. package/lib/build/provider/hana/2migration.js +179 -0
  51. package/lib/build/provider/hana/index.js +522 -0
  52. package/lib/build/provider/hana/migrationtable.js +472 -0
  53. package/lib/build/provider/hana/template/.hdiconfig-all +163 -0
  54. package/lib/build/provider/hana/template/.hdiconfig-cloud +137 -0
  55. package/lib/build/provider/hana/template/.hdinamespace +4 -0
  56. package/lib/build/provider/hana/template/package.json +12 -0
  57. package/lib/build/provider/hana/template/undeploy.json +5 -0
  58. package/lib/build/provider/java/index.js +93 -0
  59. package/lib/build/provider/java-cf/index.js +1 -0
  60. package/lib/build/provider/mtx/index.js +37 -0
  61. package/lib/build/provider/mtx/resourcesTarBuilder.js +94 -0
  62. package/lib/build/provider/mtx-extension/index.js +131 -0
  63. package/lib/build/provider/mtx-sidecar/index.js +138 -0
  64. package/lib/build/provider/node-cf/index.js +1 -0
  65. package/lib/build/provider/nodejs/index.js +178 -0
  66. package/lib/build/util.js +263 -0
  67. package/lib/cds.js +9 -21
  68. package/lib/client/auth_manager.js +39 -16
  69. package/lib/client/helper/dependency_helper.js +7 -6
  70. package/lib/client/push.js +2 -1
  71. package/lib/client/settings_manager.js +10 -39
  72. package/lib/deploy/to-hana/hana.js +273 -0
  73. package/lib/deploy/to-hana/hdiDeployUtil.js +68 -0
  74. package/lib/deploy/to-hana/mtaUtil.js +171 -0
  75. package/lib/import/asyncapi/importAsyncAPI.js +3 -2
  76. package/lib/import/asyncapi/index.js +5 -2
  77. package/lib/import/asyncapi/parserContext.js +67 -26
  78. package/lib/import/asyncapi/utils.js +34 -3
  79. package/lib/import/common.js +40 -30
  80. package/lib/import/importapi.js +36 -35
  81. package/lib/index.js +12 -17
  82. package/lib/init/constants.js +36 -71
  83. package/lib/init/index.js +18 -52
  84. package/lib/init/template/_merging/registry-mta.js +21 -3
  85. package/lib/init/template/approuter/files/mta.yaml.hbs +29 -29
  86. package/lib/init/template/approuter/files/values.yaml.hbs +5 -5
  87. package/lib/init/template/approuter/files/xs-app.json.hbs +8 -2
  88. package/lib/init/template/approuter/index.js +7 -8
  89. package/lib/init/template/auditlog/files/mta.yaml.hbs +5 -5
  90. package/lib/init/template/auditlog/files/package.json.hbs +13 -13
  91. package/lib/init/template/auditlog/index.js +3 -3
  92. package/lib/init/template/cf-manifest/files/manifest.yml.hbs +22 -22
  93. package/lib/init/template/cf-manifest/files/services-manifest.yml.hbs +3 -3
  94. package/lib/init/template/connectivity/files/mta.yaml.hbs +14 -0
  95. package/lib/init/template/connectivity/files/package.json.hbs +17 -0
  96. package/lib/init/template/connectivity/index.js +21 -4
  97. package/lib/init/template/data/index.js +5 -1
  98. package/lib/init/template/destination/files/mta.yaml.hbs +14 -0
  99. package/lib/init/template/destination/files/package.json.hbs +17 -0
  100. package/lib/init/template/{destinations → destination}/index.js +19 -13
  101. package/lib/init/template/enterprise-messaging/files/event-mesh.json.hbs +3 -3
  102. package/lib/init/template/enterprise-messaging/files/mta.yaml.hbs +5 -5
  103. package/lib/init/template/enterprise-messaging/files/package.json.hbs +9 -9
  104. package/lib/init/template/enterprise-messaging/files/xs-security.json.hbs +19 -0
  105. package/lib/init/template/enterprise-messaging/index.js +27 -6
  106. package/lib/init/template/enterprise-messaging-shared/files/event-mesh.json.hbs +3 -3
  107. package/lib/init/template/enterprise-messaging-shared/files/mta.yaml.hbs +5 -5
  108. package/lib/init/template/enterprise-messaging-shared/files/package.json.hbs +9 -9
  109. package/lib/init/template/enterprise-messaging-shared/index.js +4 -5
  110. package/lib/init/template/extensibility/files/package.json.hbs +10 -10
  111. package/lib/init/template/extensibility/index.js +8 -9
  112. package/lib/init/template/file-based-messaging/files/package.json.hbs +9 -9
  113. package/lib/init/template/file-based-messaging/index.js +3 -4
  114. package/lib/init/template/hana/files/db/package.json +1 -1
  115. package/lib/init/template/hana/files/mta.yaml.hbs +21 -21
  116. package/lib/init/template/hana/files/package.json.hbs +16 -22
  117. package/lib/init/template/hana/files/values.yaml.hbs +1 -1
  118. package/lib/init/template/hana/index.js +5 -15
  119. package/lib/init/template/helm/files/Chart.yaml.hbs +4 -4
  120. package/lib/init/template/helm/files/values.yaml.hbs +6 -6
  121. package/lib/init/template/helm/index.js +5 -10
  122. package/lib/init/template/helm/subcharts/content-deployment/Chart.yaml +2 -0
  123. package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +37 -31
  124. package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +13 -14
  125. package/lib/init/template/helm/subcharts/content-deployment/templates/secret.yaml +2 -2
  126. package/lib/init/template/helm/subcharts/content-deployment/templates/service-account.yaml +1 -1
  127. package/lib/init/template/helm/subcharts/content-deployment/templates/service-binding.yaml +3 -3
  128. package/lib/init/template/helm/subcharts/content-deployment/values.md +116 -116
  129. package/lib/init/template/helm/subcharts/service-instance/Chart.yaml +2 -0
  130. package/lib/init/template/helm/subcharts/service-instance/templates/_helpers.tpl +9 -9
  131. package/lib/init/template/helm/subcharts/service-instance/templates/serviceinstance.yaml +2 -2
  132. package/lib/init/template/helm/subcharts/service-instance/values.md +15 -15
  133. package/lib/init/template/helm/subcharts/web-application/Chart.yaml +2 -0
  134. package/lib/init/template/helm/subcharts/web-application/templates/NOTES.txt +15 -0
  135. package/lib/init/template/helm/subcharts/web-application/templates/_helpers.tpl +23 -23
  136. package/lib/init/template/helm/subcharts/web-application/templates/api-rule.yaml +4 -4
  137. package/lib/init/template/helm/subcharts/web-application/templates/deployment.yaml +17 -17
  138. package/lib/init/template/helm/subcharts/web-application/templates/network-policy.yaml +24 -3
  139. package/lib/init/template/helm/subcharts/web-application/templates/pod-disruption-budget.yaml +3 -3
  140. package/lib/init/template/helm/subcharts/web-application/templates/secret.yaml +2 -2
  141. package/lib/init/template/helm/subcharts/web-application/templates/service-account.yaml +1 -1
  142. package/lib/init/template/helm/subcharts/web-application/templates/service-binding.yaml +3 -3
  143. package/lib/init/template/helm/subcharts/web-application/templates/service.yaml +3 -3
  144. package/lib/init/template/helm/subcharts/web-application/values.md +141 -123
  145. package/lib/init/template/helm/subcharts/web-application/values.schema.json +7 -0
  146. package/lib/init/template/helm/subcharts/web-application/values.yaml +1 -0
  147. package/lib/init/template/html5-repo/index.js +4 -5
  148. package/lib/init/template/java/index.js +5 -5
  149. package/lib/init/template/kibana-logging/files/mta.yaml.hbs +5 -5
  150. package/lib/init/template/kibana-logging/files/package.json.hbs +9 -9
  151. package/lib/init/template/kibana-logging/index.js +3 -4
  152. package/lib/init/template/lint/index.js +3 -3
  153. package/lib/init/template/mta/files/mta.yaml.hbs +14 -14
  154. package/lib/init/template/mta/files/package.json +5 -0
  155. package/lib/init/template/mta/index.js +12 -13
  156. package/lib/init/template/mtx/index.js +2 -2
  157. package/lib/init/template/multitenancy/files/mta.yaml.hbs +29 -27
  158. package/lib/init/template/multitenancy/files/package.json.hbs +17 -14
  159. package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +7 -7
  160. package/lib/init/template/multitenancy/files/values.yaml.hbs +19 -19
  161. package/lib/init/template/multitenancy/index.js +14 -16
  162. package/lib/init/template/nodejs/files/package.json.hbs +1 -1
  163. package/lib/init/template/nodejs/index.js +5 -8
  164. package/lib/init/template/redis-messaging/files/mta.yaml.hbs +5 -5
  165. package/lib/init/template/redis-messaging/files/package.json.hbs +9 -9
  166. package/lib/init/template/redis-messaging/index.js +4 -5
  167. package/lib/init/template/sample/files/app/_i18n/i18n.properties +43 -0
  168. package/lib/init/template/sample/files/app/_i18n/i18n_de.properties +14 -0
  169. package/lib/init/template/sample/files/app/admin-books/fiori-service.cds +114 -0
  170. package/lib/init/template/sample/files/app/admin-books/webapp/Component.js +8 -0
  171. package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n.properties +11 -0
  172. package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +129 -0
  173. package/lib/init/template/sample/files/app/appconfig/fioriSandboxConfig.json +57 -0
  174. package/lib/init/template/sample/files/app/common.cds +263 -0
  175. package/lib/init/template/sample/files/app/index.html +30 -0
  176. package/lib/init/template/sample/files/app/services.cds +5 -0
  177. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +5 -0
  178. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books.csv +6 -0
  179. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books_texts.csv +5 -0
  180. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Genres.csv +16 -0
  181. package/lib/init/template/sample/files/db/schema.cds +31 -0
  182. package/lib/init/template/sample/files/nodejs/admin-service.js +12 -0
  183. package/lib/init/template/sample/files/nodejs/cat-service.js +26 -0
  184. package/lib/init/template/sample/files/srv/admin-service.cds +5 -0
  185. package/lib/init/template/sample/files/srv/cat-service.cds +16 -0
  186. package/lib/init/template/sample/index.js +24 -0
  187. package/lib/init/template/sample-tiny/index.js +39 -0
  188. package/lib/init/template/samples/index.js +5 -56
  189. package/lib/init/template/sqlite/files/package.json.hbs +13 -13
  190. package/lib/init/template/sqlite/index.js +2 -2
  191. package/lib/init/template/templateBase.js +24 -1
  192. package/lib/init/template/toggles/files/package.json.hbs +10 -10
  193. package/lib/init/template/toggles/index.js +3 -3
  194. package/lib/init/template/typer/files/gitignore +1 -0
  195. package/lib/init/template/typer/files/package.json +8 -0
  196. package/lib/init/template/typer/files/xsconfig.json +9 -0
  197. package/lib/init/template/typer/index.js +36 -0
  198. package/lib/init/template/xsuaa/files/mta.yaml.hbs +12 -12
  199. package/lib/init/template/xsuaa/files/package.json.hbs +13 -13
  200. package/lib/init/template/xsuaa/files/values.yaml.hbs +8 -8
  201. package/lib/init/template/xsuaa/index.js +8 -19
  202. package/lib/init/util/merge.js +73 -59
  203. package/lib/init/util/mvn.js +21 -17
  204. package/lib/init/util/projectReader.js +49 -87
  205. package/lib/init/util/xml.js +14 -23
  206. package/lib/util/cfUtil.js +366 -0
  207. package/lib/util/command.js +3 -3
  208. package/lib/util/gitUtil.js +55 -0
  209. package/lib/util/version.js +27 -0
  210. package/npm-shrinkwrap.json +339 -277
  211. package/package.json +6 -6
  212. package/CHANGELOG.md +0 -1453
  213. package/bin/build/all.js +0 -88
  214. package/bin/build/index.js +0 -82
  215. package/lib/compile/index.js +0 -14
  216. /package/lib/init/template/{samples → sample-tiny}/files/nodejs/db/data/my.bookshop-Books.csv +0 -0
  217. /package/lib/init/template/{samples → sample-tiny}/files/nodejs/db/data-model.cds +0 -0
  218. /package/lib/init/template/{samples → sample-tiny}/files/nodejs/srv/cat-service.cds.hbs +0 -0
@@ -0,0 +1,240 @@
1
+ const path = require('path')
2
+ const fs = require('fs').promises
3
+ const cds = require('../cds')
4
+
5
+ const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, SEVERITY_INFO, SEVERITY_WARNING, SEVERITY_ERROR, OVERRIDE_METHOD_MSG } = require('./constants')
6
+ const { hasOptionValue, getProperty, relativePaths, copy, BuildMessage } = require('./util')
7
+
8
+ /**
9
+ * The build task handler creates the build output for a dedicated build task. It is uniquely identified
10
+ * by the build task's <code>use</code> property. It represents the fully qualified node module path
11
+ * of the build task handler implementation.
12
+ * <p>
13
+ * The build task engine defines the following protocol. The methods are invoked in descending order:
14
+ * <ul>
15
+ * <li>init() - optional</li>
16
+ * <li>get priority() - optional</li>
17
+ * <li>async clean()</li>
18
+ * <li>async build()</li>
19
+ * </ul>
20
+ * The reflected CSN can be accessed using the async method <code>model()</code>.
21
+ */
22
+ class BuildTaskHandler {
23
+ /**
24
+ * @class
25
+ */
26
+ constructor() {
27
+ if (new.target === BuildTaskHandler) {
28
+ throw new TypeError("Cannot construct BuildTaskHandler instances directly");
29
+ }
30
+ this._written = new Set()
31
+ this._messages = []
32
+ }
33
+ static get INFO() {
34
+ return SEVERITY_INFO
35
+ }
36
+ static get WARNING() {
37
+ return SEVERITY_WARNING
38
+ }
39
+ static get ERROR() {
40
+ return SEVERITY_ERROR
41
+ }
42
+ /**
43
+ * Returns the build context
44
+ * @returns {object}
45
+ */
46
+ get context() {
47
+ return this._context
48
+ }
49
+ /**
50
+ * Returns the build task executed by this build task handler.
51
+ * @return {object}
52
+ */
53
+ get task() {
54
+ //injected by framework
55
+ return this._task
56
+ }
57
+
58
+ /**
59
+ * Returns the message object to add build task specific messages. Severity 'Info', 'Warning', and 'Error' are supported.
60
+ * @return {Array}
61
+ */
62
+ get messages() {
63
+ return this._messages
64
+ }
65
+
66
+ /**
67
+ * Returns the list of files written by this build task handler of current CDS build execution.
68
+ * @return {Array}
69
+ */
70
+ get files() {
71
+ return [...this._written]
72
+ }
73
+
74
+ /**
75
+ * Returns the priority of this handler as number, where 0 represents the minimum value and
76
+ * Number.MAX_SAFE_INTEGER the maximum value.
77
+ * Positive numbers mean higher and negative numbers lower priority. Build task handlers
78
+ * with higher priority value are executed before handlers with lower priority.
79
+ * <br>
80
+ * Note: Currently not supported for custom build task handlers as they are always executed
81
+ * before the built-in handlers.
82
+ * @return {number} the priority for this handler as integer.
83
+ */
84
+ get priority() {
85
+ return 1
86
+ }
87
+ /**
88
+ * Called by the framework immediately after this instance has been created.
89
+ * The instance has already been fully initialized.
90
+ */
91
+ init() { }
92
+
93
+ /**
94
+ * Called by the framework to create the artifacts of this build task handler.
95
+ */
96
+ async build() {
97
+ throw new TypeError(OVERRIDE_METHOD_MSG)
98
+ }
99
+
100
+ /**
101
+ * Called by the framework immediately before 'build' to delete any output created by this build task handler.
102
+ * <p>
103
+ * Note: The <code>BuildTaskEngine</code> is cleaning the common generation target folder if the build is
104
+ * executed in staging mode, e.g. build.target: "gen".
105
+ */
106
+ async clean() {
107
+ throw new TypeError(OVERRIDE_METHOD_MSG)
108
+ }
109
+
110
+ /**
111
+ * Asynchronously write the given content to a given file path.
112
+ * If the file exists the content is replaced. If the file does not exist, a new file will be created.
113
+ * The file name is stored in the list of files written by this build task handler.
114
+ * @param {string} dest - absolute or relative file path. Relative paths will be resolved to this task's destination path.
115
+ * @param {any} data - If data is of type object the JSON-stringified version is written.
116
+ */
117
+ write(data) {
118
+ return {
119
+ to: async (dest) => {
120
+ if (this._hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM)) {
121
+ if (!path.isAbsolute(dest)) {
122
+ // relative to build task's destination path
123
+ dest = path.resolve(this.task.dest, dest)
124
+ }
125
+ this.pushFile(dest)
126
+ await fs.mkdir(path.dirname(dest), { recursive: true })
127
+ await fs.writeFile(dest, typeof data === "object" && !Buffer.isBuffer(data) ? JSON.stringify(data, null, 2) : data)
128
+ }
129
+ }
130
+ }
131
+ }
132
+
133
+ // TODO only works with files due to fs.copyFile, check usages
134
+ /**
135
+ * Copy a file or directory if the build task option 'outputMode' does not have the value 'resultOnly'.
136
+ * The directory can have contents.
137
+ * <p>
138
+ * Note: The file name is stored in the list of files written by this build task handler.
139
+ * </p>
140
+ * @param {string} src The absolute or relative source path of the file or directory to copy.
141
+ * Relative paths will be resolved to this task's source path.
142
+ * @param {string} dest The absolute or relative target path. Relative paths will be resolved to this task's destination path.
143
+ *
144
+ */
145
+ copy(src) {
146
+ return {
147
+ to: async (dest) => {
148
+ if (this._hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM)) {
149
+ if (!path.isAbsolute(src)) {
150
+ // relative to build task's source path
151
+ src = path.resolve(this.task.src, src)
152
+ }
153
+ if (!path.isAbsolute(dest)) {
154
+ // relative to build task's destination path
155
+ dest = path.resolve(this.task.dest, dest)
156
+ }
157
+ this.pushFile(dest)
158
+ if (fs.cp) { // Node.js >= 16.7
159
+ return fs.cp(src, dest, { recursive: true })
160
+ }
161
+ return copy(src, dest)
162
+ }
163
+ return dest
164
+ }
165
+ }
166
+ }
167
+
168
+ /**
169
+ * Adds the given user message and severity to the list of messages issued by this build task.
170
+ * <p>
171
+ * User messages will be logged after CDS build has been finished based on the log-level that has been set.
172
+ * By default messages with severity <em>warning</em> and <em>error</em> will be logged.
173
+ * @param {string} message the message text
174
+ * @param {string} severity the severity of the message
175
+ */
176
+ pushMessage(message, severity) {
177
+ this.messages.push(new BuildMessage(message, severity))
178
+ }
179
+
180
+ /**
181
+ * Returns the reflected CSN model using this build task's model settings.
182
+ * @return {object} the reflected CSN
183
+ */
184
+ async model() {
185
+ const files = this._resolveModel()
186
+ if (!files || files.length === 0) {
187
+ this._logger.log(`no CDS model found for [${this.task.for}] build task [${this.task.src}] - nothing to be done`)
188
+ return null
189
+ }
190
+ this._logger._debug && this._logger.debug(`model: ${relativePaths(cds.root, files).join(", ")}`)
191
+ // $location paths are relative to current working dir by default - make sure a given project root folder is taken
192
+ const options = { ...this.options(), cwd: cds.root }
193
+
194
+ const model = await cds.load(files, options)
195
+ if (!model) {
196
+ return null
197
+ }
198
+ return model
199
+ }
200
+
201
+ options() {
202
+ return { messages: this._messages }
203
+ }
204
+
205
+ /**
206
+ * Adds the given fully qualified file path to the list of files that are written by this build task.
207
+ * @param {string} filePath
208
+ */
209
+ pushFile(filePath) {
210
+ this._written.add(filePath)
211
+ }
212
+ /**
213
+ * Returns a list of CDS model files defining the transitive closure of the CDS model based on the model options
214
+ * defined for this build task.
215
+ */
216
+ _resolveModel() {
217
+ const modelPaths = Array.isArray(this.task.options.model) && this.task.options.model.length > 0 ? this.task.options.model : !Array.isArray(this.task.options.model) && this.task.options.model || this.task.src
218
+ return cds.resolve(modelPaths)
219
+ }
220
+ /** Determines whether the given build option value has been set for this build task.
221
+ * If the value is omitted, the existence of the given property name is checked.
222
+ */
223
+ _hasBuildOption(qualifiedName, value) {
224
+ return hasOptionValue(this._getBuildOption(qualifiedName), value)
225
+ }
226
+
227
+ // Returns the value of the given build option defined for this build task.
228
+ _getBuildOption(qualifiedName) {
229
+ // build task options overwriting other settings
230
+ let value = getProperty(this.task.options, qualifiedName)
231
+ if (value !== undefined) {
232
+ return value
233
+ }
234
+ value = getProperty(this.context.options, qualifiedName)
235
+ if (value !== undefined) {
236
+ return value
237
+ }
238
+ }
239
+ }
240
+ module.exports = BuildTaskHandler
@@ -0,0 +1,22 @@
1
+ /* eslint-disable no-unused-vars */
2
+ module.exports = class BuildTaskProvider {
3
+ constructor() {
4
+ //injected by framework
5
+ this._plugin = null
6
+ }
7
+ canHandleTask(task) {
8
+ // return this._plugin.provides.includes(task.for || task.use && this._getTaskId(task.use))
9
+ }
10
+ loadHandler(task) {
11
+ // return module.require(`${this._plugin.path}/${task.for || this._getTaskId(task.use)}`)
12
+ }
13
+ async lookupTasks(tasks) { }
14
+ async applyTaskDefaults(task) {
15
+ // task.for = task.for || this._getTaskId(task.use)
16
+ }
17
+ _getTaskId(use) {
18
+ if (this._plugin && this._plugin.id) {
19
+ return use.substring(this._plugin.id.length + 1)
20
+ }
21
+ }
22
+ }
@@ -0,0 +1,182 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const cds = require('../cds')
4
+ const { LOG_MODULE_NAMES, OUTPUT_MODE_FILESYSTEM } = require("./constants")
5
+ const BuildTaskProviderInternal = require('./provider/buildTaskProviderInternal')
6
+ const BuildTaskProvider = require('./buildTaskProvider')
7
+
8
+ class BuildTaskProviderFactory {
9
+ constructor(options = {}) {
10
+ options.logger = options.logger || cds.log(LOG_MODULE_NAMES)
11
+ options.outputMode = options.outputMode || OUTPUT_MODE_FILESYSTEM
12
+ if (options.clean === undefined) {
13
+ options.clean = true
14
+ }
15
+ this._buildOptions = options
16
+ this._context = { options }
17
+ }
18
+ get logger() {
19
+ return this.buildOptions.logger
20
+ }
21
+ get buildOptions() {
22
+ return this._context.options
23
+ }
24
+ get context() {
25
+ return this._context
26
+ }
27
+ get providers() {
28
+ if (!this._providers) {
29
+ this._providers = this._loadProviders()
30
+ }
31
+ return this._providers
32
+ }
33
+
34
+ async applyTaskDefaults(tasks) {
35
+ return Promise.all(tasks.map(async task => {
36
+ if (!task.for && !task.use) {
37
+ throw new Error("Invalid build task definition - property 'for' and property 'use' missing")
38
+ }
39
+ const provider = this.providers.find(provider => {
40
+ try {
41
+ return provider.canHandleTask(task)
42
+ } catch (e) {
43
+ this.logger.error(`Build task provider ${provider.constructor.name} returned error:\n` + e)
44
+ throw e
45
+ }
46
+ })
47
+ if (!provider) {
48
+ throw new Error(`No provider found for build task '${task.for || task.use}'`)
49
+ }
50
+ if (provider instanceof DefaultBuildTaskProvider) {
51
+ this.logger._debug && this.logger.debug(`No provider found for build task '${task.use}', using default provider`)
52
+ }
53
+ return this._applyTaskDefaults(provider, [task])
54
+ }))
55
+ }
56
+
57
+ async lookupTasks(tasks = []) {
58
+ for (let i = 0; i < this.providers.length; i++) {
59
+ const provider = this.providers[i]
60
+ const existingTasks = [...tasks]
61
+ await this._lookupTasks(provider, tasks)
62
+ if (existingTasks.length < tasks.length) {
63
+ // apply defaults
64
+ const newTasks = tasks.filter(task => !existingTasks.includes(task))
65
+ await this._applyTaskDefaults(provider, newTasks)
66
+ this.logger._debug && this.logger.debug(`Build task provider ${provider.constructor.name} returned build tasks ${JSON.stringify(newTasks)}`)
67
+ }
68
+ }
69
+ return tasks
70
+ }
71
+
72
+ /**
73
+ * Create a BuildTaskHandler instance for the given build task.
74
+ * The implementation is loaded based on the build task's 'for' or 'use' option.
75
+ * @param {*} task
76
+ */
77
+ createHandler(task) {
78
+ const BuildTaskHandlerClass = this.loadHandler(task)
79
+ const resolvedTask = this.resolveTask(task)
80
+ this.logger._debug && this.logger.debug(`loaded build task handler [${resolvedTask.use}]`)
81
+
82
+ const handler = new BuildTaskHandlerClass()
83
+ handler._task = resolvedTask
84
+ handler._logger = this.logger
85
+ handler._context = this.context
86
+ this.logger._debug && this.logger.debug(`created BuildTaskHandler [${resolvedTask.use}]`)
87
+ return handler
88
+ }
89
+
90
+ /**
91
+ * Loads the build task handler implementation for the given build task.
92
+ * 'for' defines an alias for built-in handlers like 'hana', 'java', 'node', 'fiori' or 'mtx'.
93
+ * 'use' defines the fully qualified module name of external build task handler implemenations.
94
+ * @param {object} task
95
+ */
96
+ loadHandler(task) {
97
+ let provider = this.providers.find(provider => provider.canHandleTask(task))
98
+ if (!provider) {
99
+ throw new Error(`No provider found for build task '${task.for || task.use}'`)
100
+ }
101
+ try {
102
+ return provider.loadHandler(task)
103
+ }
104
+ catch (e) {
105
+ this.logger.error(`Provider failed to load handler class - provider: ${provider.constructor.name}, task: ${task.for || task.use} :\n` + e)
106
+ throw e
107
+ }
108
+ }
109
+
110
+ resolveTasks(tasks) {
111
+ return tasks.map(task => this.resolveTask(task))
112
+ }
113
+
114
+ /**
115
+ * Resolves the given build task based on the project root folder.<br>
116
+ * The task is validated in order to ensure that 'src' refers to a valid folder and 'for' or 'use' reference can be required.
117
+ * @param {*} task
118
+ */
119
+ resolveTask(task) {
120
+ // first validate handler implementation
121
+ this.loadHandler(task)
122
+
123
+ // second validate src path
124
+ const resolvedTask = JSON.parse(JSON.stringify(task))
125
+
126
+ // Do not store resolved symlinks as this is causing issues on Windows, e.g. if git projects are
127
+ // located under 'C:\SAPDevelop\git\...' using a sym-link from '%USERHOME%\git' to 'C:\SAPDevelop\git'.
128
+ // see cap/issues/#8694
129
+ resolvedTask.src = path.resolve(cds.root, task.src)
130
+ try {
131
+ //validate source path
132
+ fs.realpathSync(resolvedTask.src)
133
+ } catch (e) {
134
+ throw new Error(`Build task [${resolvedTask.for || resolvedTask.use}] could not be resolved - folder src [${path.resolve(cds.root, task.src)}] does not exist`)
135
+ }
136
+ resolvedTask.dest = path.resolve(cds.root, cds.env.build.target, task.dest || task.src)
137
+ resolvedTask.options = task.options || {}
138
+ return resolvedTask
139
+ }
140
+
141
+ async _lookupTasks(provider, tasks) {
142
+ return provider.lookupTasks(tasks)
143
+ }
144
+
145
+ async _applyTaskDefaults(provider, tasks) {
146
+ return Promise.all(tasks.map(task => provider.applyTaskDefaults(task)))
147
+ }
148
+
149
+ _loadProviders() {
150
+ // order is important - the DefaultBuildTaskProvider has to be the last provider in the list
151
+ return [this._createProvider(BuildTaskProviderInternal), this._createProvider(DefaultBuildTaskProvider)]
152
+ }
153
+
154
+ _createProvider(clazz, plugin) {
155
+ const provider = new clazz()
156
+ provider._logger = this.logger
157
+ provider._plugin = plugin
158
+ return provider
159
+ }
160
+ }
161
+
162
+ /**
163
+ * Default provider implementation handling fully qualified custom build task declarations.
164
+ * Has to be the last entry in the providers list.
165
+ */
166
+ class DefaultBuildTaskProvider extends BuildTaskProvider {
167
+ canHandleTask(task) {
168
+ return !!task.use
169
+ }
170
+ loadHandler(task) {
171
+ if (!task.use) {
172
+ throw new Error(`Invalid build task definition [${task.for}] - property 'use' missing`)
173
+ }
174
+ try {
175
+ return require(require.resolve(task.use, { paths: [cds.root] }))
176
+ }
177
+ catch (e) {
178
+ throw new Error(`Build task could not be resolved - module [${task.use}] cannot be loaded:\n` + e)
179
+ }
180
+ }
181
+ }
182
+ module.exports = BuildTaskProviderFactory
@@ -0,0 +1,56 @@
1
+ exports.OUTPUT_MODE = "outputMode"
2
+ exports.OUTPUT_MODE_NONE = 0x0
3
+ exports.OUTPUT_MODE_FILESYSTEM = 0x1
4
+ exports.OUTPUT_MODE_RESULT = 0x2
5
+
6
+ exports.BUILD_TASK_NPM_SCOPE = "@sap"
7
+ exports.BUILD_TASK_PREFIX = exports.BUILD_TASK_NPM_SCOPE + "/cds/build"
8
+ exports.BUILD_TASK_JAVA = "java"
9
+ exports.BUILD_TASK_JAVA_CF = "java-cf"
10
+ exports.BUILD_TASK_NODEJS = "nodejs"
11
+ exports.BUILD_TASK_NODE_CF = "node-cf"
12
+ exports.BUILD_TASK_HANA = "hana"
13
+ exports.BUILD_TASK_FIORI = "fiori"
14
+ exports.BUILD_TASK_MTX = "mtx"
15
+ exports.BUILD_TASK_MTX_SIDECAR = "mtx-sidecar"
16
+ exports.BUILD_TASK_MTX_EXTENSION = "mtx-extension"
17
+ exports.BUILD_TASKS = [this.BUILD_TASK_JAVA, this.BUILD_TASK_JAVA_CF, this.BUILD_TASK_NODEJS, this.BUILD_TASK_NODE_CF, this.BUILD_TASK_HANA, this.BUILD_TASK_FIORI, this.BUILD_TASK_MTX, this.BUILD_TASK_MTX_SIDECAR, this.BUILD_TASK_MTX_EXTENSION]
18
+
19
+ exports.ODATA_VERSION_V2 = "v2"
20
+ exports.ODATA_VERSION_V4 = "v4"
21
+
22
+ exports.CONTENT_LANGUAGE_BUNDLES = "contentLanguageBundles" // create i18n.json language bundles
23
+ exports.CONTENT_DEFAULT_CSN = "contentDefaultCsn" // create default CSN format flavor: "inferred"
24
+ exports.CONTENT_EDMX = "contentEdmx" // create EDMX for required languages
25
+ exports.CONTENT_PACKAGE_JSON = "contentPackageJson" // create package.json file if not existing, or modify existing package.json
26
+ exports.CONTENT_PACKAGELOCK_JSON = "contentPackageLockJson" // copy package-lock.json file if existing into deployment folder
27
+ exports.CONTENT_HDBTABLEDATA = "contentHdbtabledata" // create .hdbtabledata files for .csv files if not existing
28
+ exports.CONTENT_NPMRC = "contentNpmrc" // copy .npmrc file if existing into deployment folder
29
+ exports.CONTENT_CDSRC_JSON = "contentCdsrcJson" // copy .cdsrc.json file if existing into deployment folder
30
+ exports.CONTENT_NODE_MODULES = "contentNodeModules" // copy node_modules folder if existing into deployment folder
31
+ exports.CONTENT_ENV = "contentEnv" // copy .env file if existing into deployment folder
32
+ exports.CONTENT_DEFAULT_ENV_JSON = "contentDefaultEnvJson" // copy default-env.json file if existing into deployment folder
33
+ exports.CSV_FILE_DETECTION = "csvFileDetection" // detect CSV files based on CDS model location
34
+ exports.EXTENSION_POINT_VALIDATION = "extensionPointValidation" // validate extension point restrictions defined by the extended SaaS app
35
+ exports.DEFAULT_BUILT_IN_MODELS = "defaultBuiltInModels" // add @sap/cds* built-in models to build tasks
36
+
37
+ exports.FOLDER_GEN = "gen"
38
+ exports.FILE_EXT_CDS = ".cds"
39
+ exports.MTX_SIDECAR_FOLDER = "mtx/sidecar" // default name of the mtx sidecar folder
40
+ exports.DEFAULT_CSN_FILE_NAME = "csn.json"
41
+ // REVISIT: the models are not required if a custom server.js file is used for MTX bootstrap
42
+ exports.NODEJS_MODEL_EXCLUDE_LIST = ['@sap/cds/srv/mtx', '@sap/cds-mtxs/srv/bootstrap']
43
+
44
+ exports.CDS_CONFIG_PATH_SEP = "/"
45
+ exports.SEVERITY_ERROR = "Error"
46
+ exports.SEVERITY_WARNING = "Warning"
47
+ exports.SEVERITY_INFO = "Info"
48
+ exports.SEVERITY_DEBUG = "Debug"
49
+ exports.SEVERITIES = [exports.SEVERITY_ERROR, exports.SEVERITY_WARNING, exports.SEVERITY_INFO, exports.SEVERITY_DEBUG]
50
+ exports.LOG_LEVEL_ERROR = "error"
51
+ exports.LOG_LEVEL_WARN = "warn"
52
+ exports.LOG_LEVEL_INFO = "info"
53
+ exports.LOG_LEVEL_DEBUG = "debug"
54
+ exports.LOG_LEVELS = [exports.LOG_LEVEL_ERROR, exports.LOG_LEVEL_WARN, exports.LOG_LEVEL_INFO, exports.LOG_LEVEL_DEBUG]
55
+ exports.LOG_MODULE_NAMES = "cds|build"
56
+ exports.OVERRIDE_METHOD_MSG = "Must override method"
@@ -0,0 +1,21 @@
1
+ const fs = require('fs')
2
+ const cds = require('../cds')
3
+ const BuildTaskEngine = require('./buildTaskEngine')
4
+ const BuildTaskFactory = require('./buildTaskFactory')
5
+ const BuildTaskHandler = require('./buildTaskHandler')
6
+ const { BuildError } = require('./util')
7
+
8
+ module.exports = { build, BuildTaskFactory, BuildTaskEngine, BuildTaskHandler, BuildError }
9
+
10
+ /**
11
+ * Executes cds build in the directory defined by cds.root.
12
+ *
13
+ * @param {object} options - command options as defined by build command.
14
+ */
15
+ async function build(options = {}) {
16
+ if (!fs.existsSync(cds.root) || !fs.lstatSync(cds.root).isDirectory()) {
17
+ const { CliError } = require('../client/helper/errors')
18
+ throw new CliError(`Project folder '${cds.root}' does not exist`)
19
+ }
20
+ return await new BuildTaskEngine(options).processTasks()
21
+ }
@@ -0,0 +1,83 @@
1
+ const path = require('path')
2
+ const cds = require('../../cds')
3
+ const BuildTaskHandlerFeatureToggles = require('./buildTaskHandlerFeatureToggles')
4
+ const { OUTPUT_MODE, OUTPUT_MODE_RESULT } = require('../constants')
5
+
6
+ class BuildTaskHandlerEdmx extends BuildTaskHandlerFeatureToggles {
7
+ async compileToEdmx(model, edmxDest, compileOptions = {}) { // NOSONAR
8
+ const promises = []
9
+
10
+ // generate edmx for services only that have the odata protocol
11
+ const serviceNames = cds.reflect(model).services
12
+ .filter(service => this._isOdataProtocol(service))
13
+ .map(service => service.name)
14
+
15
+ // new compile impl is throwing error in case no services exist!
16
+ if (serviceNames.length > 0) {
17
+ const options = {
18
+ ...this._options4edmx(),
19
+ ...compileOptions,
20
+ serviceNames
21
+ }
22
+ this.logger._debug && this.logger.debug(`compiling edmx files using OData version ${options.version}`)
23
+
24
+ const result = cds.compile.to.edmx(model, options)
25
+
26
+ if (result) {
27
+ let langs = this.task.options.lang || cds.env.i18n.languages
28
+ if (langs.split) { // string to array
29
+ langs = langs.split(',')
30
+ }
31
+ if (langs.length > 0 && langs[0] !== 'all' && langs.indexOf('') < 0) {
32
+ langs.push('') // make sure fallback language is in, runtimes expect it
33
+ }
34
+ for (let [content, key] of result) {
35
+ const serviceName = key.file ? key.file : key.name
36
+ if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
37
+ this._result.services.add(serviceName)
38
+ }
39
+ const locResult = cds.localize(model, langs, content)
40
+ if (locResult[Symbol.iterator]) { // multi result
41
+ for (let [localizedContent, { lang }] of locResult) {
42
+ promises.push(this._writeEdmxForLang(localizedContent, serviceName, lang, edmxDest))
43
+ }
44
+ } else { // single result
45
+ promises.push(this._writeEdmxForLang(locResult, serviceName, langs[0], edmxDest))
46
+ }
47
+ }
48
+ }
49
+ }
50
+ return Promise.all(promises)
51
+ }
52
+
53
+ _isOdataProtocol(srv) {
54
+ return cds.service.protocols.protocol4(srv).startsWith('odata')
55
+ }
56
+
57
+ _options4odata() {
58
+ const o = this.options()
59
+ o.version = cds.env.odata.version
60
+ return o
61
+ }
62
+
63
+ _options4edmx() {
64
+ const o = this._options4odata()
65
+ o.service = 'all'
66
+ return o
67
+ }
68
+
69
+ _writeEdmxForLang(content, serviceName, lang, edmxDest) {
70
+ const fileName = serviceName + (lang ? '_' + lang + '.xml' : '.xml')
71
+ if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
72
+ this._result.languages.add(lang)
73
+ this._result.edmx.set(fileName, content)
74
+ }
75
+
76
+ //edmxDest might be null
77
+ if (edmxDest) {
78
+ return this.write(content).to(path.join(edmxDest, fileName))
79
+ }
80
+ return Promise.resolve()
81
+ }
82
+ }
83
+ module.exports = BuildTaskHandlerEdmx