@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,12 +1,12 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "9.7.2",
3
+ "version": "9.8.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@sap/cds-dk",
9
- "version": "9.7.2",
9
+ "version": "9.8.1",
10
10
  "license": "SEE LICENSE IN LICENSE",
11
11
  "dependencies": {
12
12
  "@cap-js/asyncapi": "^1.0.0",
@@ -41,15 +41,15 @@
41
41
  }
42
42
  },
43
43
  "node_modules/@cap-js/db-service": {
44
- "version": "2.8.2",
45
- "integrity": "sha512-5BUWnoRX7LQBEWvEZmq0urEkxWPIIUnV9v2uFYop19W10jtmK6bxKqk+oUGD/7o6C9GNiFcZoLpja7SFohfKOg==",
44
+ "version": "2.9.0",
45
+ "integrity": "sha512-WCXhoqezaF6A5I2l0MNZeHKXXtHRNEq7Rp0R89/uccOHQIx0DuU0U9NuJJPV/1G5RGk2QKQ9VBo/KYn+MZuuNQ==",
46
46
  "devOptional": true,
47
47
  "license": "Apache-2.0",
48
48
  "dependencies": {
49
49
  "generic-pool": "^3.9.0"
50
50
  },
51
51
  "peerDependencies": {
52
- "@sap/cds": ">=9.4.5"
52
+ "@sap/cds": ">=9.8"
53
53
  }
54
54
  },
55
55
  "node_modules/@cap-js/openapi": {
@@ -64,33 +64,47 @@
64
64
  }
65
65
  },
66
66
  "node_modules/@cap-js/sqlite": {
67
- "version": "2.1.3",
68
- "integrity": "sha512-JkIAR8khPEW0jgw440JrtOzsj+TacZmACJsifGnCWpgrC17f2q8r15pzrCnvvCmkLXTqUW1kRg5/B3nLbaO86Q==",
67
+ "version": "2.2.0",
68
+ "integrity": "sha512-FPj+uVU/14vtGUl2P/Q8y7XhZbsLgrCav2O5PjHPXnupegjby4sMJkgVNxVHnkyKPFgO/W8uEsq9r5TU9VPx8w==",
69
69
  "license": "Apache-2.0",
70
70
  "optional": true,
71
71
  "dependencies": {
72
- "@cap-js/db-service": "^2.8.2",
72
+ "@cap-js/db-service": "^2.9.0",
73
73
  "better-sqlite3": "^12.0.0"
74
74
  },
75
75
  "peerDependencies": {
76
- "@sap/cds": ">=9"
76
+ "@sap/cds": ">=9.8",
77
+ "sql.js": "^1.13.0"
78
+ },
79
+ "peerDependenciesMeta": {
80
+ "sql.js": {
81
+ "optional": true
82
+ }
77
83
  }
78
84
  },
79
85
  "node_modules/@eslint/js": {
80
- "version": "9.39.2",
81
- "integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
86
+ "version": "10.0.1",
87
+ "integrity": "sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==",
82
88
  "license": "MIT",
83
89
  "peer": true,
84
90
  "engines": {
85
- "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
91
+ "node": "^20.19.0 || ^22.13.0 || >=24"
86
92
  },
87
93
  "funding": {
88
94
  "url": "https://eslint.org/donate"
95
+ },
96
+ "peerDependencies": {
97
+ "eslint": "^10.0.0"
98
+ },
99
+ "peerDependenciesMeta": {
100
+ "eslint": {
101
+ "optional": true
102
+ }
89
103
  }
90
104
  },
91
105
  "node_modules/@sap/cds": {
92
- "version": "9.7.1",
93
- "integrity": "sha512-DCMCB3FiQoWVeHQulSFbZMkmuoW0z6tJRP85Xv2Bd2Cl2J2I4+LQD1GKDiUXrlJXm0CtKsFQcrsxcQmUeO5uXw==",
106
+ "version": "9.8.2",
107
+ "integrity": "sha512-B85qUoUCVHN8gqHdD4nY+0LM1hEGGllEqWnMxsIBijBv3KXB4tOkf/krC8POieKZGMFRHylAcW1fAYVgbLqppw==",
94
108
  "license": "SEE LICENSE IN LICENSE",
95
109
  "dependencies": {
96
110
  "@sap/cds-compiler": "^6.4",
@@ -106,7 +120,7 @@
106
120
  "node": ">=20"
107
121
  },
108
122
  "peerDependencies": {
109
- "@eslint/js": "^9",
123
+ "@eslint/js": "^9 || ^10",
110
124
  "tar": "^7.5.6"
111
125
  },
112
126
  "peerDependenciesMeta": {
@@ -116,8 +130,8 @@
116
130
  }
117
131
  },
