@abaplint/core 2.85.24 → 2.85.27

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.
@@ -4996,6 +4996,7 @@ declare class StatementNode extends AbstractNode<ExpressionNode | TokenNode> {
4996
4996
  */
4997
4997
  findTokenSequencePosition(first: string, second: string): Position | undefined;
4998
4998
  findExpressionAfterToken(text: string): ExpressionNode | undefined;
4999
+ findExpressionsAfterToken(text: string): ExpressionNode[];
4999
5000
  private toTokens;
5000
5001
  private toTokenNodess;
5001
5002
  }
@@ -16,9 +16,8 @@ class SQLCompare extends combi_1.Expression {
16
16
  const nul = (0, combi_1.seq)("IS", (0, combi_1.optPrio)("NOT"), (0, combi_1.altPrio)("NULL", (0, combi_1.ver)(version_1.Version.v753, "INITIAL")));
17
17
  const source = new _1.SQLSource();
18
18
  const sub = (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.altPrio)("ALL", "ANY", "SOME")), subSelect);
19
- const builtin = (0, combi_1.ver)(version_1.Version.v751, (0, combi_1.seq)((0, combi_1.altPrio)("lower", "upper"), (0, combi_1.tok)(tokens_1.ParenLeftW), _1.SQLFieldName, (0, combi_1.tok)(tokens_1.WParenRightW)));
20
19
  const arith = (0, combi_1.ver)(version_1.Version.v750, (0, combi_1.plusPrio)((0, combi_1.seq)((0, combi_1.altPrio)("+", "-", "*", "/"), _1.SQLFieldName)));
21
- const rett = (0, combi_1.seq)((0, combi_1.altPrio)(builtin, (0, combi_1.seq)(_1.SQLFieldName, (0, combi_1.optPrio)(arith))), (0, combi_1.altPrio)((0, combi_1.seq)(_1.SQLCompareOperator, (0, combi_1.altPrio)(sub, source)), (0, combi_1.seq)((0, combi_1.optPrio)("NOT"), (0, combi_1.altPrio)(inn, like, between)), nul));
20
+ const rett = (0, combi_1.seq)((0, combi_1.altPrio)(_1.SQLFunction, (0, combi_1.seq)(_1.SQLFieldName, (0, combi_1.optPrio)(arith))), (0, combi_1.altPrio)((0, combi_1.seq)(_1.SQLCompareOperator, (0, combi_1.altPrio)(sub, source)), (0, combi_1.seq)((0, combi_1.optPrio)("NOT"), (0, combi_1.altPrio)(inn, like, between)), nul));
22
21
  const exists = (0, combi_1.seq)("EXISTS", subSelect);
23
22
  return (0, combi_1.altPrio)(exists, _1.Dynamic, rett);
24
23
  }
@@ -8,9 +8,13 @@ const combi_1 = require("../combi");
8
8
  const integer_1 = require("./integer");
9
9
  const sql_alias_field_1 = require("./sql_alias_field");
10
10
  const sql_field_name_1 = require("./sql_field_name");
11
+ const simple_source3_1 = require("./simple_source3");
12
+ const source_1 = require("./source");
11
13
  class SQLFunction extends combi_1.Expression {
12
14
  getRunnable() {
13
- const param = (0, combi_1.alt)(sql_field_name_1.SQLFieldName, sql_alias_field_1.SQLAliasField, SQLFunction, constant_1.Constant);
15
+ const paren = (0, combi_1.seq)((0, combi_1.tok)(tokens_1.ParenLeftW), source_1.Source, (0, combi_1.tok)(tokens_1.WParenRightW));
16
+ const at = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WAt), (0, combi_1.alt)(simple_source3_1.SimpleSource3, paren)));
17
+ const param = (0, combi_1.alt)(sql_field_name_1.SQLFieldName, sql_alias_field_1.SQLAliasField, SQLFunction, constant_1.Constant, at);
14
18
  const castTypes = (0, combi_1.altPrio)((0, combi_1.seq)("CHAR", (0, combi_1.tok)(tokens_1.ParenLeftW), integer_1.Integer, (0, combi_1.tok)(tokens_1.WParenRightW)), "FLTP");
