@sap/cds-dk 9.7.1 → 9.8.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 (108) hide show
  1. package/CHANGELOG.md +44 -1
  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 +27 -7
  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} +3 -23
  29. package/lib/build/{provider → plugins}/fiori/index.js +27 -38
  30. package/lib/build/{provider → plugins}/hana/index.js +61 -83
  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 +18 -4
  40. package/lib/build/{provider → plugins}/nodejs/index.js +29 -28
  41. package/lib/build/{plugin.js → plugins/plugin.js} +45 -59
  42. package/lib/build/plugins.js +11 -8
  43. package/lib/build/util.js +18 -16
  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 +0 -1
  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/approuter/files/values.yaml.hbs +1 -0
  55. package/lib/init/template/completion/completionSetup.js +1 -1
  56. package/lib/init/template/data/as-csv.js +1 -1
  57. package/lib/init/template/github-actions/index.js +1 -1
  58. package/lib/init/template/handler/index.js +1 -1
  59. package/lib/init/template/helm/index.js +3 -3
  60. package/lib/init/template/initial/files/readme.md +2 -4
  61. package/lib/init/template/kyma/index.js +9 -5
  62. package/lib/init/template/lint/index.js +7 -21
  63. package/lib/init/template/multitenancy/files/package.json.hbs +0 -5
  64. package/lib/init/template/postgres/files/containerize.yaml.hbs +15 -0
  65. package/lib/init/template/postgres/files/package.json.hbs +35 -0
  66. package/lib/init/template/postgres/files/values.yaml.hbs +23 -0
  67. package/lib/init/template/postgres/index.js +34 -9
  68. package/lib/init/template/test/files/package.json +1 -1
  69. package/lib/init/template/typescript/files/package.json +1 -1
  70. package/lib/init/template/workzone-standard/files/mta.yaml.hbs +1 -0
  71. package/lib/lint/eslintHelp.json +1 -1
  72. package/lib/lint/io.js +9 -13
  73. package/lib/mtx/pull.js +1 -1
  74. package/lib/mtx/settings_manager.js +11 -5
  75. package/lib/mtx/tenant_action.js +1 -1
  76. package/lib/mtx/util/fs.js +2 -2
  77. package/lib/util/cf.js +1 -1
  78. package/lib/util/fs.js +3 -3
  79. package/lib/util/git.js +1 -1
  80. package/lib/util/glob.js +1 -1
  81. package/lib/watch/hot-reload.js +202 -0
  82. package/lib/watch/livereload-server.js +6 -4
  83. package/lib/watch/node-watch.js +5 -1
  84. package/lib/watch/watched.js +7 -3
  85. package/lib/watch/watcher.js +41 -3
  86. package/npm-shrinkwrap.json +35 -26
  87. package/package.json +1 -1
  88. package/lib/build/buildTaskEngine.js +0 -377
  89. package/lib/build/buildTaskFactory.js +0 -198
  90. package/lib/build/buildTaskProvider.js +0 -38
  91. package/lib/build/buildTaskProviderFactory.js +0 -233
  92. package/lib/build/provider/internalBuildTaskProvider.js +0 -227
  93. package/lib/build/provider/java-cf/index.js +0 -1
  94. package/lib/build/provider/mtx/index.js +0 -36
  95. package/lib/build/provider/mtx/resourcesTarBuilder.js +0 -102
  96. package/lib/build/provider/node-cf/index.js +0 -1
  97. package/lib/init/template/lint/files/.eslint/rules/no-entity-moo.js +0 -40
  98. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/fixed/schema.cds +0 -4
  99. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/invalid/schema.cds +0 -4
  100. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/rule.test.js +0 -15
  101. package/lib/init/template/lint/files/.eslint/tests/no-entity-moo/valid/schema.cds +0 -6
  102. package/lib/init/types.d.ts +0 -23
  103. /package/lib/build/{provider → plugins}/hana/2migration.js +0 -0
  104. /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-all +0 -0
  105. /package/lib/build/{provider → plugins}/hana/template/.hdiconfig-cloud +0 -0
  106. /package/lib/build/{provider → plugins}/hana/template/.hdinamespace +0 -0
  107. /package/lib/build/{provider → plugins}/hana/template/package.json +0 -0
  108. /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,10 +30,7 @@ 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
@@ -90,5 +72,3 @@ class FeatureToggleBuildPlugin extends InternalBuildPlugin {
90
72
  cds.compiler.compileSources({ [ftCsn.requires[0]]: baseCsn, 'feature.csn': ftCsn }, { ...super.options(), ...cds.env.cdsc ?? {} })
91
73
  }
