@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 +24 -0
- package/lib/client/helper/errors.js +3 -1
- package/lib/compile/openapi/csdl2openapi.js +2 -0
- package/lib/import/message.js +2 -1
- package/lib/import/odata/metadataconverter/MetadataConverter.js +7 -2
- package/lib/import/odata/v4parser.js +133 -45
- package/lib/init/index.js +2 -0
- package/lib/init/template/html5-repo/files/html5-apps-deployer-configmap.yaml +2 -2
- package/lib/init/template/java/index.js +1 -1
- package/lib/init/util/mvnArchetypeUtil.js +34 -2
- package/lib/init/util/projectReader.js +1 -1
- package/lib/watch/livereload-server.js +9 -4
- package/npm-shrinkwrap.json +502 -615
- package/package.json +3 -3
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
|
-
|
|
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) {
|
package/lib/import/message.js
CHANGED
|
@@ -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('$
|
|
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
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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
|
-
|
|
948
|
-
|
|
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
|
|
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
|
|
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(
|
|
1187
|
-
if (
|
|
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,
|
|
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 (
|
|
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,
|
|
1230
|
+
_checkAnnotatationTerm(annotation, csnDefs[path1], no_of_terms, str, vocab);
|
|
1215
1231
|
}
|
|
1216
1232
|
} else {
|
|
1217
|
-
_checkAnnotatationTerm(annotation,
|
|
1233
|
+
_checkAnnotatationTerm(annotation, csnDefs[annotation[0]], no_of_terms, str, vocab);
|
|
1218
1234
|
}
|
|
1219
1235
|
}
|
|
1220
1236
|
else {
|
|
1221
|
-
_checkAnnotatationTerm(annotation,
|
|
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 (
|
|
1229
|
-
_checkAnnotatationTerm(annotation,
|
|
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,
|
|
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,
|
|
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,
|
|
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 (
|
|
1263
|
-
_checkAnnotatationTerm(annotation,
|
|
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 (
|
|
1269
|
-
_checkAnnotatationTerm(annotation,
|
|
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 (
|
|
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 (
|
|
1281
|
-
_checkAnnotatationTerm(annotation,
|
|
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,
|
|
1302
|
+
_checkAnnotatationTerm(annotation, csnDefs[path[0]], no_of_terms, str, vocab);
|
|
1286
1303
|
} else {
|
|
1287
1304
|
let path1 = path[1].split('/');
|
|
1288
|
-
if (
|
|
1289
|
-
_checkAnnotatationTerm(annotation,
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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
|
|
4
|
-
{{- $defaultParameters := dict "Type" "HTTP" "ProxyType" "Internet" "Authentication" "NoAuthentication" "sap.cloud.service"
|
|
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
|
|
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
|
}
|
|
@@ -73,8 +73,9 @@ module.exports = class LiveReload {
|
|
|
73
73
|
}
|
|
74
74
|
|
|
75
75
|
process.once('shutdown', ()=>{
|
|
76
|
-
|
|
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
|
|
120
|
-
//
|
|
121
|
-
|
|
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
|
}
|