@sap/cds-dk 9.7.2 → 9.8.1

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 (105) hide show
  1. package/CHANGELOG.md +42 -2
  2. package/bin/bind.js +7 -2
  3. package/bin/build.js +14 -4
  4. package/bin/cds.js +2 -2
  5. package/bin/completion/completionFs.js +1 -1
  6. package/bin/completion/index.js +2 -2
  7. package/bin/data-products/get-csn-via-dp-cli.js +1 -1
  8. package/bin/debug.js +1 -1
  9. package/bin/deploy/index.js +3 -2
  10. package/bin/gen.js +1 -1
  11. package/bin/help.js +1 -1
  12. package/bin/import.js +3 -0
  13. package/bin/minify.js +1 -1
  14. package/bin/mock.js +1 -1
  15. package/bin/repl.js +212 -39
  16. package/bin/test.js +0 -2
  17. package/bin/up.js +27 -3
  18. package/bin/util/containerize.js +1 -3
  19. package/bin/version.js +30 -9
  20. package/bin/watch.js +20 -4
  21. package/lib/bind/cf.js +2 -2
  22. package/lib/bind/k8s.js +0 -1
  23. package/lib/bind/plugin.js +2 -0
  24. package/lib/bind/shared.js +6 -1
  25. package/lib/build/constants.js +0 -8
  26. package/lib/build/index.js +569 -25
  27. package/lib/build/{provider/edmxBuildPlugin.js → plugins/edmx.js} +6 -15
  28. package/lib/build/{provider/featureToggleBuildPlugin.js → plugins/featureToggles.js} +8 -27
  29. package/lib/build/{provider → plugins}/fiori/index.js +27 -40
  30. package/lib/build/{provider → plugins}/hana/index.js +67 -85
  31. package/lib/build/{provider → plugins}/hana/migrationtable.js +4 -3
  32. package/lib/build/plugins/helm/index.js +6 -6
  33. package/lib/build/{provider/internalBuildPlugin.js → plugins/internal.js} +7 -31
  34. package/lib/build/{provider → plugins}/java/index.js +18 -26
  35. package/lib/build/plugins/mtx/index.js +41 -0
  36. package/lib/build/plugins/mtx/resourcesTarBuilder.js +41 -0
  37. package/lib/build/{provider → plugins}/mtx-extension/extensionCompilation.js +1 -1
  38. package/lib/build/{provider → plugins}/mtx-extension/index.js +35 -44
  39. package/lib/build/{provider → plugins}/mtx-sidecar/index.js +17 -3
  40. package/lib/build/{provider → plugins}/nodejs/index.js +29 -28
  41. package/lib/build/{plugin.js → plugins/plugin.js} +57 -60
  42. package/lib/build/plugins.js +11 -8
  43. package/lib/build/util.js +0 -8
  44. package/lib/compile/to-xsuaa.js +2 -2
  45. package/lib/deploy/to-hana/hana.js +64 -56
  46. package/lib/import/common.js +1 -1
  47. package/lib/import/odata/metadataconverter/MetadataConverter.js +4 -3
  48. package/lib/import/odata/v2parser.js +28 -28
  49. package/lib/import/odata/v4parser.js +37 -2
  50. package/lib/import/openapi/index.js +1 -1
  51. package/lib/init/constants.js +1 -2
  52. package/lib/init/template/app-frontend/index.js +1 -1
  53. package/lib/init/template/approuter/files/package.json +1 -1
  54. package/lib/init/template/completion/completionSetup.js +1 -1
  55. package/lib/init/template/data/as-csv.js +1 -1
  56. package/lib/init/template/github-actions/index.js +1 -1
  57. package/lib/init/template/handler/index.js +1 -1
  58. package/lib/init/template/helm/index.js +4 -4
  59. package/lib/init/template/kyma/index.js +3 -3
  60. package/lib/init/template/lint/index.js +7 -21
  61. package/lib/init/template/multitenancy/files/package.json.hbs +0 -5
  62. package/lib/init/template/postgres/files/containerize.yaml.hbs +15 -0
  63. package/lib/init/template/postgres/files/package.json.hbs +35 -0
  64. package/lib/init/template/postgres/files/values.yaml.hbs +23 -0
  65. package/lib/init/template/postgres/index.js +34 -9
  66. package/lib/init/template/test/files/package.json +1 -1
  67. package/lib/init/template/typescript/files/package.json +1 -1
  68. package/lib/init/template/workzone-standard/files/mta.yaml.hbs +1 -0
  69. package/lib/lint/eslintHelp.json +1 -1
  70. package/lib/lint/io.js +9 -13
  71. package/lib/mtx/pull.js +1 -1
  72. package/lib/mtx/settings_manager.js +11 -5
  73. package/lib/mtx/tenant_action.js +1 -1
  74. package/lib/mtx/util/fs.js +2 -2
  75. package/lib/util/fs.js +3 -3
  76. package/lib/util/git.js +1 -1
  77. package/lib/util/glob.js +1 -1
  78. package/lib/watch/hot-reload.js +202 -0
  79. package/lib/watch/livereload-server.js +6 -4
  80. package/lib/watch/node-watch.js +5 -1
  81. package/lib/watch/watched.js +7 -3
  82. package/lib/watch/watcher.js +41 -3
  83. package/npm-shrinkwrap.json +46 -31
  84. package/package.json +1 -1
  85. package/lib/build/buildTaskEngine.js +0 -377
  86. package/lib/build/buildTaskFactory.js +0 -198
  87. package/lib/build/buildTaskProvider.js +0 -38
  88. package/lib/build/buildTaskProviderFactory.js +0 -233
  89. package/lib/build/provider/internalBuildTaskProvider.js +0 -227
  90. package/lib/build/provider/java-cf/index.js +0 -1
  91. package/lib/build/provider/mtx/index.js +0 -36
  92. package/lib/build/provider/mtx/resourcesTarBuilder.js +0 -102
  93. package/lib/build/provider/node-cf/index.js +0 -1
  94. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +0 -40
  95. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/fixed/schema.cds +0 -4
  96. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/invalid/schema.cds +0 -4
  97. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +0 -15
  98. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/valid/schema.cds +0 -6
  99. package/lib/init/types.d.ts +0 -23
  100. /package/lib/build/{provider → plugins}/hana/2migration.js +0 -0
  101. /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-all +0 -0
  102. /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-cloud +0 -0
  103. /package/lib/build/{provider → plugins}/hana/template/.hdinamespace +0 -0
  104. /package/lib/build/{provider → plugins}/hana/template/package.json +0 -0
  105. /package/lib/build/{provider → plugins}/hana/template/undeploy.json +0 -0
