@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,132 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const cds = require('../../cds')
4
+ const { DEFAULT_CSN_FILE_NAME, OUTPUT_MODE, OUTPUT_MODE_RESULT } = require('../constants')
5
+ const BuildTaskHandlerInternal = require('./buildTaskHandlerInternal')
6
+
7
+ class FeatureToggleBuilder extends BuildTaskHandlerInternal {
8
+ init() {
9
+ if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
10
+ this._result = {
11
+ dest: this.task.dest,
12
+ edmx: new Map(),
13
+ languages: new Set(),
14
+ services: new Set()
15
+ }
16
+ }
17
+ }
18
+
19
+ get ftsName() {
20
+ return path.dirname(cds.env.features.folders || 'fts/*')
21
+ }
22
+
23
+ async compileAll(csn, destBase, destFts) {
24
+ const sources = await this._resolveSourcePaths(csn)
25
+ const dictionary = { base: null, features: null }
26
+
27
+ if (sources.features) {
28
+ // create base model as the given CSN is containing all features
29
+ dictionary.base = await cds.load(sources.base, this.options())
30
+ } else {
31
+ // CSN already represents the base model as no features exist
32
+ dictionary.base = csn
33
+ }
34
+ // preserve @location as @source properties
35
+ const csnStr = await this.compileToJson(dictionary.base, path.join(destBase, DEFAULT_CSN_FILE_NAME))
36
+ const csnModel = JSON.parse(csnStr)
37
+ csnModel.meta = csn.meta
38
+ if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
39
+ this._result.csn = csnModel
40
+ }
41
+
42
+ if (sources.features) {
43
+ dictionary.features = await this._compileFeatures(sources.features, destBase, destFts, dictionary.base)
44
+ }
45
+ return { dictionary, sources }
46
+ }
47
+
48
+ async collectAllLanguageBundles(dictionary, paths, destBase, destFts) {
49
+ const i18nFolder = cds.env.i18n.folders?.[0] || 'i18n'
50
+ // create language bundle for base model
51
+ const i18n = await this.collectLanguageBundles(dictionary.base, path.join(destBase, i18nFolder))
52
+ if (i18n && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
53
+ this._result.languageBundles = i18n.bundles
54
+ }
55
+
56
+ if (dictionary.features) {
57
+ // create language bundles for all features
58
+ for (const ftName in dictionary.features) {
59
+ // attach the sources information for i18n location reference
60
+ dictionary.features[ftName]['$sources'] = paths.features[ftName]
61
+ await this.collectLanguageBundles(dictionary.features[ftName], path.join(destFts, this.ftsName, ftName, i18nFolder))
62
+ }
63
+ }
64
+ }
65
+
66
+ async _resolveSourcePaths(csn) {
67
+ const regex = new RegExp(path.resolve(cds.root, this.ftsName).replace(/\\/g, '\\\\') + '[/|\\\\](?<ftName>[^/|\\\\]*)')
68
+ let paths = { base: [] }
69
+
70
+ // add ROOT source file paths for the base model
71
+ paths.base = this._resolveModel().reduce((acc, file) => {
72
+ const match = file.match(regex)
73
+ if (!match) {
74
+ acc.push(file)
75
+ }
76
+ return acc
77
+ }, [])
78
+
79
+ // keep existing behavior and return paths returned by cds.resolve if features are not supported by this project
80
+ if (!fs.existsSync(path.join(cds.root, this.ftsName))) {
81
+ return paths
82
+ }
83
+
84
+ // add source file paths for the features
85
+ paths.features = csn['$sources'].reduce((acc, file) => {
86
+ const match = file.match(regex)
87
+ if (match) {
88
+ const { ftName } = match.groups
89
+ //feature
90
+ if (!acc[ftName]) {
91
+ acc[ftName] = []
92
+ }
93
+ acc[ftName].push(file)
94
+ }
95
+ return acc
96
+ }, {})
97
+
98
+ return paths
99
+ }
100
+
101
+ async _compileFeatures(ftsPaths, destBase, destFts, baseCsn) {
102
+ if (!ftsPaths) {
103
+ return
104
+ }
105
+ const features = {}
106
+ const options = { ...this.options(), flavor: 'parsed' }
107
+
108
+ // create feature models
109
+ for (const ftName in ftsPaths) {
110
+ const ftCsn = await cds.load(ftsPaths[ftName], options)
111
+ const ftPath = path.join(destFts, this.ftsName, ftName)
112
+
113
+ // replace require paths by base model path to ensure precedence of feature annotations
114
+ // see https://pages.github.tools.sap/cap/docs/cds/compiler-messages#anno-duplicate-unrelated-layer
115
+ ftCsn.requires = [path.join(path.relative(ftPath, destBase), DEFAULT_CSN_FILE_NAME).replace(/\\/g, '/')]
116
+
117
+ await this.compileToJson(ftCsn, path.join(ftPath, DEFAULT_CSN_FILE_NAME))
118
+ this._validateFeature(ftCsn, baseCsn)
119
+ features[ftName] = ftCsn
120
+ }
121
+ return features
122
+ }
123
+
124
+ _validateFeature(ftCsn, baseCsn) {
125
+ // features must not have other dependencies than base model dependencies - cross feature dependencies are not supported
126
+ // do not pass options.messages in order to avoid duplicate compiler messages
127
+ // version 2.13.9 of compileSources does not read the requires definition of parsed CSNs
128
+ cds.compiler.compileSources({ '../..csn.json': baseCsn, 'feature.csn': ftCsn }, this.options())
129
+ }
130
+ }
131
+
132
+ module.exports = FeatureToggleBuilder
@@ -0,0 +1,228 @@
1
+ const fs = require('fs')
2
+ const path = require('path')
3
+ const cds = require('../../cds')
4
+ const BuildTaskHandler = require('../buildTaskHandler')
5
+ const { hasOptionValue } = require('../util')
6
+ const { FOLDER_GEN } = require('../constants')
7
+
8
+ class BuildTaskHandlerInternal extends BuildTaskHandler {
9
+ /**
10
+ * Returns the logger that has been passed the build task engine.
11
+ * @returns {object}
12
+ */
13
+ get logger() {
14
+ //injected by framework
15
+ return this._logger;
16
+ }
17
+ /**
18
+ * Custom build handlers are executed before internal handlers in order
19
+ * ensure and content cannot be overwritten by mistake.
20
+ */
21
+ get priority() {
22
+ return BuildTaskHandlerInternal.PRIORITY_MAX_VALUE
23
+ }
24
+
25
+ async clean() {
26
+ // build results are deleted by the BuildTaskEngine if the build.target !== '.'
27
+ // make sure that src is not a subfolder of dest
28
+ if (cds.env.build.target === '.' && this.task.src !== this.task.dest && !this._isSubDirectory(this.task.dest, this.task.src)) {
29
+ await fs.promises.rm(this.task.dest, { force: true, recursive: true })
30
+ }
31
+ }
32
+ /**
33
+ * Maximum allowed priority for internal build tasks.
34
+ */
35
+ static get PRIORITY_MAX_VALUE() {
36
+ return 0;
37
+ }
38
+ /**
39
+ * Minimum allowed priority for custom build tasks.
40
+ */
41
+ static get PRIORITY_MIN_VALUE() {
42
+ return Number.MIN_SAFE_INTEGER;
43
+ }
44
+
45
+ /**
46
+ * Called by the framework after {@link #init()}. Handlers may want to perform more elaborate preparation.
47
+ * E.g. caching some pre-calculated data that can be used across multiple build tasks. This kind of data
48
+ * has to be stored in the handler type specific buildOptions section.
49
+ * @returns {Promise<boolean>} A value 'false' indicates that {@link #prepare()} will not be called for other instances
50
+ * of this handler type.
51
+ * True indicates that {@link #prepare()} will be called for other instances of this of this handler type.
52
+ * @deprecated
53
+ */
54
+ async prepare() {
55
+ // cancel subsequent prepare calls for other handlers of the same type by default
56
+ return false
57
+ }
58
+
59
+ /**
60
+ * Returns whether cds env has a property with the specified value.
61
+ * If the value is omitted the existence of the given property name is checked.
62
+ * @param {string} qualifiedName
63
+ * @param {any=} value
64
+ */
65
+ hasCdsEnvOption(qualifiedName, value) {
66
+ return hasOptionValue(cds.env.get(qualifiedName), value)
67
+ }
68
+
69
+ /**
70
+ * Determines whether the given build option value has been set for this build task.
71
+ * If the value is omitted, the existence of the given property name is checked.
72
+ * @param {string} qualifiedName
73
+ * @param {any=} value
74
+ */
75
+ hasBuildOption(qualifiedName, value) {
76
+ return hasOptionValue(this._getBuildOption(qualifiedName), value)
77
+ }
78
+
79
+ /**
80
+ * Returns the value of the given build option defined for this build task.
81
+ * @param {string} qualifiedName
82
+ */
83
+ getBuildOption(qualifiedName) {
84
+ return super._getBuildOption(qualifiedName)
85
+ }
86
+
87
+ /**
88
+ * Returns a list of CDS model files defining the transitive closure of the CDS model based on the model options
89
+ * defined for this build task.
90
+ */
91
+ resolveModel() {
92
+ return this._resolveModel()
93
+ }
94
+
95
+ /**
96
+ * Returns whether the build results of this build plugin are created inplace
97
+ * or in a separate staging folder which is not part of the build tasks src folder.
98
+ */
99
+ isStagingBuild() {
100
+ return !this.task.src.startsWith(this.task.dest)
101
+ }
102
+
103
+ async copyNativeContent(srcDir, destDir, customFilter) {
104
+ const files = BuildTaskHandlerInternal._find(srcDir, (src) => {
105
+ // do not copy files that:
106
+ // - from 'cds.env.build.target'
107
+ // - from 'dest'
108
+ // - from some generation folder
109
+ // - do not match filter function
110
+ return this._commonStagingBuildFilter(src, destDir) && (!customFilter || customFilter.call(this, src))
111
+ })
112
+ return Promise.all(
113
+ files.map((srcFile) => {
114
+ let relFile = path.relative(srcDir, srcFile)
115
+ let destFile = path.join(destDir, relFile)
116
+ return this.copy(srcFile).to(destFile)
117
+ })
118
+ )
119
+ }
120
+
121
+ async compileToJson(model, csnFile) {
122
+ // This will als add a @source prop containing the relative path to the origin .cds source file
123
+ // and a parsed _where clause for @restrict.{grant,where} annotations.
124
+ // The @source annotation is required for correct custom handler resolution if no @impl annotation has been defined as
125
+ // custom service handler implementations are relative to the origin .cds source files.
126
+ // For staging builds (task.src !== task.dest) the csn.json file that is served at runtime is copied into a corresponding srv subfolder.
127
+ // As a consequence the src folder name has to be included in the @source file name while for inplace builds (task.src === task.dest) this is not the case.
128
+ // This ensures that the paths are relative to the cwd when executing cds run.
129
+ const jsonOptions = {
130
+ cwd: cds.root,
131
+ src: this.task.src
132
+ }
133
+ const csnStr = cds.compile.to.json(model, jsonOptions)
134
+ await this.write(csnStr).to(csnFile)
135
+ return csnStr
136
+ }
137
+
138
+ /**
139
+ * Collect and write language bundles into a single i18n.json file.
140
+ * @param {Object} model
141
+ * @param {string} bundleDest
142
+ */
143
+ async collectLanguageBundles(model, bundleDest) {
144
+ // collect effective i18n properties...
145
+ let bundles = {}
146
+ const bundleGenerator = cds.localize.bundles4(model)
147
+ if (bundleGenerator && bundleGenerator[Symbol.iterator]) {
148
+ for (let [locale, bundle] of bundleGenerator) {
149
+ // fallback bundle has the name ""
150
+ if (typeof locale === 'string') {
151
+ bundles[locale] = bundle
152
+ }
153
+ }
154
+ }
155
+
156
+ // omit bundles in case the fallback bundle is the only existing entry
157
+ const keys = Object.keys(bundles)
158
+ if (keys.length === 1 && keys[0] === "" && Object.keys(bundles[keys[0]]).length === 0) {
159
+ bundles = {}
160
+ }
161
+ // copied from ../compile/i18n.js
162
+ const { file: base = 'i18n' } = cds.env.i18n
163
+ const file = path.join(bundleDest, base + '.json')
164
+
165
+ // bundleDest might be null
166
+ if (bundleDest && Object.keys(bundles).length > 0) {
167
+ await this.write(bundles).to(file)
168
+ return { file, bundles }
169
+ }
170
+ return null
171
+ }
172
+
173
+ _isSubDirectory(parent, child) {
174
+ return !path.relative(parent, child).startsWith('..')
175
+ }
176
+
177
+ _commonStagingBuildFilter(src, destDir) {
178
+ if (typeof src !== "string" || typeof destDir !== "string") {
179
+ return false
180
+ }
181
+ if (!fs.statSync(src).isDirectory()) {
182
+ return true //file
183
+ }
184
+ if (src === destDir) {
185
+ return false
186
+ }
187
+ const regex = new RegExp(FOLDER_GEN + "\\b")
188
+ if (src === path.resolve(cds.root, cds.env.build.target)) {
189
+ return false
190
+ }
191
+ return !regex.exec(path.basename(src))
192
+ }
193
+
194
+ static _find(srcDir, filter) {
195
+ const files = []
196
+ this._traverseFileSystem(srcDir, files, filter)
197
+ return files;
198
+ }
199
+
200
+ static _traverseFileSystem(srcDir, files, filter) {
201
+ let entries = []
202
+ try {
203
+ entries = fs.readdirSync(srcDir)
204
+ } catch (e) {
205
+ // ignore if not existing
206
+ }
207
+ entries.map(subDirEntry => path.join(srcDir, subDirEntry)).forEach((entry) => {
208
+ this._handleResource(entry, files, filter)
209
+ })
210
+ }
211
+
212
+ static _handleResource(entry, files, filter) {
213
+ if (!filter || filter.call(this, entry)) {
214
+ var stats = this._getResourceStatus(entry)
215
+ if (stats.isDirectory()) {
216
+ this._traverseFileSystem(entry, files, filter)
217
+ } else if (stats.isFile() || stats.isSymbolicLink()) {
218
+ files.push(entry)
219
+ }
220
+ }
221
+ }
222
+
223
+ // for testing purposes
224
+ static _getResourceStatus(entry) {
225
+ return fs.lstatSync(entry)
226
+ }
227
+ }
228
+ module.exports = BuildTaskHandlerInternal