@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.
Files changed (53) hide show
  1. package/bin/cds.js +1 -1
  2. package/bin/import.js +2 -2
  3. package/bin/version.js +21 -20
  4. package/bin/watch.js +6 -0
  5. package/lib/build/buildTaskEngine.js +6 -4
  6. package/lib/build/buildTaskProviderFactory.js +5 -0
  7. package/lib/build/provider/edmxBuildPlugin.js +1 -1
  8. package/lib/build/provider/internalBuildTaskProvider.js +12 -10
  9. package/lib/build/provider/mtx/index.js +2 -2
  10. package/lib/build/provider/mtx/resourcesTarBuilder.js +1 -1
  11. package/lib/build/provider/mtx-extension/extensionCompilation.js +50 -0
  12. package/lib/build/provider/mtx-extension/index.js +50 -48
  13. package/lib/build/provider/mtx-sidecar/index.js +3 -3
  14. package/lib/build/util.js +9 -4
  15. package/lib/deploy/to-hana/hana.js +46 -76
  16. package/lib/deploy/to-hana/hdiDeployUtil.js +15 -18
  17. package/lib/deploy/to-hana/mtaUtil.js +1 -1
  18. package/lib/env/schema.js +1 -0
  19. package/lib/env/schemas/cds-rc.js +54 -1
  20. package/lib/import/asyncapi/parserContext.js +6 -0
  21. package/lib/import/common.js +18 -23
  22. package/lib/import/odata/metadataconverter/MetadataConverter.js +12 -8
  23. package/lib/import/odata/v4parser.js +67 -12
  24. package/lib/init/add.js +2 -0
  25. package/lib/init/constants.js +2 -4
  26. package/lib/init/merge.js +31 -13
  27. package/lib/init/projectReader.js +9 -1
  28. package/lib/init/registries/mta.js +19 -1
  29. package/lib/init/template/approuter/files/mta.yaml.hbs +1 -1
  30. package/lib/init/template/approuter/index.js +5 -5
  31. package/lib/init/template/connectivity/index.js +3 -4
  32. package/lib/init/template/html5-repo/files/app-package.json.hbs +16 -0
  33. package/lib/init/template/html5-repo/files/mta.yaml.hbs +83 -0
  34. package/lib/init/template/html5-repo/files/package.json.hbs +17 -0
  35. package/lib/init/template/html5-repo/files/ui5.yaml.hbs +33 -0
  36. package/lib/init/template/html5-repo/files/xs-app.json.hbs +19 -0
  37. package/lib/init/template/html5-repo/index.js +56 -12
  38. package/lib/init/template/mta/files/mta.yaml.hbs +1 -0
  39. package/lib/init/template/mta/index.js +5 -0
  40. package/lib/init/template/nodejs/files/.vscode/extensions.json +1 -2
  41. package/lib/init/template/nodejs/files/README.md +1 -1
  42. package/lib/init/template/sample/files/app/index.html +8 -6
  43. package/lib/init/template/sample/index.js +12 -2
  44. package/lib/lint/Linter.js +2 -2
  45. package/lib/lint/checks.js +0 -51
  46. package/lib/mtx/auth_manager.js +46 -55
  47. package/lib/mtx/settings_manager.js +14 -19
  48. package/lib/mtx/util/dependencies.js +1 -1
  49. package/lib/mtx/util/logging.js +10 -8
  50. package/lib/util/axios.js +5 -0
  51. package/lib/util/cf.js +1 -0
  52. package/npm-shrinkwrap.json +96 -42
  53. 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
@@ -4,7 +4,7 @@ module.exports = {
4
4
  COMMAND_INIT: 'init',
5
5
  COMMAND_ADD: 'add',
6
6
 
7
- MAVEN_ARCHETYPE_VERSION: '2.5.0',
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.forEach((templateNode, templateIndex) => {
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 { into: (dst, { with: withProject, project, ...semantics } = {}) => {
419
- if (Object.keys(semantics).length === 0) semantics = undefined
420
- project ??= withProject // to allow { with: project } for a more fluent API
421
- const isYAML = typeof dst === 'string' && ['.yaml', '.yml', '.yaml.hbs', '.yml.hbs'].some(ext => dst.endsWith(ext))
422
- const _merge = isYAML ? _mergeYAML : _mergeJSON
423
- const target = typeof dst === 'string' ? path.resolve(cds.root, dst) : dst
424
- if (typeof src[src.length-1] === 'string') {
425
- return _merge(target, path.join(...src), project, semantics)
426
- } else {
427
- return _merge(target, ...src, project, semantics)
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
  }
@@ -19,7 +19,7 @@ modules:
19
19
 
20
20
  - name: {{appName}}
21
21
  type: approuter.nodejs
22
- path: {{& appPath}}
22
+ path: {{& approuterPath}}
23
23
  parameters:
24
24
  keep-existing-routes: true
25
25
  disk-quota: 256M
@@ -22,16 +22,16 @@ module.exports = class ApprouterTemplate extends require('../../plugin') {
22
22
  }
23
23
 
24
24
  async run() {
25
- const { appPath } = readProject()
26
- const appPackageJSONPath = join(appPath, 'package.json')
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(appPath + '/default-env.json')
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, appPath } = project
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(appPath, 'xs-app.json')
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
- // Disable setting cds.requires.connectivity for now.
16
- // const project = readProject()
17
- // const { configFile } = project
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,17 @@
1
+ {
2
+ {{#isNodejs}}
3
+ "cds": {
4
+ {{/isNodejs}}
5
+ "requires": {
6
+ {{#profile}}
7
+ "[{{profile}}]": {
8
+ {{/profile}}
9
+ "html5-repo": true
10
+ {{#profile}}
11
+ }
12
+ {{/profile}}
13
+ }
14
+ {{#isNodejs}}
15
+ }
16
+ {{/isNodejs}}
17
+ }
@@ -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 { exists, copy } = require('../../../cds').utils
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
- async canRun() {
13
- const project = readProject()
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
- static hasInProduction() {
22
- // REVISIT: Should be detectable without helm charts
23
- return exists(join('chart', 'templates', 'html5-apps-deployer-configmap.yaml'))
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({
@@ -10,6 +10,7 @@ build-parameters:
10
10
  before-all:
11
11
  - builder: custom
12
12
  commands:
13
+ - npm ci
13
14
  - npx cds build --production
14
15
  {{/isNodejs}}
15
16
  modules:
@@ -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