@@ -1,20 +1,9 @@
1
1
  const path = require('path')
2
2
  const cds = require('../../cds')
3
- const { DEFAULT_CSN_FILE_NAME, OUTPUT_MODE, OUTPUT_MODE_RESULT } = require('../constants')
4
- const InternalBuildPlugin = require('./internalBuildPlugin')
3
+ const { DEFAULT_CSN_FILE_NAME } = require('../constants')
5
4
  const { getI18nDefaultFolder, filterFeaturePaths } = require('../util')
6
5
 
7
- class FeatureToggleBuildPlugin extends InternalBuildPlugin {
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
- }
6
+ module.exports = class FeatureTogglesBuildPlugin extends require('./internal') {
18
7
 
19
8
  async compileAll(csn, destBase, destFts) {
20
9
  const sources = filterFeaturePaths(csn, this.task.options.model || this.task.src)
@@ -31,10 +20,6 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
31
20
  const csnStr = await this.compileToJson(dictionary.base, path.join(destBase, DEFAULT_CSN_FILE_NAME))
32
21
  const csnModel = JSON.parse(csnStr)
33
22
  csnModel.meta = csn.meta
34
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
35
- this._result.csn = csnModel
36
- }
37
-
38
23
  if (sources.features) {
39
24
  dictionary.features = await this._compileFeatures(sources.features, destBase, destFts, dictionary.base)
40
25
  }
@@ -45,18 +30,16 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
45
30
  const i18nFolder = getI18nDefaultFolder()
46
31
  const ftsName = path.dirname(cds.env.features.folders || 'fts/*')
47
32
  // create language bundle for base model
48
- const i18n = await this.collectLanguageBundles(dictionary.base, path.join(destBase, i18nFolder))
49
- if (i18n && this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
50
- this._result.languageBundles = i18n.bundles
51
- }
33
+ await this.collectLanguageBundles(dictionary.base, path.join(destBase, i18nFolder))
52
34
 
53
35
  if (dictionary.features) {
54
36
  // create language bundles for all features
55
- for (const ftName in dictionary.features) {
37
+ const featureBundleTasks = Object.keys(dictionary.features).map(async ftName => {
56
38
  // attach the sources information for i18n location reference
57
39
  dictionary.features[ftName]['$sources'] = paths.features[ftName]
58
40
  await this.collectLanguageBundles(dictionary.features[ftName], path.join(destFts, ftsName, ftName, i18nFolder))
59
- }
41
+ })
42
+ await Promise.all(featureBundleTasks)
60
43
  }
61
44
  }
62
45
 
@@ -69,7 +52,7 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
69
52
  const ftsName = path.dirname(cds.env.features.folders || 'fts/*')
70
53
 
71
54
  // create feature models