15
19
  const abs = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)("abs", (0, combi_1.tok)(tokens_1.ParenLeftW), param, (0, combi_1.tok)(tokens_1.WParenRightW)));
16
20
  const cast = (0, combi_1.ver)(version_1.Version.v750, (0, combi_1.seq)("cast", (0, combi_1.tok)(tokens_1.ParenLeftW), param, "AS", castTypes, (0, combi_1.tok)(tokens_1.WParenRightW)));
@@ -20,10 +24,12 @@ class SQLFunction extends combi_1.Expression {
20
24
  const div = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)("div", (0, combi_1.tok)(tokens_1.ParenLeftW), param, ",", param, (0, combi_1.tok)(tokens_1.WParenRightW)));
21
25
  const floor = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)("floor", (0, combi_1.tok)(tokens_1.ParenLeftW), param, (0, combi_1.tok)(tokens_1.WParenRightW)));
22
26
  const length = (0, combi_1.ver)(version_1.Version.v750, (0, combi_1.seq)("length", (0, combi_1.tok)(tokens_1.ParenLeftW), param, (0, combi_1.tok)(tokens_1.WParenRightW)));
27
+ const lower = (0, combi_1.ver)(version_1.Version.v751, (0, combi_1.seq)("lower", (0, combi_1.tok)(tokens_1.ParenLeftW), param, (0, combi_1.tok)(tokens_1.WParenRightW)));
23
28
  const mod = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)("mod", (0, combi_1.tok)(tokens_1.ParenLeftW), param, ",", param, (0, combi_1.tok)(tokens_1.WParenRightW)));
24
29
  const replace = (0, combi_1.ver)(version_1.Version.v750, (0, combi_1.seq)("replace", (0, combi_1.tok)(tokens_1.ParenLeftW), param, ",", param, ",", param, (0, combi_1.tok)(tokens_1.WParenRightW)));
30
+ const upper = (0, combi_1.ver)(version_1.Version.v751, (0, combi_1.seq)("upper", (0, combi_1.tok)(tokens_1.ParenLeftW), param, (0, combi_1.tok)(tokens_1.WParenRightW)));
25
31
  const uuid = (0, combi_1.ver)(version_1.Version.v754, (0, combi_1.seq)("uuid", (0, combi_1.tok)(tokens_1.ParenLeftW), (0, combi_1.tok)(tokens_1.WParenRightW)));
26
- return (0, combi_1.altPrio)(uuid, abs, ceil, floor, cast, div, mod, coalesce, concat, replace, length);
32
+ return (0, combi_1.altPrio)(uuid, abs, ceil, floor, cast, div, mod, coalesce, concat, replace, length, lower, upper);
27
33
  }
28
34
  }
29
35
  exports.SQLFunction = SQLFunction;
@@ -131,6 +131,7 @@ class BuiltIn {
131
131
  ret.push(this.buildConstant("col_heading", new basic_1.IntegerType(), "1"));
132
132
  ret.push(this.buildConstant("col_key", new basic_1.IntegerType(), "4"));
133
133
  ret.push(this.buildConstant("col_negative", new basic_1.IntegerType(), "6"));
134
+ ret.push(this.buildConstant("col_group", new basic_1.IntegerType(), "7"));
134
135
  ret.push(this.buildConstant("col_normal", new basic_1.IntegerType(), "2"));
135
136
  ret.push(this.buildConstant("col_positive", new basic_1.IntegerType(), "5"));
136
137
  ret.push(this.buildConstant("col_total", new basic_1.IntegerType(), "3"));
@@ -26,9 +26,11 @@ class Find {
26
26
  this.inline(rfound, scope, filename, new basic_1.TableType(type, { withHeader: false }));
27
27
  }
28
28
  }
