@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,178 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const cds = require('../../../cds')
4
+ const BuildTaskHandlerEdmx = require('../buildTaskHandlerEdmx')
5
+ const { BuildError } = require('../../util')
6
+ const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, ODATA_VERSION_V2, FOLDER_GEN, CONTENT_EDMX,
7
+ CONTENT_PACKAGELOCK_JSON, CONTENT_NPMRC, CONTENT_CDSRC_JSON, CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON } = require('../../constants')
8
+ const { WARNING } = BuildTaskHandlerEdmx
9
+
10
+ class NodejsModuleBuilder extends BuildTaskHandlerEdmx {
11
+ init() {
12
+ super.init()
13
+ if (this.task.options.compileDest) {
14
+ throw new BuildError("Option not supported - compileDest")
15
+ }
16
+ // fallback if src has been defined as '.'
17
+ this.destSrv = this.isStagingBuild() ? path.resolve(this.task.dest, cds.env.folders.srv) : path.join(this.task.dest, FOLDER_GEN)
18
+ }
19
+
20
+ options() {
21
+ const options = super.options()
22
+ if (cds.env.requires.extensibility || cds.env.requires.toggles) {
23
+ options.flavor = 'xtended'
24
+ }
25
+ return options
26
+ }
27
+
28
+ async build() {
29
+ const destSrv = this.isStagingBuild() ? this.destSrv : path.resolve(this.destSrv, cds.env.folders.srv)
30
+ const destRoot = this.isStagingBuild() ? this.task.dest : this.destSrv
31
+
32
+ if (cds.env.odata?.version === ODATA_VERSION_V2) {
33
+ // log warning as nodejs is only supporting odata version V4
34
+ this.pushMessage("OData v2 is not supported by node runtime. Make sure to define OData v2 in cds configuration.", WARNING)
35
+ }
36
+ // by default model contains all features
37
+ const model = await this.model()
38
+ if (!model) {
39
+ return
40
+ }
41
+
42
+ const { dictionary, sources } = await this.compileAll(model, destSrv, destRoot)
43
+
44
+ // collect and write language bundles into single i18n.json file
45
+ await this.collectAllLanguageBundles(dictionary, sources, destSrv, destRoot)
46
+
47
+ if (this.hasBuildOption(CONTENT_EDMX, true)) {
48
+ const m = await cds.load(sources.base, super.options()) // REVISIT: Quick hack to get inferred model as expected by cds.compile.to.edmx()
49
+ await this.compileToEdmx(m, this.destSrv)
50
+ }
51
+
52
+ if (this.isStagingBuild() && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM)) {
53
+ const srcSrv = this.task.src === cds.root ? path.resolve(this.task.src, cds.env.folders.srv) : this.task.src
54
+ await this._copyNativeContent(cds.root, srcSrv, destRoot)
55
+ await this._fixCapireSamplesDeps(destRoot)
56
+ }
57
+ return this._result
58
+ }
59
+
60
+ // REVISIT: fix for capire samples - needs to be reworked
61
+ // Instead of adding relative paths we may better delete the entire entry as relative paths
62
+ // cannot be resolved in cloud deployments anyway.
63
+ // Support for HANA native artifacts defined in sub-modules required
64
+ async _fixCapireSamplesDeps(dest) {
65
+ const packageJson = path.join(dest, 'package.json')
66
+ try {
67
+ const content = require(packageJson)
68
+ const { dependencies } = content
69
+ let changed
70
+ for (let dependency in dependencies) {
71
+ if (dependency.startsWith('@capire/')) {
72
+ dependencies[dependency] = path.relative(dest, path.dirname(require.resolve(dependency + '/package.json')))
73
+ changed = true
74
+ }
75
+ }
76
+ if (changed) {
77
+ return this.write(JSON.stringify(content, null, ' ')).to(packageJson)
78
+ }
79
+ } catch (e) {/*ignore*/ }
80
+ }
81
+
82
+ async clean() {
83
+ // staging build content is deleted by BuildTaskEngine
84
+ if (cds.env.build.target === '.') {
85
+ // delete the entire 'task.dest' folder otherwise, for details see #constructor
86
+ // - the value of the folder 'src' has been appended to the origin 'task.dest' dir
87
+ this.logger._debug && this.logger.debug(`Deleting build target folder ${this.destSrv}`)
88
+ await fs.promises.rm(this.isStagingBuild() ? this.task.dest : this.destSrv, { force: true, recursive: true })
89
+ }
90
+ }
91
+
92
+ async _copyNativeContent(srcRoot, srcSrv, destRoot) {
93
+ // project/srv/** -> 'gen/srv/srv/**'
94
+ const filesFilter = await this._copySrvContent(srcSrv, destRoot)
95
+
96
+ // project/* -> 'gen/srv/*'
97
+ await this.copyProjectRootContent(srcRoot, destRoot, (entry) => !filesFilter.includes(path.basename(entry)))
98
+ }
99
+
100
+ /**
101
+ * Copy files for nodejs staging builds from the given <em>src</em>' folder (e.g. 'project/srv') to either <em>destRoot</em> (e.g. 'project/gen/srv')
102
+ * or <em>destSrv</em> (e.g. 'project/gen/srv/srv') folders according to the file semantics.
103
+ * Files with project semantics like 'package.json' or '.npmrc' file are copied to <em>destRoot</em> while others like '.js' service handlers
104
+ * are copied to <em>destSrv</em>.
105
+ * @param {*} src
106
+ * @param {*} destRoot - folder name representing the app root folder (e.g. gen/srv)
107
+ * @returns the list of files that have been copied
108
+ */
109
+ async _copySrvContent(src, destRoot) {
110
+ const srvRootBlockList = RegExp('package\\.json$|package-lock\\.json$|\\.npmrc$|\\.cdsrc\\.json$')
111
+ const srvBlockList = RegExp('\\.cds$|csn\\.json$|\\.csn$|manifest\\.y.?ml$|\\.env($|\\..*$)|default-env\\.json$')
112
+ const srvRootFileNames = []
113
+
114
+ // 1. copy all files to 'destSrv' except those contained in the blocklist (including node_modules)
115
+ // project/srv -> 'gen/srv/srv'
116
+ await super.copyNativeContent(src, destRoot, (entry) => {
117
+ if (fs.statSync(entry).isDirectory()) {
118
+ // TODO shall not copy language bundles - return !/(\/|\\)(node_modules|_i18n)(\/|\\)?$/.test(entry)
119
+ return !/(\/|\\)node_modules(\/|\\)?$/.test(entry)
120
+ }
121
+ // make sure the file exists on srv root level - see https://github.tools.sap/cap/issues/issues/12077
122
+ if (srvRootBlockList.test(entry) && path.dirname(entry) === src) {
123
+ srvRootFileNames.push(path.basename(entry))
124
+ return false
125
+ }
126
+ return !srvBlockList.test(entry)
127
+ })
128
+
129
+ // 2. copy dedicated files like package.json, .npmrc to 'destRoot'
130
+ // project/srv -> 'gen/srv'
131
+ let srvAllowList = "package\\.json$" // always copy package.json, modify only if CONTENT_PACKAGE_JSON is true
132
+ srvAllowList += !this.hasBuildOption(CONTENT_PACKAGELOCK_JSON, false) ? "|package-lock\\.json$" : ""
133
+ srvAllowList += !this.hasBuildOption(CONTENT_NPMRC, false) ? "|\\.npmrc$" : ""
134
+ srvAllowList += !this.hasBuildOption(CONTENT_CDSRC_JSON, false) ? "|\\.cdsrc\\.json$" : ""
135
+ srvAllowList += this.hasBuildOption(CONTENT_ENV, true) ? "|\\.env($|\\..*$)" : ""
136
+ srvAllowList += this.hasBuildOption(CONTENT_DEFAULT_ENV_JSON, true) ? "|default-env\\.json$" : ""
137
+ srvAllowList = new RegExp(srvAllowList)
138
+ await Promise.all(srvRootFileNames.map(fileName => {
139
+ if (srvAllowList.test(fileName)) {
140
+ return this.copy(path.join(src, fileName)).to(path.join(destRoot, fileName))
141
+ }
142
+ }))
143
+
144
+ return srvRootFileNames
145
+ }
146
+
147
+ /**
148
+ * Copy dedicated files (files with project semantics like package.json, .npmrc, .cdsrc, etc.)
149
+ * from the given <em>src</em> folder (e.g. 'project') into the given <em>dest</em> folder (e.g. 'project/gen/srv')
150
+ * @param {*} src
151
+ * @param {*} dest
152
+ * @param {*} filter - copy file if filter function returns true
153
+ */
154
+ async copyProjectRootContent(src, dest, filter) {
155
+ let { folders = ['i18n'] } = cds.env.i18n
156
+ folders.push('handlers')
157
+ folders = folders.map(folder => path.join(src, folder))
158
+ let srvAllowList = "package\\.json$" // always copy package.json, modify only if CONTENT_PACKAGE_JSON is true
159
+ srvAllowList += !this.hasBuildOption(CONTENT_PACKAGELOCK_JSON, false) ? "|package-lock\\.json$" : ""
160
+ srvAllowList += !this.hasBuildOption(CONTENT_NPMRC, false) ? "|\\.npmrc$" : ""
161
+ srvAllowList += !this.hasBuildOption(CONTENT_CDSRC_JSON, false) ? "|\\.cdsrc\\.json$" : ""
162
+ srvAllowList += this.hasBuildOption(CONTENT_ENV, true) ? "|\\.env($|\\..*$)" : ""
163
+ srvAllowList += this.hasBuildOption(CONTENT_DEFAULT_ENV_JSON, true) ? "|default-env\\.json$" : ""
164
+ srvAllowList = new RegExp(srvAllowList)
165
+
166
+ await super.copyNativeContent(src, dest, (entry) => {
167
+ if (fs.statSync(entry).isDirectory()) {
168
+ return folders.some(folder => entry.startsWith(folder))
169
+ }
170
+ if (/\.js$|\.properties$/.test(entry)) {
171
+ return true
172
+ }
173
+ return srvAllowList.test(entry) && (!filter || filter.call(this, entry))
174
+ })
175
+ }
176
+ }
177
+
178
+ module.exports = NodejsModuleBuilder
@@ -0,0 +1,263 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const cds = require('../cds')
4
+ const { SEVERITY_ERROR, FILE_EXT_CDS } = require('./constants')
5
+
6
+ function getProperty(src, segments) {
7
+ segments = Array.isArray(segments) ? segments : segments.split('.')
8
+ return segments.reduce((p, n) => p && p[n], src)
9
+ }
10
+
11
+ function setProperty(src, segments, value) {
12
+ segments = Array.isArray(segments) ? segments : segments.split('.')
13
+ segments.reduce((p, n, idx) => {
14
+ if (segments.length === idx + 1) {
15
+ p[n] = value
16
+ } else {
17
+ if (p[n] === undefined) {
18
+ p[n] = {}
19
+ }
20
+ }
21
+ return p[n]
22
+ }, src)
23
+ }
24
+
25
+ /**
26
+ * Returns whether this project is a java project or not.
27
+ * @param {Array} dirs - the absolute path names to check.
28
+ */
29
+ function hasJavaNature(dirs) {
30
+ return dirs.flat().reduce((acc, dir) => {
31
+ if (dir) {
32
+ const file = path.join(dir, 'pom.xml')
33
+ if (fs.existsSync(file)) {
34
+ acc.push(file)
35
+ }
36
+ }
37
+ return acc
38
+ }, []).length > 0
39
+ }
40
+
41
+ /**
42
+ * Determines whether the both values are identical.
43
+ * @param {*} actual
44
+ * @param {*} expected
45
+ */
46
+ function hasOptionValue(actual, expected) {
47
+ if (typeof expected === 'undefined') {
48
+ return actual !== undefined
49
+ }
50
+ if (typeof actual === 'undefined') {
51
+ return false
52
+ }
53
+ if (typeof expected === 'boolean') {
54
+ if (typeof actual === 'string') {
55
+ return String(expected) === actual
56
+ }
57
+ }
58
+ if (typeof expected === 'number') {
59
+ return (actual & expected) !== 0
60
+ }
61
+ return actual === expected
62
+ }
63
+
64
+ // Returning the project relative path representation of the given path(s),
65
+ function relativePaths(root, qualifiedPaths) {
66
+ qualifiedPaths = typeof qualifiedPaths === "string" ? [qualifiedPaths] : qualifiedPaths
67
+ if (Array.isArray(qualifiedPaths)) {
68
+ return qualifiedPaths.map(qualifiedPath => {
69
+ const relPath = path.relative(root, qualifiedPath)
70
+ return relPath || "."
71
+ })
72
+ }
73
+ return qualifiedPaths
74
+ }
75
+
76
+ function redactCredentials(config, o) {
77
+ return JSON.stringify(config, (k, v) => {
78
+ if (!v) {
79
+ return v
80
+ }
81
+ if (k === 'credentials') {
82
+ try {
83
+ return _redacted(v)
84
+ } catch (e) {/* ignored */ }
85
+ }
86
+ return v
87
+ }, o && o.indents || 2)
88
+ }
89
+
90
+ /** redacts password-like strings, also reducing clutter in output */
91
+ function _redacted(cred) {
92
+ const secrets = /(password)|(certificate)|(ca)/i // 'certificate' and 'ca' on HANA
93
+ const newCred = Object.assign({}, cred)
94
+ Object.keys(newCred)
95
+ .filter(k => typeof newCred[k] === 'string' && secrets.test(k))
96
+ .forEach(k => newCred[k] = '...')
97
+ return newCred
98
+ }
99
+
100
+
101
+ /**
102
+ * Returns a list of fully qualified model names belonging to the '@sap' namespace that cannot be resolved.
103
+ * E.g. the module might NOT have been installed.
104
+ * @param {Array} modelPaths
105
+ * @returns {Array}
106
+ */
107
+ function resolveRequiredSapModels(modelPaths) {
108
+ return Array.isArray(modelPaths) && modelPaths.filter(p => {
109
+ if (p.startsWith('@sap/')) {
110
+ const files = cds.resolve(p)
111
+ return !files || files.length === 0
112
+ }
113
+ })
114
+ }
115
+
116
+ function getDefaultModelOptions() {
117
+ const fts = cds.env.features.folders
118
+ const modelPaths = cds.resolve(!fts ? '*' : ['*', fts], false)
119
+ return _pushModelPaths(modelPaths)
120
+ }
121
+
122
+ function _pushModelPaths(...modelPaths) {
123
+ const model = new Set()
124
+ // may contain nested arrays
125
+ modelPaths = flatten(modelPaths)
126
+ const { roots } = cds.env
127
+ modelPaths.forEach(m => {
128
+ if (m && !model.has(m) && !model.has(m + "/")) {
129
+ // filter root model paths that do not exist
130
+ // other entries are added as is, e.g. reuse model entries
131
+ if (roots.includes(m)) {
132
+ const dir = path.resolve(cds.root, m)
133
+ if (fs.existsSync(dir)) {
134
+ model.add(m.replace(/\/$/, ''))
135
+ } else if (fs.existsSync(dir + FILE_EXT_CDS)) { //might be cds file name, compatibility to old build configs
136
+ model.add(m)
137
+ }
138
+ } else {
139
+ model.add(m)
140
+ }
141
+ }
142
+ })
143
+ return [...model]
144
+ }
145
+
146
+ function flatten(modelPaths) {
147
+ return modelPaths.reduce((acc, m) => {
148
+ if (Array.isArray(m)) {
149
+ acc = acc.concat(flatten(m))
150
+ } else if (m) {
151
+ acc.push(m)
152
+ }
153
+ return acc
154
+ }, [])
155
+ }
156
+
157
+ /**
158
+ * Copy a file or directory. The directory can have contents.
159
+ * REVISIT: 'fs.promises.cp' replacement for nodejs 14
160
+ * @param src <String> Note that if src is a directory it will copy everything inside of this directory, not the entire directory itself.
161
+ * @param dest <String> Note that if src is a file, dest cannot be a directory.
162
+ */
163
+ async function copy(src, dest) {
164
+ if ((await fs.promises.stat(src)).isDirectory()) {
165
+ const entries = await fs.promises.readdir(src)
166
+ return Promise.all(entries.map(async each => copy(path.join(src, each), path.join(dest, each))))
167
+ } else {
168
+ await fs.promises.mkdir(path.dirname(dest), { recursive: true })
169
+ return fs.promises.copyFile(src, dest)
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Return gnu-style error string for location `loc`:
175
+ * - 'File:Line:Col' without `loc.end`
176
+ * - 'File:Line:StartCol-EndCol' if Line = start.line = end.line
177
+ * - 'File:StartLine.StartCol-EndLine.EndCol' otherwise
178
+ *
179
+ * @param {CSN.Location|CSN.Location} location
180
+ */
181
+ function _locationString(loc) {
182
+ if (!loc)
183
+ return '<???>';
184
+ if (!(loc instanceof Object))
185
+ return loc;
186
+ if (!loc.line) {
187
+ return loc.file;
188
+ }
189
+ else if (!loc.endLine) {
190
+ return (loc.col)
191
+ ? `${loc.file}:${loc.line}:${loc.col}`
192
+ : `${loc.file}:${loc.line}`;
193
+ }
194
+
195
+ return (loc.line === loc.endLine)
196
+ ? `${loc.file}:${loc.line}:${loc.col}-${loc.endCol}`
197
+ : `${loc.file}:${loc.line}.${loc.col}-${loc.endLine}.${loc.endCol}`;
198
+ }
199
+
200
+ /**
201
+ * Class for individual build message.
202
+ *
203
+ * @class BuildMessage
204
+ */
205
+ class BuildMessage {
206
+ /**
207
+ * Creates an instance of BuildMessage.
208
+ * @param {string} message The message text
209
+ * @param {string} [severity='Error'] Severity: Debug, Info, Warning, Error
210
+ * @param {any} location Location of the message
211
+ *
212
+ * @memberOf BuildMessage
213
+ */
214
+ constructor(message, severity = SEVERITY_ERROR, location) {
215
+ this.message = message
216
+ this.name = "BuildMessage"
217
+ this.severity = severity
218
+ this.$location = location
219
+ }
220
+ toString() {
221
+ return `${this.$location?.file ? _locationString(this.$location) + ':' : ''} ${this.severity}: ${this.message}`
222
+ }
223
+ }
224
+
225
+ /**
226
+ * Class for combined build and compiler errors.
227
+ * Additional members:
228
+ * messages: vector of detailed build messages
229
+ * @class BuildError
230
+ * @extends {Error}
231
+ */
232
+ class BuildError extends Error {
233
+ constructor(message, messages = []) {
234
+ super(message)
235
+ this.name = "BuildError"
236
+ this.messages = Array.isArray(messages) ? messages : [messages]
237
+ this.stack = ""
238
+ }
239
+
240
+ // for compatibility reasons
241
+ get errors() {
242
+ return this.messages
243
+ }
244
+
245
+ toString() {
246
+ return this.message + (this.messages.length > 0 ? '\n' + this.messages.map(m => m.toString()).join('\n') : '')
247
+ }
248
+ }
249
+
250
+ module.exports = {
251
+ getProperty,
252
+ setProperty,
253
+ hasJavaNature,
254
+ redactCredentials,
255
+ hasOptionValue,
256
+ relativePaths,
257
+ resolveRequiredSapModels,
258
+ getDefaultModelOptions,
259
+ flatten,
260
+ copy,
261
+ BuildMessage,
262
+ BuildError
263
+ }
package/lib/cds.js CHANGED
@@ -1,27 +1,15 @@
1
- const _local = id => require(_resolve(id))
2
-
3
1
  /** @type { import('@sap/cds/lib') } */
4
- const cds = module.exports = _local ('@sap/cds')
5
-
6
- // for internal use in cds-dk only
7
- cds._log = _local ('@sap/cds/bin/utils/log')
8
- cds._local = _local
2
+ const cds = _local ('@sap/cds')
9
3
 
10
- if (/^(4\.[56]|5|6\.[01])\b/.test(cds.version)) {
11
- // cds.debug may return false as of @sap/cds@(>=4.5 && < 6.2).
12
- // Patch this to be able to call `cds.debug(label)?.(message)`.
13
- // REVISIT remove once we no longer support these versions
14
- Object.defineProperty(cds, 'debug', {
15
- value: function cds_debug_patched (module, options) {
16
- const L = cds.log (module, options)
17
- if (L._debug) return L.debug
18
- }
19
- })
20
- }
4
+ module.exports = Object.defineProperties (cds, {
5
+ // for internal use in cds-dk only
6
+ _log: { value: _local ('../bin/util/log') },
7
+ _local: { value: _local },
8
+ })
21
9
 
22
- function _resolve (id) {
23
- return require.resolve (id, {paths:[
10
+ function _local (id) {
11
+ return require(require.resolve (id, {paths:[
24
12
  process.cwd(), // project-local module is preferred
25
13
  __dirname // otherwise from our own dependencies
26
- ]})
14
+ ]}))
27
15
  }
@@ -22,21 +22,35 @@ function addTokenInfo(params, authData) {
22
22
  function addUrlInfo(params, authData) {
23
23
  params.set('passcodeUrl', authData.passcode_url);
24
24
  }
25
- function getTokenUrl(params) {
26
- const tokenUrl = new URL(params.get('tokenUrl'));
27
- tokenUrl.search = `subdomain=${params.get('subdomain')}`;
28
-
25
+ function* reqParams(params) {
26
+ const url = params.get('tokenUrl');
27
+ const d = {};
28
+ if (params.has('subdomain')) {
29
+ d.subdomain = params.get('subdomain');
30
+ }
29
31
  if (params.has('refreshToken')) {
30
- tokenUrl.search += `&refresh_token=${encodeURIComponent(params.get('refreshToken'))}`;
32
+ d.refresh_token = params.get('refreshToken');
31
33
  } else if (params.has('passcode')) {
32
- tokenUrl.search += `&passcode=${encodeURIComponent(params.get('passcode'))}`;
34
+ d.passcode = params.get('passcode');
33
35
  }
34
36
  if (params.has('clientsecret')) {
35
- tokenUrl.search += `&clientid=${encodeURIComponent(params.get('clientid'))}&clientsecret=${encodeURIComponent(params.get('clientsecret'))}`;
37
+ d.clientid = params.get('clientid');
38
+ d.clientsecret = params.get('clientsecret');
36
39
  } else if (params.has('key')) {
37
- tokenUrl.search += `&clientid=${encodeURIComponent(params.get('clientid'))}&key=${encodeURIComponent(params.get('key'))}`;
40
+ d.clientid = params.get('clientid');
41
+ d.key = params.get('key');
38
42
  }
39
- return tokenUrl.toString();
43
+ const data = new URLSearchParams(d).toString();
44
+ yield {
45
+ method: 'post',
46
+ url,
47
+ data
48
+ };
49
+ yield {
50
+ method: 'get',
51
+ url: `${url}?${data}`,
52
+ data: undefined
53
+ };
40
54
  }
41
55
 
42
56
  async function retrieveTokenOrPasscodeUrl(params) {
@@ -56,14 +70,23 @@ async function retrieveTokenOrPasscodeUrl(params) {
56
70
  let retry;
57
71
  let authData;
58
72
  do {
59
- const tokenUrl = getTokenUrl(params);
60
- DEBUG?.(`Getting authentication token or passcode URL from ${(params.obfuscateQueryParams(tokenUrl))}`);
61
-
62
73
  let response;
63
- try {
64
- response = await axios.get(tokenUrl);
65
- } catch (error) {
66
- throw new CliError('Failed to get authentication token', { error });
74
+ for (const { method, url, data } of reqParams(params)) {
75
+ try {
76
+ DEBUG?.(`Getting authentication token or passcode URL from ${method.toUpperCase()} ${(params.obfuscateQueryParams(url))}`);
77
+ response = await axios[method](url, data);
78
+ } catch (error) {
79
+ if (error.response?.status === 404) { // may represent 405 in case of wrong method
80
+ continue;
81
+ }
82
+ throw new CliError('Failed to get authentication token', { error });
83
+ }
84
+ if (response) {
85
+ break;
86
+ }
87
+ }
88
+ if (!response) {
89
+ throw new CliError('Failed to get authentication token');
67
90
  }
68
91
  authData = response.data;
69
92
 
@@ -4,16 +4,17 @@ const { execFileSync } = require('child_process');
4
4
  const cds = require('../../cds');
5
5
  const DEBUG = cds.debug('cli');
6
6
 
7
- let cachedDir;
7
+ let modulesDir;
8
8
 
9
9
  function globalModulesDir() {
10
- if (!cachedDir) {
11
- cachedDir = execFileSync('npm', ['root', '-g'], {
10
+ if (!modulesDir) {
11
+ modulesDir = execFileSync('npm', ['root', '-g'], {
12
12
  encoding: 'utf8',
13
- shell: os.platform() === 'win32'
13
+ shell: os.platform() === 'win32',
14
+ stdio: ['ignore', 'pipe', 'ignore']
14
15
  }).trim();
15
16
  }
16
- return cachedDir;
17
+ return modulesDir;
17
18
  }
18
19
 
19
20
  function requireGlobal(packageId) {
@@ -27,7 +28,7 @@ function requireGlobal(packageId) {
27
28
  }
28
29
 
29
30
  function resetCache() {
30
- cachedDir = undefined;
31
+ modulesDir = undefined;
31
32
  }
32
33
 
33
34
  module.exports = {
@@ -7,6 +7,7 @@ const { login } = require('./auth_manager');
7
7
  const BaseCommand = require('./base_command');
8
8
  const { CliError } = require('./helper/errors');
9
9
  const { schemaRegex } = require('./helper/url_helper');
10
+ const buildSystem = require('../build')
10
11
 
11
12
  module.exports = class Push extends BaseCommand {
12
13
 
@@ -17,7 +18,7 @@ module.exports = class Push extends BaseCommand {
17
18
 
18
19
  if (!('extArchive' in pushOptions)) {
19
20
  console.log(`Building project`);
20
- await cds.build({ project: projectFolder });
21
+ await buildSystem.build();
21
22
  }
22
23
 
23
24
  const { src, content } = await this.readSource(params, pushOptions);