@abaplint/cli 2.120.28 → 2.120.30

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 (2) hide show
  1. package/build/cli.js +247 -28
  2. package/package.json +2 -2
package/build/cli.js CHANGED
@@ -3781,10 +3781,10 @@ exports.ClassName = ClassName;
3781
3781
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3782
3782
  exports.Color = void 0;
3783
3783
  const combi_1 = __webpack_require__(/*! ../combi */ "../core/build/src/abap/2_statements/combi.js");
3784
- const source_1 = __webpack_require__(/*! ./source */ "../core/build/src/abap/2_statements/expressions/source.js");
3784
+ const simple_source3_1 = __webpack_require__(/*! ./simple_source3 */ "../core/build/src/abap/2_statements/expressions/simple_source3.js");
3785
3785
  class Color extends combi_1.Expression {
3786
3786
  getRunnable() {
3787
- const eq = (0, combi_1.seq)("=", source_1.Source);
3787
+ const eq = (0, combi_1.seq)("=", simple_source3_1.SimpleSource3);
3788
3788
  const integers = (0, combi_1.altPrio)("1", "2", "3", "4", "5", "6", "7");
3789
3789
  const texts = (0, combi_1.altPrio)("COL_BACKGROUND", "COL_HEADING", "COL_NORMAL", "COL_TOTAL", "COL_KEY", "COL_POSITIVE", "COL_NEGATIVE", "COL_GROUP");
3790
3790
  const value = (0, combi_1.alt)(eq, (0, combi_1.altPrio)("ON", "OFF", "COLOR OFF", (0, combi_1.altPrio)(integers, texts)));
@@ -26676,6 +26676,31 @@ class ObjectOriented {
26676
26676
  }
26677
26677
  return ret;
26678
26678
  }
26679
+ // does the supplied class have friendship with "friendName"?
26680
+ // note that interfaces of the friend, and subclasses of the friend also have friendship
26681
+ hasFriendship(cd, friendName) {
26682
+ var _a;
26683
+ const friends = cd.getFriends().map(f => f.toUpperCase());
26684
+ const isFriend = (name) => friends.includes(name.toUpperCase()) || this.scope.isLocalFriend(cd.getName(), name);
26685
+ if (isFriend(friendName)) {
26686
+ return true;
26687
+ }
26688
+ const friendDefinition = this.scope.findClassDefinition(friendName);
26689
+ if (friendDefinition === undefined) {
26690
+ return false;
26691
+ }
26692
+ if (this.findInterfaces(friendDefinition).some(i => friends.includes(i.name.toUpperCase()))) {
26693
+ return true;
26694
+ }
26695
+ let sup = friendDefinition.getSuperClass();
26696
+ while (sup !== undefined) {
26697
+ if (isFriend(sup)) {
26698
+ return true;
26699
+ }
26700
+ sup = (_a = this.scope.findClassDefinition(sup)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
26701
+ }
26702
+ return false;
26703
+ }
26679
26704
  searchEvent(def, name) {
26680
26705
  if (def === undefined || name === undefined) {
26681
26706
  return undefined;
@@ -27865,6 +27890,9 @@ class TypeUtils {
27865
27890
  console.dir(source);
27866
27891
  console.dir(target);
27867
27892
  */
27893
+ if (source instanceof basic_1.UTCLongType || target instanceof basic_1.UTCLongType) {
27894
+ return this.isUTCLongAssignable(source, target);
27895
+ }
27868
27896
  if (target instanceof basic_1.TableType) {
27869
27897
  if (target.isWithHeader()) {
27870
27898
  return this.isAssignable(source, target.getRowType());
@@ -28016,6 +28044,33 @@ class TypeUtils {
28016
28044
  }
28017
28045
  return true;
28018
28046
  }
28047
+ // utclong can only be converted to and from character like types
28048
+ isUTCLongAssignable(source, target) {
28049
+ if (this.isGenericOrVoid(source) || this.isGenericOrVoid(target)) {
28050
+ return true;
28051
+ }
28052
+ else if (source instanceof basic_1.UTCLongType && target instanceof basic_1.UTCLongType) {
28053
+ return true;
28054
+ }
28055
+ else if (source instanceof basic_1.UTCLongType) {
28056
+ return this.isTextLike(target);
28057
+ }
28058
+ return this.isTextLike(source);
28059
+ }
28060
+ isGenericOrVoid(type) {
28061
+ return type instanceof basic_1.VoidType
28062
+ || type instanceof basic_1.AnyType
28063
+ || type instanceof basic_1.DataType
28064
+ || type instanceof basic_1.UnknownType;
28065
+ }
28066
+ isTextLike(type) {
28067
+ return type instanceof basic_1.CharacterType
28068
+ || type instanceof basic_1.StringType
28069
+ || type instanceof basic_1.CLikeType
28070
+ || type instanceof basic_1.CSequenceType
28071
+ || type instanceof cgeneric_type_1.CGenericType
28072
+ || type instanceof basic_1.SimpleType;
28073
+ }
28019
28074
  }
28020
28075
  exports.TypeUtils = TypeUtils;
28021
28076
  //# sourceMappingURL=_type_utils.js.map
@@ -28098,6 +28153,7 @@ const types_1 = __webpack_require__(/*! ../types */ "../core/build/src/abap/type
28098
28153
  const expressions_1 = __webpack_require__(/*! ../2_statements/expressions */ "../core/build/src/abap/2_statements/expressions/index.js");
28099
28154
  const _builtin_1 = __webpack_require__(/*! ./_builtin */ "../core/build/src/abap/5_syntax/_builtin.js");
28100
28155
  const position_1 = __webpack_require__(/*! ../../position */ "../core/build/src/position.js");
28156
+ const _syntax_input_1 = __webpack_require__(/*! ./_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
28101
28157
  class BasicTypes {
28102
28158
  constructor(input) {
28103
28159
  this.input = input;
@@ -29038,6 +29094,13 @@ class BasicTypes {
29038
29094
  }
29039
29095
  const chain = val.findFirstExpression(Expressions.SimpleFieldChain);
29040
29096
  if (chain) {
29097
+ // todo, hardcoded for now, should be a generic check that the chain is a constant
29098
+ const concat = chain.concatTokens().toUpperCase();
29099
+ if (concat === "SY-DATUM" || concat === "SY-UZEIT") {
29100
+ const message = "VALUE, " + concat.toLowerCase() + " is not a constant";
29101
+ this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, chain.getFirstToken(), message));
29102
+ return undefined;
29103
+ }
29041
29104
  return this.resolveConstantValue(chain);
29042
29105
  }
29043
29106
  throw new Error("findValue, unexpected");
@@ -32311,6 +32374,8 @@ const _reference_1 = __webpack_require__(/*! ../_reference */ "../core/build/src
32311
32374
  const component_name_1 = __webpack_require__(/*! ./component_name */ "../core/build/src/abap/5_syntax/expressions/component_name.js");
32312
32375
  const attribute_name_1 = __webpack_require__(/*! ./attribute_name */ "../core/build/src/abap/5_syntax/expressions/attribute_name.js");
32313
32376
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
32377
+ const visibility_1 = __webpack_require__(/*! ../../4_file_information/visibility */ "../core/build/src/abap/4_file_information/visibility.js");
32378
+ const class_definition_1 = __webpack_require__(/*! ../../types/class_definition */ "../core/build/src/abap/types/class_definition.js");
32314
32379
  class MethodCallChain {
32315
32380
  static runSyntax(node, input, targetType) {
32316
32381
  var _a, _b;
@@ -32359,6 +32424,12 @@ class MethodCallChain {
32359
32424
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, methodToken, message));
32360
32425
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
32361
32426
  }
32427
+ const notVisible = method ? this.checkVisibility(method, def, foundDef, input) : undefined;
32428
+ if (notVisible !== undefined) {
32429
+ const message = `Method "${methodName}" is ${notVisible} and cannot be accessed`;
32430
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, methodToken, message));
32431
+ return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
32432
+ }
32362
32433
  const voidedName = context instanceof basic_1.VoidType ? context.getVoided() : undefined;
32363
32434
  const extra = helper.methodReferenceExtras(foundDef, className || voidedName);
32364
32435
  input.scope.addReference(methodToken, method, _reference_1.ReferenceType.MethodReference, input.filename, extra);
@@ -32401,6 +32472,47 @@ class MethodCallChain {
32401
32472
  return context;
32402
32473
  }
32403
32474
  //////////////////////////////////////
32475
+ // returns the visibility as text if the method cannot be accessed from the current scope
32476
+ static checkVisibility(method, def, foundDef, input) {
32477
+ var _a, _b, _c;
32478
+ const visibility = method.getVisibility();
32479
+ if (visibility === visibility_1.Visibility.Public || foundDef === undefined) {
32480
+ return undefined;
32481
+ }
32482
+ else if (!(foundDef instanceof class_definition_1.ClassDefinition)) {
32483
+ // interface members are always public
32484
+ return undefined;
32485
+ }
32486
+ const name = foundDef.getName().toUpperCase();
32487
+ const enclosing = (_a = input.scope.getEnclosingClassName()) === null || _a === void 0 ? void 0 : _a.toUpperCase();
32488
+ if (enclosing === undefined || enclosing === name) {
32489
+ return undefined;
32490
+ }
32491
+ // friendship with the class used at the call site also gives access to inherited members
32492
+ const helper = new _object_oriented_1.ObjectOriented(input.scope);
32493
+ const visited = [];
32494
+ let current = def instanceof class_definition_1.ClassDefinition ? def : foundDef;
32495
+ while (current !== undefined && visited.includes(current.getName().toUpperCase()) === false) {
32496
+ visited.push(current.getName().toUpperCase());
32497
+ if (helper.hasFriendship(current, enclosing)) {
32498
+ return undefined;
32499
+ }
32500
+ const sup = current.getSuperClass();
32501
+ current = sup === undefined ? undefined : input.scope.findClassDefinition(sup);
32502
+ }
32503
+ if (visibility === visibility_1.Visibility.Protected) {
32504
+ // subclasses can access protected members
32505
+ let sup = (_b = input.scope.findClassDefinition(enclosing)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
32506
+ while (sup !== undefined) {
32507
+ if (sup.toUpperCase() === name) {
32508
+ return undefined;
32509
+ }
32510
+ sup = (_c = input.scope.findClassDefinition(sup)) === null || _c === void 0 ? void 0 : _c.getSuperClass();
32511
+ }
32512
+ return "protected";
32513
+ }
32514
+ return "private";
32515
+ }
32404
32516
  static findTop(first, input, targetType) {
32405
32517
  var _a;
32406
32518
  if (first.get() instanceof Expressions.ClassName) {
@@ -35069,6 +35181,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/
35069
35181
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
35070
35182
  const sql_set_op_group_1 = __webpack_require__(/*! ./sql_set_op_group */ "../core/build/src/abap/5_syntax/expressions/sql_set_op_group.js");
35071
35183
  const sql_source_1 = __webpack_require__(/*! ./sql_source */ "../core/build/src/abap/5_syntax/expressions/sql_source.js");
35184
+ const RANGE_COMPONENTS = ["SIGN", "OPTION", "LOW", "HIGH"];
35072
35185
  class SQLIn {
35073
35186
  static runSyntax(node, input) {
35074
35187
  const setop = node.findDirectExpression(Expressions.SQLSetOpGroup);
@@ -35088,6 +35201,12 @@ class SQLIn {
35088
35201
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
35089
35202
  return;
35090
35203
  }
35204
+ if (intype instanceof basic_1.TableType && this.isRangeRow(intype.getRowType()) === false) {
35205
+ const name = insource.concatTokens().replace(/^@/, "").replace(/\[\]$/, "");
35206
+ const message = `row structure of ${name} is not correct`;
35207
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
35208
+ return;
35209
+ }
35091
35210
  }
35092
35211
  return;
35093
35212
  }
@@ -35098,6 +35217,16 @@ class SQLIn {
35098
35217
  sql_source_1.SQLSource.runSyntax(s, input);
35099
35218
  }
35100
35219
  }
35220
+ // "IN itab" expects a ranges table, ie. the row must have SIGN, OPTION, LOW and HIGH
35221
+ static isRangeRow(rowType) {
35222
+ if (rowType instanceof basic_1.VoidType || rowType instanceof basic_1.UnknownType || rowType instanceof basic_1.AnyType) {
35223
+ return true;
35224
+ }
35225
+ else if (!(rowType instanceof basic_1.StructureType)) {
35226
+ return false;
35227
+ }
35228
+ return RANGE_COMPONENTS.every(c => rowType.getComponentByName(c) !== undefined);
35229
+ }
35101
35230
  }
35102
35231
  exports.SQLIn = SQLIn;
35103
35232
  //# sourceMappingURL=sql_in.js.map
@@ -39176,7 +39305,7 @@ class CreateObject {
39176
39305
  this.validateParameters(cdef, node, input);
39177
39306
  }
39178
39307
  static checkInstantiationAllowed(cdef, input) {
39179
- var _a, _b, _c;
39308
+ var _a, _b;
39180
39309
  const createVis = cdef.getCreateVisibility();
39181
39310
  if (createVis === visibility_1.Visibility.Public) {
39182
39311
  return undefined;
@@ -39189,34 +39318,17 @@ class CreateObject {
39189
39318
  if (enclosingClass.toUpperCase() === cdef.getName().toUpperCase()) {
39190
39319
  return undefined;
39191
39320
  }
39192
- if (cdef.getFriends().some(f => f.toUpperCase() === enclosingClass.toUpperCase()) ||
39193
- input.scope.isLocalFriend(cdef.getName(), enclosingClass)) {
39321
+ if (new _object_oriented_1.ObjectOriented(input.scope).hasFriendship(cdef, enclosingClass)) {
39194
39322
  return undefined;
39195
39323
  }
39196
- const enclosingDefinition = input.scope.findClassDefinition(enclosingClass);
39197
- if (enclosingDefinition !== undefined) {
39198
- const implementedInterfaces = new _object_oriented_1.ObjectOriented(input.scope).findInterfaces(enclosingDefinition);
39199
- if (cdef.getFriends().some(friend => implementedInterfaces.some(implemented => implemented.name.toUpperCase() === friend.toUpperCase()))) {
39200
- return undefined;
39201
- }
39202
- }
39203
- // subclasses of friends also have friendship
39204
- let enclosingSup = enclosingDefinition === null || enclosingDefinition === void 0 ? void 0 : enclosingDefinition.getSuperClass();
39205
- while (enclosingSup !== undefined) {
39206
- if (cdef.getFriends().some(f => f.toUpperCase() === enclosingSup.toUpperCase()) ||
39207
- input.scope.isLocalFriend(cdef.getName(), enclosingSup)) {
39208
- return undefined;
39209
- }
39210
- enclosingSup = (_a = input.scope.findClassDefinition(enclosingSup)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
39211
- }
39212
39324
  if (createVis === visibility_1.Visibility.Protected) {
39213
39325
  // subclasses are also allowed
39214
- let sup = (_b = input.scope.findClassDefinition(enclosingClass)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
39326
+ let sup = (_a = input.scope.findClassDefinition(enclosingClass)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
39215
39327
  while (sup !== undefined) {
39216
39328
  if (sup.toUpperCase() === cdef.getName().toUpperCase()) {
39217
39329
  return undefined;
39218
39330
  }
39219
- sup = (_c = input.scope.findClassDefinition(sup)) === null || _c === void 0 ? void 0 : _c.getSuperClass();
39331
+ sup = (_b = input.scope.findClassDefinition(sup)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
39220
39332
  }
39221
39333
  }
39222
39334
  return cdef.getName() + " cannot be instantiated, class is defined as " +
@@ -39480,6 +39592,7 @@ const source_1 = __webpack_require__(/*! ../expressions/source */ "../core/build
39480
39592
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/build/src/abap/5_syntax/expressions/dynamic.js");
39481
39593
  const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "../core/build/src/abap/5_syntax/expressions/database_table.js");
39482
39594
  const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "../core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
39595
+ const sql_in_1 = __webpack_require__(/*! ../expressions/sql_in */ "../core/build/src/abap/5_syntax/expressions/sql_in.js");
39483
39596
  class DeleteDatabase {
39484
39597
  runSyntax(node, input) {
39485
39598
  for (const s of node.findAllExpressions(Expressions.Source)) {
@@ -39491,6 +39604,12 @@ class DeleteDatabase {
39491
39604
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
39492
39605
  dynamic_1.Dynamic.runSyntax(d, input);
39493
39606
  }
39607
+ for (const compare of node.findAllExpressions(Expressions.SQLCompare)) {
39608
+ const sqlin = compare.findDirectExpression(Expressions.SQLIn);
39609
+ if (sqlin !== undefined) {
39610
+ sql_in_1.SQLIn.runSyntax(sqlin, input);
39611
+ }
39612
+ }
39494
39613
  const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
39495
39614
  if (dbtab !== undefined) {
39496
39615
  const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
@@ -40495,13 +40614,17 @@ const expressions_1 = __webpack_require__(/*! ../../2_statements/expressions */
40495
40614
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
40496
40615
  class Form {
40497
40616
  runSyntax(node, input) {
40498
- var _a;
40499
- const name = (_a = node.findDirectExpression(expressions_1.FormName)) === null || _a === void 0 ? void 0 : _a.concatTokens();
40500
- if (name === undefined) {
40617
+ const nameExpression = node.findDirectExpression(expressions_1.FormName);
40618
+ const name = nameExpression === null || nameExpression === void 0 ? void 0 : nameExpression.concatTokens();
40619
+ if (nameExpression === undefined || name === undefined) {
40501
40620
  const message = "Form, could not find name";
40502
40621
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
40503
40622
  return;
40504
40623
  }
40624
+ if (name.length > 30) {
40625
+ const message = "FORM name longer than 30 characters";
40626
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, nameExpression.getFirstToken(), message));
40627
+ }
40505
40628
  input.scope.push(_scope_type_1.ScopeType.Form, name, node.getFirstToken().getStart(), input.filename);
40506
40629
  const form = new form_definition_1.FormDefinition(node, input);
40507
40630
  input.scope.addList(form.getUsingParameters());
@@ -40561,7 +40684,7 @@ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expr
40561
40684
  const source_1 = __webpack_require__(/*! ../expressions/source */ "../core/build/src/abap/5_syntax/expressions/source.js");
40562
40685
  class Format {
40563
40686
  runSyntax(node, input) {
40564
- for (const s of node.findAllExpressions(Expressions.Source)) {
40687
+ for (const s of node.findAllExpressionsMulti([Expressions.Source, Expressions.SimpleSource3])) {
40565
40688
  source_1.Source.runSyntax(s, input);
40566
40689
  }
40567
40690
  }
@@ -43386,6 +43509,11 @@ class Parameter {
43386
43509
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
43387
43510
  return;
43388
43511
  }
43512
+ if (this.hasUserCommand(node) && this.hasLength(node)) {
43513
+ const message = "USER-COMMAND and LENGTH not possible together";
43514
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
43515
+ return;
43516
+ }
43389
43517
  const bfound = new basic_types_1.BasicTypes(input).parseType(node);
43390
43518
  if (bfound) {
43391
43519
  input.scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, input.filename, bfound));
@@ -43397,6 +43525,30 @@ class Parameter {
43397
43525
  const magicToken = new tokens_1.Identifier(nameToken.getStart(), magicName);
43398
43526
  input.scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(magicToken, input.filename, basic_1.VoidType.get("PARAMETER-MAGIC")));
43399
43527
  }
43528
+ // "USER-COMMAND" is lexed as three tokens
43529
+ hasUserCommand(node) {
43530
+ const tokens = node.getTokens();
43531
+ for (let i = 0; i < tokens.length - 2; i++) {
43532
+ if (tokens[i].getStr().toUpperCase() === "USER"
43533
+ && tokens[i + 1].getStr() === "-"
43534
+ && tokens[i + 2].getStr().toUpperCase() === "COMMAND") {
43535
+ return true;
43536
+ }
43537
+ }
43538
+ return false;
43539
+ }
43540
+ // "VISIBLE LENGTH" is not the same as "LENGTH"
43541
+ hasLength(node) {
43542
+ var _a;
43543
+ const tokens = node.getTokens();
43544
+ for (let i = 0; i < tokens.length; i++) {
43545
+ if (tokens[i].getStr().toUpperCase() === "LENGTH"
43546
+ && ((_a = tokens[i - 1]) === null || _a === void 0 ? void 0 : _a.getStr().toUpperCase()) !== "VISIBLE") {
43547
+ return true;
43548
+ }
43549
+ }
43550
+ return false;
43551
+ }
43400
43552
  }
43401
43553
  exports.Parameter = Parameter;
43402
43554
  //# sourceMappingURL=parameter.js.map
@@ -69851,7 +70003,7 @@ class Registry {
69851
70003
  }
69852
70004
  static abaplintVersion() {
69853
70005
  // magic, see build script "version.js"
69854
- return "2.120.28";
70006
+ return "2.120.30";
69855
70007
  }
69856
70008
  getDDICReferences() {
69857
70009
  return this.ddicReferences;
@@ -72538,6 +72690,11 @@ class CDSCheckSyntaxConf extends _basic_rule_config_1.BasicRuleConfig {
72538
72690
  exports.CDSCheckSyntaxConf = CDSCheckSyntaxConf;
72539
72691
  const KNOWN_QUAN_DATA_ELEMENTS = ["MENGE_D"];
72540
72692
  const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
72693
+ // Reserved names, cannot be used as element names, see DDIC table TRESE
72694
+ const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION"];
72695
+ const MAX_LABEL_LENGTH = 40;
72696
+ // Annotations which are not supported in CDS view entities
72697
+ const VIEW_ENTITY_FORBIDDEN_ANNOTATIONS = ["Semantics.unitOfMeasure"];
72541
72698
  class CDSCheckSyntax {
72542
72699
  constructor() {
72543
72700
  this.conf = new CDSCheckSyntaxConf();
@@ -72579,6 +72736,9 @@ Missing objects are only reported when their names match the configured errorNam
72579
72736
  this.checkTypes(tree, ddic, issues, file);
72580
72737
  this.checkRootProjection(tree, ddic, issues, file);
72581
72738
  this.checkFieldAnnotations(tree, ddic, issues, file);
72739
+ this.checkLabels(tree, issues, file);
72740
+ this.checkViewEntityAnnotations(tree, issues, file);
72741
+ this.checkReservedNames(tree, issues, file);
72582
72742
  this.checkFields(tree, sources, object, issues, file);
72583
72743
  return issues;
72584
72744
  }
@@ -72763,6 +72923,62 @@ Missing objects are only reported when their names match the configured errorNam
72763
72923
  || a.toUpperCase().includes("@SEMANTICS:{CURRENCYCODE:TRUE"));
72764
72924
  }
72765
72925
  }
72926
+ checkLabels(tree, issues, file) {
72927
+ for (const annotation of tree.findAllExpressionsRecursive(expressions_1.CDSAnnotation)) {
72928
+ const concatenated = annotation.concatTokens();
72929
+ if (/@\s*<?\s*EndUserText/i.test(concatenated) === false) {
72930
+ continue;
72931
+ }
72932
+ const expression = /label\s*:\s*'((?:[^']|'')*)'/gi;
72933
+ let match = expression.exec(concatenated);
72934
+ while (match !== null) {
72935
+ const label = match[1].replace(/''/g, "'");
72936
+ if (label.length > MAX_LABEL_LENGTH) {
72937
+ const message = `CDS label is ${label.length} characters, maximum is ${MAX_LABEL_LENGTH}`;
72938
+ issues.push(issue_1.Issue.atToken(file, annotation.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
72939
+ }
72940
+ match = expression.exec(concatenated);
72941
+ }
72942
+ }
72943
+ }
72944
+ checkViewEntityAnnotations(tree, issues, file) {
72945
+ const view = tree.findFirstExpression(expressions_1.CDSDefineView);
72946
+ if (view === undefined || view.findDirectTokenByText("ENTITY") === undefined) {
72947
+ return;
72948
+ }
72949
+ for (const annotation of tree.findAllExpressionsRecursive(expressions_1.CDSAnnotation)) {
72950
+ const normalized = annotation.concatTokens().replace(/\s/g, "").toUpperCase().replace(/^@</, "@");
72951
+ for (const forbidden of VIEW_ENTITY_FORBIDDEN_ANNOTATIONS) {
72952
+ const upper = forbidden.toUpperCase();
72953
+ if (normalized.startsWith("@" + upper) === false
72954
+ && normalized.startsWith("@" + upper.replace(".", ":{")) === false) {
72955
+ continue;
72956
+ }
72957
+ const message = `Annotation ${forbidden} is not allowed in view entities`;
72958
+ issues.push(issue_1.Issue.atToken(file, annotation.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
72959
+ }
72960
+ }
72961
+ }
72962
+ checkReservedNames(tree, issues, file) {
72963
+ var _a, _b;
72964
+ for (const element of tree.findAllExpressionsRecursive(expressions_1.CDSElement)) {
72965
+ if (element.findDirectTokenByText("INCLUDE") !== undefined) {
72966
+ continue;
72967
+ }
72968
+ let nameNode = (_a = element.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
72969
+ if (nameNode === undefined) {
72970
+ const names = ((_b = element.findDirectExpression(expressions_1.CDSPrefixedName)) === null || _b === void 0 ? void 0 : _b.findDirectExpressions(expressions_1.CDSName)) || [];
72971
+ nameNode = names[names.length - 1];
72972
+ }
72973
+ if (nameNode === undefined) {
72974
+ continue;
72975
+ }
72976
+ const name = this.name(nameNode);
72977
+ if (RESERVED_ELEMENT_NAMES.includes(name.toUpperCase())) {
72978
+ issues.push(issue_1.Issue.atToken(file, nameNode.getFirstToken(), `CDS element name "${name}" is reserved`, this.getMetadata().key, this.conf.severity));
72979
+ }
72980
+ }
72981
+ }
72766
72982
  checkFields(tree, sources, object, issues, file) {
72767
72983
  var _a;
72768
72984
  const associationNames = new Set();
@@ -75226,6 +75442,7 @@ class CloudTypes {
75226
75442
  || obj instanceof Objects.BehaviorDefinition
75227
75443
  || obj instanceof Objects.BusinessCatalog
75228
75444
  || obj instanceof Objects.BusinessCatalogAppAssignment
75445
+ || obj instanceof Objects.BusinessConfigurationMaintenanceObject
75229
75446
  || obj instanceof Objects.CDSMetadataExtension
75230
75447
  || obj instanceof Objects.Class
75231
75448
  || obj instanceof Objects.CDSType
@@ -75242,11 +75459,13 @@ class CloudTypes {
75242
75459
  || obj instanceof Objects.EventBinding
75243
75460
  || obj instanceof Objects.EventConsumer
75244
75461
  || obj instanceof Objects.FunctionGroup
75462
+ || obj instanceof Objects.GatewayODataGroupAndAssignment
75245
75463
  || obj instanceof Objects.HttpService
75246
75464
  || obj instanceof Objects.IAMApp
75247
75465
  || obj instanceof Objects.InboundService
75248
75466
  || obj instanceof Objects.Interface
75249
75467
  || obj instanceof Objects.LockObject
75468
+ || obj instanceof Objects.MaintenanceAndTransportObject
75250
75469
  || obj instanceof Objects.MessageClass
75251
75470
  || obj instanceof Objects.NumberRange
75252
75471
  || obj instanceof Objects.OutboundService
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/cli",
3
- "version": "2.120.28",
3
+ "version": "2.120.30",
4
4
  "description": "abaplint - Command Line Interface",
5
5
  "funding": "https://github.com/sponsors/larshp",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "homepage": "https://abaplint.org",
41
41
  "devDependencies": {
42
- "@abaplint/core": "^2.120.28",
42
+ "@abaplint/core": "^2.120.30",
43
43
  "@types/chai": "^4.3.20",
44
44
  "@types/minimist": "^1.2.5",
45
45
  "@types/mocha": "^10.0.10",