@abaplint/core 2.97.16 → 2.98.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 +1 -0
- package/build/src/abap/2_statements/expressions/select.js +5 -1
- package/build/src/abap/5_syntax/_current_scope.js +11 -5
- package/build/src/registry.js +1 -1
- package/build/src/rules/abapdoc.js +1 -1
- package/build/src/rules/colon_missing_space.js +2 -0
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/select_single_full_key.js +90 -0
- package/package.json +2 -2
package/build/abaplint.d.ts
CHANGED
|
@@ -2958,6 +2958,7 @@ declare interface IGlobalConfig {
|
|
|
2958
2958
|
/** input files, glob format */
|
|
2959
2959
|
files: string;
|
|
2960
2960
|
skipGeneratedBOPFInterfaces?: boolean;
|
|
2961
|
+
/** Skips generated table maintenances, determined via TOBJ object */
|
|
2961
2962
|
skipGeneratedFunctionGroups?: boolean;
|
|
2962
2963
|
skipGeneratedGatewayClasses?: boolean;
|
|
2963
2964
|
skipGeneratedPersistentClasses?: boolean;
|
|
@@ -17,8 +17,12 @@ class Select extends combi_1.Expression {
|
|
|
17
17
|
const bypass = (0, combi_1.str)("BYPASSING BUFFER");
|
|
18
18
|
const fields = (0, combi_1.seq)("FIELDS", _1.SQLFieldList);
|
|
19
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);
|
|
20
|
+
const permSingle = (0, combi_1.per)(_1.SQLFrom, sql_into_structure_1.SQLIntoStructure, where, _1.SQLClient, bypass, fields, _1.DatabaseConnection);
|
|
20
21
|
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));
|
|
21
|
-
const
|
|
22
|
+
const fieldList = (0, combi_1.optPrio)((0, combi_1.altPrio)(_1.SQLFieldList, paren));
|
|
23
|
+
const single = (0, combi_1.seq)("SINGLE", (0, combi_1.optPrio)("FOR UPDATE"), fieldList, permSingle);
|
|
24
|
+
const other = (0, combi_1.seq)((0, combi_1.optPrio)("DISTINCT"), fieldList, perm);
|
|
25
|
+
const ret = (0, combi_1.seq)("SELECT", (0, combi_1.altPrio)(single, other), (0, combi_1.optPrio)(_1.SQLHints));
|
|
22
26
|
return ret;
|
|
23
27
|
}
|
|
24
28
|
}
|
|
@@ -181,16 +181,19 @@ class CurrentScope {
|
|
|
181
181
|
if (name === undefined) {
|
|
182
182
|
return { found: false };
|
|
183
183
|
}
|
|
184
|
-
let
|
|
184
|
+
let prefixRTTI = "";
|
|
185
185
|
if (this.parentObj.getType() === "PROG") {
|
|
186
|
-
|
|
186
|
+
prefixRTTI = "\\PROGRAM=" + this.parentObj.getName();
|
|
187
187
|
}
|
|
188
188
|
else if (this.parentObj.getType() === "CLAS") {
|
|
189
|
-
|
|
189
|
+
prefixRTTI = "\\CLASS-POOL=" + this.parentObj.getName();
|
|
190
190
|
}
|
|
191
191
|
const findLocalClass = (_a = this.current) === null || _a === void 0 ? void 0 : _a.findClassDefinition(name);
|
|
192
192
|
if (findLocalClass) {
|
|
193
|
-
|
|
193
|
+
if (findLocalClass.isGlobal() === true) {
|
|
194
|
+
prefixRTTI = "";
|
|
195
|
+
}
|
|
196
|
+
return { found: true, id: findLocalClass, type: _reference_1.ReferenceType.ObjectOrientedReference, ooType: "CLAS", RTTIName: prefixRTTI + "\\CLASS=" + findLocalClass.getName() };
|
|
194
197
|
}
|
|
195
198
|
const globalClas = this.reg.getObject("CLAS", name);
|
|
196
199
|
if (globalClas) {
|
|
@@ -198,7 +201,10 @@ class CurrentScope {
|
|
|
198
201
|
}
|
|
199
202
|
const findLocalInterface = (_b = this.current) === null || _b === void 0 ? void 0 : _b.findInterfaceDefinition(name);
|
|
200
203
|
if (findLocalInterface) {
|
|
201
|
-
|
|
204
|
+
if (findLocalInterface.isGlobal() === true) {
|
|
205
|
+
prefixRTTI = "";
|
|
206
|
+
}
|
|
207
|
+
return { found: true, id: findLocalInterface, type: _reference_1.ReferenceType.ObjectOrientedReference, ooType: "INTF", RTTIName: prefixRTTI + "\\INTERFACE=" + findLocalInterface.getName() };
|
|
202
208
|
}
|
|
203
209
|
const globalIntf = this.reg.getObject("INTF", name);
|
|
204
210
|
if (globalIntf) {
|
package/build/src/registry.js
CHANGED
|
@@ -44,7 +44,7 @@ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#abap-doc-on
|
|
|
44
44
|
var _a, _b;
|
|
45
45
|
const issues = [];
|
|
46
46
|
const rows = file.getRawRows();
|
|
47
|
-
const regexEmptyTags = '^\\"! .*<[
|
|
47
|
+
const regexEmptyTags = '^\\"! .*<[^/>]*><\\/';
|
|
48
48
|
const regexEmptyAbapdoc = '^\\"!.+$';
|
|
49
49
|
const regexEmptyParameterName = '^\\"! @parameter .+\\|';
|
|
50
50
|
let methods = [];
|
|
@@ -21,6 +21,8 @@ class ColonMissingSpace extends _abap_rule_1.ABAPRule {
|
|
|
21
21
|
title: "Colon missing space",
|
|
22
22
|
shortDescription: `Checks for missing spaces after colons in chained statements.`,
|
|
23
23
|
tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
|
|
24
|
+
badExample: `WRITE:hello, world.`,
|
|
25
|
+
goodExample: `WRITE: hello, world.`,
|
|
24
26
|
};
|
|
25
27
|
}
|
|
26
28
|
getMessage() {
|
package/build/src/rules/index.js
CHANGED
|
@@ -132,6 +132,7 @@ __exportStar(require("./remove_descriptions"), exports);
|
|
|
132
132
|
__exportStar(require("./rfc_error_handling"), exports);
|
|
133
133
|
__exportStar(require("./select_add_order_by"), exports);
|
|
134
134
|
__exportStar(require("./select_performance"), exports);
|
|
135
|
+
__exportStar(require("./select_single_full_key"), exports);
|
|
135
136
|
__exportStar(require("./selection_screen_naming"), exports);
|
|
136
137
|
__exportStar(require("./sequential_blank"), exports);
|
|
137
138
|
__exportStar(require("./short_case"), exports);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SelectSingleFullKey = exports.SelectSingleFullKeyConf = void 0;
|
|
4
|
+
const issue_1 = require("../issue");
|
|
5
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
6
|
+
const _irule_1 = require("./_irule");
|
|
7
|
+
const __1 = require("..");
|
|
8
|
+
class SelectSingleFullKeyConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
9
|
+
}
|
|
10
|
+
exports.SelectSingleFullKeyConf = SelectSingleFullKeyConf;
|
|
11
|
+
class SelectSingleFullKey {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.conf = new SelectSingleFullKeyConf();
|
|
14
|
+
}
|
|
15
|
+
getMetadata() {
|
|
16
|
+
return {
|
|
17
|
+
key: "select_single_full_key",
|
|
18
|
+
title: "Detect SELECT SINGLE which are possibily not unique",
|
|
19
|
+
shortDescription: `Detect SELECT SINGLE which are possibily not unique`,
|
|
20
|
+
extendedInformation: `Table definitions must be known, ie. inside the errorNamespace`,
|
|
21
|
+
pseudoComment: "EC CI_NOORDER",
|
|
22
|
+
tags: [_irule_1.RuleTag.Experimental],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
initialize(reg) {
|
|
26
|
+
this.reg = reg;
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
getConfig() {
|
|
30
|
+
return this.conf;
|
|
31
|
+
}
|
|
32
|
+
setConfig(conf) {
|
|
33
|
+
this.conf = conf;
|
|
34
|
+
}
|
|
35
|
+
run(obj) {
|
|
36
|
+
var _a, _b;
|
|
37
|
+
if (!(obj instanceof __1.ABAPObject)) {
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
const syntax = new __1.SyntaxLogic(this.reg, obj).run();
|
|
41
|
+
if (syntax.issues.length > 0) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const issues = [];
|
|
45
|
+
const message = "SELECT SINGLE possibily not unique";
|
|
46
|
+
for (const file of obj.getABAPFiles()) {
|
|
47
|
+
const statements = file.getStatements();
|
|
48
|
+
for (let i = 0; i < statements.length; i++) {
|
|
49
|
+
const s = statements[i];
|
|
50
|
+
if (!(s.get() instanceof __1.Statements.Select)) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
else if (s.findTokenSequencePosition("SELECT", "SINGLE") === undefined) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const databaseTable = s.findFirstExpression(__1.Expressions.DatabaseTable);
|
|
57
|
+
if (databaseTable === undefined) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const next = statements[i + 1];
|
|
61
|
+
if ((next === null || next === void 0 ? void 0 : next.get()) instanceof __1.Comment && next.concatTokens().includes(this.getMetadata().pseudoComment + "")) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const tabl = this.findReference(databaseTable.getFirstToken().getStart(), syntax.spaghetti, file);
|
|
65
|
+
const keys = this.reg.getObject("TABL", tabl).listKeys(this.reg);
|
|
66
|
+
const cond = s.findFirstExpression(__1.Expressions.SQLCond);
|
|
67
|
+
const set = new Set(keys);
|
|
68
|
+
for (const compare of (cond === null || cond === void 0 ? void 0 : cond.findAllExpressionsRecursive(__1.Expressions.SQLCompare)) || []) {
|
|
69
|
+
if (compare.getChildren().length === 3) {
|
|
70
|
+
const fname = (_a = compare.findDirectExpression(__1.Expressions.SQLFieldName)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
71
|
+
const operator = (_b = compare.findDirectExpression(__1.Expressions.SQLCompareOperator)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
|
|
72
|
+
if (fname && (operator === "=" || operator === "EQ")) {
|
|
73
|
+
set.delete(fname);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (set.size > 0) {
|
|
78
|
+
issues.push(issue_1.Issue.atStatement(file, s, message, this.getMetadata().key, this.getConfig().severity));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return issues;
|
|
83
|
+
}
|
|
84
|
+
findReference(position, spaghetti, file) {
|
|
85
|
+
const scope = spaghetti.lookupPosition(position, file.getFilename());
|
|
86
|
+
return scope === null || scope === void 0 ? void 0 : scope.findTableReference(position);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.SelectSingleFullKey = SelectSingleFullKey;
|
|
90
|
+
//# sourceMappingURL=select_single_full_key.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.98.0",
|
|
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
|
"@microsoft/api-extractor": "^7.34.4",
|
|
51
51
|
"@types/chai": "^4.3.4",
|
|
52
52
|
"@types/mocha": "^10.0.1",
|
|
53
|
-
"@types/node": "^18.
|
|
53
|
+
"@types/node": "^18.16.1",
|
|
54
54
|
"chai": "^4.3.7",
|
|
55
55
|
"eslint": "^8.39.0",
|
|
56
56
|
"mocha": "^10.2.0",
|