118
132
  "node_modules/@sap/cds-compiler": {
119
- "version": "6.7.3",
120
- "integrity": "sha512-MlKvr3b7meSD4UsMr/u5eXUS0q226MyHg/+x5xKOxxdqhh1yGGnJD0lj0USqo4S3rggFfCSgWypTAjD7VLZdUw==",
133
+ "version": "6.8.0",
134
+ "integrity": "sha512-yRoTZcH8DFiP4PcEuIHe42YAaNt51V736+6RRr+U4nbO91sz36L8be2djcE8n760t8IbqLxzZ/UkATiL0fjRmA==",
121
135
  "license": "SEE LICENSE IN LICENSE",
122
136
  "bin": {
123
137
  "cdsc": "bin/cdsc.js",
@@ -129,16 +143,16 @@
129
143
  }
130
144
  },
131
145
  "node_modules/@sap/cds-fiori": {
132
- "version": "2.2.0",
133
- "integrity": "sha512-NnvpmU40Eez5Q3SkyCCLRuBd1XUjk7N+pbXcIPIkKw4rwvqR2/FbjNveRzc8mcrLcQA3/5b/CXYsafDoozUhng==",
146
+ "version": "2.3.0",
147
+ "integrity": "sha512-6oWov+DSpFrSTgxXR0dZhak6aZ/IVRZvaHERMi0EgSTzIJdlvZlpw3Kf18ePMcTrRrtEXwD4RIjKt8pbs0g2Hg==",
134
148
  "license": "SEE LICENSE IN LICENSE",
135
149
  "peerDependencies": {
136
150
  "@sap/cds": ">=8"
137
151
  }
138
152
  },
