@sap/cds-dk 7.9.6 → 8.0.3

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 (291) hide show
  1. package/CHANGELOG.md +2136 -0
  2. package/bin/add.js +18 -52
  3. package/bin/bind.js +2 -2
  4. package/bin/build.js +29 -4
  5. package/bin/cds.js +31 -14
  6. package/bin/compile/index.js +7 -6
  7. package/bin/completion/index.js +70 -46
  8. package/bin/completion/scripts/cds-bash.sh +4 -1
  9. package/bin/completion/scripts/cds-fish.fish +13 -0
  10. package/bin/completion/scripts/cds-ps.ps1 +2 -1
  11. package/bin/completion/scripts/cds-zsh.sh +2 -1
  12. package/bin/deploy/index.js +6 -5
  13. package/bin/deploy/to-sqlite.js +2 -2
  14. package/bin/extend.js +19 -50
  15. package/bin/help.js +2 -2
  16. package/bin/init.js +10 -77
  17. package/bin/login.js +13 -5
  18. package/bin/migrate.js +1 -1
  19. package/bin/pull.js +11 -0
  20. package/bin/repl.js +3 -0
  21. package/bin/test.js +5 -0
  22. package/bin/version.js +7 -7
  23. package/bin/watch.js +13 -14
  24. package/lib/bind/KubernetesApiAccessor.js +10 -9
  25. package/lib/build/buildTaskEngine.js +11 -7
  26. package/lib/build/buildTaskFactory.js +15 -43
  27. package/lib/build/buildTaskProviderFactory.js +16 -44
  28. package/lib/build/constants.js +4 -3
  29. package/lib/build/index.js +2 -2
  30. package/lib/build/{buildPlugin.js → plugin.js} +65 -46
  31. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/Chart.yaml +1 -1
  32. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/values.yaml +1 -1
  33. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/service-instance/Chart.yaml +1 -1
  34. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/service-instance/templates/_helpers.tpl +7 -0
  35. package/lib/build/plugins/helm/files/subcharts/service-instance/templates/servicebinding.yaml +32 -0
  36. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/service-instance/templates/serviceinstance.yaml +3 -0
  37. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/service-instance/values.schema.json +63 -0
  38. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/service-instance/values.yaml +23 -1
  39. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/Chart.yaml +1 -1
  40. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/deployment.yaml +2 -0
  41. package/lib/build/plugins/helm/files/subcharts/web-application/templates/hpa.yaml +22 -0
  42. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/pod-disruption-budget.yaml +1 -0
  43. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/values.schema.json +49 -0
  44. package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/values.yaml +8 -2
  45. package/lib/{init/template/helm/files/chart → build/plugins/helm/files}/templates/_deployment_helpers.tpl +5 -0
  46. package/lib/build/plugins/helm/files/templates/_helpers.tpl +13 -0
  47. package/lib/build/plugins/helm/index.js +81 -0
  48. package/lib/build/plugins.js +12 -15
  49. package/lib/build/provider/featureToggleBuildPlugin.js +7 -39
  50. package/lib/build/provider/hana/2migration.js +168 -124
  51. package/lib/build/provider/hana/index.js +69 -56
  52. package/lib/build/provider/hana/template/package.json +4 -3
  53. package/lib/build/provider/internalBuildPlugin.js +32 -97
  54. package/lib/build/provider/internalBuildTaskProvider.js +12 -48
  55. package/lib/build/provider/java/index.js +2 -3
  56. package/lib/build/provider/mtx/index.js +5 -4
  57. package/lib/build/provider/mtx-extension/index.js +5 -2
  58. package/lib/build/provider/mtx-sidecar/index.js +2 -2
  59. package/lib/build/provider/nodejs/index.js +4 -3
  60. package/lib/build/util.js +83 -12
  61. package/lib/compile/to-mermaid.js +108 -0
  62. package/lib/compile/to_asyncapi.js +7 -0
  63. package/lib/compile/to_openapi.js +7 -0
  64. package/lib/deploy/to-hana/hana.js +37 -34
  65. package/lib/deploy/to-hana/hdiDeployUtil.js +8 -6
  66. package/lib/env/schemas/cds-rc.js +1 -1
  67. package/lib/import/common.js +2 -2
  68. package/lib/import/odata/metadataconverter/MetadataConverter.js +4 -4
  69. package/lib/import/odata/v2parser.js +83 -197
  70. package/lib/import/odata/v4parser.js +1 -38
  71. package/lib/import/openapi/importOpenAPI.js +164 -42
  72. package/lib/index.js +10 -12
  73. package/lib/init/bas.js +91 -0
  74. package/lib/init/constants.js +21 -11
  75. package/lib/init/index.js +72 -150
  76. package/lib/init/merge.js +12 -20
  77. package/lib/init/mvn.js +103 -150
  78. package/lib/init/plugin.js +11 -7
  79. package/lib/init/projectReader.js +53 -20
  80. package/lib/init/registries/mta.js +51 -6
  81. package/lib/init/template/application-logging/files/package.json.hbs +7 -0
  82. package/lib/init/template/application-logging/index.js +13 -1
  83. package/lib/init/template/approuter/files/containerize.yaml.hbs +10 -0
  84. package/lib/init/template/approuter/files/mta.yaml.hbs +1 -2
  85. package/lib/init/template/approuter/files/values.yaml.hbs +19 -4
  86. package/lib/init/template/approuter/files/xs-app.json.hbs +12 -3
  87. package/lib/init/template/approuter/index.js +29 -25
  88. package/lib/init/template/attachments/files/mta.yaml.hbs +14 -0
  89. package/lib/init/template/attachments/files/package.json.hbs +5 -0
  90. package/lib/init/template/attachments/files/values.yaml +7 -0
  91. package/lib/init/template/attachments/index.js +53 -0
  92. package/lib/init/template/{redis-messaging → audit-logging}/files/mta.yaml.hbs +4 -4
  93. package/lib/init/template/audit-logging/files/package.json.hbs +7 -0
  94. package/lib/init/template/audit-logging/index.js +66 -0
  95. package/lib/init/template/cf-manifest/index.js +4 -0
  96. package/lib/init/template/completion/completionSetup.js +54 -33
  97. package/lib/init/template/completion/index.js +7 -1
  98. package/lib/init/template/connectivity/index.js +4 -4
  99. package/lib/init/template/containerize/files/containerize.yaml.hbs +26 -0
  100. package/lib/init/template/containerize/index.js +24 -0
  101. package/lib/init/template/data/index.js +4 -0
  102. package/lib/init/template/destination/files/mta.yaml.hbs +31 -1
  103. package/lib/init/template/destination/files/package.sidecar.json +7 -0
  104. package/lib/init/template/destination/index.js +22 -2
  105. package/lib/init/template/enterprise-messaging/index.js +6 -3
  106. package/lib/init/template/enterprise-messaging-shared/index.js +5 -1
  107. package/lib/init/template/extensibility/files/package.json.hbs +1 -1
  108. package/lib/init/template/extensibility/files/xs-security.json.hbs +2 -8
  109. package/lib/init/template/extensibility/index.js +3 -1
  110. package/lib/init/template/file-based-messaging/index.js +4 -0
  111. package/lib/init/template/h2/index.js +4 -0
  112. package/lib/init/template/hana/files/containerize.yaml.hbs +10 -0
  113. package/lib/init/template/hana/files/db/package.json +3 -2
  114. package/lib/init/template/hana/files/package.json.hbs +4 -7
  115. package/lib/init/template/hana/files/values.yaml.hbs +1 -2
  116. package/lib/init/template/hana/index.js +15 -7
  117. package/lib/init/template/helm/files/Chart.yaml.hbs +2 -3
  118. package/lib/init/template/helm/files/values.schema.json +2173 -0
  119. package/lib/init/template/helm/files/values.yaml.hbs +11 -6
  120. package/lib/init/template/helm/index.js +77 -18
  121. package/lib/init/template/helm-unified-runtime/index.js +19 -56
  122. package/lib/init/template/html5-repo/files/app-package.json.hbs +11 -7
  123. package/lib/init/template/html5-repo/files/manifest.json +13 -0
  124. package/lib/init/template/html5-repo/files/mta.yaml.hbs +14 -33
  125. package/lib/init/template/html5-repo/files/package.sidecar.json +7 -0
  126. package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +21 -0
  127. package/lib/init/template/html5-repo/files/ui5.yaml.hbs +2 -29
  128. package/lib/init/template/html5-repo/files/values.yaml.hbs +6 -2
  129. package/lib/init/template/html5-repo/files/xs-app.json.hbs +6 -7
  130. package/lib/init/template/html5-repo/index.js +41 -35
  131. package/lib/init/template/http/index.js +36 -12
  132. package/lib/init/template/java/index.js +18 -12
  133. package/lib/init/template/kafka/index.js +4 -0
  134. package/lib/init/template/lint/index.js +7 -2
  135. package/lib/init/template/liquibase/index.js +4 -0
  136. package/lib/init/template/local-messaging/index.js +4 -0
  137. package/lib/init/template/malware-scanner/files/mta.yaml.hbs +14 -0
  138. package/lib/init/template/malware-scanner/files/package.json.hbs +17 -0
  139. package/lib/init/template/malware-scanner/files/values.yaml +7 -0
  140. package/lib/init/template/malware-scanner/index.js +47 -0
  141. package/lib/init/template/mta/files/mta.yaml.hbs +3 -3
  142. package/lib/init/template/mta/files/package.json +1 -1
  143. package/lib/init/template/mta/index.js +4 -0
  144. package/lib/init/template/mtx/index.js +4 -0
  145. package/lib/init/template/multitenancy/files/containerize.yaml.hbs +10 -0
  146. package/lib/init/template/multitenancy/files/mta.yaml.hbs +0 -1
  147. package/lib/init/template/multitenancy/files/package.json.hbs +1 -1
  148. package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +6 -5
  149. package/lib/init/template/multitenancy/files/values.yaml.hbs +14 -24
  150. package/lib/init/template/multitenancy/index.js +50 -28
  151. package/lib/init/template/nodejs/files/eslint.config.mjs +2 -0
  152. package/lib/init/template/nodejs/files/package.json.hbs +2 -3
  153. package/lib/init/template/nodejs/index.js +4 -0
  154. package/lib/init/template/notifications/files/mta.yaml.hbs +2 -2
  155. package/lib/init/template/notifications/index.js +4 -0
  156. package/lib/init/template/pipeline/files/.pipeline/config.yml +1 -1
  157. package/lib/init/template/pipeline/files/Jenkinsfile +1 -1
  158. package/lib/init/template/pipeline/index.js +4 -0
  159. package/lib/init/template/portal/files/mta.yaml.hbs +52 -0
  160. package/lib/init/template/portal/files/package.json.hbs +11 -0
  161. package/lib/init/template/portal/files/package.sidecar.json +7 -0
  162. package/lib/init/template/portal/files/portal-site/CommonDataModel.json.hbs +97 -0
  163. package/lib/init/template/portal/files/portal-site/i18n/catalog.properties +1 -0
  164. package/lib/init/template/portal/files/portal-site/i18n/catalog_de.properties +1 -0
  165. package/lib/init/template/portal/files/portal-site/i18n/group.properties +1 -0
  166. package/lib/init/template/portal/files/portal-site/i18n/group_de.properties +1 -0
  167. package/lib/init/template/portal/index.js +84 -0
  168. package/lib/init/template/postgres/index.js +5 -1
  169. package/lib/init/template/redis/files/mta.yaml.hbs +25 -0
  170. package/lib/init/template/redis/files/package.json.hbs +5 -0
  171. package/lib/init/template/redis/index.js +44 -0
  172. package/lib/init/template/redis-messaging/files/package.json.hbs +0 -3
  173. package/lib/init/template/redis-messaging/index.js +8 -18
  174. package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n_de.properties +3 -0
  175. package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n_en.properties +3 -0
  176. package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +13 -1
  177. package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n.properties +2 -2
  178. package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n_de.properties +3 -0
  179. package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n_en.properties +4 -0
  180. package/lib/init/template/sample/files/app/browse/webapp/manifest.json +3 -3
  181. package/lib/init/template/sample/files/app/index.html +1 -1
  182. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Authors.csv +5 -5
  183. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books.csv +6 -6
  184. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books_texts.csv +5 -5
  185. package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Genres.csv +16 -16
  186. package/lib/init/template/sample/files/nodejs/cat-service.js +2 -2
  187. package/lib/init/template/sample/files/package.json.hbs +3 -0
  188. package/lib/init/template/sample/index.js +16 -9
  189. package/lib/init/template/sqlite/index.js +4 -0
  190. package/lib/init/template/tiny-sample/files/nodejs/db/data/my.bookshop-Books.csv +3 -3
  191. package/lib/init/template/tiny-sample/files/nodejs/srv/cat-service.cds.hbs +1 -1
  192. package/lib/init/template/tiny-sample/index.js +4 -0
  193. package/lib/init/template/toggles/files/package.json.hbs +1 -1
  194. package/lib/init/template/toggles/index.js +4 -0
  195. package/lib/init/template/typer/index.js +4 -0
  196. package/lib/init/template/typescript/files/package.json +12 -0
  197. package/lib/init/template/typescript/files/tsconfig.json +13 -0
  198. package/lib/init/template/typescript/index.js +39 -0
  199. package/lib/init/template/workzone/index.js +9 -0
  200. package/lib/init/template/workzone-standard/files/manifest.json.hbs +6 -0
  201. package/lib/init/template/workzone-standard/files/mta.yaml.hbs +59 -0
  202. package/lib/init/template/workzone-standard/index.js +46 -0
  203. package/lib/init/template/xsuaa/files/package.json.hbs +1 -1
  204. package/lib/init/template/xsuaa/files/values.yaml.hbs +3 -2
  205. package/lib/init/template/xsuaa/index.js +11 -7
  206. package/lib/init/validate.js +27 -0
  207. package/lib/lint/generators.js +1 -1
  208. package/lib/lint/io.js +25 -7
  209. package/lib/mtx/auth_manager.js +64 -30
  210. package/lib/mtx/download_legacy.js +2 -2
  211. package/lib/mtx/index.js +0 -4
  212. package/lib/mtx/params.js +32 -38
  213. package/lib/mtx/pull.js +151 -43
  214. package/lib/mtx/push.js +3 -3
  215. package/lib/mtx/settings_manager.js +75 -35
  216. package/lib/mtx/tenant_action.js +1 -1
  217. package/lib/mtx/util/cf.js +1 -1
  218. package/lib/mtx/util/fs.js +26 -1
  219. package/lib/mtx/util/logging.js +7 -3
  220. package/lib/util/command.js +0 -2
  221. package/lib/util/fs.js +2 -3
  222. package/lib/util/question.js +28 -0
  223. package/lib/util/term.js +5 -3
  224. package/npm-shrinkwrap.json +225 -1083
  225. package/package.json +13 -8
  226. package/bin/activate.js +0 -77
  227. package/lib/compile/asyncapi/channels.js +0 -22
  228. package/lib/compile/asyncapi/components/messageTraits/index.js +0 -89
  229. package/lib/compile/asyncapi/components/messages/index.js +0 -173
  230. package/lib/compile/asyncapi/components/schemas/annotations.js +0 -33
  231. package/lib/compile/asyncapi/components/schemas/array.js +0 -8
  232. package/lib/compile/asyncapi/components/schemas/cache.js +0 -14
  233. package/lib/compile/asyncapi/components/schemas/definition.js +0 -187
  234. package/lib/compile/asyncapi/components/schemas/enum.js +0 -16
  235. package/lib/compile/asyncapi/components/schemas/examples.js +0 -10
  236. package/lib/compile/asyncapi/components/schemas/index.js +0 -14
  237. package/lib/compile/asyncapi/components/schemas/localized.js +0 -29
  238. package/lib/compile/asyncapi/components/schemas/primitiveElement.js +0 -41
  239. package/lib/compile/asyncapi/components/schemas/ref.js +0 -45
  240. package/lib/compile/asyncapi/components/schemas/utils.js +0 -108
  241. package/lib/compile/asyncapi/index.js +0 -247
  242. package/lib/compile/asyncapi/message.js +0 -13
  243. package/lib/compile/asyncapi/utils.js +0 -27
  244. package/lib/compile/openapi/csdl2openapi.js +0 -2448
  245. package/lib/compile/openapi/index.js +0 -68
  246. package/lib/init/template/helm/files/chart/templates/NOTES.txt +0 -14
  247. package/lib/init/template/helm/files/chart/templates/_helpers.tpl +0 -28
  248. package/lib/init/template/helm/files/chart/values.root.schema.json +0 -61
  249. package/lib/init/template/helm/files/chart/values.schema.json +0 -366
  250. package/lib/init/template/helm-unified-runtime/files/Chart.yaml.hbs +0 -10
  251. package/lib/init/template/helm-unified-runtime/files/templates/_deployment_helpers.tpl +0 -90
  252. package/lib/init/template/helm-unified-runtime/files/templates/_helpers.tpl +0 -28
  253. package/lib/init/template/helm-unified-runtime/files/values.root.schema.json +0 -61
  254. package/lib/init/template/helm-unified-runtime/files/values.schema.json +0 -366
  255. package/lib/init/template/helm-unified-runtime/files/values.yaml.hbs +0 -26
  256. package/lib/init/template/helm-unified-runtime/package.json +0 -4
  257. package/lib/init/template/multitenancy/files/mtxs-configmap-java-approuter.yaml +0 -20
  258. package/lib/init/template/multitenancy/files/mtxs-configmap-java.yaml +0 -18
  259. package/lib/init/template/multitenancy/files/mtxs-configmap-nodejs-approuter.yaml +0 -12
  260. package/lib/init/template/multitenancy/files/mtxs-configmap-nodejs.yaml +0 -12
  261. package/lib/init/template/multitenancy/files/saas-registry-secret.yaml +0 -9
  262. package/lib/init/template/nodejs/files/eslint.config.js +0 -13
  263. package/lib/init/template/notebook/index.js +0 -11
  264. package/lib/init/template/samples/index.js +0 -9
  265. package/lib/mtx/activate.js +0 -238
  266. package/lib/mtx/extend.js +0 -173
  267. package/lib/util/exec.d.ts +0 -54
  268. package/lib/util/exec.js +0 -211
  269. /package/lib/{init/template/approuter/files → build/plugins/helm/files/plugins/approuter}/approuter-configmap.yaml +0 -0
  270. /package/lib/{init/template/connectivity/files → build/plugins/helm/files/plugins/connectivity}/connectivity-proxy-info.yaml +0 -0
  271. /package/lib/{init/template/html5-repo/files → build/plugins/helm/files/plugins/html5-repo}/html5-apps-deployer-configmap.yaml +0 -0
  272. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/templates/_helpers.tpl +0 -0
  273. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/templates/job.yaml +0 -0
  274. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/templates/secret.yaml +0 -0
  275. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/templates/service-account.yaml +0 -0
  276. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/templates/service-binding.yaml +0 -0
  277. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/content-deployment/values.schema.json +0 -0
  278. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/NOTES.txt +0 -0
  279. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/_api.tpl +0 -0
  280. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/_helpers.tpl +0 -0
  281. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/api-rule.yaml +0 -0
  282. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/network-policy.yaml +0 -0
  283. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/rbac.yaml +0 -0
  284. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/secret.yaml +0 -0
  285. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/service-account.yaml +0 -0
  286. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/service-binding.yaml +0 -0
  287. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/service.yaml +0 -0
  288. /package/lib/{init/template/helm/files → build/plugins/helm/files/subcharts}/web-application/templates/virtual-service.yaml +0 -0
  289. /package/lib/{init/template/helm-unified-runtime → build/plugins/helm}/files/templates/NOTES.txt +0 -0
  290. /package/lib/init/template/{nodejs/files → java}/.cdsrc.json +0 -0
  291. /package/lib/init/template/tiny-sample/files/nodejs/db/{data-model.cds → schema.cds} +0 -0