72
- for (const ftName in ftsPaths) {
55
+ await Promise.all(Object.keys(ftsPaths).map(async ftName => {
73
56
  const ftCsn = await cds.load(ftsPaths[ftName], options)
74
57
  const ftPath = path.join(destFts, ftsName, ftName)
75
58
 
@@ -80,7 +63,7 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
80
63
  await this.compileToJson(ftCsn, path.join(ftPath, DEFAULT_CSN_FILE_NAME))
81
64
  this._validateFeature(ftCsn, baseCsn)
82
65
  features[ftName] = ftCsn
83
- }
66
+ }))
84
67
  return features
85
68
  }
86
69
 
@@ -90,5 +73,3 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
90
73
  cds.compiler.compileSources({ [ftCsn.requires[0]]: baseCsn, 'feature.csn': ftCsn }, { ...super.options(), ...cds.env.cdsc ?? {} })
91
74
  }
92
75
  }
93
-
94
- module.exports = FeatureToggleBuildPlugin
@@ -1,8 +1,7 @@
1
- const path = require('path')
1
+ const path = require('node:path')
2
2
  const cds = require('../../../cds')
3
- const EdmxBuildPlugin = require('../edmxBuildPlugin')
4
- const { relativePaths } = require('../../util')
5
- const { OUTPUT_MODE, OUTPUT_MODE_RESULT, BUILD_TASK_FIORI, CDS_CONFIG_PATH_SEP, OUTPUT_MODE_FILESYSTEM } = require('../../constants')
3
+ const { relativePaths, normalizePath } = require('../../util')
4
+ const { BUILD_TASK_FIORI, CDS_CONFIG_PATH_SEP } = require('../../constants')
6
5
  const DEBUG = cds.debug('cli|build')
7
6
 
8
7
  /**
@@ -10,25 +9,25 @@ const DEBUG = cds.debug('cli|build')
10
9
  * For SAP Web IDE Full-Stack compatibility a corresponding metadata.xml is still generated.
11
10
  * Though, 'fiori' build tasks can still be configured for UI5 mock server usage - see cap/issues#8673
12
11
  */
13
- class FioriBuildPlugin extends EdmxBuildPlugin {
14
- init() {
15
- // enforce
16
- this._result = {
17
- dest: this.task.dest,
18
- edmx: new Map(),
19
- languages: new Set(),
20
- services: new Set()
21
- }
22
- }
12
+ module.exports = class FioriBuildPlugin extends require('../edmx') {
13
+
14
+ _cachedEdmx = new Map()
15
+
16
+ static get taskDefaults() { return { src: normalizePath(cds.env.folders.app) } }
23
17
 
24
- async prepare() {
25
- this.context.for = this.context.for || {}
26
- this.context.for[BUILD_TASK_FIORI] = this.context.for[BUILD_TASK_FIORI] || {}
18
+ static hasTask() { return false } // never auto-pulled, only if configured in build tasks
19
+
20
+ async _ensureCachesInitialized() {
21
+ this.context.for ??= {}
22
+ this.context.for[BUILD_TASK_FIORI] ??= {}
27
23
 
28
24
  // cache for later use across multiple FioriBuildPlugin instances
29
25
  const fioriBuildOptions = this.context.for[BUILD_TASK_FIORI]
30
- fioriBuildOptions.appModel = new Map()
31
- fioriBuildOptions.appEdmx = new Map()
26
+ if (fioriBuildOptions._initialized) {
27
+ return
28
+ }
29
+ fioriBuildOptions.appModel ??= new Map()
30
+ fioriBuildOptions.appEdmx ??= new Map()
32
31
 
33
32
  // group tasks that have a common application root folder
34
33
  const appTaskGroups = new Map()
@@ -51,10 +50,6 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
51
50
  appModelGroups.set(appFolder, appModels)
52
51
  }
53
52
 
54
- // ensure edmx is cached as build result
55
- const buildOption = this.context.options[OUTPUT_MODE]
56
- this.context.options[OUTPUT_MODE] |= OUTPUT_MODE_RESULT
57
-
58
53
  try {
59
54
  for (let [appFolder, appModelGroup] of appModelGroups.entries()) {
60
55
  DEBUG?.(`building module [${appFolder}] using [${this.constructor.name}]`)
@@ -64,20 +59,19 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
64
59
  }
65
60
  DEBUG?.(`model: ${relativePaths(cds.root, modelPaths).join(", ")}`)
66
61
 
67
- //cache model per fiori app root folder
62
+ // cache model per fiori app root folder
68
63
  const options = this.options()
69
64
  const model = await cds.load(modelPaths, options)
70
65
  fioriBuildOptions.appModel.set(appFolder, model)
71
66
 
72
- await this.compileToEdmx(model)
73
-
74
67
  // cache edmx per fiori app root folder
75
- fioriBuildOptions.appEdmx.set(appFolder, this._result.edmx)
68
+ this._cachedEdmx = new Map()
69
+ await this.compileToEdmx(model)
70
+ fioriBuildOptions.appEdmx.set(appFolder, this._cachedEdmx)
76
71
  }
77
72
  } finally {
78
- this.context.options[OUTPUT_MODE] = buildOption
73
+ fioriBuildOptions._initialized = true
79
74
  }
80
- return false
81
75
  }
82
76
 
83
77
  /**
@@ -87,10 +81,7 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
87
81
  * cannot be resolved based on the defined service URI
88
82
  */
89
83
  async build() {
90
- const model = await this.model()
91
- if (!model) {
92
- return
93
- }
84
+ await this._ensureCachesInitialized()
94
85
  await this._writeEdmxToWebapp(this.task.src, this.task.dest)
95
86
  }
96
87
 
@@ -100,7 +91,7 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
100
91
 
101
92
  try {
102
93
  manifest = require(manifestPath)
103
- } catch (error) {
94
+ } catch {
104
95
  console.log(`UI module does not contain a manifest.json [${relativePaths(cds.root, manifestPath)}], skipping build`)
105
96
  return
106
97
  }
@@ -133,10 +124,8 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
133
124
  return
134
125
  }
