@abaplint/core 2.113.247 → 2.114.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 +18 -1
- package/build/src/abap/5_syntax/expressions/select.js +20 -8
- package/build/src/objects/email_template.js +21 -0
- package/build/src/objects/index.js +2 -1
- package/build/src/objects/table.js +27 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/index_completely_contained.js +67 -0
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -2023,6 +2023,15 @@ declare class ElseIf_2 implements IStatement {
|
|
|
2023
2023
|
getMatcher(): IStatementRunnable;
|
|
2024
2024
|
}
|
|
2025
2025
|
|
|
2026
|
+
declare class EmailTemplate extends AbstractObject {
|
|
2027
|
+
getType(): string;
|
|
2028
|
+
getAllowedNaming(): {
|
|
2029
|
+
maxLength: number;
|
|
2030
|
+
allowNamespace: boolean;
|
|
2031
|
+
};
|
|
2032
|
+
getDescription(): string | undefined;
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2026
2035
|
export declare class Empty implements IStatement {
|
|
2027
2036
|
getMatcher(): IStatementRunnable;
|
|
2028
2037
|
}
|
|
@@ -5008,7 +5017,6 @@ declare namespace Objects {
|
|
|
5008
5017
|
BRFPlusSystemApplication,
|
|
5009
5018
|
BSPApplication,
|
|
5010
5019
|
BusinessAddInImplementation,
|
|
5011
|
-
CDSEntityBuffer,
|
|
5012
5020
|
BusinessCatalogAppAssignment,
|
|
5013
5021
|
BusinessCatalog,
|
|
5014
5022
|
BusinessConfigurationMaintenanceObject,
|
|
@@ -5017,6 +5025,7 @@ declare namespace Objects {
|
|
|
5017
5025
|
BusinessFunctionSetAssignment,
|
|
5018
5026
|
BusinessObjectModel,
|
|
5019
5027
|
BusinessObjectType,
|
|
5028
|
+
CDSEntityBuffer,
|
|
5020
5029
|
ParsedMetadataExtension,
|
|
5021
5030
|
CDSMetadataExtension,
|
|
5022
5031
|
CDSType,
|
|
@@ -5046,6 +5055,7 @@ declare namespace Objects {
|
|
|
5046
5055
|
EcattTestConfiguration,
|
|
5047
5056
|
EcattTestDataContainer,
|
|
5048
5057
|
EcattTestScript,
|
|
5058
|
+
EmailTemplate,
|
|
5049
5059
|
EnhancementImplementation,
|
|
5050
5060
|
IBadiDefinition,
|
|
5051
5061
|
EnhancementSpot,
|
|
@@ -5142,6 +5152,7 @@ declare namespace Objects {
|
|
|
5142
5152
|
TableType,
|
|
5143
5153
|
EnhancementCategory,
|
|
5144
5154
|
TableCategory,
|
|
5155
|
+
SecondaryIndex,
|
|
5145
5156
|
Table,
|
|
5146
5157
|
TechnicalJobDefinition,
|
|
5147
5158
|
TransactionVariant,
|
|
@@ -5871,6 +5882,11 @@ declare class SearchHelp extends AbstractObject {
|
|
|
5871
5882
|
getDescription(): string | undefined;
|
|
5872
5883
|
}
|
|
5873
5884
|
|
|
5885
|
+
declare type SecondaryIndex = {
|
|
5886
|
+
name: string;
|
|
5887
|
+
fields: string[];
|
|
5888
|
+
};
|
|
5889
|
+
|
|
5874
5890
|
declare class SectionContents implements IStructure {
|
|
5875
5891
|
getMatcher(): IStructureRunnable;
|
|
5876
5892
|
}
|
|
@@ -6963,6 +6979,7 @@ declare class Table extends AbstractObject {
|
|
|
6963
6979
|
private parsedType;
|
|
6964
6980
|
getType(): string;
|
|
6965
6981
|
getDescription(): string | undefined;
|
|
6982
|
+
getSecondaryIndexes(): SecondaryIndex[] | undefined;
|
|
6966
6983
|
getAllowedNaming(): IAllowedNaming;
|
|
6967
6984
|
setDirty(): void;
|
|
6968
6985
|
listKeys(reg: IRegistry): string[];
|
|
@@ -17,7 +17,7 @@ const _syntax_input_1 = require("../_syntax_input");
|
|
|
17
17
|
const isSimple = /^\w+$/;
|
|
18
18
|
class Select {
|
|
19
19
|
static runSyntax(node, input, skipImplicitInto = false) {
|
|
20
|
-
var _a
|
|
20
|
+
var _a;
|
|
21
21
|
const token = node.getFirstToken();
|
|
22
22
|
let from = node.findDirectExpression(Expressions.SQLFrom);
|
|
23
23
|
if (from === undefined) {
|
|
@@ -38,10 +38,8 @@ class Select {
|
|
|
38
38
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
|
-
const isSingle = ((_a = node.getChildren()[1]) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase()) === "SINGLE"
|
|
42
|
-
|| node.get() instanceof Expressions.SelectLoop;
|
|
43
41
|
this.checkFields(fields, dbSources, input, node);
|
|
44
|
-
this.handleInto(node, input, fields, dbSources
|
|
42
|
+
const intoExpression = this.handleInto(node, input, fields, dbSources);
|
|
45
43
|
const fae = node.findDirectExpression(Expressions.SQLForAllEntries);
|
|
46
44
|
if (fae) {
|
|
47
45
|
input.scope.push(_scope_type_1.ScopeType.OpenSQL, "SELECT", token.getStart(), input.filename);
|
|
@@ -55,7 +53,7 @@ class Select {
|
|
|
55
53
|
&& node.findDirectExpression(Expressions.SQLIntoTable) === undefined
|
|
56
54
|
&& node.findDirectExpression(Expressions.SQLIntoList) === undefined
|
|
57
55
|
&& node.findDirectExpression(Expressions.SQLIntoStructure) === undefined) {
|
|
58
|
-
const fields = (
|
|
56
|
+
const fields = (_a = node.findFirstExpression(Expressions.SQLAggregation)) === null || _a === void 0 ? void 0 : _a.concatTokens();
|
|
59
57
|
const c = new RegExp(/^count\(\s*\*\s*\)$/, "i");
|
|
60
58
|
if (fields === undefined || c.test(fields) === false) {
|
|
61
59
|
const nameToken = from === null || from === void 0 ? void 0 : from.findDirectExpression(Expressions.SQLFromSource);
|
|
@@ -89,8 +87,18 @@ class Select {
|
|
|
89
87
|
for (const s of node.findAllExpressions(Expressions.SQLCompare)) {
|
|
90
88
|
sql_compare_1.SQLCompare.runSyntax(s, input, dbSources);
|
|
91
89
|
}
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
const orderBy = node.findDirectExpression(Expressions.SQLOrderBy);
|
|
91
|
+
if (orderBy) {
|
|
92
|
+
sql_order_by_1.SQLOrderBy.runSyntax(orderBy, input);
|
|
93
|
+
const where = node.findDirectExpression(Expressions.SQLCond);
|
|
94
|
+
if (intoExpression
|
|
95
|
+
&& where
|
|
96
|
+
&& intoExpression.getFirstToken().getStart().isBefore(orderBy.getFirstToken().getStart())
|
|
97
|
+
&& where.getFirstToken().getStart().isBefore(orderBy.getFirstToken().getStart())
|
|
98
|
+
&& where.getFirstToken().getStart().isBefore(intoExpression.getFirstToken().getStart())) {
|
|
99
|
+
const message = `ORDER BY must be before INTO, after WHERE`;
|
|
100
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, orderBy.getFirstToken(), message));
|
|
101
|
+
}
|
|
94
102
|
}
|
|
95
103
|
if (this.isStrictMode(node)) {
|
|
96
104
|
this.strictModeChecks(node, input);
|
|
@@ -141,13 +149,14 @@ class Select {
|
|
|
141
149
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
142
150
|
}
|
|
143
151
|
}
|
|
144
|
-
static handleInto(node, input, fields, dbSources
|
|
152
|
+
static handleInto(node, input, fields, dbSources) {
|
|
145
153
|
const intoTable = node.findDirectExpression(Expressions.SQLIntoTable);
|
|
146
154
|
if (intoTable) {
|
|
147
155
|
const inline = intoTable.findFirstExpression(Expressions.InlineData);
|
|
148
156
|
if (inline) {
|
|
149
157
|
inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope));
|
|
150
158
|
}
|
|
159
|
+
return intoTable;
|
|
151
160
|
}
|
|
152
161
|
const intoStructure = node.findDirectExpression(Expressions.SQLIntoStructure);
|
|
153
162
|
if (intoStructure) {
|
|
@@ -161,6 +170,7 @@ class Select {
|
|
|
161
170
|
inline_data_1.InlineData.runSyntax(inline, input, basic_1.VoidType.get("SELECT_todo1"));
|
|
162
171
|
}
|
|
163
172
|
}
|
|
173
|
+
return intoStructure;
|
|
164
174
|
}
|
|
165
175
|
const intoList = node.findDirectExpression(Expressions.SQLIntoList);
|
|
166
176
|
if (intoList) {
|
|
@@ -200,7 +210,9 @@ class Select {
|
|
|
200
210
|
inline_data_1.InlineData.runSyntax(inline, input, type);
|
|
201
211
|
}
|
|
202
212
|
}
|
|
213
|
+
return intoList;
|
|
203
214
|
}
|
|
215
|
+
return undefined;
|
|
204
216
|
}
|
|
205
217
|
static checkFields(fields, dbSources, input, node) {
|
|
206
218
|
if (dbSources.length > 1) {
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EmailTemplate = void 0;
|
|
4
|
+
const _abstract_object_1 = require("./_abstract_object");
|
|
5
|
+
class EmailTemplate extends _abstract_object_1.AbstractObject {
|
|
6
|
+
getType() {
|
|
7
|
+
return "SMTG";
|
|
8
|
+
}
|
|
9
|
+
getAllowedNaming() {
|
|
10
|
+
return {
|
|
11
|
+
maxLength: 60, // todo
|
|
12
|
+
allowNamespace: true,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
getDescription() {
|
|
16
|
+
// todo
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.EmailTemplate = EmailTemplate;
|
|
21
|
+
//# sourceMappingURL=email_template.js.map
|
|
@@ -36,7 +36,6 @@ __exportStar(require("./behavior_definition"), exports);
|
|
|
36
36
|
__exportStar(require("./brf_plus_system_application"), exports);
|
|
37
37
|
__exportStar(require("./bsp_application"), exports);
|
|
38
38
|
__exportStar(require("./business_add_in_implementation"), exports);
|
|
39
|
-
__exportStar(require("./cds_entity_buffer"), exports);
|
|
40
39
|
__exportStar(require("./business_catalog_app_assignment"), exports);
|
|
41
40
|
__exportStar(require("./business_catalog"), exports);
|
|
42
41
|
__exportStar(require("./business_configuration_maintenance_object"), exports);
|
|
@@ -45,6 +44,7 @@ __exportStar(require("./business_function_assignment"), exports);
|
|
|
45
44
|
__exportStar(require("./business_function_set_assignment"), exports);
|
|
46
45
|
__exportStar(require("./business_object_model"), exports);
|
|
47
46
|
__exportStar(require("./business_object_type"), exports);
|
|
47
|
+
__exportStar(require("./cds_entity_buffer"), exports);
|
|
48
48
|
__exportStar(require("./cds_metadata_extension"), exports);
|
|
49
49
|
__exportStar(require("./cds_type"), exports);
|
|
50
50
|
__exportStar(require("./change_document"), exports);
|
|
@@ -70,6 +70,7 @@ __exportStar(require("./domain"), exports);
|
|
|
70
70
|
__exportStar(require("./ecatt_test_configuration"), exports);
|
|
71
71
|
__exportStar(require("./ecatt_test_data_container"), exports);
|
|
72
72
|
__exportStar(require("./ecatt_test_script"), exports);
|
|
73
|
+
__exportStar(require("./email_template"), exports);
|
|
73
74
|
__exportStar(require("./enhancement_implementation"), exports);
|
|
74
75
|
__exportStar(require("./enhancement_spot"), exports);
|
|
75
76
|
__exportStar(require("./entity_type"), exports);
|
|
@@ -40,6 +40,13 @@ class Table extends _abstract_object_1.AbstractObject {
|
|
|
40
40
|
}
|
|
41
41
|
return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.description;
|
|
42
42
|
}
|
|
43
|
+
getSecondaryIndexes() {
|
|
44
|
+
var _a;
|
|
45
|
+
if (this.parsedData === undefined) {
|
|
46
|
+
this.parseXML();
|
|
47
|
+
}
|
|
48
|
+
return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.secondaryIndexes;
|
|
49
|
+
}
|
|
43
50
|
getAllowedNaming() {
|
|
44
51
|
let length = 30;
|
|
45
52
|
const regex = /^((\/[A-Z_\d]{3,8}\/)|[a-zA-Z0-9]{3}|CI_)\w+$/;
|
|
@@ -267,7 +274,7 @@ class Table extends _abstract_object_1.AbstractObject {
|
|
|
267
274
|
}
|
|
268
275
|
///////////////
|
|
269
276
|
parseXML() {
|
|
270
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
277
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
271
278
|
const parsed = super.parseRaw2();
|
|
272
279
|
if (parsed === undefined) {
|
|
273
280
|
return;
|
|
@@ -306,6 +313,25 @@ class Table extends _abstract_object_1.AbstractObject {
|
|
|
306
313
|
DDTEXT: field.DDTEXT,
|
|
307
314
|
});
|
|
308
315
|
}
|
|
316
|
+
// secondary indexes
|
|
317
|
+
const indexes = (_m = parsed.abapGit["asx:abap"]["asx:values"]) === null || _m === void 0 ? void 0 : _m.DD12V;
|
|
318
|
+
;
|
|
319
|
+
this.parsedData.secondaryIndexes = [];
|
|
320
|
+
for (const index of (0, xml_utils_1.xmlToArray)(indexes === null || indexes === void 0 ? void 0 : indexes.DD12V)) {
|
|
321
|
+
const indexName = index.INDEXNAME;
|
|
322
|
+
const indexFields = [];
|
|
323
|
+
const indexFieldsXml = (_o = parsed.abapGit["asx:abap"]["asx:values"]) === null || _o === void 0 ? void 0 : _o.DD17V;
|
|
324
|
+
for (const indexField of (0, xml_utils_1.xmlToArray)(indexFieldsXml === null || indexFieldsXml === void 0 ? void 0 : indexFieldsXml.DD17V)) {
|
|
325
|
+
if (indexField.INDEXNAME === indexName) {
|
|
326
|
+
// assumption: fields are listed by POSITION in the xml
|
|
327
|
+
indexFields.push(indexField.FIELDNAME);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
this.parsedData.secondaryIndexes.push({
|
|
331
|
+
name: indexName,
|
|
332
|
+
fields: indexFields,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
309
335
|
}
|
|
310
336
|
}
|
|
311
337
|
exports.Table = Table;
|
package/build/src/registry.js
CHANGED
package/build/src/rules/index.js
CHANGED
|
@@ -83,6 +83,7 @@ __exportStar(require("./implement_methods"), exports);
|
|
|
83
83
|
__exportStar(require("./implicit_start_of_selection"), exports);
|
|
84
84
|
__exportStar(require("./in_statement_indentation"), exports);
|
|
85
85
|
__exportStar(require("./indentation"), exports);
|
|
86
|
+
__exportStar(require("./index_completely_contained"), exports);
|
|
86
87
|
__exportStar(require("./inline_data_old_versions"), exports);
|
|
87
88
|
__exportStar(require("./intf_referencing_clas"), exports);
|
|
88
89
|
__exportStar(require("./invalid_table_index"), exports);
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IndexCompletelyContained = exports.IndexCompletelyContainedConf = void 0;
|
|
4
|
+
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
5
|
+
const _irule_1 = require("./_irule");
|
|
6
|
+
const issue_1 = require("../issue");
|
|
7
|
+
const position_1 = require("../position");
|
|
8
|
+
const Objects = require("../objects");
|
|
9
|
+
class IndexCompletelyContainedConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
10
|
+
}
|
|
11
|
+
exports.IndexCompletelyContainedConf = IndexCompletelyContainedConf;
|
|
12
|
+
class IndexCompletelyContained {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.conf = new IndexCompletelyContainedConf();
|
|
15
|
+
}
|
|
16
|
+
getMetadata() {
|
|
17
|
+
return {
|
|
18
|
+
key: "index_completely_contained",
|
|
19
|
+
title: "Check if database table indexes are completely contained",
|
|
20
|
+
shortDescription: `If indexes are completely contained in other indexes, they can be removed to improve performance.`,
|
|
21
|
+
tags: [_irule_1.RuleTag.Performance],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
initialize() {
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
getConfig() {
|
|
28
|
+
return this.conf;
|
|
29
|
+
}
|
|
30
|
+
setConfig(conf) {
|
|
31
|
+
this.conf = conf;
|
|
32
|
+
}
|
|
33
|
+
run(obj) {
|
|
34
|
+
if (!(obj instanceof Objects.Table)) {
|
|
35
|
+
return [];
|
|
36
|
+
}
|
|
37
|
+
const indexes = obj.getSecondaryIndexes();
|
|
38
|
+
if (indexes === undefined || indexes.length === 0) {
|
|
39
|
+
return [];
|
|
40
|
+
}
|
|
41
|
+
const issues = [];
|
|
42
|
+
for (let i = 0; i < indexes.length; i++) {
|
|
43
|
+
const indexA = indexes[i];
|
|
44
|
+
for (let j = 0; j < indexes.length; j++) {
|
|
45
|
+
if (i === j) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const indexB = indexes[j];
|
|
49
|
+
let contained = true;
|
|
50
|
+
for (const field of indexA.fields) {
|
|
51
|
+
if (indexB.fields.indexOf(field) === -1) {
|
|
52
|
+
contained = false;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (contained) {
|
|
57
|
+
const position = new position_1.Position(1, 1);
|
|
58
|
+
const message = `Index "${indexA.name}" is completely contained in index "${indexB.name}"`;
|
|
59
|
+
issues.push(issue_1.Issue.atPosition(obj.getFiles()[0], position, message, this.getMetadata().key, this.conf.severity));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return issues;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
exports.IndexCompletelyContained = IndexCompletelyContained;
|
|
67
|
+
//# sourceMappingURL=index_completely_contained.js.map
|