@sap/cds-compiler 3.1.2 → 3.4.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 (117) hide show
  1. package/CHANGELOG.md +101 -3
  2. package/bin/cdsc.js +4 -2
  3. package/doc/CHANGELOG_BETA.md +35 -0
  4. package/lib/api/main.js +153 -29
  5. package/lib/api/validate.js +8 -3
  6. package/lib/base/dictionaries.js +6 -6
  7. package/lib/base/error.js +2 -2
  8. package/lib/base/keywords.js +106 -24
  9. package/lib/base/message-registry.js +177 -79
  10. package/lib/base/messages.js +78 -57
  11. package/lib/base/model.js +2 -1
  12. package/lib/checks/actionsFunctions.js +1 -1
  13. package/lib/checks/annotationsOData.js +2 -2
  14. package/lib/checks/arrayOfs.js +15 -7
  15. package/lib/checks/cdsPersistence.js +1 -1
  16. package/lib/checks/checkForTypes.js +53 -0
  17. package/lib/checks/defaultValues.js +4 -2
  18. package/lib/checks/elements.js +81 -6
  19. package/lib/checks/foreignKeys.js +12 -13
  20. package/lib/checks/invalidTarget.js +10 -11
  21. package/lib/checks/managedInType.js +21 -15
  22. package/lib/checks/nullableKeys.js +1 -1
  23. package/lib/checks/onConditions.js +9 -9
  24. package/lib/checks/parameters.js +23 -0
  25. package/lib/checks/queryNoDbArtifacts.js +1 -1
  26. package/lib/checks/selectItems.js +1 -1
  27. package/lib/checks/sql-snippets.js +12 -10
  28. package/lib/checks/types.js +2 -2
  29. package/lib/checks/utils.js +17 -7
  30. package/lib/checks/validator.js +36 -14
  31. package/lib/compiler/assert-consistency.js +21 -13
  32. package/lib/compiler/builtins.js +8 -0
  33. package/lib/compiler/checks.js +57 -40
  34. package/lib/compiler/define.js +139 -69
  35. package/lib/compiler/extend.js +319 -50
  36. package/lib/compiler/finalize-parse-cdl.js +14 -9
  37. package/lib/compiler/kick-start.js +2 -35
  38. package/lib/compiler/populate.js +111 -68
  39. package/lib/compiler/propagator.js +5 -3
  40. package/lib/compiler/resolve.js +71 -108
  41. package/lib/compiler/shared.js +82 -54
  42. package/lib/compiler/tweak-assocs.js +26 -14
  43. package/lib/compiler/utils.js +13 -2
  44. package/lib/edm/annotations/genericTranslation.js +10 -7
  45. package/lib/edm/csn2edm.js +11 -11
  46. package/lib/edm/edm.js +17 -9
  47. package/lib/edm/edmPreprocessor.js +53 -30
  48. package/lib/edm/edmUtils.js +7 -2
  49. package/lib/gen/Dictionary.json +14 -0
  50. package/lib/gen/language.checksum +1 -1
  51. package/lib/gen/language.interp +3 -2
  52. package/lib/gen/languageParser.js +4312 -4186
  53. package/lib/inspect/inspectModelStatistics.js +1 -1
  54. package/lib/inspect/inspectPropagation.js +23 -9
  55. package/lib/json/csnVersion.js +13 -13
  56. package/lib/json/from-csn.js +161 -172
  57. package/lib/json/to-csn.js +70 -10
  58. package/lib/language/.eslintrc.json +4 -0
  59. package/lib/language/antlrParser.js +8 -11
  60. package/lib/language/docCommentParser.js +1 -2
  61. package/lib/language/errorStrategy.js +54 -27
  62. package/lib/language/genericAntlrParser.js +140 -93
  63. package/lib/language/language.g4 +57 -33
  64. package/lib/language/multiLineStringParser.js +75 -63
  65. package/lib/main.d.ts +3 -6
  66. package/lib/main.js +1 -0
  67. package/lib/model/.eslintrc.json +13 -0
  68. package/lib/model/api.js +4 -2
  69. package/lib/model/csnRefs.js +78 -50
  70. package/lib/model/csnUtils.js +272 -222
  71. package/lib/model/enrichCsn.js +41 -31
  72. package/lib/model/revealInternalProperties.js +61 -57
  73. package/lib/model/sortViews.js +35 -31
  74. package/lib/modelCompare/compare.js +52 -18
  75. package/lib/modelCompare/filter.js +83 -0
  76. package/lib/optionProcessor.js +10 -1
  77. package/lib/render/manageConstraints.js +11 -7
  78. package/lib/render/toCdl.js +151 -106
  79. package/lib/render/toHdbcds.js +8 -6
  80. package/lib/render/toRename.js +4 -4
  81. package/lib/render/toSql.js +17 -7
  82. package/lib/render/utils/common.js +27 -9
  83. package/lib/render/utils/sql.js +5 -5
  84. package/lib/sql-identifier.js +7 -0
  85. package/lib/transform/db/applyTransformations.js +32 -3
  86. package/lib/transform/db/assertUnique.js +27 -38
  87. package/lib/transform/db/expansion.js +92 -41
  88. package/lib/transform/db/flattening.js +1 -1
  89. package/lib/transform/db/temporal.js +3 -1
  90. package/lib/transform/db/transformExists.js +8 -2
  91. package/lib/transform/db/views.js +42 -13
  92. package/lib/transform/draft/db.js +2 -2
  93. package/lib/transform/forOdataNew.js +10 -7
  94. package/lib/transform/{forHanaNew.js → forRelationalDB.js} +18 -12
  95. package/lib/transform/localized.js +29 -20
  96. package/lib/transform/odata/toFinalBaseType.js +8 -11
  97. package/lib/transform/odata/typesExposure.js +2 -1
  98. package/lib/transform/parseExpr.js +245 -0
  99. package/lib/transform/transformUtilsNew.js +122 -51
  100. package/lib/transform/translateAssocsToJoins.js +17 -16
  101. package/lib/utils/moduleResolve.js +5 -5
  102. package/lib/utils/objectUtils.js +3 -3
  103. package/lib/utils/term.js +5 -5
  104. package/package.json +2 -2
  105. package/share/messages/anno-duplicate-unrelated-layer.md +6 -6
  106. package/share/messages/check-proper-type-of.md +4 -4
  107. package/share/messages/check-proper-type.md +2 -2
  108. package/share/messages/duplicate-autoexposed.md +4 -4
  109. package/share/messages/extend-repeated-intralayer.md +4 -5
  110. package/share/messages/extend-unrelated-layer.md +4 -4
  111. package/share/messages/message-explanations.json +3 -1
  112. package/share/messages/redirected-to-ambiguous.md +7 -6
  113. package/share/messages/redirected-to-complex.md +63 -0
  114. package/share/messages/redirected-to-unrelated.md +6 -5
  115. package/share/messages/rewrite-not-supported.md +4 -4
  116. package/share/messages/{syntax-expected-integer.md → syntax-expecting-integer.md} +4 -4
  117. package/share/messages/wildcard-excluding-one.md +37 -0
