@sap/cds-dk 8.4.2 → 8.5.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 -3
- package/bin/cds.js +49 -28
- package/bin/debug.js +90 -0
- package/bin/repl.js +50 -4
- package/bin/watch.js +13 -3
- package/lib/bind/userCdsrcJsonStorageProvider.js +0 -19
- package/lib/build/buildTaskEngine.js +4 -4
- package/lib/build/provider/hana/2migration.js +34 -20
- package/lib/build/provider/hana/index.js +74 -41
- package/lib/build/provider/internalBuildTaskProvider.js +1 -1
- package/lib/build/provider/mtx-extension/index.js +4 -4
- package/lib/build/provider/mtx-sidecar/index.js +2 -2
- package/lib/build/provider/nodejs/index.js +3 -19
- package/lib/build/util.js +41 -17
- package/lib/cds.js +10 -2
- package/lib/deploy/to-hana/hdiDeployUtil.js +14 -10
- package/lib/import/message.js +2 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +5 -0
- package/lib/import/odata/v4parser.js +32 -43
- package/lib/init/add.js +26 -0
- package/lib/init/constants.js +5 -6
- package/lib/init/index.js +17 -25
- package/lib/init/merge.js +2 -5
- package/lib/init/projectReader.js +76 -9
- package/lib/init/registries/mta.js +0 -1
- package/lib/init/template/approuter/files/package.json +1 -1
- package/lib/init/template/cloud-logging/files/package.json.hbs +1 -12
- package/lib/init/template/cloud-logging/files/values.yaml.hbs +16 -0
- package/lib/init/template/cloud-logging/index.js +14 -10
- package/lib/init/template/data/as-json.js +1 -1
- package/lib/init/template/data/index.js +1 -26
- package/lib/init/template/esm/files/package.json.hbs +3 -0
- package/lib/init/template/esm/index.js +16 -0
- package/lib/init/template/handler/files/handler.xs.hbs +56 -0
- package/lib/init/template/handler/index.js +84 -9
- package/lib/init/template/helm/index.js +4 -1
- package/lib/init/template/html5-repo/files/xs-app.json.hbs +1 -0
- package/lib/init/template/html5-repo/index.js +2 -0
- package/lib/init/template/http/index.js +102 -35
- package/lib/init/template/nodejs/files/package.json.hbs +1 -1
- package/lib/init/template/sample/files/nodejs/{admin-service.js → admin-service.js.hbs} +8 -1
- package/lib/init/template/sample/files/nodejs/{cat-service.js → cat-service.js.hbs} +8 -3
- package/lib/init/template/sample/index.js +4 -2
- package/lib/init/template/telemetry/files/package.json.hbs +18 -0
- package/lib/init/template/telemetry/index.js +8 -2
- package/lib/init/template/typescript/files/package.json +2 -2
- package/lib/init/template/workzone-standard/index.js +1 -1
- package/lib/init/types.d.ts +0 -6
- package/lib/watch/node-watch.js +25 -9
- package/npm-shrinkwrap.json +63 -48
- package/package.json +1 -1
package/lib/init/add.js
CHANGED
|
@@ -15,5 +15,31 @@ module.exports = {
|
|
|
15
15
|
register: (name, plugin) => {
|
|
16
16
|
registered.set(name, plugin)
|
|
17
17
|
},
|
|
18
|
+
filterStringAsRegex,
|
|
18
19
|
registered
|
|
19
20
|
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Turns a filter string with optional meta characters into a regular expression.
|
|
24
|
+
* If no meta characters are found, the string is treated as an include pattern.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} spec the filter string
|
|
27
|
+
* @returns {RegExp} the regular expression
|
|
28
|
+
*/
|
|
29
|
+
function filterStringAsRegex(spec) {
|
|
30
|
+
if (typeof spec === 'string') {
|
|
31
|
+
try {
|
|
32
|
+
if (spec.match(/[\^$|*]/)) {
|
|
33
|
+
spec = spec.replace(/^\*/, '.*') // * at start would be invalid, so make it a .*
|
|
34
|
+
return new RegExp(spec, 'i')
|
|
35
|
+
}
|
|
36
|
+
else { // no meta chars -> include semantics
|
|
37
|
+
spec = spec.replace(/\./g, '\\.') // escape literal dot
|
|
38
|
+
return new RegExp(spec, 'i')
|
|
39
|
+
}
|
|
40
|
+
} catch (err) {
|
|
41
|
+
throw err.message // user error, so cut off stack trace
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return /.*/
|
|
45
|
+
}
|
package/lib/init/constants.js
CHANGED
|
@@ -5,7 +5,7 @@ module.exports = {
|
|
|
5
5
|
COMMAND_ADD: 'add',
|
|
6
6
|
|
|
7
7
|
JAVA_LTS_VERSIONS: [17, 21],
|
|
8
|
-
MAVEN_ARCHETYPE_VERSION: '3.
|
|
8
|
+
MAVEN_ARCHETYPE_VERSION: '3.5.0',
|
|
9
9
|
|
|
10
10
|
OPTIONS: Object.freeze({
|
|
11
11
|
COMPLETION: 'completion',
|
|
@@ -13,9 +13,13 @@ module.exports = {
|
|
|
13
13
|
JAVA_MVN: 'java:mvn',
|
|
14
14
|
JAVA_PACKAGE: 'java:package',
|
|
15
15
|
NODEJS: 'nodejs',
|
|
16
|
+
ESM: 'esm',
|
|
16
17
|
SAMPLES: 'samples', // deprecated
|
|
17
18
|
TINY_SAMPLE: 'tiny-sample',
|
|
18
19
|
SAMPLE: 'sample',
|
|
20
|
+
TYPER: 'typer',
|
|
21
|
+
TYPESCRIPT: 'typescript',
|
|
22
|
+
HANDLER: 'handler', // influenced by esm, typer and typescript
|
|
19
23
|
MTA: 'mta',
|
|
20
24
|
CF_MANIFEST: 'cf-manifest',
|
|
21
25
|
HELM: 'helm',
|
|
@@ -57,8 +61,6 @@ module.exports = {
|
|
|
57
61
|
LINT_GLOBAL: 'lint:global',
|
|
58
62
|
LINT_DEV: 'lint:dev',
|
|
59
63
|
PIPELINE: 'pipeline',
|
|
60
|
-
TYPER: 'typer',
|
|
61
|
-
TYPESCRIPT: 'typescript'
|
|
62
64
|
}),
|
|
63
65
|
|
|
64
66
|
REGEX_JAVA_PACKAGE: /^[a-z_][a-z0-9_]*(\.[a-z_][a-z0-9_]*)*$/g,
|
|
@@ -71,9 +73,6 @@ module.exports = {
|
|
|
71
73
|
CAPIRE: 'https://cap.cloud.sap',
|
|
72
74
|
MAVEN_ARCHETYPE_HELP: `https://cap.cloud.sap/docs/java/developing-applications/building#the-maven-archetype`,
|
|
73
75
|
MAVEN_INSTALL_HELP: `https://maven.apache.org/install.html`,
|
|
74
|
-
CAP_JS_COMMUNITY_ODATA_V2: 'https://github.com/cap-js-community/odata-v2-adapter',
|
|
75
|
-
CAP_JS_COMMUNITY_EVENT_QUEUE: 'https://github.com/cap-js-community/event-queue',
|
|
76
|
-
CAP_JS_COMMUNITY_WEBSOCKET: 'https://github.com/cap-js-community/websocket',
|
|
77
76
|
CF_CLI: 'https://github.com/cloudfoundry/cli'
|
|
78
77
|
}),
|
|
79
78
|
|
package/lib/init/index.js
CHANGED
|
@@ -12,17 +12,13 @@ const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) ? console.debug : undefi
|
|
|
12
12
|
|
|
13
13
|
module.exports = class CDSGenerator {
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const fromDk = readdirSync(join(__dirname, 'template'))
|
|
19
|
-
const fromPlugins = Object.keys(Object.fromEntries(require('./add').registered))
|
|
20
|
-
return [...fromDk, ...fromPlugins]
|
|
21
|
-
.filter(plugin => !excluded?.includes(plugin))
|
|
15
|
+
constructor() {
|
|
16
|
+
this.cwd = process.cwd()
|
|
17
|
+
this.uiConfig = require('./bas') // Used by CAP Generator
|
|
22
18
|
}
|
|
23
19
|
|
|
24
20
|
static help({ exclude = [] } = {}) {
|
|
25
|
-
if (!cds.add) return //
|
|
21
|
+
if (!cds.add) return // shell completion: cds.add is undefined and not needed
|
|
26
22
|
|
|
27
23
|
const plugins = this.readPlugins(exclude)
|
|
28
24
|
const nameFixedLength = Math.max(...plugins.map(plugin => plugin.name.length))
|
|
@@ -35,10 +31,14 @@ module.exports = class CDSGenerator {
|
|
|
35
31
|
}
|
|
36
32
|
|
|
37
33
|
/**
|
|
34
|
+
* @param excluded {string[]}
|
|
38
35
|
* @returns {{name: string, module: import('module')}[]}
|
|
39
36
|
*/
|
|
40
37
|
static readPlugins(excluded = []) {
|
|
41
|
-
const
|
|
38
|
+
const fromDk = readdirSync(join(__dirname, 'template'))
|
|
39
|
+
const fromPlugins = Object.keys(Object.fromEntries(require('./add').registered))
|
|
40
|
+
const all = [...fromDk, ...fromPlugins]
|
|
41
|
+
.filter(plugin => !excluded?.includes(plugin))
|
|
42
42
|
.map(plugin => ({
|
|
43
43
|
name: plugin,
|
|
44
44
|
module: cds.add.registered.get(plugin) ?? require('./template/' + plugin)
|
|
@@ -51,12 +51,7 @@ module.exports = class CDSGenerator {
|
|
|
51
51
|
if (b === -1) return -1
|
|
52
52
|
return a - b
|
|
53
53
|
}
|
|
54
|
-
return
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
constructor() {
|
|
58
|
-
this.cwd = process.cwd()
|
|
59
|
-
this.uiConfig = require('./bas') // Used by CAP Generator
|
|
54
|
+
return all.sort(byPriority)
|
|
60
55
|
}
|
|
61
56
|
|
|
62
57
|
/**
|
|
@@ -216,15 +211,14 @@ module.exports = class CDSGenerator {
|
|
|
216
211
|
}
|
|
217
212
|
|
|
218
213
|
const cmds = Object.values(OPTIONS)
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if (b === -1) return -1
|
|
214
|
+
const priorities = new Map(cmds.map((cmd, i) => [cmd, i]))
|
|
215
|
+
this.templateList = Array.from(templates.keys())
|
|
216
|
+
.sort((lhs, rhs) => {
|
|
217
|
+
const a = priorities.get(lhs) ?? Infinity
|
|
218
|
+
const b = priorities.get(rhs) ?? Infinity
|
|
225
219
|
return a - b
|
|
226
220
|
})
|
|
227
|
-
.map(
|
|
221
|
+
.map(key => templates.get(key))
|
|
228
222
|
|
|
229
223
|
DEBUG?.(`Features: ${this.templateList.map(({ name }) => name).join(', ')}`);
|
|
230
224
|
}
|
|
@@ -240,11 +234,9 @@ module.exports = class CDSGenerator {
|
|
|
240
234
|
|
|
241
235
|
const { options } = cds.cli
|
|
242
236
|
if (typeof options.add === 'string') {
|
|
243
|
-
tokens = options.add.split(/[,\s+]/g)
|
|
244
|
-
|
|
237
|
+
tokens = options.add.split(/[,\s+]/g)
|
|
245
238
|
} else if (Array.isArray(options.add)) {
|
|
246
239
|
tokens = options.add
|
|
247
|
-
|
|
248
240
|
} else if (options.add instanceof Set) {
|
|
249
241
|
tokens = [...options.add];
|
|
250
242
|
}
|
package/lib/init/merge.js
CHANGED
|
@@ -6,11 +6,8 @@ const { readYAML, writeYAML, readJSON } = require('../util/fs')
|
|
|
6
6
|
const { detectIndent } = require('./indent')
|
|
7
7
|
const { colors } = require('../util/term')
|
|
8
8
|
|
|
9
|
-
function _isObject(item) {
|
|
10
|
-
return item && typeof item === 'object' && !Array.isArray(item)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
function _mergeObject(target, source) {
|
|
10
|
+
const _isObject = item => item && typeof item === 'object' && !Array.isArray(item)
|
|
14
11
|
const unique = array => [...new Set(array.map(JSON.stringify))].map(JSON.parse)
|
|
15
12
|
if (_isObject(target) && _isObject(source)) {
|
|
16
13
|
for (const key in source) {
|
|
@@ -156,7 +153,7 @@ async function _mergeYAML(into, from, project, semantics = {}) {
|
|
|
156
153
|
relationships?.forEach(relationship => {
|
|
157
154
|
const [entry] = relationship.into
|
|
158
155
|
const [insertEntry] = relationship.insert
|
|
159
|
-
const hash = insertEntry + ' -> ' + entry
|
|
156
|
+
const hash = JSON.stringify(insertEntry) + ' -> ' + JSON.stringify(entry)
|
|
160
157
|
entryMap.set(hash, undefined)
|
|
161
158
|
})
|
|
162
159
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const cds = require('../cds')
|
|
2
2
|
const { join, resolve, basename } = require('path')
|
|
3
|
-
const { fs, exists, isdir, path } = cds.utils
|
|
3
|
+
const { fs, exists, isfile, isdir, path } = cds.utils
|
|
4
4
|
const { parseXml } = require('./xml')
|
|
5
5
|
const { REGEX_JAVA_VERSION, JAVA_LTS_VERSIONS } = require('./constants')
|
|
6
6
|
const TRACE = cds.debug('trace')
|
|
@@ -12,13 +12,15 @@ module.exports = new class ProjectReader {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
#setPackageInfo() {
|
|
15
|
+
this.isJava = (exists('pom.xml') || cds.cli.options?.add?.has('java'))
|
|
16
|
+
&& !cds.env.for('cds').profiles.includes('node') // opt-out for hybrid projects like sflight
|
|
17
|
+
|
|
15
18
|
// 1. Use project name and static default values
|
|
16
|
-
this.appVersion =
|
|
19
|
+
this.appVersion = this.isJava ? '1.0.0-SNAPSHOT' : '1.0.0'
|
|
17
20
|
this.appName = this.appId = basename(cds.root)
|
|
18
21
|
this.appDescription = 'A simple CAP project.'
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
if (isJava) {
|
|
23
|
+
if (this.isJava) {
|
|
22
24
|
let artifactId, description, version, properties
|
|
23
25
|
try {
|
|
24
26
|
({ artifactId, description, version, properties } = parseXml(resolve(cds.root, 'pom.xml')) ?? {})
|
|
@@ -74,6 +76,10 @@ module.exports = new class ProjectReader {
|
|
|
74
76
|
* @property {boolean} isUI5 Indicates if the project is a UI5 project.
|
|
75
77
|
* @property {boolean} isJava Indicates if the project is using Java.
|
|
76
78
|
* @property {boolean} isNodejs Indicates if the project is using Node.js.
|
|
79
|
+
* @property {boolean} isESM Indicates if the project is an ESM project (type 'module')
|
|
80
|
+
* @property {boolean} hasEsmStyle Indicates if code supports ESM-style imports and exports. This is true for ESM and Typescript projects.
|
|
81
|
+
* @property {boolean} isTypescript Indicates if the project is a Typescript project.
|
|
82
|
+
* @property {boolean} hasTyper Indicates if code supports CDS typer.
|
|
77
83
|
* @property {boolean} hasHelmUnifiedRuntime Indicates if the project uses Unified Runtime Helm deployment.
|
|
78
84
|
* @property {boolean} hasHelm Indicates if the project uses CAP Helm deployment.
|
|
79
85
|
* @property {boolean} hasMta Indicates if the project uses MTA deployment.
|
|
@@ -95,7 +101,7 @@ module.exports = new class ProjectReader {
|
|
|
95
101
|
* @property {boolean} hasMTXRouteJava Indicates if the approuter should have a multitenant subscription route (java).
|
|
96
102
|
* @property {boolean} hasMalwareScanner Indicates if the project uses the SAP Malware Scanning service.
|
|
97
103
|
* @property {boolean} hasDynatrace Indicates if the project uses Dynatrace.
|
|
98
|
-
*
|
|
104
|
+
* @property {boolean} hasCloudLogging Indicates if the project uses Cloud Logging.
|
|
99
105
|
*/
|
|
100
106
|
|
|
101
107
|
/**
|
|
@@ -110,18 +116,27 @@ module.exports = new class ProjectReader {
|
|
|
110
116
|
const { appVersion, appName, appId, appDescription, jdkVersion } = this
|
|
111
117
|
TRACE?.({ env })
|
|
112
118
|
|
|
119
|
+
const pkgJson = () => exists('package.json') ? JSON.parse(fs.readFileSync(join(cds.root, 'package.json'))) : {}
|
|
120
|
+
const _isESM = () => pkgJson().type === 'module'
|
|
121
|
+
const _isTypescript = () => !!pkgJson().dependencies?.typescript || !!pkgJson().devDependencies?.typescript
|
|
122
|
+
const _hasTyper = () => !!pkgJson().dependencies?.['@cap-js/cds-typer'] || !!pkgJson().devDependencies?.['@cap-js/cds-typer']
|
|
123
|
+
|
|
113
124
|
const _inProd = plugin => require(`./template/${plugin}`).hasInProduction(env)
|
|
114
|
-
const _ui5 = () =>
|
|
125
|
+
const _ui5 = () => pkgJson().sapux
|
|
115
126
|
const _uiEmbedded = () => exists(join(env.folders.app, 'xs-app.json'))
|
|
116
127
|
const _uiModule = () => !_uiEmbedded() && isdir(env.folders.app) && fs.readdirSync(resolve(cds.root, env.folders.app)).length > 0
|
|
117
|
-
const _isJava = () =>
|
|
128
|
+
const _isJava = () => this.isJava
|
|
118
129
|
const isApp = name => name !== 'appconfig' && !name.startsWith('_') && name !== 'router' && name !== 'portal'
|
|
119
130
|
const reserved = {
|
|
120
131
|
has: x => _inProd(x),
|
|
121
132
|
profile: () => cds.cli.options?.for,
|
|
122
|
-
language: () =>
|
|
133
|
+
language: () => _isJava() ? 'java' : 'nodejs',
|
|
123
134
|
isJava: () => _isJava(),
|
|
124
135
|
isNodejs: () => !_isJava(),
|
|
136
|
+
isTypescript: () => _isTypescript(),
|
|
137
|
+
isESM: () => _isESM,
|
|
138
|
+
hasEsmStyle: () => _isTypescript() || _isESM(),
|
|
139
|
+
hasTyper: () => _hasTyper(),
|
|
125
140
|
srvPath: () => join(env.build.target, env.folders.srv.replace(/\/$/, '')).replace(/\\/g, '/'),
|
|
126
141
|
archiveName: () => {
|
|
127
142
|
const pomXmlPath = resolve(cds.root, env.folders.srv, 'pom.xml')
|
|
@@ -135,7 +150,7 @@ module.exports = new class ProjectReader {
|
|
|
135
150
|
const path = join(env.build.target, name).replace(/\\/g, '/')
|
|
136
151
|
return { folder, name, path }
|
|
137
152
|
},
|
|
138
|
-
configFile: () =>
|
|
153
|
+
configFile: () => _isJava() ? '.cdsrc.json' : 'package.json',
|
|
139
154
|
apps: () => {
|
|
140
155
|
const apps = fs.readdirSync(path.resolve(cds.root, cds.env.folders.app)).filter(e =>
|
|
141
156
|
isdir(path.join(cds.root, cds.env.folders.app, e)) && isApp(e)
|
|
@@ -152,6 +167,7 @@ module.exports = new class ProjectReader {
|
|
|
152
167
|
appUIPaths: () => (fs.readdirSync(path.resolve(cds.root, cds.env.folders.app))).filter(e =>
|
|
153
168
|
isdir(join(cds.root, cds.env.folders.app, e)) && isApp(e)
|
|
154
169
|
),
|
|
170
|
+
hasIndexHtml: () => {},
|
|
155
171
|
appPath: () => env.folders.app,
|
|
156
172
|
appVersion: () => appVersion,
|
|
157
173
|
jdkVersion: () => jdkVersion,
|
|
@@ -191,3 +207,54 @@ module.exports = new class ProjectReader {
|
|
|
191
207
|
return project
|
|
192
208
|
}
|
|
193
209
|
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Finds and reads SpringBoot configuration in `cds.root/srv` dir.
|
|
213
|
+
* This is done in a best-effort way. In no way can we replciate all of SpringBoot's
|
|
214
|
+
* config variants.
|
|
215
|
+
* @param {string[]?} roots array of directories to search for application.yaml, like `srv`
|
|
216
|
+
* @returns {Promise<object[]>} array of objects with `cds` property
|
|
217
|
+
*/
|
|
218
|
+
module.exports._readSpringBootConfig = async function (roots=[cds.env.folders.srv]) {
|
|
219
|
+
const configNodes = []
|
|
220
|
+
const rootDirs = roots.map(d => join(cds.root, d))
|
|
221
|
+
for (let r of rootDirs) {
|
|
222
|
+
const file = isfile (join (r,'./src/main/resources/application.yaml'))
|
|
223
|
+
if (file) {
|
|
224
|
+
const yaml = cds.load.yaml(file)
|
|
225
|
+
for (let yamlDoc of Array.isArray(yaml) ? yaml : [yaml]) {
|
|
226
|
+
let cds = yamlDoc?.cds;
|
|
227
|
+
if (!cds) continue
|
|
228
|
+
cds = _normalizeSpringBootCfg(cds)
|
|
229
|
+
configNodes.push({cds})
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
return configNodes
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Normalize SpringBoot's dots in keys to express nested objects
|
|
238
|
+
*
|
|
239
|
+
* @example: `cds.foo.bar = 1` --> `cds: { foo: { bar: 1 } }`
|
|
240
|
+
* @param {object} obj
|
|
241
|
+
* @returns {object}
|
|
242
|
+
*/
|
|
243
|
+
function _normalizeSpringBootCfg(obj) {
|
|
244
|
+
if (typeof obj !== 'object') return obj
|
|
245
|
+
Object.keys(obj).forEach(k => {
|
|
246
|
+
const prop = k.split('.')
|
|
247
|
+
const last = prop.pop()
|
|
248
|
+
// and define the object if not already defined
|
|
249
|
+
const res = prop.reduce((o, key) => {
|
|
250
|
+
// define the object if not defined and return
|
|
251
|
+
return o[key] = o[key] ?? {}
|
|
252
|
+
}, obj)
|
|
253
|
+
res[last] = obj[k]
|
|
254
|
+
// recursively normalize
|
|
255
|
+
_normalizeSpringBootCfg(obj[k])
|
|
256
|
+
// delete the original property from object if it was rewritten
|
|
257
|
+
if (prop.length) delete obj[k]
|
|
258
|
+
})
|
|
259
|
+
return obj
|
|
260
|
+
}
|
|
@@ -1,18 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"dependencies": {
|
|
3
|
-
"@cap-js/telemetry": ">=0",
|
|
4
|
-
"@grpc/grpc-js": "^1",
|
|
5
|
-
"@opentelemetry/exporter-trace-otlp-grpc": "^0",
|
|
6
|
-
"@opentelemetry/exporter-metrics-otlp-grpc": "^0",
|
|
7
|
-
"@opentelemetry/host-metrics": "^0"
|
|
8
|
-
},
|
|
9
2
|
"cds": {
|
|
10
3
|
"requires": {
|
|
11
|
-
"
|
|
12
|
-
"telemetry": {
|
|
13
|
-
"kind": "to-cloud-logging"
|
|
14
|
-
}
|
|
15
|
-
}
|
|
4
|
+
"cloud-logging": true
|
|
16
5
|
}
|
|
17
6
|
}
|
|
18
7
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
srv:
|
|
3
|
+
bindings:
|
|
4
|
+
cloud-logging:
|
|
5
|
+
serviceInstanceName: cloud-logging
|
|
6
|
+
credentialsRotationPolicy:
|
|
7
|
+
enabled: true
|
|
8
|
+
rotationFrequency: 168h
|
|
9
|
+
cloud-logging:
|
|
10
|
+
serviceOfferingName: cloud-logging
|
|
11
|
+
servicePlanName: standard
|
|
12
|
+
parameters:
|
|
13
|
+
ingest_otlp:
|
|
14
|
+
enabled: true
|
|
15
|
+
|
|
16
|
+
|
|
@@ -7,7 +7,7 @@ const { srv4, mtxSidecar4, approuter } = require('../../registries/mta')
|
|
|
7
7
|
module.exports = class extends require('../../plugin') {
|
|
8
8
|
|
|
9
9
|
static hasInProduction(env) {
|
|
10
|
-
return env.requires?.
|
|
10
|
+
return env.requires?.['cloud-logging'];
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
options() {
|
|
@@ -24,23 +24,23 @@ module.exports = class extends require('../../plugin') {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
async canRun() {
|
|
27
|
-
const { hasMta, hasHelm, hasHelmUnifiedRuntime } = readProject()
|
|
28
|
-
if ((hasHelmUnifiedRuntime || hasHelm) && !hasMta) throw `'cds add cloud-logging' is not available for Kyma yet`
|
|
29
27
|
return true
|
|
30
28
|
}
|
|
31
29
|
|
|
30
|
+
requires() {
|
|
31
|
+
const project = readProject(), { hasTelemetry } = project
|
|
32
|
+
if ((cds.cli.options['with-telemetry'] || hasTelemetry)) return ['telemetry']
|
|
33
|
+
}
|
|
34
|
+
|
|
32
35
|
async run() {
|
|
33
|
-
const project = readProject()
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
|
|
37
|
-
await sort('package.json', 'dependencies')
|
|
38
|
-
}
|
|
36
|
+
const project = readProject();
|
|
37
|
+
await merge(__dirname, 'files/package.json.hbs').into('package.json', { with: project })
|
|
38
|
+
await sort('package.json', 'dependencies')
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
async combine() {
|
|
42
42
|
const project = readProject()
|
|
43
|
-
const { hasMta, hasApprouter, isJava, hasMultitenancy, srvPath } = project
|
|
43
|
+
const { hasMta, hasHelm, hasHelmUnifiedRuntime, hasApprouter, isJava, hasMultitenancy, srvPath } = project
|
|
44
44
|
|
|
45
45
|
if (hasMta) {
|
|
46
46
|
const cloudLogging = {
|
|
@@ -77,5 +77,9 @@ module.exports = class extends require('../../plugin') {
|
|
|
77
77
|
with: project, additions, relationships
|
|
78
78
|
})
|
|
79
79
|
}
|
|
80
|
+
if (hasHelm || hasHelmUnifiedRuntime) {
|
|
81
|
+
await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml')
|
|
82
|
+
}
|
|
80
83
|
}
|
|
81
84
|
}
|
|
85
|
+
|
|
@@ -80,7 +80,7 @@ function fillRecord(record, recordID, artifact, csn, data, parent, depth, refere
|
|
|
80
80
|
Object.defineProperty(record, '$id', {value: recordID, enumerable: false})
|
|
81
81
|
if (data[artifact.name]) data[artifact.name].push(record) // add id to data, to be referenced by associations to prevent circular dependencies
|
|
82
82
|
|
|
83
|
-
const elems = Object.values(artifact.elements ?? artifact.params).sort(asJson.elementsSorter(csn))
|
|
83
|
+
const elems = Object.values(artifact.elements ?? artifact.params ?? {}).sort(asJson.elementsSorter(csn))
|
|
84
84
|
elems.forEach(el => {
|
|
85
85
|
record[el.name] = dataForField(el, artifact, csn, record, data, parent, depth, referenceData)
|
|
86
86
|
})
|
|
@@ -6,6 +6,7 @@ const { URLSearchParams } = require('url')
|
|
|
6
6
|
const { env4 } = require('../../projectReader')
|
|
7
7
|
const asJson = require('./as-json')
|
|
8
8
|
const asCsv = require('./as-csv')
|
|
9
|
+
const { filterStringAsRegex } = require('../../add')
|
|
9
10
|
|
|
10
11
|
module.exports = class DataTemplate extends require('../../plugin') {
|
|
11
12
|
|
|
@@ -92,32 +93,6 @@ module.exports = class DataTemplate extends require('../../plugin') {
|
|
|
92
93
|
}
|
|
93
94
|
module.exports.asJson = asJson
|
|
94
95
|
module.exports.asCsv = asCsv
|
|
95
|
-
module.exports.filterStringAsRegex = filterStringAsRegex
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Turns a filter string with optional meta characters into a regular expression.
|
|
99
|
-
* If no meta characters are found, the string is treated as an include pattern.
|
|
100
|
-
*
|
|
101
|
-
* @param {string} spec the filter string
|
|
102
|
-
* @returns {RegExp} the regular expression
|
|
103
|
-
*/
|
|
104
|
-
function filterStringAsRegex(spec) {
|
|
105
|
-
if (typeof spec === 'string') {
|
|
106
|
-
try {
|
|
107
|
-
if (spec.match(/[\^$|*]/)) {
|
|
108
|
-
spec = spec.replace(/^\*/, '.*') // * at start would be invalid, so make it a .*
|
|
109
|
-
return new RegExp(spec, 'i')
|
|
110
|
-
}
|
|
111
|
-
else { // no meta chars -> include semantics
|
|
112
|
-
spec = spec.replace(/\./g, '\\.') // escape literal dot
|
|
113
|
-
return new RegExp(spec, 'i')
|
|
114
|
-
}
|
|
115
|
-
} catch (err) {
|
|
116
|
-
throw err.message // user error, so cut off stack trace
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
return /.*/
|
|
120
|
-
}
|
|
121
96
|
|
|
122
97
|
function parseQueryStr(queryStr) {
|
|
123
98
|
const params = new URLSearchParams(queryStr) // e.g. key1&key2=false
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const { readProject } = require('../../projectReader')
|
|
2
|
+
const { merge } = require('../../merge')
|
|
3
|
+
|
|
4
|
+
module.exports = class EsmTemplate extends require('../../plugin') {
|
|
5
|
+
|
|
6
|
+
static help() {
|
|
7
|
+
return 'ESM-compatible Node.js project'
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
async run() {
|
|
11
|
+
const project = readProject()
|
|
12
|
+
const { configFile } = project
|
|
13
|
+
await merge(__dirname, 'files/package.json.hbs').into(configFile, { with: project, forceOverwrite: true })
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{{! ESM }}
|
|
2
|
+
{{#hasEsmStyle}}
|
|
3
|
+
import cds from '@sap/cds'
|
|
4
|
+
{{#hasTyper}}
|
|
5
|
+
{{#allNames}}
|
|
6
|
+
import { {{allNames}} } from '#cds-models/{{{servicePath}}}'
|
|
7
|
+
{{/allNames}}
|
|
8
|
+
{{/hasTyper}}
|
|
9
|
+
|
|
10
|
+
{{! class declaration }}
|
|
11
|
+
export class {{serviceClass}} extends cds.ApplicationService { init() {
|
|
12
|
+
{{/hasEsmStyle}}
|
|
13
|
+
{{! CJS }}
|
|
14
|
+
{{^hasEsmStyle}}
|
|
15
|
+
const cds = require('@sap/cds')
|
|
16
|
+
{{#hasTyper}}
|
|
17
|
+
{{#allNames}}
|
|
18
|
+
const { {{allNames}} } = require('#cds-models/{{{servicePath}}}')
|
|
19
|
+
{{/allNames}}
|
|
20
|
+
{{/hasTyper}}
|
|
21
|
+
|
|
22
|
+
{{! class declaration }}
|
|
23
|
+
module.exports = class {{serviceClass}} extends cds.ApplicationService { init() {
|
|
24
|
+
{{/hasEsmStyle}}
|
|
25
|
+
{{! dynamic model imports }}
|
|
26
|
+
{{^hasTyper}}
|
|
27
|
+
|
|
28
|
+
{{#entityNames}}
|
|
29
|
+
const { {{entityNames}} } = cds.entities('{{serviceName}}')
|
|
30
|
+
{{/entityNames}}
|
|
31
|
+
{{/hasTyper}}
|
|
32
|
+
|
|
33
|
+
{{! entity handlers }}
|
|
34
|
+
{{#entities}}
|
|
35
|
+
this.before (['CREATE', 'UPDATE'], {{name}}, async (req) => {
|
|
36
|
+
console.log('Before CREATE/UPDATE {{name}}', req.data)
|
|
37
|
+
})
|
|
38
|
+
this.after ('READ', {{name}}, async ({{dataVar}}, req) => {
|
|
39
|
+
console.log('After READ {{name}}', {{dataVar}})
|
|
40
|
+
})
|
|
41
|
+
{{/entities}}
|
|
42
|
+
|
|
43
|
+
{{! action handlers }}
|
|
44
|
+
{{#operations}}
|
|
45
|
+
{{#hasTyper}}
|
|
46
|
+
this.on ({{name}}, async (req) => {
|
|
47
|
+
{{/hasTyper}}
|
|
48
|
+
{{^hasTyper}}
|
|
49
|
+
this.on ('{{name}}', async (req) => {
|
|
50
|
+
{{/hasTyper}}
|
|
51
|
+
console.log('On {{name}}', req.data)
|
|
52
|
+
})
|
|
53
|
+
{{/operations}}
|
|
54
|
+
|
|
55
|
+
return super.init()
|
|
56
|
+
}}
|