135
126
 
136
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM)) {
137
- const edmxPath = path.resolve(path.join(dest, 'webapp'), this._strippedUrlPath(localUri))
138
- return this.write(edmx).to(edmxPath)
139
- }
127
+ const edmxPath = path.resolve(path.join(dest, 'webapp'), this._strippedUrlPath(localUri))
128
+ return this.write(edmx).to(edmxPath)
140
129
  }
141
130
 
142
131
  _getEdmxForUri(model, appFolder, uri) {
@@ -161,5 +150,3 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
161
150
  return urlString.replace(/^(\/|\\)/, '').replace(/(\/|\\)$/, '') // strip leading and trailing slash or backslash
162
151
  }
163
152
  }
164
-
165
- module.exports = FioriBuildPlugin
@@ -1,14 +1,10 @@
1
1
  const fs = require('fs')
2
- const path = require('path')
3
2
  const cds = require('../../../cds')
3
+ const { exists, isdir, path } = cds.utils
4
4
  const { compileToHdbMigration, getJournalEntities, getMigrationTableName } = require('./2migration')
5
- const InternalBuildPlugin = require('../internalBuildPlugin')
6
5
  const { find } = require('../../../util/fs')
7
- const { BuildError, relativePaths, BuildMessage, hasOptionValue, getWorkspacePaths } = require('../../util')
8
- const { OUTPUT_MODE_NONE, OUTPUT_MODE, CONTENT_PACKAGE_JSON, CONTENT_HDBTABLEDATA, CSV_FILE_DETECTION,
9
- CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES, OUTPUT_MODE_RESULT, CONTINUE_UNRESOLVED_SCHEMA_CHANGES,
10
- CSV_FILE_TARGET, OPTION_WS } = require('../../constants')
11
- const { WARNING } = InternalBuildPlugin
6
+ const { BuildError, relativePaths, BuildMessage, hasOptionValue, getWorkspacePaths, normalizePath } = require('../../util')
7
+ const { CONTENT_PACKAGE_JSON, CONTENT_HDBTABLEDATA, CSV_FILE_DETECTION, CONTENT_ENV, CONTENT_DEFAULT_ENV_JSON, CONTENT_NODE_MODULES, CONTINUE_UNRESOLVED_SCHEMA_CHANGES, CSV_FILE_TARGET, OPTION_WS, SEVERITY_WARNING } = require('../../constants')
12
8
  const DEFAULT_COMPILE_DEST_FOLDER = path.normalize("src/gen")
13
9
  const FILE_EXT_CSV = ".csv"
14
10
  const FILE_EXT_HDBTABLEDATA = ".hdbtabledata"
@@ -26,14 +22,19 @@ const DEBUG = cds.debug('cli|build')
26
22
  // This list contains exceptions which will be ignored during the consistency check.
27
23
  const PLUGINLESS_HDB_FILES = new Set([".hdbgrants", ".hdbrevokes"])
28
24
 