@@ -16,8 +16,8 @@ class CatalogService extends cds.ApplicationService { init(){
16
16
  })
17
17
 
18
18
  // Add some discount for overstocked books
19
- this.after ('READ','ListOfBooks', each => {
20
- if (each.stock > 111) each.title += ` -- 11% discount!`
19
+ this.after ('each','ListOfBooks', book => {
20
+ if (book.stock > 111) book.title += ` -- 11% discount!`
21
21
  })
22
22
 
23
23
  return super.init()
@@ -0,0 +1,3 @@
1
+ {
2
+ "sapux": ["{{& appPath}}admin-books", "{{& appPath}}browse"]
3
+ }
@@ -1,10 +1,15 @@
1
1
  const { join } = require('path')
2
2
  const cds = require('../../../cds'), { exists, read, write, copy } = cds.utils
3
3
  const { env4, readProject } = require('../../projectReader')
4
+ const { merge } = require('../../merge')
4
5
  const mvn = require('../../mvn')
5
6
 
6
7
  module.exports = class SampleTemplate extends require('../../plugin') {
7
8
 
9
+ static help() {
10
+ return 'add sample files including Fiori UI'
11
+ }
12
+
8
13
  async run() {
9
14
  const { db, srv, app } = env4('production').folders
10
15
  const language = exists('pom.xml') ? 'java' : 'nodejs'
@@ -15,17 +20,19 @@ module.exports = class SampleTemplate extends require('../../plugin') {
15
20
  copy(join(__dirname, 'files/srv')).to(srv)
16
21
  ])
17
22
  await copy(join(__dirname, 'files', language)).to(srv)
18
- await copy(join(__dirname, 'files', 'app')).to(app)
19
- const { appName, appPath, appUIPaths } = readProject()
20
-
21
- // manifest.json must be unique // REVISIT: Check if relevant for `cds add sample` in Java scenario
22
- await Promise.all(appUIPaths.map(async p => {
23
- const manifest = await read(join(appPath, p, 'webapp/manifest.json'))
24
- manifest['sap.app'].id = appName + '.' + p
25
- await write(join(appPath, p, 'webapp/manifest.json'), manifest, { spaces: 2 })
26
- }))
23
+ await copy(join(__dirname, 'files/app')).to(app)
27
24
  } else if (language === 'java') {
28
25
  await mvn.add('sample')
29
26
  }
27
+
28
+ const { appName, appPath, appUIPaths } = readProject()
29
+ await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: { appPath }})
30
+
31
+ // manifest.json must be unique
32
+ await Promise.all(appUIPaths.map(async p => {
33
+ const manifest = await read(join(appPath, p, 'webapp/manifest.json'))
34
+ manifest['sap.app'].id = appName + '.' + p
35
+ await write(join(appPath, p, 'webapp/manifest.json'), manifest, { spaces: 2 })
36
+ }))
30
37
  }
