@sap/cds-dk 6.6.0 → 6.6.2

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 CHANGED
@@ -7,6 +7,30 @@ This project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
8
  The format is based on [Keep a Changelog](http://keepachangelog.com/).
9
9
 
10
+ ## Version 6.6.2 - 2023-03-22
11
+
12
+ ### Fixed
13
+
14
+ - Bump `sqlite3` to 5.1.6
15
+ - Bump `@sap/cds` to 6.2.2
16
+ - `cds init` creates project sample files correctly.
17
+
18
+ ## Version 6.6.1 - 2023-03-09
19
+
20
+ ### Added
21
+
22
+ - `cds compile --to openapi` now adds extension validation keywords `x-sap-precision` and `x-sap-scale` for decimal values.
23
+
24
+ ### Fixed
25
+
26
+ - `cds add helm` fixed html5 cloud service is now read properly.
27
+ - `cds import` now flattens the `@Capabilities` anotation in the CSN for OData V4 files.
28
+ - `cds import` for OData V4 files now captures the `EnumTypes` information in the CSN according to `UnderlyingType`.
29
+ - `cds import` now captures the `@Common.Text` annotation value properly in the CSN for OData V4 files.
30
+ - `cds init --add java` now uses local Java version when creating new Java project.
31
+ - `cds watch` terminates properly in case livereload websocket clients are connected
32
+ - `cds watch`'s livereload feature works again on Node.js >= 17, where local IPv6 addresses are the default (`::1` instead of `127.0.0.1`)
33
+
10
34
  ## Version 6.6.0 - 2023-02-28
11
35
 
12
36
  ### Added
@@ -4,8 +4,10 @@ class CliError extends Error {
4
4
  // noinspection JSAnnotator
5
5
  constructor(message, { error, command } = {}) {
6
6
  const help = command && getCommandHelp(command);
7
+ const stackLimit = Error.stackTraceLimit;
7
8
  Error.stackTraceLimit = 0
8
- throw new Error(getMessage(message, { error, help }));
9
+ super(getMessage(message, { error, help }));
10
+ Error.stackTraceLimit = stackLimit;
9
11
  }
10
12
  }
11
13
 
@@ -2047,6 +2047,8 @@ see [Expand](http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part1-prot
2047
2047
  anyOf: [{ type: 'number', format: 'decimal' }, { type: 'string' }],
2048
2048
  example: 0
2049
2049
  };
2050
+ if (!isNaN(element.$Precision)) s['x-sap-precision'] = element.$Precision;
2051
+ if (!isNaN(element.$Scale)) s['x-sap-scale'] = element.$Scale;
2050
2052
  // eslint-disable-next-line no-case-declarations
2051
2053
  let scale = !isNaN(element.$Scale) ? element.$Scale : null;
2052
2054
  if (scale !== null) {
@@ -17,7 +17,8 @@ const messages = {
17
17
  COLLECTION_IN_KEY: 'Key Property of an Entity cannot be of the type Collection.',
18
18
  INVALID_OPENAPI_FILE: 'The OpenAPI file is not valid. Specify the correct OpenAPI file.',
19
19
  UNRESOLVED_TYPE: 'Could not resolve the type: ',
20
- NO_RETURN_TYPE: 'No ReturnType found in Function: '
20
+ NO_RETURN_TYPE: 'No ReturnType found in Function: ',
21
+ INVALID_ENUM_TYPE: 'The Underlying type provided is not supported for the EnumType: '
21
22
  };
22
23
 
23
24
  function getMessages() {
@@ -1682,6 +1682,11 @@ class PropertyValueExpression extends Expression {
1682
1682
  if (element.attributes.EnumMember) target[name] = { "#": element.attributes.EnumMember.substring(element.attributes.EnumMember.lastIndexOf('/') + 1) };
1683
1683
  if (element.attributes.NavigationPropertyPath) target[name] = { "=": element.attributes.NavigationPropertyPath };
1684
1684
  if (element.attributes.String) target[name] = element.attributes.String;
1685
+ /**
1686
+ * EnumType is converted to TypeDefinition when generating edmx from compiler
1687
+ * we then have to fetch this value correctly via this attribute of annotation
1688
+ */
1689
+ if (element.attributes.Int) target[name] = Number(element.attributes.Int);
1685
1690
  if (element.attributes.Bool) target[name] = element.attributes.Bool === 'true';
1686
1691
 
1687
1692
  this.getStack().forEach((expr) => {
@@ -1993,8 +1998,8 @@ class EnumTypeExpression extends Expression {
1993
1998
  Object.assign(target, interpretation);
1994
1999
  }
1995
2000
  });
1996
-
1997
- this.buildTypeCollectionAndFacets('$Type', '$UnderlyingType', '$IsFlags', '$BaseType');
2001
+ // EnumType doesn't have Type, BaseType as attribute/facet so removed it
2002
+ this.buildTypeCollectionAndFacets('$UnderlyingType', '$IsFlags');
1998
2003
  return result;
1999
2004
  }
2000
2005
  }
@@ -12,7 +12,6 @@ const ignoreObjects = ["$Reference"]; // add all the objects that needs to be ig
12
12
  const validEdmDatatypes = ["Edm.DateTimeOffset"];
13
13
  const { warn } = require("../../util/term");
14
14
  const MetadataConverterFactory = require("./metadataconverter/MetadataConverterFactory");
15
- const cds = require('../../cds');
16
15
 
17
16
  const edmxncdsdatatype = {
18
17
  "Edm.String": "cds.LargeString",
@@ -142,7 +141,7 @@ function _hasEntityContainer(jsonObj, parserContext) {
142
141
  jsonObj[parserContext.namespace][parserContext.jsonEntityContainerName] instanceof Object
143
142
  ) {
144
143
  return true;
145
- }
144
+ }
146
145
  } catch (err) {
147
146
  throw new Error(messages.MISSING_ENTITY_CONTAINER);
148
147
  }
@@ -158,7 +157,7 @@ function _includeExternalNamespaceAnnotation(source, target) {
158
157
 
159
158
  function _addNotNull(property, isCollection) {
160
159
  if (isCollection) property.items["notNull"] = true;
161
- else property["notNull"] = true;
160
+ else property["notNull"] = true;
162
161
  }
163
162
 
164
163
  function _typeWithCollections(property, type, isCollection) {
@@ -567,6 +566,7 @@ function _collectEnumType(schemaDataList, parserContext) {
567
566
  }
568
567
 
569
568
  function _generateCSNForEnumType(schemaData, parserContext) {
569
+ const nonMemberList = ["$Kind", "$Type", "$UnderlyingType", "$IsFlags"];
570
570
  let enumCsn = {};
571
571
  let eTypes;
572
572
  eTypes = _collectEnumType(schemaData, parserContext);
@@ -575,15 +575,19 @@ function _generateCSNForEnumType(schemaData, parserContext) {
575
575
  enumCsn[element].kind = 'type';
576
576
  enumCsn[element]['@cds.external'] = true;
577
577
  enumCsn[element].enum = {};
578
- enumCsn[element].type = eTypes[element].$Type != null ? edmxncdsdatatype[eTypes[element].$Type] : 'cds.LargeString';
579
- Object.keys(eTypes[element]).forEach(property => {
580
- if (property != "$Kind" && property != "$Type") {
581
- if (enumCsn[element].type == 'cds.LargeString') {
582
- enumCsn[element].enum[property] = cds.parse.expr(`'${(eTypes[element][property])}'`);
583
- }
584
- else {
585
- enumCsn[element].enum[property] = cds.parse.expr(`${(eTypes[element][property])}`);
586
- }
578
+ /**
579
+ * If UnderlyingType not specified, default is Edm.Int32 --> cds.Integer
580
+ */
581
+ let underlyingType = eTypes[element].$UnderlyingType;
582
+ enumCsn[element].type = underlyingType ? edmxncdsdatatype[underlyingType] : 'cds.Integer';
583
+
584
+ if (!enumCsn[element].type || enumCsn[element].type !== "cds.Integer" ) {
585
+ throw new Error(messages.INVALID_ENUM_TYPE + `'${underlyingType}'`);
586
+ }
587
+ Object.keys(eTypes[element]).forEach(member => {
588
+ if (!nonMemberList.includes(member)) {
589
+ enumCsn[element].enum[member] = {};
590
+ enumCsn[element].enum[member].val = eTypes[element][member];
587
591
  }
588
592
  });
589
593
  });
@@ -900,7 +904,7 @@ function _generateCSNForComplexType(schemaData, parserContext) {
900
904
  }
901
905
  if ((isAbstract || isOpenType) && !parserContext.complexTypeOpenEntries.includes(element)) {
902
906
  parserContext.complexTypeOpenEntries.push(element);
903
- }
907
+ }
904
908
  Object.keys(cTypes[element]).forEach(property => { // cTypes[element][property].$Type.startsWith('Edm.')
905
909
  if (cTypes[element][property] instanceof Object) {
906
910
  if (!cTypes[element][property].$Type ||
@@ -944,11 +948,16 @@ function _parseTypeDefinition(parserContext) {
944
948
  typeDef[element] = {};
945
949
  typeDef[element].kind = 'type';
946
950
  typeDef[element]['@cds.external'] = true;
947
- if (!parserContext.typeDefinitions[element].$Type ||
948
- edmxncdsdatatype[parserContext.typeDefinitions[element].$Type]
949
- ) {
951
+
952
+ let underlyingType = parserContext.typeDefinitions[element].$UnderlyingType;
953
+ parserContext.typeDefinitions[element].$Type = underlyingType;
954
+
955
+ if (edmxncdsdatatype[underlyingType] ) {
950
956
  propertyType = parserContext.typeDefinitions[element];
951
957
  typeDef[element] = Object.assign(typeDef[element], generatePropertyCsn(propertyType, false));
958
+ if (typeDef[element].type === "cds.LargeString") typeDef[element].type = "cds.String";
959
+ } else {
960
+ throw new Error(messages.UNRESOLVED_TYPE + `'${underlyingType}'`);
952
961
  }
953
962
  });
954
963
  return typeDef;
@@ -999,13 +1008,13 @@ function _parseUnbounded(schemaData, flag, parserContext) {
999
1008
  if (objData.$Parameter[i].$Collection && !paramType.items) {
1000
1009
  obj[objType].params[objData.$Parameter[i].$Name] = {};
1001
1010
  obj[objType].params[objData.$Parameter[i].$Name].items = paramType;
1002
- if(objData.$Parameter[i].$Nullable != true){
1011
+ if (!objData.$Parameter[i].$Nullable) {
1003
1012
  obj[objType].params[objData.$Parameter[i].$Name].items["notNull"] = true;
1004
1013
  }
1005
1014
  } else {
1006
1015
  obj[objType].params[objData.$Parameter[i].$Name] = paramType;
1007
1016
  if (!paramType.items) {
1008
- if(objData.$Parameter[i].$Nullable != true){
1017
+ if (!objData.$Parameter[i].$Nullable) {
1009
1018
  obj[objType].params[objData.$Parameter[i].$Name]["notNull"] = true;
1010
1019
  }
1011
1020
  }
@@ -1169,6 +1178,7 @@ function _replaceSpecialCharacters(text) {
1169
1178
  }
1170
1179
 
1171
1180
  function _checkAnnotatationTerm(annotation, path, no_of_terms, targetString, vocab) {
1181
+ let annoTerm = targetString.substring(targetString.indexOf('@') + 1).split('.')[0];
1172
1182
  if (path) {
1173
1183
  if (targetString === "@Core.Description" && annotation[1]["@Core.Description"]) {
1174
1184
  if (path.doc === undefined)
@@ -1182,11 +1192,17 @@ function _checkAnnotatationTerm(annotation, path, no_of_terms, targetString, voc
1182
1192
  else if (targetString === "@Core.OptionalParameter" && annotation[1]["@Core.OptionalParameter"]) {
1183
1193
  _captureOptionalParameter(annotation, path);
1184
1194
  }
1185
- else if (vocab) {
1186
- if (vocab.includes(targetString.substring(targetString.indexOf('@') + 1, targetString.lastIndexOf('.')))) {
1187
- if (annotation[1][targetString]?.$Cast) {
1195
+ else if (vocab) {
1196
+ if (vocab.includes(annoTerm)) {
1197
+ if (annoTerm === "Capabilities") {
1198
+ path[targetString] = annotation[1][1];
1199
+ }
1200
+ else if (annotation[1][targetString]?.$Cast) {
1188
1201
  path[targetString] = Number(annotation[1][targetString].$Cast);
1189
1202
  }
1203
+ else if (annotation[1][targetString]?.$Path) {
1204
+ path[targetString] = { "=": annotation[1][targetString].$Path };
1205
+ }
1190
1206
  else {
1191
1207
  path[targetString] = annotation[1][targetString] === null ? true : annotation[1][targetString];
1192
1208
  }
@@ -1202,37 +1218,38 @@ function checkEntitySetMap(pathName, parserContext, index = 0) {
1202
1218
  return pathName;
1203
1219
  }
1204
1220
 
1205
- function _checkAnnotationTarget(annotation, cdsDefs, str, no_of_terms, vocab, parserContext) {
1221
+ function _checkAnnotationTarget(annotation, csnDefs, str, no_of_terms, vocab, parserContext) {
1206
1222
  if ((annotation[0].indexOf('/') === -1 && annotation[0].indexOf('(') === -1) || annotation[0].includes("Container")) {
1207
- if (cdsDefs[annotation[0]]) {
1223
+ if (csnDefs[annotation[0]]) {
1208
1224
  let path = annotation[0].split('/');
1209
1225
  let pathFromEntityTypeMap = parserContext.entitySetToEntityTypeMap.get(path[0]);
1210
1226
  if (pathFromEntityTypeMap != null) {
1211
1227
  if (pathFromEntityTypeMap.length > 1) {
1212
1228
  for (let index = 0; index < pathFromEntityTypeMap.length; index++) {
1213
1229
  let path1 = checkEntitySetMap(path[0], parserContext, index);
1214
- _checkAnnotatationTerm(annotation, cdsDefs[path1], no_of_terms, str, vocab);
1230
+ _checkAnnotatationTerm(annotation, csnDefs[path1], no_of_terms, str, vocab);
1215
1231
  }
1216
1232
  } else {
1217
- _checkAnnotatationTerm(annotation, cdsDefs[annotation[0]], no_of_terms, str, vocab);
1233
+ _checkAnnotatationTerm(annotation, csnDefs[annotation[0]], no_of_terms, str, vocab);
1218
1234
  }
1219
1235
  }
1220
1236
  else {
1221
- _checkAnnotatationTerm(annotation, cdsDefs[annotation[0]], no_of_terms, str, vocab);
1237
+ _checkAnnotatationTerm(annotation, csnDefs[annotation[0]], no_of_terms, str, vocab);
1222
1238
  }
1223
1239
  }
1240
+
1224
1241
  if (annotation[0].indexOf('/') > 0) {
1225
1242
  let path = annotation[0].split('/');
1226
1243
  let temp = parserContext.namespace + '.' + path[1];
1227
1244
  let path1 = checkEntitySetMap(temp, parserContext);
1228
- if (cdsDefs[path1]) {
1229
- _checkAnnotatationTerm(annotation, cdsDefs[path1], no_of_terms, str, vocab);
1245
+ if (csnDefs[path1]) {
1246
+ _checkAnnotatationTerm(annotation, csnDefs[path1], no_of_terms, str, vocab);
1230
1247
  }
1231
1248
  }
1232
1249
  else if (annotation[0].includes("Container")) {
1233
1250
  let path = annotation[0].substring(0, annotation[0].lastIndexOf('.'));
1234
1251
  let actualPath = checkEntitySetMap(path, parserContext);
1235
- _checkAnnotatationTerm(annotation, cdsDefs[actualPath], no_of_terms, str, vocab);
1252
+ _checkAnnotatationTerm(annotation, csnDefs[actualPath], no_of_terms, str, vocab);
1236
1253
  }
1237
1254
  else if (annotation[0].indexOf('(') === -1 && (annotation[0].indexOf('/') === -1)) {
1238
1255
  let path = annotation[0].split('/');
@@ -1241,7 +1258,7 @@ function _checkAnnotationTarget(annotation, cdsDefs, str, no_of_terms, vocab, pa
1241
1258
  if (pathFromEntityTypeMap.length > 1) {
1242
1259
  for (let index = 0; index < pathFromEntityTypeMap.length; index++) {
1243
1260
  let path1 = checkEntitySetMap(path[0], parserContext, index);
1244
- _checkAnnotatationTerm(annotation, cdsDefs[path1], no_of_terms, str, vocab);
1261
+ _checkAnnotatationTerm(annotation, csnDefs[path1], no_of_terms, str, vocab);
1245
1262
  }
1246
1263
  }
1247
1264
  }
@@ -1254,39 +1271,39 @@ function _checkAnnotationTarget(annotation, cdsDefs, str, no_of_terms, vocab, pa
1254
1271
  if (pathFromEntityTypeMap.length > 1) {
1255
1272
  for (let index = 0; index < pathFromEntityTypeMap.length; index++) {
1256
1273
  let path1 = checkEntitySetMap(path[0], parserContext, index);
1257
- _checkAnnotatationTerm(annotation, cdsDefs[path1]["elements"][path[1]], no_of_terms, str, vocab);
1274
+ _checkAnnotatationTerm(annotation, csnDefs[path1]["elements"][path[1]], no_of_terms, str, vocab);
1258
1275
  }
1259
1276
  }
1260
1277
  else {
1261
1278
  let path1 = checkEntitySetMap(path[0], parserContext);
1262
- if (cdsDefs[path1]) {
1263
- _checkAnnotatationTerm(annotation, cdsDefs[path1]["elements"][path[1]], no_of_terms, str, vocab);
1279
+ if (csnDefs[path1]) {
1280
+ _checkAnnotatationTerm(annotation, csnDefs[path1]["elements"][path[1]], no_of_terms, str, vocab);
1264
1281
  }
1265
1282
  }
1266
1283
  }
1267
1284
  else {
1268
- if (cdsDefs[path[0]]) {
1269
- _checkAnnotatationTerm(annotation, cdsDefs[path[0]]["elements"][path[1]], no_of_terms, str, vocab);
1285
+ if (csnDefs[path[0]]) {
1286
+ _checkAnnotatationTerm(annotation, csnDefs[path[0]]["elements"][path[1]], no_of_terms, str, vocab);
1270
1287
  }
1271
1288
  }
1272
1289
  }
1273
1290
  else {
1274
1291
  let path = annotation[0].split('(');
1275
1292
  let actualPath = checkEntitySetMap(path[0], parserContext);
1276
- if (cdsDefs[actualPath] === undefined) {
1293
+ if (csnDefs[actualPath] === undefined) {
1277
1294
  let temp = path[1].split(')');
1278
1295
  let path1 = temp[0].split(',');
1279
1296
  let path2 = path[0].split('.');
1280
- if (cdsDefs[path1[0]]) {
1281
- _checkAnnotatationTerm(annotation, cdsDefs[path1[0]]["actions"][path2[1]], no_of_terms, str, vocab);
1297
+ if (csnDefs[path1[0]]) {
1298
+ _checkAnnotatationTerm(annotation, csnDefs[path1[0]]["actions"][path2[1]], no_of_terms, str, vocab);
1282
1299
  }
1283
1300
  } else {
1284
1301
  if (path[1].indexOf('/') === -1) {
1285
- _checkAnnotatationTerm(annotation, cdsDefs[path[0]], no_of_terms, str, vocab);
1302
+ _checkAnnotatationTerm(annotation, csnDefs[path[0]], no_of_terms, str, vocab);
1286
1303
  } else {
1287
1304
  let path1 = path[1].split('/');
1288
- if (cdsDefs[path[0]] && cdsDefs[path[0]]["params"]) {
1289
- _checkAnnotatationTerm(annotation, cdsDefs[path[0]]["params"][path1[1]], no_of_terms, str, vocab);
1305
+ if (csnDefs[path[0]] && csnDefs[path[0]]["params"]) {
1306
+ _checkAnnotatationTerm(annotation, csnDefs[path[0]]["params"][path1[1]], no_of_terms, str, vocab);
1290
1307
  }
1291
1308
  }
1292
1309
  }
@@ -1305,7 +1322,7 @@ function _replaceSchemaDataAnnotation(vocabAlias, vocabNamespce, schemaDataAnnot
1305
1322
  return JSON.parse(schemaDataAnnotation);
1306
1323
  }
1307
1324
 
1308
- function _generateDocumentation(edmxAsJson, schemaData, cdsDefs, parserContext) {
1325
+ function _generateDocumentation(edmxAsJson, schemaData, csnDefs, parserContext) {
1309
1326
  let vocabAlias = [];
1310
1327
  let vocab = [];
1311
1328
  let vocabNamespce = [];
@@ -1326,18 +1343,23 @@ function _generateDocumentation(edmxAsJson, schemaData, cdsDefs, parserContext)
1326
1343
  Object.entries(schemaData[0].$Annotations).map(annotation => {
1327
1344
  let no_of_terms;
1328
1345
  Object.entries(annotation[1]).forEach(anno => {
1329
- if (vocab.includes(anno[0].substring(anno[0].indexOf('@') + 1, anno[0].lastIndexOf('.')))) {
1346
+ let annoTerm = anno[0].substring(anno[0].indexOf('@') + 1).split('.')[0];
1347
+
1348
+ if (vocab.includes(annoTerm) && annoTerm !== 'Capabilities') {
1330
1349
  if (annotation[1].hasOwnProperty('@Core.Description')) {
1331
1350
  no_of_terms = true;
1332
1351
  }
1333
1352
  if (annotation[1].hasOwnProperty('@Common.FieldControl') && controlFieldFlag === 0) {
1334
- annotation[1]["@Common.FieldControl"] = { "#": annotation[1]["@Common.FieldControl"]}
1353
+ annotation[1]["@Common.FieldControl"] = { "#": annotation[1]["@Common.FieldControl"] };
1335
1354
  controlFieldFlag = 1;
1336
1355
  }
1337
1356
  if (annotation[1].hasOwnProperty('@Common.IsUpperCase')) {
1338
1357
  annotation[1]["@Common.IsUpperCase"] = true;
1339
1358
  }
1340
- _checkAnnotationTarget(annotation, cdsDefs, anno[0], no_of_terms, vocab, parserContext);
1359
+ _checkAnnotationTarget(annotation, csnDefs, anno[0], no_of_terms, vocab, parserContext);
1360
+ }
1361
+ if (vocab.includes(annoTerm) && annoTerm === 'Capabilities') {
1362
+ _parseCapabilitiesAnnotation(annotation[0], anno, csnDefs, vocab, parserContext);
1341
1363
  }
1342
1364
  });
1343
1365
  controlFieldFlag = 0;
@@ -1345,6 +1367,72 @@ function _generateDocumentation(edmxAsJson, schemaData, cdsDefs, parserContext)
1345
1367
  }
1346
1368
  }
1347
1369
 
1370
+ function _flattenAnnotationObject(annotationPrefix, annotationObject) {
1371
+ let flattenedResult = [];
1372
+
1373
+ Object.entries(annotationObject).forEach(annotation => {
1374
+ let currentResult = [];
1375
+ currentResult[0] = annotationPrefix + '.' + annotation[0];
1376
+ currentResult[1] = annotation[1];
1377
+ flattenedResult.push(currentResult);
1378
+ });
1379
+
1380
+ return flattenedResult;
1381
+ }
1382
+
1383
+ function _removeTypeInAnnotation(annotationObject) {
1384
+ Object.keys(annotationObject).forEach(key => {
1385
+ if (key === "$Type") delete annotationObject[key];
1386
+ else if (annotationObject[key] instanceof Object) {
1387
+ _removeTypeInAnnotation(annotationObject[key]);
1388
+ }
1389
+ });
1390
+ }
1391
+
1392
+ function _parseCapabilitiesAnnotation(annotationTargetPath, currentAnnotation, csnDefs, vocab, parserContext) {
1393
+ let annotationResult = [annotationTargetPath, ''], currentResult = [], targetString;
1394
+
1395
+ _removeTypeInAnnotation(currentAnnotation);
1396
+
1397
+ /**
1398
+ * For entries like:
1399
+ * <Annotation Term="Capabilities.FilterFunctions"> <Collection> <String>eq</String> <String>ne</String> </Collection> </Annotation>
1400
+ * <Annotation Term="Capabilities.DeleteRestrictions.Deletable" Bool="true"/>
1401
+ *
1402
+ * simply preserve the value as it is
1403
+ */
1404
+ if (currentAnnotation[1] instanceof Array || !(currentAnnotation[1] instanceof Object)) {
1405
+ targetString = currentAnnotation[0];
1406
+ currentResult = [targetString, currentAnnotation[1]];
1407
+ annotationResult[1] = currentResult;
1408
+ _checkAnnotationTarget(annotationResult, csnDefs, targetString, undefined, vocab, parserContext);
1409
+ }
1410
+ else {
1411
+ Object.keys(currentAnnotation[1]).forEach(annoKey => {
1412
+ let currentAnnoValue = currentAnnotation[1][annoKey];
1413
+ // if the currentAnnoValue is an Object, we need to flatten it
1414
+ if (currentAnnoValue instanceof Object && !(currentAnnoValue instanceof Array)) {
1415
+ targetString = currentAnnotation[0] + '.' + annoKey;
1416
+ let currentResultList = _flattenAnnotationObject(targetString, currentAnnoValue);
1417
+
1418
+ for (let idx = 0; idx < currentResultList.length; idx++) {
1419
+ targetString = currentResultList[idx][0];
1420
+ annotationResult[1] = currentResultList[idx];
1421
+ _checkAnnotationTarget(annotationResult, csnDefs, targetString, undefined, vocab, parserContext);
1422
+ }
1423
+ }
1424
+ // if the currentAnnoValue is a list or direct value, we preserve as it is
1425
+ else {
1426
+ targetString = currentAnnotation[0] + '.' + annoKey;
1427
+ currentResult[0] = targetString;
1428
+ currentResult[1] = currentAnnoValue;
1429
+ annotationResult[1] = currentResult;
1430
+ _checkAnnotationTarget(annotationResult, csnDefs, targetString, undefined, vocab, parserContext);
1431
+ }
1432
+ });
1433
+ }
1434
+ }
1435
+
1348
1436
  function _generateLongDescription(annotation, path, no_of_terms) {
1349
1437
  if (path) {
1350
1438
  path.doc = no_of_terms ? (path.doc += "\n\n") : (path.doc ? (path.doc += "") : (path.doc = ""));
package/lib/init/index.js CHANGED
@@ -24,6 +24,8 @@ module.exports = class CDSGenerator {
24
24
  target: 'projectName',
25
25
  validate: async (value) => {
26
26
  try {
27
+ cds.root = path.resolve(this.cwd, value || '.');
28
+
27
29
  await this._validateProjectName(value);
28
30
  await this._validateProjectFolder(path.join(this.cwd, value), this.cwd);
29
31
 
@@ -1,7 +1,7 @@
1
1
  # Please do not modify this file. This file may be overwritten.
2
2
 
3
- {{- $cloudService := index .Values "html5-apps-deployer.env.SAP_CLOUD_SERVICE" -}}
4
- {{- $defaultParameters := dict "Type" "HTTP" "ProxyType" "Internet" "Authentication" "NoAuthentication" "sap.cloud.service" "sap.fe.cap.sflight" "HTML5.forwardAuthToken" "true" }}
3
+ {{- $cloudService := index .Values "html5-apps-deployer" "env" "SAP_CLOUD_SERVICE" -}}
4
+ {{- $defaultParameters := dict "Type" "HTTP" "ProxyType" "Internet" "Authentication" "NoAuthentication" "sap.cloud.service" $cloudService "HTML5.forwardAuthToken" "true" }}
5
5
  {{- $ := dict "root" . "defaultParameters" $defaultParameters "html5" true }}
6
6
 
7
7
  apiVersion: v1
@@ -30,7 +30,7 @@ module.exports = class JavaTemplate extends require('../templateBase') {
30
30
  }
31
31
 
32
32
  async run() {
33
- const mvnCmdArgs = mvnArchetypeUtil.getGenerateCmdArgs(this.projectName, this.options);
33
+ const mvnCmdArgs = await mvnArchetypeUtil.getGenerateCmdArgs(this.projectName, this.options);
34
34
  const { cmdLine, artifactId, archetypeVersion } = mvnCmdArgs
35
35
 
36
36
  LOG.info(`Using Maven archetype version ${archetypeVersion}`);
@@ -2,10 +2,19 @@
2
2
  const { MAVEN_ARCHETYPE_VERSION, OPTION_JAVA_MVN,
3
3
  OPTION_JAVA_PACKAGE, OPTION_SAMPLES, REGEX_JAVA_PACKAGE, OPTION_HANA } = require('../constants');
4
4
 
5
+ const { CliError } = require('../../client/helper/errors');
6
+
7
+
8
+ const cp = require('child_process');
9
+ const util = require('util');
10
+ const execAsync = util.promisify(cp.exec);
11
+
12
+
5
13
  const DEFAULT_GROUP_ID = 'customer';
6
14
 
7
15
  const LOG = console
8
- const DEBUG = /\b(y|all|cli)\b/.test(process.env.DEBUG) && console.debug
16
+ const cds = require('../../cds')
17
+ const DEBUG = cds.debug('cli')
9
18
 
10
19
  class MvnArchetypeUtil {
11
20
 
@@ -88,7 +97,7 @@ class MvnArchetypeUtil {
88
97
  return packageName.toLowerCase().replace(/-/g, '_').replace(/\.([0-9])/g, '._$1').replace(/^([0-9])/, '_$1').replace(/\.+/g, '.');
89
98
  }
90
99
 
91
- getGenerateCmdArgs(projectName, options) {
100
+ async getGenerateCmdArgs(projectName, options) {
92
101
  const params = new Map();
93
102
 
94
103
  // set header
@@ -115,6 +124,29 @@ class MvnArchetypeUtil {
115
124
  this._scanMvnParams(options[OPTION_JAVA_MVN], params);
116
125
  }
117
126
 
127
+ // -DjdkVersion=[11|17]
128
+ if (!params.get('-DjdkVersion')) {
129
+ try {
130
+ const javaVersion = await execAsync('java -version');
131
+ const match = javaVersion?.stderr?.match(/version\s*"?(\d+\.\d+\.\d+)"?/);
132
+ if (match?.[1]) {
133
+ const segments = match[1]?.split('.');
134
+ const version = new Number(segments?.[0]);
135
+ switch (true) {
136
+ case (version < 11): throw new CliError(`Java version ${match[1]} is not supported. Use Java 11 or higher.`);
137
+ case (version <= 16): params.set(`-DjdkVersion`, 11); break;
138
+ case (version > 16): params.set(`-DjdkVersion`, 17); break;
139
+ default:
140
+ }
141
+ }
142
+ } catch (err) {
143
+ if (err instanceof CliError) {
144
+ throw err;
145
+ }
146
+ DEBUG?.(err);
147
+ }
148
+ }
149
+
118
150
  if (options[OPTION_JAVA_PACKAGE]) {
119
151
  params.set(`-Dpackage`, options[OPTION_JAVA_PACKAGE]);
120
152
  }
@@ -36,7 +36,7 @@ module.exports = new class ProjectReader {
36
36
  }
37
37
 
38
38
  async readProject(options) {
39
- if (options?.cwd) cds.root = options.cwd
39
+ // if (options?.cwd) cds.root = options.cwd
40
40
 
41
41
  const env = this.getEnv()
42
42
  DEBUG && DEBUG({ env })
@@ -73,8 +73,9 @@ module.exports = class LiveReload {
73
73
  }
74
74
 
75
75
  process.once('shutdown', ()=>{
76
- server.close()
76
+ this.wsServer.clients?.forEach(ws => ws.terminate())
77
77
  this.wsServer.close()
78
+ server.close()
78
79
  })
79
80
  })
80
81
  }
@@ -116,8 +117,12 @@ async function livereloadURL(address, port) {
116
117
  return
117
118
  }
118
119
  }
119
- // Local case. Add effective server address/host to URL so that e.g.
120
- // 2 reload servers on same port but different network stacks (IPv4 and IPv6)
121
- // can be uniquely addressed.
120
+ // Local case. Add effective server address/host to URL.
121
+ // Make sure IPv6 addresses are properly escaped.
122
+ if (require('net').isIPv6(address)) {
123
+ // TODO remove as soon as IPv6 support in https://github.com/livereload/livereload-js/pull/103 is fixed
124
+ if (address === '::1') address = 'localhost'
125
+ // address = `[${address}]`
126
+ }
122
127
  return `http://${address}:${port}/livereload.js?snipver=1`
123
128
  }