@sap/cds-dk 9.4.3 → 9.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +77 -0
- package/bin/compile/index.js +1 -1
- package/bin/export.js +1 -1
- package/bin/help.js +0 -1
- package/bin/import.js +8 -3
- package/bin/repl.js +7 -11
- package/bin/up.js +150 -20
- package/bin/util/containerize.js +66 -25
- package/bin/version.js +4 -4
- package/lib/bind/k8s.js +1 -1
- package/lib/build/plugins/helm/files/templates/_deployment_helpers.tpl +1 -1
- package/lib/build/plugins/helm/index.js +1 -1
- package/lib/build/provider/hana/2migration.js +16 -24
- package/lib/build/provider/hana/index.js +1 -1
- package/lib/build/provider/hana/template/.hdiconfig-all +7 -1
- package/lib/build/provider/hana/template/package.json +1 -1
- package/lib/build/provider/internalBuildPlugin.js +15 -1
- package/lib/build/provider/java/index.js +12 -1
- package/lib/build/provider/mtx-sidecar/index.js +2 -1
- package/lib/build/provider/nodejs/index.js +2 -1
- package/lib/build/util.js +3 -3
- package/lib/compile/to_openapi.js +1 -5
- package/lib/import/common.js +2 -1
- package/lib/import/odata/ParserContext.js +1 -0
- package/lib/import/odata/v4parser.js +48 -3
- package/lib/import/openapi/importOpenAPI.js +6 -1
- package/lib/init/constants.js +1 -1
- package/lib/init/index.js +15 -6
- package/lib/init/merge.js +16 -0
- package/lib/init/projectReader.js +19 -4
- package/lib/init/registries/mta.js +2 -2
- package/lib/init/template/ams/index.js +1 -1
- package/lib/init/template/app-frontend/files/app-package.json.hbs +1 -7
- package/lib/init/template/app-frontend/files/ui5.yaml.hbs +20 -1
- package/lib/init/template/app-frontend/index.js +0 -4
- package/lib/init/template/application-logging/index.js +9 -14
- package/lib/init/template/approuter/files/mta.yaml.hbs +0 -2
- package/lib/init/template/approuter/index.js +6 -7
- package/lib/init/template/cloud-logging/index.js +2 -3
- package/lib/init/template/containerize/files/containerize.yaml.hbs +17 -2
- package/lib/init/template/containerize/index.js +0 -4
- package/lib/init/template/data/as-json.js +18 -20
- package/lib/init/template/dynatrace/index.js +0 -2
- package/lib/init/template/github-actions/files/workflows/cf.yaml.hbs +16 -1
- package/lib/init/template/github-actions/files/workflows/test.yaml.hbs +20 -0
- package/lib/init/template/github-actions/index.js +5 -8
- package/lib/init/template/hana/files/db/package.json +2 -2
- package/lib/init/template/hana/files/mta.yaml.hbs +0 -4
- package/lib/init/template/hana/index.js +3 -5
- package/lib/init/template/helm/index.js +2 -7
- package/lib/init/template/helm-unified-runtime/index.js +0 -4
- package/lib/init/template/html5-repo/files/app-package.json.hbs +1 -7
- package/lib/init/template/html5-repo/files/ui5.yaml.hbs +20 -1
- package/lib/init/template/html5-repo/index.js +6 -12
- package/lib/init/template/ias/files/values.yaml.hbs +6 -6
- package/lib/init/template/ias/index.js +12 -20
- package/lib/init/template/kyma/index.js +14 -1
- package/lib/init/template/malware-scanner/files/mta.yaml.hbs +3 -1
- package/lib/init/template/malware-scanner/files/values.yaml +3 -1
- package/lib/init/template/multitenancy/files/mta.yaml.hbs +1 -3
- package/lib/init/template/multitenancy/files/values.yaml.hbs +8 -0
- package/lib/init/template/multitenancy/index.js +8 -3
- package/lib/init/template/nodejs/files/package.json.hbs +1 -1
- package/lib/init/template/pipeline/files/app-package.json.hbs +1 -7
- package/lib/init/template/pipeline/files/ui5.yaml.hbs +20 -1
- package/lib/init/template/pipeline/index.js +1 -2
- package/lib/init/template/portal/files/mta.yaml.hbs +5 -3
- package/lib/init/template/portal/index.js +3 -6
- package/lib/init/template/sample/files/_i18n/i18n_de.properties +12 -0
- package/lib/init/template/sample/files/_i18n/i18n_en.properties +21 -0
- package/lib/init/template/sample/files/_i18n/i18n_fr.properties +20 -0
- package/lib/init/template/sample/files/_i18n/messages_de.properties +34 -0
- package/lib/init/template/sample/files/_i18n/messages_en.properties +34 -0
- package/lib/init/template/sample/files/_i18n/messages_fr.properties +34 -0
- package/lib/init/template/sample/files/app/_i18n/i18n_de.properties +0 -26
- package/lib/init/template/sample/files/app/_i18n/i18n_en.properties +8 -0
- package/lib/init/template/sample/files/app/admin-authors/fiori-service.cds +52 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/i18n/i18n.properties +11 -0
- package/lib/init/template/sample/files/app/admin-authors/webapp/manifest.json +130 -0
- package/lib/init/template/sample/files/app/admin-books/fiori-service.cds +81 -88
- package/lib/init/template/sample/files/app/admin-books/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n.properties +10 -2
- package/lib/init/template/sample/files/app/admin-books/webapp/manifest.json +24 -48
- package/lib/init/template/sample/files/app/appconfig/fioriSandboxConfig.json +54 -3
- package/lib/init/template/sample/files/app/browse/fiori-service.cds +30 -30
- package/lib/init/template/sample/files/app/browse/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n.properties +10 -3
- package/lib/init/template/sample/files/app/browse/webapp/manifest.json +18 -23
- package/lib/init/template/sample/files/app/common.cds +126 -158
- package/lib/init/template/sample/files/app/fiori-apps.html +30 -0
- package/lib/init/template/sample/files/app/genres/fiori-service.cds +33 -0
- package/lib/init/template/sample/files/app/genres/tree-view.cds +42 -0
- package/lib/init/template/sample/files/app/genres/value-help.cds +6 -0
- package/lib/init/template/sample/files/app/genres/webapp/Component.js.hbs +3 -0
- package/lib/init/template/sample/files/app/genres/webapp/i18n/i18n.properties +4 -0
- package/lib/init/template/sample/files/app/genres/webapp/i18n/i18n_de.properties +2 -0
- package/lib/init/template/sample/files/app/genres/webapp/manifest.json +126 -0
- package/lib/init/template/sample/files/app/services.cds +6 -2
- package/lib/init/template/sample/files/db/currencies.cds +13 -0
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Books.csv +5 -5
- package/lib/init/template/sample/files/db/data/{sap.capire.bookshop-Books_texts.csv → sap.capire.bookshop-Books.texts.csv} +4 -4
- package/lib/init/template/sample/files/db/data/sap.capire.bookshop-Genres.csv +42 -15
- package/lib/init/template/sample/files/db/data/sap.common-Currencies.csv +12 -0
- package/lib/init/template/sample/files/db/data/sap.common-Currencies.texts.csv +15 -0
- package/lib/init/template/sample/files/db/hana/index.cds +10 -0
- package/lib/init/template/sample/files/db/schema.cds +35 -22
- package/lib/init/template/sample/files/db/sqlite/index.cds +10 -0
- package/lib/init/template/sample/files/package.json.hbs +14 -1
- package/lib/init/template/sample/files/srv/access-control.cds +3 -0
- package/lib/init/template/sample/files/srv/admin-service.cds +3 -2
- package/lib/init/template/sample/files/srv/cat-service.cds +7 -11
- package/lib/init/template/sample/index.js +26 -17
- package/lib/init/template/telemetry/index.js +1 -3
- package/lib/init/template/typescript/files/package.json +1 -1
- package/lib/init/template/workzone-standard/files/mta.yaml.hbs +0 -5
- package/lib/init/template/workzone-standard/index.js +0 -1
- package/lib/init/template/xsuaa/files/mta.yaml.hbs +4 -0
- package/lib/init/template/xsuaa/index.js +3 -5
- package/lib/lint/Linter.js +10 -4
- package/lib/lint/eslintHelp.json +1 -1
- package/lib/mtx/tenant_action.js +12 -4
- package/lib/util/checksum.js +32 -0
- package/lib/util/question.js +60 -7
- package/npm-shrinkwrap.json +59 -35
- package/package.json +2 -2
- package/lib/init/template/app-frontend/files/ui5-deploy.yaml.hbs +0 -25
- package/lib/init/template/github-actions/files/cf-setup/action.yaml +0 -53
- package/lib/init/template/html5-repo/files/ui5-deploy.yaml.hbs +0 -25
- package/lib/init/template/pipeline/files/ui5-deploy.yaml.hbs +0 -25
- package/lib/init/template/sample/files/app/_i18n/i18n.properties +0 -29
- package/lib/init/template/sample/files/app/admin-books/webapp/Component.js +0 -8
- package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n_de.properties +0 -3
- package/lib/init/template/sample/files/app/admin-books/webapp/i18n/i18n_en.properties +0 -3
- package/lib/init/template/sample/files/app/browse/webapp/Component.js +0 -7
- package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n_de.properties +0 -3
- package/lib/init/template/sample/files/app/browse/webapp/i18n/i18n_en.properties +0 -4
- package/lib/init/template/sample/files/app/index.html +0 -32
|
@@ -48,31 +48,23 @@ function _compileToHana(model, options, beforeImage) {
|
|
|
48
48
|
let migrations = []
|
|
49
49
|
let afterImage
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
definitions.push({ name, suffix, sql: content })
|
|
67
|
-
}
|
|
51
|
+
const result = cds.compile.to.hana(model, options, beforeImage);
|
|
52
|
+
|
|
53
|
+
for (const [content, { file }] of result) {
|
|
54
|
+
switch (file) {
|
|
55
|
+
case 'deletions.json':
|
|
56
|
+
break
|
|
57
|
+
case 'migrations.json':
|
|
58
|
+
migrations = content
|
|
59
|
+
break
|
|
60
|
+
case 'afterImage.json':
|
|
61
|
+
afterImage = content
|
|
62
|
+
break
|
|
63
|
+
default: {
|
|
64
|
+
const { name, ext: suffix } = path.parse(file)
|
|
65
|
+
definitions.push({ name, suffix, sql: content })
|
|
68
66
|
}
|
|
69
67
|
}
|
|
70
|
-
} else {
|
|
71
|
-
// compatibility with cds < 8.0.0
|
|
72
|
-
const result = cdsc.to.hdi.migration(cds.minify(model), options, beforeImage)
|
|
73
|
-
definitions = result.definitions
|
|
74
|
-
migrations = result.migrations
|
|
75
|
-
afterImage = result.afterImage
|
|
76
68
|
}
|
|
77
69
|
let migrationTableNames = new Set()
|
|
78
70
|
if (afterImage) {
|
|
@@ -97,7 +89,7 @@ function _compileToHana(model, options, beforeImage) {
|
|
|
97
89
|
* @param {String} srcPath Fully qualified path of the directory containing .hdbmigrationtable files
|
|
98
90
|
* @param {String} migration the migration descriptor
|
|
99
91
|
* @param {String} tableSql SQL TABLE definition
|
|
100
|
-
* @returns {Object} Providing access to 'content' and 'fileName'.
|
|
92
|
+
* @returns {Promise<Object>} Providing access to 'content' and 'fileName'.
|
|
101
93
|
*/
|
|
102
94
|
async function _2migrationtable(srcPath, migration, tableSql) {
|
|
103
95
|
let migrationTableModel = null
|
|
@@ -586,7 +586,7 @@ class HanaBuildPlugin extends InternalBuildPlugin {
|
|
|
586
586
|
/**
|
|
587
587
|
* Returns all hana native artifacts located in db/src/** workspace folders.
|
|
588
588
|
* @param {Array} workspacePaths Array of workspace paths, 'cds.root' is excluded from the list
|
|
589
|
-
* @returns {Array} Array of workspace files, each entry contains the db src directory,
|
|
589
|
+
* @returns {Promise<Array>} Array of workspace files, each entry contains the db src directory,
|
|
590
590
|
* the relative file path and the file name.
|
|
591
591
|
*/
|
|
592
592
|
async _getWorkspaceFiles(workspacePaths) {
|
|
@@ -167,6 +167,12 @@
|
|
|
167
167
|
},
|
|
168
168
|
"hdbschedulerjob" : {
|
|
169
169
|
"plugin_name" : "com.sap.hana.di.schedulerjob"
|
|
170
|
+
},
|
|
171
|
+
"hdblogicalschema" : {
|
|
172
|
+
"plugin_name" : "com.sap.hana.di.logicalschema"
|
|
173
|
+
},
|
|
174
|
+
"hdblogicalschemaconfig" : {
|
|
175
|
+
"plugin_name" : "com.sap.hana.di.logicalschema.config"
|
|
170
176
|
}
|
|
171
177
|
}
|
|
172
|
-
}
|
|
178
|
+
}
|
|
@@ -4,6 +4,7 @@ const cds = require('../../cds')
|
|
|
4
4
|
const Plugin = require('../plugin')
|
|
5
5
|
const { hasOptionValue, getFiles } = require('../util')
|
|
6
6
|
const { FOLDER_GEN, DEFAULT_BUILTIN_PRIORITY_MAX } = require('../constants')
|
|
7
|
+
const TRACE = cds.debug('trace')
|
|
7
8
|
|
|
8
9
|
class InternalBuildPlugin extends Plugin {
|
|
9
10
|
/**
|
|
@@ -116,7 +117,7 @@ class InternalBuildPlugin extends Plugin {
|
|
|
116
117
|
cwd: cds.root,
|
|
117
118
|
src: this.hasBuildOption('flatDeployLayout', true) || this.task.src === this.task.dest ? this.task.src : cds.root
|
|
118
119
|
}
|
|
119
|
-
const csnStr =
|
|
120
|
+
const csnStr = cds_compile_to_json(model, jsonOptions)
|
|
120
121
|
await this.write(csnStr).to(csnFile)
|
|
121
122
|
return csnStr
|
|
122
123
|
}
|
|
@@ -156,4 +157,17 @@ class InternalBuildPlugin extends Plugin {
|
|
|
156
157
|
return null
|
|
157
158
|
}
|
|
158
159
|
}
|
|
160
|
+
|
|
161
|
+
// Emits the 'compile.for.runtime' event, as the produced CSN is for runtime usage.
|
|
162
|
+
// Plugins use it to modify the CSN before it is stringified.
|
|
163
|
+
function cds_compile_to_json (csn,o) {
|
|
164
|
+
TRACE?.time('cds.compile 2json'.padEnd(22)); try {
|
|
165
|
+
let result, next = ()=> result ??= cds.compile.to.json (csn,o)
|
|
166
|
+
cds.emit ('compile.for.runtime', csn, o, next)
|
|
167
|
+
return next() //> in case no handler called next
|
|
168
|
+
}
|
|
169
|
+
finally { TRACE?.timeEnd('cds.compile 2json'.padEnd(22)) }
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
|
|
159
173
|
module.exports = InternalBuildPlugin
|
|
@@ -7,6 +7,7 @@ const { OUTPUT_MODE, OUTPUT_MODE_RESULT, FILE_EXT_CDS, CONTENT_LANGUAGE_BUNDLES,
|
|
|
7
7
|
const { getI18nDefaultFolder } = require('../../util')
|
|
8
8
|
const DEFAULT_COMPILE_DEST_FOLDER = path.normalize('src/main/resources/edmx')
|
|
9
9
|
const DEBUG = cds.debug('cli|build')
|
|
10
|
+
const LOG = cds.log('cli|build')
|
|
10
11
|
|
|
11
12
|
class JavaBuildPlugin extends EdmxBuildPlugin {
|
|
12
13
|
init() {
|
|
@@ -25,7 +26,17 @@ class JavaBuildPlugin extends EdmxBuildPlugin {
|
|
|
25
26
|
|
|
26
27
|
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
27
28
|
// generate edmx files containing all features - localized edmx for backward compatibility
|
|
28
|
-
|
|
29
|
+
let localized = this.hasBuildOption(CONTENT_LOCALIZED_EDMX, true)
|
|
30
|
+
|
|
31
|
+
// Force localized to true for OData v2
|
|
32
|
+
if (cds.env.odata.version === 'v2') {
|
|
33
|
+
if (!localized) {
|
|
34
|
+
LOG.info('Forcing localized EDMX generation for OData v2')
|
|
35
|
+
localized = true
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (localized) {
|
|
29
40
|
await this.compileToEdmx(model, compileDest, { [FLAVOR_LOCALIZED_EDMX]: true })
|
|
30
41
|
}
|
|
31
42
|
// non-localized edmx
|
|
@@ -86,7 +86,8 @@ class MtxSidecarBuildPlugin extends NodejsBuildPlugin {
|
|
|
86
86
|
return
|
|
87
87
|
}
|
|
88
88
|
const { dictionary, sources } = await this.compileAll(model, destMainSrv, destMain)
|
|
89
|
-
await this.collectAllLanguageBundles(dictionary, sources, destMainSrv, destMain)
|
|
89
|
+
// await this.collectAllLanguageBundles(dictionary, sources, destMainSrv, destMain)
|
|
90
|
+
await this.collectAllLanguageBundles(dictionary, sources, destMain, destMain)
|
|
90
91
|
|
|
91
92
|
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
92
93
|
//inferred model expected by cds.compile.to.edmx()
|
|
@@ -53,7 +53,8 @@ class NodejsBuildPlugin extends EdmxBuildPlugin {
|
|
|
53
53
|
if (model) {
|
|
54
54
|
const { dictionary, sources } = await this.compileAll(model, destSrv, destRoot)
|
|
55
55
|
// collect and write language bundles into single i18n.json file
|
|
56
|
-
await this.collectAllLanguageBundles(dictionary, sources,
|
|
56
|
+
await this.collectAllLanguageBundles(dictionary, sources, destRoot, destRoot)
|
|
57
|
+
// await this.collectAllLanguageBundles(dictionary, sources, destSrv, destRoot)
|
|
57
58
|
|
|
58
59
|
if (!this.hasBuildOption(CONTENT_EDMX, false)) {
|
|
59
60
|
const compileOptions = { [FLAVOR_LOCALIZED_EDMX]: this.hasBuildOption(FLAVOR_LOCALIZED_EDMX, true) }
|
package/lib/build/util.js
CHANGED
|
@@ -165,9 +165,9 @@ function flatten(modelPaths) {
|
|
|
165
165
|
|
|
166
166
|
function getI18nDefaultFolder() {
|
|
167
167
|
// keep '_i18n' as preferred folder for compatibility reasons
|
|
168
|
-
if (cds.env.i18n.folders.includes('_i18n')) return '_i18n'
|
|
169
|
-
if (cds.env.i18n.folders.includes('i18n')) return 'i18n'
|
|
170
|
-
return cds.env.i18n.folders[0] ?? '
|
|
168
|
+
// if (cds.env.i18n.folders.includes('_i18n')) return '_i18n'
|
|
169
|
+
// if (cds.env.i18n.folders.includes('i18n')) return 'i18n'
|
|
170
|
+
return cds.env.i18n.folders?.[0] ?? '_i18n'
|
|
171
171
|
}
|
|
172
172
|
|
|
173
173
|
async function pathExists(path) {
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
const cds = require('../cds')
|
|
2
|
-
const { compile } = cds._local('@cap-js/openapi') // load a local cap-js/openapi (fallback to our own)
|
|
3
|
-
|
|
4
|
-
function cds_compile_to_openapi (csn, options) {
|
|
5
|
-
return compile(csn, options)
|
|
6
|
-
}
|
|
2
|
+
const { compile: cds_compile_to_openapi } = cds._local('@cap-js/openapi') // load a local cap-js/openapi (fallback to our own)
|
|
7
3
|
|
|
8
4
|
module.exports = cds_compile_to_openapi
|
package/lib/import/common.js
CHANGED
|
@@ -510,7 +510,8 @@ async function postProcess(filePath, options, csn, cwd) {
|
|
|
510
510
|
usingStatements.push(`using from './${path.basename(csnFile.replace(`'`, `''`))}';`);
|
|
511
511
|
}
|
|
512
512
|
|
|
513
|
-
|
|
513
|
+
if (!options.dry)
|
|
514
|
+
_printUsageHint(csnFile, services, cwd);
|
|
514
515
|
|
|
515
516
|
if (!options.dry && !options.no_copy)
|
|
516
517
|
await _copyToSrvExternal(filePath, destFilePath, cwd);
|
|
@@ -38,6 +38,7 @@ module.exports = class ParserContext {
|
|
|
38
38
|
this.schemaAliasToNamespace = {};
|
|
39
39
|
this.schemaToSchemaDataIndex = {};
|
|
40
40
|
this.schemaToPrimarySchema = {};
|
|
41
|
+
this.schemaDetails = {};
|
|
41
42
|
this.vocabNamespaceToAlias = {};
|
|
42
43
|
this.entityToBoundActions = {};
|
|
43
44
|
this.entityToBoundFunctions = {};
|
|
@@ -634,7 +634,7 @@ function _generateStructuredDataTypeCsn(dataType, propertyObject, isPrimaryKey,
|
|
|
634
634
|
|
|
635
635
|
function _parseAssociationProperty(foreignReference, associationNode, parserContext) {
|
|
636
636
|
const associationProperty = {};
|
|
637
|
-
associationProperty.type = (associationNode.$OnDelete === 'Cascade') ? 'cds.Composition' : 'cds.Association';
|
|
637
|
+
associationProperty.type = (associationNode.$OnDelete === 'Cascade' || associationNode.$ContainsTarget) ? 'cds.Composition' : 'cds.Association';
|
|
638
638
|
|
|
639
639
|
let schemaName = associationNode.$Type.substring(0, associationNode.$Type.lastIndexOf('.'));
|
|
640
640
|
|
|
@@ -642,6 +642,11 @@ function _parseAssociationProperty(foreignReference, associationNode, parserCont
|
|
|
642
642
|
schemaName = parserContext.schemaAliasToNamespace[schemaName];
|
|
643
643
|
}
|
|
644
644
|
|
|
645
|
+
if (associationNode.$ContainsTarget) {
|
|
646
|
+
parserContext.schemaDetails[schemaName] ??= {}
|
|
647
|
+
parserContext.schemaDetails[schemaName].containment = true
|
|
648
|
+
}
|
|
649
|
+
|
|
645
650
|
let resolvedEntityName;
|
|
646
651
|
let entityTypeMapping = (
|
|
647
652
|
parserContext.entityToEntitySetMap?.get(associationNode.$Type) ||
|
|
@@ -676,9 +681,18 @@ function _parseAssociationProperty(foreignReference, associationNode, parserCont
|
|
|
676
681
|
} else {
|
|
677
682
|
associationProperty.cardinality.max = 1;
|
|
678
683
|
}
|
|
679
|
-
|
|
684
|
+
|
|
685
|
+
// Generate on condition in case $Partner exists, as that indicates a backlink with which the
|
|
686
|
+
// condition can be generated.
|
|
687
|
+
// If not given convert managed associations and compositions in unmanaged with empty key to avoid
|
|
680
688
|
// "generation" of keys, that do not exist in the external service.
|
|
681
|
-
if (
|
|
689
|
+
if (associationNode.$Partner && associationProperty.type === 'cds.Composition') {
|
|
690
|
+
associationProperty.on = [
|
|
691
|
+
{ref: [foreignReference, associationNode.$Partner]},
|
|
692
|
+
'=',
|
|
693
|
+
{ref: ['$self']}
|
|
694
|
+
]
|
|
695
|
+
} else if (common.checkForEmptyKeys(associationProperty, "V4")) {
|
|
682
696
|
associationProperty.keys = [];
|
|
683
697
|
}
|
|
684
698
|
_captureAnnotationWithinElement(associationNode, associationProperty, parserContext);
|
|
@@ -1653,12 +1667,43 @@ function _generateCSN(edmxAsJson, ignorePersistenceSkip, parserContext, importer
|
|
|
1653
1667
|
csn.definitions[parserContext.primarySchema].kind = 'service';
|
|
1654
1668
|
csn.definitions[parserContext.primarySchema]['@cds.external'] = true;
|
|
1655
1669
|
|
|
1670
|
+
if (parserContext.schemaDetails[parserContext.primarySchema]?.containment) {
|
|
1671
|
+
csn.definitions[parserContext.primarySchema]['@odata.containment'] = true;
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1656
1674
|
// Step 8: parse entity container contents and their annotations
|
|
1657
1675
|
let schemaData = schemaDataList[parserContext.schemaToSchemaDataIndex[parserContext.primarySchema]];
|
|
1658
1676
|
let entityContainerElements = schemaData[parserContext.entityContainerName];
|
|
1659
1677
|
csn.definitions = Object.assign(_parseEntityContainer(csn.definitions, entityContainerElements, parserContext), csn.definitions);
|
|
1660
1678
|
}
|
|
1661
1679
|
|
|
1680
|
+
|
|
1681
|
+
// Step 9: 2. Step for generating $ContainsTarget & $Partner links
|
|
1682
|
+
// The containing composition is already generated. Now the Keys: [] has to be removed
|
|
1683
|
+
// on the backlink association because per OData spec, OData does not expose the foreign key fields
|
|
1684
|
+
// used by the backlink and thus it is save to assume they must be generated for proper mocking
|
|
1685
|
+
//
|
|
1686
|
+
// This happens after Step 8 because that adjusts the names of entity container entities where
|
|
1687
|
+
// entity type and entity set differ in naming
|
|
1688
|
+
for (const entity in csn.definitions) {
|
|
1689
|
+
if (entity.type !== 'entity') continue;
|
|
1690
|
+
|
|
1691
|
+
const containingCompositions = Object.keys(csn.definitions[entity].elements).filter(e =>
|
|
1692
|
+
csn.definitions[entity].elements[e].type === 'cds.Composition' &&
|
|
1693
|
+
csn.definitions[entity].elements[e].on
|
|
1694
|
+
);
|
|
1695
|
+
for (const comp of containingCompositions) {
|
|
1696
|
+
const compTarget = csn.definitions[csn.definitions[entity].elements[comp].target];
|
|
1697
|
+
const backLink = Object.keys(compTarget.elements).find(e =>
|
|
1698
|
+
compTarget.elements[e].type === 'cds.Association' &&
|
|
1699
|
+
compTarget.elements[e].target === entity
|
|
1700
|
+
)
|
|
1701
|
+
if (compTarget.elements[backLink].keys) {
|
|
1702
|
+
delete compTarget.elements[backLink].keys
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1662
1707
|
return JSON.stringify(csn, null, 4);
|
|
1663
1708
|
}
|
|
1664
1709
|
|
|
@@ -4,6 +4,8 @@ const {
|
|
|
4
4
|
pathAndMethod,
|
|
5
5
|
serviceName,
|
|
6
6
|
} = require("./utilities");
|
|
7
|
+
const cds = require('../../cds');
|
|
8
|
+
|
|
7
9
|
|
|
8
10
|
module.exports = { importOpenAPI };
|
|
9
11
|
|
|
@@ -32,7 +34,10 @@ function importOpenAPI(input) {
|
|
|
32
34
|
};
|
|
33
35
|
|
|
34
36
|
const context = {
|
|
35
|
-
serviceName: serviceName(
|
|
37
|
+
serviceName: serviceName(cds.cli.options["into-namespace"]
|
|
38
|
+
?? input.info?.title
|
|
39
|
+
?? "TODO.service"
|
|
40
|
+
),
|
|
36
41
|
oasVersion: input.openapi || input.swagger,
|
|
37
42
|
v3: !!input.openapi,
|
|
38
43
|
schemas: input.openapi ? input.components?.schemas : input.definitions,
|
package/lib/init/constants.js
CHANGED
package/lib/init/index.js
CHANGED
|
@@ -231,17 +231,26 @@ module.exports = class CDSGenerator {
|
|
|
231
231
|
const templates = new Map
|
|
232
232
|
for (let plugin of plugins) {
|
|
233
233
|
// Compat
|
|
234
|
-
if (plugin === 'appfront') plugin = 'app-front'
|
|
235
234
|
if (plugin === 'helm' && cds.cli.options['internal-unified-runtime-charts']) {
|
|
235
|
+
console.warn(term.warn('"--internal-unified-runtime-charts" is deprecated, please use "cds add kyma --unified-runtime" instead'))
|
|
236
236
|
plugin = 'helm-unified-runtime'
|
|
237
237
|
cds.cli.options.add?.delete('helm')
|
|
238
238
|
cds.cli.options.add?.add('helm-unified-runtime')
|
|
239
239
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
240
|
+
const _alias = (alias, preferred) => {
|
|
241
|
+
if (plugin === alias) {
|
|
242
|
+
plugin = preferred
|
|
243
|
+
cds.cli.options.add?.delete(alias)
|
|
244
|
+
cds.cli.options.add?.add(preferred)
|
|
245
|
+
cds.cli.argv[0] = cds.cli.argv[0].replace(alias, preferred)
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
_alias('appfront', 'app-frontend')
|
|
249
|
+
_alias('app-front', 'app-frontend')
|
|
250
|
+
_alias('gha', 'github-actions')
|
|
251
|
+
_alias('postgresql', 'postgres')
|
|
252
|
+
_alias('kibana', 'application-logging')
|
|
253
|
+
_alias('kibana-logging', 'application-logging')
|
|
245
254
|
|
|
246
255
|
if (!templates.has(plugin)) {
|
|
247
256
|
const template = await this._createTemplate(plugin)
|
package/lib/init/merge.js
CHANGED
|
@@ -106,6 +106,9 @@ async function _mergeYAML(into, from, project, semantics = {}) {
|
|
|
106
106
|
if (project) await writeYAML(into, source)
|
|
107
107
|
else await copy(from, into)
|
|
108
108
|
return source
|
|
109
|
+
} else if (typeof into === 'string') {
|
|
110
|
+
await writeYAML(into, source)
|
|
111
|
+
return source
|
|
109
112
|
}
|
|
110
113
|
throw new Error(`Target YAML doesn't exist`)
|
|
111
114
|
}
|
|
@@ -113,6 +116,19 @@ async function _mergeYAML(into, from, project, semantics = {}) {
|
|
|
113
116
|
const entryMap = new Map, templateEntryMap = new Map
|
|
114
117
|
|
|
115
118
|
const { additions, overwrites, deletions, relationships } = semantics
|
|
119
|
+
if (relationships && Array.isArray(relationships)) {
|
|
120
|
+
semantics.additions ??= []
|
|
121
|
+
const add = semantics.additions
|
|
122
|
+
|
|
123
|
+
for (const rel of relationships) {
|
|
124
|
+
for (const ins of (Array.isArray(rel.insert) ? rel.insert : [rel.insert])) {
|
|
125
|
+
if (!add.includes(ins)) add.push(ins)
|
|
126
|
+
}
|
|
127
|
+
const base = rel.into?.[0]
|
|
128
|
+
if (base && !add.includes(base)) add.push(base)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
116
132
|
for (const entry of additions ?? []) {
|
|
117
133
|
entryMap.set(entry, undefined)
|
|
118
134
|
templateEntryMap.set(entry, undefined)
|
|
@@ -123,9 +123,9 @@ module.exports = new class ProjectReader {
|
|
|
123
123
|
const inbounds = manifest?.['sap.app']?.crossNavigation?.inbounds
|
|
124
124
|
const [firstInbound] = Object.values(inbounds ?? { intent: { semanticObject: 'Books', action: 'display' } })
|
|
125
125
|
const vizId = firstInbound.semanticObject + '-' + firstInbound.action
|
|
126
|
-
// Try to read archiveName from ui5
|
|
126
|
+
// Try to read archiveName from ui5.yaml if it exists
|
|
127
127
|
let archiveName = ''
|
|
128
|
-
const ui5DeployPath = path.resolve(cds.root, cds.env.folders.app, app, 'ui5
|
|
128
|
+
const ui5DeployPath = path.resolve(cds.root, cds.env.folders.app, app, 'ui5.yaml')
|
|
129
129
|
if (exists(ui5DeployPath)) {
|
|
130
130
|
const ui5Deploy = cds.load.yaml(ui5DeployPath)
|
|
131
131
|
const customTasks = ui5Deploy?.builder?.customTasks
|
|
@@ -159,6 +159,7 @@ module.exports = new class ProjectReader {
|
|
|
159
159
|
hasUIEmbedded: _uiEmbedded,
|
|
160
160
|
hasUIModule: _uiModule,
|
|
161
161
|
hasUI: () => _uiEmbedded() || _uiModule(),
|
|
162
|
+
hasUI5: () => _uiEmbedded() || _uiModule(),
|
|
162
163
|
literal: () => () => text => text,
|
|
163
164
|
hasMTXRoute: () => _inProd('extensibility') || (_inProd('multitenancy') && !_isJava()),
|
|
164
165
|
hasMTXRouteJava: () => (_inProd('helm-unified-runtime') || _inProd('helm')) && _isJava() && _inProd('multitenancy'),
|
|
@@ -175,7 +176,21 @@ module.exports = new class ProjectReader {
|
|
|
175
176
|
return this.npmWorkspaceRoot() !== cds.root
|
|
176
177
|
},
|
|
177
178
|
hasRoles: () => { }, roles: () => { }, // for xs-security generation
|
|
178
|
-
hasCustomRoleCollections: () => exists('xs-security.json') && !!JSON.parse(fs.readFileSync(path.join(cds.root, 'xs-security.json')))['role-collections']
|
|
179
|
+
hasCustomRoleCollections: () => exists('xs-security.json') && !!JSON.parse(fs.readFileSync(path.join(cds.root, 'xs-security.json')))['role-collections'],
|
|
180
|
+
k8s: () => {
|
|
181
|
+
if (!exists('chart/values.yaml')) return {}
|
|
182
|
+
|
|
183
|
+
const values = cds.load.yaml(join(cds.root, 'chart/values.yaml'))
|
|
184
|
+
|
|
185
|
+
let containerize = {}
|
|
186
|
+
if (exists('containerize.yaml'))
|
|
187
|
+
containerize = cds.load.yaml(join(cds.root, 'containerize.yaml'))
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
values: values ?? {},
|
|
191
|
+
containerize: containerize ?? {}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
179
194
|
}
|
|
180
195
|
|
|
181
196
|
// Automatically creates availability checks for `cds add` commands.
|
|
@@ -311,4 +326,4 @@ function _normalizeSpringBootCfg(obj) {
|
|
|
311
326
|
* @property {String} githubSlug GitHub org/repo.
|
|
312
327
|
* @property {boolean} isMonorepoMicroservice Indicates if the project is a monorepo microservice.
|
|
313
328
|
* @property {String} npmWorkspaceRoot The root path of the monorepo workspace.
|
|
314
|
-
*/
|
|
329
|
+
*/
|
|
@@ -152,9 +152,9 @@ const requiredAppApi4 = module => ({
|
|
|
152
152
|
where: { name: 'app-api' }
|
|
153
153
|
})
|
|
154
154
|
|
|
155
|
-
const requiredMtxSidecarApi4 = srv => ({
|
|
155
|
+
const requiredMtxSidecarApi4 = (srv, name) => ({
|
|
156
156
|
in: [srv, 'requires'],
|
|
157
|
-
where: { 'properties.CDS_MULTITENANCY_SIDECAR_URL':
|
|
157
|
+
where: { 'properties.CDS_MULTITENANCY_SIDECAR_URL': name }
|
|
158
158
|
})
|
|
159
159
|
|
|
160
160
|
const requiredJavaApprouterApi4 = srv => ({
|
|
@@ -15,7 +15,7 @@ module.exports = class AmsTemplate extends require('../../plugin') {
|
|
|
15
15
|
|
|
16
16
|
static hasInProduction(env) {
|
|
17
17
|
const { dependencies, devDependencies } = readProject()
|
|
18
|
-
return env.requires?.auth?.ams || devDependencies?.['@sap/ams-dev'] || dependencies?.['@sap/ams']
|
|
18
|
+
return env.requires?.auth?.ams || devDependencies?.['@sap/ams-dev'] || devDependencies?.['@sap/ams'] || dependencies?.['@sap/ams']
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
async run() {
|
|
@@ -3,18 +3,12 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"main": "webapp/index.html",
|
|
5
5
|
"scripts": {
|
|
6
|
-
"build": "ui5 build preload --clean-dest
|
|
7
|
-
"build-local": "ui5 build preload --clean-dest",
|
|
6
|
+
"build": "ui5 build preload --clean-dest",
|
|
8
7
|
"start": "ui5 serve"
|
|
9
8
|
},
|
|
10
9
|
"devDependencies": {
|
|
11
10
|
"@ui5/cli": "^4",
|
|
12
11
|
"ui5-task-zipper": "^3"
|
|
13
|
-
},
|
|
14
|
-
"ui5": {
|
|
15
|
-
"dependencies": [
|
|
16
|
-
"ui5-task-zipper"
|
|
17
|
-
]
|
|
18
12
|
}
|
|
19
13
|
{{/hasUI5}}
|
|
20
14
|
}
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
---
|
|
2
2
|
# yaml-language-server: $schema=https://sap.github.io/ui5-tooling/schema/ui5.yaml.json
|
|
3
|
-
specVersion: '
|
|
3
|
+
specVersion: '4.0'
|
|
4
4
|
metadata:
|
|
5
5
|
name: {{app}}
|
|
6
6
|
type: application
|
|
7
|
+
resources:
|
|
8
|
+
configuration:
|
|
9
|
+
propertiesFileSourceEncoding: UTF-8
|
|
10
|
+
builder:
|
|
11
|
+
resources:
|
|
12
|
+
excludes:
|
|
13
|
+
- "/test/**"
|
|
14
|
+
- "/localService/**"
|
|
15
|
+
customTasks:
|
|
16
|
+
- name: ui5-task-zipper
|
|
17
|
+
afterTask: generateVersionInfo
|
|
18
|
+
configuration:
|
|
19
|
+
archiveName: {{app}}
|
|
20
|
+
additionalFiles:
|
|
21
|
+
- xs-app.json
|
|
22
|
+
{{#isTypescript}}
|
|
23
|
+
- name: ui5-tooling-transpile-task
|
|
24
|
+
afterTask: replaceVersion
|
|
25
|
+
{{/isTypescript}}
|
|
@@ -26,10 +26,6 @@ module.exports = class extends require('../../plugin') {
|
|
|
26
26
|
project.app = app
|
|
27
27
|
await merge(__dirname, 'files/ui5.yaml.hbs').into(join(appPath, app, 'ui5.yaml'), { project })
|
|
28
28
|
}
|
|
29
|
-
for (const { app } of apps) {
|
|
30
|
-
project.app = app
|
|
31
|
-
await merge(__dirname, 'files/ui5-deploy.yaml.hbs').into(join(appPath, app, 'ui5-deploy.yaml'), { project })
|
|
32
|
-
}
|
|
33
29
|
}
|
|
34
30
|
|
|
35
31
|
for (const { app } of apps) {
|
|
@@ -28,28 +28,23 @@ module.exports = class ApplicationLoggingTemplate extends require('../../plugin'
|
|
|
28
28
|
|
|
29
29
|
async combine() {
|
|
30
30
|
const project = readProject()
|
|
31
|
-
const { addMta,
|
|
31
|
+
const { addMta, hasMta, hasApprouter, isJava, addMultitenancy, hasMultitenancy, srvPath } = project
|
|
32
32
|
|
|
33
|
-
if (addMta || addMultitenancy) {
|
|
33
|
+
if (addMta || (addMultitenancy && hasMta)) {
|
|
34
34
|
const additions = [], relationships = []
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
if (addMultitenancy) {
|
|
35
|
+
const srv = srv4(srvPath)
|
|
36
|
+
relationships.push({
|
|
37
|
+
insert: [applicationLogging, 'name'],
|
|
38
|
+
into: [srv, 'requires', 'name']
|
|
39
|
+
})
|
|
40
|
+
if (hasMultitenancy) {
|
|
44
41
|
const mtxSidecar = mtxSidecar4(isJava ? 'mtx/sidecar' : 'gen/mtx/sidecar')
|
|
45
|
-
additions.push(mtxSidecar)
|
|
46
42
|
relationships.push({
|
|
47
43
|
insert: [applicationLogging, 'name'],
|
|
48
44
|
into: [mtxSidecar, 'requires', 'name']
|
|
49
45
|
})
|
|
50
46
|
}
|
|
51
|
-
if (
|
|
52
|
-
additions.push(approuter)
|
|
47
|
+
if (hasApprouter) {
|
|
53
48
|
relationships.push({
|
|
54
49
|
insert: [applicationLogging, 'name'],
|
|
55
50
|
into: [approuter, 'requires', 'name']
|
|
@@ -57,7 +57,6 @@ modules:
|
|
|
57
57
|
url: ${default-url}
|
|
58
58
|
{{/isJava}}
|
|
59
59
|
|
|
60
|
-
{{#hasMultitenancy}}
|
|
61
60
|
- name: {{appName}}-mtx
|
|
62
61
|
type: nodejs
|
|
63
62
|
path: {{#isNodejs}}gen/{{/isNodejs}}mtx/sidecar{{#isNodejs}}
|
|
@@ -66,7 +65,6 @@ modules:
|
|
|
66
65
|
properties:
|
|
67
66
|
SUBSCRIPTION_URL: ~{app-protocol}://\${tenant_subdomain}-~{app-uri}
|
|
68
67
|
{{/isNodejs}}
|
|
69
|
-
{{/hasMultitenancy}}
|
|
70
68
|
|
|
71
69
|
resources:
|
|
72
70
|
- name: {{appName}}-auth
|
|
@@ -35,30 +35,29 @@ module.exports = class ApprouterTemplate extends require('../../plugin') {
|
|
|
35
35
|
const {
|
|
36
36
|
isNodejs, isJava,
|
|
37
37
|
addIas, addXsuaa, hasXsuaa, hasIas, addMultitenancy, hasMTXRoute, hasMTXRouteJava,
|
|
38
|
-
addMta, addHelm, addHelmUnifiedRuntime,
|
|
38
|
+
addMta, addHelm, addHelmUnifiedRuntime,
|
|
39
|
+
hasMta, hasHelm, hasHelmUnifiedRuntime, hasMultitenancy,
|
|
39
40
|
addContainerize, srvPath, approuterPath
|
|
40
41
|
} = project
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
if (addMta || (addMultitenancy || addXsuaa || addIas) && hasMta) {
|
|
44
45
|
const srv = srv4(srvPath)
|
|
45
|
-
const apis = isJava &&
|
|
46
|
+
const apis = isJava && hasMultitenancy ? [requiredJavaApprouterApi4(srv), providedJavaApprouterApi] : []
|
|
46
47
|
const mtxSidecar = mtxSidecar4(isJava ? 'mtx/sidecar' : 'gen/mtx/sidecar')
|
|
47
|
-
if (isNodejs &&
|
|
48
|
-
if (isJava &&
|
|
48
|
+
if (isNodejs && hasMultitenancy) apis.push(requiredMtxApi, requiredAppApi4(mtxSidecar), providedAppApi)
|
|
49
|
+
if (isJava && hasMultitenancy) apis.push(requiredMtxApi)
|
|
49
50
|
const modules = [srv, approuter]
|
|
50
|
-
if (
|
|
51
|
+
if (hasMultitenancy) modules.push(mtxSidecar)
|
|
51
52
|
const additions = [...modules, ...apis]
|
|
52
53
|
const relationships = []
|
|
53
54
|
if (hasXsuaa) {
|
|
54
|
-
additions.push(xsuaa)
|
|
55
55
|
relationships.push({
|
|
56
56
|
insert: [xsuaa, 'name'],
|
|
57
57
|
into: [approuter, 'requires', 'name']
|
|
58
58
|
})
|
|
59
59
|
}
|
|
60
60
|
if (hasIas) {
|
|
61
|
-
additions.push(ias)
|
|
62
61
|
relationships.push({
|
|
63
62
|
insert: [ias, 'name'],
|
|
64
63
|
into: [approuter, 'requires', 'name']
|