@sap/cds-dk 7.3.0 → 7.3.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.
- package/bin/add.js +1 -1
- package/bin/extend.js +5 -1
- package/bin/init.js +31 -37
- package/bin/repl.js +23 -43
- package/bin/watch.js +5 -9
- package/lib/bind/bindingResolver.js +2 -1
- package/lib/bind/index.js +1 -1
- package/lib/build/buildPlugin.js +18 -3
- package/lib/build/buildTaskEngine.js +2 -1
- package/lib/build/buildTaskFactory.js +33 -9
- package/lib/build/buildTaskProvider.js +1 -1
- package/lib/build/buildTaskProviderFactory.js +15 -61
- package/lib/build/constants.js +2 -0
- package/lib/build/index.js +5 -2
- package/lib/build/plugins.js +35 -0
- package/lib/build/provider/edmxBuildPlugin.js +5 -1
- package/lib/build/provider/featureToggleBuildPlugin.js +2 -2
- package/lib/build/provider/internalBuildPlugin.js +4 -0
- package/lib/build/provider/internalBuildTaskProvider.js +1 -1
- package/lib/build/provider/java/index.js +12 -6
- package/lib/build/util.js +5 -0
- package/lib/client/download_legacy.js +2 -7
- package/lib/client/params.js +1 -0
- package/lib/client/settings_manager.js +16 -14
- package/lib/compile/openapi/csdl2openapi.js +1 -1
- package/lib/index.js +6 -0
- package/lib/init/constants.js +2 -1
- package/lib/init/template/_merging/registry-mta.js +12 -0
- package/lib/init/template/helm/subcharts/content-deployment/Chart.yaml +4 -4
- package/lib/init/template/helm/subcharts/content-deployment/templates/_helpers.tpl +4 -2
- package/lib/init/template/helm/subcharts/content-deployment/templates/job.yaml +4 -3
- package/lib/init/template/helm/subcharts/content-deployment/values.schema.json +9 -83
- package/lib/init/template/helm/subcharts/content-deployment/values.yaml +54 -15
- package/lib/init/template/helm/subcharts/service-instance/Chart.yaml +4 -4
- package/lib/init/template/helm/subcharts/service-instance/templates/serviceinstance.yaml +1 -1
- package/lib/init/template/helm/subcharts/service-instance/values.schema.json +0 -17
- package/lib/init/template/helm/subcharts/service-instance/values.yaml +28 -0
- package/lib/init/template/helm/subcharts/web-application/Chart.yaml +5 -5
- package/lib/init/template/helm/subcharts/web-application/templates/_api.tpl +60 -0
- package/lib/init/template/helm/subcharts/web-application/templates/_helpers.tpl +34 -73
- package/lib/init/template/helm/subcharts/web-application/templates/api-rule.yaml +4 -4
- package/lib/init/template/helm/subcharts/web-application/templates/deployment.yaml +96 -17
- package/lib/init/template/helm/subcharts/web-application/templates/network-policy.yaml +19 -3
- package/lib/init/template/helm/subcharts/web-application/templates/pod-disruption-budget.yaml +3 -3
- package/lib/init/template/helm/subcharts/web-application/templates/rbac.yaml +26 -0
- package/lib/init/template/helm/subcharts/web-application/templates/secret.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service-account.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service-binding.yaml +1 -1
- package/lib/init/template/helm/subcharts/web-application/templates/service.yaml +21 -3
- package/lib/init/template/helm/subcharts/web-application/templates/virtual-service.yaml +36 -0
- package/lib/init/template/helm/subcharts/web-application/values.schema.json +535 -142
- package/lib/init/template/helm/subcharts/web-application/values.yaml +168 -44
- package/lib/init/template/mta/index.js +2 -2
- package/lib/init/template/nodejs/files/.vscode/launch.json +0 -3
- package/lib/init/template/notifications/files/mta.yaml.hbs +17 -0
- package/lib/init/template/notifications/files/notificationtypes.json.hbs +16 -0
- package/lib/init/template/notifications/files/package.json.hbs +14 -0
- package/lib/init/template/notifications/index.js +52 -0
- package/lib/util/pruneAxiosErrors.js +4 -1
- package/lib/util/term.js +1 -2
- package/lib/watch/livereload-server.js +38 -2
- package/lib/watch/node-watch.js +3 -2
- package/npm-shrinkwrap.json +383 -2190
- package/package.json +2 -2
- package/lib/init/template/helm/subcharts/content-deployment/templating.md +0 -37
- package/lib/init/template/helm/subcharts/content-deployment/values-lint.yaml +0 -5
- package/lib/init/template/helm/subcharts/content-deployment/values.md +0 -1011
- package/lib/init/template/helm/subcharts/service-instance/templating.md +0 -18
- package/lib/init/template/helm/subcharts/service-instance/values-lint.yaml +0 -2
- package/lib/init/template/helm/subcharts/service-instance/values.md +0 -186
- package/lib/init/template/helm/subcharts/web-application/templating.md +0 -51
- package/lib/init/template/helm/subcharts/web-application/values-lint.yaml +0 -8
- package/lib/init/template/helm/subcharts/web-application/values.md +0 -1363
package/bin/add.js
CHANGED
package/bin/extend.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
module.exports = Object.assign(extend, {
|
|
2
|
-
options: ['--directory', '--subdomain', '--passcode', '--username', '--clientid', '--tagRule'],
|
|
2
|
+
options: ['--directory', '--subdomain', '--passcode', '--username', '--clientid', '--tagRule', '--defaultTag'],
|
|
3
3
|
flags: ['--wsdl', '--templates', '--force', '--download-migrated-projects'],
|
|
4
4
|
shortcuts: ['-d', '-s', '-p', '-u', '-c'],
|
|
5
5
|
help: `
|
|
@@ -58,6 +58,10 @@ module.exports = Object.assign(extend, {
|
|
|
58
58
|
|
|
59
59
|
Rule used to split up migrated extension projects into separate projects (please check migration documentation for more).
|
|
60
60
|
|
|
61
|
+
*--defaultTag*
|
|
62
|
+
|
|
63
|
+
Default tag used for migrated extension projects, default is 'migrated' (please check migration documentation for more).
|
|
64
|
+
|
|
61
65
|
# SEE ALSO
|
|
62
66
|
|
|
63
67
|
*cds activate* to activate an extension project.
|
package/bin/init.js
CHANGED
|
@@ -22,56 +22,51 @@ module.exports = Object.assign(init, {
|
|
|
22
22
|
Add one or more features while creating the project.
|
|
23
23
|
<feature> can be one of the following:
|
|
24
24
|
|
|
25
|
-
*nodejs*
|
|
25
|
+
*nodejs* - creates as a Node.js-based project
|
|
26
26
|
|
|
27
|
-
*java*
|
|
27
|
+
*java* - creates as a Java-based project
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
project using the *Java* programming language.
|
|
29
|
+
*hana* - add support for SAP HANA
|
|
31
30
|
|
|
32
|
-
*
|
|
31
|
+
*sqlite* - add support for SQLite databases
|
|
33
32
|
|
|
34
|
-
*
|
|
33
|
+
*xsuaa* - add support for authentication via XSUAA
|
|
35
34
|
|
|
36
|
-
*
|
|
35
|
+
*multitenancy* - add support for multitenancy
|
|
37
36
|
|
|
38
|
-
*
|
|
37
|
+
*toggles* - add support for feature toggles
|
|
39
38
|
|
|
40
|
-
*
|
|
39
|
+
*extensibility* - add support for extensibility
|
|
41
40
|
|
|
42
|
-
*
|
|
41
|
+
*approuter* - add support for application routing
|
|
43
42
|
|
|
44
|
-
*
|
|
45
|
-
extensibility
|
|
43
|
+
*file-based-messaging* - add support for file-based messaging
|
|
46
44
|
|
|
47
|
-
*
|
|
45
|
+
*enterprise-messaging* - add support for SAP Event Mesh
|
|
48
46
|
|
|
49
|
-
*
|
|
50
|
-
Technology Platform deployment
|
|
47
|
+
*redis-messaging* - add support for Redis messaging
|
|
51
48
|
|
|
52
|
-
*
|
|
53
|
-
Cloud Foundry native deployment
|
|
49
|
+
*kibana* - add support for Kibana formatting
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
Plugin' that has to be installed separately using
|
|
57
|
-
_cf install-plugin Create-Service-Push_.
|
|
58
|
-
_cf create-service-push_ creates the service(s) and pushes
|
|
59
|
-
the application(s) to the SAP Business Technology
|
|
60
|
-
Platform.
|
|
51
|
+
*mta* - add support for MTA-based deployment
|
|
61
52
|
|
|
62
|
-
*
|
|
53
|
+
*cf-manifest* - add support for CF-native deployment
|
|
63
54
|
|
|
64
|
-
*
|
|
55
|
+
*helm* - add support for Helm-based Kyma deployment
|
|
65
56
|
|
|
66
|
-
*
|
|
57
|
+
*html5-repo* - add support for the HTML5 repository
|
|
67
58
|
|
|
68
|
-
*
|
|
59
|
+
*pipeline* - add files for CI/CD pipeline integration
|
|
69
60
|
|
|
70
|
-
*
|
|
71
|
-
deploy the application using Kyma.
|
|
61
|
+
*tiny-sample* - add minimal sample files
|
|
72
62
|
|
|
73
|
-
*
|
|
74
|
-
|
|
63
|
+
*sample* - add sample files including Fiori UI
|
|
64
|
+
|
|
65
|
+
*data* - add CSV headers for modeled entities
|
|
66
|
+
|
|
67
|
+
*typer* - add type generation for CDS models
|
|
68
|
+
|
|
69
|
+
*lint* - add support for CDS Lint
|
|
75
70
|
|
|
76
71
|
*--java:mvn* <Comma separated maven archetype specific parameters>
|
|
77
72
|
|
|
@@ -85,16 +80,15 @@ module.exports = Object.assign(init, {
|
|
|
85
80
|
|
|
86
81
|
# EXAMPLES
|
|
87
82
|
|
|
88
|
-
*cds init*
|
|
89
|
-
*cds init*
|
|
90
|
-
*cds init*
|
|
91
|
-
*cds init* --add mta
|
|
92
|
-
*cds init* --add cf-manifest
|
|
83
|
+
*cds init* bookshop
|
|
84
|
+
*cds init* bookshop --add java
|
|
85
|
+
*cds init* bookshop --add java,hana
|
|
86
|
+
*cds init* bookshop --add multitenancy,mta
|
|
93
87
|
*cds init* --add java --java:mvn groupId=myGroup,artifactId=newId,package=my.company
|
|
94
88
|
|
|
95
89
|
# SEE ALSO
|
|
96
90
|
|
|
97
|
-
*cds add*
|
|
91
|
+
*cds add* - to augment your projects later on
|
|
98
92
|
|
|
99
93
|
`})
|
|
100
94
|
|
package/bin/repl.js
CHANGED
|
@@ -12,62 +12,42 @@ module.exports = Object.assign (repl, { options: [], help: `
|
|
|
12
12
|
*cds eval* to evaluate and execute JavaScript.
|
|
13
13
|
`})
|
|
14
14
|
|
|
15
|
-
function repl (_, options={}) {
|
|
16
|
-
|
|
17
|
-
// enable `await` statement for Node.js < 16
|
|
18
|
-
if (!process.env['CDS_REPL_SPAWNED'] && process.version.split('.')[0].slice(1) < '16') {
|
|
19
|
-
process.env['CDS_REPL_SPAWNED'] = true
|
|
20
|
-
return require('child_process').spawn('node',['--experimental-repl-await',
|
|
21
|
-
...process.argv.slice(1) ], {stdio:'inherit'}
|
|
22
|
-
)
|
|
23
|
-
}
|
|
15
|
+
async function repl (_, options={}) {
|
|
24
16
|
|
|
25
17
|
const cds = require('../lib/cds')
|
|
26
|
-
|
|
27
|
-
|
|
18
|
+
console.log('\x1b[32m\x1b[1m'+'Welcome to cds repl v', cds.version, '\x1b[0m')
|
|
19
|
+
|
|
20
|
+
await cds.plugins
|
|
21
|
+
|
|
22
|
+
const { inspect } = require('util')
|
|
23
|
+
inspect.defaultOptions.colors = true
|
|
24
|
+
inspect.defaultOptions.depth = 11
|
|
28
25
|
|
|
29
|
-
const colors = options.colors !== false
|
|
30
|
-
const log = options.log || console.log
|
|
31
|
-
const info = colors ? require('../lib/util/term').info : s => s
|
|
32
|
-
log(info('Welcome to cds repl v'+ cds.version))
|
|
33
26
|
|
|
34
|
-
const
|
|
35
|
-
|
|
27
|
+
const repl = require('repl').start ({
|
|
28
|
+
...options, ignoreUndefined: true,
|
|
29
|
+
writer: o => {
|
|
30
|
+
if (!o || typeof o !== 'object') return o
|
|
31
|
+
return inspect(o).replace(/\[Object: null prototype\] /g, '')
|
|
32
|
+
}
|
|
33
|
+
})
|
|
36
34
|
|
|
37
|
-
|
|
35
|
+
Object.defineProperty (cds,'repl',{value:repl})
|
|
36
|
+
cds.lazify (Object.assign (repl.context,{ cds,
|
|
38
37
|
Foo: lazy => new cds.entity ({name:'Foo'}),
|
|
39
38
|
Bar: lazy => new cds.entity ({name:'Bar'}),
|
|
40
39
|
}))
|
|
41
40
|
|
|
42
|
-
|
|
43
|
-
if (Reflect.getOwnPropertyDescriptor(cds,'env')) {
|
|
44
|
-
Reflect.defineProperty (cds,'env',{ value:cds.env, enumerable:false })
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
inspect.defaultOptions.colors = true
|
|
48
|
-
inspect.defaultOptions.depth = 11
|
|
49
|
-
function _writer (o) {
|
|
50
|
-
if (!o || typeof o !== 'object') return o
|
|
51
|
-
return inspect(o).replace(/\[Object: null prototype\] /g, '')
|
|
52
|
-
}
|
|
53
|
-
|
|
41
|
+
repl.history = new Array(222)
|
|
54
42
|
const home = process.env.HOME || process.env.USERPROFILE
|
|
55
|
-
const history = path.join(home,'.cds-repl-history')
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const fs = require('fs')
|
|
60
|
-
const historySize = 111
|
|
61
|
-
fs.readFile(history, 'utf-8', (e, txt) => e || (cdsr.history = txt.split('\n')))
|
|
62
|
-
cdsr.on('exit', () => {
|
|
63
|
-
if (cdsr.history) fs.writeFile(history, cdsr.history.slice(-historySize).join('\n'), () => {})
|
|
64
|
-
})
|
|
65
|
-
}
|
|
66
|
-
|
|
43
|
+
const history = require('path').join(home,'.cds-repl-history')
|
|
44
|
+
const fs = require('fs')
|
|
45
|
+
fs.readFile(history, 'utf-8', (e, txt) => e || Object.assign(repl.history, txt.split('\n')))
|
|
46
|
+
repl.on('exit', () => fs.writeFile(history, repl.history.join('\n'), () => {}))
|
|
67
47
|
|
|
68
48
|
process.on('uncaughtException', console.error)
|
|
69
49
|
process.on('unhandledRejection', console.error)
|
|
70
50
|
|
|
71
51
|
}
|
|
72
|
-
|
|
52
|
+
|
|
73
53
|
if (!module.parent) repl()
|
package/bin/watch.js
CHANGED
|
@@ -59,8 +59,7 @@ const t = module.exports.codes = {
|
|
|
59
59
|
orange: colors ? '\x1b[38;2;255;140;0m' : '' // darker orange, works with bright and dark background
|
|
60
60
|
}
|
|
61
61
|
const extDefaults = 'cds,csn,csv,ts,mjs,cjs,js,json,properties,edmx,xml,env'
|
|
62
|
-
const
|
|
63
|
-
const ignore = RegExp(`(node_modules\\${sep}|app(\\${sep}.+)?\\${sep}((webapp|dist|target)\\${sep}|\\.cds-services\\.json$|tsconfig\\.json$|.*\\.tsbuildinfo$))`)
|
|
62
|
+
const ignore = RegExp(`(node_modules\\${sep}|@cds-models\\${sep}|@types\\${sep}|app(\\${sep}.+)?\\${sep}((webapp|dist|target)\\${sep}|\\.cds-services\\.json$|tsconfig\\.json$|.*\\.tsbuildinfo$))`)
|
|
64
63
|
|
|
65
64
|
async function watch ([cwd], {
|
|
66
65
|
args = ['serve', 'all'],
|
|
@@ -88,16 +87,14 @@ async function watch ([cwd], {
|
|
|
88
87
|
env.NODE_PATH = [...paths(cwd||process.cwd()), ...paths(__dirname)].join(delimiter)
|
|
89
88
|
|
|
90
89
|
if (typeof ext !== 'string') ext = extDefaults
|
|
90
|
+
const delay = parseInt(process.env.CDS_WATCH_DELAY) || 200
|
|
91
91
|
|
|
92
|
-
let includes
|
|
93
92
|
let liveReload //= ...
|
|
94
93
|
let firstTime = true
|
|
95
94
|
if (!/false|no/.test(options['livereload']) && cds.env.for('cds', cwd||process.cwd()).livereload !== false) {
|
|
96
|
-
ext += ',css,gif,html,jpg,png,svg'
|
|
97
|
-
includes = fioriIncludes
|
|
98
95
|
liveReload = new (require ('../lib/watch/livereload-server'))
|
|
99
96
|
env.CDS_LIVERELOAD_PATH = require.resolve ('../lib/watch/livereload-connect')
|
|
100
|
-
env.CDS_LIVERELOAD_URL = await liveReload.start (options['livereload'])
|
|
97
|
+
env.CDS_LIVERELOAD_URL = await liveReload.start (options['livereload'], cwd, delay)
|
|
101
98
|
.catch(err => { console.log(`Error starting live reload: ${err.message}`); liveReload = null })
|
|
102
99
|
}
|
|
103
100
|
|
|
@@ -113,7 +110,6 @@ async function watch ([cwd], {
|
|
|
113
110
|
log ()
|
|
114
111
|
log (`${t.bold}cds ${args.join(' ')}`)
|
|
115
112
|
DEBUG && log (process.pid, 'watching:', ext, '...')
|
|
116
|
-
includes && DEBUG && log (`also watching: ${includes.source}`)
|
|
117
113
|
DEBUG && log ('ignoring:', ignore.source)
|
|
118
114
|
if (liveReload) log (`live reload enabled for browsers`)
|
|
119
115
|
|
|
@@ -124,8 +120,8 @@ async function watch ([cwd], {
|
|
|
124
120
|
|
|
125
121
|
const nodemon = require('../lib/watch/node-watch')
|
|
126
122
|
const watcher = nodemon ({
|
|
127
|
-
script: resolve(__dirname,'watched'), cwd, env, ext,
|
|
128
|
-
delay
|
|
123
|
+
script: resolve(__dirname,'watched'), cwd, env, ext, ignore,
|
|
124
|
+
delay,
|
|
129
125
|
options
|
|
130
126
|
}).on('restart', (files)=>{
|
|
131
127
|
log (`\n${t.bold} ___________________________\n`)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const cds = require('../cds');
|
|
2
|
+
const path = require('path');
|
|
2
3
|
const { platformText, bindingText, logger } = require('./bindingUtil');
|
|
3
4
|
|
|
4
5
|
class BindingResolver {
|
|
5
6
|
getUnresolvedBindings({ cwd = process.cwd(), env } = {}) {
|
|
6
7
|
if (!env) {
|
|
7
|
-
env = cds.env.for('cds', cwd) // REVISIT: This might load cds.env too early!
|
|
8
|
+
env = cds.env.for('cds', path.resolve(cwd)) // REVISIT: This might load cds.env too early!
|
|
8
9
|
}
|
|
9
10
|
const bindings = {}
|
|
10
11
|
const requires = env.requires || {}
|
package/lib/bind/index.js
CHANGED
|
@@ -101,7 +101,7 @@ function runCmd(profile, isJavaProject) {
|
|
|
101
101
|
profile = parseProfile(profile);
|
|
102
102
|
if (isJavaProject) {
|
|
103
103
|
const p = profile === 'hybrid' ? '' : ` --profile ${profile}`;
|
|
104
|
-
return `cds bind exec${p} mvn spring-boot:run`;
|
|
104
|
+
return `cds bind --exec${p} mvn spring-boot:run`;
|
|
105
105
|
} else {
|
|
106
106
|
const p = profile === 'development' ? '' : ` --profile ${profile}`;
|
|
107
107
|
return `cds watch${p}`;
|
package/lib/build/buildPlugin.js
CHANGED
|
@@ -3,7 +3,7 @@ const fs = require('fs').promises
|
|
|
3
3
|
const cds = require('../cds')
|
|
4
4
|
|
|
5
5
|
const { OUTPUT_MODE, OUTPUT_MODE_FILESYSTEM, SEVERITY_INFO, SEVERITY_WARNING, SEVERITY_ERROR } = require('./constants')
|
|
6
|
-
const { hasOptionValue, getProperty, relativePaths, BuildMessage } = require('./util')
|
|
6
|
+
const { hasOptionValue, getProperty, relativePaths, BuildMessage, pathExists } = require('./util')
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The build plugin creates the build output for a dedicated build task. It is uniquely identified
|
|
@@ -27,6 +27,9 @@ class BuildPlugin {
|
|
|
27
27
|
this._written = new Set()
|
|
28
28
|
this._messages = []
|
|
29
29
|
}
|
|
30
|
+
static hasTask() {
|
|
31
|
+
return true
|
|
32
|
+
}
|
|
30
33
|
static get INFO() {
|
|
31
34
|
return SEVERITY_INFO
|
|
32
35
|
}
|
|
@@ -86,7 +89,11 @@ class BuildPlugin {
|
|
|
86
89
|
* Called by the framework immediately after this instance has been created.
|
|
87
90
|
* The instance has already been fully initialized.
|
|
88
91
|
*/
|
|
89
|
-
init() {
|
|
92
|
+
init() {
|
|
93
|
+
if (cds.env.build.target === '.') {
|
|
94
|
+
this.task.dest = path.join(this.task.dest, 'gen')
|
|
95
|
+
}
|
|
96
|
+
}
|
|
90
97
|
|
|
91
98
|
/**
|
|
92
99
|
* @abstract
|
|
@@ -96,13 +103,21 @@ class BuildPlugin {
|
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
/**
|
|
99
|
-
* @abstract
|
|
100
106
|
* Called by the framework immediately before 'build' to delete any output created by this build plugin.
|
|
101
107
|
* <p>
|
|
102
108
|
* Note: The <code>BuildTaskEngine</code> is cleaning the common generation target folder if the build is
|
|
103
109
|
* executed in staging mode, e.g. build.target: "gen".
|
|
104
110
|
*/
|
|
105
111
|
async clean() {
|
|
112
|
+
function isSubDirectory(parent, child) {
|
|
113
|
+
return !path.relative(parent, child).startsWith('..')
|
|
114
|
+
}
|
|
115
|
+
if (cds.env.build.target === '.'
|
|
116
|
+
&& this.task.src !== this.task.dest
|
|
117
|
+
&& !isSubDirectory(this.task.dest, this.task.src)
|
|
118
|
+
&& await pathExists(this.task.dest)) {
|
|
119
|
+
return fs.rm(this.task.dest, { force: true, recursive: true })
|
|
120
|
+
}
|
|
106
121
|
}
|
|
107
122
|
|
|
108
123
|
/**
|
|
@@ -219,7 +219,8 @@ class BuildTaskEngine {
|
|
|
219
219
|
// log all generated files
|
|
220
220
|
const files = BuildTaskEngine._getOutput(plugins)
|
|
221
221
|
if (files.length > 0) {
|
|
222
|
-
|
|
222
|
+
const term = require('../util/term')
|
|
223
|
+
this.logger.log(`done > wrote output to:\n ${term.secondary(files.join("\n "))}\n`)
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
|
|
@@ -4,6 +4,7 @@ const cds = require('../cds')
|
|
|
4
4
|
const BuildTaskProviderFactory = require('./buildTaskProviderFactory')
|
|
5
5
|
const { hasJavaNature, getProperty, redactCredentials, flatten, getDefaultModelOptions } = require('./util')
|
|
6
6
|
const { FILE_EXT_CDS, BUILD_TASK_JAVA_CF, BUILD_TASK_JAVA } = require("./constants")
|
|
7
|
+
const term = require('../util/term')
|
|
7
8
|
|
|
8
9
|
class BuildTaskFactory {
|
|
9
10
|
constructor(options) {
|
|
@@ -27,12 +28,11 @@ class BuildTaskFactory {
|
|
|
27
28
|
const tasks = await this._createTasks()
|
|
28
29
|
|
|
29
30
|
// log build tasks
|
|
30
|
-
|
|
31
|
-
let tasksOutput = " {\n \"build\": {\n \"target\": \"" + cds.env.build.target + "\",\n \"tasks\": ["
|
|
31
|
+
let tasksOutput = "{\n build: {\n target: " + term.info("'" + cds.env.build.target + "'") + ",\n tasks: [\n"
|
|
32
32
|
for (let i = 0; i < tasks.length; i++) {
|
|
33
|
-
tasksOutput += "
|
|
33
|
+
tasksOutput += " " + BuildTaskFactory._stringifyTask(tasks[i]) + (i + 1 < tasks.length ? ",\n" : "\n")
|
|
34
34
|
}
|
|
35
|
-
tasksOutput += "
|
|
35
|
+
tasksOutput += " ]\n }\n}\n"
|
|
36
36
|
this.logger.log(tasksOutput)
|
|
37
37
|
|
|
38
38
|
// for testing purposes
|
|
@@ -196,12 +196,36 @@ class BuildTaskFactory {
|
|
|
196
196
|
static _stringifyTask(task) {
|
|
197
197
|
// ensures identical order of properties
|
|
198
198
|
const order = ["for", "use", "src", "dest", "options"]
|
|
199
|
-
const keys = Object.keys(task).sort((a, b) => order.indexOf(a) - order.indexOf(b))
|
|
199
|
+
const keys = Object.keys(task).filter(key => order.includes(key)).sort((a, b) => order.indexOf(a) - order.indexOf(b))
|
|
200
200
|
|
|
201
|
-
return keys.reduce((acc, key,
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
201
|
+
return keys.reduce((acc, key, i) => {
|
|
202
|
+
const prefix = acc !== '{' ? ', ' : (i === 0 ? ' ' : '')
|
|
203
|
+
if (!key.startsWith('_')) {
|
|
204
|
+
// render either "for" OR "use" value
|
|
205
|
+
if (key in { src: 1, for: 1 } || (!task.for && key === 'use')) {
|
|
206
|
+
return `${acc}${prefix}${key}: ${term.info(`'${task[key]}'`)}`
|
|
207
|
+
} else if (key === 'options') {
|
|
208
|
+
const options = Object.entries(task.options)
|
|
209
|
+
.map(([key, value]) => {
|
|
210
|
+
if (Array.isArray(value)) {
|
|
211
|
+
return `${key}: [${value.map(v => term.info(`'${v}'`)).join(', ')}]`
|
|
212
|
+
} else if (typeof value === 'object') {
|
|
213
|
+
const nested = Object.entries(value)
|
|
214
|
+
.map(([key, value]) => `${key}: ${term.info(`'${value}'`)}`)
|
|
215
|
+
.join(', ')
|
|
216
|
+
return `${key}: { ${nested} }`
|
|
217
|
+
} else {
|
|
218
|
+
return `${key}: ${term.info(`'${value}'`)}`
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
.join(', ')
|
|
222
|
+
return `${acc}${prefix}${key}: { ${options} }`
|
|
223
|
+
} else if (key !== 'use') {
|
|
224
|
+
return `${acc}${prefix}${key}: ${term.info(`'${task[key]}'`)}`
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return acc
|
|
228
|
+
}, '{') + '}'
|
|
205
229
|
}
|
|
206
230
|
|
|
207
231
|
static _scanTaskOptionParams(optsParams) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const cds = require('../cds')
|
|
4
|
-
const { LOG_MODULE_NAMES, OUTPUT_MODE_FILESYSTEM } = require('./constants')
|
|
4
|
+
const { LOG_MODULE_NAMES, OUTPUT_MODE_FILESYSTEM, DEFAULT_SRC_FOLDER } = require('./constants')
|
|
5
5
|
const InternalBuildTaskProvider = require('./provider/internalBuildTaskProvider')
|
|
6
6
|
const BuildTaskProvider = require('./buildTaskProvider')
|
|
7
7
|
const { BuildError } = require('./util')
|
|
@@ -74,11 +74,14 @@ class BuildTaskProviderFactory {
|
|
|
74
74
|
* @param {*} task
|
|
75
75
|
*/
|
|
76
76
|
createPlugin(task) {
|
|
77
|
-
const BuildPluginClass = this.
|
|
77
|
+
const BuildPluginClass = this.getPluginClass(task)
|
|
78
78
|
const resolvedTask = this._resolveTask(task)
|
|
79
79
|
this.logger._debug && this.logger.debug(`loaded build plugin [${resolvedTask.use}]`)
|
|
80
80
|
|
|
81
81
|
const plugin = new BuildPluginClass()
|
|
82
|
+
if (!(plugin instanceof BuildPlugin)) {
|
|
83
|
+
throw new Error(`Invalid Build plugin type ${task.for}`)
|
|
84
|
+
}
|
|
82
85
|
plugin._task = resolvedTask
|
|
83
86
|
plugin._logger = this.logger
|
|
84
87
|
plugin._context = this.context
|
|
@@ -93,10 +96,10 @@ class BuildTaskProviderFactory {
|
|
|
93
96
|
* 'use' defines the fully qualified module name of custom build plugins implementations.
|
|
94
97
|
* @param {object} task
|
|
95
98
|
*/
|
|
96
|
-
|
|
99
|
+
getPluginClass(task) {
|
|
97
100
|
const provider = this._getProvider(task)
|
|
98
101
|
try {
|
|
99
|
-
return provider.
|
|
102
|
+
return provider.getPluginClass(task)
|
|
100
103
|
} catch (e) {
|
|
101
104
|
this.logger.error(`Provider failed to load build plugin class - provider: ${provider.constructor.name}, task: ${task.for || task.use} :\n` + e)
|
|
102
105
|
throw e
|
|
@@ -113,9 +116,6 @@ class BuildTaskProviderFactory {
|
|
|
113
116
|
* @param {*} task
|
|
114
117
|
*/
|
|
115
118
|
_resolveTask(task) {
|
|
116
|
-
// first validate plugin implementation
|
|
117
|
-
this.loadPlugin(task)
|
|
118
|
-
|
|
119
119
|
// second validate src path
|
|
120
120
|
const resolvedTask = JSON.parse(JSON.stringify(task))
|
|
121
121
|
|
|
@@ -181,7 +181,7 @@ class DefaultBuildTaskProvider extends BuildTaskProvider {
|
|
|
181
181
|
return !!key.use
|
|
182
182
|
}
|
|
183
183
|
|
|
184
|
-
|
|
184
|
+
getPluginClass(task) {
|
|
185
185
|
try {
|
|
186
186
|
return require(require.resolve(task.use, { paths: [cds.root] }))
|
|
187
187
|
} catch (e) {
|
|
@@ -192,36 +192,14 @@ class DefaultBuildTaskProvider extends BuildTaskProvider {
|
|
|
192
192
|
|
|
193
193
|
/**
|
|
194
194
|
* Default provider implementation handling fully qualified custom build task declarations.
|
|
195
|
-
* Has to be the last entry in the providers list. // REVISIT: Above it says DefaultBuildTaskProvider should be last entry? -> clarify
|
|
196
195
|
*/
|
|
197
196
|
class PluginBuildTaskProvider extends BuildTaskProvider {
|
|
198
197
|
constructor(logger) {
|
|
199
198
|
super()
|
|
200
199
|
this._logger = logger
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
// REVISIT: Remove once fetch mechanism is removed
|
|
204
|
-
function _local (id) {
|
|
205
|
-
return require(require.resolve (id, {paths:[
|
|
206
|
-
process.cwd(), // project-local module is preferred
|
|
207
|
-
__dirname // otherwise from our own dependencies
|
|
208
|
-
]}))
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
const cdsPlugins = _local('@sap/cds/lib/plugins').fetch?.() // REVISIT: Get rid of fetch mechanism
|
|
212
|
-
const buildPlugins = cds.env.build.plugins // REVISIT: Compat to old plugin mechanism, remove if possible
|
|
213
|
-
|
|
214
|
-
for (const [id, plugin] of Object.entries({ ...cdsPlugins, ...buildPlugins })) {
|
|
215
|
-
try {
|
|
216
|
-
const clazz = this._loadPlugin(id, plugin)
|
|
217
|
-
if (!clazz) continue
|
|
218
|
-
plugins.set(id, { id: id, impl: plugin.impl, class: clazz })
|
|
219
|
-
} catch (e) {
|
|
220
|
-
this._logger.error(`Skipping build plugin '${id}', it cannot be loaded.\n` + e + '\n') // REVISIT: why not throw? seems like an error one should fix, not exit with code 0
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
this._plugins = plugins
|
|
200
|
+
this._plugins = require('./plugins').getPlugins()
|
|
224
201
|
}
|
|
202
|
+
|
|
225
203
|
get plugins() {
|
|
226
204
|
return this._plugins
|
|
227
205
|
}
|
|
@@ -230,8 +208,8 @@ class PluginBuildTaskProvider extends BuildTaskProvider {
|
|
|
230
208
|
return this.plugins.has(key.for)
|
|
231
209
|
}
|
|
232
210
|
|
|
233
|
-
|
|
234
|
-
return this.
|
|
211
|
+
getPluginClass(task) {
|
|
212
|
+
return this.plugins.get(task.for).class
|
|
235
213
|
}
|
|
236
214
|
|
|
237
215
|
async lookupTasks(tasks, dependencies) {
|
|
@@ -258,35 +236,11 @@ class PluginBuildTaskProvider extends BuildTaskProvider {
|
|
|
258
236
|
}
|
|
259
237
|
|
|
260
238
|
getTask(key) {
|
|
261
|
-
const task = this.plugins.get(key.for).
|
|
262
|
-
task.src ??= '.'
|
|
263
|
-
if (task.src) {
|
|
264
|
-
task.src = task.src.replace(/\/$/, '')
|
|
265
|
-
}
|
|
239
|
+
const task = this.plugins.get(key.for).taskDefaults
|
|
266
240
|
task.for = key.for
|
|
241
|
+
task.src ??= DEFAULT_SRC_FOLDER
|
|
242
|
+
task.src = task.src.replace(/\/$/, '')
|
|
267
243
|
return task
|
|
268
244
|
}
|
|
269
|
-
|
|
270
|
-
_loadPlugin(id, plugin) {
|
|
271
|
-
let pluginClass
|
|
272
|
-
try {
|
|
273
|
-
pluginClass = require(require.resolve(plugin.impl, { paths: [cds.root] }))
|
|
274
|
-
const inheritsFrom = (child, parent) => {
|
|
275
|
-
let proto = Object.getPrototypeOf(child)
|
|
276
|
-
while (proto) {
|
|
277
|
-
if (proto === parent) return true
|
|
278
|
-
proto = Object.getPrototypeOf(proto)
|
|
279
|
-
}
|
|
280
|
-
return false
|
|
281
|
-
}
|
|
282
|
-
if (!inheritsFrom(pluginClass, BuildPlugin)) return // REVISIT: better way to check if plugin is build-enabled than traversing prototype chain?
|
|
283
|
-
} catch (e) {
|
|
284
|
-
throw new Error(`Custom build plugin implementation '${plugin.impl}' for '${id}' cannot be loaded:\n` + e)
|
|
285
|
-
}
|
|
286
|
-
if (!pluginClass.hasTask || !pluginClass.getTaskDefaults) {
|
|
287
|
-
throw new Error(`Custom build plugin '${id}' must implement 'hasTask' and 'getTaskDefaults' methods`)
|
|
288
|
-
}
|
|
289
|
-
return pluginClass
|
|
290
|
-
}
|
|
291
245
|
}
|
|
292
246
|
module.exports = BuildTaskProviderFactory
|
package/lib/build/constants.js
CHANGED
|
@@ -3,6 +3,7 @@ exports.OUTPUT_MODE_NONE = 0x0
|
|
|
3
3
|
exports.OUTPUT_MODE_FILESYSTEM = 0x1
|
|
4
4
|
exports.OUTPUT_MODE_RESULT = 0x2
|
|
5
5
|
|
|
6
|
+
exports.DEFAULT_SRC_FOLDER = '.'
|
|
6
7
|
exports.BUILD_TASK_NPM_SCOPE = "@sap"
|
|
7
8
|
exports.BUILD_TASK_PREFIX = exports.BUILD_TASK_NPM_SCOPE + "/cds/build"
|
|
8
9
|
exports.BUILD_TASK_JAVA = "java"
|
|
@@ -23,6 +24,7 @@ exports.CONTENT_LANGUAGE_BUNDLES = "contentLanguageBundles" // create i18n.j
|
|
|
23
24
|
exports.CONTENT_DEFAULT_CSN = "contentDefaultCsn" // create default CSN format flavor: "inferred"
|
|
24
25
|
exports.FLAVOR_LOCALIZED_EDMX = "flavorLocalizedEdmx" // create localized EDMX languages based on existing properties files
|
|
25
26
|
exports.CONTENT_EDMX = "contentEdmx" // create EDMX for required languages - ENABLED by default
|
|
27
|
+
exports.CONTENT_LOCALIZED_EDMX = "contentLocalizedEdmx" // create EDMX for required languages - ENABLED for Java by default
|
|
26
28
|
exports.CONTENT_PACKAGE_JSON = "contentPackageJson" // create package.json file if not existing, or modify existing package.json - ENABLED by default
|
|
27
29
|
exports.CONTENT_PACKAGELOCK_JSON = "contentPackageLockJson" // copy package-lock.json file if existing into deployment folder - ENABLED by default
|
|
28
30
|
exports.CONTENT_HDBTABLEDATA = "contentHdbtabledata" // create .hdbtabledata files for .csv files if not existing - ENABLED by default
|
package/lib/build/index.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const cds = require('../cds')
|
|
3
3
|
const BuildTaskEngine = require('./buildTaskEngine')
|
|
4
|
-
const BuildTaskFactory = require('./buildTaskFactory')
|
|
5
4
|
const BuildPlugin = require('./buildPlugin')
|
|
6
5
|
const { BuildError } = require('./util')
|
|
7
6
|
|
|
8
|
-
module.exports = { build,
|
|
7
|
+
module.exports = { build, register, BuildPlugin }
|
|
9
8
|
|
|
10
9
|
/**
|
|
11
10
|
* Executes cds build in the directory defined by cds.root.
|
|
@@ -28,4 +27,8 @@ async function build(options = {}) {
|
|
|
28
27
|
}
|
|
29
28
|
throw e
|
|
30
29
|
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function register(id, options) {
|
|
33
|
+
return require('./plugins').register(id, options)
|
|
31
34
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const cds = require('../cds')
|
|
2
|
+
|
|
3
|
+
module.exports = new (class BuildPlugins {
|
|
4
|
+
constructor() {
|
|
5
|
+
this._plugins = new Map()
|
|
6
|
+
}
|
|
7
|
+
getPlugins() {
|
|
8
|
+
return this._plugins
|
|
9
|
+
}
|
|
10
|
+
getPlugin(id) {
|
|
11
|
+
return this._plugins.get(id)
|
|
12
|
+
}
|
|
13
|
+
register(id, options) {
|
|
14
|
+
if (!id || !options?.impl) {
|
|
15
|
+
throw Error("Invalid build plugin parameter")
|
|
16
|
+
}
|
|
17
|
+
if (this._plugins.has(id)) {
|
|
18
|
+
throw Error(`Build plugin ${id} already registered`)
|
|
19
|
+
}
|
|
20
|
+
this._plugins.set(id, {
|
|
21
|
+
id,
|
|
22
|
+
class: this._loadPlugin(id, options.impl),
|
|
23
|
+
description: options.description,
|
|
24
|
+
taskDefaults: options.taskDefaults ?? {}
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
_loadPlugin(id, impl) {
|
|
28
|
+
try {
|
|
29
|
+
// project-local module is preferred - otherwise from our own dependencies
|
|
30
|
+
return require(require.resolve(impl, { paths: [cds.root, __dirname] }))
|
|
31
|
+
} catch (e) {
|
|
32
|
+
throw new Error(`Custom build plugin implementation '${impl}' for '${id}' cannot be loaded:\n` + e)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
})
|