29
- class HanaBuildPlugin extends InternalBuildPlugin {
25
+ module.exports = class HanaBuildPlugin extends require('../internal') {
26
+
27
+ static get taskDefaults() { return { src: normalizePath(cds.env.folders.db) } }
28
+
29
+ static hasTask() {
30
+ if (cds.env.extends) return false
31
+ const src = path.join(cds.root, this.taskDefaults?.src ?? 'db')
32
+ if (!exists(src)) return false
33
+ const db = cds.env.requires.db
34
+ return db?.kind === 'hana' || db?.dialect === 'hana'
35
+ }
36
+
30
37
  init() {
31
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
32
- this._result = {
33
- dest: this.task.dest,
34
- hana: new Set()
35
- }
36
- }
37
38
  this.task.options.compileDest = path.resolve(this.task.dest, this.task.options.compileDest || DEFAULT_COMPILE_DEST_FOLDER)
38
39
  }
39
40
 
@@ -57,7 +58,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
57
58
  // 1. compile
58
59
  const hdiPlugins = await this._compileToHana(model, wsPaths)
59
60
 
60
- if (!this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_NONE)) {
61
+ if (!cds.cli.options.dry) {
61
62
  // 2. copy resources
62
63
  if (this.hasBuildOption(CSV_FILE_DETECTION, false)) {
63
64
  await this._copyResources(src, dest)
@@ -83,13 +84,12 @@ class HanaBuildPlugin extends InternalBuildPlugin {
83
84
  // common model artifacts that are not part of the current project
84
85
  if (wsPaths.length || cds.cli.options?.[OPTION_WS] || hasOptionValue(this.task.options[OPTION_WS], true)) {
85
86
  // first is winning, e.g. a .hdiconfig file might exist in multiple workspaces
86
- const wsFiles = (await this._getWorkspaceFiles(wsPaths)).reduce((acc, src) => {
87
- const { filePath } = src;
88
- if (!acc.some(file => file.filePath === filePath)) {
89
- acc.push(src);
90
- }
91
- return acc;
92
- }, []);
87
+ const seen = new Set()
88
+ const wsFiles = (await this._getWorkspaceFiles(wsPaths)).filter(src => {
89
+ if (seen.has(src.filePath)) return false
90
+ seen.add(src.filePath)
91
+ return true
92
+ });
93
93
 
94
94
  // copy artifacts to the src/gen folder in inplace mode
95
95
  const dest = path.join(this.task.dest, this.isStagingBuild() ? 'src' : 'src/gen')
@@ -101,13 +101,12 @@ class HanaBuildPlugin extends InternalBuildPlugin {
101
101
  )
102
102
  }
103
103
  }
104
- return this._result
105
104
  }
106
105
 
107
106
  /**
108
107
  * Deletes any content that has been created in folder '#this.task.dest/src/gen' by inplace mode.
109
108
  * <br>
110
- * Note: Content created in staging build will be deleted by the #BuildTaskEngine itself.
109
+ * Note: Content created in staging build will be deleted by default.
111
110
  */
112
111
  async clean() {
113
112
  if (this.isStagingBuild()) {
@@ -142,13 +141,17 @@ class HanaBuildPlugin extends InternalBuildPlugin {
142
141
  csvFolder = !dbCSVs.length || dbCSVs.some(res => res && res.startsWith(csvPath)) ? "data" : "csv"
143
142
  }
144
143
 
145
- // await each copy as order is important - reuse resources first and app resources last
144
+ // preserve last-write-wins semantics for duplicate basenames while parallelizing distinct file copies
145
+ const csvResourcesByName = new Map()
146
146
  for (const res of resources) {
147
147
  // do not duplicate resources that are already contained in db/src/**
148
148
  if (res && /\.csv$/.test(res) && !res.startsWith(dbSrc)) {
149
- await this.copy(res).to(path.join(this.task.options.compileDest, csvFolder, path.basename(res)))
149
+ csvResourcesByName.set(path.basename(res), res)
150
150
  }
151
151
  }
152
+ await Promise.all(Array.from(csvResourcesByName.entries()).map(([fileName, res]) => {
153
+ return this.copy(res).to(path.join(this.task.options.compileDest, csvFolder, fileName))
154
+ }))
152
155
  }
153
156
 
154
157
  if (this.isStagingBuild()) {
@@ -162,7 +165,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
162
165
  if (entry.startsWith(dbSrc)) {
163
166
  return true
164
167
  }
165
- if (cds.utils.isdir(entry)) {
168
+ if (isdir(entry)) {
166
169
  return !/(\/|\\)node_modules(\/|\\)?$/.test(entry) ||
167
170
  (/(\/|\\)node_modules(\/|\\)?$/.test(entry) && this.hasBuildOption(CONTENT_NODE_MODULES, true))
168
171
  }
@@ -188,7 +191,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
188
191
  const regex = RegExp('\\.cds$|\\.csv$|\\.hdbtabledata$')
189
192
 
190
193
  await this.copyNativeContent(src, dest, (entry) => {
191
- if (cds.utils.isdir(entry)) {
194
+ if (isdir(entry)) {
192
195
  return !/(\/|\\)node_modules(\/|\\)?$/.test(entry)
193
196
  }
194
197
  return (!regex.test(entry) && entry !== cds.env.build.outputfile) ||
@@ -200,7 +203,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
200
203
  // subfolders are not supported
201
204
  const allFiles = []
202
205
  for (const csvDir of csvDirs) {
203
- allFiles.push(...await find(csvDir, { filter: entry => regexData.test(entry) && !cds.utils.isdir(entry) }))
206
+ allFiles.push(...await find(csvDir, { filter: entry => regexData.test(entry) && !isdir(entry) }))
204
207
  }
205
208
 
206
209
  return Promise.all(allFiles.map((file) => {
@@ -224,7 +227,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
224
227
  const destSrcDir = path.join(this.task.dest, "src")
225
228
 
226
229
  const allCsvFiles = await find(destSrcDir, { filter: (entry) => {
227
- if (cds.utils.isdir(entry)) {
230
+ if (isdir(entry)) {
228
231
  return true
229
232
  }
230
233
  if (/\.hdbtabledata$/.test(entry)) {
@@ -257,9 +260,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
257
260
  // otherwise create in 'src/gen'
258
261
  let tableDataPath = csvFolder.startsWith(this.task.options.compileDest) ? csvFolder : this.task.options.compileDest
259
262
  tableDataPath = path.join(tableDataPath, file)
260
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
261
- this._result.hana.add(path.relative(this.task.dest, tableDataPath))
262
- }
263
263
  promises.push(this.write(tableData).to(tableDataPath))
264
264
  }
265
265
  await Promise.all(promises)
@@ -269,13 +269,11 @@ class HanaBuildPlugin extends InternalBuildPlugin {
269
269
  async _stripCsvComments(csvFiles) {
270
270
  // Note: modification of csv files is only allowed for files located in the compile destination folder,
271
271
  // meaning having their origin location at db/data/* or db/csv/*
272
- const stripComments = cds.utils.csv?.stripComments ?? require(path.join(cds.home, 'bin/build/csv-reader')).stripComments // cds@6 compatibility
273
-
274
- for (const file of csvFiles) {
272
+ await Promise.all(csvFiles.map(file => {
275
273
  if (this.isStagingBuild() || file.startsWith(this.task.options.compileDest)) {
276
- await stripComments(file, null, this.task.options.trimCsvWhitespaces)
274
+ return cds.utils.csv?.stripComments(file, null, this.task.options.trimCsvWhitespaces)
277
275
  }
278
- }
276
+ }))
279
277
  }
280
278
 
281
279
  /**
@@ -300,7 +298,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
300
298
 
301
299
  async _compileToHdb(model, format) {
302
300
  const hdiPlugins = new Set()
303
- const relDest = path.relative(this.task.dest, this.task.options.compileDest)
304
301
  // enforces sqlNames option for compiler in tests
305
302
  const options = { ...this.options(), sql_mapping: cds.env.sql.names }
306
303
  const result = cds.compile.to[format](model, options)
@@ -311,9 +308,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
311
308
  const file = key.file ? key.file : key.name + key.suffix
312
309
 
313
310
  hdiPlugins.add(suffix)
314
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
315
- this._result.hana.add(path.join(relDest, file))
316
- }
317
311
  promises.push(this.write(content).to(path.join(this.task.options.compileDest, file)))
318
312
  if (suffix === FILE_EXT_HDBTABLE) {
319
313
  const name = key.name || path.parse(key.file).name
@@ -332,7 +326,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
332
326
 
333
327
  async _compileToHdbmigration(model, format, wsPaths) {
334
328
  const hdiPlugins = new Set()
335
- const relDestDir = path.relative(this.task.dest, this.task.options.compileDest)
336
329
  const relDbDestDir = path.relative(cds.root, this.task.options.compileDest)
337
330
  const dbSrcDir = path.join(this.task.src, "src")
338
331
  const relDbSrcDir = path.relative(cds.root, dbSrcDir)
@@ -371,9 +364,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
371
364
  if (!wsMigrationTables.has(name)) {
372
365
  migrationTableFiles.push(path.join(relDbSrcDir, fileName))
373
366
  if (changed) {
374
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
375
- this._result.hana.add(path.join("src", fileName))
376
- }
377
367
  promises.push(this.write(content).to(path.join(dbSrcDir, fileName)))
378
368
  } else {
379
369
  DEBUG?.(`no change, keep existing ${fileName}`)
@@ -382,9 +372,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
382
372
  DEBUG?.(`skip generation of migration table [${fileName}] as it originates from a different workspace`)
383
373
  }
384
374
  } else {
385
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
386
- this._result.hana.add(path.join(relDestDir, fileName))
387
- }
388
375
  promises.push(this.write(content).to(path.join(this.task.options.compileDest, fileName)))
389
376
  if (suffix === FILE_EXT_HDBTABLE) {
390
377
  // issue an error in case a .hdbmigrationtable file already exists
@@ -407,12 +394,12 @@ class HanaBuildPlugin extends InternalBuildPlugin {
407
394
  } finally {
408
395
  // update last-dev CSN version
409
396
  if (afterImage) {
410
- if (!HanaBuildPlugin._toEqualIgnoreMeta(lastDev, afterImage)) {
397
+ if (!_toEqualIgnoreMeta(lastDev, afterImage)) {
411
398
  await this.write(afterImage).to(lastDevCsnDir)
412
399
  }
413
400
  // add src/.hdiconfig if not existing
414
401
  if (migrationTableFiles.length > 0 && !fs.existsSync(path.join(dbSrcDir, FILE_NAME_HDICONFIG))) {
415
- const template = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-cloud')
402
+ const template = await _readTemplateAsJson('.hdiconfig-cloud')
416
403
  await this.write(template).to(path.join(dbSrcDir, FILE_NAME_HDICONFIG))
417
404
  }
418
405
  }
@@ -428,7 +415,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
428
415
  DEBUG?.(`skip create [${relativePaths(cds.root, pkgJson)}], already existing`)
429
416
  }
430
417
  if (this.isStagingBuild() && !exists) {
431
- const content = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
418
+ const content = await _readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
432
419
  await this.write(content).to(path.join(this.task.dest, FILE_NAME_PACKAGE_JSON))
433
420
  }
434
421
  }
@@ -451,7 +438,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
451
438
  // // without the need of creating a static .hdiconfig file in the 'db' folder
452
439
 
453
440
  // // add all known plugins
454
- // const defaultHdiConfig = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-cloud')
441
+ // const defaultHdiConfig = await this._readTemplateAsJson('.hdiconfig-cloud')
455
442
  // for (const plugin in defaultHdiConfig['file_suffixes']) {
456
443
  // hdiPlugins.add('.' + plugin)
457
444
  // }
@@ -463,7 +450,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
463
450
  hdiConfigPath = path.join(this.task.options.compileDest, FILE_NAME_HDICONFIG)
464
451
  // }
465
452
 
466
- const template = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-all')
453
+ const template = await _readTemplateAsJson('.hdiconfig-all')
467
454
  let content = {
468
455
  'file_suffixes': {}
469
456
  }
@@ -490,7 +477,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
490
477
  async _writeHdiNamespace() {
491
478
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
492
479
  const hdiNamespace = path.join(this.task.options.compileDest, FILE_NAME_HDINAMESPACE)
493
- const content = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
480
+ const content = await _readTemplateAsJson(FILE_NAME_HDINAMESPACE)
494
481
  return await this.write(content).to(hdiNamespace)
495
482
  }
496
483
 
@@ -502,7 +489,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
502
489
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
503
490
  const undeployJsonDest = path.join(this.task.dest, FILE_NAME_UNDEPLOY_JSON)
504
491
  const undeployJsonSrc = path.join(this.task.src, FILE_NAME_UNDEPLOY_JSON)
505
- const templateEntries = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
492
+ const templateEntries = await _readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
506
493
  let newEntries = []
507
494
  if (fs.existsSync(undeployJsonSrc)) {
508
495
  newEntries = await JSON.parse((await fs.promises.readFile(undeployJsonSrc, 'utf-8')).toString())
@@ -532,7 +519,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
532
519
  if (fs.existsSync(file)) {
533
520
  const undeployList = JSON.parse((await fs.promises.readFile(file)).toString(), 'utf-8')
534
521
  if (Array.isArray(undeployList)) {
535
- const hdiconfig = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-all')
522
+ const hdiconfig = await _readTemplateAsJson('.hdiconfig-all')
536
523
  const keys = new Set(Object.keys(hdiconfig['file_suffixes']).map(key => '.' + key))
537
524
  undeployList.forEach(entry => {
538
525
  const extName = path.extname(entry)
@@ -540,7 +527,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
540
527
  if (keys.has(extName)) {
541
528
  hdiPlugins.add(extName)
542
529
  } else {
543
- this.pushMessage(`Ignoring invalid entry '${entry}' in undeploy.json file`, WARNING)
530
+ this.pushMessage(`Ignoring invalid entry '${entry}' in undeploy.json file`, SEVERITY_WARNING)
544
531
  }
545
532
  }
546
533
  })
@@ -566,7 +553,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
566
553
  resolutionMessages.push(new BuildMessage(`Manual resolution required for file ${path.relative(cds.root, file)}. Check migration version content for further details.`))
567
554
  }
568
555
  } catch (e) {
569
- throw new Error(`${path.relative(cds.root, file)}: ${e.toString()}`)
556
+ throw new Error(`${path.relative(cds.root, file)}: ${e.message}`, { cause: e })
570
557
  }
571
558
  }))
572
559
  if (resolutionMessages.length) {
@@ -618,35 +605,30 @@ class HanaBuildPlugin extends InternalBuildPlugin {
618
605
 
619
606
  return workspaceFiles
620
607
  }
608
+ }
621
609
 
622
- _hasJournalDefinitions(model) {
623
- return Object.values(model.definitions).some(def => def['@cds.persistence.journal'])
624
- }
610
+ async function _readTemplateAsJson(template) {
611
+ const content = await fs.promises.readFile(path.join(__dirname, 'template', template), 'utf-8')
612
+ return JSON.parse(content.toString())
613
+ }
625
614
 
626
- static async _readTemplateAsJson(template) {
627
- const content = await fs.promises.readFile(path.join(__dirname, 'template', template), 'utf-8')
628
- return JSON.parse(content.toString())
615
+ function _toEqualIgnoreMeta(csn1, csn2) {
616
+ function toString(csn) {
617
+ return JSON.stringify(csn, (k, v) => {
618
+ if (v?.creator) {
619
+ // make sure it's the compiler meta tag
620
+ if (k === 'meta' && v.creator?.startsWith('CDS Compiler'))
621
+ return
622
+ }
623
+ return v
624
+ })
629
625
  }
630
626
 
631
- static _toEqualIgnoreMeta(csn1, csn2) {
632
- function toString(csn) {
633
- return JSON.stringify(csn, (k, v) => {
634
- if (v?.creator) {
635
- // make sure it's the compiler meta tag
636
- if (k === 'meta' && v.creator?.startsWith('CDS Compiler'))
637
- return
638
- }
639
- return v
640
- })
641
- }
642
-
643
- if (csn1 === csn2) {
644
- return true
645
- }
646
- if (!csn1 || !csn2) {
647
- return false
648
- }
649
- return toString(csn1) === toString(csn2)
627
+ if (csn1 === csn2) {
628
+ return true
629
+ }
630
+ if (!csn1 || !csn2) {
631
+ return false
650
632
  }
633
+ return toString(csn1) === toString(csn2)
651
634
  }
652
- module.exports = HanaBuildPlugin
@@ -1,3 +1,4 @@
1
+ const cds = require('../../../cds')
1
2
  const fs = require('fs').promises
2
3
  const {existsSync} = require('fs')
3
4
  class MigrationTableParser {
@@ -306,7 +307,7 @@ class MigrationTableModel {
306
307
  * Delete comments and return only those lines representing DDL statements.
307
308
  */
308
309
  _compactLine(line) {
309
- return line.replace(/ /g, '')
310
+ return line.replaceAll(' ', '')
310
311
  }
311
312
  }
312
313
 
@@ -354,7 +355,7 @@ class MigrationTable {
354
355
  }
355
356
 
356
357
  clone() {
357
- return new MigrationTable(JSON.parse(JSON.stringify(this.lines)))
358
+ return new MigrationTable(cds.clone(this.lines))
358
359
  }
359
360
  }
360
361
 
@@ -465,7 +466,7 @@ class Migration {
465
466
  }
466
467
 
467
468
  clone() {
468
- return new Migration(JSON.parse(JSON.stringify(this.lines)))
469
+ return new Migration(cds.clone(this.lines))
469
470
  }
470
471
  }
471
472
 
@@ -1,11 +1,11 @@
1
1
  const cds = require('../../../cds')
2
- const { exists, path, readFileSync, yaml } = cds.utils
3
- const { Plugin, BuildError } = require('../..')
4
- const { join } = path
2
+ const { exists, path: { join }, readFileSync, yaml } = cds.utils
3
+ const { BuildError } = require('../../util')
5
4
  const { readProject } = require('../../../init/projectReader')
5
+ const { SEVERITY_WARNING } = require('../../constants')
6
6
 
7
- module.exports = class HelmBuildPlugin extends Plugin {
8
- static taskDefaults = { src: "." }
7
+ module.exports = class HelmBuildPlugin extends require('../plugin') {
8
+ static get taskDefaults() { return { src: "." } }
9
9
 
10
10
  static hasTask() {
11
11
  if (exists('chart/Chart.yaml')) {
@@ -27,7 +27,7 @@ module.exports = class HelmBuildPlugin extends Plugin {
27
27
 
28
28
  async build() {
29
29
  if (!HelmBuildPlugin.hasTask()) {
30
- this.pushMessage("Helm Chart not found. Execute `cds add kyma` to add the helm chart.", Plugin.WARNING)
30
+ this.pushMessage("Helm Chart not found. Execute `cds add kyma` to add the helm chart.", SEVERITY_WARNING)
31
31
  return
32
32
  }
33
33