139
153
  "node_modules/@sap/cds-mtxs": {
140
- "version": "3.7.1",
141
- "integrity": "sha512-yMsD6C4UAPozvm4TNUojAFYYC13au45hamr+S7cXT7K9ufYl7zzLGQ3Z/bE91D57z0IfryCXMsxk437P3cEJuA==",
154
+ "version": "3.8.0",
155
+ "integrity": "sha512-8P/CKQbdbKH/1ZmgrRWiReXFb9MjLf/TjEH/MrbiJEGWCIv/bTKL6nNb0BIcBa7HQhekVqapa/cwx241NEnAVQ==",
142
156
  "license": "SEE LICENSE IN LICENSE",
143
157
  "dependencies": {
144
158
  "@sap/hdi-deploy": "^5"
@@ -251,8 +265,8 @@
251
265
  "license": "MIT"
252
266
  },
253
267
  "node_modules/axios": {
254
- "version": "1.13.5",
255
- "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==",
268
+ "version": "1.13.6",
269
+ "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
256
270
  "license": "MIT",
257
271
  "dependencies": {
258
272
  "follow-redirects": "^1.15.11",
@@ -1203,8 +1217,8 @@
1203
1217
  "license": "MIT"
1204
1218
  },
1205
1219
  "node_modules/node-abi": {
1206
- "version": "3.87.0",
1207
- "integrity": "sha512-+CGM1L1CgmtheLcBuleyYOn7NWPVu0s0EJH2C4puxgEZb9h8QpR9G2dBfZJOAUhi7VQxuBPMd0hiISWcTyiYyQ==",
1220
+ "version": "3.88.0",
1221
+ "integrity": "sha512-At6b4UqIEVudaqPsXjmUO1r/N5BUr4yhDGs5PkBE8/oG5+TfLPhFechiskFsnT6Ql0VfUXbalUUCbfXxtj7K+w==",
1208
1222
  "license": "MIT",
1209
1223
  "optional": true,
1210
1224
  "dependencies": {
@@ -1283,6 +1297,7 @@
1283
1297
  "node_modules/prebuild-install": {
1284
1298
  "version": "7.1.3",
1285
1299
  "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==",
1300
+ "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.",
1286
1301
  "license": "MIT",
1287
1302
  "optional": true,
1288
1303
  "dependencies": {
@@ -1324,8 +1339,8 @@
1324
1339
  "license": "MIT"
1325
1340
  },
1326
1341
  "node_modules/pump": {
1327
- "version": "3.0.3",
1328
- "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==",
1342
+ "version": "3.0.4",
1343
+ "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
1329
1344
  "license": "MIT",
1330
1345
  "optional": true,
1331
1346
  "dependencies": {
@@ -1334,8 +1349,8 @@
1334
1349
  }
1335
1350
  },
1336
1351
  "node_modules/qs": {
1337
- "version": "6.14.2",
1338
- "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==",
1352
+ "version": "6.15.0",
1353
+ "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==",
1339
1354
  "license": "BSD-3-Clause",
1340
1355
  "dependencies": {
1341
1356
  "side-channel": "^1.1.0"
@@ -1439,8 +1454,8 @@
1439
1454
  "license": "MIT"
1440
1455
  },
1441
1456
  "node_modules/sax": {
1442
- "version": "1.4.4",
1443
- "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==",
1457
+ "version": "1.5.0",
1458
+ "integrity": "sha512-21IYA3Q5cQf089Z6tgaUTr7lDAyzoTPx5HRtbhsME8Udispad8dC/+sziTNugOEx54ilvatQ9YCzl4KQLPcRHA==",
1444
1459
  "license": "BlueOak-1.0.0",
1445
1460
  "engines": {
1446
1461
  "node": ">=11.0.0"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-dk",
3
- "version": "9.7.2",
3
+ "version": "9.8.1",
4
4
  "description": "Command line client and development toolkit for the SAP Cloud Application Programming Model",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "keywords": [
@@ -1,377 +0,0 @@
1
- // @ts-check
2
- const fs = require('node:fs')
3
- const path = require('node:path')
4
- const { inspect } = require('node:util')
5
- // @ts-expect-error - _log not declared in cds-types
6
- const cds = require('../cds'), { _log: log } = cds
7
- const { sortMessagesSeverityAware, deduplicateMessages, CompilationError } = cds.compiler
8
- const { relativePaths, BuildError, BuildMessage, resolveRequiredSapModels } = require('./util')
9
- const { SEVERITIES, SEVERITY_ERROR, LOG_LEVELS } = require('./constants')
10
- const BuildTaskFactory = require('./buildTaskFactory')
11
- const InternalBuildPlugin = require('./provider/internalBuildPlugin')
12
- const COMPILATION_ERROR = 'CompilationError'
13
- const COMPILE_MESSAGE = 'CompileMessage'
14
- const DEBUG = cds.debug('cli|build')
15
- const LOG_LIMIT = 30
16
-
17
- class BuildTaskEngine {
18
-
19
- /**
20
- * @param {import('../build').BuildOptions} options - command options
21
- */
22
- constructor(options) {
23
- this._taskFactory = new BuildTaskFactory(options)
24
- }
25
- get taskFactory() {
26
- return this._taskFactory
27
- }
28
- get options() {
29
- return this.taskFactory.options
30
- }
31
-
32
- async processTasks(tasks) {
33
- const startTime = Date.now()
34
-
35
- tasks ??= await this.taskFactory.getTasks()
36
- console.log(`building project with`, inspect({
37
- versions: { cds: cds.version, compiler: cds.compiler.version(), dk: require('../../package.json').version },
38
- target: cds.env.build.target,
39
- tasks: tasks.map(({ _uses, ...task }) => task),
40
- ...(!this.options.clean && { clean: this.options.clean }),
41
- }, { depth: 11, colors: cds.utils.colors.enabled, compact: 3, breakLength: 250 }))
42
-
43
- // validate required @sap namespace models - log only
44
- const unresolved = BuildTaskEngine._resolveRequiredSapServices(tasks)
45
- if (unresolved.length > 0) {
46
- throw new BuildError(`Required CDS models [${unresolved.join(', ')}] cannot be resolved. Run the 'npm install' command to install up-to-date versions of the missing packages.`)
47
- }
48
-
49
- // create build plugins
50
- const plugins = []
51
- tasks.forEach((task) => {
52
- if (task) {
53
- const plugin = this._createPlugin(task)
54
- plugins.push(plugin)
55
- }
56
- })
57
-
58
- try {
59
- await this._executePrepare(plugins)
60
- await this._executeCleanBuildTasks(plugins)
61
-
62
- // throwing Exception in case of compilation errors
63
- const buildResult = await this._executeBuildTasks(plugins)
64
-
65
- await this._writeGenerationLog(plugins)
66
- this._logOutput(plugins)
67
- this._logMessages(BuildTaskEngine._getMessages(plugins))
68
- this._logTimer(startTime, Date.now())
69
-
70
- return buildResult
71
- } catch (error) {
72
- this._logOutput(plugins)
73
- throw error
74
- }
75
- }
76
-
77
- /**
78
- * Plugin#prepare has been deprecated and was never part of the public API.
79
- * Currently only used by internal FioriBuildPlugin.
80
- * @deprecated
81
- * @private
82
- * @param {*} plugins
83
- * @returns
84
- */
85
- async _executePrepare(plugins) {
86
- const pluginGroups = new Map()
87
-
88
- // group plugins by type
89
- plugins.forEach(plugin => {
90
- pluginGroups.has(plugin.task.for) ? pluginGroups.get(plugin.task.for).push(plugin) : pluginGroups.set(plugin.task.for, [plugin])
91
- })
92
-
93
- const promises = []
94
- for (let pluginGroup of pluginGroups.values()) {
95
- promises.push(this._doPrepare(pluginGroup))
96
- }
97
- return Promise.all(promises)
98
- }
99
-
100
- /**
101
- * @deprecated
102
- * @private
103
- * @param {*} pluginGroup
104
- */
105
- async _doPrepare(pluginGroup) {
106
- for (let plugin of pluginGroup) {
107
- // prepare has been deprecated
108
- if (plugin instanceof InternalBuildPlugin) {
109
- DEBUG?.(`preparing, plugin [${plugin.constructor.name}], src [${relativePaths(cds.root, plugin.task.src)}]`)
110
- const result = await plugin.prepare()
111
- if (result === false) {
112
- break
113
- }
114
- }
115
- }
116
- }
117
-
118
- /** @private */
119
- async _executeCleanBuildTasks(plugins) {
120
- if (this.options.clean) {
121
- // clean entire build staging folder once
122
- if (cds.env.build.target !== '.') {
123
- const target = path.resolve(cds.root, cds.env.build.target)
124
- DEBUG?.(`cleaning staging folder ${target}`)
125
- await fs.promises.rm(target, { force: true, recursive: true })
126
- }
127
-
128
- const results = await Promise.allSettled(plugins.map((plugin) => {
129
- DEBUG?.(`cleaning, plugin [${plugin.constructor.name}], src [${relativePaths(cds.root, plugin.task.src)}]`)
130
- return plugin.clean()
131
- }))
132
- // check for errors and throw exception
133
- this._resolveHandlerResponse(results)
134
- }
135
- }
136
-
137
- /** @private */
138
- async _executeBuildTasks(plugins) {
139
- // sort plugins based on priority in
140
- plugins = plugins.sort((a, b) => {
141
- return a.priority === b.priority ? 0 : a.priority > b.priority ? -1 : 1
142
- })
143
- // group plugins with same priority in order to execute in parallel
144
- const buildPipeline = plugins.reduce((acc, plugin) => {
145
- if (acc.length === 0) {
146
- acc.push([plugin])
147
- } else {
148
- const currGroup = acc[acc.length - 1]
149
- if (currGroup[0].priority === plugin.priority) {
150
- currGroup.push(plugin)
151
- } else {
152
- acc.push([plugin])
153
- }
154
- }
155
- return acc
156
- }, [])
157
-
158
- const results = await this._executePipeline(buildPipeline)
159
-
160
- // check for errors and throw exception - return results otherwise including any compiler and build status messages
161
- return this._resolveHandlerResponse(results, BuildTaskEngine._getMessages(plugins))
162
- }
163
-
164
- /** @private */
165
- async _executePipeline(pipeline) {
166
- let allResults = []
167
- for (const group of pipeline) {
168
- const results = await Promise.allSettled(group.map((plugin) => {
169
- DEBUG?.(`building, plugin [${plugin.constructor.name}], src [${relativePaths(cds.root, plugin.task.src)}]`)
170
- return plugin.build()
171
- .then(pluginResult => {
172
- return Promise.resolve({
173
- task: plugin.task,
174
- result: pluginResult,
175
- messages: this._sortMessagesUnique(plugin.messages)
176
- })
177
- })
178
- }))
179
- allResults = allResults.concat(results)
180
- }
181
- return allResults
182
- }
183
-
184
- /** @private */
185
- _resolveHandlerResponse(results, pluginMessages = []) {
186
- /** @type {(BuildError | Error)[]}*/
187
- const errors = []
188
- const resolvedResults = results.reduce((acc, r) => {
189
- if (r.status === 'fulfilled') {
190
- acc.push(r.value)
191
- }
192
- if (r.status === 'rejected' && r.reason) {
193
- errors.push(r.reason)
194
- }
195
- return acc
196
- }, [])
197
-
198
- if (errors.length > 0) {
199
- const error = errors.find(e => e.constructor.name !== COMPILATION_ERROR)
200
- if (error) {
201
- // throw original BuildError including existing BuildMessages
202
- if (!(error instanceof BuildError)) {
203
- throw error
204
- }
205
- error.messages = error.messages?.map(m => typeof m === 'string' ? new BuildMessage(m, SEVERITY_ERROR) : m)
206
- error.messages = this._sortMessagesUnique(pluginMessages.filter(m => m instanceof BuildMessage), error.messages)
207
- throw error
208
- }
209
-
210
- // propagate existing CompilationErrors
211
- // merge all existing compilation messages into a single CompilationError
212
- // compiler warning and info messages are returned as plugin messages
213
- const compileErrors = errors.filter(e => e.constructor.name === COMPILATION_ERROR)
214
- const compileMessages = pluginMessages.filter(message => message.constructor.name === COMPILE_MESSAGE)
215
- if (compileErrors.length) {
216
- throw new CompilationError(this._sortMessagesUnique(BuildTaskEngine._getErrorMessages(compileErrors), compileMessages))
217
- }
218
- }
219
- return resolvedResults
220
- }
221
-
222
- /** @private */
223
- _createPlugin(task) {
224
- const plugin = this.taskFactory.createPlugin(task)
225
- plugin.init()
226
-
227
- if (!(plugin instanceof InternalBuildPlugin) && plugin.priority >= 0 && plugin.priority <= 512) {
228
- throw new Error(
229
- `Invalid priority value for ${plugin.constructor.name}.
230
- The valid priority value range for custom plugins is -1024..-1 and 512..1024.
231
- Range 0..512 is blocked for internal plugins.
232
- The higher the value the earlier the plugin is run.`
233
- )
234
- }
235
-
236
- this._logTaskHandler(plugin)
237
- return plugin
238
- }
239
-
240
- /** @private */
241
- _logOutput(plugins) {
242
- // log all generated files
243
- const files = BuildTaskEngine._getOutput(plugins)
244
- if (files.length > 0) {
245
- const term = require('../util/term')
246
- if (!process.env.DEBUG && files.length > LOG_LIMIT) {
247
- const length = files.length
248
- files.length = LOG_LIMIT
249
- files.push(`... ${length - files.length} more. Run with DEBUG=build to show all files.`)
250
- }
251
- console.log(`done > wrote output to:\n ${term.dim(files.join("\n "))}\n`)
252
- }
253
- }
254
-
255
- /** @private */
256
- async _writeGenerationLog(plugins) {
257
- const outputFile = cds.env.build.outputfile || process.env.GENERATION_LOG
258
- if (outputFile) {
259
- const files = BuildTaskEngine._getOutput(plugins)
260
- console.log(`writing generation log to [${outputFile}]\n`)
261
- try {
262
- await fs.promises.mkdir(path.dirname(outputFile), { recursive: true })
263
- await fs.promises.writeFile(outputFile, files.join('\n'))
264
- } catch (error) {
265
- console.error(`failed to write generation log`)
266
- console.error(error.stack || error)
267
- }
268
- }
269
- }
270
-
271
- /** @private */
272
- static _getOutput(plugins) {
273
- const files = plugins.reduce((acc, plugin) => acc.concat(plugin.files), []).sort()
274
- return files.map(file => {
275
- if (path.isAbsolute(cds.env.build.target)) {
276
- return file
277
- }
278
- return path.relative(cds.root, file)
279
- })
280
- }
281
-
282
- /** @private */
283
- _logTimer(start, end) {
284
- console.log(`build completed in ${end - start} ms`)
285
- }
286
-
287
- /** @private */
288
- _logTaskHandler(plugin) {
289
- DEBUG?.(`plugin ${plugin.constructor.name}`)
290
- DEBUG?.(`details src [${relativePaths(cds.root, plugin.task.src)}], dest [${relativePaths(cds.root, plugin.task.dest)}], options [${JSON.stringify(plugin.task.options)}]`)
291
- }
292
-
293
- /** @private */
294
- _logMessages(messages) {
295
- if (messages.length > 0) {
296
- const options = {
297
- log: console.log,
298
- "log-level": this._getLogLevel() // ensures that for tests the correct cds.env is used
299
- }
300
- deduplicateMessages(messages)
301
- sortMessagesSeverityAware(messages)
302
- log(messages, options)
303
- }
304
- }
305
-
306
- /** @private */
307
- static _resolveRequiredSapServices(tasks) {
308
- const taskModelPaths = tasks.reduce((acc, task) => {
309
- const model = task.options?.model
310
- if (model) {
311
- if (Array.isArray(model)) {
312
- model.forEach(m => acc.add(m))
313
- } else {
314
- acc.add(model)
315
- }
316
- }
317
- return acc
318
- }, new Set())
319
-
320
- return resolveRequiredSapModels([...taskModelPaths])
321
- }
322
-
323
- /**
324
- * Returns a sorted and flattened list of all messages extracted from the given errors.
325
- * @private
326
- * @param {(string | BuildError)[]} errors
327
- */
328
- static _getErrorMessages(errors) {
329
- let messages = []
330
- // flatten all compile messages in order to filter duplicates and sort later on
331
- errors.forEach(error => {
332
- if (typeof error !== 'string' && Array.isArray(error.errors) && error.errors.length > 0) {
333
- messages = messages.concat(this._getErrorMessages(error.errors))
334
- } else {
335
- messages.push(error)
336
- }
337
- })
338
- return messages
339
- }
340
-
341
- /**
342
- * Returns compiler messages and validation messages issued by plugins.
343
- * @param {Array} plugins
344
- */
345
- static _getMessages(plugins) {
346
- return plugins.reduce((acc, plugin) => acc.concat(plugin.messages), [])
347
- }
348
-
349
- /**
350
- * Sort and filter the given errors of type CompileMessage or BuildMessage according to their severity and location,
351
- * but leave any other errors untouched as part of the result array.<br>
352
- * The log level ('command line' or 'cds.env' option) is used to filter the given messages.
353
- * @private
354
- * @param {...{[key:string]: any, severity?: import('./constants').Severity}} messages
355
- */
356
- _sortMessagesUnique(...messages) {
357
- const logLevelIdx = LOG_LEVELS.indexOf(this._getLogLevel())
358
- // flatten
359
- messages = messages.reduce((acc, m) => acc.concat(m), [])
360
- // filter according to log-level
361
- const filteredMessages = messages.filter(message => message && (!message.severity || logLevelIdx >= SEVERITIES.indexOf(message.severity)))
362
- // remove duplicates
363
- // @ts-expect-error - formally expects CompileMessage, but actually, an .severity is the only expected property
364
- deduplicateMessages(filteredMessages)
365
- // sort
366
- // @ts-expect-error - see above
367
- return sortMessagesSeverityAware(filteredMessages)
368
- }
369
-
370
- /**
371
- * Return user defined log level or default value 'warn'
372
- */
373
- _getLogLevel() {
374
- return this.options["log-level"] || cds.env["log-level"]
375
- }
376
- }
377
- module.exports = BuildTaskEngine