@sap/cds-dk 7.6.0 → 7.7.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/bin/cds.js +1 -1
- package/bin/import.js +2 -2
- package/bin/version.js +21 -20
- package/bin/watch.js +6 -0
- package/lib/build/buildTaskEngine.js +6 -4
- package/lib/build/buildTaskProviderFactory.js +5 -0
- package/lib/build/provider/edmxBuildPlugin.js +1 -1
- package/lib/build/provider/internalBuildTaskProvider.js +12 -10
- package/lib/build/provider/mtx/index.js +2 -2
- package/lib/build/provider/mtx/resourcesTarBuilder.js +1 -1
- package/lib/build/provider/mtx-extension/extensionCompilation.js +50 -0
- package/lib/build/provider/mtx-extension/index.js +50 -48
- package/lib/build/provider/mtx-sidecar/index.js +3 -3
- package/lib/build/util.js +9 -4
- package/lib/deploy/to-hana/hana.js +46 -76
- package/lib/deploy/to-hana/hdiDeployUtil.js +15 -18
- package/lib/deploy/to-hana/mtaUtil.js +1 -1
- package/lib/env/schema.js +1 -0
- package/lib/env/schemas/cds-rc.js +54 -1
- package/lib/import/asyncapi/parserContext.js +6 -0
- package/lib/import/common.js +18 -23
- package/lib/import/odata/metadataconverter/MetadataConverter.js +12 -8
- package/lib/import/odata/v4parser.js +67 -12
- package/lib/init/add.js +2 -0
- package/lib/init/constants.js +2 -4
- package/lib/init/merge.js +31 -13
- package/lib/init/projectReader.js +9 -1
- package/lib/init/registries/mta.js +19 -1
- package/lib/init/template/approuter/files/mta.yaml.hbs +1 -1
- package/lib/init/template/approuter/index.js +5 -5
- package/lib/init/template/connectivity/index.js +3 -4
- package/lib/init/template/html5-repo/files/app-package.json.hbs +16 -0
- package/lib/init/template/html5-repo/files/mta.yaml.hbs +83 -0
- package/lib/init/template/html5-repo/files/package.json.hbs +17 -0
- package/lib/init/template/html5-repo/files/ui5.yaml.hbs +33 -0
- package/lib/init/template/html5-repo/files/xs-app.json.hbs +19 -0
- package/lib/init/template/html5-repo/index.js +56 -12
- package/lib/init/template/mta/files/mta.yaml.hbs +1 -0
- package/lib/init/template/mta/index.js +5 -0
- package/lib/init/template/nodejs/files/.vscode/extensions.json +1 -2
- package/lib/init/template/nodejs/files/README.md +1 -1
- package/lib/init/template/sample/files/app/index.html +8 -6
- package/lib/init/template/sample/index.js +12 -2
- package/lib/lint/Linter.js +2 -2
- package/lib/lint/checks.js +0 -51
- package/lib/mtx/auth_manager.js +46 -55
- package/lib/mtx/settings_manager.js +14 -19
- package/lib/mtx/util/dependencies.js +1 -1
- package/lib/mtx/util/logging.js +10 -8
- package/lib/util/axios.js +5 -0
- package/lib/util/cf.js +1 -0
- package/npm-shrinkwrap.json +96 -42
- package/package.json +1 -10
|
@@ -426,8 +426,8 @@ function _parseAnnotationTerms(annotationTerm, annotationTermObject, csnDefsTarg
|
|
|
426
426
|
function _resolveAnotationTerm(schemaDataAnnotation, parserContext) {
|
|
427
427
|
// Case 1: We have the Namespace and Alias for the vocabulary
|
|
428
428
|
for (const [alias, namespace] of Object.entries(parserContext.vocabAliasToNamespace)) {
|
|
429
|
-
if (schemaDataAnnotation.includes('@' + alias)) {
|
|
430
|
-
schemaDataAnnotation = schemaDataAnnotation.split('@' + alias).join('@' + known_vocabularies[namespace]);
|
|
429
|
+
if (schemaDataAnnotation.includes('@' + alias + '.')) {
|
|
430
|
+
schemaDataAnnotation = schemaDataAnnotation.split('@' + alias + '.').join('@' + known_vocabularies[namespace] + '.');
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
/**
|
|
@@ -1225,6 +1225,15 @@ function _addSuffixForCollisionTypes(fqName, suffix) {
|
|
|
1225
1225
|
function _parseEntityContainer(csnDefs, entityContainerElements, parserContext) {
|
|
1226
1226
|
const entityContainerElementNames = Object.keys(entityContainerElements);
|
|
1227
1227
|
const redundantElementNames = [];
|
|
1228
|
+
let possibleAnnotations = {};
|
|
1229
|
+
|
|
1230
|
+
// filter entries starting with '@', they can be possible annotation
|
|
1231
|
+
entityContainerElementNames.filter(
|
|
1232
|
+
elementName => elementName.startsWith('@')
|
|
1233
|
+
).forEach(elementName => {
|
|
1234
|
+
possibleAnnotations[elementName] = entityContainerElements[elementName];
|
|
1235
|
+
delete entityContainerElements[elementName];
|
|
1236
|
+
});
|
|
1228
1237
|
|
|
1229
1238
|
entityContainerElementNames.forEach(ecElement => {
|
|
1230
1239
|
if (entityContainerElements[ecElement] instanceof Object) {
|
|
@@ -1294,6 +1303,49 @@ function _parseEntityContainer(csnDefs, entityContainerElements, parserContext)
|
|
|
1294
1303
|
delete csnDefs[name];
|
|
1295
1304
|
});
|
|
1296
1305
|
|
|
1306
|
+
// check for possible annotations present within the entity container
|
|
1307
|
+
if (Object.keys(possibleAnnotations).length > 0) {
|
|
1308
|
+
let entityContainerAnnotations = {};
|
|
1309
|
+
let annotationTarget = parserContext.primarySchema + '.' + parserContext.entityContainerName;
|
|
1310
|
+
possibleAnnotations = _resolveAnotationTerm(
|
|
1311
|
+
JSON.stringify(possibleAnnotations), parserContext
|
|
1312
|
+
);
|
|
1313
|
+
/**
|
|
1314
|
+
* If the same annotation target already exists because of the annotation present outside
|
|
1315
|
+
* of the EntityContainer, then append the possible annotations to it and parse all of them.
|
|
1316
|
+
* Few exact same annotation term if exists, will result in information being overwritten
|
|
1317
|
+
* by the annotation term present within the EntityContainer.
|
|
1318
|
+
*/
|
|
1319
|
+
if (Object.keys(parserContext.entityContainerAnnotations).length > 0) {
|
|
1320
|
+
entityContainerAnnotations = parserContext.entityContainerAnnotations;
|
|
1321
|
+
/**
|
|
1322
|
+
* When the parserContext.entityContainerAnnotations contains the annotation target,
|
|
1323
|
+
* and we have unique information present within EntityContainer as well as indipendent
|
|
1324
|
+
* annotation, we have to merge them.
|
|
1325
|
+
*/
|
|
1326
|
+
if (parserContext.entityContainerAnnotations[annotationTarget] &&
|
|
1327
|
+
Object.keys(parserContext.entityContainerAnnotations[annotationTarget]).length > 0
|
|
1328
|
+
) {
|
|
1329
|
+
entityContainerAnnotations[annotationTarget] = Object.assign(
|
|
1330
|
+
entityContainerAnnotations[annotationTarget],
|
|
1331
|
+
possibleAnnotations
|
|
1332
|
+
);
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* If the annotation target name is different, we can expand all of the information
|
|
1336
|
+
* into a single object itself
|
|
1337
|
+
*/
|
|
1338
|
+
else {
|
|
1339
|
+
entityContainerAnnotations[annotationTarget] = possibleAnnotations;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
// Simply add the possible annotations to the object with the target
|
|
1343
|
+
else {
|
|
1344
|
+
entityContainerAnnotations[annotationTarget] = possibleAnnotations;
|
|
1345
|
+
}
|
|
1346
|
+
parserContext.entityContainerAnnotations = entityContainerAnnotations;
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1297
1349
|
// parse all the entity container annotations
|
|
1298
1350
|
if (parserContext.entityContainerAnnotations) {
|
|
1299
1351
|
_parseAnnotations(parserContext.entityContainerAnnotations, csnDefs, parserContext);
|
|
@@ -1450,6 +1502,17 @@ function _collectSchemaElements(edmxAsJson, schemaDataList, parserContext) {
|
|
|
1450
1502
|
|
|
1451
1503
|
_collectUnboundedActionFunction(schemaDataList, parserContext);
|
|
1452
1504
|
|
|
1505
|
+
// capture all the references
|
|
1506
|
+
if (edmxAsJson.$Reference) {
|
|
1507
|
+
Object.entries(edmxAsJson.$Reference).forEach(ref => {
|
|
1508
|
+
if (ref[1].$Include[0].$Alias &&
|
|
1509
|
+
known_vocabularies.hasOwnProperty(ref[1].$Include[0].$Namespace)
|
|
1510
|
+
) {
|
|
1511
|
+
parserContext.vocabAliasToNamespace[ref[1].$Include[0].$Alias] = ref[1].$Include[0].$Namespace;
|
|
1512
|
+
}
|
|
1513
|
+
});
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1453
1516
|
// collect entityType, enumType, complexType, typeDefinition, bounded action/function, annotations
|
|
1454
1517
|
for (let schemaData of schemaDataList) {
|
|
1455
1518
|
let currNamespace = schemaData.$SchemaNamespace;
|
|
@@ -1472,15 +1535,6 @@ function _collectSchemaElements(edmxAsJson, schemaDataList, parserContext) {
|
|
|
1472
1535
|
}
|
|
1473
1536
|
// annotations
|
|
1474
1537
|
else if (elementName === '$Annotations') {
|
|
1475
|
-
if (edmxAsJson.$Reference) {
|
|
1476
|
-
Object.entries(edmxAsJson.$Reference).forEach(ref => {
|
|
1477
|
-
if (ref[1].$Include[0].$Alias &&
|
|
1478
|
-
known_vocabularies.hasOwnProperty(ref[1].$Include[0].$Namespace)
|
|
1479
|
-
) {
|
|
1480
|
-
parserContext.vocabAliasToNamespace[ref[1].$Include[0].$Alias] = ref[1].$Include[0].$Namespace;
|
|
1481
|
-
}
|
|
1482
|
-
});
|
|
1483
|
-
}
|
|
1484
1538
|
schemaData.$Annotations = _resolveAnotationTerm(JSON.stringify(schemaData.$Annotations), parserContext);
|
|
1485
1539
|
/**
|
|
1486
1540
|
* collect entity container annotations with the assumption that
|
|
@@ -1552,7 +1606,8 @@ function _preProcess(edmxAsJson, parserContext, importerContext) {
|
|
|
1552
1606
|
parserContext.entityToEntitySetMap._.size === 0 &&
|
|
1553
1607
|
parserContext.entityToSingletonMap._.size === 0 &&
|
|
1554
1608
|
parserContext.actionToActionImportMap._.size === 0 &&
|
|
1555
|
-
parserContext.functionToFunctionImportMap._.size === 0)
|
|
1609
|
+
parserContext.functionToFunctionImportMap._.size === 0)
|
|
1610
|
+
{
|
|
1556
1611
|
parserContext.mockServerUc = false;
|
|
1557
1612
|
}
|
|
1558
1613
|
|
package/lib/init/add.js
CHANGED
|
@@ -3,6 +3,8 @@ const registered = new Map
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
Plugin: require('./plugin'),
|
|
5
5
|
merge: require('./merge').merge, // fluent API
|
|
6
|
+
removeFromYAML: require('./merge').removeFromYAML,
|
|
7
|
+
removeFromYAMLArray: require('./merge').removeFromYAMLArray,
|
|
6
8
|
readProject: require('./projectReader').readProject,
|
|
7
9
|
mvn: {
|
|
8
10
|
add: require('./mvn').add
|
package/lib/init/constants.js
CHANGED
|
@@ -4,7 +4,7 @@ module.exports = {
|
|
|
4
4
|
COMMAND_INIT: 'init',
|
|
5
5
|
COMMAND_ADD: 'add',
|
|
6
6
|
|
|
7
|
-
MAVEN_ARCHETYPE_VERSION: '2.
|
|
7
|
+
MAVEN_ARCHETYPE_VERSION: '2.6.1',
|
|
8
8
|
|
|
9
9
|
OPTIONS: Object.freeze({
|
|
10
10
|
JAVA: 'java',
|
|
@@ -57,9 +57,7 @@ module.exports = {
|
|
|
57
57
|
SAMPLES: 'https://github.com/SAP-samples/cloud-cap-samples',
|
|
58
58
|
CAPIRE: 'https://cap.cloud.sap',
|
|
59
59
|
MAVEN_ARCHETYPE_HELP: `https://cap.cloud.sap/docs/java/development/#the-maven-archetype`,
|
|
60
|
-
MAVEN_INSTALL_HELP: `https://maven.apache.org/install.html
|
|
61
|
-
VSCODE: 'https://code.visualstudio.com/',
|
|
62
|
-
VSCODE_ESLINT: 'https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint'
|
|
60
|
+
MAVEN_INSTALL_HELP: `https://maven.apache.org/install.html`
|
|
63
61
|
}),
|
|
64
62
|
|
|
65
63
|
PROJECT_FILES: ['package.json', 'pom.xml', '.cdsrc.json']
|
package/lib/init/merge.js
CHANGED
|
@@ -141,7 +141,7 @@ async function _mergeYAML(into, from, project, semantics = {}) {
|
|
|
141
141
|
throw new Error(`Target YAML doesn't exist`)
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
-
const entryMap = new Map, templateEntryMap = new Map
|
|
144
|
+
const entryMap = new Map, templateEntryMap = new Map
|
|
145
145
|
|
|
146
146
|
const { additions, overwrites, deletions, relationships } = semantics
|
|
147
147
|
additions?.forEach(entry => {
|
|
@@ -236,7 +236,7 @@ async function _mergeYAML(into, from, project, semantics = {}) {
|
|
|
236
236
|
|
|
237
237
|
if (!templateCollection?.items) return
|
|
238
238
|
|
|
239
|
-
templateCollection.items
|
|
239
|
+
templateCollection.items?.forEach((templateNode, templateIndex) => {
|
|
240
240
|
if (YAML.isScalar(templateNode)) {
|
|
241
241
|
if (!collection.items.map(item => item.value).includes(templateNode.value)) {
|
|
242
242
|
collection.add(templateNode)
|
|
@@ -413,20 +413,38 @@ async function removeFromYAMLArray(name, keyPath, aliasToRemove) {
|
|
|
413
413
|
await writeYAML(name, yaml)
|
|
414
414
|
}
|
|
415
415
|
|
|
416
|
+
|
|
416
417
|
const path = require('path')
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* @param {...(string | Object | YAML.Document)} src The source to merge from.
|
|
421
|
+
* @returns {{
|
|
422
|
+
* into: (dst: (string | Object | YAML.Document), options?: {project?: Object, semantics?: MergingSemantics}) => Promise<any>
|
|
423
|
+
* }} An object with an 'into' method to merge the sources into the specified destination.
|
|
424
|
+
*/
|
|
417
425
|
const merge = (...src) => {
|
|
418
|
-
return {
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
426
|
+
return {
|
|
427
|
+
/**
|
|
428
|
+
* Merges sources into the specified destination.
|
|
429
|
+
* @param {(string | Object | YAML.Document)} dst File path or object to merge into.
|
|
430
|
+
* @param {Object} [options] Merging options.
|
|
431
|
+
* @param {Object} [options.project] Project descriptor used for Mustache replacements.
|
|
432
|
+
* @param {MergingSemantics} [options.semantics] Merging algorithm semantics.
|
|
433
|
+
* @returns {Promise} A promise resolving to the merged object.
|
|
434
|
+
*/
|
|
435
|
+
into: (dst, { with: withProject, project, ...semantics } = {}) => {
|
|
436
|
+
if (Object.keys(semantics).length === 0) semantics = undefined
|
|
437
|
+
project ??= withProject // to allow { with: project } for a more fluent API
|
|
438
|
+
const isYAML = typeof dst === 'string' && ['.yaml', '.yml', '.yaml.hbs', '.yml.hbs'].some(ext => dst.endsWith(ext))
|
|
439
|
+
const _merge = isYAML ? _mergeYAML : _mergeJSON
|
|
440
|
+
const target = typeof dst === 'string' ? path.resolve(cds.root, dst) : dst
|
|
441
|
+
if (typeof src[src.length-1] === 'string') {
|
|
442
|
+
return _merge(target, path.join(...src), project, semantics)
|
|
443
|
+
} else {
|
|
444
|
+
return _merge(target, ...src, project, semantics)
|
|
445
|
+
}
|
|
428
446
|
}
|
|
429
|
-
}
|
|
447
|
+
}
|
|
430
448
|
}
|
|
431
449
|
|
|
432
450
|
module.exports = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const cds = require('../cds')
|
|
2
2
|
const { join, resolve, basename } = require('path')
|
|
3
|
-
const { fs, exists, isdir } = cds.utils
|
|
3
|
+
const { fs, exists, isdir, path } = cds.utils
|
|
4
4
|
const { parseXml } = require('./xml')
|
|
5
5
|
const { REGEX_JAVA_VERSION } = require('./constants')
|
|
6
6
|
const DEBUG = cds.debug('cli')
|
|
@@ -59,6 +59,7 @@ module.exports = new class ProjectReader {
|
|
|
59
59
|
* @property {Object} db Database configuration.
|
|
60
60
|
* @property {string} configFile The name of the configuration file. This is typically the `package.json` for Node.js and `.cdsrc.json` for Java.
|
|
61
61
|
* @property {string} appPath The path to the app folder.
|
|
62
|
+
* @property {string} approuterPath The path to the approuter folder.
|
|
62
63
|
* @property {boolean} hasUIEmbedded Indicates if the project uses an embedded UI.
|
|
63
64
|
* @property {boolean} hasUIModule Indicates if the project is using a modular UI.
|
|
64
65
|
* @property {boolean} hasUI Indicates if the project has a UI.
|
|
@@ -112,8 +113,15 @@ module.exports = new class ProjectReader {
|
|
|
112
113
|
return { folder, name, path }
|
|
113
114
|
},
|
|
114
115
|
configFile: () => exists('pom.xml') ? '.cdsrc.json' : 'package.json',
|
|
116
|
+
apps: () => (fs.readdirSync(path.resolve(cds.root, cds.env.folders.app))).filter(e =>
|
|
117
|
+
isdir(join(cds.root, cds.env.folders.app, e)) && e !== 'appconfig' && e !== '_i18n' && e !== 'router'
|
|
118
|
+
).map(app => ({ app })),
|
|
119
|
+
appUIPaths: () => (fs.readdirSync(path.resolve(cds.root, cds.env.folders.app))).filter(e =>
|
|
120
|
+
isdir(join(cds.root, cds.env.folders.app, e)) && e !== 'appconfig' && e !== '_i18n' && e !== 'router'
|
|
121
|
+
),
|
|
115
122
|
appPath: () => env.folders.app,
|
|
116
123
|
appVersion: () => appVersion,
|
|
124
|
+
approuterPath: () => join(env.folders.app, 'router'),
|
|
117
125
|
appName: () => appName,
|
|
118
126
|
cleanedAppName: () => appName.replaceAll('_', '-'),
|
|
119
127
|
appId: () => appId,
|
|
@@ -122,6 +122,21 @@ const approuterExtensibility = {
|
|
|
122
122
|
where: { source: '^/-/cds/.*', destination: 'mtx-api', authenticationType: 'none' }
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
+
const html5RepoHost = {
|
|
126
|
+
in: 'resources',
|
|
127
|
+
where: { 'parameters.service': 'html5-apps-repo', 'parameters.service-plan': 'app-host' }
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const html5Runtime = {
|
|
131
|
+
in: 'resources',
|
|
132
|
+
where: { 'parameters.service': 'html5-apps-repo', 'parameters.service-plan': 'app-runtime' }
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const appContent = {
|
|
136
|
+
in: 'modules',
|
|
137
|
+
where: { type: 'com.sap.application.content' }
|
|
138
|
+
}
|
|
139
|
+
|
|
125
140
|
module.exports = {
|
|
126
141
|
srv4,
|
|
127
142
|
approuter,
|
|
@@ -147,5 +162,8 @@ module.exports = {
|
|
|
147
162
|
providedJavaApprouterApi4,
|
|
148
163
|
providedJavaApprouterApi,
|
|
149
164
|
applicationLogging,
|
|
150
|
-
approuterExtensibility
|
|
165
|
+
approuterExtensibility,
|
|
166
|
+
html5RepoHost,
|
|
167
|
+
html5Runtime,
|
|
168
|
+
appContent
|
|
151
169
|
}
|
|
@@ -22,16 +22,16 @@ module.exports = class ApprouterTemplate extends require('../../plugin') {
|
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
async run() {
|
|
25
|
-
const {
|
|
26
|
-
const appPackageJSONPath = join(
|
|
25
|
+
const { approuterPath } = readProject()
|
|
26
|
+
const appPackageJSONPath = join(approuterPath, 'package.json')
|
|
27
27
|
await merge(__dirname, 'files/package.json').into(appPackageJSONPath)
|
|
28
28
|
await sort(appPackageJSONPath, 'dependencies')
|
|
29
|
-
await merge(__dirname, 'files/default-env.json').into(
|
|
29
|
+
await merge(__dirname, 'files/default-env.json').into(approuterPath + '/default-env.json')
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
async combine() {
|
|
33
33
|
const project = readProject(this.options)
|
|
34
|
-
const { isNodejs, isJava, hasExtensibility, hasMultitenancy, hasMta, hasHelm, hasHelmUnifiedRuntime, srvPath,
|
|
34
|
+
const { isNodejs, isJava, hasExtensibility, hasMultitenancy, hasMta, hasHelm, hasHelmUnifiedRuntime, srvPath, approuterPath } = project
|
|
35
35
|
|
|
36
36
|
if (hasMta) {
|
|
37
37
|
const srv = srv4(srvPath)
|
|
@@ -72,7 +72,7 @@ module.exports = class ApprouterTemplate extends require('../../plugin') {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
const xsAppPath = join(
|
|
75
|
+
const xsAppPath = join(approuterPath, 'xs-app.json')
|
|
76
76
|
const additions = hasExtensibility ? [{ ...approuterExtensibility, at: 0 }] : []
|
|
77
77
|
await merge(__dirname, 'files/xs-app.json.hbs').into(xsAppPath, { project, additions })
|
|
78
78
|
}
|
|
@@ -12,10 +12,9 @@ module.exports = class ConnectivityTemplate extends require('../../plugin') {
|
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
async run() {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
// await merge(__dirname, 'files', 'package.json.hbs').into(configFile, { with: project })
|
|
15
|
+
const project = readProject()
|
|
16
|
+
const { configFile } = project
|
|
17
|
+
await merge(__dirname, 'files', 'package.json.hbs').into(configFile, { with: project })
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
async combine() {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{app}}",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "<description>",
|
|
6
|
+
"main": "webapp/index.html",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "ui5 build preload --clean-dest --include-task=generateCachebusterInfo",
|
|
9
|
+
"start": "ui5 serve"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"@ui5/cli": "^3.8.0",
|
|
13
|
+
"ui5-middleware-simpleproxy": "^3.2.10",
|
|
14
|
+
"ui5-task-zipper": "^3.1.1"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
modules:
|
|
3
|
+
- name: {{appName}}-srv
|
|
4
|
+
type: {{language}}
|
|
5
|
+
path: {{& srvPath}}
|
|
6
|
+
|
|
7
|
+
- name: {{appName}}
|
|
8
|
+
type: approuter.nodejs
|
|
9
|
+
path: {{& approuterPath}}
|
|
10
|
+
requires:
|
|
11
|
+
- name: {{appName}}-html5-runtime
|
|
12
|
+
|
|
13
|
+
- name: {{appName}}-app-content
|
|
14
|
+
type: com.sap.application.content
|
|
15
|
+
path: {{& appPath}}
|
|
16
|
+
requires:
|
|
17
|
+
- name: {{appName}}-destination
|
|
18
|
+
- name: {{appName}}-html5-repo-host
|
|
19
|
+
parameters:
|
|
20
|
+
content-target: true
|
|
21
|
+
build-parameters:
|
|
22
|
+
build-result: resources
|
|
23
|
+
requires:
|
|
24
|
+
{{#apps}}
|
|
25
|
+
- name: {{appName}}-app-{{app}}
|
|
26
|
+
artifacts:
|
|
27
|
+
- {{app}}.zip
|
|
28
|
+
target-path: resources/
|
|
29
|
+
{{/apps}}
|
|
30
|
+
|
|
31
|
+
{{#apps}}
|
|
32
|
+
- name: {{appName}}-app-{{app}}
|
|
33
|
+
type: html5
|
|
34
|
+
path: {{& appPath}}{{app}}
|
|
35
|
+
build-parameters:
|
|
36
|
+
build-result: dist
|
|
37
|
+
builder: custom
|
|
38
|
+
commands:
|
|
39
|
+
- npm ci
|
|
40
|
+
- npm run build
|
|
41
|
+
supported-platforms: []
|
|
42
|
+
{{/apps}}
|
|
43
|
+
|
|
44
|
+
resources:
|
|
45
|
+
{{#hasApprouter}}
|
|
46
|
+
- name: {{appName}}-html5-runtime
|
|
47
|
+
type: org.cloudfoundry.managed-service
|
|
48
|
+
parameters:
|
|
49
|
+
service: html5-apps-repo
|
|
50
|
+
service-plan: app-runtime
|
|
51
|
+
{{/hasApprouter}}
|
|
52
|
+
|
|
53
|
+
- name: {{appName}}-html5-repo-host
|
|
54
|
+
type: org.cloudfoundry.managed-service
|
|
55
|
+
parameters:
|
|
56
|
+
service: html5-apps-repo
|
|
57
|
+
service-plan: app-host
|
|
58
|
+
|
|
59
|
+
- name: {{appName}}-destination
|
|
60
|
+
type: org.cloudfoundry.managed-service
|
|
61
|
+
parameters:
|
|
62
|
+
service: destination
|
|
63
|
+
service-plan: lite
|
|
64
|
+
config:
|
|
65
|
+
HTML5Runtime_enabled: true
|
|
66
|
+
init_data:
|
|
67
|
+
instance:
|
|
68
|
+
existing_destinations_policy: update
|
|
69
|
+
destinations:
|
|
70
|
+
- Name: {{appName}}-srv
|
|
71
|
+
URL: ~{srv-api/srv-url}
|
|
72
|
+
Authentication: NoAuthentication
|
|
73
|
+
Type: HTTP
|
|
74
|
+
ProxyType: Internet
|
|
75
|
+
HTML5.ForwardAuthToken: true
|
|
76
|
+
HTML5.DynamicDestination: true
|
|
77
|
+
requires:
|
|
78
|
+
- name: srv-api
|
|
79
|
+
group: destinations
|
|
80
|
+
properties:
|
|
81
|
+
name: srv-api # must be used in xs-app.json as well
|
|
82
|
+
url: ~{srv-url}
|
|
83
|
+
forwardAuthToken: true
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
# yaml-language-server: $schema=https://sap.github.io/ui5-tooling/schema/ui5.yaml.json
|
|
3
|
+
specVersion: "3.0"
|
|
4
|
+
metadata:
|
|
5
|
+
name: sap.fe.cap.{{app}}
|
|
6
|
+
type: application
|
|
7
|
+
|
|
8
|
+
resources:
|
|
9
|
+
configuration:
|
|
10
|
+
propertiesFileSourceEncoding: UTF-8
|
|
11
|
+
|
|
12
|
+
builder:
|
|
13
|
+
resources:
|
|
14
|
+
excludes:
|
|
15
|
+
- "/test/**"
|
|
16
|
+
- "/localService/**"
|
|
17
|
+
customTasks:
|
|
18
|
+
- name: ui5-task-zipper
|
|
19
|
+
afterTask: generateCachebusterInfo
|
|
20
|
+
configuration:
|
|
21
|
+
archiveName: {{app}}
|
|
22
|
+
additionalFiles:
|
|
23
|
+
- xs-app.json
|
|
24
|
+
|
|
25
|
+
server:
|
|
26
|
+
customMiddleware:
|
|
27
|
+
- name: ui5-middleware-simpleproxy
|
|
28
|
+
mountPath: /{{app}}
|
|
29
|
+
afterMiddleware: compression
|
|
30
|
+
configuration:
|
|
31
|
+
baseUri: http://localhost:4004/{{app}}
|
|
32
|
+
username: admin # dummy credentials for local testing
|
|
33
|
+
password: admin # dummy credentials for local testing
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"welcomeFile": "/index.html",
|
|
3
|
+
"authenticationMethod": "route",
|
|
4
|
+
"routes": [
|
|
5
|
+
{
|
|
6
|
+
"source": "^/{{app}}/(.*)$",
|
|
7
|
+
"target": "/{{app}}/$1",
|
|
8
|
+
"destination": "srv-api",
|
|
9
|
+
"authenticationType": "xsuaa",
|
|
10
|
+
"csrfProtection": false
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"source": "^(.*)$",
|
|
14
|
+
"target": "$1",
|
|
15
|
+
"service": "html5-apps-repo-rt",
|
|
16
|
+
"authenticationType": "xsuaa"
|
|
17
|
+
}
|
|
18
|
+
]
|
|
19
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const { join } = require('path')
|
|
2
|
-
const
|
|
2
|
+
const cds = require('../../../cds')
|
|
3
|
+
const { copy } = cds.utils
|
|
3
4
|
const { readProject } = require('../../projectReader')
|
|
4
5
|
const { merge } = require('../../merge')
|
|
6
|
+
const { srv4, destination, html5RepoHost, html5Runtime, appContent, approuter } = require('../../registries/mta')
|
|
5
7
|
|
|
6
8
|
module.exports = class Html5RepoTemplate extends require('../../plugin') {
|
|
7
9
|
|
|
@@ -9,23 +11,65 @@ module.exports = class Html5RepoTemplate extends require('../../plugin') {
|
|
|
9
11
|
return ['destination']
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const { hasMta, hasHelm, hasHelmUnifiedRuntime } = project
|
|
15
|
-
if (!(hasHelm || hasHelmUnifiedRuntime) && hasMta) {
|
|
16
|
-
throw `'cds add html5-repo' is not available for Cloud Foundry yet`
|
|
17
|
-
}
|
|
18
|
-
return true
|
|
14
|
+
static hasInProduction(env) {
|
|
15
|
+
return !!env.requires['html5-repo']
|
|
19
16
|
}
|
|
20
17
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
async run() {
|
|
19
|
+
const project = readProject()
|
|
20
|
+
const { apps, appPath, configFile } = project
|
|
21
|
+
await merge(__dirname, 'files', 'package.json.hbs').into(configFile, { with: project })
|
|
22
|
+
|
|
23
|
+
await Promise.all(apps.map(async ({app}) => {
|
|
24
|
+
project.app = app
|
|
25
|
+
await merge(__dirname, 'files/ui5.yaml.hbs').into(join(appPath, app, 'ui5.yaml'), { project })
|
|
26
|
+
}))
|
|
27
|
+
await Promise.all(apps.map(async ({app}) => {
|
|
28
|
+
project.app = app
|
|
29
|
+
await merge(__dirname, 'files/app-package.json.hbs').into(join(appPath, app, 'package.json'), { project })
|
|
30
|
+
}))
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
async combine() {
|
|
27
34
|
const project = readProject()
|
|
28
|
-
const { hasHelm, hasHelmUnifiedRuntime } = project
|
|
35
|
+
const { srvPath, appPath, hasMta, hasHelm, hasHelmUnifiedRuntime, hasApprouter, apps } = project
|
|
36
|
+
|
|
37
|
+
if (hasApprouter) {
|
|
38
|
+
await Promise.all(apps.map(async ({app}) => {
|
|
39
|
+
project.app = app
|
|
40
|
+
await merge(__dirname, 'files/xs-app.json.hbs').into(join(appPath, app, 'xs-app.json'), { project })
|
|
41
|
+
}))
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (hasMta) {
|
|
45
|
+
const srv = srv4(srvPath)
|
|
46
|
+
project.apps = apps
|
|
47
|
+
const appModules = project.apps.map(app => ( {
|
|
48
|
+
in: 'modules',
|
|
49
|
+
where: { type: 'html5', path: `${appPath}${app.app}` }
|
|
50
|
+
}))
|
|
51
|
+
const additions = [srv, appContent, destination, html5RepoHost, ...appModules]
|
|
52
|
+
const relationships = [{
|
|
53
|
+
insert: [destination, 'name'],
|
|
54
|
+
into: [appContent, 'requires', 'name'],
|
|
55
|
+
}, {
|
|
56
|
+
insert: [html5RepoHost, 'name'],
|
|
57
|
+
into: [appContent, 'requires', 'name'],
|
|
58
|
+
}]
|
|
59
|
+
if (hasApprouter) {
|
|
60
|
+
console.log('aaddd')
|
|
61
|
+
additions.push(approuter, html5Runtime)
|
|
62
|
+
relationships.push({
|
|
63
|
+
insert: [html5Runtime, 'name'],
|
|
64
|
+
into: [approuter, 'requires', 'name'],
|
|
65
|
+
})
|
|
66
|
+
}
|
|
67
|
+
await merge(__dirname, 'files/mta.yaml.hbs').into('mta.yaml', { with: project,
|
|
68
|
+
additions,
|
|
69
|
+
relationships
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
29
73
|
if (hasHelm || hasHelmUnifiedRuntime) {
|
|
30
74
|
await merge(__dirname, 'files/values.yaml.hbs').into('chart/values.yaml', { with: project })
|
|
31
75
|
await merge({
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const { join } = require('path')
|
|
2
2
|
const cds = require('../../../cds')
|
|
3
3
|
const { exists } = cds.utils
|
|
4
|
+
const { bold } = require('../../../util/term')
|
|
4
5
|
const { copyRenderedYAML } = require('../../../util/fs')
|
|
5
6
|
const { readProject } = require('../../projectReader')
|
|
6
7
|
const { merge, sort } = require('../../merge')
|
|
@@ -19,4 +20,8 @@ module.exports = class MtaTemplate extends require('../../plugin') {
|
|
|
19
20
|
await merge(__dirname, 'files/package.json').into('package.json')
|
|
20
21
|
await sort('package.json', 'devDependencies')
|
|
21
22
|
}
|
|
23
|
+
|
|
24
|
+
async finalize() {
|
|
25
|
+
if (!exists('pom.xml')) console.log(`\nRun ${bold('npm update --package-lock-only')} to freeze dependencies.`)
|
|
26
|
+
}
|
|
22
27
|
}
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
"esbenp.prettier-vscode",
|
|
10
10
|
"mechatroner.rainbow-csv",
|
|
11
11
|
"qwtel.sqlite-viewer",
|
|
12
|
-
"humao.rest-client"
|
|
13
|
-
"sdras.night-owl"
|
|
12
|
+
"humao.rest-client"
|
|
14
13
|
],
|
|
15
14
|
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
|
|
16
15
|
"unwantedRecommendations": [
|
|
@@ -15,7 +15,7 @@ File or Folder | Purpose
|
|
|
15
15
|
|
|
16
16
|
## Next Steps
|
|
17
17
|
|
|
18
|
-
- Open a new terminal and run `cds watch`
|
|
18
|
+
- Open a new terminal and run `cds watch`
|
|
19
19
|
- (in VS Code simply choose _**Terminal** > Run Task > cds watch_)
|
|
20
20
|
- Start adding content, for example, a [db/schema.cds](db/schema.cds).
|
|
21
21
|
|