@abaplint/core 2.91.2 → 2.91.5
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 +3 -3
- package/build/src/abap/2_statements/expressions/select.js +1 -2
- package/build/src/abap/2_statements/expressions/select_loop.js +1 -2
- package/build/src/abap/2_statements/expressions/sql_client.js +2 -1
- package/build/src/abap/2_statements/statements/insert_database.js +3 -4
- package/build/src/abap/2_statements/statements/modify_database.js +1 -2
- package/build/src/registry.js +1 -1
- package/build/src/rules/obsolete_statement.js +19 -2
- package/build/src/rules/select_performance.js +5 -0
- package/build/src/rules/selection_screen_naming.js +14 -1
- package/package.json +5 -5
package/build/abaplint.d.ts
CHANGED
|
@@ -2741,9 +2741,9 @@ declare interface IFunctionModuleParameter {
|
|
|
2741
2741
|
declare interface IGlobalConfig {
|
|
2742
2742
|
/** input files, glob format */
|
|
2743
2743
|
files: string;
|
|
2744
|
-
skipGeneratedGatewayClasses
|
|
2745
|
-
skipGeneratedPersistentClasses
|
|
2746
|
-
skipGeneratedFunctionGroups
|
|
2744
|
+
skipGeneratedGatewayClasses?: boolean;
|
|
2745
|
+
skipGeneratedPersistentClasses?: boolean;
|
|
2746
|
+
skipGeneratedFunctionGroups?: boolean;
|
|
2747
2747
|
/** Clone and parse dependencies specified in .apack-manifest.xml if it is present */
|
|
2748
2748
|
useApackDependencies?: boolean;
|
|
2749
2749
|
/** Do not report any issues for includes without main programs */
|
|
@@ -14,10 +14,9 @@ class Select extends combi_1.Expression {
|
|
|
14
14
|
const into = (0, combi_1.altPrio)(_1.SQLIntoTable, sql_into_structure_1.SQLIntoStructure);
|
|
15
15
|
const where = (0, combi_1.seq)("WHERE", _1.SQLCond);
|
|
16
16
|
const offset = (0, combi_1.ver)(version_1.Version.v751, (0, combi_1.seq)("OFFSET", _1.SQLSource));
|
|
17
|
-
const client = (0, combi_1.str)("CLIENT SPECIFIED");
|
|
18
17
|
const bypass = (0, combi_1.str)("BYPASSING BUFFER");
|
|
19
18
|
const fields = (0, combi_1.seq)("FIELDS", _1.SQLFieldList);
|
|
20
|
-
const perm = (0, combi_1.per)(_1.SQLFrom, into, _1.SQLForAllEntries, where, _1.SQLOrderBy, sql_up_to_1.SQLUpTo, offset,
|
|
19
|
+
const perm = (0, combi_1.per)(_1.SQLFrom, into, _1.SQLForAllEntries, where, _1.SQLOrderBy, sql_up_to_1.SQLUpTo, offset, _1.SQLClient, _1.SQLHaving, bypass, sql_group_by_1.SQLGroupBy, fields, _1.DatabaseConnection);
|
|
21
20
|
const paren = (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WParenLeftW), sql_field_name_1.SQLFieldName, (0, combi_1.tok)(tokens_1.WParenRightW));
|
|
22
21
|
const ret = (0, combi_1.seq)("SELECT", (0, combi_1.altPrio)("DISTINCT", (0, combi_1.optPrio)((0, combi_1.seq)("SINGLE", (0, combi_1.optPrio)("FOR UPDATE")))), (0, combi_1.optPrio)((0, combi_1.altPrio)(_1.SQLFieldList, paren)), perm, (0, combi_1.optPrio)(_1.SQLHints));
|
|
23
22
|
return ret;
|
|
@@ -13,11 +13,10 @@ const sql_up_to_1 = require("./sql_up_to");
|
|
|
13
13
|
class SelectLoop extends combi_1.Expression {
|
|
14
14
|
getRunnable() {
|
|
15
15
|
const where = (0, combi_1.seq)("WHERE", _1.SQLCond);
|
|
16
|
-
const client = "CLIENT SPECIFIED";
|
|
17
16
|
const bypass = "BYPASSING BUFFER";
|
|
18
17
|
const pack = (0, combi_1.seq)("PACKAGE SIZE", _1.SQLSource);
|
|
19
18
|
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)));
|
|
20
|
-
const perm = (0, combi_1.per)(_1.SQLFrom, where, sql_up_to_1.SQLUpTo, sql_order_by_1.SQLOrderBy, sql_having_1.SQLHaving,
|
|
19
|
+
const perm = (0, combi_1.per)(_1.SQLFrom, where, sql_up_to_1.SQLUpTo, sql_order_by_1.SQLOrderBy, sql_having_1.SQLHaving, _1.SQLClient, bypass, _1.SQLGroupBy, _1.SQLForAllEntries, (0, combi_1.alt)(tab, sql_into_structure_1.SQLIntoStructure));
|
|
21
20
|
const strict = (0, combi_1.seq)(_1.SQLFrom, "FIELDS", sql_field_list_1.SQLFieldList, where, sql_into_structure_1.SQLIntoStructure, sql_up_to_1.SQLUpTo);
|
|
22
21
|
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));
|
|
23
22
|
return ret;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SQLClient = void 0;
|
|
4
|
+
const version_1 = require("../../../version");
|
|
4
5
|
const combi_1 = require("../combi");
|
|
5
6
|
const sql_source_simple_1 = require("./sql_source_simple");
|
|
6
7
|
class SQLClient extends combi_1.Expression {
|
|
7
8
|
getRunnable() {
|
|
8
9
|
// todo, client specified and connection not possible in Cloud
|
|
9
|
-
const client = (0, combi_1.alt)("CLIENT SPECIFIED", (0, combi_1.seq)("USING CLIENT", sql_source_simple_1.SQLSourceSimple));
|
|
10
|
+
const client = (0, combi_1.alt)("CLIENT SPECIFIED", (0, combi_1.seq)("USING", (0, combi_1.alt)((0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)("CLIENT", sql_source_simple_1.SQLSourceSimple)), (0, combi_1.ver)(version_1.Version.v754, (0, combi_1.seq)("CLIENTS IN", (0, combi_1.alt)(sql_source_simple_1.SQLSourceSimple, "T000"))), (0, combi_1.ver)(version_1.Version.v754, "ALL CLIENTS"))));
|
|
10
11
|
return client;
|
|
11
12
|
}
|
|
12
13
|
}
|
|
@@ -6,11 +6,10 @@ const expressions_1 = require("../expressions");
|
|
|
6
6
|
const tokens_1 = require("../../1_lexer/tokens");
|
|
7
7
|
class InsertDatabase {
|
|
8
8
|
getMatcher() {
|
|
9
|
-
const client = (0, combi_1.str)("CLIENT SPECIFIED");
|
|
10
9
|
const sub = (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WParenLeftW), expressions_1.Select, (0, combi_1.tok)(tokens_1.WParenRightW));
|
|
11
|
-
const f = (0, combi_1.seq)((0, combi_1.opt)(
|
|
12
|
-
const from = (0, combi_1.seq)(expressions_1.DatabaseTable, (0, combi_1.opt)((0, combi_1.alt)(f,
|
|
13
|
-
const into = (0, combi_1.seq)("INTO", expressions_1.DatabaseTable, (0, combi_1.opt)(
|
|
10
|
+
const f = (0, combi_1.seq)((0, combi_1.opt)(expressions_1.SQLClient), (0, combi_1.opt)(expressions_1.DatabaseConnection), "FROM", (0, combi_1.opt)("TABLE"), (0, combi_1.alt)(expressions_1.SQLSource, sub), (0, combi_1.opt)("ACCEPTING DUPLICATE KEYS"));
|
|
11
|
+
const from = (0, combi_1.seq)(expressions_1.DatabaseTable, (0, combi_1.opt)((0, combi_1.alt)(f, expressions_1.SQLClient, expressions_1.DatabaseConnection)));
|
|
12
|
+
const into = (0, combi_1.seq)("INTO", expressions_1.DatabaseTable, (0, combi_1.opt)(expressions_1.SQLClient), (0, combi_1.opt)(expressions_1.DatabaseConnection), "VALUES", expressions_1.SQLSource);
|
|
14
13
|
return (0, combi_1.seq)("INSERT", (0, combi_1.alt)(from, into));
|
|
15
14
|
}
|
|
16
15
|
}
|
|
@@ -6,8 +6,7 @@ const expressions_1 = require("../expressions");
|
|
|
6
6
|
class ModifyDatabase {
|
|
7
7
|
getMatcher() {
|
|
8
8
|
const from = (0, combi_1.seq)("FROM", (0, combi_1.opt)("TABLE"), expressions_1.SQLSource);
|
|
9
|
-
const
|
|
10
|
-
const options = (0, combi_1.per)(expressions_1.DatabaseConnection, from, client);
|
|
9
|
+
const options = (0, combi_1.per)(expressions_1.DatabaseConnection, from, expressions_1.SQLClient);
|
|
11
10
|
return (0, combi_1.seq)("MODIFY", expressions_1.DatabaseTable, options);
|
|
12
11
|
}
|
|
13
12
|
}
|
package/build/src/registry.js
CHANGED
|
@@ -65,6 +65,8 @@ class ObsoleteStatementConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
|
65
65
|
this.regex = true;
|
|
66
66
|
/** Check for OCCURENCES vs OCCURRENCES usage */
|
|
67
67
|
this.occurences = true;
|
|
68
|
+
/** Check for CLIENT SPECIFIED */
|
|
69
|
+
this.clientSpecified = true;
|
|
68
70
|
}
|
|
69
71
|
}
|
|
70
72
|
exports.ObsoleteStatementConf = ObsoleteStatementConf;
|
|
@@ -119,7 +121,9 @@ CALL TRANSFORMATION OBJECTS: https://help.sap.com/doc/abapdocu_752_index_htm/7.5
|
|
|
119
121
|
|
|
120
122
|
POSIX REGEX: https://help.sap.com/doc/abapdocu_755_index_htm/7.55/en-US/index.htm
|
|
121
123
|
|
|
122
|
-
OCCURENCES: check for OCCURENCES vs OCCURRENCES
|
|
124
|
+
OCCURENCES: check for OCCURENCES vs OCCURRENCES
|
|
125
|
+
|
|
126
|
+
CLIENT SPECIFIED, from 754: https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/index.htm?file=abapselect_client_obsolete.htm`,
|
|
123
127
|
};
|
|
124
128
|
}
|
|
125
129
|
getConfig() {
|
|
@@ -229,7 +233,7 @@ OCCURENCES: check for OCCURENCES vs OCCURRENCES`,
|
|
|
229
233
|
}
|
|
230
234
|
if (this.conf.withHeaderLine === true && sta instanceof Statements.Data) {
|
|
231
235
|
if (staNode.concatTokens().toUpperCase().includes("WITH HEADER LINE")) {
|
|
232
|
-
const token = staNode.
|
|
236
|
+
const token = staNode.getTokens().find(t => t.getStr().toUpperCase() === "WITH");
|
|
233
237
|
if (token) {
|
|
234
238
|
const issue = issue_1.Issue.atToken(file, token, "WITH HEADER LINE is obsolete", this.getMetadata().key, this.conf.severity);
|
|
235
239
|
issues.push(issue);
|
|
@@ -283,6 +287,19 @@ OCCURENCES: check for OCCURENCES vs OCCURRENCES`,
|
|
|
283
287
|
issues.push(issue);
|
|
284
288
|
}
|
|
285
289
|
}
|
|
290
|
+
if (configVersion >= version_1.Version.v754 && this.conf.clientSpecified
|
|
291
|
+
&& (sta instanceof Statements.Select
|
|
292
|
+
|| sta instanceof Statements.SelectLoop
|
|
293
|
+
|| sta instanceof Statements.DeleteDatabase
|
|
294
|
+
|| sta instanceof Statements.InsertDatabase
|
|
295
|
+
|| sta instanceof Statements.ModifyDatabase
|
|
296
|
+
|| sta instanceof Statements.UpdateDatabase)) {
|
|
297
|
+
const concat = staNode.concatTokens().toUpperCase();
|
|
298
|
+
if (concat.includes(" CLIENT SPECIFIED")) {
|
|
299
|
+
const issue = issue_1.Issue.atStatement(file, staNode, "Use USING CLIENT", this.getMetadata().key, this.conf.severity);
|
|
300
|
+
issues.push(issue);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
286
303
|
if (configVersion >= version_1.Version.v756 && this.conf.regex) {
|
|
287
304
|
if (sta instanceof Statements.Find || sta instanceof Statements.Replace) {
|
|
288
305
|
if ((_c = staNode.findFirstExpression(Expressions.FindType)) === null || _c === void 0 ? void 0 : _c.concatTokens().includes("REGEX")) {
|
|
@@ -36,6 +36,11 @@ class SelectPerformance {
|
|
|
36
36
|
|
|
37
37
|
SELECT *: not reported if using INTO/APPENDING CORRESPONDING FIELDS OF`,
|
|
38
38
|
tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Performance],
|
|
39
|
+
badExample: `SELECT field1, field2 FROM table
|
|
40
|
+
INTO @DATA(structure) UP TO 1 ROWS ORDER BY field3 DESCENDING.
|
|
41
|
+
ENDSELECT.`,
|
|
42
|
+
goodExample: `SELECT field1, field2 FROM table UP TO 1 ROWS
|
|
43
|
+
INTO TABLE @DATA(table) ORDER BY field3 DESCENDING`,
|
|
39
44
|
};
|
|
40
45
|
}
|
|
41
46
|
initialize(reg) {
|
|
@@ -15,6 +15,8 @@ class SelectionScreenNamingConf extends _naming_rule_config_1.NamingRuleConfig {
|
|
|
15
15
|
this.parameter = "^P_.+$";
|
|
16
16
|
/** The pattern for selection-screen select-options */
|
|
17
17
|
this.selectOption = "^S_.+$";
|
|
18
|
+
/** The pattern for selection-screen screen elements */
|
|
19
|
+
this.screenElement = "^SC_.+$";
|
|
18
20
|
}
|
|
19
21
|
}
|
|
20
22
|
exports.SelectionScreenNamingConf = SelectionScreenNamingConf;
|
|
@@ -49,15 +51,20 @@ class SelectionScreenNaming extends _abap_rule_1.ABAPRule {
|
|
|
49
51
|
}
|
|
50
52
|
let parameterCheckDisabled = false;
|
|
51
53
|
let selectOptionDisabled = false;
|
|
54
|
+
let screenElementDisabled = false;
|
|
52
55
|
if (this.conf.parameter === undefined || this.conf.parameter.length === 0) {
|
|
53
56
|
parameterCheckDisabled = true;
|
|
54
57
|
}
|
|
55
58
|
if (this.conf.selectOption === undefined || this.conf.selectOption.length === 0) {
|
|
56
59
|
selectOptionDisabled = true;
|
|
57
60
|
}
|
|
61
|
+
if (this.conf.screenElement === undefined || this.conf.screenElement.length === 0) {
|
|
62
|
+
screenElementDisabled = true;
|
|
63
|
+
}
|
|
58
64
|
for (const stat of file.getStatements()) {
|
|
59
65
|
if ((stat.get() instanceof statements_1.Parameter && !parameterCheckDisabled)
|
|
60
|
-
|| (stat.get() instanceof statements_1.SelectOption && !selectOptionDisabled)
|
|
66
|
+
|| (stat.get() instanceof statements_1.SelectOption && !selectOptionDisabled)
|
|
67
|
+
|| (stat.get() instanceof statements_1.SelectionScreen && !screenElementDisabled)) {
|
|
61
68
|
const fieldNode = this.getFieldForStatementNode(stat);
|
|
62
69
|
const regex = new RegExp(this.getPatternForStatement(stat.get()), "i");
|
|
63
70
|
if (fieldNode && name_validator_1.NameValidator.violatesRule(fieldNode.getFirstToken().getStr(), regex, this.conf)) {
|
|
@@ -75,6 +82,9 @@ class SelectionScreenNaming extends _abap_rule_1.ABAPRule {
|
|
|
75
82
|
else if (statement instanceof statements_1.SelectOption) {
|
|
76
83
|
pattern = this.conf.selectOption;
|
|
77
84
|
}
|
|
85
|
+
else if (statement instanceof statements_1.SelectionScreen) {
|
|
86
|
+
pattern = this.conf.screenElement;
|
|
87
|
+
}
|
|
78
88
|
return pattern;
|
|
79
89
|
}
|
|
80
90
|
getFieldForStatementNode(statNode) {
|
|
@@ -84,6 +94,9 @@ class SelectionScreenNaming extends _abap_rule_1.ABAPRule {
|
|
|
84
94
|
else if (statNode.get() instanceof statements_1.SelectOption) {
|
|
85
95
|
return statNode.findFirstExpression(expressions_1.FieldSub);
|
|
86
96
|
}
|
|
97
|
+
else if (statNode.get() instanceof statements_1.SelectionScreen) {
|
|
98
|
+
return statNode.findFirstExpression(expressions_1.InlineField);
|
|
99
|
+
}
|
|
87
100
|
else {
|
|
88
101
|
return undefined;
|
|
89
102
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.91.
|
|
3
|
+
"version": "2.91.5",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -45,17 +45,17 @@
|
|
|
45
45
|
},
|
|
46
46
|
"homepage": "https://abaplint.org",
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@microsoft/api-extractor": "^7.
|
|
48
|
+
"@microsoft/api-extractor": "^7.28.2",
|
|
49
49
|
"@types/chai": "^4.3.1",
|
|
50
50
|
"@types/mocha": "^9.1.1",
|
|
51
|
-
"@types/node": "^
|
|
51
|
+
"@types/node": "^18.0.0",
|
|
52
52
|
"chai": "^4.3.6",
|
|
53
|
-
"eslint": "^8.
|
|
53
|
+
"eslint": "^8.18.0",
|
|
54
54
|
"mocha": "^10.0.0",
|
|
55
55
|
"c8": "^7.11.3",
|
|
56
56
|
"source-map-support": "^0.5.21",
|
|
57
57
|
"ts-json-schema-generator": "^1.0.0",
|
|
58
|
-
"typescript": "^4.7.
|
|
58
|
+
"typescript": "^4.7.4"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"fast-xml-parser": "^4.0.8",
|