@sap/cds-dk 7.8.1 → 7.9.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 +28 -7
- package/bin/bind.js +64 -21
- package/bin/build.js +35 -3
- package/bin/cds.js +32 -13
- package/bin/compile/index.js +44 -3
- package/bin/completion/completionFs.js +61 -0
- package/bin/completion/index.js +212 -0
- package/bin/completion/scripts/cds-bash.sh +17 -0
- package/bin/completion/scripts/cds-ps.ps1 +18 -0
- package/bin/completion/scripts/cds-zsh.sh +12 -0
- package/bin/help.js +8 -2
- package/bin/init.js +34 -4
- package/bin/subscribe.js +5 -1
- package/bin/watch.js +4 -2
- package/lib/bind/KubernetesApiAccessor.js +3 -2
- package/lib/bind/bindingResolver.js +3 -2
- package/lib/bind/bindingUtil.js +10 -8
- package/lib/bind/cfKeyProvider.js +58 -153
- package/lib/bind/index.js +46 -36
- package/lib/bind/kubernetesCredentialsProvider.js +6 -5
- package/lib/bind/userCdsrcJsonStorageProvider.js +25 -3
- package/lib/build/buildTaskEngine.js +1 -1
- package/lib/build/provider/hana/index.js +1 -1
- package/lib/build/provider/hana/template/undeploy.json +3 -1
- package/lib/build/provider/nodejs/index.js +1 -1
- package/lib/compile/openapi/csdl2openapi.js +4 -0
- package/lib/compile/openapi/index.js +5 -0
- package/lib/deploy/to-hana/hana.js +25 -7
- package/lib/env/schemas/cds-rc.js +29 -2
- package/lib/import/odata/v4parser.js +78 -25
- package/lib/init/constants.js +2 -1
- package/lib/init/index.js +18 -13
- package/lib/init/merge.js +1 -0
- package/lib/init/mvn.js +8 -47
- package/lib/init/plugin.js +0 -4
- package/lib/init/projectReader.js +17 -10
- package/lib/init/template/approuter/files/values.yaml.hbs +6 -12
- package/lib/init/template/approuter/index.js +1 -7
- package/lib/init/template/completion/completionSetup.js +184 -0
- package/lib/init/template/completion/index.js +22 -0
- package/lib/init/template/data/as-csv.js +25 -17
- package/lib/init/template/data/as-json.js +115 -30
- package/lib/init/template/data/index.js +28 -15
- package/lib/init/template/hana/files/undeploy.json +2 -1
- package/lib/init/template/helm/files/chart/values.schema.json +1 -1
- package/lib/init/template/helm/files/content-deployment/Chart.yaml +0 -2
- package/lib/init/template/helm/files/content-deployment/values.schema.json +0 -1
- package/lib/init/template/helm/files/service-instance/Chart.yaml +0 -2
- package/lib/init/template/helm/files/service-instance/values.schema.json +0 -1
- package/lib/init/template/helm/files/web-application/Chart.yaml +1 -3
- package/lib/init/template/helm/files/web-application/templates/_helpers.tpl +23 -0
- package/lib/init/template/helm/files/web-application/templates/deployment.yaml +3 -29
- package/lib/init/template/helm/files/web-application/values.schema.json +17 -2
- package/lib/init/template/helm/files/web-application/values.yaml +10 -2
- package/lib/init/template/helm-unified-runtime/files/templates/NOTES.txt +2 -0
- package/lib/init/template/helm-unified-runtime/files/templates/_deployment_helpers.tpl +10 -2
- package/lib/init/template/helm-unified-runtime/files/values.schema.json +1 -1
- package/lib/init/template/http/index.js +150 -104
- package/lib/init/template/kafka/index.js +6 -0
- package/lib/init/template/lint/index.js +12 -13
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -1
- package/lib/init/template/multitenancy/files/mtxs-configmap-java.yaml +1 -1
- package/lib/init/template/multitenancy/files/values.yaml.hbs +0 -5
- package/lib/init/template/multitenancy/index.js +13 -5
- package/lib/init/template/nodejs/files/.vscode/settings.json +11 -0
- package/lib/init/template/nodejs/files/eslint.config.js +13 -0
- package/lib/init/template/nodejs/files/package.json.hbs +3 -1
- package/lib/init/template/sample/index.js +18 -20
- package/lib/init/template/tiny-sample/index.js +1 -2
- package/lib/init/template/typer/index.js +2 -2
- package/lib/lint/Linter.js +133 -55
- package/lib/lint/checks.js +5 -6
- package/lib/lint/io.js +119 -10
- package/lib/mtx/auth_manager.js +5 -5
- package/lib/mtx/params.js +4 -2
- package/lib/mtx/settings_manager.js +1 -1
- package/lib/mtx/tenant_action.js +12 -2
- package/lib/mtx/util/logging.js +10 -4
- package/lib/util/axios.js +2 -1
- package/lib/util/cf.js +32 -37
- package/lib/util/fs.js +1 -1
- package/lib/util/git.js +1 -1
- package/lib/util/term.js +1 -1
- package/{bin → lib/watch}/watched.js +2 -2
- package/npm-shrinkwrap.json +317 -293
- package/package.json +2 -2
- package/lib/init/template/approuter/files/approuter-mtxs-configmap.yaml +0 -19
- package/lib/init/template/nodejs/files/.eslintrc +0 -26
- /package/lib/init/template/{approuter/files/mtxs-configmap-java.yaml → multitenancy/files/mtxs-configmap-java-approuter.yaml} +0 -0
- /package/lib/init/template/{approuter/files/mtxs-configmap-nodejs.yaml → multitenancy/files/mtxs-configmap-nodejs-approuter.yaml} +0 -0
package/bin/add.js
CHANGED
|
@@ -23,6 +23,7 @@ const flags = ['--force', ...Object.values(conf).flatMap(p => p.flags).map(o =>
|
|
|
23
23
|
DEBUG?.('cli config ', { options, shortcuts, flags })
|
|
24
24
|
|
|
25
25
|
module.exports = Object.assign(add, {
|
|
26
|
+
handleCompletion,
|
|
26
27
|
options,
|
|
27
28
|
shortcuts,
|
|
28
29
|
flags,
|
|
@@ -98,18 +99,18 @@ module.exports = Object.assign(add, {
|
|
|
98
99
|
# FEATURE OPTIONS
|
|
99
100
|
|
|
100
101
|
${Object.entries(conf).sort(([a], [b]) => a.localeCompare(b)).flatMap(([pluginName, { options, flags }]) => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
}).join('\n\n\n')}
|
|
102
|
+
const text4 = arr => arr.map(({ key, help, short }) => help && ` ${key}${short ? ' | '+short : ''}\n\n ${help}`).join('\n\n')
|
|
103
|
+
const optionsText = text4(options), flagsText = text4(flags)
|
|
104
|
+
if (!optionsText && !flagsText) return []
|
|
105
|
+
return ` *cds add ${pluginName}*\n\n${optionsText}${flagsText}`
|
|
106
|
+
}).join('\n\n\n')}
|
|
106
107
|
|
|
107
108
|
|
|
108
109
|
# EXAMPLES
|
|
109
110
|
|
|
110
111
|
*cds add* sample
|
|
111
112
|
*cds add* multitenancy,hana,xsuaa --for production
|
|
112
|
-
*cds add* data --
|
|
113
|
+
*cds add* data --filter my.namespace.MyEntity
|
|
113
114
|
*cds add* mta
|
|
114
115
|
*cds add* helm
|
|
115
116
|
|
|
@@ -118,7 +119,27 @@ ${Object.entries(conf).sort(([a], [b]) => a.localeCompare(b)).flatMap(([pluginNa
|
|
|
118
119
|
|
|
119
120
|
*cds init*
|
|
120
121
|
|
|
121
|
-
`})
|
|
122
|
+
`});
|
|
123
|
+
|
|
124
|
+
async function handleCompletion(currentWord, previousWord, argv, util) {
|
|
125
|
+
const allOptionsFlags = [
|
|
126
|
+
...options ?? [],
|
|
127
|
+
...flags ?? []
|
|
128
|
+
].filter(e => !argv.includes(e));
|
|
129
|
+
|
|
130
|
+
if (currentWord?.startsWith('-')) {
|
|
131
|
+
return allOptionsFlags;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (!currentWord && options?.includes(previousWord)) {
|
|
135
|
+
return [];
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const entries = await util.completionFs.readTemplates(argv);
|
|
139
|
+
entries.push(...allOptionsFlags);
|
|
140
|
+
|
|
141
|
+
return entries;
|
|
142
|
+
}
|
|
122
143
|
|
|
123
144
|
async function add(args) {
|
|
124
145
|
// await cds.plugins
|
package/bin/bind.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const term = require('../lib/util/term')
|
|
2
2
|
|
|
3
3
|
module.exports = Object.assign(cds_bind, {
|
|
4
|
-
options: ['--to', '--for', '--on', '--kind', '--out', '--to-app-services', '--
|
|
5
|
-
flags: ['--exec'],
|
|
6
|
-
shortcuts: ['-2', '-4', '-n', '-k', '-o', '-a'],
|
|
4
|
+
options: ['--to', '--for', '--on', '--kind', '--out', '--to-app-services', '--credentials', '--output-file'],
|
|
5
|
+
flags: ['--exec', '--no-create-service-key'],
|
|
6
|
+
shortcuts: ['-2', '-4', '-n', '-k', '-o', '-a', '-c'],
|
|
7
7
|
help: `
|
|
8
8
|
# SYNOPSIS
|
|
9
9
|
|
|
@@ -52,6 +52,11 @@ module.exports = Object.assign(cds_bind, {
|
|
|
52
52
|
|
|
53
53
|
Skip automatic creation of service keys.
|
|
54
54
|
|
|
55
|
+
*-c | --credentials* <JSON|{file path}> (Beta)
|
|
56
|
+
|
|
57
|
+
JSON or file path defining custom fields overwriting service credentials.
|
|
58
|
+
Custom credentials are merged with the credentials read from BTP when running your application in hybrid mode.
|
|
59
|
+
|
|
55
60
|
# EXAMPLE
|
|
56
61
|
|
|
57
62
|
cds bind --to bookshop-db
|
|
@@ -64,72 +69,110 @@ module.exports = Object.assign(cds_bind, {
|
|
|
64
69
|
cds bind --to bookshop-db --for my-profile
|
|
65
70
|
|
|
66
71
|
cds bind --to-app-services bookshop-srv
|
|
72
|
+
|
|
73
|
+
cds bind messaging --to redis-cache --credentials '{"host":"localhost","port":6379}'
|
|
74
|
+
cds bind messaging --to redis-cache --credentials ./credentials.json
|
|
67
75
|
`
|
|
68
76
|
});
|
|
69
77
|
|
|
70
78
|
const os = require('os');
|
|
71
79
|
const IS_WIN = os.platform() === 'win32';
|
|
72
80
|
|
|
73
|
-
const { bind, parseProfile } = require('../lib/bind');
|
|
81
|
+
const { bind, storeBindings, parseProfile } = require('../lib/bind');
|
|
74
82
|
|
|
75
83
|
|
|
76
84
|
async function cds_bind(args, options) {
|
|
77
|
-
|
|
78
|
-
const { on, 'to-app-services': app, to, out, 'output-file': outputFile, exec } = options
|
|
85
|
+
const { on, 'to-app-services': app, to, out, 'output-file': outputFile, exec, credentials } = options
|
|
79
86
|
|
|
80
87
|
if (exec) {
|
|
81
88
|
process.env.CDS_ENV = parseProfile(process.env.CDS_ENV);
|
|
82
89
|
if (options.for) {
|
|
83
|
-
console.warn(
|
|
90
|
+
console.warn(term.warn(`Parameter --for is not supported in combination with --exec. Its value will be ignored.`));
|
|
84
91
|
}
|
|
85
92
|
return cds_bind_exec(args)
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
// Check if cds command was bind. Don't abort in case of deploy
|
|
89
96
|
if (process.env.CDS_ENV && process.argv[2] === 'bind') {
|
|
90
|
-
throw
|
|
97
|
+
throw `Option ${term.bold('--profile')} is no longer supported. Use ${term.bold('--for')} instead to specify the profile to use when storing connection settings.`;
|
|
91
98
|
}
|
|
92
99
|
|
|
93
100
|
if (outputFile) {
|
|
94
|
-
console.warn(warn(
|
|
101
|
+
console.warn(term.warn(`Option --output-file is deprecated. Please use --out instead.`))
|
|
95
102
|
options.out ??= outputFile
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
if (on === 'k8s' && app) {
|
|
99
|
-
throw
|
|
106
|
+
throw `Option ${term.bold('--to-app-services')} is only supported for Cloud Foundry.`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (credentials === true) {
|
|
110
|
+
throw `Option ${term.bold('--credentials')} requires a JSON object or a file path.`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// read credentials from file if it is a file, from JSON if it is JSON
|
|
114
|
+
if (credentials) {
|
|
115
|
+
let credentialsJson = options.credentials;
|
|
116
|
+
if (!credentials.trim().startsWith('{')) {
|
|
117
|
+
const fs = require('fs');
|
|
118
|
+
try {
|
|
119
|
+
credentialsJson = fs.readFileSync(credentials, 'utf8');
|
|
120
|
+
} catch (e) {
|
|
121
|
+
throw `Error reading credentials from file ${credentials}: ${e.message}`
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
options.credentials = JSON.parse(credentialsJson);
|
|
126
|
+
} catch (e) {
|
|
127
|
+
throw `Invalid JSON format for option ${term.bold('--credentials')}: ${e.message}`;
|
|
128
|
+
}
|
|
129
|
+
if (options.to) {
|
|
130
|
+
//at least one service must match
|
|
131
|
+
const toServices = options.to.split(',');
|
|
132
|
+
if (toServices.length > 1) {
|
|
133
|
+
if (!toServices.some(toService => options.credentials[toService])) {
|
|
134
|
+
throw `Option ${term.bold('--credentials')} cannot uniquely identify a matching service defined in ${term.bold('--to')}.\nWhen passing multiple services, include the service name in the credentials object.\nExample: cds bind --to bookshop-db,bookshop-redis --credentials '{ "bookshop-redis": {"host": "localhost", "port": 1234}}'`
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
100
138
|
}
|
|
101
139
|
|
|
102
140
|
if (!to && !app) {
|
|
103
|
-
throw `Use option --to or -2 to specify the target instance, e.g. cds bind --to myInstance:myService`;
|
|
141
|
+
throw `Use option ${term.bold('--to')} or ${term.bold('-2')} to specify the target instance, e.g. ${term.bold('cds bind --to myInstance:myService')}`;
|
|
104
142
|
}
|
|
105
143
|
|
|
106
144
|
if (app === true) {
|
|
107
|
-
throw `Option '--to-app-services' requires an app name, for example 'cds bind --to-app-services bookshop-srv'.`
|
|
145
|
+
throw `Option ${term.bold('--to-app-services')} requires an app name, for example ${term.bold('cds bind --to-app-services bookshop-srv')}.`
|
|
108
146
|
}
|
|
109
147
|
|
|
148
|
+
options.for ??= 'hybrid';
|
|
149
|
+
|
|
110
150
|
if (app) {
|
|
111
151
|
const services = await require('../lib/util/cf').getServices(app)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
152
|
+
const allServices = await Promise.all(
|
|
153
|
+
services
|
|
154
|
+
.filter(s => Object.keys(s.credentials).length > 0)
|
|
155
|
+
.map(s => bind({ ...options, to: s.name, out }))
|
|
156
|
+
)
|
|
157
|
+
await storeBindings(allServices.flat(), options);
|
|
116
158
|
} else {
|
|
117
159
|
if (args.length > 1) {
|
|
118
|
-
throw
|
|
160
|
+
throw 'Too many arguments: Please specify only one or no service.';
|
|
119
161
|
}
|
|
120
162
|
|
|
121
163
|
options.serviceArg = args[0]
|
|
122
164
|
options.targets = options.to.split(/,/g);
|
|
123
165
|
|
|
124
166
|
if (options.targets.length >= 2 && options.serviceArg) {
|
|
125
|
-
throw `Service argument cannot be specified together with multiple targets ('--to') services. Use one service per call or omit the service argument.`;
|
|
167
|
+
throw `Service argument cannot be specified together with multiple targets (${term.bold('--to')}) services. Use one service per call or omit the service argument.`;
|
|
126
168
|
}
|
|
127
169
|
|
|
128
170
|
if (options.targets.length >= 2 && options.kind) {
|
|
129
|
-
throw `The option '--kind' cannot be specified together with multiple targets ('--to') services. Use one service per call or omit the '--kind' option.`;
|
|
171
|
+
throw `The option '--kind' cannot be specified together with multiple targets (${term.bold('--to')}) services. Use one service per call or omit the ${term.bold('--kind')} option.`;
|
|
130
172
|
}
|
|
131
173
|
|
|
132
|
-
await bind({ ...options, out });
|
|
174
|
+
const services = await bind({ ...options, out });
|
|
175
|
+
await storeBindings(services, options);
|
|
133
176
|
}
|
|
134
177
|
}
|
|
135
178
|
|
package/bin/build.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
module.exports = Object.assign(build, {
|
|
2
|
+
handleCompletion,
|
|
2
3
|
options: ['--project', '--src', '--dest', '--for', '--use', '--opts', '--log-level', '--options-model'],
|
|
3
4
|
shortcuts: ['-in', '-s', '-o', '-4'],
|
|
4
5
|
flags: ['--clean', '--no-clean', '--ws', '--ws-pack'], // REVISIT: --clean is deprecated, backward compatibility
|
|
@@ -67,7 +68,7 @@ module.exports = Object.assign(build, {
|
|
|
67
68
|
*-in | --project* [<project>]
|
|
68
69
|
Runs 'cds build' for the specified project, default is current working
|
|
69
70
|
directory.
|
|
70
|
-
|
|
71
|
+
|
|
71
72
|
*--no-clean* (beta)
|
|
72
73
|
Skips cleaning the build output folder before running the actual build
|
|
73
74
|
operation. Clients need to clean the output folder upfront to ensure
|
|
@@ -92,7 +93,7 @@ module.exports = Object.assign(build, {
|
|
|
92
93
|
folder of the project. This 'db' folder represents the single database shared by all workspaces.
|
|
93
94
|
*Note:* Make sure to use consistent package versions in your workspace dependencies in order
|
|
94
95
|
to avoid compilation errors caused by duplicate model definitions.
|
|
95
|
-
|
|
96
|
+
|
|
96
97
|
# EXAMPLES
|
|
97
98
|
|
|
98
99
|
*cds* build
|
|
@@ -102,10 +103,41 @@ module.exports = Object.assign(build, {
|
|
|
102
103
|
*cds* build --for java --dest ../srv/target --opts model=[db/model,srv,schema]
|
|
103
104
|
`})
|
|
104
105
|
|
|
106
|
+
async function handleCompletion(currentWord, previousWord, argv, util) {
|
|
107
|
+
const allOptionsFlags = [
|
|
108
|
+
...build.options ?? [],
|
|
109
|
+
...build.flags ?? []
|
|
110
|
+
].filter(e => !argv.includes(e));
|
|
111
|
+
|
|
112
|
+
if (currentWord?.startsWith('-')) {
|
|
113
|
+
return allOptionsFlags;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
switch (previousWord) {
|
|
117
|
+
case '--log-level':
|
|
118
|
+
return ['debug', 'info', 'warn', 'error'];
|
|
119
|
+
case '-4':
|
|
120
|
+
case '--for':
|
|
121
|
+
return ['hana', 'java', 'mtx', 'mtx-extension', 'mtx-sidecar', 'nodejs'];
|
|
122
|
+
case '--dest':
|
|
123
|
+
case '-o':
|
|
124
|
+
case '-s':
|
|
125
|
+
case '--src': {
|
|
126
|
+
return util.completionFs.readdir(currentWord, { files: false });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (!currentWord && build.options?.includes(previousWord)) {
|
|
131
|
+
return [];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return allOptionsFlags;
|
|
135
|
+
}
|
|
136
|
+
|
|
105
137
|
async function build([project], options = {}) {
|
|
106
138
|
const path = require('path')
|
|
107
139
|
|
|
108
|
-
// ensure that cds build plugins defined as devDependencies are loaded
|
|
140
|
+
// ensure that cds build plugins defined as devDependencies are loaded
|
|
109
141
|
if (process.env.NODE_ENV === 'production') delete process.env.NODE_ENV
|
|
110
142
|
|
|
111
143
|
const cds = require('../lib/cds')
|
package/bin/cds.js
CHANGED
|
@@ -34,6 +34,14 @@ const cli = {
|
|
|
34
34
|
DEBUG?.(`[cds] - @sap/cds ${cds.version} loaded: ${cds.home}`)
|
|
35
35
|
|
|
36
36
|
try {
|
|
37
|
+
const allCmds = getCommands();
|
|
38
|
+
|
|
39
|
+
//TODO: make better; only POC for cds help
|
|
40
|
+
Object.assign(module.exports, { cmds: allCmds })
|
|
41
|
+
|
|
42
|
+
// const { handleCompletion } = require('./util/completion');
|
|
43
|
+
// await handleCompletion(process.argv, allCmds, this);
|
|
44
|
+
|
|
37
45
|
const task = this.load(cmd, /*else*/(f) => argv.unshift(cmd) && (cmd = 'compile') && _defaultCompile(argv, f))
|
|
38
46
|
if (task) {
|
|
39
47
|
// REVISIT bind: '--' handling for cds bind --exec. Should be moved to cds_cli
|
|
@@ -46,7 +54,7 @@ const cli = {
|
|
|
46
54
|
// REVISIT: Have to do it here to allow custom flags for plugins!
|
|
47
55
|
if (cmd === 'add') {
|
|
48
56
|
await cds.plugins
|
|
49
|
-
for (const [
|
|
57
|
+
for (const [, Plugin] of cds.add.registered) {
|
|
50
58
|
task.options.push(...Object.keys((new Plugin).options()).map(key => '--'+key))
|
|
51
59
|
}
|
|
52
60
|
}
|
|
@@ -130,6 +138,7 @@ async function _resolveBindings(options) {
|
|
|
130
138
|
const bindingEnv = await bindingManager.bindingEnv()
|
|
131
139
|
Object.assign(process.env, bindingEnv)
|
|
132
140
|
cds.env = cds.env.for('cds') // reload env // FIXME: This is too early!
|
|
141
|
+
cds.requires = cds.env.requires // REVISIT: We should clean this up!
|
|
133
142
|
}
|
|
134
143
|
|
|
135
144
|
function _local (id, _else) {
|
|
@@ -160,15 +169,7 @@ function _dieForUnknownCommand(cmd) {
|
|
|
160
169
|
|
|
161
170
|
let bestMatchText = '';
|
|
162
171
|
|
|
163
|
-
const
|
|
164
|
-
const { readdirSync } = require('fs');
|
|
165
|
-
const { resolve } = require('path');
|
|
166
|
-
let commands = readdirSync(__dirname, { withFileTypes: true })
|
|
167
|
-
.concat(readdirSync(resolve(_local('@sap/cds'), '..', '..', 'bin'), { withFileTypes: true }))
|
|
168
|
-
.filter((f) => !excludeList.includes(f.name))
|
|
169
|
-
.map((f) => f.name.split('.')[0])
|
|
170
|
-
commands = [...new Set(commands)] // make unique
|
|
171
|
-
.sort();
|
|
172
|
+
const commands = getCommands();
|
|
172
173
|
|
|
173
174
|
const bestMatches = fuzzySearch(cmd, commands, DEBUG);
|
|
174
175
|
|
|
@@ -192,9 +193,7 @@ function _dieForUnknownCommand(cmd) {
|
|
|
192
193
|
|
|
193
194
|
You can use ${term.bold("cds help [command]")} to get more information on the command.
|
|
194
195
|
`
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
process.exit(1)
|
|
196
|
+
throw msg;
|
|
198
197
|
}
|
|
199
198
|
|
|
200
199
|
function _require (id,o) {
|
|
@@ -211,4 +210,24 @@ module.exports = Object.assign ((..._) => cli.exec(..._), cli)
|
|
|
211
210
|
|
|
212
211
|
if (!module.parent) module.exports()
|
|
213
212
|
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
function getCommands() {
|
|
216
|
+
const fs = require('fs');
|
|
217
|
+
const path = require('path');
|
|
218
|
+
|
|
219
|
+
const excludeList = ['cds.js', 'cds-ts.js', 'fix-redirects.js'];
|
|
220
|
+
|
|
221
|
+
const files = fs.readdirSync(__dirname, { withFileTypes: true, encoding: 'utf8' })
|
|
222
|
+
const result = new Set()
|
|
223
|
+
for (const f of files) {
|
|
224
|
+
if (!excludeList.includes(f.name)) {
|
|
225
|
+
if (f.isDirectory() && fs.existsSync(path.join(__dirname, f.name, 'index.js')) || f.isFile() && f.name.endsWith('.js')) {
|
|
226
|
+
result.add(path.parse(f.name).name)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return Array.from(result).sort()
|
|
231
|
+
}
|
|
232
|
+
|
|
214
233
|
/* eslint no-console:off */
|
package/bin/compile/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
|
|
3
3
|
module.exports = Object.assign ( compile, {
|
|
4
|
+
handleCompletion,
|
|
4
5
|
options: [
|
|
5
6
|
'--from', '--service', '--lang', '--for', '--to', '--dest', '--log-level', '--flavor', '--dialect', '--sql-dialect', '--openapi:url', '--openapi:servers', '--odata-version'
|
|
6
7
|
],
|
|
@@ -53,13 +54,13 @@ module.exports = Object.assign ( compile, {
|
|
|
53
54
|
|
|
54
55
|
- odata
|
|
55
56
|
- sql
|
|
56
|
-
|
|
57
|
+
|
|
57
58
|
*--dialect* <dialect>
|
|
58
|
-
|
|
59
|
+
|
|
59
60
|
Needs option *--to*.
|
|
60
61
|
Specify the dialect in combination with *--to sql*.
|
|
61
62
|
Currently supported:
|
|
62
|
-
|
|
63
|
+
|
|
63
64
|
- sqlite
|
|
64
65
|
- h2
|
|
65
66
|
- postgres
|
|
@@ -147,6 +148,46 @@ module.exports = Object.assign ( compile, {
|
|
|
147
148
|
|
|
148
149
|
`})
|
|
149
150
|
|
|
151
|
+
async function handleCompletion(currentWord, previousWord, argv, util) {
|
|
152
|
+
const allOptionsFlags = [
|
|
153
|
+
...compile.options ?? [],
|
|
154
|
+
...compile.flags ?? []
|
|
155
|
+
].filter(e => !argv.includes(e))
|
|
156
|
+
|
|
157
|
+
if (currentWord?.startsWith('-')) { return allOptionsFlags }
|
|
158
|
+
|
|
159
|
+
switch (previousWord) {
|
|
160
|
+
case '-2':
|
|
161
|
+
case '--to':
|
|
162
|
+
return ['json', 'yml', 'edm', 'edmx', 'edmx-v2', 'edmx-v4', 'sql', 'hdbcds', 'hdbtable', 'cdl', 'xsuaa', 'openapi', 'asyncapi'];
|
|
163
|
+
case '-4':
|
|
164
|
+
case '--for':
|
|
165
|
+
return ['odata', 'sql'];
|
|
166
|
+
case '--dialect':
|
|
167
|
+
return ['sqlite', 'h2', 'postgres', 'hana'];
|
|
168
|
+
case '--log-level':
|
|
169
|
+
return ['debug', 'info', 'warn', 'error'];
|
|
170
|
+
case '--odata-version':
|
|
171
|
+
return ['4.0', '4.01'];
|
|
172
|
+
case '-f':
|
|
173
|
+
case '--flavor':
|
|
174
|
+
return ['sources', 'files', 'parsed', 'xtended', 'inferred'];
|
|
175
|
+
case '-s':
|
|
176
|
+
case '--service':
|
|
177
|
+
case '-l':
|
|
178
|
+
case '--lang':
|
|
179
|
+
return ['all'];
|
|
180
|
+
case '-o':
|
|
181
|
+
case '--dest':
|
|
182
|
+
return util.completionFs.readdir(currentWord, { files: false })
|
|
183
|
+
default:
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!currentWord && compile.options?.includes(previousWord)) { return [] }
|
|
187
|
+
|
|
188
|
+
return util.completionFs.readdir(currentWord, { fileRegex: /\.(cds|json)/ })
|
|
189
|
+
}
|
|
190
|
+
|
|
150
191
|
async function compile_all (root='.') {
|
|
151
192
|
|
|
152
193
|
const {exec} = require ('child_process')
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module.exports = new class CompletionFS {
|
|
2
|
+
async readdir(currentFolder, options) {
|
|
3
|
+
options = {
|
|
4
|
+
files: true,
|
|
5
|
+
folders: true,
|
|
6
|
+
fileRegex: /.*/,
|
|
7
|
+
folderRegex: /.*/,
|
|
8
|
+
...options
|
|
9
|
+
}
|
|
10
|
+
const fsp = require('node:fs/promises');
|
|
11
|
+
const path = require('node:path');
|
|
12
|
+
|
|
13
|
+
const match = /\/|(\\)[^\s]/.exec(currentFolder);
|
|
14
|
+
const separationChar = match?.[1] || match?.[0] || '/';
|
|
15
|
+
let folder = currentFolder || process.cwd();
|
|
16
|
+
|
|
17
|
+
let entries;
|
|
18
|
+
try {
|
|
19
|
+
entries = await fsp.readdir(folder, { withFileTypes: true });
|
|
20
|
+
} catch (err) {
|
|
21
|
+
folder = path.dirname(folder);
|
|
22
|
+
entries = await fsp.readdir(folder, { withFileTypes: true });
|
|
23
|
+
}
|
|
24
|
+
const isCwd = folder === '.' || folder === process.cwd();
|
|
25
|
+
|
|
26
|
+
entries = entries
|
|
27
|
+
.filter(e =>
|
|
28
|
+
options.folders && e.isDirectory() && e.name.match(options.folderRegex)
|
|
29
|
+
|| options.files && e.isFile() && e.name.match(options.fileRegex))
|
|
30
|
+
.map(e => {
|
|
31
|
+
let result = isCwd
|
|
32
|
+
? path.relative(folder, e.name)
|
|
33
|
+
: (folder + separationChar + e.name).replace(/\\{2,}/g, '\\').replace(/\/{2,}/g, '/');
|
|
34
|
+
|
|
35
|
+
if (e.isDirectory()) {
|
|
36
|
+
result += separationChar;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return result;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (entries.length === 0) {
|
|
43
|
+
entries.push(folder);
|
|
44
|
+
}
|
|
45
|
+
return entries;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
async readTemplates(argv) {
|
|
49
|
+
const fsp = require('node:fs/promises');
|
|
50
|
+
const path = require('node:path');
|
|
51
|
+
|
|
52
|
+
const excludes = ['nodejs', 'java', ...argv];
|
|
53
|
+
|
|
54
|
+
return (await fsp.readdir(path.join(__dirname, '../../lib/init/template'), { withFileTypes: true }))
|
|
55
|
+
.filter(e =>
|
|
56
|
+
e.isDirectory()
|
|
57
|
+
&& !e.name.startsWith('_')
|
|
58
|
+
&& !excludes.includes(e.name))
|
|
59
|
+
.map(e => e.name);
|
|
60
|
+
}
|
|
61
|
+
}
|