29
- const ofound = node.findExpressionAfterToken("OFFSET");
30
- if (ofound && ofound.get() instanceof Expressions.Target) {
31
- this.inline(ofound, scope, filename, new basic_1.IntegerType());
29
+ const ofound = node.findExpressionsAfterToken("OFFSET");
30
+ for (const o of ofound) {
31
+ if (o.get() instanceof Expressions.Target) {
32
+ this.inline(o, scope, filename, new basic_1.IntegerType());
33
+ }
32
34
  }
33
35
  const lfound = node.findExpressionAfterToken("LINE");
34
36
  if (lfound && lfound.get() instanceof Expressions.Target) {
@@ -44,7 +46,10 @@ class Find {
44
46
  }
45
47
  if (node.findDirectTokenByText("SUBMATCHES")) {
46
48
  for (const t of node.findDirectExpressions(Expressions.Target)) {
47
- if (t === rfound || t === ofound || t === lfound || t === cfound || t === lnfound) {
49
+ if (t === rfound || t === lfound || t === cfound || t === lnfound) {
50
+ continue;
51
+ }
52
+ else if (ofound.indexOf(t) >= 0) {
48
53
  continue;
49
54
  }
50
55
  const inline = t === null || t === void 0 ? void 0 : t.findDirectExpression(Expressions.InlineData);
@@ -255,6 +255,20 @@ class StatementNode extends _abstract_node_1.AbstractNode {
255
255
  }
256
256
  return undefined;
257
257
  }
258
+ findExpressionsAfterToken(text) {
259
+ const children = this.getChildren();
260
+ const ret = [];
261
+ for (let i = 0; i < children.length - 1; i++) {
262
+ const c = children[i];
263
+ const next = children[i + 1];
264
+ if (c instanceof token_node_1.TokenNode
265
+ && c.get().getStr().toUpperCase() === text.toUpperCase()
266
+ && next instanceof expression_node_1.ExpressionNode) {
267
+ ret.push(next);
268
+ }
269
+ }
270
+ return ret;
271
+ }
258
272
  ////////////////////////////////
259
273
  toTokens(b) {
260
274
  const tokens = [];
@@ -68,7 +68,7 @@ class Registry {
68
68
  }
69
69
  static abaplintVersion() {
70
70
  // magic, see build script "version.sh"
71
- return "2.85.24";
71
+ return "2.85.27";
72
72
  }
73
73
  getDDICReferences() {
74
74
  return this.references;
@@ -44,19 +44,21 @@ Current rules:
44
44
  * CONV is outlined
45
45
  * COND is outlined
46
46
  * REDUCE is outlined
47
+ * SWITCH is outlined
48
+ * APPEND expression is outlined
47
49
  * EMPTY KEY is changed to DEFAULT KEY, opposite of DEFAULT KEY in https://rules.abaplint.org/avoid_use/
48
50
  * CAST changed to ?=
49
51
  * LOOP AT method_call( ) is outlined
50
52
  * VALUE # with structure fields
51
53
  * VALUE # with internal table lines
52
- * Table Expressions[ index ] are outlined
54
+ * Table Expressions are outlined
53
55
  * SELECT INTO @DATA definitions are outlined
54
56
  * Some occurrences of string template formatting option ALPHA changed to function module call
55
57
  * SELECT/INSERT/MODIFY/DELETE/UPDATE "," in field list removed, "@" in source/targets removed
56
58
  * PARTIALLY IMPLEMENTED removed, it can be quick fixed via rule implement_methods
57
59
  * RAISE EXCEPTION ... MESSAGE
58
- * APPEND expression is outlined
59
60
  * Moving with +=, -=, /=, *=, &&= is expanded
61
+ * line_exists and line_index is downported to READ TABLE
60
62
 
61
63
  Only one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,
62
64
  tags: [_irule_1.RuleTag.Experimental, _irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],
@@ -192,6 +194,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
192
194
  if (found) {
193
195
  return found;
194
196
  }
197
+ found = this.outlineSwitch(high, lowFile, highSyntax);
198
+ if (found) {
199
+ return found;
200
+ }
195
201
  found = this.outlineCast(high, lowFile, highSyntax);
196
202
  if (found) {
197
203
  return found;
@@ -224,7 +230,7 @@ Only one transformation is applied to a statement at a time, so multiple steps m
224
230
  if (found) {
225
231
  return found;
226
232
  }
227
- found = this.replaceLineExists(high, lowFile, highSyntax);
233
+ found = this.replaceLineFunctions(high, lowFile, highSyntax);
228
234
  if (found) {
229
235
  return found;
230
236
  }
@@ -329,6 +335,9 @@ Only one transformation is applied to a statement at a time, so multiple steps m
329
335
  if (fields.length === 1) {
330
336
  fieldDefinition = `DATA ${name} TYPE ${tableName}-${fields[0].concatTokens()}.`;
331
337
  }
338
+ else if (fieldList.concatTokens() === "*") {
339
+ fieldDefinition = `DATA ${name} TYPE ${tableName}.`;
340
+ }
332
341
  else {
333
342
  for (const f of fields) {
334
343
  const fieldName = f.concatTokens();
@@ -408,16 +417,11 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
408
417
  return undefined;
409
418
  }
410
419
  replaceTableExpression(node, lowFile, highSyntax) {
411
- var _a;
412
420
  for (const fieldChain of node.findAllExpressionsRecursive(Expressions.FieldChain)) {
413
421
  const tableExpression = fieldChain.findDirectExpression(Expressions.TableExpression);
414
422
  if (tableExpression === undefined) {
415
423
  continue;
416
424
  }
417
- if (tableExpression.getChildren().length > 3) {
418
- // for now, only support the INDEX scenario
419
- continue;
420
- }
421
425
  let pre = "";
422
426
  let startToken = undefined;
423
427
  for (const child of fieldChain.getChildren()) {
@@ -432,11 +436,24 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
432
436
  if (startToken === undefined) {
433
437
  continue;
434
438
  }
439
+ let condition = "";
440
+ for (const c of tableExpression.getChildren() || []) {
441
+ if (c.getFirstToken().getStr() === "[" || c.getFirstToken().getStr() === "]") {
442
+ continue;
443
+ }
444
+ else if (c.get() instanceof Expressions.ComponentChainSimple && condition === "") {
445
+ condition = "WITH KEY ";
446
+ }
447
+ else if (c.get() instanceof Expressions.Source && condition === "") {
448
+ condition = "INDEX ";
449
+ }
450
+ condition += c.concatTokens() + " ";
451
+ }
435
452
  const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
436
453
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
437
454
  const firstToken = node.getFirstToken();
438
455
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
439
- ${indentation}READ TABLE ${pre} INDEX ${(_a = tableExpression.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens()} INTO ${uniqueName}.
456
+ ${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
440
457
  ${indentation}IF sy-subrc <> 0.
441
458
  ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
442
459
  ${indentation}ENDIF.
@@ -735,6 +752,67 @@ ${indentation} output = ${topTarget}.`;
735
752
  }
736
753
  return { body, end };
737
754
  }
755
+ outlineSwitch(node, lowFile, highSyntax) {
756
+ var _a, _b;
757
+ for (const i of node.findAllExpressionsRecursive(Expressions.Source)) {
758
+ const firstToken = i.getFirstToken();
759
+ if (firstToken.getStr().toUpperCase() !== "SWITCH") {
760
+ continue;
761
+ }
762
+ const type = this.findType(i, lowFile, highSyntax);
763
+ if (type === undefined) {
764
+ continue;
765
+ }
766
+ const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
767
+ const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
768
+ let body = "";
769
+ let name = "";
770
+ const switchBody = i.findDirectExpression(Expressions.SwitchBody);
771
+ if (switchBody === undefined) {
772
+ continue;
773
+ }
774
+ for (const l of ((_a = switchBody === null || switchBody === void 0 ? void 0 : switchBody.findDirectExpression(Expressions.Let)) === null || _a === void 0 ? void 0 : _a.findDirectExpressions(Expressions.InlineFieldDefinition)) || []) {
775
+ name = l.getFirstToken().getStr();
776
+ body += indentation + `DATA(${name}) = ${(_b = switchBody.findFirstExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens()}.\n`;
777
+ }
778
+ body += `DATA ${uniqueName} TYPE ${type}.\n`;
779
+ let firstSource = false;
780
+ let inWhen = false;
781
+ for (const c of switchBody.getChildren()) {
782
+ if (c.get() instanceof Expressions.Source && firstSource === false) {
783
+ body += indentation + `CASE ${c.concatTokens()}.`;
784
+ firstSource = true;
785
+ }
786
+ else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === "THEN") {
787
+ inWhen = true;
788
+ body += ".\n";
789
+ }
790
+ else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === "WHEN") {
791
+ inWhen = false;
792
+ body += `\n${indentation} WHEN `;
793
+ }
794
+ else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === "OR") {
795
+ body += ` OR `;
796
+ }
797
+ else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === "ELSE") {
798
+ inWhen = true;
799
+ body += `\n${indentation} WHEN OTHERS.\n`;
800
+ }
801
+ else if (inWhen === false) {
802
+ body += c.concatTokens();
803
+ }
804
+ else {
805
+ body += indentation + " " + uniqueName + " = " + c.concatTokens() + ".";
806
+ }
807
+ }
808
+ body += "\n" + indentation + "ENDCASE.\n" + indentation;
809
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), body);
810
+ const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), i.getLastToken().getEnd(), uniqueName);
811
+ const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
812
+ return issue_1.Issue.atToken(lowFile, firstToken, "Downport SWITCH", this.getMetadata().key, this.conf.severity, fix);
813
+ }
814
+ return undefined;
815
+ }
738
816
  outlineReduce(node, lowFile, highSyntax) {
739
817
  var _a;
740
818
  for (const i of node.findAllExpressionsRecursive(Expressions.Source)) {
@@ -1101,12 +1179,13 @@ ${indentation} output = ${topTarget}.`;
1101
1179
  }
1102
1180
  return undefined;
1103
1181
  }
1104
- replaceLineExists(node, lowFile, highSyntax) {
1182
+ replaceLineFunctions(node, lowFile, highSyntax) {
1105
1183
  var _a, _b;
1106
1184
  const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
1107
1185
  for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {
1186
+ const func = r.position.getName().toUpperCase();
1108
1187
  if (r.referenceType === _reference_1.ReferenceType.BuiltinMethodReference
1109
- && r.position.getName().toUpperCase() === "LINE_EXISTS") {
1188
+ && (func === "LINE_EXISTS" || func === "LINE_INDEX")) {
1110
1189
  const token = r.position.getToken();
1111
1190
  const expression = this.findMethodCallExpression(node, token);
1112
1191
  if (expression === undefined) {
@@ -1120,19 +1199,23 @@ ${indentation} output = ${topTarget}.`;
1120
1199
  else if (c.get() instanceof Expressions.ComponentChainSimple && condition === "") {
1121
1200
  condition = "WITH KEY ";
1122
1201
  }
1202
+ else if (c.get() instanceof Expressions.Source && condition === "") {
1203
+ condition = "INDEX ";
1204
+ }
1123
1205
  condition += c.concatTokens() + " ";
1124
1206
  }
1125
1207
  const tableName = (_b = expression === null || expression === void 0 ? void 0 : expression.findFirstExpression(Expressions.SourceField)) === null || _b === void 0 ? void 0 : _b.concatTokens();
1126
1208
  const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
1127
1209
  const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
1210
+ const sy = func === "LINE_EXISTS" ? "sy-subrc" : "sy-tabix";
1128
1211
  const code = `DATA ${uniqueName} LIKE sy-subrc.\n` +
1129
1212
  indentation + `READ TABLE ${tableName} ${condition}TRANSPORTING NO FIELDS.\n` +
1130
- indentation + uniqueName + " = sy-subrc.\n" +
1213
+ indentation + uniqueName + ` = ${sy}.\n` +
1131
1214
  indentation;
1132
1215
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);
1133
1216
  const start = expression.getFirstToken().getStart();
1134
1217
  const end = expression.getLastToken().getEnd();
1135
- const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, uniqueName + " = 0");
1218
+ const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, uniqueName + (func === "LINE_EXISTS" ? " = 0" : ""));
1136
1219
  const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
1137
1220
  return issue_1.Issue.atToken(lowFile, token, "Use BOOLC", this.getMetadata().key, this.conf.severity, fix);
1138
1221
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.85.24",
3
+ "version": "2.85.27",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",
@@ -50,7 +50,7 @@
50
50
  "@types/mocha": "^9.1.0",
51
51
  "@types/node": "^17.0.21",
52
52
  "chai": "^4.3.6",
53
- "eslint": "^8.9.0",
53
+ "eslint": "^8.10.0",
54
54
  "mocha": "^9.2.1",
55
55
  "c8": "^7.11.0",
56
56
  "source-map-support": "^0.5.21",