@abaplint/core 2.93.15 → 2.93.17
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.
- package/build/src/abap/2_statements/expressions/for.js +1 -1
- package/build/src/abap/2_statements/statement_parser.js +15 -12
- package/build/src/abap/5_syntax/expressions/for.js +3 -0
- package/build/src/abap/5_syntax/expressions/value_body.js +9 -6
- package/build/src/registry.js +1 -1
- package/build/src/rules/change_if_to_case.js +13 -0
- package/build/src/rules/downport.js +55 -11
- package/build/src/rules/sicf_consistency.js +3 -1
- package/build/src/rules/unused_types.js +3 -1
- package/package.json +2 -2
|
@@ -14,7 +14,7 @@ class For extends combi_1.Expression {
|
|
|
14
14
|
const then = (0, combi_1.seq)("THEN", _1.Source);
|
|
15
15
|
const whil = (0, combi_1.seq)((0, combi_1.altPrio)("UNTIL", "WHILE"), _1.Cond);
|
|
16
16
|
const itera = (0, combi_1.seq)(_1.InlineFieldDefinition, (0, combi_1.opt)(then), whil);
|
|
17
|
-
const groupBy = (0, combi_1.seq)("GROUP BY", field_chain_1.FieldChain);
|
|
17
|
+
const groupBy = (0, combi_1.seq)("GROUP BY", (0, combi_1.alt)(field_chain_1.FieldChain, (0, combi_1.seq)("(", (0, combi_1.plus)(_1.LoopGroupByComponent), ")")));
|
|
18
18
|
const groups = (0, combi_1.ver)(version_1.Version.v740sp08, (0, combi_1.seq)("GROUPS", field_chain_1.FieldChain, "OF", _1.Target, "IN", _1.Source, (0, combi_1.optPrio)(groupBy)));
|
|
19
19
|
const f = (0, combi_1.seq)("FOR", (0, combi_1.alt)(itera, inn, groups), (0, combi_1.optPrio)(_1.Let));
|
|
20
20
|
return (0, combi_1.ver)(version_1.Version.v740sp05, f);
|
|
@@ -104,18 +104,21 @@ class StatementParser {
|
|
|
104
104
|
const result = [];
|
|
105
105
|
for (let statement of wa.statements) {
|
|
106
106
|
// dont use CALL METHOD, when executing lazy, it easily gives a Move for the last statment if lazy logic is evaluated
|
|
107
|
-
if (statement.get() instanceof _statement_1.Unknown
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
107
|
+
if (statement.get() instanceof _statement_1.Unknown) {
|
|
108
|
+
const concat = statement.concatTokens().toUpperCase();
|
|
109
|
+
if (concat.startsWith("CALL METHOD ") === false
|
|
110
|
+
&& concat.startsWith("RAISE EXCEPTION TYPE ") === false
|
|
111
|
+
&& concat.startsWith("CALL FUNCTION ") === false) {
|
|
112
|
+
for (const { first, second } of this.buildSplits(statement.getTokens())) {
|
|
113
|
+
if (second.length === 1) {
|
|
114
|
+
continue; // probably punctuation
|
|
115
|
+
}
|
|
116
|
+
const s = this.categorizeStatement(new nodes_1.StatementNode(new _statement_1.Unknown()).setChildren(this.tokensToNodes(second)));
|
|
117
|
+
if (!(s.get() instanceof _statement_1.Unknown)) {
|
|
118
|
+
result.push(new nodes_1.StatementNode(new _statement_1.Unknown()).setChildren(this.tokensToNodes(first)));
|
|
119
|
+
statement = s;
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
119
122
|
}
|
|
120
123
|
}
|
|
121
124
|
}
|
|
@@ -10,12 +10,14 @@ const component_cond_1 = require("./component_cond");
|
|
|
10
10
|
const cond_1 = require("./cond");
|
|
11
11
|
class For {
|
|
12
12
|
runSyntax(node, scope, filename) {
|
|
13
|
+
let scoped = false;
|
|
13
14
|
const inlineLoop = node.findDirectExpressions(Expressions.InlineLoopDefinition);
|
|
14
15
|
const inlineField = node.findAllExpressions(Expressions.InlineFieldDefinition);
|
|
15
16
|
const addScope = inlineLoop.length > 0 || inlineField.length > 0;
|
|
16
17
|
if (addScope) {
|
|
17
18
|
// this scope is popped in parent expressions
|
|
18
19
|
scope.push(_scope_type_1.ScopeType.For, "FOR", node.getFirstToken().getStart(), filename);
|
|
20
|
+
scoped = true;
|
|
19
21
|
}
|
|
20
22
|
for (const s of inlineLoop) {
|
|
21
23
|
new inline_loop_definition_1.InlineLoopDefinition().runSyntax(s, scope, filename);
|
|
@@ -32,6 +34,7 @@ class For {
|
|
|
32
34
|
for (const s of node.findDirectExpressions(Expressions.Cond)) {
|
|
33
35
|
new cond_1.Cond().runSyntax(s, scope, filename);
|
|
34
36
|
}
|
|
37
|
+
return scoped;
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
exports.For = For;
|
|
@@ -6,20 +6,23 @@ const for_1 = require("./for");
|
|
|
6
6
|
const source_1 = require("./source");
|
|
7
7
|
const let_1 = require("./let");
|
|
8
8
|
const field_assignment_1 = require("./field_assignment");
|
|
9
|
-
const _scope_type_1 = require("../_scope_type");
|
|
10
9
|
const basic_1 = require("../../types/basic");
|
|
11
10
|
class ValueBody {
|
|
12
11
|
runSyntax(node, scope, filename, targetType) {
|
|
13
12
|
if (node === undefined) {
|
|
14
13
|
return targetType;
|
|
15
14
|
}
|
|
15
|
+
let forScopes = 0;
|
|
16
16
|
for (const forNode of node.findDirectExpressions(Expressions.For) || []) {
|
|
17
|
-
new for_1.For().runSyntax(forNode, scope, filename);
|
|
17
|
+
const scoped = new for_1.For().runSyntax(forNode, scope, filename);
|
|
18
|
+
if (scoped === true) {
|
|
19
|
+
forScopes++;
|
|
20
|
+
}
|
|
18
21
|
}
|
|
19
|
-
let
|
|
22
|
+
let letScoped = false;
|
|
20
23
|
const letNode = node.findDirectExpression(Expressions.Let);
|
|
21
24
|
if (letNode) {
|
|
22
|
-
|
|
25
|
+
letScoped = new let_1.Let().runSyntax(letNode, scope, filename);
|
|
23
26
|
}
|
|
24
27
|
for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
|
|
25
28
|
new field_assignment_1.FieldAssignment().runSyntax(s, scope, filename, targetType);
|
|
@@ -52,10 +55,10 @@ class ValueBody {
|
|
|
52
55
|
new source_1.Source().runSyntax(s, scope, filename);
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
|
-
if (
|
|
58
|
+
if (letScoped === true) {
|
|
56
59
|
scope.pop(node.getLastToken().getEnd());
|
|
57
60
|
}
|
|
58
|
-
|
|
61
|
+
for (let i = 0; i < forScopes; i++) {
|
|
59
62
|
scope.pop(node.getLastToken().getEnd());
|
|
60
63
|
}
|
|
61
64
|
if ((targetType === null || targetType === void 0 ? void 0 : targetType.isGeneric()) && type) {
|
package/build/src/registry.js
CHANGED
|
@@ -9,6 +9,13 @@ const _abap_rule_1 = require("./_abap_rule");
|
|
|
9
9
|
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
10
10
|
const _irule_1 = require("./_irule");
|
|
11
11
|
class ChangeIfToCaseConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
12
|
+
constructor() {
|
|
13
|
+
super(...arguments);
|
|
14
|
+
/** skip specific names, case insensitive regular expression
|
|
15
|
+
* @uniqueItems true
|
|
16
|
+
*/
|
|
17
|
+
this.skipNames = [];
|
|
18
|
+
}
|
|
12
19
|
}
|
|
13
20
|
exports.ChangeIfToCaseConf = ChangeIfToCaseConf;
|
|
14
21
|
class ChangeIfToCase extends _abap_rule_1.ABAPRule {
|
|
@@ -113,6 +120,12 @@ ENDCASE.`,
|
|
|
113
120
|
else {
|
|
114
121
|
return false;
|
|
115
122
|
}
|
|
123
|
+
for (const skip of this.getConfig().skipNames || []) {
|
|
124
|
+
const reg = new RegExp(skip, "i");
|
|
125
|
+
if (chain.match(reg)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
116
129
|
for (const t of tuples) {
|
|
117
130
|
if (t.left !== chain && t.right !== chain) {
|
|
118
131
|
return false;
|
|
@@ -139,6 +139,7 @@ Only one transformation is applied to a statement at a time, so multiple steps m
|
|
|
139
139
|
const message = "Internal Error: Statement lengths does not match";
|
|
140
140
|
ret.push(Issue.atStatement(lowFile, lowStatements[0], message, this.getMetadata().key));
|
|
141
141
|
*/
|
|
142
|
+
// hmm, add some way to disable lazyUnknown() in statement_parser.ts
|
|
142
143
|
continue;
|
|
143
144
|
}
|
|
144
145
|
for (let i = 0; i < lowStatements.length; i++) {
|
|
@@ -221,6 +222,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
|
|
|
221
222
|
if (found) {
|
|
222
223
|
return found;
|
|
223
224
|
}
|
|
225
|
+
found = this.downportCorrespondingSimple(high, lowFile);
|
|
226
|
+
if (found) {
|
|
227
|
+
return found;
|
|
228
|
+
}
|
|
224
229
|
found = this.downportRef(low, high, lowFile, highSyntax);
|
|
225
230
|
if (found) {
|
|
226
231
|
return found;
|
|
@@ -872,6 +877,28 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
|
|
|
872
877
|
const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
|
|
873
878
|
return issue_1.Issue.atToken(lowFile, high.getFirstToken(), "Downport, call function parameter", this.getMetadata().key, this.conf.severity, fix);
|
|
874
879
|
}
|
|
880
|
+
downportCorrespondingSimple(high, lowFile) {
|
|
881
|
+
var _a;
|
|
882
|
+
if (!(high.get() instanceof Statements.Move)
|
|
883
|
+
|| high.getChildren().length !== 4
|
|
884
|
+
|| high.getChildren()[2].getFirstToken().getStr().toUpperCase() !== "CORRESPONDING") {
|
|
885
|
+
return undefined;
|
|
886
|
+
}
|
|
887
|
+
const target = high.findDirectExpression(Expressions.Target);
|
|
888
|
+
if (target === undefined) {
|
|
889
|
+
console.dir("sdf1");
|
|
890
|
+
return undefined;
|
|
891
|
+
}
|
|
892
|
+
const sourceRef = (_a = high.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.findFirstExpression(Expressions.CorrespondingBody);
|
|
893
|
+
if (sourceRef === undefined || sourceRef.getChildren().length !== 1) {
|
|
894
|
+
return;
|
|
895
|
+
}
|
|
896
|
+
const code = `MOVE-CORRESPONDING ${sourceRef.concatTokens()} TO ${target.concatTokens()}`;
|
|
897
|
+
const start = high.getFirstToken().getStart();
|
|
898
|
+
const end = high.getLastToken().getStart();
|
|
899
|
+
const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);
|
|
900
|
+
return issue_1.Issue.atToken(lowFile, high.getFirstToken(), "Downport, simple CORRESPONDING move", this.getMetadata().key, this.conf.severity, fix);
|
|
901
|
+
}
|
|
875
902
|
downportRefSimple(high, lowFile) {
|
|
876
903
|
var _a;
|
|
877
904
|
if (!(high.get() instanceof Statements.Move)
|
|
@@ -894,7 +921,7 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
|
|
|
894
921
|
return issue_1.Issue.atToken(lowFile, high.getFirstToken(), "Downport, simple REF move", this.getMetadata().key, this.conf.severity, fix);
|
|
895
922
|
}
|
|
896
923
|
downportLoopGroup(high, lowFile, highSyntax, highFile) {
|
|
897
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
924
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
898
925
|
if (!(high.get() instanceof Statements.Loop)) {
|
|
899
926
|
return undefined;
|
|
900
927
|
}
|
|
@@ -906,6 +933,7 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
|
|
|
906
933
|
const loopSourceName = ((_b = high.findFirstExpression(Expressions.SimpleSource2)) === null || _b === void 0 ? void 0 : _b.concatTokens()) || "nameNotFound";
|
|
907
934
|
const loopTargetName = ((_c = high.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || "nameNotFound";
|
|
908
935
|
const groupTarget = ((_d = group.findDirectExpression(Expressions.LoopGroupByTarget)) === null || _d === void 0 ? void 0 : _d.concatTokens()) || "";
|
|
936
|
+
const isReference = (_e = high.findFirstExpression(Expressions.LoopTarget)) === null || _e === void 0 ? void 0 : _e.concatTokens().toUpperCase().startsWith("REFERENCE INTO ");
|
|
909
937
|
let loopSourceRowType = "typeNotFound";
|
|
910
938
|
const spag = highSyntax.spaghetti.lookupPosition(high.getFirstToken().getStart(), lowFile.getFilename());
|
|
911
939
|
if (spag !== undefined) {
|
|
@@ -920,8 +948,8 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
|
|
|
920
948
|
let groupCountName = undefined;
|
|
921
949
|
for (const c of group.findAllExpressions(Expressions.LoopGroupByComponent)) {
|
|
922
950
|
const name = c.findFirstExpression(Expressions.ComponentName);
|
|
923
|
-
let type = ((
|
|
924
|
-
if ((
|
|
951
|
+
let type = ((_f = c.findFirstExpression(Expressions.Source)) === null || _f === void 0 ? void 0 : _f.concatTokens()) || "todo";
|
|
952
|
+
if ((_g = c.concatTokens()) === null || _g === void 0 ? void 0 : _g.toUpperCase().endsWith(" = GROUP SIZE")) {
|
|
925
953
|
type = "i";
|
|
926
954
|
groupCountName = name === null || name === void 0 ? void 0 : name.concatTokens();
|
|
927
955
|
}
|
|
@@ -938,29 +966,31 @@ ${indentation}RAISE EXCEPTION ${uniqueName2}.`;
|
|
|
938
966
|
END OF ${groupTargetName}type.
|
|
939
967
|
DATA ${groupTargetName}tab TYPE STANDARD TABLE OF ${groupTargetName}type WITH DEFAULT KEY.
|
|
940
968
|
DATA ${uniqueName} LIKE LINE OF ${groupTargetName}tab.
|
|
941
|
-
LOOP AT ${loopSourceName} ${(
|
|
969
|
+
LOOP AT ${loopSourceName} ${(_h = high.findFirstExpression(Expressions.LoopTarget)) === null || _h === void 0 ? void 0 : _h.concatTokens()}.
|
|
942
970
|
READ TABLE ${groupTargetName}tab ASSIGNING FIELD-SYMBOL(<${uniqueFS}>) WITH KEY ${condition}.
|
|
943
|
-
IF sy-subrc = 0
|
|
944
|
-
|
|
945
|
-
|
|
971
|
+
IF sy-subrc = 0.\n`;
|
|
972
|
+
if (groupCountName !== undefined) {
|
|
973
|
+
code += ` <${uniqueFS}>-${groupCountName} = <${uniqueFS}>-${groupCountName} + 1.\n`;
|
|
974
|
+
}
|
|
975
|
+
code += ` INSERT ${loopTargetName}${isReference ? "->*" : ""} INTO TABLE <${uniqueFS}>-items.
|
|
946
976
|
ELSE.\n`;
|
|
947
977
|
code += ` CLEAR ${uniqueName}.\n`;
|
|
948
978
|
for (const c of group.findAllExpressions(Expressions.LoopGroupByComponent)) {
|
|
949
979
|
code += ` ${uniqueName}-${c.concatTokens().replace("GROUP SIZE", "1")}.\n`;
|
|
950
980
|
}
|
|
951
|
-
code += ` INSERT ${loopTargetName}->* INTO TABLE ${uniqueName}-items.\n`;
|
|
981
|
+
code += ` INSERT ${loopTargetName}${isReference ? "->*" : ""} INTO TABLE ${uniqueName}-items.\n`;
|
|
952
982
|
code += ` INSERT ${uniqueName} INTO TABLE ${groupTargetName}tab.\n`;
|
|
953
983
|
code += `ENDIF.
|
|
954
984
|
ENDLOOP.
|
|
955
985
|
LOOP AT ${groupTargetName}tab ${groupTarget}.`;
|
|
956
986
|
let fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), code);
|
|
957
|
-
for (const l of ((
|
|
987
|
+
for (const l of ((_j = highFile.getStructure()) === null || _j === void 0 ? void 0 : _j.findAllStructures(Structures.Loop)) || []) {
|
|
958
988
|
// make sure to find the correct/current loop statement
|
|
959
989
|
if (l.findDirectStatement(Statements.Loop) !== high) {
|
|
960
990
|
continue;
|
|
961
991
|
}
|
|
962
992
|
for (const loop of l.findAllStatements(Statements.Loop)) {
|
|
963
|
-
if ((
|
|
993
|
+
if ((_k = loop.concatTokens()) === null || _k === void 0 ? void 0 : _k.toUpperCase().startsWith("LOOP AT GROUP ")) {
|
|
964
994
|
const subLoopSource = loop.findFirstExpression(Expressions.SimpleSource2);
|
|
965
995
|
if (subLoopSource === undefined) {
|
|
966
996
|
continue;
|
|
@@ -1361,8 +1391,22 @@ ${indentation} output = ${topTarget}.`;
|
|
|
1361
1391
|
from = from ? " FROM " + from : "";
|
|
1362
1392
|
let to = (_j = forLoop.findExpressionAfterToken("TO")) === null || _j === void 0 ? void 0 : _j.concatTokens();
|
|
1363
1393
|
to = to ? " TO " + to : "";
|
|
1394
|
+
let gby = "";
|
|
1395
|
+
for (const lg of forLoop.findDirectExpressions(Expressions.LoopGroupByComponent)) {
|
|
1396
|
+
if (gby !== "") {
|
|
1397
|
+
gby += " ";
|
|
1398
|
+
}
|
|
1399
|
+
gby = lg.concatTokens();
|
|
1400
|
+
}
|
|
1401
|
+
if (gby !== "") {
|
|
1402
|
+
gby = " GROUP BY ( " + gby + " )";
|
|
1403
|
+
}
|
|
1404
|
+
const groups = forLoop.findExpressionAfterToken("GROUPS");
|
|
1405
|
+
if (groups) {
|
|
1406
|
+
gby += " INTO DATA(" + groups.concatTokens() + ")";
|
|
1407
|
+
}
|
|
1364
1408
|
// todo, also backup sy-index / sy-tabix here?
|
|
1365
|
-
body += indentation + `LOOP AT ${loopSource} INTO DATA(${loopTargetField})${from}${to}${cond}.\n`;
|
|
1409
|
+
body += indentation + `LOOP AT ${loopSource} INTO DATA(${loopTargetField})${from}${to}${cond}${gby}.\n`;
|
|
1366
1410
|
if (indexInto) {
|
|
1367
1411
|
body += indentation + " DATA(" + indexInto + ") = sy-tabix.\n";
|
|
1368
1412
|
}
|
|
@@ -8,7 +8,9 @@ const position_1 = require("../position");
|
|
|
8
8
|
class SICFConsistencyConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
9
9
|
constructor() {
|
|
10
10
|
super(...arguments);
|
|
11
|
-
/** skip specific names, case insensitive
|
|
11
|
+
/** skip specific names, case insensitive
|
|
12
|
+
* @uniqueItems true
|
|
13
|
+
*/
|
|
12
14
|
this.skipNames = [];
|
|
13
15
|
}
|
|
14
16
|
}
|
|
@@ -39,7 +39,9 @@ class WorkArea {
|
|
|
39
39
|
class UnusedTypesConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
40
40
|
constructor() {
|
|
41
41
|
super(...arguments);
|
|
42
|
-
/** skip specific names, case insensitive
|
|
42
|
+
/** skip specific names, case insensitive
|
|
43
|
+
* @uniqueItems true
|
|
44
|
+
*/
|
|
43
45
|
this.skipNames = [];
|
|
44
46
|
}
|
|
45
47
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.93.
|
|
3
|
+
"version": "2.93.17",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"homepage": "https://abaplint.org",
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@microsoft/api-extractor": "^7.31.
|
|
49
|
+
"@microsoft/api-extractor": "^7.31.1",
|
|
50
50
|
"@types/chai": "^4.3.3",
|
|
51
51
|
"@types/mocha": "^9.1.1",
|
|
52
52
|
"@types/node": "^18.7.18",
|