@sap/cds-dk 9.3.2 → 9.4.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/CHANGELOG.md +41 -0
- package/bin/bind.js +1 -1
- package/bin/cds.js +3 -0
- package/bin/compile/index.js +53 -3
- package/bin/data-products/get-csn-via-dp-cli.js +41 -0
- package/bin/data-products/get-csn.js +76 -0
- package/bin/data-products/import.js +114 -0
- package/bin/data-products/index.js +30 -0
- package/bin/data-products/merge-csns.js +46 -0
- package/bin/data-products/prepare-csn.js +282 -0
- package/bin/data-products/prepare-files.js +69 -0
- package/bin/export.js +240 -0
- package/bin/help/export.md +37 -0
- package/bin/help/import.md +11 -0
- package/bin/help/minify.md +23 -0
- package/bin/import.js +13 -3
- package/bin/inspect.js +226 -0
- package/bin/minify.js +123 -0
- package/bin/util/cli.js +132 -0
- package/bin/util/log.js +2 -0
- package/bin/version.js +2 -1
- package/bin/watch.js +21 -3
- package/lib/bind/shared.js +3 -1
- package/lib/build/buildTaskEngine.js +2 -1
- package/lib/build/plugins/helm/files/templates/NOTES.txt +1 -1
- package/lib/build/plugins/helm/index.js +1 -1
- package/lib/build/provider/internalBuildTaskProvider.js +3 -3
- package/lib/build/provider/nodejs/index.js +62 -3
- package/lib/deploy/index.js +1 -1
- package/lib/deploy/to-hana/hana.js +18 -16
- package/lib/import/odata/v2parser.js +2 -2
- package/lib/import/odata/v4parser.js +21 -2
- package/lib/import/odata.package.json +4 -4
- package/lib/init/constants.js +2 -1
- package/lib/init/index.js +2 -0
- package/lib/init/mvn.js +3 -2
- package/lib/init/projectReader.js +1 -0
- package/lib/init/registries/mta.js +6 -0
- package/lib/init/template/ams/files/manifest.yml.hbs +1 -1
- package/lib/init/template/ams/files/mta.yaml.hbs +1 -1
- package/lib/init/template/app-frontend/files/app-package.json.hbs +20 -0
- package/lib/init/template/app-frontend/files/index.html.hbs +34 -0
- package/lib/init/template/app-frontend/files/manifest.json +13 -0
- package/lib/init/template/app-frontend/files/mta.yaml.hbs +71 -0
- package/lib/init/template/app-frontend/files/package.json.hbs +17 -0
- package/lib/init/template/app-frontend/files/ui5-deploy.yaml.hbs +25 -0
- package/lib/init/template/app-frontend/files/ui5.yaml.hbs +6 -0
- package/lib/init/template/app-frontend/files/values.yaml.hbs +20 -0
- package/lib/init/template/app-frontend/files/xs-app.json.hbs +17 -0
- package/lib/init/template/app-frontend/index.js +98 -0
- package/lib/init/template/approuter/files/mta.yaml.hbs +0 -2
- package/lib/init/template/attachments/index.js +4 -10
- package/lib/init/template/audit-logging/files/package.json.hbs +5 -0
- package/lib/init/template/handler/index.js +1 -0
- package/lib/init/template/helm/index.js +5 -1
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +7 -2
- package/lib/init/template/ias/files/manifest.yml.hbs +1 -1
- package/lib/init/template/ias/files/mta.yaml.hbs +6 -5
- package/lib/init/template/ias/files/values.yaml.hbs +10 -1
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +16 -3
- package/lib/init/template/multitenancy/files/package.json.hbs +5 -0
- package/lib/init/template/multitenancy/files/values.yaml.hbs +1 -6
- package/lib/init/template/portal/files/mta.yaml.hbs +12 -2
- package/lib/init/template/sample/files/db/schema.cds +5 -8
- package/lib/init/template/typer/files/xsconfig.json +2 -1
- package/lib/init/template/typescript/files/package.json +1 -1
- package/lib/init/template/typescript/files/tsconfig.json +4 -1
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +4 -0
- package/lib/init/template/workzone-standard/index.js +3 -2
- package/lib/init/template/xsuaa/files/package.json.hbs +3 -0
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/util/term.js +2 -4
- package/npm-shrinkwrap.json +25 -25
- package/package.json +1 -1
package/bin/import.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
module.exports = Object.assign(_import, {
|
|
2
2
|
_name: 'import',
|
|
3
|
-
options: ['--for', '--out', '--as', '--name', '--include-namespaces', '--dependencies', '--from', '--config', '--destination', '--group'],
|
|
4
|
-
shortcuts: ['-4', '-o', '-as', '-n', '-ns', '-d', undefined, '-c', undefined, undefined, '-', '-f'],
|
|
5
|
-
flags: ['--dry', '--force', '--no-copy', '--no-save', '--keep-namespace'],
|
|
3
|
+
options: [ '--services', '--for', '--out', '--as', '--name', '--include-namespaces', '--dependencies', '--from', '--config', '--destination', '--group' ],
|
|
4
|
+
shortcuts: [ '-s', '-4', '-o', '-as', '-n', '-ns', '-d', undefined, '-c', undefined, undefined, '-', '-f'],
|
|
5
|
+
flags: [ '--dry', '--force', '--no-copy', '--no-save', '--keep-namespace', '--data-product', '--edmx', '--rfc', '--odata', '--openapi', '--asyncapi' ],
|
|
6
6
|
help: `
|
|
7
7
|
# SYNOPSIS
|
|
8
8
|
|
|
@@ -121,6 +121,11 @@ async function _import(args, options = {}) {
|
|
|
121
121
|
await cds.plugins
|
|
122
122
|
const cwd = process.cwd();
|
|
123
123
|
|
|
124
|
+
if (options['data-product']) {
|
|
125
|
+
const import_ = require ('./data-products/import.js')
|
|
126
|
+
return import_.exec (this)
|
|
127
|
+
}
|
|
128
|
+
|
|
124
129
|
// process options
|
|
125
130
|
const apiOptions = {};
|
|
126
131
|
await common.processOptions(options, apiOptions);
|
|
@@ -140,6 +145,11 @@ async function _import(args, options = {}) {
|
|
|
140
145
|
}
|
|
141
146
|
|
|
142
147
|
let csn
|
|
148
|
+
if (options.edmx) options.from = 'edmx'
|
|
149
|
+
else if (options.odata) options.from = 'edmx'
|
|
150
|
+
else if (options.openapi) options.from = 'openapi'
|
|
151
|
+
else if (options.asyncapi) options.from = 'asyncapi'
|
|
152
|
+
else if (options.rfc) options.from = 'rfc'
|
|
143
153
|
if (options.from) {
|
|
144
154
|
if (!cds.import.from[options.from]) {
|
|
145
155
|
// the required plugin might not be installed, e.g. rfc importer
|
package/bin/inspect.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
/* USAGE:
|
|
3
|
+
cds inspect model.Req
|
|
4
|
+
cds inspect model.Requisition --ids
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
module.exports = Object.assign (inspect, {
|
|
8
|
+
options: [ '--stats', '--list', '--kind' ],
|
|
9
|
+
shortcuts: [ '-s', '-l', '-k' ],
|
|
10
|
+
help: `
|
|
11
|
+
# SYNOPSIS
|
|
12
|
+
|
|
13
|
+
*cds inspect* [ <options> ]
|
|
14
|
+
|
|
15
|
+
Inspects the cds models of a project, or a specific definition.
|
|
16
|
+
Without arguments shows --stats a summary of your models.
|
|
17
|
+
|
|
18
|
+
You can list all definitions, and thereby filter the listed definitions
|
|
19
|
+
by kind, and/or a name pattern, using wildcards like * and ?.
|
|
20
|
+
|
|
21
|
+
For a specific definition you can list its elements, keys, associations,
|
|
22
|
+
compositions, or IDs using --list. It also shows where the definition
|
|
23
|
+
is inherited from, and counts of its elements.
|
|
24
|
+
|
|
25
|
+
See examples below.
|
|
26
|
+
|
|
27
|
+
# OPTIONS
|
|
28
|
+
|
|
29
|
+
*-s | --stats*
|
|
30
|
+
|
|
31
|
+
Shows a summary of the kinds of definitions found.
|
|
32
|
+
|
|
33
|
+
*-l | --list* <names|elements|keys|associations|compositions|ids>
|
|
34
|
+
|
|
35
|
+
Lists the specified kind of elements of a specific definition.
|
|
36
|
+
|
|
37
|
+
*-k | --kind* <entity|type|service|...>
|
|
38
|
+
|
|
39
|
+
Filters the listed definitions by kind.
|
|
40
|
+
|
|
41
|
+
# EXAMPLES
|
|
42
|
+
|
|
43
|
+
*cds inspect*
|
|
44
|
+
*cds inspect* --stats
|
|
45
|
+
*cds inspect* --kind aspect
|
|
46
|
+
*cds inspect* --list all
|
|
47
|
+
*cds inspect* --list names --kind entity
|
|
48
|
+
*cds inspect* --list names model.Req*
|
|
49
|
+
*cds inspect* requisition.model.Requisition
|
|
50
|
+
*cds inspect* requisition.model.Requisition --list elements
|
|
51
|
+
*cds inspect* requisition.model.Requisition --list ids
|
|
52
|
+
*cds inspect* requisition.model.Requisition --list keys
|
|
53
|
+
*cds inspect* requisition.model.Requisition --list associations
|
|
54
|
+
*cds inspect* requisition.model.Requisition --list compositions
|
|
55
|
+
`})
|
|
56
|
+
|
|
57
|
+
async function inspect(){
|
|
58
|
+
|
|
59
|
+
const cds = require ('../lib/cds')
|
|
60
|
+
const path = require ('node:path')
|
|
61
|
+
|
|
62
|
+
const { YELLOW, GREEN, CYAN, RED, GRAY, RESET } = cds.utils.colors
|
|
63
|
+
const i2 = ' '.repeat(2)
|
|
64
|
+
const i4 = ' '.repeat(4)
|
|
65
|
+
const args = process.argv.slice(3)
|
|
66
|
+
|
|
67
|
+
const option = (...oo) => {
|
|
68
|
+
for (let o of oo) {
|
|
69
|
+
const i = args.indexOf(o)
|
|
70
|
+
if (i>=0) return args.splice(i,2)[1] || ''
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const fetch = { __proto__: {
|
|
75
|
+
get 'id elements' () { return this.ids },
|
|
76
|
+
},
|
|
77
|
+
names: () => true,
|
|
78
|
+
elements: () => true,
|
|
79
|
+
ids: e => e.name.match(/(ID|Id|id$)/),
|
|
80
|
+
keys: e => e.key,
|
|
81
|
+
associations: a => a.isAssociation && !a.isComposition,
|
|
82
|
+
compositions: a => a.isComposition,
|
|
83
|
+
'to-many': a => a.is2many,
|
|
84
|
+
'to-one': a => a.is2one,
|
|
85
|
+
unmanaged: a => a.is2one && a.on,
|
|
86
|
+
virtuals: e => e.virtual,
|
|
87
|
+
calculated: e => e.value,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
const $location = d => {
|
|
92
|
+
if (Object.hasOwn(d,'$location')) return d.$location.file+':'+d.$location.line
|
|
93
|
+
let includes = d.parent?.includes; if (!includes) return ''
|
|
94
|
+
for (let inc of includes) {
|
|
95
|
+
let e = csn.definitions[inc]?.elements?.[d.name]
|
|
96
|
+
if (e) return $location(e)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const csn = await cds.load('*').then(cds.linked)
|
|
101
|
+
let defs = Object.values (csn.definitions)
|
|
102
|
+
|
|
103
|
+
const kinds = {
|
|
104
|
+
entities: 'entity',
|
|
105
|
+
aspects: 'aspect',
|
|
106
|
+
types: 'type',
|
|
107
|
+
services: 'service',
|
|
108
|
+
events: 'event',
|
|
109
|
+
actions: 'action',
|
|
110
|
+
functions: 'function',
|
|
111
|
+
contexts: 'context',
|
|
112
|
+
all: undefined,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let kind = option ('-k','--kind')
|
|
116
|
+
let list = option ('-l','--list')
|
|
117
|
+
let stats = option ('-s','--stats')
|
|
118
|
+
if (list in kinds) [kind,list] = [kinds[list],'names']
|
|
119
|
+
if (kind) defs = defs.filter (d => d.kind === kind)
|
|
120
|
+
if (process.argv.length < 4) stats = true
|
|
121
|
+
|
|
122
|
+
const regexp4 = pattern => RegExp (pattern.replace(/\./g, '\\.').replace(/\*/g, '.*'))
|
|
123
|
+
for (let pattern of args) {
|
|
124
|
+
const regexp = regexp4(pattern || '.*')
|
|
125
|
+
defs = defs.filter (d => regexp.test(d.name))
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
console.log()
|
|
129
|
+
if (stats !== undefined) {
|
|
130
|
+
|
|
131
|
+
const count = (kind,f) => {
|
|
132
|
+
let n = defs.filter(f).length; if (!n) return
|
|
133
|
+
if (kind === 'entities') for (let each of ['.texts','.drafts']) {
|
|
134
|
+
let n = defs.filter(d => d.name.endsWith(each)).length
|
|
135
|
+
if (n) kind += ` - ${YELLOW}${n}${GRAY} ${each}`
|
|
136
|
+
}
|
|
137
|
+
if (n) console.log (YELLOW, n.toString().padStart(4,' '), GRAY + kind)
|
|
138
|
+
}
|
|
139
|
+
for (let k in kinds) count (k, d => d.kind === kinds[k])
|
|
140
|
+
console.log (GRAY, '-'.repeat(14), RESET)
|
|
141
|
+
console.log (YELLOW, defs.length.toString().padStart(4,' '), GRAY + 'in total')
|
|
142
|
+
|
|
143
|
+
} else {
|
|
144
|
+
defs = defs.filter (d => !d.name.match(/\.(texts|drafts)$/))
|
|
145
|
+
switch (list) {
|
|
146
|
+
|
|
147
|
+
case 'names':
|
|
148
|
+
const pad = kind?.length || 7 // eslint-disable-line no-case-declarations
|
|
149
|
+
defs.forEach (d => console.log (i2, RED + d.kind.padEnd(pad), GREEN + d.name))
|
|
150
|
+
console.log(GRAY+i2, '-'.repeat(27), RESET)
|
|
151
|
+
console.log(GRAY+i2, 'Total:', YELLOW + defs.length, GRAY + 'definitions')
|
|
152
|
+
break;
|
|
153
|
+
|
|
154
|
+
case 'sources':
|
|
155
|
+
csn.$sources.forEach(f => console.log (GRAY+i2, path.relative(cds.root,f)))
|
|
156
|
+
break;
|
|
157
|
+
|
|
158
|
+
default:
|
|
159
|
+
defs.forEach (inspect)
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
console.log(RESET)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
function inspect (d) {
|
|
167
|
+
|
|
168
|
+
console.log(GRAY+i2, '-'.repeat(79), RESET)
|
|
169
|
+
console.log(GRAY+i2, 'Inspecting', RED + d.kind, GREEN + d.name, RESET)
|
|
170
|
+
console.log(GRAY+i2, '( declared at'+ CYAN, $location(d), GRAY+')', RESET)
|
|
171
|
+
console.log()
|
|
172
|
+
|
|
173
|
+
if (list !== undefined) {
|
|
174
|
+
const filter = fetch [list]
|
|
175
|
+
if (!filter) return console.error (RED, 'ERROR:'+ RESET, 'Use --list with one of:\n\n ', Object.keys(fetch).join('\n '), RESET)
|
|
176
|
+
const elements = Object.values(d.elements??{}).filter(filter)
|
|
177
|
+
const pad = elements.reduce((p, e) => Math.max(p, e.name.length), 0)
|
|
178
|
+
for (let e of elements) {
|
|
179
|
+
console.log (i4, GRAY + '-', YELLOW + e.name.padEnd(pad), GRAY, $location(e))
|
|
180
|
+
}
|
|
181
|
+
return console.log()
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
count(d.elements, 'keys')
|
|
185
|
+
count(d.elements, 'id elements')
|
|
186
|
+
count(d.elements, 'elements')
|
|
187
|
+
count(d.elements, 'associations', 'to-many', 'unmanaged')
|
|
188
|
+
count(d.elements, 'compositions', 'to-many')
|
|
189
|
+
count(d.elements, 'virtuals')
|
|
190
|
+
count(d.elements, 'calculated')
|
|
191
|
+
|
|
192
|
+
if (d.includes) {
|
|
193
|
+
console.log(RESET + '\n', i2, 'inherits: \n')
|
|
194
|
+
inheritance(d)
|
|
195
|
+
}
|
|
196
|
+
console.log()
|
|
197
|
+
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function inheritance (d, indent = '') {
|
|
201
|
+
if (d.includes) for (let each of d.includes) {
|
|
202
|
+
let d = csn.definitions[each]
|
|
203
|
+
console.log(i4, ' -', count(d.elements), GRAY + 'elements from' + indent, RED + d.kind, GREEN + d.name, RESET)
|
|
204
|
+
inheritance(d, indent + i2)
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function count (defs, kind, ...more) {
|
|
209
|
+
if (!defs) return
|
|
210
|
+
if (!Array.isArray(defs)) defs = Object.values(defs)
|
|
211
|
+
if (kind) {
|
|
212
|
+
const filter = fetch[kind]
|
|
213
|
+
if (filter) defs = defs.filter(filter)
|
|
214
|
+
if (!defs.length) return
|
|
215
|
+
}
|
|
216
|
+
let info = YELLOW+ defs.length.toString().padStart(3, ' ')
|
|
217
|
+
if (kind) info += GRAY + ' ' + kind; else return info
|
|
218
|
+
for (let kind of more) {
|
|
219
|
+
let filter = fetch[kind] || fetch[kind.replace(/-/g,'_')]
|
|
220
|
+
let n = defs.filter(filter).length
|
|
221
|
+
if (n) info += ', '+ YELLOW + defs.filter(filter).length + GRAY+' ' + kind
|
|
222
|
+
}
|
|
223
|
+
console.log (i4, info, GRAY)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
}
|
package/bin/minify.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const cds = require ('../lib/cds.js')
|
|
3
|
+
const { Minifier } = cds.minify; if (!Minifier) throw new Error ('@sap/cds >= 9.4.0 required for this command')
|
|
4
|
+
const { Command } = require ('./util/cli.js')
|
|
5
|
+
const { inspect } = require ('node:util')
|
|
6
|
+
|
|
7
|
+
class Minify extends Command {
|
|
8
|
+
|
|
9
|
+
options = Minify.options // for IntelliSense
|
|
10
|
+
static options = {
|
|
11
|
+
cleanse: { _excluding: 'keep' },
|
|
12
|
+
keep: { _excluding: 'skip',
|
|
13
|
+
aspect: false,
|
|
14
|
+
entity: true,
|
|
15
|
+
event: true,
|
|
16
|
+
type: false,
|
|
17
|
+
action: true,
|
|
18
|
+
function: true,
|
|
19
|
+
},
|
|
20
|
+
skip: {},
|
|
21
|
+
dry: false,
|
|
22
|
+
debug: false,
|
|
23
|
+
inspect: false,
|
|
24
|
+
}
|
|
25
|
+
static shortcuts = { skip:'x', dry:'y' }
|
|
26
|
+
static filename = __filename
|
|
27
|
+
|
|
28
|
+
parseArgs (conf) {
|
|
29
|
+
let [sources,o] = super.parseArgs (conf)
|
|
30
|
+
this.sources = sources.length ? o.from = sources : sources = o.from || '*'
|
|
31
|
+
return [sources,o]
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async exec ( args, options ) {
|
|
35
|
+
let [sources,o] = this.parseArgs ({ args, options })
|
|
36
|
+
try {
|
|
37
|
+
let csn = await this.load (sources,o); this.csn = csn
|
|
38
|
+
let min = await this.minify (csn,o); this.min = min
|
|
39
|
+
if (o.dry) return
|
|
40
|
+
if (o.inspect) return this.inspect (min,o)
|
|
41
|
+
if (this.print) return this.print (min)
|
|
42
|
+
else await this.export (min,o)
|
|
43
|
+
console.log()
|
|
44
|
+
} catch (e) {
|
|
45
|
+
if (typeof e === 'string') return console.error (e)
|
|
46
|
+
if (e.code) return console.error (e.message)
|
|
47
|
+
else throw e
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Subclasses override this method to provide custom loading behavior.
|
|
53
|
+
*/
|
|
54
|
+
async load (sources,o) { // eslint-disable-line no-unused-vars
|
|
55
|
+
return cds.load (sources)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Subclasses override this method to provide custom cleansing behavior.
|
|
60
|
+
*/
|
|
61
|
+
async cleanse (csn,o) { // eslint-disable-line no-unused-vars
|
|
62
|
+
return csn
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Subclasses override this method to provide custom minification behavior.
|
|
67
|
+
*/
|
|
68
|
+
async minify (csn,o) {
|
|
69
|
+
let m = this.minifier ??= o.dry ? new Dryifier(csn) : new Minifier()
|
|
70
|
+
csn = await this.cleanse (csn,o)
|
|
71
|
+
return m.minify (csn,o)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Subclasses override this method to generate exported artifacts.
|
|
76
|
+
*/
|
|
77
|
+
export (csn,o) {} // eslint-disable-line no-unused-vars
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Subclasses override this method to provide custom print behavior.
|
|
81
|
+
*/
|
|
82
|
+
print (csn,o) { // eslint-disable-line no-unused-vars
|
|
83
|
+
console.log (cds.compile.to.json (csn))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
inspect (csn, {inspect:depth} = this.options) {
|
|
87
|
+
const colors = cds.utils.colors.enabled
|
|
88
|
+
console.log (inspect (cds.linked(csn), { depth, colors }))
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Custom minifier to capture kept definitions in dry run mode
|
|
95
|
+
*/
|
|
96
|
+
class Dryifier extends Minifier {
|
|
97
|
+
|
|
98
|
+
constructor(csn) { super(); this.all = Object.keys (csn.definitions) }
|
|
99
|
+
capture = {}
|
|
100
|
+
level = 0
|
|
101
|
+
|
|
102
|
+
keep (each,d) {
|
|
103
|
+
if (each in this.kept) return; else this.capture[each] = ++this.level
|
|
104
|
+
super.keep (each, d)
|
|
105
|
+
this.level--
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
minify (csn,o) {
|
|
109
|
+
const { GREEN, GRAY, DIMMED, RESET } = cds.utils.colors
|
|
110
|
+
const min = super.minify (csn, o)
|
|
111
|
+
const kept = Object.keys(this.capture)
|
|
112
|
+
console.log (RESET+'\n', 'Keep:', kept.length, '\n')
|
|
113
|
+
for (let [ each, level ] of Object.entries(this.capture))
|
|
114
|
+
console.log (' '+GRAY,'•'.repeat(level)+GREEN, each, RESET)
|
|
115
|
+
console.log (RESET+'\n', 'Skip:', this.all.length - kept.length, '\n')
|
|
116
|
+
for (let each of this.all)
|
|
117
|
+
each in this.capture || console.log (DIMMED, ' -', each, RESET)
|
|
118
|
+
console.log (RESET+'\n', 'Total:', this.all.length, '\n')
|
|
119
|
+
return min
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = Object.assign (Minify._for_cds_dk(), { Minify })
|
package/bin/util/cli.js
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
const { parseArgs } = require ('node:util')
|
|
2
|
+
const path = require ('node:path')
|
|
3
|
+
const fs = require ('node:fs')
|
|
4
|
+
|
|
5
|
+
class Command { static filename = __filename // to be overridden in subclasses
|
|
6
|
+
|
|
7
|
+
get class(){ return this.constructor }
|
|
8
|
+
get name(){ return this.class.name }
|
|
9
|
+
|
|
10
|
+
/** @type <T>(defaults: T) => [ string[], T ] */
|
|
11
|
+
parseArgs (conf) {
|
|
12
|
+
|
|
13
|
+
const args = conf.args || process.argv.slice(2)
|
|
14
|
+
const shorts = { ...this.class.shortcuts, ...conf.shortcuts }
|
|
15
|
+
const options = { ...this.class.options, ...conf.options, help:false }
|
|
16
|
+
for (let k in options) options[k] = option4 (options[k]) .short (shorts[k]||k[0])
|
|
17
|
+
|
|
18
|
+
// parse the CLI args with node:util.parseArgs
|
|
19
|
+
const { positionals:p, values:o } = parseArgs ({
|
|
20
|
+
allowPositionals: true, strict: false, ...conf,
|
|
21
|
+
args, options,
|
|
22
|
+
})
|
|
23
|
+
this.positionals = p
|
|
24
|
+
this.options = o
|
|
25
|
+
|
|
26
|
+
// convert the parsed values according to the options
|
|
27
|
+
for (let k in o) {
|
|
28
|
+
const v = options[k]; if (!v) continue
|
|
29
|
+
if (v.convert) o[k] = v.convert (o[k],o)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// help / debug
|
|
33
|
+
if (o.help || args == '?' || !args.length) throw this.help()
|
|
34
|
+
if (o.debug) throw this.debug()
|
|
35
|
+
|
|
36
|
+
// parsed
|
|
37
|
+
return [ this.positionals, this.options ]
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
usage() {
|
|
41
|
+
const source = this.class.filename; if (!source) return super.usage = undefined
|
|
42
|
+
const { dir, name } = path.parse (source)
|
|
43
|
+
const md = path.join(dir,'help',name+'.md')
|
|
44
|
+
return super.usage = fs.readFileSync (md,'utf8')
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
help (usage = this.usage()) {
|
|
48
|
+
console.log (usage
|
|
49
|
+
.replace(/\n# ([^\n]*)\n/g, `\n\x1b[1m$1\x1b[0m\n`)
|
|
50
|
+
.replace(/ \*([^*]+)\*/g, ` \x1b[1m$1\x1b[0m`)
|
|
51
|
+
.replace(/ _([^_]+)_/g, ` \x1b[4m$1\x1b[0m`)
|
|
52
|
+
)
|
|
53
|
+
process.exit(0)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
debug (positionals = this.positionals, o = this.options) {
|
|
57
|
+
console.log('Debugging information:')
|
|
58
|
+
const shortcuts = {}, options = {...o}; delete options.o
|
|
59
|
+
for (let o in options) shortcuts[this.class.shortcuts[o] || o[0]] = o
|
|
60
|
+
console.log ({ positionals, options, shortcuts })
|
|
61
|
+
process.exit(0)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
static _for_cds_dk (cmd = this) {
|
|
65
|
+
return { _is_new_cmd: true,
|
|
66
|
+
options: Object.keys(this.options).map(o => '--'+o), // for shell completion
|
|
67
|
+
exec() { return (new cmd) .exec (process.argv.slice(3)) },
|
|
68
|
+
get help() { return (new cmd).usage() },
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
class Option {
|
|
75
|
+
constructor (spec) { Object.assign (this,spec) }
|
|
76
|
+
convert (x) { return x }
|
|
77
|
+
to(fn) { this.convert = fn; return this }
|
|
78
|
+
short(sc) { this.short = sc; return this }
|
|
79
|
+
get array() { this.multiple = true; return this }
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
class Flags extends Option {
|
|
83
|
+
constructor (defaults) {
|
|
84
|
+
super({
|
|
85
|
+
type: 'string',
|
|
86
|
+
multiple: true,
|
|
87
|
+
default: [],
|
|
88
|
+
defaults,
|
|
89
|
+
})
|
|
90
|
+
if (defaults._excluding) {
|
|
91
|
+
this.skip = defaults._excluding
|
|
92
|
+
delete defaults._excluding
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
convert (strings,o) {
|
|
96
|
+
const flags = { ...this.defaults }
|
|
97
|
+
const keep = strings4(strings).reduce?.((o,x)=>(o[x]=true,o),{}) || strings
|
|
98
|
+
if (keep.all) for (let x in this.defaults) flags[x] = true
|
|
99
|
+
if (this.skip) {
|
|
100
|
+
const skip = o[this.skip].reduce?.((o,x)=>(o[x]=true,o),{}) || o[this.skip]
|
|
101
|
+
if (skip.all) for (let x in this.defaults) delete flags[x]
|
|
102
|
+
else for (let x in skip) delete flags[x]
|
|
103
|
+
}
|
|
104
|
+
for (let x in keep) flags[x] = keep[x]
|
|
105
|
+
return flags
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const option4 = exports.option4 = (v) => {
|
|
110
|
+
if (v instanceof Option) return v
|
|
111
|
+
if (v instanceof RegExp) return pattern(v)
|
|
112
|
+
if (v instanceof Array) return strings(v)
|
|
113
|
+
if (v == null) return string('')
|
|
114
|
+
if (typeof v === 'string') return string(v)
|
|
115
|
+
if (typeof v === 'object') return flags(v)
|
|
116
|
+
if (typeof v === 'boolean') return flag(v)
|
|
117
|
+
if (typeof v === 'number') return number(v)
|
|
118
|
+
}
|
|
119
|
+
const option = exports.option = (x) => new Option (x)
|
|
120
|
+
const number = exports.number = d => string (String(d)).to(Number)
|
|
121
|
+
const pattern = exports.pattern = d => string (d.source !== '.' ? [d.source] : []) .array.to (regex4)
|
|
122
|
+
const strings = exports.strings = d => string (d.length ? d : undefined) .array.to (strings4)
|
|
123
|
+
const string = exports.string = d => option ({ type:'string', default:d })
|
|
124
|
+
const flag = exports.flag = d => option ({ type:'boolean', default:d })
|
|
125
|
+
const flags = exports.flags = (d,x) => new Flags (d,x)
|
|
126
|
+
const regex4 = exports.regex4 = raw => RegExp (strings4(raw).join('|')
|
|
127
|
+
.replaceAll ('.','\\.')
|
|
128
|
+
.replaceAll ('*','.*'),
|
|
129
|
+
'i')
|
|
130
|
+
const strings4 = exports.strings4 = raw => raw.length === 1 ? raw[0].split?.(',')||'' : raw
|
|
131
|
+
|
|
132
|
+
exports.Command = Command
|
package/bin/util/log.js
CHANGED
|
@@ -15,6 +15,8 @@ module.exports = (messages, options={}) => {
|
|
|
15
15
|
error: { Error:4, undefined:4 },
|
|
16
16
|
} [logLevel.toLowerCase()] || { Error:4, undefined:4, Warning:3 }
|
|
17
17
|
const log = options.log || console.error
|
|
18
|
+
// cds10: Remove cds.utils.colors.for check
|
|
19
|
+
if (log === console.error && cds.utils.colors.for) format.colors = cds.utils.colors.for(process.stderr).enabled
|
|
18
20
|
|
|
19
21
|
if (!Array.isArray (messages)) messages = [messages]
|
|
20
22
|
for (let m of messages.filter (m => m.severity in levels)) {
|
package/bin/version.js
CHANGED
|
@@ -145,7 +145,8 @@ function _pkg_path(id, ...paths) {
|
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
function capJavaVersion(cwd) {
|
|
148
|
-
const
|
|
148
|
+
const { MAVEN_ARCHETYPE_VERSION } = require('../lib/init/constants')
|
|
149
|
+
const cmd = `mvn com.sap.cds:cds-maven-plugin:${MAVEN_ARCHETYPE_VERSION}:version -B -ntp -Dcds.version.excludeCds -Dcds.version.json`
|
|
149
150
|
|
|
150
151
|
let out = ''
|
|
151
152
|
try {
|
package/bin/watch.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const watchOnlyOptions = ['--ext', '--livereload', '--open', '--debug', '--inspect', '--inspect-brk', '--include', '--exclude']
|
|
2
2
|
|
|
3
3
|
module.exports = Object.assign ( watch, {
|
|
4
|
-
flags: [ '--in-memory', '--in-memory?', '--with-mocks' ],
|
|
4
|
+
flags: [ '--in-memory', '--in-memory?', '--with-mocks', '--with-mtx' ],
|
|
5
5
|
options: [ '--port', ...watchOnlyOptions ],
|
|
6
6
|
help: `
|
|
7
7
|
# SYNOPSIS
|
|
@@ -51,6 +51,11 @@ module.exports = Object.assign ( watch, {
|
|
|
51
51
|
Specify from which profile(s) the binding information is taken.
|
|
52
52
|
*Example:* cds w --profile hybrid,production
|
|
53
53
|
|
|
54
|
+
*--with-mtx*
|
|
55
|
+
|
|
56
|
+
A shortcut for _--profile with-mtx_ to enable mtx features also in
|
|
57
|
+
development, while by default, these are only enabled in production.
|
|
58
|
+
|
|
54
59
|
*--debug* / *--inspect* <host:port | 127.0.0.1:9229>
|
|
55
60
|
|
|
56
61
|
Activate debugger on the given host:port.
|
|
@@ -67,11 +72,11 @@ module.exports = Object.assign ( watch, {
|
|
|
67
72
|
|
|
68
73
|
`})
|
|
69
74
|
|
|
75
|
+
const fs = require ('node:fs')
|
|
70
76
|
const cds = require('../lib/cds')
|
|
71
77
|
const DEBUG = /\b(y|all|cli|watch)\b/.test (process.env.DEBUG) ? ((..._) => console.debug ('[cli] -', ..._)) : undefined
|
|
72
78
|
const {delimiter,relative,resolve,sep} = require ('path')
|
|
73
79
|
const {codes} = require('../lib/util/term'), t = codes
|
|
74
|
-
const fs = require ('fs')
|
|
75
80
|
|
|
76
81
|
const escapedSep = sep === '\\' ? '\\\\' : sep // escape backslash for windows
|
|
77
82
|
const ignoreDefaults = [
|
|
@@ -99,6 +104,7 @@ async function watch ([cwd], {
|
|
|
99
104
|
const log = (first,...more) => console.log (t.yellow + (first||''), ...more, t.reset)
|
|
100
105
|
const paths4 = p => typeof p === 'string' ? p.split(',').map(p => p.trim()) : (p || [])
|
|
101
106
|
const included = paths4(include), excluded = paths4(exclude)
|
|
107
|
+
const isJava = fs.existsSync('pom.xml') && process.env.CDS_ENV !== 'node'
|
|
102
108
|
|
|
103
109
|
if (!Object.keys(options).includes('with-mocks')) args.push ('--with-mocks')
|
|
104
110
|
if (!Object.keys(options).find(a => /^in-memory\??$/.test(a))) args.push ('--in-memory?')
|
|
@@ -118,7 +124,8 @@ async function watch ([cwd], {
|
|
|
118
124
|
}
|
|
119
125
|
else cwd = cds.root
|
|
120
126
|
|
|
121
|
-
|
|
127
|
+
if (isJava) options.livereload = false
|
|
128
|
+
if (!isJava) log (`\n${t.bold}cds ${args.join(' ')}`)
|
|
122
129
|
|
|
123
130
|
const env = Object.assign (process.env, {
|
|
124
131
|
_args: JSON.stringify(args),
|
|
@@ -164,6 +171,17 @@ async function watch ([cwd], {
|
|
|
164
171
|
Object.assign(env, await bind.env({cwd}))
|
|
165
172
|
}
|
|
166
173
|
|
|
174
|
+
// if (isJava) {
|
|
175
|
+
// const { spawn } = require('node:child_process')
|
|
176
|
+
// const path = require('node:path')
|
|
177
|
+
// const cwd = path.join(cds.root, cds.env.folders.srv)
|
|
178
|
+
// const child = spawn('mvn', ['cds:watch'], { cwd, stdio: 'inherit' })
|
|
179
|
+
// child.on('close', (code) => {
|
|
180
|
+
// if (code !== 0) console.error(`mvn process exited with code ${code}`)
|
|
181
|
+
// })
|
|
182
|
+
// return
|
|
183
|
+
// }
|
|
184
|
+
|
|
167
185
|
const nodemon = require('../lib/watch/node-watch')
|
|
168
186
|
const watcher = nodemon ({
|
|
169
187
|
script: resolve(__dirname,'../lib/watch/watched'), cwd, env, ext, ignore, watched,
|
package/lib/bind/shared.js
CHANGED
|
@@ -82,7 +82,9 @@ async function bind(options = { on: 'cf' }) {
|
|
|
82
82
|
if (!requiresName) throw `unknown CDS service name for service ${bold(instance)} of kind ${bold(kind)} – please specify as argument for ${bold('cds bind')}`
|
|
83
83
|
resolved.name = requiresName
|
|
84
84
|
}
|
|
85
|
-
resolved.name ??= `custom-service:${instance || secret}`
|
|
85
|
+
if (exists('pom.xml')) resolved.name ??= `custom-service:${instance || secret}`
|
|
86
|
+
else resolved.name ??= `${instance || secret}`
|
|
87
|
+
|
|
86
88
|
const kindText = kind ? ` with kind ${bold(kind)}` : ''
|
|
87
89
|
console.log(`binding ${bold(resolved.name)} to ${plugin.displayName()} ${_bindingText(binding)}${kindText}`)
|
|
88
90
|
}
|
|
@@ -6,7 +6,7 @@ const { inspect } = require('node:util')
|
|
|
6
6
|
const cds = require('../cds'), { _log: log } = cds
|
|
7
7
|
const { sortMessagesSeverityAware, deduplicateMessages, CompilationError } = cds.compiler
|
|
8
8
|
const { relativePaths, BuildError, BuildMessage, resolveRequiredSapModels } = require('./util')
|
|
9
|
-
const { SEVERITIES, LOG_LEVELS } = require('./constants')
|
|
9
|
+
const { SEVERITIES, SEVERITY_ERROR, LOG_LEVELS } = require('./constants')
|
|
10
10
|
const BuildTaskFactory = require('./buildTaskFactory')
|
|
11
11
|
const InternalBuildPlugin = require('./provider/internalBuildPlugin')
|
|
12
12
|
const COMPILATION_ERROR = 'CompilationError'
|
|
@@ -195,6 +195,7 @@ class BuildTaskEngine {
|
|
|
195
195
|
const error = errors.find(e => e.constructor.name !== COMPILATION_ERROR)
|
|
196
196
|
if (error) {
|
|
197
197
|
// throw original BuildError including existing BuildMessages
|
|
198
|
+
error.messages = error.messages.map(m => typeof m === 'string' ? new BuildMessage(m, SEVERITY_ERROR) : m)
|
|
198
199
|
error.messages = this._sortMessagesUnique(pluginMessages.filter(m => m instanceof BuildMessage), error.messages)
|
|
199
200
|
throw error
|
|
200
201
|
}
|
|
@@ -8,7 +8,7 @@ Your services are available at:
|
|
|
8
8
|
{{- $deployment := (get $root.Values $name) }}
|
|
9
9
|
{{- if $deployment.expose.enabled }}
|
|
10
10
|
{{- $ := merge (dict "name" $name "deployment" $deployment) $root }}
|
|
11
|
-
{{- $url := include "cap.deploymentHostFull" $ }}
|
|
11
|
+
{{- $url := tpl (include "cap.deploymentHostFull" $) $ }}
|
|
12
12
|
{{ printf "%s - https://%s" $name $url }}
|
|
13
13
|
{{- end -}}
|
|
14
14
|
{{- end }}
|
|
@@ -39,7 +39,7 @@ module.exports = class HelmBuildPlugin extends Plugin {
|
|
|
39
39
|
const isInternal = chartYaml.dependencies?.find(dep => dep.name === 'web-application')?.repository !== undefined
|
|
40
40
|
|
|
41
41
|
if (!isInternal) {
|
|
42
|
-
// copy web
|
|
42
|
+
// copy web application helm chart
|
|
43
43
|
await this.copy(join(__dirname, 'files', 'subcharts', 'web-application')).to('charts/web-application')
|
|
44
44
|
|
|
45
45
|
// copy service instance helm chart
|
|
@@ -143,7 +143,7 @@ class InternalBuildTaskProvider extends BuildTaskProvider {
|
|
|
143
143
|
sidecarEnv = cds.env.for("cds", sidecarPath)
|
|
144
144
|
}
|
|
145
145
|
if (
|
|
146
|
-
cds.env.profiles?.includes('with-mtx-sidecar') || // new presets
|
|
146
|
+
cds.env.profiles?.includes('with-mtx-sidecar') || // new presets // FIXME: BAD hard-coded dependency to profile
|
|
147
147
|
cds.env.requires["cds.xt.ModelProviderService"]?.external // for compatibility with former mtxs presets
|
|
148
148
|
) {
|
|
149
149
|
DEBUG?.("MTX app with sidecar")
|
|
@@ -161,7 +161,7 @@ class InternalBuildTaskProvider extends BuildTaskProvider {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
if (sidecarEnv?.requires["cds.xt.ModelProviderService"]?._in_sidecar || sidecarEnv?.profiles?.includes('mtx-sidecar')) {
|
|
164
|
-
throw new BuildError(`MTX sidecar requires profile 'with-mtx-sidecar' in project root configuration.`)
|
|
164
|
+
throw new BuildError(`MTX sidecar requires profile 'with-mtx-sidecar' in project root configuration.`) // FIXME: BAD hard-coded dependency to profile
|
|
165
165
|
}
|
|
166
166
|
if (cds.env.requires["cds.xt.ModelProviderService"]?._in_sidecar || cds.env.profiles?.includes('mtx-sidecar')) {
|
|
167
167
|
// cds build is executed in sidecar folder
|
|
@@ -222,7 +222,7 @@ class InternalBuildTaskProvider extends BuildTaskProvider {
|
|
|
222
222
|
*/
|
|
223
223
|
static _isMtxs() {
|
|
224
224
|
return cds.env.requires.toggles
|
|
225
|
-
|| cds.env.profiles.includes('with-mtx-sidecar')
|
|
225
|
+
|| cds.env.profiles.includes('with-mtx-sidecar') // FIXME: BAD hard-coded dependency to profile
|
|
226
226
|
|| cds.env.requires['cds.xt.ModelProviderService']
|
|
227
227
|
|| (typeof cds.env.requires.multitenancy === "object")
|
|
228
228
|
}
|