@abaplint/core 2.85.29 → 2.85.32
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/abaplint.d.ts +5 -0
- package/build/src/abap/2_statements/expressions/index.js +1 -0
- package/build/src/abap/2_statements/expressions/select_loop.js +2 -12
- package/build/src/abap/2_statements/expressions/sql_field_list_loop.js +21 -0
- package/build/src/abap/2_statements/statement_parser.js +3 -1
- package/build/src/abap/5_syntax/expressions/constant.js +5 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/downport.js +63 -19
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -1912,6 +1912,7 @@ declare namespace Expressions {
|
|
|
1912
1912
|
SQLCompareOperator,
|
|
1913
1913
|
SQLCompare,
|
|
1914
1914
|
SQLCond,
|
|
1915
|
+
SQLFieldListLoop,
|
|
1915
1916
|
SQLFieldList,
|
|
1916
1917
|
SQLFieldName,
|
|
1917
1918
|
SQLForAllEntries,
|
|
@@ -4894,6 +4895,10 @@ declare class SQLFieldList extends Expression {
|
|
|
4894
4895
|
getRunnable(): IStatementRunnable;
|
|
4895
4896
|
}
|
|
4896
4897
|
|
|
4898
|
+
declare class SQLFieldListLoop extends Expression {
|
|
4899
|
+
getRunnable(): IStatementRunnable;
|
|
4900
|
+
}
|
|
4901
|
+
|
|
4897
4902
|
declare class SQLFieldName extends Expression {
|
|
4898
4903
|
getRunnable(): IStatementRunnable;
|
|
4899
4904
|
}
|
|
@@ -158,6 +158,7 @@ __exportStar(require("./sql_client"), exports);
|
|
|
158
158
|
__exportStar(require("./sql_compare_operator"), exports);
|
|
159
159
|
__exportStar(require("./sql_compare"), exports);
|
|
160
160
|
__exportStar(require("./sql_cond"), exports);
|
|
161
|
+
__exportStar(require("./sql_field_list_loop"), exports);
|
|
161
162
|
__exportStar(require("./sql_field_list"), exports);
|
|
162
163
|
__exportStar(require("./sql_field_name"), exports);
|
|
163
164
|
__exportStar(require("./sql_for_all_entries"), exports);
|
|
@@ -3,25 +3,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SelectLoop = void 0;
|
|
4
4
|
const combi_1 = require("../combi");
|
|
5
5
|
const _1 = require(".");
|
|
6
|
-
const version_1 = require("../../../version");
|
|
7
6
|
const sql_order_by_1 = require("./sql_order_by");
|
|
8
7
|
const sql_having_1 = require("./sql_having");
|
|
9
|
-
const sql_path_1 = require("./sql_path");
|
|
10
|
-
const sql_as_name_1 = require("./sql_as_name");
|
|
11
|
-
const sql_case_1 = require("./sql_case");
|
|
12
8
|
const sql_into_structure_1 = require("./sql_into_structure");
|
|
13
9
|
const sql_field_list_1 = require("./sql_field_list");
|
|
14
10
|
const sql_hints_1 = require("./sql_hints");
|
|
15
|
-
const
|
|
11
|
+
const sql_field_list_loop_1 = require("./sql_field_list_loop");
|
|
16
12
|
class SelectLoop extends combi_1.Expression {
|
|
17
13
|
getRunnable() {
|
|
18
14
|
const where = (0, combi_1.seq)("WHERE", _1.SQLCond);
|
|
19
|
-
const comma = (0, combi_1.opt)((0, combi_1.ver)(version_1.Version.v740sp05, ","));
|
|
20
|
-
const as = (0, combi_1.seq)("AS", sql_as_name_1.SQLAsName);
|
|
21
|
-
const someField = (0, combi_1.seq)((0, combi_1.alt)(_1.SQLFieldName, sql_path_1.SQLPath, _1.SQLAggregation, sql_function_1.SQLFunction, sql_case_1.SQLCase), (0, combi_1.optPrio)(as), comma);
|
|
22
|
-
const fieldList = (0, combi_1.seq)((0, combi_1.star)(someField), (0, combi_1.alt)(_1.SQLFieldName, sql_path_1.SQLPath), (0, combi_1.optPrio)(as), comma, (0, combi_1.star)(someField));
|
|
23
|
-
// todo, use SQLFieldList instead?
|
|
24
|
-
const fields = (0, combi_1.alt)("*", _1.Dynamic, fieldList);
|
|
25
15
|
const client = "CLIENT SPECIFIED";
|
|
26
16
|
const bypass = "BYPASSING BUFFER";
|
|
27
17
|
const up = (0, combi_1.seq)("UP TO", _1.SQLSource, "ROWS");
|
|
@@ -29,7 +19,7 @@ class SelectLoop extends combi_1.Expression {
|
|
|
29
19
|
const tab = (0, combi_1.seq)(_1.SQLIntoTable, (0, combi_1.alt)(pack, (0, combi_1.seq)(_1.SQLFrom, pack), (0, combi_1.seq)(pack, _1.SQLFrom)));
|
|
30
20
|
const perm = (0, combi_1.per)(_1.SQLFrom, where, up, sql_order_by_1.SQLOrderBy, sql_having_1.SQLHaving, client, bypass, _1.SQLGroupBy, _1.SQLForAllEntries, (0, combi_1.alt)(tab, sql_into_structure_1.SQLIntoStructure));
|
|
31
21
|
const strict = (0, combi_1.seq)(_1.SQLFrom, "FIELDS", sql_field_list_1.SQLFieldList, where, sql_into_structure_1.SQLIntoStructure, up);
|
|
32
|
-
const ret = (0, combi_1.seq)("SELECT", (0, combi_1.altPrio)((0, combi_1.seq)((0, combi_1.optPrio)("DISTINCT"),
|
|
22
|
+
const ret = (0, combi_1.seq)("SELECT", (0, combi_1.altPrio)((0, combi_1.seq)((0, combi_1.optPrio)("DISTINCT"), sql_field_list_loop_1.SQLFieldListLoop, perm), strict), (0, combi_1.optPrio)(sql_hints_1.SQLHints));
|
|
33
23
|
return ret;
|
|
34
24
|
}
|
|
35
25
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SQLFieldListLoop = void 0;
|
|
4
|
+
const combi_1 = require("../combi");
|
|
5
|
+
const _1 = require(".");
|
|
6
|
+
const version_1 = require("../../../version");
|
|
7
|
+
const sql_function_1 = require("./sql_function");
|
|
8
|
+
const sql_path_1 = require("./sql_path");
|
|
9
|
+
// loop must include one field from the database table
|
|
10
|
+
class SQLFieldListLoop extends combi_1.Expression {
|
|
11
|
+
getRunnable() {
|
|
12
|
+
const comma = (0, combi_1.opt)((0, combi_1.ver)(version_1.Version.v740sp05, ","));
|
|
13
|
+
const as = (0, combi_1.seq)("AS", _1.SQLAsName);
|
|
14
|
+
const someField = (0, combi_1.seq)((0, combi_1.alt)(_1.SQLFieldName, sql_path_1.SQLPath, _1.SQLAggregation, sql_function_1.SQLFunction, _1.SQLCase), (0, combi_1.optPrio)(as), comma);
|
|
15
|
+
const fieldList = (0, combi_1.seq)((0, combi_1.star)(someField), (0, combi_1.alt)(_1.SQLFieldName, sql_path_1.SQLPath), (0, combi_1.optPrio)(as), comma, (0, combi_1.star)(someField));
|
|
16
|
+
const fields = (0, combi_1.alt)("*", _1.Dynamic, fieldList);
|
|
17
|
+
return fields;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.SQLFieldListLoop = SQLFieldListLoop;
|
|
21
|
+
//# sourceMappingURL=sql_field_list_loop.js.map
|
|
@@ -103,7 +103,9 @@ class StatementParser {
|
|
|
103
103
|
lazyUnknown(wa) {
|
|
104
104
|
const result = [];
|
|
105
105
|
for (let statement of wa.statements) {
|
|
106
|
-
if
|
|
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
|
+
&& statement.concatTokens().toUpperCase().startsWith("CALL METHOD ") === false) {
|
|
107
109
|
for (const { first, second } of this.buildSplits(statement.getTokens())) {
|
|
108
110
|
const s = this.categorizeStatement(new nodes_1.StatementNode(new _statement_1.Unknown()).setChildren(this.tokensToNodes(second)));
|
|
109
111
|
if (!(s.get() instanceof _statement_1.Unknown)) {
|
|
@@ -9,7 +9,11 @@ class Constant {
|
|
|
9
9
|
return new basic_1.IntegerType("I");
|
|
10
10
|
}
|
|
11
11
|
else if (node.getFirstToken().getStr().startsWith("'")) {
|
|
12
|
-
|
|
12
|
+
let len = node.getFirstToken().getStr().length - 2;
|
|
13
|
+
if (len <= 0) {
|
|
14
|
+
len = 1;
|
|
15
|
+
}
|
|
16
|
+
return new basic_1.CharacterType(len);
|
|
13
17
|
}
|
|
14
18
|
else {
|
|
15
19
|
return new basic_1.StringType("STRING");
|
package/build/src/registry.js
CHANGED
|
@@ -291,8 +291,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
|
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
293
|
downportSelectInline(low, high, lowFile, highSyntax) {
|
|
294
|
-
if (!(low.get() instanceof _statement_1.Unknown)
|
|
295
|
-
|
|
294
|
+
if (!(low.get() instanceof _statement_1.Unknown)) {
|
|
295
|
+
return undefined;
|
|
296
|
+
}
|
|
297
|
+
else if (!(high.get() instanceof Statements.Select) && !(high.get() instanceof Statements.SelectLoop)) {
|
|
296
298
|
return undefined;
|
|
297
299
|
}
|
|
298
300
|
// as first step outline the @DATA, note that void types are okay, as long the field names are specified
|
|
@@ -307,7 +309,7 @@ Only one transformation is applied to a statement at a time, so multiple steps m
|
|
|
307
309
|
return undefined;
|
|
308
310
|
}
|
|
309
311
|
downportSelectSingleInline(_low, high, lowFile, _highSyntax) {
|
|
310
|
-
var _a, _b, _c;
|
|
312
|
+
var _a, _b, _c, _d;
|
|
311
313
|
const targets = ((_a = high.findFirstExpression(Expressions.SQLIntoStructure)) === null || _a === void 0 ? void 0 : _a.findDirectExpressions(Expressions.SQLTarget)) || [];
|
|
312
314
|
if (targets.length !== 1) {
|
|
313
315
|
return undefined;
|
|
@@ -325,7 +327,10 @@ Only one transformation is applied to a statement at a time, so multiple steps m
|
|
|
325
327
|
return undefined;
|
|
326
328
|
}
|
|
327
329
|
const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
|
|
328
|
-
|
|
330
|
+
let fieldList = high.findFirstExpression(Expressions.SQLFieldList);
|
|
331
|
+
if (fieldList === undefined) {
|
|
332
|
+
fieldList = high.findFirstExpression(Expressions.SQLFieldListLoop);
|
|
333
|
+
}
|
|
329
334
|
if (fieldList === undefined) {
|
|
330
335
|
return undefined;
|
|
331
336
|
}
|
|
@@ -341,6 +346,13 @@ Only one transformation is applied to a statement at a time, so multiple steps m
|
|
|
341
346
|
else if (fieldList.concatTokens().toUpperCase() === "COUNT( * )") {
|
|
342
347
|
fieldDefinition = `DATA ${name} TYPE i.`;
|
|
343
348
|
}
|
|
349
|
+
else if (fieldList.getChildren().length === 1 && fieldList.getChildren()[0].get() instanceof Expressions.SQLAggregation) {
|
|
350
|
+
const c = fieldList.getChildren()[0];
|
|
351
|
+
if (c instanceof nodes_1.ExpressionNode) {
|
|
352
|
+
const concat = (_d = c.findFirstExpression(Expressions.SQLArithmetics)) === null || _d === void 0 ? void 0 : _d.concatTokens();
|
|
353
|
+
fieldDefinition = `DATA ${name} TYPE ${tableName}-${concat}.`;
|
|
354
|
+
}
|
|
355
|
+
}
|
|
344
356
|
else {
|
|
345
357
|
for (const f of fields) {
|
|
346
358
|
const fieldName = f.concatTokens();
|
|
@@ -361,26 +373,31 @@ ${indentation}`);
|
|
|
361
373
|
if (targets.length !== 1) {
|
|
362
374
|
return undefined;
|
|
363
375
|
}
|
|
376
|
+
const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
|
|
364
377
|
const inlineData = targets[0].findFirstExpression(Expressions.InlineData);
|
|
365
378
|
if (inlineData === undefined) {
|
|
366
379
|
return undefined;
|
|
367
380
|
}
|
|
368
381
|
const sqlFrom = high.findAllExpressions(Expressions.SQLFromSource);
|
|
369
|
-
if (sqlFrom.length
|
|
370
|
-
return
|
|
382
|
+
if (sqlFrom.length === 0) {
|
|
383
|
+
return issue_1.Issue.atToken(lowFile, high.getFirstToken(), "Error outlining, sqlFrom not found", this.getMetadata().key, this.conf.severity);
|
|
371
384
|
}
|
|
372
|
-
|
|
385
|
+
let tableName = (_b = sqlFrom[0].findDirectExpression(Expressions.DatabaseTable)) === null || _b === void 0 ? void 0 : _b.concatTokens();
|
|
373
386
|
if (tableName === undefined) {
|
|
374
387
|
return undefined;
|
|
375
388
|
}
|
|
376
|
-
const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
|
|
377
389
|
const fieldList = high.findFirstExpression(Expressions.SQLFieldList);
|
|
378
390
|
if (fieldList === undefined) {
|
|
379
391
|
return undefined;
|
|
380
392
|
}
|
|
381
393
|
let fieldDefinitions = "";
|
|
382
394
|
for (const f of fieldList.findDirectExpressions(Expressions.SQLFieldName)) {
|
|
383
|
-
|
|
395
|
+
let fieldName = f.concatTokens();
|
|
396
|
+
if (fieldName.includes("~")) {
|
|
397
|
+
const split = fieldName.split("~");
|
|
398
|
+
fieldName = split[0];
|
|
399
|
+
tableName = split[1];
|
|
400
|
+
}
|
|
384
401
|
fieldDefinitions += indentation + " " + fieldName + " TYPE " + tableName + "-" + fieldName + ",\n";
|
|
385
402
|
}
|
|
386
403
|
const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
|
|
@@ -477,6 +494,7 @@ ${indentation}`);
|
|
|
477
494
|
if (!(((_a = target === null || target === void 0 ? void 0 : target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.InlineData)) {
|
|
478
495
|
return undefined;
|
|
479
496
|
}
|
|
497
|
+
let type = "";
|
|
480
498
|
const source = node.findFirstExpression(Expressions.Source);
|
|
481
499
|
if (source === undefined) {
|
|
482
500
|
return undefined;
|
|
@@ -494,13 +512,25 @@ ${indentation}`);
|
|
|
494
512
|
return undefined;
|
|
495
513
|
}
|
|
496
514
|
else if (source.findFirstExpression(Expressions.TableExpression)) {
|
|
497
|
-
|
|
515
|
+
const chain = source.findDirectExpression(Expressions.FieldChain);
|
|
516
|
+
if (chain !== undefined
|
|
517
|
+
&& chain.getChildren().length === 2
|
|
518
|
+
&& chain.getChildren()[0].get() instanceof Expressions.SourceField
|
|
519
|
+
&& chain.getChildren()[1].get() instanceof Expressions.TableExpression) {
|
|
520
|
+
type = "LINE OF " + chain.getChildren()[0].concatTokens();
|
|
521
|
+
}
|
|
522
|
+
else {
|
|
523
|
+
return undefined;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
else {
|
|
527
|
+
type = source.concatTokens();
|
|
498
528
|
}
|
|
499
529
|
const targetName = (_c = target.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens();
|
|
500
530
|
const indentation = " ".repeat(node.getFirstToken().getStart().getCol() - 1);
|
|
501
531
|
const firstToken = node.getFirstToken();
|
|
502
532
|
const lastToken = node.getLastToken();
|
|
503
|
-
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${targetName} LIKE ${
|
|
533
|
+
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${targetName} LIKE ${type}.\n${indentation}`);
|
|
504
534
|
const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), lastToken.getEnd(), `${targetName} = ${source.concatTokens()}.`);
|
|
505
535
|
const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
|
|
506
536
|
return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
|
|
@@ -1007,15 +1037,22 @@ ${indentation} output = ${topTarget}.`;
|
|
|
1007
1037
|
if (spag === undefined) {
|
|
1008
1038
|
continue;
|
|
1009
1039
|
}
|
|
1010
|
-
|
|
1011
|
-
if (
|
|
1012
|
-
|
|
1040
|
+
let type = "";
|
|
1041
|
+
if (node.concatTokens().toUpperCase().startsWith("APPEND INITIAL LINE TO ")) {
|
|
1042
|
+
type = "LIKE LINE OF " + ((_b = node.findFirstExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());
|
|
1013
1043
|
}
|
|
1014
|
-
else
|
|
1015
|
-
|
|
1044
|
+
else {
|
|
1045
|
+
const found = spag.findVariable(name);
|
|
1046
|
+
if (found === undefined) {
|
|
1047
|
+
continue;
|
|
1048
|
+
}
|
|
1049
|
+
else if (found.getType() instanceof basic_1.VoidType) {
|
|
1050
|
+
return issue_1.Issue.atToken(lowFile, i.getFirstToken(), "Error outlining voided type", this.getMetadata().key, this.conf.severity);
|
|
1051
|
+
}
|
|
1052
|
+
type = "TYPE ";
|
|
1053
|
+
type += found.getType().getQualifiedName() ? found.getType().getQualifiedName().toLowerCase() : found.getType().toABAP();
|
|
1016
1054
|
}
|
|
1017
|
-
const
|
|
1018
|
-
const code = `FIELD-SYMBOLS ${name} TYPE ${type}.\n` +
|
|
1055
|
+
const code = `FIELD-SYMBOLS ${name} ${type}.\n` +
|
|
1019
1056
|
" ".repeat(node.getFirstToken().getStart().getCol() - 1);
|
|
1020
1057
|
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);
|
|
1021
1058
|
const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), name);
|
|
@@ -1076,11 +1113,18 @@ ${indentation} output = ${topTarget}.`;
|
|
|
1076
1113
|
}
|
|
1077
1114
|
buildCondBody(body, uniqueName, indent, lowFile, highSyntax) {
|
|
1078
1115
|
let code = "";
|
|
1116
|
+
let first = true;
|
|
1079
1117
|
for (const c of body.getChildren()) {
|
|
1080
1118
|
if (c instanceof nodes_1.TokenNode) {
|
|
1081
1119
|
switch (c.getFirstToken().getStr().toUpperCase()) {
|
|
1082
1120
|
case "WHEN":
|
|
1083
|
-
|
|
1121
|
+
if (first === true) {
|
|
1122
|
+
code += indent + "IF ";
|
|
1123
|
+
first = false;
|
|
1124
|
+
}
|
|
1125
|
+
else {
|
|
1126
|
+
code += indent + "ELSEIF ";
|
|
1127
|
+
}
|
|
1084
1128
|
break;
|
|
1085
1129
|
case "THEN":
|
|
1086
1130
|
code += ".\n";
|