@abaplint/core 2.97.17 → 2.98.1
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/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 +99 -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
|
}
|
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,99 @@
|
|
|
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 table = this.reg.getObject("TABL", tabl);
|
|
66
|
+
const keys = table.listKeys(this.reg);
|
|
67
|
+
// const type = table.parseType(this.reg);
|
|
68
|
+
const cond = s.findFirstExpression(__1.Expressions.SQLCond);
|
|
69
|
+
const set = new Set();
|
|
70
|
+
for (const key of keys) {
|
|
71
|
+
if (key === "MANDT") {
|
|
72
|
+
// todo, it should check for the correct type instead
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
set.add(key);
|
|
76
|
+
}
|
|
77
|
+
for (const compare of (cond === null || cond === void 0 ? void 0 : cond.findAllExpressionsRecursive(__1.Expressions.SQLCompare)) || []) {
|
|
78
|
+
if (compare.getChildren().length === 3) {
|
|
79
|
+
const fname = (_a = compare.findDirectExpression(__1.Expressions.SQLFieldName)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
80
|
+
const operator = (_b = compare.findDirectExpression(__1.Expressions.SQLCompareOperator)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
|
|
81
|
+
if (fname && (operator === "=" || operator === "EQ")) {
|
|
82
|
+
set.delete(fname);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (set.size > 0) {
|
|
87
|
+
issues.push(issue_1.Issue.atStatement(file, s, message, this.getMetadata().key, this.getConfig().severity));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return issues;
|
|
92
|
+
}
|
|
93
|
+
findReference(position, spaghetti, file) {
|
|
94
|
+
const scope = spaghetti.lookupPosition(position, file.getFilename());
|
|
95
|
+
return scope === null || scope === void 0 ? void 0 : scope.findTableReference(position);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
exports.SelectSingleFullKey = SelectSingleFullKey;
|
|
99
|
+
//# 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.1",
|
|
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",
|