@abaplint/cli 2.120.50 → 2.120.52

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 +223 -13
  2. package/package.json +2 -2
package/build/cli.js CHANGED
@@ -53,6 +53,13 @@ const BUFS = new Set([
53
53
  CH_DOT, CH_COMMA, CH_COLON, 40 /* ( */, 41 /* ) */, 91 /* [ */,
54
54
  93 /* ] */, 43 /* + */, CH_AT
55
55
  ]);
56
+ // characters that may follow the closing "'", "`" or "|" of a literal, anything else
57
+ // is a syntax error, "There must be a space or equivalent character after ...",
58
+ // note that "(" is allowed, ie. text elements like 'text'(001)
59
+ const AFTER_LITERAL = new Set([
60
+ EOF, CH_SPACE, CH_TAB, CH_NL, CH_DOT, CH_COMMA, CH_COLON, CH_DQUOTE,
61
+ 40 /* ( */, 41 /* ) */, 91 /* [ */, 93 /* ] */
62
+ ]);
56
63
  class Lexer {
57
64
  run(file, virtual) {
58
65
  this.virtual = virtual;
@@ -332,7 +339,11 @@ class Lexer {
332
339
  && ahead !== CH_BACKTICK
333
340
  && this.buffer.countIsEven(CH_BACKTICK)) {
334
341
  // end of ping
335
- this.add();
342
+ if (AFTER_LITERAL.has(ahead)) {
343
+ this.add();
344
+ }
345
+ // else: no separator after the literal, keep the buffer so the following
346
+ // characters are glued onto the token, the parser will report the error
336
347
  if (ahead === CH_DQUOTE) {
337
348
  this.m = ModeComment;
338
349
  }
@@ -345,7 +356,9 @@ class Lexer {
345
356
  && (current === CH_PIPE || current === CH_LBRACE)
346
357
  && (stream.prevChar() !== CH_BACKSLASH || (stream.prevPrevChar() === CH_BACKSLASH && stream.prevChar() === CH_BACKSLASH))) {
347
358
  // end of template
348
- this.add();
359
+ if (current === CH_LBRACE || AFTER_LITERAL.has(ahead)) {
360
+ this.add();
361
+ }
349
362
  this.m = ModeNormal;
350
363
  }
351
364
  else if (this.m === ModeTemplate
@@ -360,7 +373,9 @@ class Lexer {
360
373
  && ahead !== CH_QUOTE
361
374
  && this.buffer.countIsEven(CH_QUOTE)) {
362
375
  // end of string
363
- this.add();
376
+ if (AFTER_LITERAL.has(ahead)) {
377
+ this.add();
378
+ }
364
379
  if (ahead === CH_DQUOTE) {
365
380
  this.m = ModeComment;
366
381
  }
@@ -27714,6 +27729,20 @@ class TypeUtils {
27714
27729
  || node.findFirstExpression(Expressions.ArithOperator) !== undefined;
27715
27730
  return calculated;
27716
27731
  }
27732
+ // a character constant is only assignable to a hexadecimal target if it can be
27733
+ // interpreted as a hexadecimal value
27734
+ isHexConstant(node) {
27735
+ const constant = node === null || node === void 0 ? void 0 : node.concatTokens();
27736
+ if (constant === undefined) {
27737
+ return true;
27738
+ }
27739
+ if ((constant.startsWith("'") && constant.endsWith("'"))
27740
+ || (constant.startsWith("`") && constant.endsWith("`"))) {
27741
+ const value = constant.substring(1, constant.length - 1);
27742
+ return value.length > 0 && /^[0-9A-Fa-f]+$/.test(value);
27743
+ }
27744
+ return true;
27745
+ }
27717
27746
  isAssignableNew(source, target, node) {
27718
27747
  const calculated = (node === null || node === void 0 ? void 0 : node.findFirstExpression(Expressions.ArithOperator)) !== undefined;
27719
27748
  if (calculated && source instanceof basic_1.HexType && target instanceof basic_1.IntegerType) {
@@ -27779,7 +27808,7 @@ class TypeUtils {
27779
27808
  }
27780
27809
  else if (target instanceof basic_1.XStringType) {
27781
27810
  if (((_d = source.getAbstractTypeData()) === null || _d === void 0 ? void 0 : _d.derivedFromConstant) === true) {
27782
- return (node === null || node === void 0 ? void 0 : node.concatTokens()) !== "''";
27811
+ return this.isHexConstant(node);
27783
27812
  }
27784
27813
  return false;
27785
27814
  }
@@ -34711,6 +34740,7 @@ class Source {
34711
34740
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
34712
34741
  }
34713
34742
  this.addIfInferred(node, input, foundType);
34743
+ this.traverseRemainingChildren(children, input);
34714
34744
  return foundType;
34715
34745
  }
34716
34746
  case "REF":
@@ -70549,7 +70579,7 @@ class Registry {
70549
70579
  }
70550
70580
  static abaplintVersion() {
70551
70581
  // magic, see build script "version.js"
70552
- return "2.120.50";
70582
+ return "2.120.52";
70553
70583
  }
70554
70584
  getDDICReferences() {
70555
70585
  return this.ddicReferences;
@@ -78686,15 +78716,19 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
78686
78716
  continue;
78687
78717
  }
78688
78718
  const condition = this.tableCondition(tableExpression);
78689
- const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
78719
+ // ASSIGNING, not INTO: from v740 a table expression in a read position addresses the
78720
+ // row rather than copying it, so "REF #( tab[ i ]-comp )" and "ASSIGN tab[ i ]-comp"
78721
+ // hand back an address INTO a work area would not preserve. The write path
78722
+ // (moveWithTableTarget) already lowers to ASSIGNING for the same reason.
78723
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
78690
78724
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
78691
78725
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
78692
78726
  const firstToken = high.getFirstToken();
78693
78727
  // note that the tabix restore should be done before throwing the exception
78694
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
78728
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${pre}.
78695
78729
  ${indentation}DATA ${tabixBackup} LIKE sy-tabix.
78696
78730
  ${indentation}${tabixBackup} = sy-tabix.
78697
- ${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
78731
+ ${indentation}READ TABLE ${pre} ${condition}ASSIGNING ${uniqueName}.
78698
78732
  ${indentation}sy-tabix = ${tabixBackup}.
78699
78733
  ${indentation}IF sy-subrc <> 0.
78700
78734
  ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
@@ -79448,8 +79482,7 @@ CONSTANTS: BEGIN OF ${structureName},\n`;
79448
79482
  if (index === undefined) {
79449
79483
  return undefined;
79450
79484
  }
79451
- let uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79452
- uniqueName = `<${uniqueName}>`;
79485
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
79453
79486
  const tName = target.concatTokens().split("[")[0];
79454
79487
  const condition = this.tableCondition(tableExpression);
79455
79488
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
@@ -80461,12 +80494,16 @@ ${indentation} output = ${uniqueName}.\n`;
80461
80494
  }
80462
80495
  return undefined;
80463
80496
  }
80464
- uniqueName(position, filename, highSyntax) {
80497
+ /** a FIELD-SYMBOLS declaration is known to the scope under its bracketed spelling, so
80498
+ * the collision check has to use that spelling too - otherwise a second outline in the
80499
+ * same method is handed a name that is already taken and the result does not compile */
80500
+ uniqueName(position, filename, highSyntax, fieldSymbol = false) {
80501
+ const decorate = (name) => fieldSymbol === true ? `<${name}>` : name;
80465
80502
  const spag = highSyntax.spaghetti.lookupPosition(position, filename);
80466
80503
  if (spag === undefined) {
80467
80504
  const name = "temprr" + this.counter;
80468
80505
  this.counter++;
80469
- return name;
80506
+ return decorate(name);
80470
80507
  }
80471
80508
  let postfix = "";
80472
80509
  if (spag.getIdentifier().stype === _scope_type_1.ScopeType.ClassDefinition) {
@@ -80475,7 +80512,7 @@ ${indentation} output = ${uniqueName}.\n`;
80475
80512
  postfix = "_" + hash.substring(0, 10);
80476
80513
  }
80477
80514
  while (true) {
80478
- const name = "temp" + this.counter + postfix;
80515
+ const name = decorate("temp" + this.counter + postfix);
80479
80516
  const exists = this.existsRecursive(spag, name);
80480
80517
  this.counter++;
80481
80518
  if (exists === false) {
@@ -84957,6 +84994,7 @@ __exportStar(__webpack_require__(/*! ./use_line_exists */ "../core/build/src/rul
84957
84994
  __exportStar(__webpack_require__(/*! ./use_new */ "../core/build/src/rules/use_new.js"), exports);
84958
84995
  __exportStar(__webpack_require__(/*! ./when_others_last */ "../core/build/src/rules/when_others_last.js"), exports);
84959
84996
  __exportStar(__webpack_require__(/*! ./whitespace_end */ "../core/build/src/rules/whitespace_end.js"), exports);
84997
+ __exportStar(__webpack_require__(/*! ./wrong_abapdoc_position */ "../core/build/src/rules/wrong_abapdoc_position.js"), exports);
84960
84998
  __exportStar(__webpack_require__(/*! ./xml_consistency */ "../core/build/src/rules/xml_consistency.js"), exports);
84961
84999
  __exportStar(__webpack_require__(/*! ./no_exclamation_escape */ "../core/build/src/rules/no_exclamation_escape.js"), exports);
84962
85000
  __exportStar(__webpack_require__(/*! ./xml_bom */ "../core/build/src/rules/xml_bom.js"), exports);
@@ -100439,6 +100477,178 @@ exports.WhitespaceEnd = WhitespaceEnd;
100439
100477
 
100440
100478
  /***/ },
100441
100479
 
100480
+ /***/ "../core/build/src/rules/wrong_abapdoc_position.js"
100481
+ /*!*********************************************************!*\
100482
+ !*** ../core/build/src/rules/wrong_abapdoc_position.js ***!
100483
+ \*********************************************************/
100484
+ (__unused_webpack_module, exports, __webpack_require__) {
100485
+
100486
+ "use strict";
100487
+
100488
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
100489
+ if (k2 === undefined) k2 = k;
100490
+ var desc = Object.getOwnPropertyDescriptor(m, k);
100491
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
100492
+ desc = { enumerable: true, get: function() { return m[k]; } };
100493
+ }
100494
+ Object.defineProperty(o, k2, desc);
100495
+ }) : (function(o, m, k, k2) {
100496
+ if (k2 === undefined) k2 = k;
100497
+ o[k2] = m[k];
100498
+ }));
100499
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
100500
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
100501
+ }) : function(o, v) {
100502
+ o["default"] = v;
100503
+ });
100504
+ var __importStar = (this && this.__importStar) || (function () {
100505
+ var ownKeys = function(o) {
100506
+ ownKeys = Object.getOwnPropertyNames || function (o) {
100507
+ var ar = [];
100508
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
100509
+ return ar;
100510
+ };
100511
+ return ownKeys(o);
100512
+ };
100513
+ return function (mod) {
100514
+ if (mod && mod.__esModule) return mod;
100515
+ var result = {};
100516
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
100517
+ __setModuleDefault(result, mod);
100518
+ return result;
100519
+ };
100520
+ })();
100521
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
100522
+ exports.WrongAbapdocPosition = exports.WrongAbapdocPositionConf = void 0;
100523
+ const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "../core/build/src/abap/2_statements/statements/index.js"));
100524
+ const issue_1 = __webpack_require__(/*! ../issue */ "../core/build/src/issue.js");
100525
+ const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "../core/build/src/rules/_abap_rule.js");
100526
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "../core/build/src/rules/_basic_rule_config.js");
100527
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "../core/build/src/rules/_irule.js");
100528
+ const _statement_1 = __webpack_require__(/*! ../abap/2_statements/statements/_statement */ "../core/build/src/abap/2_statements/statements/_statement.js");
100529
+ class WrongAbapdocPositionConf extends _basic_rule_config_1.BasicRuleConfig {
100530
+ }
100531
+ exports.WrongAbapdocPositionConf = WrongAbapdocPositionConf;
100532
+ class WrongAbapdocPosition extends _abap_rule_1.ABAPRule {
100533
+ constructor() {
100534
+ super(...arguments);
100535
+ this.conf = new WrongAbapdocPositionConf();
100536
+ }
100537
+ getMetadata() {
100538
+ return {
100539
+ key: "wrong_abapdoc_position",
100540
+ title: "Wrong ABAP Doc position",
100541
+ shortDescription: `ABAP Doc must be placed directly in front of the declaration it documents.`,
100542
+ extendedInformation: `ABAP Doc documents the single declaration following it, an ABAP Doc block placed
100543
+ elsewhere is silently ignored, leaving the declaration undocumented.
100544
+
100545
+ The following positions are reported,
100546
+ * in front of a chained keyword, ie. before "CONSTANTS:" instead of after the colon,
100547
+ * in the middle of a statement, ie. between the parameters of a METHODS definition,
100548
+ * directly in front of ENDCLASS, ENDINTERFACE or a SECTION statement.
100549
+
100550
+ Only checks ABAP Doc inside class definitions and interfaces.`,
100551
+ tags: [_irule_1.RuleTag.SingleFile],
100552
+ badExample: `CLASS zcl_foo DEFINITION PUBLIC.
100553
+ PUBLIC SECTION.
100554
+ "! Navigation modes
100555
+ CONSTANTS:
100556
+ BEGIN OF cs_nav_mode,
100557
+ back TYPE i VALUE 1,
100558
+ END OF cs_nav_mode.
100559
+ ENDCLASS.`,
100560
+ goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
100561
+ PUBLIC SECTION.
100562
+ CONSTANTS:
100563
+ "! Navigation modes
100564
+ BEGIN OF cs_nav_mode,
100565
+ back TYPE i VALUE 1,
100566
+ END OF cs_nav_mode.
100567
+ ENDCLASS.`,
100568
+ };
100569
+ }
100570
+ getConfig() {
100571
+ return this.conf;
100572
+ }
100573
+ setConfig(conf) {
100574
+ this.conf = conf;
100575
+ }
100576
+ runParsed(file) {
100577
+ const issues = [];
100578
+ const statements = file.getStatements();
100579
+ let definition = false;
100580
+ for (let i = 0; i < statements.length; i++) {
100581
+ const statement = statements[i];
100582
+ const type = statement.get();
100583
+ if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
100584
+ definition = true;
100585
+ continue;
100586
+ }
100587
+ else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
100588
+ definition = false;
100589
+ continue;
100590
+ }
100591
+ else if (definition === false || this.isAbapdoc(statement) === false) {
100592
+ continue;
100593
+ }
100594
+ else if (this.isAbapdoc(statements[i - 1]) === true
100595
+ && statements[i - 1].getStart().getRow() + 1 === statement.getStart().getRow()) {
100596
+ continue; // only report the first row of each block
100597
+ }
100598
+ let next = undefined;
100599
+ for (let j = i + 1; j < statements.length; j++) {
100600
+ if (statements[j].get() instanceof _statement_1.Comment) {
100601
+ continue;
100602
+ }
100603
+ next = statements[j];
100604
+ break;
100605
+ }
100606
+ if (next === undefined) {
100607
+ continue;
100608
+ }
100609
+ const message = this.check(statement, next);
100610
+ if (message !== undefined) {
100611
+ issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
100612
+ }
100613
+ }
100614
+ return issues;
100615
+ }
100616
+ isAbapdoc(statement) {
100617
+ return (statement === null || statement === void 0 ? void 0 : statement.get()) instanceof _statement_1.Comment
100618
+ && statement.getFirstToken().getStr().startsWith(`"!`);
100619
+ }
100620
+ check(abapdoc, next) {
100621
+ const type = next.get();
100622
+ if (type instanceof Statements.EndClass
100623
+ || type instanceof Statements.EndInterface
100624
+ || type instanceof Statements.Public
100625
+ || type instanceof Statements.Protected
100626
+ || type instanceof Statements.Private) {
100627
+ return "ABAP Doc does not document anything, move or delete it";
100628
+ }
100629
+ const position = abapdoc.getStart();
100630
+ const colon = next.getColon();
100631
+ if (colon === undefined) {
100632
+ if (position.isAfter(next.getStart()) === true) {
100633
+ return "ABAP Doc inside statement, move it in front of the statement";
100634
+ }
100635
+ return undefined;
100636
+ }
100637
+ if (position.isBefore(colon.getStart()) === true) {
100638
+ return "ABAP Doc in front of chained statement, move it after the colon";
100639
+ }
100640
+ const member = next.getTokens().find(t => t.getStart().isAfter(colon.getStart()));
100641
+ if (member !== undefined && position.isAfter(member.getStart()) === true) {
100642
+ return "ABAP Doc inside statement, move it in front of the chained declaration";
100643
+ }
100644
+ return undefined;
100645
+ }
100646
+ }
100647
+ exports.WrongAbapdocPosition = WrongAbapdocPosition;
100648
+ //# sourceMappingURL=wrong_abapdoc_position.js.map
100649
+
100650
+ /***/ },
100651
+
100442
100652
  /***/ "../core/build/src/rules/xml_bom.js"
100443
100653
  /*!******************************************!*\
100444
100654
  !*** ../core/build/src/rules/xml_bom.js ***!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/cli",
3
- "version": "2.120.50",
3
+ "version": "2.120.52",
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.50",
42
+ "@abaplint/core": "^2.120.52",
43
43
  "@types/chai": "^4.3.20",
44
44
  "@types/minimist": "^1.2.5",
45
45
  "@types/mocha": "^10.0.10",