@@ -12,14 +12,17 @@ const { cloneCsnNonDict, cloneCsnDictionary, getUtils } = require('../model/csnU
12
12
  const { typeParameters, isBuiltinType } = require('../compiler/builtins');
13
13
  const { ModelError } = require("../base/error");
14
14
  const { forEach } = require('../utils/objectUtils');
15
+ const { pathName } = require("../compiler/utils");
15
16
 
17
+ const RestrictedOperators = ['<', '>', '>=', '<='];
18
+ const RelationalOperators = ['=', '!=', '<>', 'is' /*, 'like'*/,...RestrictedOperators];
16
19
  // Return the public functions of this module, with 'model' captured in a closure (for definitions, options etc).
17
20
  // Use 'pathDelimiter' for flattened names (e.g. of struct elements or foreign key elements).
18
21
  // 'model' is compacted new style CSN
19
22
  // TODO: Error and warnings handling with compacted CSN? - currently just throw new ModelError for everything
20
23
  // TODO: check the situation with assocs with values. In compacted CSN such elements have only "@Core.Computed": true
21
24
  function getTransformers(model, options, pathDelimiter = '_') {
22
- const { error, warning, info } = makeMessageFunction(model, options);
25
+ const { message, error, warning, info } = makeMessageFunction(model, options);
23
26
  const csnUtils = getUtils(model);
24
27
  const {
25
28
  getCsnDef,
@@ -500,7 +503,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
500
503
  * Create a 'DraftAdministrativeData' projection on entity 'DRAFT.DraftAdministrativeData'
501
504
  * in service 'service' and add it to the model.
502
505
  *
503
- * For forHanaNew, use String(36) instead of UUID and UTCTimestamp instead of Timestamp
506
+ * For forRelationalDB, use String(36) instead of UUID and UTCTimestamp instead of Timestamp
504
507
  *
505
508
  * @param {string} service
506
509
  * @param {boolean} [hanaMode=false] Turn UUID into String(36)
@@ -709,7 +712,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
709
712
  if (artifactName) {
710
713
  path = ['definitions', artifactName, 'elements', elemName];
711
714
  }
712
- error(null, path, { name: elemName }, `Generated element $(NAME) conflicts with existing element`);
715
+ error(null, path, { name: elemName }, 'Generated element $(NAME) conflicts with existing element');
713
716
  return;
714
717
  }
715
718
 
@@ -863,9 +866,9 @@ function getTransformers(model, options, pathDelimiter = '_') {
863
866
  if (array.length > 1) {
864
867
  const loc = ['definitions', artifactName];
865
868
  if (err === true) {
866
- error(null, loc, { anno: annoName }, `Annotation $(ANNO) must be assigned only once`);
869
+ error(null, loc, { anno: annoName }, 'Annotation $(ANNO) must be assigned only once');
867
870
  } else {
868
- warning(null, loc, { anno: annoName },`Annotation $(ANNO) must be assigned only once`);
871
+ warning(null, loc, { anno: annoName },'Annotation $(ANNO) must be assigned only once');
869
872
  }
870
873
  }
871
874
  }
@@ -956,7 +959,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
956
959
  node[name] = value;
957
960
  if(wasOverwritten)
958
961
  info(null, path, { anno: name, prop: value, otherprop: oldValue },
959
- `Value $(OTHERPROP) of annotation $(ANNO) is overwritten with new value $(PROP)`);
962
+ 'Value $(OTHERPROP) of annotation $(ANNO) is overwritten with new value $(PROP)');
960
963
  return wasOverwritten;
961
964
  }