92
74
  }
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,7 +59,7 @@ 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)
@@ -72,12 +67,13 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
72
67
  await this.compileToEdmx(model)
73
68
 
74
69
  // cache edmx per fiori app root folder
75
- fioriBuildOptions.appEdmx.set(appFolder, this._result.edmx)
70
+ this._cachedEdmx = new Map()
71
+ await this.compileToEdmx(model)
72
+ fioriBuildOptions.appEdmx.set(appFolder, this._cachedEdmx)
76
73
  }
77
74
  } finally {
78
- this.context.options[OUTPUT_MODE] = buildOption
75
+ fioriBuildOptions._initialized = true
79
76
  }
80
- return false
81
77
  }
82
78
 
83
79
  /**
@@ -87,10 +83,7 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
87
83
  * cannot be resolved based on the defined service URI
88
84
  */
89
85
  async build() {
90
- const model = await this.model()
91
- if (!model) {
92
- return
93
- }
86
+ await this._ensureCachesInitialized()
94
87
  await this._writeEdmxToWebapp(this.task.src, this.task.dest)
95
88
  }
96
89
 
@@ -100,7 +93,7 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
100
93
 
101
94
  try {
102
95
  manifest = require(manifestPath)
103
- } catch (error) {
96
+ } catch {
104
97
  console.log(`UI module does not contain a manifest.json [${relativePaths(cds.root, manifestPath)}], skipping build`)
105
98
  return
106
99
  }
@@ -133,10 +126,8 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
133
126
  return
134
127
  }
135
128
 
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
- }
129
+ const edmxPath = path.resolve(path.join(dest, 'webapp'), this._strippedUrlPath(localUri))
130
+ return this.write(edmx).to(edmxPath)
140
131
  }
141
132
 
