@abaplint/core 2.85.43 → 2.85.46

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.
@@ -7,6 +7,33 @@ class TypeUtils {
7
7
  constructor(scope) {
8
8
  this.scope = scope;
9
9
  }
10
+ isCharLikeStrict(type) {
11
+ if (type === undefined) {
12
+ return false;
13
+ }
14
+ else if (type instanceof basic_1.StructureType) {
15
+ for (const c of type.getComponents()) {
16
+ if (this.isCharLikeStrict(c.type) === false) {
17
+ return false;
18
+ }
19
+ }
20
+ return true;
21
+ }
22
+ else if (type instanceof basic_1.StringType
23
+ || type instanceof basic_1.AnyType
24
+ || type instanceof basic_1.CharacterType
25
+ || type instanceof basic_1.CLikeType
26
+ || type instanceof basic_1.DateType
27
+ || type instanceof basic_1.CSequenceType
28
+ || type instanceof basic_1.NumericGenericType
29
+ || type instanceof basic_1.NumericType
30
+ || type instanceof basic_1.TimeType
31
+ || type instanceof basic_1.UnknownType
32
+ || type instanceof basic_1.VoidType) {
33
+ return true;
34
+ }
35
+ return false;
36
+ }
10
37
  isCharLike(type) {
11
38
  if (type === undefined) {
12
39
  return false;
@@ -6,16 +6,31 @@ const basic_1 = require("../../types/basic");
6
6
  const inline_data_1 = require("../expressions/inline_data");
7
7
  const source_1 = require("../expressions/source");
8
8
  const target_1 = require("../expressions/target");
9
+ const _type_utils_1 = require("../_type_utils");
9
10
  class Split {
10
11
  runSyntax(node, scope, filename) {
11
- const type = node.findTokenSequencePosition("INTO", "TABLE") ? new basic_1.TableType(new basic_1.StringType(), { withHeader: false }) : new basic_1.StringType();
12
+ const intoTable = node.findTokenSequencePosition("INTO", "TABLE") !== undefined;
13
+ const type = intoTable ? new basic_1.TableType(new basic_1.StringType(), { withHeader: false }) : new basic_1.StringType();
12
14
  for (const target of node.findAllExpressions(Expressions.Target)) {
13
15
  const inline = target.findDirectExpression(Expressions.InlineData);
14
16
  if (inline) {
15
17
  new inline_data_1.InlineData().runSyntax(inline, scope, filename, type);
16
18
  }
17
19
  else {
18
- new target_1.Target().runSyntax(target, scope, filename);
20
+ let targetType = new target_1.Target().runSyntax(target, scope, filename);
21
+ if (intoTable) {
22
+ if (!(targetType instanceof basic_1.TableType)
23
+ && !(targetType instanceof basic_1.UnknownType)
24
+ && !(targetType instanceof basic_1.VoidType)) {
25
+ throw new Error("Into must be table typed");
26
+ }
27
+ if (targetType instanceof basic_1.TableType) {
28
+ targetType = targetType.getRowType();
29
+ }
30
+ }
31
+ if (new _type_utils_1.TypeUtils(scope).isCharLikeStrict(targetType) === false) {
32
+ throw new Error("Incompatible, target not character like");
33
+ }
19
34
  }
20
35
  }
21
36
  for (const s of node.findDirectExpressions(Expressions.Source)) {
@@ -68,7 +68,7 @@ class Registry {
68
68
  }
69
69
  static abaplintVersion() {
70
70
  // magic, see build script "version.sh"
71
- return "2.85.43";
71
+ return "2.85.46";
72
72
  }
73
73
  getDDICReferences() {
74
74
  return this.references;
@@ -191,6 +191,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
191
191
  if (found) {
192
192
  return found;
193
193
  }
194
+ found = this.moveWithTableTarget(low, high, lowFile, highSyntax);
195
+ if (found) {
196
+ return found;
197
+ }
194
198
  found = this.downportSelectInline(low, high, lowFile, highSyntax);
195
199
  if (found) {
196
200
  return found;
@@ -259,6 +263,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
259
263
  if (found) {
260
264
  return found;
261
265
  }
266
+ found = this.replaceContains(high, lowFile, highSyntax);
267
+ if (found) {
268
+ return found;
269
+ }
262
270
  found = this.replaceTableExpression(high, lowFile, highSyntax);
263
271
  if (found) {
264
272
  return found;
@@ -704,6 +712,37 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
704
712
  const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);
705
713
  return issue_1.Issue.atToken(lowFile, high.getFirstToken(), "Downport, Reduce statement", this.getMetadata().key, this.conf.severity, fix);
706
714
  }
715
+ moveWithTableTarget(node, high, lowFile, highSyntax) {
716
+ if (!(high.get() instanceof Statements.Move)) {
717
+ return undefined;
718
+ }
719
+ const target = high.findDirectExpression(Expressions.Target);
720
+ if (target === undefined) {
721
+ return undefined;
722
+ }
723
+ const tableExpression = target.findDirectExpression(Expressions.TableExpression);
724
+ if (tableExpression === undefined) {
725
+ return undefined;
726
+ }
727
+ const index = tableExpression.findDirectExpression(Expressions.Source);
728
+ if (index === undefined) {
729
+ return undefined;
730
+ }
731
+ let uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
732
+ uniqueName = `<${uniqueName}>`;
733
+ const tName = target.concatTokens().split("[")[0];
734
+ const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
735
+ const code = `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${tName}.
736
+ ${indentation}READ TABLE ${tName} INDEX ${index === null || index === void 0 ? void 0 : index.concatTokens()} ASSIGNING <temp1>.
737
+ ${indentation}IF sy-subrc <> 0.
738
+ ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
739
+ ${indentation}ENDIF.
740
+ ${uniqueName}`;
741
+ const start = target.getFirstToken().getStart();
742
+ const end = target.getLastToken().getEnd();
743
+ const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);
744
+ return issue_1.Issue.atToken(lowFile, high.getFirstToken(), "Downport, Reduce statement", this.getMetadata().key, this.conf.severity, fix);
745
+ }
707
746
  moveWithOperator(high, lowFile) {
708
747
  var _a, _b, _c;
709
748
  if (!(high.get() instanceof Statements.Move)) {
@@ -1034,6 +1073,7 @@ ${indentation} output = ${topTarget}.`;
1034
1073
  let structureName = uniqueName;
1035
1074
  let added = false;
1036
1075
  let data = "";
1076
+ let previous = undefined;
1037
1077
  for (const b of (valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren()) || []) {
1038
1078
  if (b.concatTokens() === "(" && added === false) {
1039
1079
  structureName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
@@ -1053,8 +1093,13 @@ ${indentation} output = ${topTarget}.`;
1053
1093
  body += this.outlineLet(b, indentation, highSyntax, lowFile);
1054
1094
  }
1055
1095
  else if (b.concatTokens() === ")") {
1096
+ if (added === false && (previous === null || previous === void 0 ? void 0 : previous.concatTokens()) === "(") {
1097
+ body += data;
1098
+ added = true;
1099
+ }
1056
1100
  body += indentation + `APPEND ${structureName} TO ${uniqueName}.\n`;
1057
1101
  }
1102
+ previous = b;
1058
1103
  }
1059
1104
  if (forLoop !== undefined) {
1060
1105
  indentation = indentation.substring(2);
@@ -1332,6 +1377,43 @@ ${indentation} output = ${topTarget}.`;
1332
1377
  }
1333
1378
  return undefined;
1334
1379
  }
1380
+ replaceContains(node, lowFile, highSyntax) {
1381
+ const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
1382
+ // only downport if its an single method call condition
1383
+ let found = false;
1384
+ for (const c of node.findAllExpressionsRecursive(Expressions.Compare)) {
1385
+ found = c.findDirectExpression(Expressions.MethodCallChain) !== undefined;
1386
+ if (found === true) {
1387
+ break;
1388
+ }
1389
+ }
1390
+ if (found === false) {
1391
+ return undefined;
1392
+ }
1393
+ for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {
1394
+ if (r.referenceType !== _reference_1.ReferenceType.BuiltinMethodReference) {
1395
+ continue;
1396
+ }
1397
+ const func = r.position.getName().toUpperCase();
1398
+ if (func === "CONTAINS") {
1399
+ const token = r.position.getToken();
1400
+ const expression = this.findMethodCallExpression(node, token);
1401
+ if (expression === undefined) {
1402
+ continue;
1403
+ }
1404
+ const sList = expression.findAllExpressions(Expressions.Source).map(e => e.concatTokens());
1405
+ if (sList.length !== 2) {
1406
+ continue;
1407
+ }
1408
+ const code = sList[0] + " CS " + sList[1];
1409
+ const start = expression.getFirstToken().getStart();
1410
+ const end = expression.getLastToken().getEnd();
1411
+ const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);
1412
+ return issue_1.Issue.atToken(lowFile, token, "Downport contains()", this.getMetadata().key, this.conf.severity, fix);
1413
+ }
1414
+ }
1415
+ return undefined;
1416
+ }
1335
1417
  replaceLineFunctions(node, lowFile, highSyntax) {
1336
1418
  var _a, _b;
1337
1419
  const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
@@ -19,8 +19,10 @@ class MethodOverwritesBuiltIn extends _abap_rule_1.ABAPRule {
19
19
  key: "method_overwrites_builtin",
20
20
  title: "Method name overwrites builtin function",
21
21
  shortDescription: `Checks Method names that overwrite builtin SAP functions`,
22
- extendedInformation: `https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-us/abenbuilt_in_functions_overview.htm`,
23
- tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile],
22
+ extendedInformation: `https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-us/abenbuilt_in_functions_overview.htm
23
+
24
+ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-obscuring-built-in-functions`,
25
+ tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Styleguide],
24
26
  };
25
27
  }
26
28
  getConfig() {
@@ -19,6 +19,7 @@ class PragmaPlacement extends _abap_rule_1.ABAPRule {
19
19
  title: "Pragma Placement",
20
20
  shortDescription: `Place pragmas at end of statements`,
21
21
  tags: [_irule_1.RuleTag.SingleFile],
22
+ extendedInformation: `https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/abenpragma.htm`,
22
23
  badExample: `DATA field ##NO_TEXT TYPE i.`,
23
24
  goodExample: `DATA field TYPE i ##NO_TEXT.`,
24
25
  };
@@ -42,7 +43,7 @@ class PragmaPlacement extends _abap_rule_1.ABAPRule {
42
43
  }
43
44
  if (children[children.length - 2].getLastToken().getStart().isAfter(p.getStart())) {
44
45
  const message = "Place pragma at end of statement";
45
- const issue = issue_1.Issue.atStatement(file, s, message, this.getMetadata().key, this.conf.severity);
46
+ const issue = issue_1.Issue.atToken(file, p, message, this.getMetadata().key, this.conf.severity);
46
47
  issues.push(issue);
47
48
  continue; // max one finding per statement
48
49
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.85.43",
3
+ "version": "2.85.46",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",
@@ -45,21 +45,21 @@
45
45
  },
46
46
  "homepage": "https://abaplint.org",
47
47
  "devDependencies": {
48
- "@microsoft/api-extractor": "^7.19.4",
48
+ "@microsoft/api-extractor": "^7.19.5",
49
49
  "@types/chai": "^4.3.0",
50
50
  "@types/mocha": "^9.1.0",
51
- "@types/node": "^17.0.21",
51
+ "@types/node": "^17.0.22",
52
52
  "chai": "^4.3.6",
53
- "eslint": "^8.10.0",
54
- "mocha": "^9.2.1",
53
+ "eslint": "^8.11.0",
54
+ "mocha": "^9.2.2",
55
55
  "c8": "^7.11.0",
56
56
  "source-map-support": "^0.5.21",
57
- "ts-json-schema-generator": "^0.98.0",
57
+ "ts-json-schema-generator": "^1.0.0",
58
58
  "typescript": "^4.6.2"
59
59
  },
60
60
  "dependencies": {
61
- "fast-xml-parser": "^4.0.6",
62
- "json5": "^2.2.0",
61
+ "fast-xml-parser": "^4.0.7",
62
+ "json5": "^2.2.1",
63
63
  "vscode-languageserver-protocol": "^3.16.0",
64
64
  "vscode-languageserver-types": "^3.16.0"
65
65
  }