@abaplint/core 2.96.2 → 2.97.0
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 +9 -1
- package/build/src/abap/5_syntax/_builtin.js +2 -2
- package/build/src/abap/5_syntax/_procedural.js +2 -2
- package/build/src/abap/5_syntax/basic_types.js +16 -11
- package/build/src/abap/5_syntax/statements/controls.js +1 -1
- package/build/src/abap/5_syntax/statements/find.js +2 -2
- package/build/src/abap/5_syntax/statements/ranges.js +1 -1
- package/build/src/abap/5_syntax/statements/selectoption.js +1 -1
- package/build/src/abap/5_syntax/statements/split.js +1 -1
- package/build/src/abap/5_syntax/structures/data.js +2 -2
- package/build/src/abap/5_syntax/structures/statics.js +2 -2
- package/build/src/abap/types/basic/table_type.js +8 -1
- package/build/src/abap/types/form_definition.js +2 -2
- package/build/src/ddic.js +1 -1
- package/build/src/objects/table_type.js +1 -0
- package/build/src/registry.js +1 -1
- package/build/src/rules/constant_classes.js +1 -1
- package/build/src/rules/downport.js +2 -2
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/sql_escape_host_variables.js +1 -1
- package/build/src/rules/strict_sql.js +71 -0
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -401,6 +401,7 @@ declare namespace BasicTypes {
|
|
|
401
401
|
IStructureComponent,
|
|
402
402
|
StructureType,
|
|
403
403
|
TableAccessType,
|
|
404
|
+
TableKeyType,
|
|
404
405
|
ITableKey,
|
|
405
406
|
ITableOptions,
|
|
406
407
|
TableType_2 as TableType,
|
|
@@ -3626,13 +3627,14 @@ declare interface ISyntaxSettings {
|
|
|
3626
3627
|
|
|
3627
3628
|
declare type ITableKey = {
|
|
3628
3629
|
name: string;
|
|
3629
|
-
type
|
|
3630
|
+
type: TableAccessType;
|
|
3630
3631
|
keyFields: string[];
|
|
3631
3632
|
isUnique: boolean;
|
|
3632
3633
|
};
|
|
3633
3634
|
|
|
3634
3635
|
declare type ITableOptions = {
|
|
3635
3636
|
withHeader: boolean;
|
|
3637
|
+
keyType: TableKeyType;
|
|
3636
3638
|
primaryKey?: ITableKey;
|
|
3637
3639
|
secondary?: ITableKey[];
|
|
3638
3640
|
};
|
|
@@ -5959,6 +5961,12 @@ declare class TableExpression extends Expression {
|
|
|
5959
5961
|
getRunnable(): IStatementRunnable;
|
|
5960
5962
|
}
|
|
5961
5963
|
|
|
5964
|
+
declare enum TableKeyType {
|
|
5965
|
+
default = "DEFAULT",
|
|
5966
|
+
user = "USER",
|
|
5967
|
+
empty = "EMPTY"
|
|
5968
|
+
}
|
|
5969
|
+
|
|
5962
5970
|
declare class Tables implements IStatement {
|
|
5963
5971
|
getMatcher(): IStatementRunnable;
|
|
5964
5972
|
}
|
|
@@ -388,7 +388,7 @@ BuiltIn.methods = [
|
|
|
388
388
|
{
|
|
389
389
|
name: "CONCAT_LINES_OF",
|
|
390
390
|
mandatory: {
|
|
391
|
-
"table": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false }),
|
|
391
|
+
"table": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false, keyType: basic_1.TableKeyType.default }),
|
|
392
392
|
},
|
|
393
393
|
optional: {
|
|
394
394
|
"sep": new basic_1.StringType(),
|
|
@@ -684,7 +684,7 @@ BuiltIn.methods = [
|
|
|
684
684
|
{
|
|
685
685
|
name: "LINES",
|
|
686
686
|
mandatory: {
|
|
687
|
-
"val": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false }),
|
|
687
|
+
"val": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false, keyType: basic_1.TableKeyType.default }),
|
|
688
688
|
},
|
|
689
689
|
return: new basic_1.IntegerType(),
|
|
690
690
|
},
|
|
@@ -90,10 +90,10 @@ class Procedural {
|
|
|
90
90
|
}
|
|
91
91
|
if (param.direction === types_1.FunctionModuleParameterDirection.tables) {
|
|
92
92
|
if (found instanceof basic_1.TableType) {
|
|
93
|
-
found = new basic_1.TableType(found.getRowType(), { withHeader: true });
|
|
93
|
+
found = new basic_1.TableType(found.getRowType(), { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
94
94
|
}
|
|
95
95
|
else {
|
|
96
|
-
found = new basic_1.TableType(found, { withHeader: true });
|
|
96
|
+
found = new basic_1.TableType(found, { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
99
|
if ((found instanceof basic_1.UnknownType || found instanceof basic_1.VoidType) && ((_a = param.type) === null || _a === void 0 ? void 0 : _a.includes("-"))) {
|
|
@@ -143,7 +143,7 @@ class BasicTypes {
|
|
|
143
143
|
}
|
|
144
144
|
else if (child.concatTokens() === "[]") {
|
|
145
145
|
if (type instanceof Types.TableType) {
|
|
146
|
-
type = new basic_1.TableType(type.getRowType(), { withHeader: false });
|
|
146
|
+
type = new basic_1.TableType(type.getRowType(), { withHeader: false, keyType: Types.TableKeyType.default });
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
else { // field name
|
|
@@ -295,7 +295,7 @@ class BasicTypes {
|
|
|
295
295
|
const isNamed = (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpression(expressions_1.Field)) !== undefined;
|
|
296
296
|
const primaryKey = {
|
|
297
297
|
name: "primary_key",
|
|
298
|
-
type: type,
|
|
298
|
+
type: type || basic_1.TableAccessType.standard,
|
|
299
299
|
isUnique: isNamed ? false : (firstKey === null || firstKey === void 0 ? void 0 : firstKey.concatTokens().toUpperCase().includes("WITH UNIQUE ")) === true,
|
|
300
300
|
keyFields: [],
|
|
301
301
|
};
|
|
@@ -304,9 +304,6 @@ class BasicTypes {
|
|
|
304
304
|
for (const k of (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpressions(expressions_1.FieldSub)) || []) {
|
|
305
305
|
primaryKey.keyFields.push(k.concatTokens().toUpperCase());
|
|
306
306
|
}
|
|
307
|
-
if (primaryKey.keyFields.length === 0 && text.includes(" DEFAULT KEY")) {
|
|
308
|
-
primaryKey.keyFields.push("TABLE_LINE");
|
|
309
|
-
}
|
|
310
307
|
}
|
|
311
308
|
else {
|
|
312
309
|
start = 0;
|
|
@@ -329,8 +326,16 @@ class BasicTypes {
|
|
|
329
326
|
}
|
|
330
327
|
secondaryKeys.push(secondary);
|
|
331
328
|
}
|
|
329
|
+
let keyType = Types.TableKeyType.user;
|
|
330
|
+
if (text.includes(" EMPTY KEY")) {
|
|
331
|
+
keyType = Types.TableKeyType.empty;
|
|
332
|
+
}
|
|
333
|
+
else if (text.includes(" DEFAULT KEY")) {
|
|
334
|
+
keyType = Types.TableKeyType.default;
|
|
335
|
+
}
|
|
332
336
|
const options = {
|
|
333
337
|
withHeader: text.includes(" WITH HEADER LINE"),
|
|
338
|
+
keyType: keyType,
|
|
334
339
|
primaryKey: primaryKey,
|
|
335
340
|
secondary: secondaryKeys,
|
|
336
341
|
};
|
|
@@ -477,7 +482,7 @@ class BasicTypes {
|
|
|
477
482
|
|| text === "TYPE HASHED TABLE"
|
|
478
483
|
|| text === "TYPE INDEX TABLE"
|
|
479
484
|
|| text === "TYPE ANY TABLE") {
|
|
480
|
-
return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes("WITH HEADER LINE") });
|
|
485
|
+
return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes("WITH HEADER LINE"), keyType: Types.TableKeyType.default });
|
|
481
486
|
}
|
|
482
487
|
else if (text.startsWith("LIKE ")) {
|
|
483
488
|
let sub = node.findFirstExpression(Expressions.Type);
|
|
@@ -495,7 +500,7 @@ class BasicTypes {
|
|
|
495
500
|
}
|
|
496
501
|
found = this.resolveLikeName(sub);
|
|
497
502
|
if (found && this.isOccurs(node)) {
|
|
498
|
-
found = new Types.TableType(found, { withHeader: text.includes("WITH HEADER LINE") }, qualifiedName);
|
|
503
|
+
found = new Types.TableType(found, { withHeader: text.includes("WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
|
|
499
504
|
}
|
|
500
505
|
}
|
|
501
506
|
else if (text.startsWith("TYPE LINE OF ")) {
|
|
@@ -524,17 +529,17 @@ class BasicTypes {
|
|
|
524
529
|
found = this.resolveTypeName(typeName, this.findLength(node), this.findDecimals(node), qualifiedName);
|
|
525
530
|
const concat = node.concatTokens().toUpperCase();
|
|
526
531
|
if (found && this.isOccurs(node)) {
|
|
527
|
-
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE") }, qualifiedName);
|
|
532
|
+
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
|
|
528
533
|
}
|
|
529
534
|
else if (found && concat.includes(" WITH HEADER LINE")) {
|
|
530
535
|
if (found instanceof Types.VoidType) {
|
|
531
|
-
found = new Types.TableType(found, { withHeader: true });
|
|
536
|
+
found = new Types.TableType(found, { withHeader: true, keyType: Types.TableKeyType.default });
|
|
532
537
|
}
|
|
533
538
|
else if (!(found instanceof Types.TableType)) {
|
|
534
539
|
throw new Error("WITH HEADER LINE can only be used with internal table");
|
|
535
540
|
}
|
|
536
541
|
else {
|
|
537
|
-
found = new Types.TableType(found.getRowType(), { withHeader: true });
|
|
542
|
+
found = new Types.TableType(found.getRowType(), { withHeader: true, keyType: Types.TableKeyType.default });
|
|
538
543
|
}
|
|
539
544
|
}
|
|
540
545
|
if (found === undefined && typeName === undefined) {
|
|
@@ -548,7 +553,7 @@ class BasicTypes {
|
|
|
548
553
|
}
|
|
549
554
|
found = new Types.CharacterType(length, { qualifiedName: qualifiedName }); // fallback
|
|
550
555
|
if (this.isOccurs(node)) {
|
|
551
|
-
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE") }, qualifiedName);
|
|
556
|
+
found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
|
|
552
557
|
}
|
|
553
558
|
}
|
|
554
559
|
}
|
|
@@ -32,7 +32,7 @@ class Controls {
|
|
|
32
32
|
{ name: "LINE_SELECTOR", type: new basic_1.CharacterType(1) },
|
|
33
33
|
{ name: "H_GRID", type: new basic_1.CharacterType(1) },
|
|
34
34
|
{ name: "V_GRID", type: new basic_1.CharacterType(1) },
|
|
35
|
-
{ name: "COLS", type: new basic_1.TableType(cols, { withHeader: false }) },
|
|
35
|
+
{ name: "COLS", type: new basic_1.TableType(cols, { withHeader: false, keyType: basic_1.TableKeyType.default }) },
|
|
36
36
|
{ name: "INVISIBLE", type: new basic_1.CharacterType(1) },
|
|
37
37
|
]);
|
|
38
38
|
const id = new _typed_identifier_1.TypedIdentifier(token, filename, type);
|
|
@@ -21,13 +21,13 @@ class Find {
|
|
|
21
21
|
{ name: "LINE", type: new basic_1.IntegerType() },
|
|
22
22
|
{ name: "OFFSET", type: new basic_1.IntegerType() },
|
|
23
23
|
{ name: "LENGTH", type: new basic_1.IntegerType() },
|
|
24
|
-
{ name: "SUBMATCHES", type: new basic_1.TableType(sub, { withHeader: false }) },
|
|
24
|
+
{ name: "SUBMATCHES", type: new basic_1.TableType(sub, { withHeader: false, keyType: basic_1.TableKeyType.default }) },
|
|
25
25
|
], "MATCH_RESULT", "MATCH_RESULT");
|
|
26
26
|
if (node.concatTokens().toUpperCase().startsWith("FIND FIRST")) {
|
|
27
27
|
this.inline(rfound, scope, filename, type);
|
|
28
28
|
}
|
|
29
29
|
else {
|
|
30
|
-
this.inline(rfound, scope, filename, new basic_1.TableType(type, { withHeader: false }, "MATCH_RESULT_TAB"));
|
|
30
|
+
this.inline(rfound, scope, filename, new basic_1.TableType(type, { withHeader: false, keyType: basic_1.TableKeyType.default }, "MATCH_RESULT_TAB"));
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
const ofound = node.findExpressionsAfterToken("OFFSET");
|
|
@@ -21,7 +21,7 @@ class Ranges {
|
|
|
21
21
|
{ name: "low", type: found },
|
|
22
22
|
{ name: "high", type: found },
|
|
23
23
|
]);
|
|
24
|
-
const type = new basic_1.TableType(structure, { withHeader: true });
|
|
24
|
+
const type = new basic_1.TableType(structure, { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
25
25
|
const id = new _typed_identifier_1.TypedIdentifier(nameToken, filename, type);
|
|
26
26
|
scope.addIdentifier(id);
|
|
27
27
|
}
|
|
@@ -39,7 +39,7 @@ class SelectOption {
|
|
|
39
39
|
{ name: "LOW", type: found },
|
|
40
40
|
{ name: "HIGH", type: found },
|
|
41
41
|
]);
|
|
42
|
-
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, new basic_1.TableType(stru, { withHeader: true })));
|
|
42
|
+
scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, new basic_1.TableType(stru, { withHeader: true, keyType: basic_1.TableKeyType.default })));
|
|
43
43
|
return;
|
|
44
44
|
}
|
|
45
45
|
if (nameToken) {
|
|
@@ -10,7 +10,7 @@ const _type_utils_1 = require("../_type_utils");
|
|
|
10
10
|
class Split {
|
|
11
11
|
runSyntax(node, scope, filename) {
|
|
12
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();
|
|
13
|
+
const type = intoTable ? new basic_1.TableType(new basic_1.StringType(), { withHeader: false, keyType: basic_1.TableKeyType.default }) : new basic_1.StringType();
|
|
14
14
|
for (const target of node.findAllExpressions(Expressions.Target)) {
|
|
15
15
|
const inline = target.findDirectExpression(Expressions.InlineData);
|
|
16
16
|
if (inline) {
|
|
@@ -58,7 +58,7 @@ class Data {
|
|
|
58
58
|
}
|
|
59
59
|
if (found instanceof Basic.VoidType) {
|
|
60
60
|
if (table === true) {
|
|
61
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true }));
|
|
61
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
62
62
|
}
|
|
63
63
|
else {
|
|
64
64
|
return new _typed_identifier_1.TypedIdentifier(name, filename, found);
|
|
@@ -76,7 +76,7 @@ class Data {
|
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
if (table === true) {
|
|
79
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true }));
|
|
79
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
80
80
|
}
|
|
81
81
|
else {
|
|
82
82
|
const val = Object.keys(values).length > 0 ? values : undefined;
|
|
@@ -49,7 +49,7 @@ class Statics {
|
|
|
49
49
|
}
|
|
50
50
|
if (found instanceof Basic.VoidType) {
|
|
51
51
|
if (table === true) {
|
|
52
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true }));
|
|
52
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
53
53
|
}
|
|
54
54
|
else {
|
|
55
55
|
return new _typed_identifier_1.TypedIdentifier(name, filename, found);
|
|
@@ -67,7 +67,7 @@ class Statics {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
if (table === true) {
|
|
70
|
-
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true }));
|
|
70
|
+
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true, keyType: Basic.TableKeyType.default }));
|
|
71
71
|
}
|
|
72
72
|
else {
|
|
73
73
|
return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.StructureType(components));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TableType = exports.TableAccessType = void 0;
|
|
3
|
+
exports.TableType = exports.TableKeyType = exports.TableAccessType = void 0;
|
|
4
4
|
const _abstract_type_1 = require("./_abstract_type");
|
|
5
5
|
var TableAccessType;
|
|
6
6
|
(function (TableAccessType) {
|
|
@@ -10,6 +10,12 @@ var TableAccessType;
|
|
|
10
10
|
TableAccessType["index"] = "INDEX";
|
|
11
11
|
TableAccessType["any"] = "ANY";
|
|
12
12
|
})(TableAccessType = exports.TableAccessType || (exports.TableAccessType = {}));
|
|
13
|
+
var TableKeyType;
|
|
14
|
+
(function (TableKeyType) {
|
|
15
|
+
TableKeyType["default"] = "DEFAULT";
|
|
16
|
+
TableKeyType["user"] = "USER";
|
|
17
|
+
TableKeyType["empty"] = "EMPTY";
|
|
18
|
+
})(TableKeyType = exports.TableKeyType || (exports.TableKeyType = {}));
|
|
13
19
|
class TableType extends _abstract_type_1.AbstractType {
|
|
14
20
|
constructor(rowType, options, qualifiedName) {
|
|
15
21
|
var _a;
|
|
@@ -49,6 +55,7 @@ class TableType extends _abstract_type_1.AbstractType {
|
|
|
49
55
|
isGeneric() {
|
|
50
56
|
var _a, _b;
|
|
51
57
|
if (((_a = this.options.primaryKey) === null || _a === void 0 ? void 0 : _a.type) !== TableAccessType.standard
|
|
58
|
+
&& this.options.keyType === TableKeyType.user
|
|
52
59
|
&& ((_b = this.options.primaryKey) === null || _b === void 0 ? void 0 : _b.keyFields.length) === 0) {
|
|
53
60
|
return true;
|
|
54
61
|
}
|
|
@@ -49,10 +49,10 @@ class FormDefinition extends _identifier_1.Identifier {
|
|
|
49
49
|
let type = p.getType();
|
|
50
50
|
const isStructure = param.findDirectTokenByText("STRUCTURE") !== undefined;
|
|
51
51
|
if (isStructure) {
|
|
52
|
-
type = new basic_1.TableType(type, { withHeader: true });
|
|
52
|
+
type = new basic_1.TableType(type, { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
53
53
|
}
|
|
54
54
|
if (type instanceof basic_1.TableType) {
|
|
55
|
-
type = new basic_1.TableType(type.getRowType(), { withHeader: true });
|
|
55
|
+
type = new basic_1.TableType(type.getRowType(), { withHeader: true, keyType: basic_1.TableKeyType.default });
|
|
56
56
|
}
|
|
57
57
|
else if (!(type instanceof basic_1.UnknownType) && !(type instanceof basic_1.VoidType)) {
|
|
58
58
|
type = new basic_1.UnknownType("FORM TABLES type must be table type");
|
package/build/src/ddic.js
CHANGED
|
@@ -66,7 +66,7 @@ class DDIC {
|
|
|
66
66
|
case "%_C_POINTER":
|
|
67
67
|
return new Types.HexType(8, qualifiedName);
|
|
68
68
|
case "TABLE":
|
|
69
|
-
return new Types.TableType(new Types.AnyType(), { withHeader: false });
|
|
69
|
+
return new Types.TableType(new Types.AnyType(), { withHeader: false, keyType: Types.TableKeyType.default });
|
|
70
70
|
case "DATA":
|
|
71
71
|
return new Types.AnyType({ qualifiedName: qualifiedName });
|
|
72
72
|
case "NUMERIC":
|
|
@@ -32,6 +32,7 @@ class TableType extends _abstract_object_1.AbstractObject {
|
|
|
32
32
|
var _a, _b, _c;
|
|
33
33
|
const tableOptions = {
|
|
34
34
|
withHeader: false,
|
|
35
|
+
keyType: Types.TableKeyType.user,
|
|
35
36
|
secondary: [],
|
|
36
37
|
};
|
|
37
38
|
for (const k of ((_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.dd43v) || []) {
|
package/build/src/registry.js
CHANGED
|
@@ -24,7 +24,7 @@ class ConstantClasses {
|
|
|
24
24
|
title: "Validate constant classes",
|
|
25
25
|
shortDescription: `Checks that a class contains exactly the constants corresponding to a domain's fixed values.`,
|
|
26
26
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-enumeration-classes-to-constants-interfaces`,
|
|
27
|
-
tags: [_irule_1.RuleTag.Styleguide
|
|
27
|
+
tags: [_irule_1.RuleTag.Styleguide],
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
30
|
initialize(reg) {
|
|
@@ -122,7 +122,7 @@ class Downport {
|
|
|
122
122
|
return {
|
|
123
123
|
key: "downport",
|
|
124
124
|
title: "Downport statement",
|
|
125
|
-
shortDescription: `
|
|
125
|
+
shortDescription: `Downport functionality`,
|
|
126
126
|
extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with
|
|
127
127
|
a higher level language version. If successful, various rules are applied to downport the statement.
|
|
128
128
|
Target downport version is always v702, thus rule is only enabled if target version is v702.
|
|
@@ -155,7 +155,7 @@ Current rules:
|
|
|
155
155
|
* MESSAGE with non simple source
|
|
156
156
|
|
|
157
157
|
Only one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,
|
|
158
|
-
tags: [_irule_1.RuleTag.
|
|
158
|
+
tags: [_irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],
|
|
159
159
|
};
|
|
160
160
|
}
|
|
161
161
|
getConfig() {
|
package/build/src/rules/index.js
CHANGED
|
@@ -142,6 +142,7 @@ __exportStar(require("./space_before_dot"), exports);
|
|
|
142
142
|
__exportStar(require("./sql_escape_host_variables"), exports);
|
|
143
143
|
__exportStar(require("./start_at_tab"), exports);
|
|
144
144
|
__exportStar(require("./static_call_via_instance"), exports);
|
|
145
|
+
__exportStar(require("./strict_sql"), exports);
|
|
145
146
|
__exportStar(require("./superclass_final"), exports);
|
|
146
147
|
__exportStar(require("./superfluous_value"), exports);
|
|
147
148
|
__exportStar(require("./sy_modification"), exports);
|
|
@@ -23,7 +23,7 @@ class SQLEscapeHostVariables extends _abap_rule_1.ABAPRule {
|
|
|
23
23
|
title: "Escape SQL host variables",
|
|
24
24
|
shortDescription: `Escape SQL host variables, from 740sp05`,
|
|
25
25
|
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-obsolete-language-elements`,
|
|
26
|
-
tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix],
|
|
26
|
+
tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.Syntax],
|
|
27
27
|
badExample: `SELECT * FROM tab INTO TABLE res WHERE field = val.`,
|
|
28
28
|
goodExample: `SELECT * FROM tab INTO TABLE @res WHERE field = @val.`,
|
|
29
29
|
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StrictSQL = exports.StrictSQLConf = void 0;
|
|
4
|
+
const Statements = require("../abap/2_statements/statements");
|
|
5
|
+
const Expressions = require("../abap/2_statements/expressions");
|
|
6
|
+
const issue_1 = require("../issue");
|
|
7
|
+
const _abap_rule_1 = require("./_abap_rule");
|
|
8
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
9
|
+
const version_1 = require("../version");
|
|
10
|
+
const _irule_1 = require("./_irule");
|
|
11
|
+
class StrictSQLConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
12
|
+
}
|
|
13
|
+
exports.StrictSQLConf = StrictSQLConf;
|
|
14
|
+
class StrictSQL extends _abap_rule_1.ABAPRule {
|
|
15
|
+
constructor() {
|
|
16
|
+
super(...arguments);
|
|
17
|
+
this.conf = new StrictSQLConf();
|
|
18
|
+
}
|
|
19
|
+
getMetadata() {
|
|
20
|
+
return {
|
|
21
|
+
key: "strict_sql",
|
|
22
|
+
title: "Strict SQL",
|
|
23
|
+
shortDescription: `Strict SQL`,
|
|
24
|
+
extendedInformation: `https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abapinto_clause.htm
|
|
25
|
+
|
|
26
|
+
https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-us/abenopensql_strict_mode_750.htm
|
|
27
|
+
|
|
28
|
+
Also see separate rule sql_escape_host_variables`,
|
|
29
|
+
tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Syntax],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
getConfig() {
|
|
33
|
+
return this.conf;
|
|
34
|
+
}
|
|
35
|
+
setConfig(conf) {
|
|
36
|
+
this.conf = conf;
|
|
37
|
+
}
|
|
38
|
+
runParsed(file, obj) {
|
|
39
|
+
const issues = [];
|
|
40
|
+
const type = obj.getType();
|
|
41
|
+
if (type === "INTF" || type === "TYPE") {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
if (this.reg.getConfig().getVersion() < version_1.Version.v740sp02
|
|
45
|
+
&& this.reg.getConfig().getVersion() !== version_1.Version.Cloud) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
for (const s of file.getStatements()) {
|
|
49
|
+
if (s.get() instanceof Statements.Select
|
|
50
|
+
|| s.get() instanceof Statements.SelectLoop) {
|
|
51
|
+
const expr = s.findDirectExpression(Expressions.Select);
|
|
52
|
+
const where = expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLCond);
|
|
53
|
+
const into = (expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLIntoStructure))
|
|
54
|
+
|| (expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLIntoTable));
|
|
55
|
+
if (into === undefined || where === undefined) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (where.getFirstToken().getStart().isBefore(into.getFirstToken().getStart())) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const message = "INTO/APPENDING must be last in strict SQL";
|
|
62
|
+
const issue = issue_1.Issue.atToken(file, s.getFirstToken(), message, this.getMetadata().key, this.conf.severity);
|
|
63
|
+
issues.push(issue);
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return issues;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
exports.StrictSQL = StrictSQL;
|
|
71
|
+
//# sourceMappingURL=strict_sql.js.map
|