@sap/cds-dk 9.6.0 → 9.7.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.
- package/CHANGELOG.md +53 -0
- package/bin/add.js +5 -2
- package/bin/cds.js +11 -26
- package/bin/compile/index.js +3 -2
- package/bin/data-products/import.js +3 -0
- package/bin/debug.js +76 -16
- package/bin/env.js +2 -1
- package/bin/export.js +18 -13
- package/bin/help/export.md +2 -1
- package/bin/import.js +21 -18
- package/bin/init.js +8 -1
- package/bin/minify.js +11 -12
- package/bin/mock.js +17 -9
- package/bin/repl.js +2 -2
- package/bin/up.js +34 -4
- package/bin/version.js +202 -131
- package/lib/build/buildTaskEngine.js +4 -0
- package/lib/build/buildTaskFactory.js +5 -35
- package/lib/build/index.js +10 -10
- package/lib/build/plugin.js +6 -3
- package/lib/build/plugins/helm/files/subcharts/content-deployment/Chart.yaml +3 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/_helpers.tpl +1 -1
- package/lib/build/plugins/helm/files/subcharts/content-deployment/templates/job.yaml +8 -0
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.schema.json +18 -0
- package/lib/build/plugins/helm/files/subcharts/content-deployment/values.yaml +11 -1
- package/lib/build/plugins.js +8 -16
- package/lib/build/provider/hana/index.js +16 -19
- package/lib/build/provider/internalBuildPlugin.js +28 -4
- package/lib/build/provider/internalBuildTaskProvider.js +26 -88
- package/lib/build/provider/mtx/index.js +0 -8
- package/lib/build/provider/mtx-sidecar/index.js +88 -80
- package/lib/build/provider/nodejs/index.js +3 -8
- package/lib/build/util.js +52 -87
- package/lib/deploy/to-hana/hana.js +117 -109
- package/lib/env/schemas/cds-rc.js +0 -4
- package/lib/import/odata/v4parser.js +80 -56
- package/lib/init/constants.js +5 -2
- package/lib/init/index.js +44 -41
- package/lib/init/merge.js +7 -2
- package/lib/init/projectReader.js +4 -10
- package/lib/init/template/ams/index.js +1 -4
- package/lib/init/template/attachments/files/package.json.hbs +1 -1
- package/lib/init/template/data/index.js +1 -1
- package/lib/init/template/extension/index.js +4 -4
- package/lib/init/template/hana/files/package.json.hbs +3 -3
- package/lib/init/template/handler/index.js +1 -1
- package/lib/init/template/helm/index.js +3 -3
- package/lib/init/template/helm-unified-runtime/index.js +5 -1
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +1 -1
- package/lib/init/template/ias/files/mta.yaml.hbs +3 -3
- package/lib/init/template/initial/files/.vscode/tasks.json +10 -0
- package/lib/init/template/{nodejs/files/README.md → initial/files/readme.md} +2 -3
- package/lib/init/template/initial/index.js +15 -0
- package/lib/init/template/java/index.js +4 -11
- package/lib/init/template/kyma/index.js +21 -20
- package/lib/init/template/lint/index.js +3 -1
- package/lib/init/template/mta/index.js +0 -5
- package/lib/init/template/multitenancy/files/package.sidecar.json.hbs +1 -2
- package/lib/init/template/multitenancy/files/values.yaml.hbs +30 -0
- package/lib/init/template/nodejs/files/.vscode/tasks.json +1 -14
- package/lib/init/template/nodejs/files/package.json.hbs +2 -4
- package/lib/init/template/nodejs/index.js +8 -12
- package/lib/init/template/sample/files/app/common.cds +1 -1
- package/lib/init/template/sample/index.js +5 -6
- package/lib/init/template/sqlite/files/package.json.hbs +7 -1
- package/lib/init/template/test/index.js +1 -1
- package/lib/init/template/tiny-sample/files/nodejs/db/data/CatalogService.Books.csv +6 -0
- package/lib/init/template/tiny-sample/files/nodejs/srv/cat-service.cds +5 -0
- package/lib/init/template/tiny-sample/index.js +2 -2
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +6 -0
- package/lib/init/template/workzone-standard/index.js +13 -3
- package/lib/init/validate.js +11 -6
- package/lib/util/checksum.js +2 -2
- package/lib/util/fs.js +109 -53
- package/lib/util/glob.js +2 -1
- package/lib/util/term.js +4 -8
- package/lib/util/write.js +2 -4
- package/lib/watch/livereload-server.js +4 -3
- package/lib/watch/node-watch.js +5 -8
- package/lib/watch/watched.js +1 -1
- package/lib/watch/watcher.js +136 -0
- package/npm-shrinkwrap.json +245 -284
- package/package.json +2 -3
- package/lib/init/template/nodejs/files/.vscode/settings.json +0 -11
- package/lib/init/template/tiny-sample/files/nodejs/db/data/my.bookshop-Books.csv +0 -3
- package/lib/init/template/tiny-sample/files/nodejs/db/schema.cds +0 -7
- package/lib/init/template/tiny-sample/files/nodejs/srv/cat-service.cds.hbs +0 -5
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
1
|
const cds = require('../../../cds')
|
|
3
|
-
const
|
|
4
|
-
const {
|
|
5
|
-
const NodejsBuildPlugin = require('../nodejs')
|
|
2
|
+
const { exists, path } = cds.utils
|
|
3
|
+
const { SEVERITY_ERROR: ERROR, FOLDER_GEN, MTX_SIDECAR_DB_VALIDATION, CONTENT_EDMX, FLAVOR_LOCALIZED_EDMX } = require('../../constants')
|
|
6
4
|
const ResourcesTarBuilder = require('../mtx/resourcesTarBuilder')
|
|
7
|
-
const { ERROR } = NodejsBuildPlugin
|
|
8
5
|
const { relativePaths, BuildError, resolveRequiredSapModels, getI18nDefaultFolder } = require('../../util')
|
|
9
6
|
const DEBUG = cds.debug('cli|build')
|
|
10
7
|
|
|
11
8
|
const DEFAULT_MAIN_FOLDER = "_main"
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
const [major, minor] = cds.version.split('.').map(Number)
|
|
11
|
+
const COMPAT = major === 9 && minor < 7 // cds10: remove
|
|
12
|
+
|
|
13
|
+
module.exports = class extends require('../nodejs') {
|
|
14
|
+
|
|
14
15
|
get priority() {
|
|
15
|
-
// must run after 'hana' build task
|
|
16
|
-
return super.priority - 10
|
|
16
|
+
return super.priority - 10 // must run after 'hana' build task
|
|
17
17
|
}
|
|
18
18
|
init() {
|
|
19
19
|
super.init()
|
|
@@ -23,43 +23,51 @@ class MtxSidecarBuildPlugin extends NodejsBuildPlugin {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Builds the
|
|
27
|
-
* -
|
|
28
|
-
* -
|
|
26
|
+
* Builds the MTX sidecar app consisting of:
|
|
27
|
+
* - Node.js app model defined by the required sidecar services
|
|
28
|
+
* - Main app model defined by the build task's model options, including feature models and resources TAR
|
|
29
29
|
*
|
|
30
30
|
* build.target=".": 'dest' -> 'model-provider/gen'
|
|
31
31
|
* build.target="gen": 'dest' -> 'gen/model-provider'
|
|
32
32
|
*/
|
|
33
33
|
async build() {
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
// REVISIT: required to load plugins from mtx/sidecar, not the main app for the sidecar CSN
|
|
35
|
+
const oldRoot = cds.root
|
|
36
|
+
cds.root = this.task.src
|
|
37
|
+
const sidecarEnv = cds.env.for('cds', this.task.src)
|
|
38
|
+
cds.root = oldRoot
|
|
39
|
+
|
|
40
|
+
const [rMain, rNode] = await Promise.allSettled([
|
|
41
|
+
this._buildMainApp(sidecarEnv),
|
|
42
|
+
this._buildSidecarApp(sidecarEnv)
|
|
43
|
+
])
|
|
44
|
+
if (rMain.status === 'rejected') throw rMain.reason
|
|
45
|
+
if (rNode.status === 'rejected') throw rNode.reason
|
|
40
46
|
}
|
|
41
47
|
|
|
42
48
|
/**
|
|
43
|
-
* Builds the
|
|
44
|
-
* @param {
|
|
49
|
+
* Builds the MTX sidecar Node.js app parts.
|
|
50
|
+
* @param {import('../../../cds').env} sidecarEnv `cds.env` based on the MTX sidecar directory.
|
|
45
51
|
*/
|
|
46
|
-
async
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
async _buildSidecarApp(sidecarEnv) {
|
|
53
|
+
const { dest, src } = this.task
|
|
54
|
+
const model = COMPAT ? this._compatCompileSidecarSync(sidecarEnv) : this._compileSidecarSync(sidecarEnv)
|
|
55
|
+
const srv = path.join(dest, sidecarEnv.folders.srv)
|
|
56
|
+
const promises = [
|
|
57
|
+
this.compileToJson(model, path.join(srv, 'csn.json')),
|
|
58
|
+
this.collectLanguageBundles(model, path.join(srv, getI18nDefaultFolder())),
|
|
59
|
+
this.copySrvContent(src, dest, dest)
|
|
60
|
+
]
|
|
54
61
|
// copy .npmrc from project root, if it exists and no .npmrc exists in the sidecar
|
|
55
|
-
if (!
|
|
56
|
-
|
|
62
|
+
if (!exists(path.join(dest, '.npmrc')) && exists('.npmrc')) {
|
|
63
|
+
promises.push(this.copy(path.join(cds.root, '.npmrc')).to(path.join(dest, '.npmrc')))
|
|
57
64
|
}
|
|
65
|
+
await Promise.all(promises)
|
|
58
66
|
}
|
|
59
67
|
|
|
60
68
|
/**
|
|
61
69
|
* Builds the main app parts containing base model CSN with feature CSNs and resources TAR.
|
|
62
|
-
* @param {
|
|
70
|
+
* @param {import('../../../cds').env} sidecarEnv `cds.env` based on the MTX sidecar directory.
|
|
63
71
|
*/
|
|
64
72
|
async _buildMainApp(sidecarEnv) {
|
|
65
73
|
let main = sidecarEnv.requires['cds.xt.ModelProviderService']?.root
|
|
@@ -78,85 +86,85 @@ class MtxSidecarBuildPlugin extends NodejsBuildPlugin {
|
|
|
78
86
|
main = DEFAULT_MAIN_FOLDER
|
|
79
87
|
}
|
|
80
88
|
|
|
81
|
-
const
|
|
82
|
-
const destMain = path.join(destRoot, main)
|
|
89
|
+
const destMain = path.join(this.task.dest, main)
|
|
83
90
|
const destMainSrv = path.join(destMain, cds.env.folders.srv)
|
|
84
91
|
const model = await this.model()
|
|
85
92
|
if (!model) {
|
|
86
93
|
return
|
|
87
94
|
}
|
|
95
|
+
|
|
88
96
|
const { dictionary, sources } = await this.compileAll(model, destMainSrv, destMain)
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
|
|
98
|
+
const promises = []
|
|
99
|
+
promises.push(this.collectAllLanguageBundles(dictionary, sources, destMainSrv, destMain))
|
|
100
|
+
// promises.push(this.collectAllLanguageBundles(dictionary, sources, destMain, destMain))
|
|
91
101
|
|
|
92
102
|
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
93
|
-
//inferred model expected by cds.compile.to.edmx()
|
|
103
|
+
// inferred model expected by cds.compile.to.edmx()
|
|
94
104
|
const compileOptions = { [FLAVOR_LOCALIZED_EDMX]: this.hasBuildOption(FLAVOR_LOCALIZED_EDMX, true) } // disabled by default
|
|
95
105
|
const baseModel = cds.compiler.compileSources({ 'base.json': dictionary.base }, { messages: this.messages })
|
|
96
|
-
|
|
106
|
+
promises.push(this.compileToEdmx(baseModel, path.join(destMainSrv, 'odata', cds.env.odata.version), compileOptions))
|
|
97
107
|
}
|
|
98
108
|
|
|
99
109
|
// create resources TAR
|
|
100
110
|
// resources are determined based on available database build task, SQLite as fallback
|
|
101
|
-
|
|
111
|
+
promises.push(new ResourcesTarBuilder(this).createTar(destMain, model))
|
|
102
112
|
|
|
103
113
|
// copy package.json and .cdsrc.json from project root
|
|
104
|
-
|
|
114
|
+
const packageJson = path.join(cds.root, 'package.json')
|
|
115
|
+
const cdsrcJson = path.join(cds.root, '.cdsrc.json')
|
|
116
|
+
if (exists('package.json')) {
|
|
117
|
+
promises.push(this.copy(packageJson).to(path.join(destMain, 'package.json')))
|
|
118
|
+
}
|
|
119
|
+
if (exists('.cdsrc.json')) {
|
|
120
|
+
promises.push(this.copy(cdsrcJson).to(path.join(destMain, '.cdsrc.json')))
|
|
121
|
+
}
|
|
122
|
+
return Promise.all(promises)
|
|
105
123
|
}
|
|
106
124
|
|
|
107
125
|
/**
|
|
108
|
-
* Synchronous compilation using the sidecar context.
|
|
109
|
-
* @param {
|
|
110
|
-
* @returns the compiled
|
|
126
|
+
* Synchronous compilation using the MTX sidecar context.
|
|
127
|
+
* @param {import('../../../cds').env} env `cds.env` based on the MTX sidecar directory.
|
|
128
|
+
* @returns the compiled MTX sidecar CSN
|
|
111
129
|
*/
|
|
112
|
-
|
|
130
|
+
_compileSidecarSync(env) {
|
|
131
|
+
const options = { env, root: this.task.src }
|
|
132
|
+
const modelPaths = COMPAT ? cds.resolve('*', false) : cds.resolve('*', { ...options, dry: true })
|
|
133
|
+
const modelFilePaths = COMPAT ? cds.resolve(modelPaths) : cds.resolve(modelPaths, options)
|
|
134
|
+
if (!modelFilePaths || modelFilePaths.length === 0) {
|
|
135
|
+
throw new BuildError("No CDS models found in MTX sidecar. Run the 'npm install' command to install up-to-date versions of the required packages.")
|
|
136
|
+
}
|
|
137
|
+
DEBUG?.(`sidecar model: ${relativePaths(cds.root, modelFilePaths).join(", ")}`)
|
|
138
|
+
|
|
139
|
+
// check whether all models belonging to the @sap namespace can be resolved
|
|
140
|
+
const unresolved = resolveRequiredSapModels(modelPaths)
|
|
141
|
+
if (unresolved.length > 0) {
|
|
142
|
+
// log error, but don't fail
|
|
143
|
+
this.pushMessage(`CDS models [${unresolved.join(', ')}] required by MTX sidecar cannot be resolved. Run the 'npm install' command to install up-to-date versions of the required packages.`, ERROR)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// using synchronous compilation as cds.root and cds.env have been switched to mtx/sidecar
|
|
147
|
+
// using different messages array ensures that cds compilation doesn't fail because of
|
|
148
|
+
// existing compilation error messages that have been downgraded to warnings
|
|
149
|
+
// see cap/issues/issues/16401#issuecomment-7205397
|
|
150
|
+
const messages = []
|
|
151
|
+
const model = cds.load(modelFilePaths, { sync: true, messages })
|
|
152
|
+
messages.forEach(msg => this.messages.push(msg))
|
|
153
|
+
return model
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// cds10: remove
|
|
157
|
+
_compatCompileSidecarSync(sidecarEnv) {
|
|
113
158
|
const env = cds.env
|
|
114
159
|
const root = cds.root
|
|
115
160
|
try {
|
|
116
161
|
cds.root = this.task.src
|
|
117
162
|
cds.env = sidecarEnv
|
|
118
|
-
|
|
119
|
-
const modelFilePaths = cds.resolve(modelPaths)
|
|
120
|
-
|
|
121
|
-
if (!modelFilePaths || modelFilePaths.length === 0) {
|
|
122
|
-
throw new BuildError("No CDS models found in MTX sidecar. Run the 'npm install' command to install up-to-date versions of the required packages.")
|
|
123
|
-
}
|
|
124
|
-
DEBUG?.(`sidecar model: ${relativePaths(cds.root, modelFilePaths).join(", ")}`)
|
|
125
|
-
|
|
126
|
-
// check whether all models belonging to the @sap namespace can be resolved
|
|
127
|
-
const unresolved = resolveRequiredSapModels(modelPaths)
|
|
128
|
-
if (unresolved.length > 0) {
|
|
129
|
-
// log error, but don't fail
|
|
130
|
-
this.pushMessage(`CDS models [${unresolved.join(', ')}] required by MTX sidecar cannot be resolved. Run the 'npm install' command to install up-to-date versions of the required packages.`, ERROR)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// using synchronous compilation as cds.root and cds.env have been switched to mtx/sidecar
|
|
134
|
-
// using different messages array ensures that cds compilation doesn't fail because of
|
|
135
|
-
// existing compilation error messages that have been downgraded to warnings
|
|
136
|
-
// see cap/issues/issues/16401#issuecomment-7205397
|
|
137
|
-
const messages = []
|
|
138
|
-
const model = cds.load(modelFilePaths, { sync: true, messages })
|
|
139
|
-
messages.forEach(msg => this.messages.push(msg))
|
|
140
|
-
|
|
141
|
-
return model
|
|
163
|
+
return this._compileSidecarSync(sidecarEnv)
|
|
142
164
|
} finally {
|
|
143
165
|
// restore project scope
|
|
144
166
|
cds.root = root
|
|
145
167
|
cds.env = env
|
|
146
168
|
}
|
|
147
169
|
}
|
|
148
|
-
|
|
149
|
-
async _copyMainConfigFiles(src, dest) {
|
|
150
|
-
const packageJson = path.join(src, 'package.json')
|
|
151
|
-
const cdsrcJson = path.join(src, '.cdsrc.json')
|
|
152
|
-
const promises = []
|
|
153
|
-
if (fs.existsSync(packageJson)) {
|
|
154
|
-
promises.push(this.copy(packageJson).to(path.join(dest, 'package.json')))
|
|
155
|
-
}
|
|
156
|
-
if (fs.existsSync(cdsrcJson)) {
|
|
157
|
-
promises.push(this.copy(cdsrcJson).to(path.join(dest, '.cdsrc.json')))
|
|
158
|
-
}
|
|
159
|
-
return promises
|
|
160
|
-
}
|
|
161
170
|
}
|
|
162
|
-
module.exports = MtxSidecarBuildPlugin
|
|
@@ -23,9 +23,6 @@ const arrayify = x => Array.isArray(x) ? x : [x]
|
|
|
23
23
|
class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
24
24
|
init() {
|
|
25
25
|
super.init()
|
|
26
|
-
if (this.task.options.compileDest) {
|
|
27
|
-
throw new BuildError("Option not supported - compileDest")
|
|
28
|
-
}
|
|
29
26
|
// fallback if src has been defined as '.'
|
|
30
27
|
this.destSrv = this.isStagingBuild() ? path.resolve(this.task.dest, cds.env.folders.srv) : path.join(this.task.dest, FOLDER_GEN)
|
|
31
28
|
}
|
|
@@ -53,8 +50,8 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
53
50
|
if (model) {
|
|
54
51
|
const { dictionary, sources } = await this.compileAll(model, destSrv, destRoot)
|
|
55
52
|
// collect and write language bundles into single i18n.json file
|
|
56
|
-
await this.collectAllLanguageBundles(dictionary, sources, destRoot, destRoot)
|
|
57
|
-
|
|
53
|
+
// await this.collectAllLanguageBundles(dictionary, sources, destRoot, destRoot)
|
|
54
|
+
await this.collectAllLanguageBundles(dictionary, sources, destSrv, destRoot)
|
|
58
55
|
|
|
59
56
|
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
60
57
|
const compileOptions = { [FLAVOR_LOCALIZED_EDMX]: this.hasBuildOption(FLAVOR_LOCALIZED_EDMX, true) }
|
|
@@ -159,7 +156,7 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
159
156
|
|
|
160
157
|
async _copyNativeContent(srcRoot, srcSrv, destRoot, destSrv) {
|
|
161
158
|
// project/srv/** -> 'gen/srv/srv/**'
|
|
162
|
-
const filesFilter = await this.copySrvContent(srcSrv, destRoot,
|
|
159
|
+
const filesFilter = await this.copySrvContent(srcSrv, destRoot, destSrv)
|
|
163
160
|
|
|
164
161
|
// project/* -> 'gen/srv/*'
|
|
165
162
|
await this.copyProjectRootContent(srcRoot, destRoot, (entry) => !filesFilter.includes(path.basename(entry)))
|
|
@@ -300,8 +297,6 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
300
297
|
static async _execNpmPack(dest, wsRoot, workspaces) {
|
|
301
298
|
const args = ['pack', '-ws', '--json', `--pack-destination=${dest}`]
|
|
302
299
|
workspaces.forEach(w => args.push(`-w=${w}`))
|
|
303
|
-
|
|
304
|
-
DEBUG?.(`execute command: npm ${args.join(', ')}`)
|
|
305
300
|
const result = await cmd.spawnCommand('npm', args, { cwd: wsRoot }, true, !!LOG._debug)
|
|
306
301
|
DEBUG?.(result)
|
|
307
302
|
return JSON.parse(result)
|
package/lib/build/util.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
const cp = require('node:child_process')
|
|
2
|
+
const cp = require('node:child_process')
|
|
3
3
|
const fs = require('node:fs')
|
|
4
4
|
const path = require('node:path')
|
|
5
5
|
|
|
6
6
|
const cds = require('../cds')
|
|
7
|
+
const { exists } = cds.utils
|
|
7
8
|
const execAsync = require('node:util').promisify(cp.exec)
|
|
8
9
|
const { isRoot } = require('../util/fs')
|
|
9
10
|
|
|
@@ -14,6 +15,7 @@ const DEBUG = cds.debug('cli|build')
|
|
|
14
15
|
// failsafe to avoid too deep recursions
|
|
15
16
|
// increased from 2 to 5, adding a config options in the future
|
|
16
17
|
const WS_MAX_DEPTH = 5
|
|
18
|
+
const FLATTEN_MAX_DEPTH = 20 // should suffice, was infinite in earlier versions
|
|
17
19
|
|
|
18
20
|
/** @typedef {{col?: number, endCol?: number, line?: number, endLine?: number, file: string}} SourceLocation */
|
|
19
21
|
/** @typedef {object[] | object} Credentials */
|
|
@@ -92,7 +94,7 @@ function relativePaths(root, qualifiedPaths) {
|
|
|
92
94
|
* Returns a list of fully qualified model names belonging to the '@sap' namespace that cannot be resolved.
|
|
93
95
|
* E.g. the module might NOT have been installed.
|
|
94
96
|
* @param {string[]} modelPaths
|
|
95
|
-
* @returns {string[]}
|
|
97
|
+
* @returns {boolean | string[]}
|
|
96
98
|
*/
|
|
97
99
|
function resolveRequiredSapModels(modelPaths) {
|
|
98
100
|
return Array.isArray(modelPaths) && modelPaths.filter(p => {
|
|
@@ -104,14 +106,35 @@ function resolveRequiredSapModels(modelPaths) {
|
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
/**
|
|
107
|
-
* Returns the default model
|
|
109
|
+
* Returns the default model paths for the given workspace.
|
|
108
110
|
* @param {boolean} ws - whether to include workspace models
|
|
109
|
-
* @
|
|
111
|
+
* @returns {Promise<string[]>} array of model paths
|
|
110
112
|
*/
|
|
111
|
-
async function
|
|
112
|
-
|
|
113
|
-
const wildcards =
|
|
114
|
-
|
|
113
|
+
async function getDefaultModelPaths(ws = false) {
|
|
114
|
+
const { toggles } = cds.env.requires, { folders } = cds.env.features
|
|
115
|
+
const wildcards = toggles && folders ? ['*', folders] : '*'
|
|
116
|
+
if (!cds.resolve.locations) return _compatGetDefaultModelPaths(ws, wildcards)
|
|
117
|
+
|
|
118
|
+
let paths = _filterModelPaths(cds.resolve.locations(wildcards))
|
|
119
|
+
if (ws) {
|
|
120
|
+
const workspaces = (await getWorkspaces())
|
|
121
|
+
.map(ws => ws.workspace)
|
|
122
|
+
workspaces.forEach(workspace => {
|
|
123
|
+
const root = path.join(cds.root, workspace)
|
|
124
|
+
const env = cds.env.for('cds', root)
|
|
125
|
+
const resolved = cds.resolve.locations(env.requires.toggles ? wildcards : '*', { env, root })
|
|
126
|
+
paths.push(..._filterModelPaths(resolved, { root, env })
|
|
127
|
+
.map(p => normalizePath(path.join(workspace, p))))
|
|
128
|
+
})
|
|
129
|
+
// exclude redundant built-in models starting with workspace path, e.g. 'books/@sap/cds-mtxs/srv/bootstrap'
|
|
130
|
+
paths = paths.filter(p => NODEJS_MODEL_EXCLUDE_LIST.includes(p) || !NODEJS_MODEL_EXCLUDE_LIST.some(ex => p.endsWith(ex)))
|
|
131
|
+
}
|
|
132
|
+
return paths
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// cds10: remove
|
|
136
|
+
async function _compatGetDefaultModelPaths(ws, wildcards) {
|
|
137
|
+
let paths = _filterModelPaths(cds.resolve(wildcards, false))
|
|
115
138
|
|
|
116
139
|
if (ws) {
|
|
117
140
|
const workspaces = (await getWorkspaces())
|
|
@@ -122,15 +145,15 @@ async function getDefaultModelOptions(ws = false, filter = undefined) {
|
|
|
122
145
|
workspaces.forEach(workspace => {
|
|
123
146
|
cds.root = path.join(root, workspace)
|
|
124
147
|
cds.env = cds.env.for('cds', cds.root)
|
|
125
|
-
|
|
148
|
+
const fromWorkspace = _filterModelPaths(cds.resolve(cds.env.requires.toggles ? wildcards : '*', false))
|
|
149
|
+
paths.push(...fromWorkspace.map(p => normalizePath(path.join(workspace, p))))
|
|
126
150
|
})
|
|
127
151
|
} finally {
|
|
128
152
|
cds.root = root
|
|
129
153
|
cds.env = env
|
|
130
154
|
}
|
|
131
155
|
// exclude redundant built-in models starting with workspace path, e.g. 'books/@sap/cds-mtxs/srv/bootstrap'
|
|
132
|
-
paths = paths
|
|
133
|
-
.filter(p => typeof(p) === 'string' && (NODEJS_MODEL_EXCLUDE_LIST.includes(p) || !NODEJS_MODEL_EXCLUDE_LIST.some(ex => p.endsWith(ex))))
|
|
156
|
+
paths = paths.filter(p => NODEJS_MODEL_EXCLUDE_LIST.includes(p) || !NODEJS_MODEL_EXCLUDE_LIST.some(ex => p.endsWith(ex)))
|
|
134
157
|
}
|
|
135
158
|
return paths
|
|
136
159
|
}
|
|
@@ -143,7 +166,7 @@ async function getDefaultModelOptions(ws = false, filter = undefined) {
|
|
|
143
166
|
/**
|
|
144
167
|
* @overload
|
|
145
168
|
* @param {unknown} dir
|
|
146
|
-
* @returns {unknown}
|
|
169
|
+
* @returns {unknown}
|
|
147
170
|
*/
|
|
148
171
|
/**
|
|
149
172
|
* For valid paths replace '\\' with '/' and remove trailing '/'. Otherwise return as is
|
|
@@ -154,21 +177,6 @@ function normalizePath(dir) {
|
|
|
154
177
|
return typeof dir === "string" ? dir.replace(/\\/g, '/').replace(/\/$/, '') : dir
|
|
155
178
|
}
|
|
156
179
|
|
|
157
|
-
/**
|
|
158
|
-
* @param {NestedStringArray} modelPaths
|
|
159
|
-
*/
|
|
160
|
-
function flatten(modelPaths) {
|
|
161
|
-
// TODO: I guess this could be modelPaths.flat(Infinity) in the future
|
|
162
|
-
return /** @type{string[]}*/(modelPaths.reduce((/** @type {string[]}*/acc, m) => {
|
|
163
|
-
if (Array.isArray(m)) {
|
|
164
|
-
acc = acc.concat(flatten(m))
|
|
165
|
-
} else if (m) {
|
|
166
|
-
acc.push(m)
|
|
167
|
-
}
|
|
168
|
-
return acc
|
|
169
|
-
}, []))
|
|
170
|
-
}
|
|
171
|
-
|
|
172
180
|
function getI18nDefaultFolder() {
|
|
173
181
|
// keep '_i18n' as preferred folder for compatibility reasons
|
|
174
182
|
// if (cds.env.i18n.folders.includes('_i18n')) return '_i18n'
|
|
@@ -176,10 +184,6 @@ function getI18nDefaultFolder() {
|
|
|
176
184
|
return cds.env.i18n.folders?.[0] ?? '_i18n'
|
|
177
185
|
}
|
|
178
186
|
|
|
179
|
-
async function pathExists(path) {
|
|
180
|
-
return fs.promises.access(path).then(() => true).catch(() => false);
|
|
181
|
-
}
|
|
182
|
-
|
|
183
187
|
async function getWorkspacePaths() {
|
|
184
188
|
const wsRoot = findWorkspaceRoot(cds.root)
|
|
185
189
|
if (!wsRoot) {
|
|
@@ -246,15 +250,15 @@ async function getWorkspacesDeclarations (root) {
|
|
|
246
250
|
* needs to be defined resulting in a corresponding symlink.
|
|
247
251
|
* @returns {Promise<Workspace[]>} the paths are relative to 'wsRoot'.
|
|
248
252
|
*/
|
|
249
|
-
async function getWorkspaces(wsRoot, resolve = false, devDependencies = true, visited = new Set()) {
|
|
250
|
-
wsRoot ??= findWorkspaceRoot(
|
|
253
|
+
async function getWorkspaces(wsRoot, resolve = false, devDependencies = true, visited = new Set(), root = cds.root) {
|
|
254
|
+
wsRoot ??= findWorkspaceRoot(root)
|
|
251
255
|
if (!wsRoot) {
|
|
252
256
|
return []
|
|
253
257
|
}
|
|
254
258
|
const pkgJsonWsRoot = require(path.join(wsRoot, 'package.json'))
|
|
255
259
|
let pkgJson = pkgJsonWsRoot
|
|
256
|
-
if (wsRoot !==
|
|
257
|
-
pkgJson = require(path.join(
|
|
260
|
+
if (wsRoot !== root) {
|
|
261
|
+
pkgJson = require(path.join(root, 'package.json'))
|
|
258
262
|
}
|
|
259
263
|
const workspaceDependencies = []
|
|
260
264
|
if (pkgJsonWsRoot.workspaces) {
|
|
@@ -271,11 +275,8 @@ async function getWorkspaces(wsRoot, resolve = false, devDependencies = true, vi
|
|
|
271
275
|
if (subproject && !visited.has(pkg)) {
|
|
272
276
|
visited.add(pkg)
|
|
273
277
|
workspaceDependencies.push(subproject)
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
cds.root = subproject.path
|
|
277
|
-
workspaceDependencies.push(...(await getWorkspaces(wsRoot, resolve, devDependencies, visited)))
|
|
278
|
-
cds.root = cdsr
|
|
278
|
+
// recursively resolve transitive deps with the subproject as root
|
|
279
|
+
workspaceDependencies.push(...(await getWorkspaces(wsRoot, resolve, devDependencies, visited, subproject.path)))
|
|
279
280
|
}
|
|
280
281
|
}
|
|
281
282
|
}
|
|
@@ -398,22 +399,21 @@ function _validateWsDependencies(wsRoot, dependencies, devDependencies) {
|
|
|
398
399
|
|
|
399
400
|
/**
|
|
400
401
|
* Returns a flat array of existing files and folders, trailing '/' or '\\' characters have been removed.
|
|
401
|
-
* @param
|
|
402
|
-
* @
|
|
403
|
-
* @returns
|
|
402
|
+
* @param {NestedStringArray | object | undefined } modelPaths array of files and folders - optionally nested
|
|
403
|
+
* @returns {string[] } flat array of existing files and folders
|
|
404
404
|
*/
|
|
405
|
-
function _filterModelPaths(modelPaths,
|
|
405
|
+
function _filterModelPaths(modelPaths, { env = cds.env, root = cds.root } = {}) {
|
|
406
406
|
const model = /** @type {Set<string>}*/(new Set())
|
|
407
407
|
// may contain nested arrays
|
|
408
|
-
const flatModelPaths =
|
|
409
|
-
const { roots } =
|
|
408
|
+
const flatModelPaths = Array.isArray(modelPaths) ? modelPaths.flat(FLATTEN_MAX_DEPTH) : modelPaths ? [modelPaths] : []
|
|
409
|
+
const { roots } = env
|
|
410
410
|
flatModelPaths.forEach(m => {
|
|
411
411
|
if (m && !model.has(m) && !model.has(m + "/")) {
|
|
412
412
|
// filter roots and absolute model paths that do not exist
|
|
413
413
|
if (roots.includes(m)) {
|
|
414
|
-
const
|
|
415
|
-
//
|
|
416
|
-
if (
|
|
414
|
+
const dirent = path.resolve(root, m)
|
|
415
|
+
// might be cds file name, compatibility to old build configs
|
|
416
|
+
if (exists(dirent) || exists(dirent + FILE_EXT_CDS) || exists(dirent.replaceAll('*', ''))) {
|
|
417
417
|
model.add(m)
|
|
418
418
|
}
|
|
419
419
|
} else {
|
|
@@ -422,41 +422,9 @@ function _filterModelPaths(modelPaths, filter = undefined) {
|
|
|
422
422
|
}
|
|
423
423
|
})
|
|
424
424
|
return [...model]
|
|
425
|
-
.filter(m => filter ? filter(m) : true)
|
|
426
425
|
.map(m => normalizePath(m))
|
|
427
426
|
}
|
|
428
427
|
|
|
429
|
-
/**
|
|
430
|
-
* Returns a set of files found in the given directory and its subdirectories.
|
|
431
|
-
* @param {string} srcDir - the directory to search for files
|
|
432
|
-
* @param {(file: string) => boolean} [filter] - the filter function to apply to the found files
|
|
433
|
-
* @param {string[]} files - the set of files to add the found files to
|
|
434
|
-
* @param {boolean} [ignoreSymlinks=false] - whether to ignore symlinks
|
|
435
|
-
* @returns {string[]} files found in the given directory and its subdirectories
|
|
436
|
-
*/
|
|
437
|
-
function getFiles(srcDir, filter, files = [], ignoreSymlinks = false) {
|
|
438
|
-
function handleResource(/** @type {string} entry */ entry) {
|
|
439
|
-
if (!filter || filter.call(this, entry)) {
|
|
440
|
-
const stats = fs.lstatSync(entry)
|
|
441
|
-
if (cds.utils.isdir(entry)) {
|
|
442
|
-
getFiles(entry, filter, files)
|
|
443
|
-
} else if (stats.isFile() || (!ignoreSymlinks && stats.isSymbolicLink())) {
|
|
444
|
-
files.push(entry)
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
let entries = []
|
|
449
|
-
try {
|
|
450
|
-
entries = fs.readdirSync(srcDir)
|
|
451
|
-
} catch {
|
|
452
|
-
// ignore if not existing
|
|
453
|
-
}
|
|
454
|
-
entries.map(subDirEntry => path.join(srcDir, subDirEntry)).forEach((entry) => {
|
|
455
|
-
handleResource(entry)
|
|
456
|
-
})
|
|
457
|
-
return files
|
|
458
|
-
}
|
|
459
|
-
|
|
460
428
|
/**
|
|
461
429
|
* Return gnu-style error string for location `loc`:
|
|
462
430
|
* - 'File:Line:Col' without `loc.end`
|
|
@@ -494,7 +462,7 @@ class BuildMessage {
|
|
|
494
462
|
* @param {string} message The message text
|
|
495
463
|
* @param {import('./constants').Severity} [severity='Error'] severity - severity of the message
|
|
496
464
|
* @param {SourceLocation | undefined} location Location of the message
|
|
497
|
-
*
|
|
465
|
+
*
|
|
498
466
|
* @memberOf BuildMessage
|
|
499
467
|
*/
|
|
500
468
|
constructor(message, severity = SEVERITY_ERROR, location = undefined) {
|
|
@@ -521,7 +489,7 @@ class BuildError extends Error {
|
|
|
521
489
|
/** @type {string[] | {message: string}[]} */
|
|
522
490
|
messages
|
|
523
491
|
|
|
524
|
-
/**
|
|
492
|
+
/**
|
|
525
493
|
* @param {string} message
|
|
526
494
|
* @param {string | string[]} messages
|
|
527
495
|
*/
|
|
@@ -548,16 +516,13 @@ module.exports = {
|
|
|
548
516
|
hasOptionValue,
|
|
549
517
|
relativePaths,
|
|
550
518
|
resolveRequiredSapModels,
|
|
551
|
-
|
|
552
|
-
flatten,
|
|
519
|
+
getDefaultModelPaths,
|
|
553
520
|
getI18nDefaultFolder,
|
|
554
521
|
normalizePath,
|
|
555
|
-
pathExists,
|
|
556
522
|
getWorkspacePaths,
|
|
557
523
|
getWorkspaces,
|
|
558
524
|
findWorkspaceRoot,
|
|
559
525
|
filterFeaturePaths,
|
|
560
|
-
getFiles,
|
|
561
526
|
BuildMessage,
|
|
562
527
|
BuildError
|
|
563
528
|
}
|