962
965
 
@@ -1113,92 +1116,122 @@ function getTransformers(model, options, pathDelimiter = '_') {
1113
1116
  for(let i = 0; i < expr.length; i++)
1114
1117
  {
1115
1118
  if(Array.isArray(expr[i]))
1116
- rc.push(expr[i].map(expand, location));
1119
+ rc.push(expr[i].map(e => expand(e, location)));
1117
1120
 
1118
1121
  if(i < expr.length-2)
1119
1122
  {
1120
- const [lhs, op, rhs] = expr.slice(i);
1123
+ let [lhs, op, not, rhs] = expr.slice(i);
1124
+ if(not !== 'not') {
1125
+ rhs = not;
1126
+ not = false;
1127
+ }
1128
+ if(lhs === undefined || op === undefined || rhs === undefined)
1129
+ return expr;
1121
1130
 
1122
1131
  // we might have to ad-hoc resolve a ref, since handleExists is run before hand and generates new refs.
1123
1132
  const lhsArt = lhs._art || lhs.ref && !lhs.$scope && inspectRef(location.concat(i)).art;
1124
1133
  const rhsArt = rhs._art || rhs.ref && !rhs.$scope && inspectRef(location.concat(i+2)).art;
1125
- // lhs & rhs must be expandable types (structures or managed associations)
1126
- if(lhsArt && rhsArt &&
1127
- lhs.ref && rhs.ref &&
1128
- isExpandable(lhsArt) && isExpandable(rhsArt) &&
1129
- ['=', '<', '>', '>=', '<=', '!=', '<>'].includes(op) &&
1130
- !(isDollarSelfOrProjectionOperand(lhs) || isDollarSelfOrProjectionOperand(rhs))) {
1134
+ const lhsIsVal = (lhs.val !== undefined);
1135
+ // if ever rhs should be alowed to be a value uncomment this
1136
+ const rhsIsVal = (rhs === 'null' /*|| rhs.val !== undefined*/);
1131
1137
 
1138
+ // lhs & rhs must be expandable types (structures or managed associations)
1139
+ // if ever lhs should be alowed to be a value uncomment this
1140
+ if(!(lhsIsVal /*&& rhsIsVal*/) &&
1141
+ !(isDollarSelfOrProjectionOperand(lhs) || isDollarSelfOrProjectionOperand(rhs)) &&
1142
+ RelationalOperators.includes(op) &&
1143
+ (lhsIsVal || (lhsArt && lhs.ref && isExpandable(lhsArt))) &&
1144
+ (rhsIsVal || (rhsArt && rhs.ref && isExpandable(rhsArt)))
1145
+ ) {
1146
+
1147
+ if(RestrictedOperators.includes(op)) {
1148
+ message('expr-unexpected-operator', location, { op }, 'Unexpected operator $(OP) in structural comparison');
1149
+ }
1132
1150
  // if path is scalar and no assoc or has no type (@Core.Computed) use original expression
1133
1151
  // only do the expansion on (managed) assocs and (items.)elements, array of check in ON cond is done elsewhere
1134
- const lhspaths = /*isScalarOrNoType(lhs._art) ? [ lhs ] : */ flattenPath({ _art: lhsArt, ref: lhs.ref }, false, true );
1135
- const rhspaths = /*isScalarOrNoType(rhs._art) ? [ rhs ] : */ flattenPath({ _art: rhsArt, ref: rhs.ref }, false, true );
1152
+ const lhspaths = lhsIsVal ? [] : flattenPath({ _art: lhsArt, ref: lhs.ref }, false, true );
1153
+ const rhspaths = rhsIsVal ? [] : flattenPath({ _art: rhsArt, ref: rhs.ref }, false, true );
1136
1154
 
1137
1155
  // mapping dict for lhs/rhs for mismatch check
1138
1156
  // strip lhs/rhs prefix from flattened paths to check remaining common trailing path
1139
1157
  // if path is idempotent, it doesn't produce new flattened paths (ends on scalar type)
1140
1158
  // key is then empty string on both sides '' (=> equality)
1141
1159
  // Path matches if lhs/rhs are available
1142
- const xref = lhspaths.reduce((a, v) => {
1143
- a[v.ref.slice(lhs.ref.length).join('.')] = { lhs: v };
1144
- return a;
1145
- }, Object.create(null));
1146
-
1147
- rhspaths.forEach(v => {
1148
- const k = v.ref.slice(rhs.ref.length).join('.');
1149
- if(xref[k])
1150
- xref[k].rhs = v;
1151
- else
1152
- xref[k] = { rhs: v };
1153
- });
1154
-
1160
+ const xref = createXRef(lhspaths, rhspaths, lhs, rhs, lhsIsVal, rhsIsVal);
1161
+ const xrefkeys = Object.keys(xref);
1162
+ const xrefvalues = Object.values(xref);
1155
1163
  let cont = true;
1156
- for(const xn in xref) {
1157
- const x = xref[xn];
1158
1164
 
1165
+ if(op === 'like' && xrefvalues.reduce((a, v) => {
1166
+ return (v.lhs && v.rhs) ? a + 1: a;
1167
+ }, 0) === 0) {
1168
+ // error if intersection of paths is zero
1169
+ error(null, location, { lhs: pathName(lhs.ref), op, rhs: pathName(rhs.ref) },
1170
+ 'Expected compatible types for $(LHS) $(OP) $(RHS)');
1171
+ cont = false;
1172
+ }
1173
+
1174
+ cont && xrefkeys.forEach(xn => {
1175
+ const x = xref[xn];
1176
+ const prefix = `${pathName(lhs.ref)} ${op} ${pathName(rhs.ref)}`;
1159
1177
  // do the paths match?
1160
- if(!(x.lhs && x.rhs)) {
1161
- if(xn.length)
1162
- error(null, location, `'${lhs.ref.join('.')} ${op} ${rhs.ref.join('.')}': Sub path '${xn}' not found in ${((x.lhs ? rhs : lhs).ref.join('.'))}`)
1163
- else
1164
- error(null, location, `'${lhs.ref.join('.')} ${op} ${rhs.ref.join('.')}': Path '${((x.lhs ? lhs : rhs).ref.join('.'))}' does not match ${((x.lhs ? rhs : lhs).ref.join('.'))}`)
1178
+ if(op !== 'like' && !(x.lhs && x.rhs)) {
1179
+ if(xn.length) {
1180
+ error(null, location, { prefix, name: xn, alias: pathName((x.lhs ? rhs : lhs).ref) },
1181
+ '$(PREFIX): Sub path $(NAME) not found in $(ALIAS)');
1182
+ }
1183
+ else {
1184
+ error(null, location, { prefix, name: pathName((x.lhs ? lhs : rhs).ref), alias: pathName((x.lhs ? rhs : lhs).ref) },
1185
+ '$(PREFIX): Path $(NAME) does not match $(ALIAS)');
1186
+ }
1165
1187
  cont = false;
1166
1188
  }
1167
1189
  // lhs && rhs are present, consistency checks that affect both ends
1168
1190
  else {
1169
1191
  // is lhs scalar?
1170
- if(!isScalarOrNoType(x.lhs._art)) {
1171
- error(null, location, `'${lhs.ref.join('.')} ${op} ${rhs.ref.join('.')}': Path '${x.lhs.ref.join('.')}${(xn.length ? '.' + xn : '')}' must end on a scalar type`)
1192
+ if(!lhsIsVal && x.lhs && !isScalarOrNoType(x.lhs._art)) {
1193
+ error(null, location, { prefix, name: `${pathName(x.lhs.ref)}${(xn.length ? '.' + xn : '')}` },
1194
+ '$(PREFIX): Path $(NAME) must end on a scalar type')
1172
1195
  cont = false;
1173
1196
  }
1174
1197
  // is rhs scalar?
1175
- if(!isScalarOrNoType(x.rhs._art)) {
1176
- error(null, location, `'${lhs.ref.join('.')} ${op} ${rhs.ref.join('.')}': Path '${x.rhs.ref.join('.')}${(xn.length ? '.' + xn : '')}' must end on a scalar type`)
1198
+ if(!rhsIsVal && x.rhs && !isScalarOrNoType(x.rhs._art)) {
1199
+ error(null, location, { prefix, name: `${pathName(x.rhs.ref)}${(xn.length ? '.' + xn : '')}` },
1200
+ '$(PREFIX): Path $(NAME) must end on a scalar type');
1177
1201
  cont = false;
1178
1202
  }
1179
- // info about type incompatibility if no other errors occured
1180
- if(xn && cont) {
1203
+ // info about type incompatibility if no other errors occurred
1204
+ if(!(lhsIsVal || rhsIsVal) && x.lhs && x.rhs && xn && cont) {
1181
1205
  const lhst = getType(x.lhs._art);
1182
1206
  const rhst = getType(x.rhs._art);
1183
1207
  if(lhst !== rhst) {
1184
- info(null, location, `'${lhs.ref.join('.')} ${op} ${rhs.ref.join('.')}': Types for sub path '${xn}' don't match`)
1208
+ info(null, location, { prefix, name: xn },'$(PREFIX): Types for sub path $(NAME) don\'t match');
1185
1209
  }
1186
1210
  }
1187
1211
  }
1188
- }
1212
+ });
1189
1213
  // don't continue if there are path errors
1190
1214
  if(!cont)
1191
1215
  return expr;
1192
1216
 
1193
- Object.keys(xref).forEach((k, i) => {
1194
- const x = xref[k];
1217
+ // if lhs and rhs are refs set operator from 'like' to '='
1218
+ if(op === 'like' && !(lhsIsVal || rhsIsVal)) {
1219
+ op = '=';
1220
+ }
1221
+ // t_0 OR ... OR t_n with t = (a <not equal> b)
1222
+ const bop = (op === 'is' && not) || op === '!=' || op === '<>' ? 'or' : 'and';
1223
+ rc.push('(');
1224
+ xrefvalues.filter(x => x.lhs && x.rhs).forEach((x,i) => {
1195
1225
  if(i>0)
1196
- rc.push('and');
1226
+ rc.push(bop);
1197
1227
  rc.push(x.lhs);
1198
1228
  rc.push(op);
1229
+ if(not)
1230
+ rc.push('not')
1199
1231
  rc.push(x.rhs);
1200
1232
  });
1201
- i += 2;
1233
+ rc.push(')');
1234
+ i += not ? 3 : 2;
1202
1235
  }
1203
1236
  else
1204
1237
  rc.push(expr[i]);
@@ -1208,6 +1241,44 @@ function getTransformers(model, options, pathDelimiter = '_') {
1208
1241
  }
1209
1242
  return rc;
1210
1243
 
1244
+ function createXRef(lhspaths, rhspaths, lhs, rhs, lhsIsVal, rhsIsVal) {
1245
+ // mapping dict for lhs/rhs for mismatch check
1246
+ // strip lhs/rhs prefix from flattened paths to check remaining common trailing path
1247
+ // if path is idempotent, it doesn't produce new flattened paths (ends on scalar type)
1248
+ // key is then empty string on both sides '' (=> equality)
1249
+ // Path matches if lhs/rhs are available
1250
+ let xref;
1251
+ if(!lhsIsVal) {
1252
+ xref = lhspaths.reduce((a, v) => {
1253
+ a[v.ref.slice(lhs.ref.length).join('.')] = rhsIsVal ? { lhs: v, rhs } : { lhs: v };
1254
+ return a;
1255
+ }, Object.create(null));
1256
+
1257
+ rhspaths.forEach(v => {
1258
+ const k = v.ref.slice(rhs.ref.length).join('.');
1259
+ if(xref[k])
1260
+ xref[k].rhs = v;
1261
+ else
1262
+ xref[k] = { rhs: v };
1263
+ });
1264
+ }
1265
+ else if(!rhsIsVal) {
1266
+ xref = rhspaths.reduce((a, v) => {
1267
+ a[v.ref.slice(rhs.ref.length).join('.')] = lhsIsVal ? { lhs, rhs: v } : { rhs: v };
1268
+ return a;
1269
+ }, Object.create(null));
1270
+
1271
+ lhspaths.forEach(v => {
1272
+ const k = v.ref.slice(lhs.ref.length).join('.');
1273
+ if(xref[k])
1274
+ xref[k].lhs = v;
1275
+ else
1276
+ xref[k] = { lhs: v };
1277
+ });
1278
+ }
1279
+ return xref;
1280
+ }
1281
+
1211
1282
  function getType(art) {
1212
1283
  const effart = effectiveType(art);
1213
1284
  return Object.keys(effart).length ? effart : art.type;
@@ -1218,7 +1289,7 @@ function getTransformers(model, options, pathDelimiter = '_') {
1218
1289
  if(art) {
1219
1290
  // items in ON conds are illegal but this should be checked elsewhere
1220
1291
  const elements = art.elements || (art.items && art.items.elements);
1221
- return (elements || art.target && art.keys)
1292
+ return !!(elements || art.target && art.keys)
1222
1293
  }
1223
1294
  return false;
1224
1295
  }
@@ -1241,7 +1312,6 @@ function getTransformers(model, options, pathDelimiter = '_') {
1241
1312
 
1242
1313
  }
1243
1314
 
1244
-
1245
1315
  /**
1246
1316
  * Modify the given CSN/artifact in-place, applying the given customTransformations.
1247
1317
  * Dictionaries are correctly handled - a "type" transformer will not be called on an entity called "type".
@@ -1333,5 +1403,6 @@ function transformModel(csn, customTransformations, transformNonEnumerableElemen
1333
1403
  module.exports = {
1334
1404
  // This function retrieves the actual exports
1335
1405
  getTransformers,
1336
- transformModel
1406
+ transformModel,
1407
+ RelationalOperators
1337
1408
  };
@@ -9,7 +9,7 @@ const { deduplicateMessages } = require('../base/messages');
9
9
  const { timetrace } = require('../utils/timetrace');
10
10
  // Paths that start with an artifact of protected kind are special
11
11
  // either ignore them in QAT building or in path rewriting
12
- const internalArtifactKinds = ['builtin'/*, '$parameters'*/, 'param'];
12
+ const internalArtifactKinds = ['builtin', '$parameters', 'param'];
13
13
 
14
14
  function translateAssocsToJoinsCSN(csn, options){
15
15
  timetrace.start('Recompiling model');
@@ -444,7 +444,7 @@ function translateAssocsToJoins(model, inputOptions = {})
444
444
  }
445
445
  else if(art.target) { // it's not an artifact, so it should be an assoc step
446
446
  if(joinTree === undefined)
447
- throw Error('Cannot follow Associations without starting Entity');
447
+ throw Error('Can\'t follow Associations without starting Entity');
448
448
 
449
449
  if(!childQat.$QA)
450
450
  childQat.$QA = createQA(env, art.target._artifact, art.name.id, childQat._namedArgs);
@@ -762,7 +762,8 @@ function translateAssocsToJoins(model, inputOptions = {})
762
762
 
763
763
  let [head, ...tail] = path;
764
764
 
765
- if(internalArtifactKinds.includes(head._artifact.kind)) // don't rewrite path
765
+ // don't rewrite path
766
+ if(internalArtifactKinds.includes(head._artifact.kind))
766
767
  return pathNode;
767
768
 
768
769
  // strip the absolute path indicators
@@ -901,29 +902,29 @@ function translateAssocsToJoins(model, inputOptions = {})
901
902
  // source side from view point of view (target side from forward point of view)
902
903
  path = tail; // pop assoc step
903
904
  let elt = env.lead._combined[path[0].id];
904
- let err = 'Element "' + path[0].id +
905
- '" referred in association "' + assoc.name.id +'" of Artifact "' + assoc.name.absolute +'"';
906
905
 
907
906
  if(elt) {
908
907
  if(Array.isArray(elt)) {
909
- err += ' is available from multiple query sources ' +
910
- elt.map(e => '"' + e._origin.name.absolute + '"').join(', ');
911
- error(null, assocQAT._origin.location, `${err}`);
908
+ const names = elt.map(e => e._origin.name.absolute);
909
+ error(null, [ assocQAT._origin.location, assocQAT._origin ], { elemref: path[0].id, id: assoc.name.id, art: assoc.name.absolute, names },
910
+ 'Element $(ELEMREF) referred in association $(ID) of artifact $(ART) is available from multiple query sources $(NAMES)');
912
911
  return pathNode.path;
913
912
  } else {
914
913
  // check if element has same origin on both ends
915
914
  if(elt._origin._main !== path[0]._artifact._origin._main) {
916
- err += ' originates from "' +
917
- path[0]._artifact._origin._main.name.absolute+'" and from "' +
918
- elt._origin._main.name.absolute +
919
- '" in "' + elt._main.name.absolute + '"';
920
- warning(null, assocQAT._origin.location, `${err}`);
915
+ warning(null, [ assocQAT._origin.location, assocQAT._origin ], {
916
+ elemref: path[0].id,
917
+ id: assoc.name.id, art: assoc.name.absolute,
918
+ name: path[0]._artifact._origin._main.name.absolute,
919
+ alias: elt._origin._main.name.absolute,
920
+ source: elt._main.name.absolute,
921
+ }, 'Element $(ELEMREF) referred in association $(ID) of artifact $(ART) originates from $(NAME) and from $(ALIAS) in $(SOURCE)');
921
922
  }
922
923
  _navigation = elt._parent;
923
924
  }
924
925
  } else {
925
- err += ' has not been found';
926
- error(null, assocQAT._origin.location, `${err}`);
926
+ error(null, [ assocQAT._origin.location, assocQAT._origin ], { elemref: path[0].id, id: assoc.name.id, art: assoc.name.absolute },
927
+ 'Element $(ELEMREF) referred in association $(ID) of artifact $(ART) has not been found');
927
928
  return pathNode.path;
928
929
  }
929
930
  } else {
@@ -1536,7 +1537,7 @@ function translateAssocsToJoins(model, inputOptions = {})
1536
1537
  ( // not leaf
1537
1538
  i < tail.length-1 &&
1538
1539
  // path terminates on a scalar type
1539
- // _effectiveType.elements can be removed if forHanaNew can expand fk paths correctly
1540
+ // _effectiveType.elements can be removed if forRelationalDB can expand fk paths correctly
1540
1541
  !(tail[tail.length-1]._artifact._effectiveType.elements || tail[tail.length-1]._artifact._effectiveType.target) &&
1541
1542
  // association is managed
1542
1543
  art.foreignKeys &&
@@ -173,13 +173,13 @@ function _errorFileNotFound(dep, options, { error }) {
173
173
  resolved = resolved.replace( /\\/g, '/' );
174
174
  for (const from of dep.usingFroms) {
175
175
  error( 'file-not-readable', from.location, { file: resolved },
176
- 'Cannot read file $(FILE)' );
176
+ 'Can\'t read file $(FILE)' );
177
177
  }
178
178
  }
179
179
  else if (isLocalFile( dep.module ) ) {
180
180
  for (const from of dep.usingFroms) {
181
181
  error( 'file-unknown-local', from.location, { file: dep.module },
182
- 'Cannot find local module $(FILE)' );
182
+ 'Can\'t find local module $(FILE)' );
183
183
  }
184
184
  }
185
185
  else {
@@ -187,8 +187,8 @@ function _errorFileNotFound(dep, options, { error }) {
187
187
  for (const from of dep.usingFroms) {
188
188
  error( 'file-unknown-package', from.location,
189
189
  { file: dep.module, '#': internal }, {
190
- std: 'Cannot find package $(FILE)',
191
- internal: 'Cannot find package module $(FILE)',
190
+ std: 'Can\'t find package $(FILE)',
191
+ internal: 'Can\'t find package module $(FILE)',
192
192
  } );
193
193
  }
194
194
  }
@@ -417,7 +417,7 @@ function resolveCDS(moduleName, options, callback) {
417
417
  * @returns {Error}
418
418
  */
419
419
  function makeNotFoundError() {
420
- const moduleError = new Error(`Cannot find module '${ moduleName }' from '${ options.basedir }'`);
420
+ const moduleError = new Error(`Can't find module '${ moduleName }' from '${ options.basedir }'`);
421
421
  // eslint-disable-next-line
422
422
  moduleError['code'] = 'MODULE_NOT_FOUND';
423
423
  return moduleError;
@@ -37,7 +37,7 @@ function createDict(obj) {
37
37
  */
38
38
  function forEach(obj, callback) {
39
39
  for (const key in obj) {
40
- if (Object.hasOwnProperty.call(obj, key))
40
+ if (Object.prototype.hasOwnProperty.call(obj, key))
41
41
  callback(key, obj[key]);
42
42
  }
43
43
  }
@@ -51,7 +51,7 @@ function forEach(obj, callback) {
51
51
  */
52
52
  function forEachValue(o, callback) {
53
53
  for (const key in o) {
54
- if (Object.hasOwnProperty.call(o, key))
54
+ if (Object.prototype.hasOwnProperty.call(o, key))
55
55
  callback(o[key]);
56
56
  }
57
57
  }
@@ -65,7 +65,7 @@ function forEachValue(o, callback) {
65
65
  */
66
66
  function forEachKey(o, callback) {
67
67
  for (const key in o) {
68
- if (Object.hasOwnProperty.call(o, key))
68
+ if (Object.prototype.hasOwnProperty.call(o, key))
69
69
  callback(key);
70
70
  }
71
71
  }
package/lib/utils/term.js CHANGED
@@ -1,6 +1,6 @@
1
1
  //
2
2
  // This file is used for color output to stderr and stdout.
3
- // Use `term.error`, `term.warn` and `term.info` as they use color output
3
+ // Use `term.asError`, `term.asWarn` and `term.asInfo` as they use color output
4
4
  // per default if the process runs in a TTY, i.e. stdout as well as
5
5
  // stderr are TTYs. stderr/stdout are no TTYs if they are
6
6
  // (for example) piped into another process or written to file:
@@ -88,10 +88,10 @@ function term(useColor = 'auto') {
88
88
  bold,
89
89
 
90
90
  severity: asSeverity,
91
- error: asError,
92
- warn: asWarning,
93
- info: asInfo,
94
- help: asHelp,
91
+ asError,
92
+ asWarning,
93
+ asInfo,
94
+ asHelp,
95
95
  };
96
96
  }
97
97
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sap/cds-compiler",
3
- "version": "3.1.2",
3
+ "version": "3.4.0",
4
4
  "description": "CDS (Core Data Services) compiler and backends",
5
5
  "homepage": "https://cap.cloud.sap/",
6
6
  "author": "SAP SE (https://www.sap.com)",
@@ -16,7 +16,7 @@
16
16
  "scripts": {
17
17
  "download": "node scripts/downloadANTLR.js",
18
18
  "gen": "node ./scripts/build.js && node scripts/genGrammarChecksum.js",
19
- "xmakeBeforeInstall": "echo \"Due to binary mirror, use sqlite 5.0.11 explicitly\" && npm install --save --save-exact --no-package-lock sqlite3@5.0.11",
19
+ "xmakeBeforeInstall": "echo \"Due to binary mirror, use sqlite 5.1.2 explicitly\" && npm install --save --save-exact --no-package-lock sqlite3@5.1.2",
20
20
  "xmakeAfterInstall": "npm run gen",
21
21
  "xmakePrepareRelease": "echo \"$(node scripts/stripReadme.js README.md)\" > README.md && node scripts/assertSnapshotVersioning.js && node scripts/assertChangelog.js && node scripts/cleanup.js --remove-dev",
22
22
  "test": "node scripts/verifyGrammarChecksum.js && mocha --reporter min --reporter-option maxDiffSize=0 scripts/testLazyLoading.js && mocha --parallel --reporter min --reporter-option maxDiffSize=0 test/ test3/",
@@ -11,7 +11,7 @@ CDL file is equivalent to a layer.
11
11
 
12
12
  Erroneous code example using four CDS files:
13
13
 
14
- ```cdl
14
+ ```cds
15
15
  // (1) Base.cds: Contains the artifact that should be annotated
16
16
  entity FooBar { }
17
17
 
@@ -41,15 +41,15 @@ represents one layer.
41
41
 
42
42
  ## How to Fix
43
43
 
44
- To fix the issue, remove one of the duplicate annotations. Chances are, that
45
- only one was intended to begin with. For the erroneous example above, remove
46
- the annotation from (3).
44
+ Remove one of the duplicate annotations. Chances are, that only one was
45
+ intended to begin with. For the erroneous example above, remove the annotation
46
+ from (3).
47
47
 
48
48
  Alternatively, add an annotation assignment to (4). This annotation has
49
49
  precedence and the error will vanish. For the example above, (4) will look
50
50
  like this:
51
51
 
52
- ```cdl
52
+ ```cds
53
53
  // (4) All.cds: Combine all files
54
54
  using from './FooAnnotate';
55
55
  using from './BarAnnotate';
@@ -60,7 +60,7 @@ annotate FooBar with @Anno: 'Bar';
60
60
  You can also make (3) depend on (2) so that they are no longer in unrelated
61
61
  layers and the compiler can determine which annotation to apply.
62
62
 
63
- ```cdl
63
+ ```cds
64
64
  // (3) BarAnnotate.cds: Now depends on (2)
65
65
  using from './FooAnnotate';
66
66
  annotate FooBar with @Anno: 'Bar';
@@ -4,13 +4,13 @@ An element in a `type of` expression doesn’t have proper type information.
4
4
 
5
5
  The message's severity is `Info` but may be raised to `Error` in the SQL,
6
6
  SAP HANA, and OData backends. These backends require elements to have a type.
7
- Otherwise they aren’t able to render elements (for example, to SQL columns).
7
+ Otherwise, they aren’t able to render elements (for example, to SQL columns).
8
8
 
9
9
  ## Example
10
10
 
11
11
  Erroneous code example:
12
12
 
13
- ```cdl
13
+ ```cds
14
14
  entity Foo {
15
15
  key id : Integer;
16
16
  };
@@ -33,9 +33,9 @@ properties but won’t have a proper type, which is required by some backends.
33
33
 
34
34
  ## How to Fix
35
35
 
36
- To fix the issue, assign an explicit type to `ViewFoo:calculatedField`.
36
+ Assign an explicit type to `ViewFoo:calculatedField`.
37
37
 
38
- ```cdl
38
+ ```cds
39
39
  view ViewFoo as select from Foo {
40
40
  1+1 as calculatedField @(anno) : Integer
41
41
  };
@@ -27,8 +27,8 @@ Erroneous code example:
27
27
 
28
28
  ## How to Fix
29
29
 
30
- To fix the issue, add explicit type information to `MainType`, for example, add
31
- an `elements` property to make a structured type.
30
+ Add explicit type information to `MainType`, for example, add an `elements`
31
+ property to make a structured type.
32
32
 
33
33
  ```json
34
34
  {
@@ -15,7 +15,7 @@ adapt your model to fix the error.
15
15
 
16
16
  Erroneous code example:
17
17
 
18
- ```cdl
18
+ ```cds
19
19
  // (1)
20
20
  entity ns.first.Foo {
21
21
  key parent : Association to one ns.Base;
@@ -46,13 +46,13 @@ of (2) and (3) are ignored, a name collision happens.
46
46
 
47
47
  ## How to Fix
48
48
 
49
- To fix the issue, you need to explicitly expose one or more entities under
50
- a name that does not exist in the service, yet.
49
+ You need to explicitly expose one or more entities under a name that does not
50
+ exist in the service, yet.
51
51
 
52
52
  For the erroneous example above, you could add these two lines to the service
53
53
  `ns.MyService`:
54
54
 
55
- ```cdl
55
+ ```cds
56
56
  entity first.Foo as projection on ns.first.Foo; // (5)
57
57
  entity second.Foo as projection on ns.second.Foo; // (6)
58
58
  ```
@@ -11,7 +11,7 @@ They form a cyclic connection through their dependencies
11
11
 
12
12
  Erroneous code example with a single CDL file:
13
13
 
14
- ```cdl
14
+ ```cds
15
15
  entity FooBar { }
16
16
 
17
17
  extend FooBar { foo : Integer; }
@@ -24,7 +24,7 @@ inside `FooBar` may not be stable. You therefore can’t depend on it.
24
24
  It's also possible to trigger this warning with multiple files.
25
25
  Look at the following example:
26
26
 
27
- ```cdl
27
+ ```cds
28
28
  // (1) Definition.cds
29
29
  using from './Extension.cds';
30
30
  entity FooBar { };
@@ -40,10 +40,9 @@ layer with multiple extensions. Again, the element order isn’t stable.
40
40
 
41
41
  ## How to Fix
42
42
 
43
- To fix the issue, move extensions for the same artifact into the same extension
44
- block:
43
+ Move extensions for the same artifact into the same extension block:
45
44
 
46
- ```cdl
45
+ ```cds
47
46
  // (1) Definition.cds : No extension block
48
47
  using from './Extension.cds';
49
48
  entity FooBar { }
@@ -11,7 +11,7 @@ They form a cyclic connection through their dependencies
11
11
 
12
12
  Erroneous code example using four CDS files:
13
13
 
14
- ```cdl
14
+ ```cds
15
15
  // (1) Base.cds: Contains the artifact that should be extended
16
16
  entity FooBar { }
17
17
 
@@ -38,13 +38,13 @@ represents one layer.
38
38
 
39
39
  ## How to Fix
40
40
 
41
- To fix the issue, move extensions for the same artifact into the same layer,
42
- that is, the same file.
41
+ Move extensions for the same artifact into the same layer, that is, the same
42
+ file.
43
43
 
44
44
  For the erroneous example above, remove the extension from (3) and move
45
45
  it to (2):
46
46
 
47
- ```cdl
47
+ ```cds
48
48
  // (2) FooExtend.cds
49
49
  using from './Base';
50
50
  extend FooBar {
@@ -8,8 +8,10 @@
8
8
  "extend-repeated-intralayer",
9
9
  "extend-unrelated-layer",
10
10
  "redirected-to-ambiguous",
11
+ "redirected-to-complex",
11
12
  "redirected-to-unrelated",
12
13
  "rewrite-not-supported",
13
- "syntax-expected-integer"
14
+ "syntax-expecting-integer",
15
+ "wildcard-excluding-one"
14
16
  ]
15
17
  }