142
133
  _getEdmxForUri(model, appFolder, uri) {
@@ -161,5 +152,3 @@ class FioriBuildPlugin extends EdmxBuildPlugin {
161
152
  return urlString.replace(/^(\/|\\)/, '').replace(/(\/|\\)$/, '') // strip leading and trailing slash or backslash
162
153
  }
163
154
  }
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()) {
@@ -162,7 +161,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
162
161
  if (entry.startsWith(dbSrc)) {
163
162
  return true
164
163
  }
165
- if (cds.utils.isdir(entry)) {
164
+ if (isdir(entry)) {
166
165
  return !/(\/|\\)node_modules(\/|\\)?$/.test(entry) ||
167
166
  (/(\/|\\)node_modules(\/|\\)?$/.test(entry) && this.hasBuildOption(CONTENT_NODE_MODULES, true))
168
167
  }
@@ -188,7 +187,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
188
187
  const regex = RegExp('\\.cds$|\\.csv$|\\.hdbtabledata$')
189
188
 
190
189
  await this.copyNativeContent(src, dest, (entry) => {
191
- if (cds.utils.isdir(entry)) {
190
+ if (isdir(entry)) {
192
191
  return !/(\/|\\)node_modules(\/|\\)?$/.test(entry)
193
192
  }
194
193
  return (!regex.test(entry) && entry !== cds.env.build.outputfile) ||
@@ -200,7 +199,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
200
199
  // subfolders are not supported
201
200
  const allFiles = []
202
201
  for (const csvDir of csvDirs) {
203
- allFiles.push(...await find(csvDir, { filter: entry => regexData.test(entry) && !cds.utils.isdir(entry) }))
202
+ allFiles.push(...await find(csvDir, { filter: entry => regexData.test(entry) && !isdir(entry) }))
204
203
  }
205
204
 
206
205
  return Promise.all(allFiles.map((file) => {
@@ -224,7 +223,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
224
223
  const destSrcDir = path.join(this.task.dest, "src")
225
224
 
226
225
  const allCsvFiles = await find(destSrcDir, { filter: (entry) => {
227
- if (cds.utils.isdir(entry)) {
226
+ if (isdir(entry)) {
228
227
  return true
229
228
  }
230
229
  if (/\.hdbtabledata$/.test(entry)) {
@@ -257,9 +256,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
257
256
  // otherwise create in 'src/gen'
258
257
  let tableDataPath = csvFolder.startsWith(this.task.options.compileDest) ? csvFolder : this.task.options.compileDest
259
258
  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
259
  promises.push(this.write(tableData).to(tableDataPath))
264
260
  }
265
261
  await Promise.all(promises)
@@ -269,13 +265,11 @@ class HanaBuildPlugin extends InternalBuildPlugin {
269
265
  async _stripCsvComments(csvFiles) {
270
266
  // Note: modification of csv files is only allowed for files located in the compile destination folder,
271
267
  // 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) {
268
+ await Promise.all(csvFiles.map(file => {
275
269
  if (this.isStagingBuild() || file.startsWith(this.task.options.compileDest)) {
276
- await stripComments(file, null, this.task.options.trimCsvWhitespaces)
270
+ return cds.utils.csv?.stripComments(file, null, this.task.options.trimCsvWhitespaces)
277
271
  }
278
- }
272
+ }))
279
273
  }
280
274
 
281
275
  /**
@@ -300,7 +294,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
300
294
 
301
295
  async _compileToHdb(model, format) {
302
296
  const hdiPlugins = new Set()
303
- const relDest = path.relative(this.task.dest, this.task.options.compileDest)
304
297
  // enforces sqlNames option for compiler in tests
305
298
  const options = { ...this.options(), sql_mapping: cds.env.sql.names }
306
299
  const result = cds.compile.to[format](model, options)
@@ -311,9 +304,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
311
304
  const file = key.file ? key.file : key.name + key.suffix
312
305
 
313
306
  hdiPlugins.add(suffix)
314
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
315
- this._result.hana.add(path.join(relDest, file))
316
- }
317
307
  promises.push(this.write(content).to(path.join(this.task.options.compileDest, file)))
318
308
  if (suffix === FILE_EXT_HDBTABLE) {
319
309
  const name = key.name || path.parse(key.file).name
@@ -332,7 +322,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
332
322
 
333
323
  async _compileToHdbmigration(model, format, wsPaths) {
334
324
  const hdiPlugins = new Set()
335
- const relDestDir = path.relative(this.task.dest, this.task.options.compileDest)
336
325
  const relDbDestDir = path.relative(cds.root, this.task.options.compileDest)
337
326
  const dbSrcDir = path.join(this.task.src, "src")
338
327
  const relDbSrcDir = path.relative(cds.root, dbSrcDir)
@@ -371,9 +360,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
371
360
  if (!wsMigrationTables.has(name)) {
372
361
  migrationTableFiles.push(path.join(relDbSrcDir, fileName))
373
362
  if (changed) {
374
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
375
- this._result.hana.add(path.join("src", fileName))
376
- }
377
363
  promises.push(this.write(content).to(path.join(dbSrcDir, fileName)))
378
364
  } else {
379
365
  DEBUG?.(`no change, keep existing ${fileName}`)
@@ -382,9 +368,6 @@ class HanaBuildPlugin extends InternalBuildPlugin {
382
368
  DEBUG?.(`skip generation of migration table [${fileName}] as it originates from a different workspace`)
383
369
  }
384
370
  } else {
385
- if (this.hasBuildOption(OUTPUT_MODE, OUTPUT_MODE_RESULT)) {
386
- this._result.hana.add(path.join(relDestDir, fileName))
387
- }
388
371
  promises.push(this.write(content).to(path.join(this.task.options.compileDest, fileName)))
389
372
  if (suffix === FILE_EXT_HDBTABLE) {
390
373
  // issue an error in case a .hdbmigrationtable file already exists
@@ -407,12 +390,12 @@ class HanaBuildPlugin extends InternalBuildPlugin {
407
390
  } finally {
408
391
  // update last-dev CSN version
409
392
  if (afterImage) {
410
- if (!HanaBuildPlugin._toEqualIgnoreMeta(lastDev, afterImage)) {
393
+ if (!_toEqualIgnoreMeta(lastDev, afterImage)) {
411
394
  await this.write(afterImage).to(lastDevCsnDir)
412
395
  }
413
396
  // add src/.hdiconfig if not existing
414
397
  if (migrationTableFiles.length > 0 && !fs.existsSync(path.join(dbSrcDir, FILE_NAME_HDICONFIG))) {
415
- const template = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-cloud')
398
+ const template = await _readTemplateAsJson('.hdiconfig-cloud')
416
399
  await this.write(template).to(path.join(dbSrcDir, FILE_NAME_HDICONFIG))
417
400
  }
418
401
  }
@@ -428,7 +411,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
428
411
  DEBUG?.(`skip create [${relativePaths(cds.root, pkgJson)}], already existing`)
429
412
  }
430
413
  if (this.isStagingBuild() && !exists) {
431
- const content = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
414
+ const content = await _readTemplateAsJson(FILE_NAME_PACKAGE_JSON)
432
415
  await this.write(content).to(path.join(this.task.dest, FILE_NAME_PACKAGE_JSON))
433
416
  }
434
417
  }
@@ -451,7 +434,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
451
434
  // // without the need of creating a static .hdiconfig file in the 'db' folder
452
435
 
453
436
  // // add all known plugins
454
- // const defaultHdiConfig = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-cloud')
437
+ // const defaultHdiConfig = await this._readTemplateAsJson('.hdiconfig-cloud')
455
438
  // for (const plugin in defaultHdiConfig['file_suffixes']) {
456
439
  // hdiPlugins.add('.' + plugin)
457
440
  // }
@@ -463,7 +446,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
463
446
  hdiConfigPath = path.join(this.task.options.compileDest, FILE_NAME_HDICONFIG)
464
447
  // }
465
448
 
466
- const template = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-all')
449
+ const template = await _readTemplateAsJson('.hdiconfig-all')
467
450
  let content = {
468
451
  'file_suffixes': {}
469
452
  }
@@ -490,7 +473,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
490
473
  async _writeHdiNamespace() {
491
474
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
492
475
  const hdiNamespace = path.join(this.task.options.compileDest, FILE_NAME_HDINAMESPACE)
493
- const content = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_HDINAMESPACE)
476
+ const content = await _readTemplateAsJson(FILE_NAME_HDINAMESPACE)
494
477
  return await this.write(content).to(hdiNamespace)
495
478
  }
496
479
 
@@ -502,7 +485,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
502
485
  // see issue #64 - add .hdinamespace file to prevent HDI from adding gen/ folder to the namespace.
503
486
  const undeployJsonDest = path.join(this.task.dest, FILE_NAME_UNDEPLOY_JSON)
504
487
  const undeployJsonSrc = path.join(this.task.src, FILE_NAME_UNDEPLOY_JSON)
505
- const templateEntries = await HanaBuildPlugin._readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
488
+ const templateEntries = await _readTemplateAsJson(FILE_NAME_UNDEPLOY_JSON)
506
489
  let newEntries = []
507
490
  if (fs.existsSync(undeployJsonSrc)) {
508
491
  newEntries = await JSON.parse((await fs.promises.readFile(undeployJsonSrc, 'utf-8')).toString())
@@ -532,7 +515,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
532
515
  if (fs.existsSync(file)) {
533
516
  const undeployList = JSON.parse((await fs.promises.readFile(file)).toString(), 'utf-8')
534
517
  if (Array.isArray(undeployList)) {
535
- const hdiconfig = await HanaBuildPlugin._readTemplateAsJson('.hdiconfig-all')
518
+ const hdiconfig = await _readTemplateAsJson('.hdiconfig-all')
536
519
  const keys = new Set(Object.keys(hdiconfig['file_suffixes']).map(key => '.' + key))
537
520
  undeployList.forEach(entry => {
538
521
  const extName = path.extname(entry)
@@ -540,7 +523,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
540
523
  if (keys.has(extName)) {
541
524
  hdiPlugins.add(extName)
542
525
  } else {
543
- this.pushMessage(`Ignoring invalid entry '${entry}' in undeploy.json file`, WARNING)
526
+ this.pushMessage(`Ignoring invalid entry '${entry}' in undeploy.json file`, SEVERITY_WARNING)
544
527
  }
545
528
  }
546
529
  })
@@ -566,7 +549,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
566
549
  resolutionMessages.push(new BuildMessage(`Manual resolution required for file ${path.relative(cds.root, file)}. Check migration version content for further details.`))
567
550
  }
568
551
  } catch (e) {
569
- throw new Error(`${path.relative(cds.root, file)}: ${e.toString()}`)
552
+ throw new Error(`${path.relative(cds.root, file)}: ${e.message}`, { cause: e })
570
553
  }
571
554
  }))
572
555
  if (resolutionMessages.length) {
@@ -618,35 +601,30 @@ class HanaBuildPlugin extends InternalBuildPlugin {
618
601
 
619
602
  return workspaceFiles
620
603
  }
604
+ }
621
605
 
622
- _hasJournalDefinitions(model) {
623
- return Object.values(model.definitions).some(def => def['@cds.persistence.journal'])
624
- }
606
+ async function _readTemplateAsJson(template) {
607
+ const content = await fs.promises.readFile(path.join(__dirname, 'template', template), 'utf-8')
608
+ return JSON.parse(content.toString())
609
+ }
625
610
 
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())
611
+ function _toEqualIgnoreMeta(csn1, csn2) {
612
+ function toString(csn) {
613
+ return JSON.stringify(csn, (k, v) => {
614
+ if (v?.creator) {
615
+ // make sure it's the compiler meta tag
616
+ if (k === 'meta' && v.creator?.startsWith('CDS Compiler'))
617
+ return
618
+ }
619
+ return v
620
+ })
629
621
  }
630
622
 
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)
623
+ if (csn1 === csn2) {
624
+ return true
625
+ }
626
+ if (!csn1 || !csn2) {
627
+ return false
650
628
  }
629
+ return toString(csn1) === toString(csn2)
651
630
  }
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
 
@@ -1,20 +1,12 @@
1
- const fs = require('fs')
2
1
  const path = require('path')
3
2
  const cds = require('../../cds')
4
- const Plugin = require('../plugin')
3
+ const { rimraf, isdir } = cds.utils
5
4
  const { find } = require('../../util/fs')
6
5
  const { hasOptionValue } = require('../util')
7
- const { FOLDER_GEN, DEFAULT_BUILTIN_PRIORITY_MAX } = require('../constants')
6
+ const { FOLDER_GEN } = require('../constants')
8
7
  const TRACE = cds.debug('trace')
9
8
 
10
- class InternalBuildPlugin extends Plugin {
11
- /**
12
- * By default custom build plugins are executed before internal build plugins
13
- * to ensure built-in plugin content isn't overwritten by mistake.
14
- */
15
- get priority() {
16
- return DEFAULT_BUILTIN_PRIORITY_MAX / 2
17
- }
9
+ module.exports = class InternalBuildPlugin extends require('./plugin') {
18
10
 
19
11
  init() {
20
12
  // REVISIT: no default gen folder for now
@@ -24,26 +16,13 @@ class InternalBuildPlugin extends Plugin {
24
16
  function _isSubDirectory(parent, child) {
25
17
  return !path.relative(parent, child).startsWith('..')
26
18
  }
27
- // build results are deleted by the BuildTaskEngine if the build.target !== '.'
19
+ // build results are deleted by default if the build.target !== '.'
28
20
  // make sure that src is not a subfolder of dest
29
21
  if (cds.env.build.target === '.' && this.task.src !== this.task.dest && !_isSubDirectory(this.task.dest, this.task.src)) {
30
- await fs.promises.rm(this.task.dest, { force: true, recursive: true })
22
+ await rimraf(this.task.dest)
31
23
  }
32
24
  }
33
25
 
34
- /**
35
- * Called by the framework after {@link #init()}, used to perform more elaborate preparation.
36
- * E.g. caching some pre-calculated data that can be used across multiple build tasks. This kind of data
37
- * has to be stored in the plugin type specific options section.
38
- * @returns {Promise<boolean>} A value 'false' indicates that {@link #prepare()} will not be called for other instances
39
- * of this plugin type.
40
- * True indicates that {@link #prepare()} will be called for other instances of this of this plugin type.
41
- * @deprecated
42
- */
43
- async prepare() {
44
- // cancel subsequent prepare calls for other plugins of the same type by default
45
- return false
46
- }
47
26
 
48
27
  /**
49
28
  * Determines whether the given build option value has been set for this build task.
@@ -72,17 +51,17 @@ class InternalBuildPlugin extends Plugin {
72
51
  }
73
52
 
74
53
  async copyNativeContent(srcDir, destDir, customFilter) {
54
+ const regex = new RegExp(FOLDER_GEN + "\\b")
75
55
  function commonStagingBuildFilter(src, destDir) {
76
56
  if (typeof src !== "string" || typeof destDir !== "string") {
77
57
  return false
78
58
  }
79
- if (!cds.utils.isdir(src)) {
59
+ if (!isdir(src)) {
80
60
  return true //file
81
61
  }
82
62
  if (src === destDir) {
83
63
  return false
84
64
  }
85
- const regex = new RegExp(FOLDER_GEN + "\\b")
86
65
  if (src === path.resolve(cds.root, cds.env.build.target)) {
87
66
  return false
88
67
  }
@@ -192,6 +171,3 @@ function cds_compile_to_json (csn,o) {
192
171
  }
193
172
  finally { TRACE?.timeEnd('cds.compile 2json'.padEnd(22)) }
194
173
  }
195
-
196
-
197
- module.exports = InternalBuildPlugin