31
38
  }
@@ -4,6 +4,10 @@ const { merge } = require('../../merge')
4
4
 
5
5
  module.exports = class SQLiteTemplate extends require('../../plugin') {
6
6
 
7
+ static help() {
8
+ return 'database support for SQLite'
9
+ }
10
+
7
11
  async run() {
8
12
  const project = readProject()
9
13
  const { isNodejs, isJava, configFile } = project
@@ -1,3 +1,3 @@
1
- ID;title;stock
2
- 1;Wuthering Heights;100
3
- 2;Jane Eyre;500
1
+ ID,title,stock
2
+ 1,Wuthering Heights,100
3
+ 2,Jane Eyre,500
@@ -1,4 +1,4 @@
1
- using my.bookshop as my from '../{{ dbFolder }}/data-model';
1
+ using my.bookshop as my from '../{{ dbFolder }}/schema';
2
2
 
3
3
  service CatalogService {
4
4
  @readonly entity Books as projection on my.Books;
@@ -7,6 +7,10 @@ const { JAVA } = require('../../constants')
7
7
 
8
8
  module.exports = class TinySampleTemplate extends require('../../plugin') {
9
9
 
10
+ static help() {
11
+ return 'add minimal sample files'
12
+ }
13
+
10
14
  async run() {
11
15
  const { isJava } = readProject()
12
16
  if (isJava) {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  {{#isNodejs}}
3
3
  "dependencies": {
4
- "@sap/cds-mtxs": "^1.9"
4
+ "@sap/cds-mtxs": "^2"
5
5
  },
6
6
  "cds": {
7
7
  {{/isNodejs}}
@@ -3,6 +3,10 @@ const { merge, sort } = require('../../merge')
3
3
 
4
4
  module.exports = class TogglesTemplate extends require('../../plugin') {
5
5
 
6
+ static help() {
7
+ return 'allow dynamically toggled features'
8
+ }
9
+
6
10
  static hasInProduction(env) {
7
11
  return !!env.requires?.toggles
8
12
  }
@@ -6,6 +6,10 @@ const { TYPER } = require('../../constants').OPTIONS
6
6
  const { exists, read } = require('../../../cds').utils
7
7
 
8
8
  module.exports = class TyperTemplate extends require('../../plugin') {
9
+ static help() {
10
+ return 'type generation for CDS models'
11
+ }
12
+
9
13
  async canRun() {
10
14
  const { isJava } = readProject()
11
15
  if (isJava) {
@@ -0,0 +1,12 @@
1
+ {
2
+ "devDependencies": {
3
+ "typescript": "^5",
4
+ "@cap-js/cds-types": "<1",
5
+ "@types/node": "^20"
6
+ },
7
+ "scripts": {
8
+ "watch": "cds-ts w",
9
+ "build:ts": "tsc",
10
+ "build": "cds build && npm run build:ts"
11
+ }
12
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "esModuleInterop": true,
7
+ "forceConsistentCasingInFileNames": true,
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "sourceMap": true,
11
+ "allowJs": true
12
+ }
13
+ }
@@ -0,0 +1,39 @@
1
+ const { join } = require('path')
2
+ const { readProject } = require('../../projectReader')
3
+ const { merge } = require('../../merge')
4
+ const { warn } = require('../../../util/term')
5
+ const { TYPESCRIPT } = require('../../constants').OPTIONS
6
+ const { exists } = require('../../../cds').utils
7
+ const TyperTemplate = require('../typer')
8
+
9
+ module.exports = class TypescriptTemplate extends require('../../plugin') {
10
+ static help() {
11
+ return 'add minimum configuration for a bare TypeScript project'
12
+ }
13
+
14
+ async canRun() {
15
+ const { isJava } = readProject()
16
+ if (isJava) {
17
+ console.warn(warn(`This appears to be a Java project. 'cds add ${TYPESCRIPT}' is intended to be used in Node.js projects. Proceeding anyway.\n`))
18
+ }
19
+ return true
20
+ }
21
+
22
+ static hasInProduction() {
23
+ return exists('tsconfig.ts')
24
+ }
25
+
26
+ async run() {
27
+ const tsconfig = join(__dirname, 'files', 'tsconfig.json')
28
+
29
+ try {
30
+ await merge(tsconfig).into('tsconfig.json')
31
+ } catch (e) {
32
+ throw e instanceof SyntaxError
33
+ ? `SyntaxError in existing tsconfig.json. This could indicate a JSON file with comments, which is not supported at this time. Remove all comments from your tsconfig.json and rerun`
34
+ : e
35
+ }
36
+ await merge(join(__dirname, 'files', 'package.json')).into('package.json')
37
+ await new TyperTemplate().run() // REVISIT: we should avoid referencing other plugins
38
+ }
39
+ }
@@ -0,0 +1,9 @@
1
+ module.exports = class extends require('../../plugin') {
2
+ help() {
3
+ return 'SAP BTP Work Zone'
4
+ }
5
+
6
+ requires() {
7
+ return ['workzone-standard']
8
+ }
9
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "sap.cloud": {
3
+ "public": true,
4
+ "service": "{{appName}}.service"
5
+ }
6
+ }
@@ -0,0 +1,59 @@
1
+ ---
2
+ modules:
3
+ - name: {{appName}}-destinations
4
+ type: com.sap.application.content
5
+ requires:
6
+ - name: {{appName}}-auth
7
+ parameters:
8
+ service-key:
9
+ name: {{appName}}-auth-key
10
+ - name: {{appName}}-html5-repo-host
11
+ parameters:
12
+ service-key:
13
+ name: {{appName}}-html5-repo-host-key
14
+ - name: srv-api
15
+ - name: {{appName}}-destination
16
+ parameters:
17
+ content-target: true
18
+ build-parameters:
19
+ no-source: true
20
+ parameters:
21
+ content:
22
+ instance:
23
+ existing_destinations_policy: update
24
+ destinations:
25
+ - Name: {{appName}}-html5-repository
26
+ ServiceInstanceName: {{appName}}-html5-repo-host
27
+ ServiceKeyName: {{appName}}-html5-repo-host-key
28
+ sap.cloud.service: {{appName}}.service
29
+ - Name: {{appName}}-auth
30
+ Authentication: OAuth2UserTokenExchange
31
+ ServiceInstanceName: {{appName}}-auth
32
+ ServiceKeyName: {{appName}}-auth-key
33
+ sap.cloud.service: {{appName}}.service
34
+
35
+ - name: {{appName}}-destination
36
+ type: org.cloudfoundry.managed-service
37
+ parameters:
38
+ service: destination
39
+ service-plan: lite
40
+ config:
41
+ HTML5Runtime_enabled: true
42
+ init_data:
43
+ instance:
44
+ existing_destinations_policy: update
45
+ destinations:
46
+ - Name: {{appName}}-srv-api
47
+ URL: ~{srv-api/srv-url}
48
+ Authentication: NoAuthentication
49
+ Type: HTTP
50
+ ProxyType: Internet
51
+ HTML5.ForwardAuthToken: true
52
+ HTML5.DynamicDestination: true
53
+ requires:
54
+ - name: srv-api
55
+ group: destinations
56
+ properties:
57
+ name: srv-api # must be used in xs-app.json as well
58
+ url: ~{srv-url}
59
+ forwardAuthToken: true
@@ -0,0 +1,46 @@
1
+ const cds = require('../../../cds')
2
+ const { readProject } = require('../../projectReader')
3
+ const { merge } = require('../../merge')
4
+ const { join } = require('path')
5
+ const { destination, destinations } = require('../../registries/mta')
6
+
7
+ module.exports = class extends require('../../plugin') {
8
+
9
+ static help() {
10
+ return 'SAP BTP Work Zone, Standard Edition'
11
+ }
12
+
13
+ requires() {
14
+ return ['html5-repo', 'destination']
15
+ }
16
+
17
+ static hasInProduction(env) {
18
+ return !!env.requires?.workzone
19
+ }
20
+
21
+ canRun() {
22
+ if (cds.requires.multitenancy) {
23
+ throw `SAP BTP Work Zone, Standard Edition does not support multitenancy yet.`
24
+ }
25
+ return true
26
+ }
27
+
28
+ async run() {
29
+ const project = readProject()
30
+ const { appUIPaths, appPath } = project
31
+ await Promise.all(appUIPaths.map(p =>
32
+ merge(__dirname, 'files/manifest.json.hbs').into(join(appPath, p, 'webapp/manifest.json'), { project })
33
+ ))
34
+ await merge({ cds: { requires: { workzone: true } } }).into('package.json')
35
+ }
36
+
37
+ async combine() {
38
+ const project = readProject()
39
+ const { hasMta } = project
40
+
41
+ if (hasMta) {
42
+ const additions = [destinations, destination]
43
+ await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { with: project, additions })
44
+ }
45
+ }
46
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  {{#isNodejs}}
3
3
  "dependencies": {
4
- "@sap/xssec": "^3"
4
+ "@sap/xssec": "^4"
5
5
  },
6
6
  "cds": {
7
7
  {{/isNodejs}}
@@ -19,10 +19,11 @@ xsuaa:
19
19
  serviceOfferingName: xsuaa
20
20
  servicePlanName: application
21
21
  parameters:
22
- xsappname: {{appName}}
23
22
  tenant-mode: {{#hasMultitenancy}}shared{{/hasMultitenancy}}{{^hasMultitenancy}}dedicated{{/hasMultitenancy}}
24
23
  {{#hasApprouter}}
25
24
  oauth2-configuration:
26
25
  redirect-uris:
27
- - https://*.<your-cluster-domain>/**
26
+ {{=<% %>=}}
27
+ - https://*.{{ tpl .Values.global.domain . }}/**
28
+ <%={{ }}=%>
28
29
  {{/hasApprouter}}
@@ -1,12 +1,15 @@
1
1
  const cds = require('../../../cds')
2
2
  const { read } = cds.utils
3
- const term = require('../../../util/term')
4
3
  const { readProject } = require('../../projectReader')
5
4
  const { merge } = require('../../merge')
6
5
  const { srv4, xsuaa, mtxSidecar4 } = require('../../registries/mta')
7
6
 
8
7
  module.exports = class XsuaaTemplate extends require('../../plugin') {
9
8
 
9
+ static help() {
10
+ return 'authentication via XSUAA'
11
+ }
12
+
10
13
  static hasInProduction(env) {
11
14
  return env.requires?.auth?.kind === 'xsuaa'
12
15
  }
@@ -50,13 +53,14 @@ module.exports = class XsuaaTemplate extends require('../../plugin') {
50
53
 
51
54
  if (hasHelm || hasHelmUnifiedRuntime) {
52
55
  await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project })
53
- }
54
- }
55
56
 
56
- finalize() {
57
- const { hasUI, hasApprouter } = readProject()
58
- if (hasUI && !hasApprouter) {
59
- console.log(`\nAlso run ${term.bold('cds add approuter --for production')} to route and authenticate the paths accessed via the UI.`)
57
+ await merge({
58
+ xsuaa: {
59
+ parameters: {
60
+ xsappname: `${project.appName}-{{ .Release.Namespace }}`
61
+ }
62
+ }
63
+ }).into('chart/values.yaml')
60
64
  }
61
65
  }
62
66
  }
@@ -0,0 +1,27 @@
1
+ const { PROJECT_FILES } = require('./constants')
2
+ const REGEX_PROJECT_NAME = /[^0-9a-zA-Z_-]+/g
3
+ const cds = require('../../lib/cds')
4
+ const { exists } = cds.utils
5
+ const { bold } = require('../../lib/util/term')
6
+
7
+ module.exports.projectName = projectName => {
8
+ if (!projectName) throw 'Specify a project name.'
9
+ const invalidChars = new Set(projectName.match(REGEX_PROJECT_NAME)) // remove duplicates
10
+ if (invalidChars.size > 0) {
11
+ throw `Project name '${projectName}' contains at least one character ('${[...invalidChars]}') which is not supported in npm package names.
12
+ Specify a different project name by replacing characters with '_' or '-', for example '${projectName.replace(REGEX_PROJECT_NAME, '_')}' or '${projectName.replace(REGEX_PROJECT_NAME, '-')}'.`
13
+ }
14
+ }
15
+
16
+ module.exports.projectFolder = cwd => {
17
+ const existingProjectFile = PROJECT_FILES.find(exists)
18
+ if (existingProjectFile) {
19
+ let message
20
+ if (cwd === cds.root) {
21
+ message = `You seem to be working in a project which is already initialized. Use ${bold('cds add')} to add more features.`
22
+ } else {
23
+ message = `You seem to be trying to initialize an existing project. Use a different project name instead.`
24
+ }
25
+ throw `${message}\nDetails: File '${existingProjectFile}' exists in the project folder which indicates an existing project. Use ${bold('cds add')} to add more features.`
26
+ }
27
+ }
@@ -34,7 +34,7 @@ module.exports = {
34
34
  eslintOpts[0] = `
35
35
  # SYNOPSIS
36
36
 
37
- ${cdslintCmd} [beta]
37
+ ${cdslintCmd}
38
38
 
39
39
  Runs environment checks and/or checks the specified models
40
40
  based on the ESLint framework
package/lib/lint/io.js CHANGED
@@ -1,8 +1,7 @@
1
+ const { read, write, exists, yaml } = require('../cds').utils;
2
+ const { readJSONC } = require("../util/fs");
1
3
  const path = require("path");
2
- const yaml = require("@sap/cds-foss")("yaml");
3
4
  const term = require("../util/term");
4
- const { read, write, exists } = require('../cds').utils;
5
- const { readJSONC } = require("../util/fs");
6
5
  const JSONC = require('../util/jsonc');
7
6
 
8
7
  module.exports = {
@@ -226,7 +225,6 @@ module.exports = {
226
225
  switch (configFile) {
227
226
  case "eslint.config.js":
228
227
  case "eslint.config.cjs":
229
- case "eslint.config.mjs":
230
228
  if (exists(configPath)) {
231
229
  logger.log(
232
230
  `${term.warn(
@@ -245,16 +243,36 @@ module.exports = [
245
243
  cds.configs.recommended,
246
244
  {
247
245
  plugins: {
248
- "@sap/cds": cds
246
+ '@sap/cds': cds
249
247
  },
250
- "files": [
248
+ files: [
251
249
  ...cds.configs.recommended.files
252
250
  ],
253
- "rules": {
251
+ rules: {
254
252
  ...cds.configs.recommended.rules
255
253
  }
256
254
  }
257
255
  ]
256
+ `)
257
+ }
258
+ break;
259
+ case "eslint.config.mjs":
260
+ if (exists(configPath)) {
261
+ logger.log(
262
+ `${term.warn(
263
+ `\n\nPlease add the following to your "${configFile}":` +
264
+ '\n\n 1. At the top of your file, import the following:')}` +
265
+ `\n\n ${term.bold('import cdsPlugin from \'@sap/eslint-plugin-cds\'')}` +
266
+ `${term.warn(
267
+ '\n\n 2. In your export, add the following to the front of the array:')}` +
268
+ `\n\n ${term.bold('cdsPlugin.configs.recommended')}`
269
+ );
270
+ } else {
271
+ await write(configPath, `
272
+ import cds from '@sap/cds/eslint.config.mjs'
273
+ import cdsPlugin from '@sap/eslint-plugin-cds'
274
+
275
+ export default [...cds.recommended, cdsPlugin.configs.recommended]
258
276
  `)
259
277
  }
260
278
  break;
@@ -12,9 +12,13 @@ const REASONS = { invalid_scope: /\binvalid_scope\b/ };
12
12
 
13
13
  function assign(params, authData) {
14
14
  if (authData?.access_token) {
15
+ let message = 'Retrieved access token';
15
16
  params.set('token', authData.access_token);
16
17
  if (authData.expires_in) {
17
18
  params.set('tokenExpirationDate', Date.now() + authData.expires_in * 1000);
19
+ if (params.get('saveData')) {
20
+ message += ` (expires on ${(new Date(params.get('tokenExpirationDate'))).toLocaleString()})`;
21
+ }
18
22
  } else {
19
23
  params.delete('tokenExpirationDate');
20
24
  }
@@ -23,6 +27,7 @@ function assign(params, authData) {
23
27
  } else {
24
28
  params.delete('refreshToken');
25
29
  }
30
+ console.log(message + '.');
26
31
  }
27
32
  if (authData?.passcode_url) {
28
33
  params.set('passcodeUrl', authData.passcode_url);
@@ -31,15 +36,19 @@ function assign(params, authData) {
31
36
  function reqParams(method, params) {
32
37
  const url = params.get('tokenUrl');
33
38
  const d = {};
39
+ const ignored = {};
34
40
  if (params.has('subdomain')) {
35
41
  d.subdomain = params.get('subdomain');
36
42
  }
37
43
  if (params.has('refreshToken')) {
38
44
  d.refresh_token = params.get('refreshToken');
45
+ const param = ['passcode', 'clientid'].find(param => params.has(param));
46
+ if (param) {
47
+ ignored[param] = 'refresh token is present';
48
+ }
39
49
  } else if (params.has('passcode')) {
40
50
  d.passcode = params.get('passcode');
41
- }
42
- if (params.has('clientsecret')) {
51
+ } else if (params.has('clientsecret')) {
43
52
  d.clientid = params.get('clientid');
44
53
  d.clientsecret = params.get('clientsecret');
45
54
  } else if (params.has('key')) {
@@ -48,43 +57,60 @@ function reqParams(method, params) {
48
57
  }
49
58
  const data = new URLSearchParams(d).toString();
50
59
  return method === 'post'
51
- ? { url, data }
52
- : { url: `${url}?${data}`, data: undefined };
60
+ ? { url, data, ignored }
61
+ : { url: `${url}?${data}`, data: undefined, ignored };
53
62
  }
54
63
 
55
- async function retrieveTokenOrPasscodeUrl(params) {
56
- if (params.has('token') || !params.has('refreshToken') && !params.has('passcode') && params.has('passcodeUrl')) {
64
+ async function fetchToken(params) {
65
+ if (params.has('token') || !(params.has('refreshToken') || params.has('passcode') || !params.has('passcodeUrl'))) {
57
66
  return;
58
67
  }
59
68
 
60
69
  let response, error;
61
- reqParams: for (const method of ['post', 'get']) {
62
- do {
63
- const { url, data } = reqParams(method, params);
64
- try {
65
- DEBUG?.(`Getting authentication token or passcode URL from ${method.toUpperCase()} ${params.obfuscateQueryParams(url)}`);
66
- response = await axios[method](url, data);
67
- } catch (e) {
68
- if (e.status === 404) { // may represent 405 in case of wrong method
69
- continue reqParams;
70
- } else if (params.has('refreshToken')) {
71
- DEBUG?.('Discarding invalid refresh token');
72
- params.delete('refreshToken');
73
- } else {
74
- error = e;
75
- break reqParams;
76
- }
70
+ const method = 'post';
71
+ do {
72
+ const { url, data, ignored } = reqParams(method, params);
73
+ if (Object.keys(ignored).length) {
74
+ console.log(`Ignoring parameters for fetching token: ${Object.entries(ignored).map(([param, reason]) => `${param} (${reason})`).join(', ')}.`);
75
+ }
76
+ DEBUG?.(`Getting authentication token from ${method.toUpperCase()} ${params.obfuscateQueryParams(url)}`);
77
+ error = undefined;
78
+ try {
79
+ response = await axios[method](url, data);
80
+ break;
81
+ } catch (e) {
82
+ error = e;
83
+ DEBUG?.(`HTTP status ${e.status}`);
84
+ if (params.has('refreshToken')) {
85
+ DEBUG?.('Discarding invalid refresh token');
86
+ params.delete('refreshToken');
87
+ } else {
88
+ break;
77
89
  }
78
- } while (!response);
79
- }
90
+ }
91
+ } while (!response);
80
92
  const data = response?.data ?? error?.auth;
81
93
  assign(params, data);
82
94
  if (error) {
83
- throw new Error(REASONS.invalid_scope.test(error.message)
84
- ? 'Token has invalid scope. Check if your user has the required roles'
85
- : `No valid passcode or token provided. Get a passcode${
86
- params.get('passcodeUrl') ? ' from ' + params.get('passcodeUrl') : ''
87
- } and re-run the command with '-p <passcode>'`, { cause: error });
95
+ let message;
96
+ if (REASONS.invalid_scope.test(error.message)) {
97
+ message = 'token has invalid scope. Check if your user has the required roles';
98
+ } else if (error.status === 404) {
99
+ message = 'token endpoint not found. Check if MTX is running with extensibility enabled';
100
+ } else if (error.message.includes('<html')) { // should already be caught when fetching passcode URL
101
+ message = 'HTML response received. Check if route to MTX is configured correctly in App Router';
102
+ } else if (error.status === 401) {
103
+ message = `invalid credentials`;
104
+ if (params.has('passcode')) {
105
+ message += `. Check if passcode is correct`;
106
+ if (params.has('passcodeUrl')) {
107
+ message += `. Passcode URL: ${params.get('passcodeUrl')}`;
108
+ }
109
+ }
110
+ } else {
111
+ message = 'error on token request';
112
+ }
113
+ throw new Error(message + '.', { cause: error });
88
114
  }
89
115
  }
90
116
 
@@ -98,7 +124,7 @@ module.exports = class AuthManager {
98
124
  params.set('reqAuth', { auth: { username: params.get('username'), password: params.get('password') } });
99
125
  } else if (!params.get('skipToken')) {
100
126
  try {
101
- await retrieveTokenOrPasscodeUrl(params);
127
+ await fetchToken(params);
102
128
  } catch (error) {
103
129
  if (params.get('saveData')) {
104
130
  await SettingsManager.saveSettings(params);
@@ -106,6 +132,14 @@ module.exports = class AuthManager {
106
132
  throw getMessage('Failed to login', { error });
107
133
  }
108
134
  params.set('reqAuth', { headers: { Authorization: 'Bearer ' + params.get('token') } });
135
+ if (params.has('refreshToken') && params.get('saveData')) {
136
+ if (params.get('saveRefreshToken')) {
137
+ console.log('Refresh Token saved. Token will be refreshed automatically.');
138
+ } else {
139
+ console.log(`Note: Refresh Token is not saved by default for security reasons. Use '--save-refresh-token' to override.`);
140
+ params.delete('refreshToken');
141
+ }
142
+ }
109
143
  }
110
144
 
111
145
  if (params.get('saveData')) {