@abaplint/core 2.78.13 → 2.79.3
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 +31 -1
- package/build/src/abap/4_file_information/abap_file_information.js +30 -1
- package/build/src/abap/5_syntax/_type_utils.js +1 -0
- package/build/src/abap/5_syntax/expressions/field_assignment.js +6 -0
- package/build/src/issue.js +3 -0
- package/build/src/lsp/semantic.js +1 -1
- package/build/src/objects/domain.js +18 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/check_syntax.js +13 -1
- package/build/src/rules/constant_classes.js +109 -0
- package/build/src/rules/index.js +1 -0
- package/build/src/rules/obsolete_statement.js +34 -1
- package/build/src/version.js +1 -0
- package/package.json +3 -3
package/build/abaplint.d.ts
CHANGED
|
@@ -1350,6 +1350,13 @@ declare class Domain extends AbstractObject {
|
|
|
1350
1350
|
updated: boolean;
|
|
1351
1351
|
runtime: number;
|
|
1352
1352
|
};
|
|
1353
|
+
getFixedValues(): DomainValue[];
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
declare interface DomainValue {
|
|
1357
|
+
language: string;
|
|
1358
|
+
value: string;
|
|
1359
|
+
description: string;
|
|
1353
1360
|
}
|
|
1354
1361
|
|
|
1355
1362
|
declare class Dynamic extends Expression {
|
|
@@ -2543,6 +2550,16 @@ export declare interface IInterfaceDefinition extends Identifier {
|
|
|
2543
2550
|
getImplementing(): readonly IImplementing[];
|
|
2544
2551
|
}
|
|
2545
2552
|
|
|
2553
|
+
declare interface IIssueData {
|
|
2554
|
+
filename: string;
|
|
2555
|
+
message: string;
|
|
2556
|
+
key: string;
|
|
2557
|
+
start: Position;
|
|
2558
|
+
end: Position;
|
|
2559
|
+
severity: Severity;
|
|
2560
|
+
fix?: IEdit;
|
|
2561
|
+
}
|
|
2562
|
+
|
|
2546
2563
|
declare interface IKeyword {
|
|
2547
2564
|
word: string;
|
|
2548
2565
|
source: string[];
|
|
@@ -2628,6 +2645,7 @@ declare namespace Info {
|
|
|
2628
2645
|
InfoMethodParameter,
|
|
2629
2646
|
InfoMethodDefinition,
|
|
2630
2647
|
InfoInterfaceDefinition,
|
|
2648
|
+
InfoConstant,
|
|
2631
2649
|
InfoAlias,
|
|
2632
2650
|
InfoImplementing,
|
|
2633
2651
|
InfoClassDefinition,
|
|
@@ -2667,6 +2685,14 @@ declare interface InfoClassImplementation {
|
|
|
2667
2685
|
methods: readonly Identifier[];
|
|
2668
2686
|
}
|
|
2669
2687
|
|
|
2688
|
+
declare interface InfoConstant {
|
|
2689
|
+
identifier: Identifier;
|
|
2690
|
+
name: string;
|
|
2691
|
+
typeName: string;
|
|
2692
|
+
visibility: Visibility;
|
|
2693
|
+
value: string;
|
|
2694
|
+
}
|
|
2695
|
+
|
|
2670
2696
|
declare interface InfoFormDefinition {
|
|
2671
2697
|
name: string;
|
|
2672
2698
|
identifier: Identifier;
|
|
@@ -2688,6 +2714,7 @@ declare interface InfoInterfaceDefinition {
|
|
|
2688
2714
|
interfaces: readonly InfoImplementing[];
|
|
2689
2715
|
methods: readonly InfoMethodDefinition[];
|
|
2690
2716
|
aliases: readonly InfoAlias[];
|
|
2717
|
+
constants: readonly InfoConstant[];
|
|
2691
2718
|
attributes: readonly InfoAttribute[];
|
|
2692
2719
|
}
|
|
2693
2720
|
|
|
@@ -3073,7 +3100,8 @@ export declare class Issue {
|
|
|
3073
3100
|
static atRange(file: IFile, start: Position, end: Position, message: string, key: string, severity?: Severity, fix?: IEdit): Issue;
|
|
3074
3101
|
static atToken(file: IFile, token: Token, message: string, key: string, severity?: Severity, fix?: IEdit): Issue;
|
|
3075
3102
|
static atIdentifier(identifier: Identifier, message: string, key: string, severity?: Severity, fix?: IEdit): Issue;
|
|
3076
|
-
|
|
3103
|
+
constructor(data: IIssueData);
|
|
3104
|
+
getData(): IIssueData;
|
|
3077
3105
|
getMessage(): string;
|
|
3078
3106
|
getKey(): string;
|
|
3079
3107
|
getStart(): Position;
|
|
@@ -3646,6 +3674,7 @@ declare namespace Objects {
|
|
|
3646
3674
|
DataElement,
|
|
3647
3675
|
DialogModule,
|
|
3648
3676
|
Documentation,
|
|
3677
|
+
DomainValue,
|
|
3649
3678
|
Domain,
|
|
3650
3679
|
EcattTestConfiguration,
|
|
3651
3680
|
EcattTestDataContainer,
|
|
@@ -5660,6 +5689,7 @@ export declare enum Version {
|
|
|
5660
5689
|
v753 = "v753",
|
|
5661
5690
|
v754 = "v754",
|
|
5662
5691
|
v755 = "v755",
|
|
5692
|
+
v756 = "v756",
|
|
5663
5693
|
Cloud = "Cloud"
|
|
5664
5694
|
}
|
|
5665
5695
|
|
|
@@ -76,7 +76,7 @@ class ABAPFileInformation {
|
|
|
76
76
|
this.implementations.push({
|
|
77
77
|
name: name.getStr(),
|
|
78
78
|
identifier: new _identifier_1.Identifier(name, this.filename),
|
|
79
|
-
methods
|
|
79
|
+
methods,
|
|
80
80
|
});
|
|
81
81
|
}
|
|
82
82
|
for (const statement of structure.findAllStructures(Structures.Form)) {
|
|
@@ -100,6 +100,7 @@ class ABAPFileInformation {
|
|
|
100
100
|
const methods = this.parseMethodDefinition(found, visibility_1.Visibility.Public);
|
|
101
101
|
const attributes = this.parseAttributes(found, visibility_1.Visibility.Public);
|
|
102
102
|
const aliases = this.parseAliases(found, visibility_1.Visibility.Public);
|
|
103
|
+
const constants = this.parseConstants(found, visibility_1.Visibility.Public);
|
|
103
104
|
const g = i.findDirectExpression(Expressions.ClassGlobal);
|
|
104
105
|
this.interfaces.push({
|
|
105
106
|
name: interfaceName.getStr(),
|
|
@@ -109,6 +110,7 @@ class ABAPFileInformation {
|
|
|
109
110
|
interfaces: this.getImplementing(found),
|
|
110
111
|
aliases,
|
|
111
112
|
methods,
|
|
113
|
+
constants,
|
|
112
114
|
attributes,
|
|
113
115
|
});
|
|
114
116
|
}
|
|
@@ -126,6 +128,9 @@ class ABAPFileInformation {
|
|
|
126
128
|
const aliases = this.parseAliases(found.findFirstStructure(Structures.PublicSection), visibility_1.Visibility.Public);
|
|
127
129
|
aliases.push(...this.parseAliases(found.findFirstStructure(Structures.ProtectedSection), visibility_1.Visibility.Protected));
|
|
128
130
|
aliases.push(...this.parseAliases(found.findFirstStructure(Structures.PrivateSection), visibility_1.Visibility.Private));
|
|
131
|
+
const constants = this.parseConstants(found.findFirstStructure(Structures.PublicSection), visibility_1.Visibility.Public);
|
|
132
|
+
constants.push(...this.parseConstants(found.findFirstStructure(Structures.ProtectedSection), visibility_1.Visibility.Protected));
|
|
133
|
+
constants.push(...this.parseConstants(found.findFirstStructure(Structures.PrivateSection), visibility_1.Visibility.Private));
|
|
129
134
|
const superClassName = (_a = found.findFirstExpression(Expressions.SuperClassName)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr();
|
|
130
135
|
const containsGlobal = found.findFirstExpression(Expressions.ClassGlobal);
|
|
131
136
|
const concat = found.findFirstStatement(Statements.ClassDefinition).concatTokens().toUpperCase();
|
|
@@ -142,6 +147,7 @@ class ABAPFileInformation {
|
|
|
142
147
|
isFinal: found.findFirstExpression(Expressions.ClassFinal) !== undefined,
|
|
143
148
|
aliases,
|
|
144
149
|
attributes,
|
|
150
|
+
constants,
|
|
145
151
|
});
|
|
146
152
|
}
|
|
147
153
|
}
|
|
@@ -194,6 +200,29 @@ class ABAPFileInformation {
|
|
|
194
200
|
}
|
|
195
201
|
return ret;
|
|
196
202
|
}
|
|
203
|
+
parseConstants(node, visibility) {
|
|
204
|
+
var _a, _b;
|
|
205
|
+
if (node === undefined) {
|
|
206
|
+
return [];
|
|
207
|
+
}
|
|
208
|
+
const results = [];
|
|
209
|
+
for (const constant of node.findAllStatements(Statements.Constant)) {
|
|
210
|
+
const name = constant.findFirstExpression(Expressions.DefinitionName).getFirstToken();
|
|
211
|
+
const typeName = constant.findFirstExpression(Expressions.TypeName);
|
|
212
|
+
// VALUE `const_value` -> `const_value`
|
|
213
|
+
const literal = (_b = (_a = constant.findFirstExpression(Expressions.Value)) === null || _a === void 0 ? void 0 : _a.getTokens()[1].getStr()) !== null && _b !== void 0 ? _b : "``";
|
|
214
|
+
// `const_value` -> const_value
|
|
215
|
+
const value = literal.slice(1, (literal === null || literal === void 0 ? void 0 : literal.length) - 1);
|
|
216
|
+
results.push({
|
|
217
|
+
name: name.getStr(),
|
|
218
|
+
typeName: typeName ? typeName.getFirstToken().getStr() : "",
|
|
219
|
+
value: value,
|
|
220
|
+
identifier: new _identifier_1.Identifier(name, this.filename),
|
|
221
|
+
visibility,
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
return results;
|
|
225
|
+
}
|
|
197
226
|
parseAttributes(node, visibility) {
|
|
198
227
|
if (node === undefined) {
|
|
199
228
|
return [];
|
|
@@ -20,6 +20,7 @@ class TypeUtils {
|
|
|
20
20
|
|| type instanceof basic_1.AnyType
|
|
21
21
|
|| type instanceof basic_1.UnknownType
|
|
22
22
|
|| type instanceof basic_1.NumericType
|
|
23
|
+
|| type instanceof basic_1.CSequenceType
|
|
23
24
|
|| type instanceof basic_1.DateType
|
|
24
25
|
|| type instanceof basic_1.CLikeType
|
|
25
26
|
|| type instanceof basic_1.PackedType
|
|
@@ -18,6 +18,12 @@ class FieldAssignment {
|
|
|
18
18
|
let type = undefined;
|
|
19
19
|
if (targetType instanceof basic_1.StructureType) {
|
|
20
20
|
type = targetType.getComponentByName(name);
|
|
21
|
+
if (type === undefined && targetType.containsVoid() === false) {
|
|
22
|
+
throw new Error(`field ${name} does not exist in structure`);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else if (targetType instanceof basic_1.VoidType) {
|
|
26
|
+
type = targetType;
|
|
21
27
|
}
|
|
22
28
|
new source_1.Source().runSyntax(s, scope, filename, type);
|
|
23
29
|
}
|
package/build/src/issue.js
CHANGED
|
@@ -70,7 +70,7 @@ class SemanticHighlighting {
|
|
|
70
70
|
|| statementInstance instanceof Statements.MethodImplementation
|
|
71
71
|
|| statementInstance instanceof Statements.EndMethod
|
|
72
72
|
|| statementInstance instanceof Statements.EndClass
|
|
73
|
-
|| statementInstance instanceof Statements.
|
|
73
|
+
|| statementInstance instanceof Statements.Interface
|
|
74
74
|
|| statementInstance instanceof Statements.EndInterface
|
|
75
75
|
|| statementInstance instanceof Statements.Form
|
|
76
76
|
|| statementInstance instanceof Statements.EndForm) {
|
|
@@ -35,7 +35,7 @@ class Domain extends _abstract_object_1.AbstractObject {
|
|
|
35
35
|
return this.parsedType;
|
|
36
36
|
}
|
|
37
37
|
parse() {
|
|
38
|
-
var _a, _b, _c;
|
|
38
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
39
39
|
if (this.parsedXML) {
|
|
40
40
|
return { updated: false, runtime: 0 };
|
|
41
41
|
}
|
|
@@ -46,15 +46,32 @@ class Domain extends _abstract_object_1.AbstractObject {
|
|
|
46
46
|
return { updated: false, runtime: 0 };
|
|
47
47
|
}
|
|
48
48
|
const dd01v = (_c = (_b = (_a = parsed.abapGit) === null || _a === void 0 ? void 0 : _a["asx:abap"]) === null || _b === void 0 ? void 0 : _b["asx:values"]) === null || _c === void 0 ? void 0 : _c.DD01V;
|
|
49
|
+
const dd07v_tab = (_g = (_f = (_e = (_d = parsed.abapGit) === null || _d === void 0 ? void 0 : _d["asx:abap"]) === null || _e === void 0 ? void 0 : _e["asx:values"]) === null || _f === void 0 ? void 0 : _f.DD07V_TAB) === null || _g === void 0 ? void 0 : _g.DD07V;
|
|
50
|
+
const values = [];
|
|
51
|
+
if (dd07v_tab) {
|
|
52
|
+
for (const ddo7v of dd07v_tab) {
|
|
53
|
+
const value = {
|
|
54
|
+
description: ddo7v === null || ddo7v === void 0 ? void 0 : ddo7v.DDTEXT,
|
|
55
|
+
value: ddo7v === null || ddo7v === void 0 ? void 0 : ddo7v.DOMVALUE_L,
|
|
56
|
+
language: ddo7v === null || ddo7v === void 0 ? void 0 : ddo7v.DDLANGUAGE,
|
|
57
|
+
};
|
|
58
|
+
values.push(value);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
49
61
|
this.parsedXML = {
|
|
50
62
|
description: dd01v === null || dd01v === void 0 ? void 0 : dd01v.DDTEXT,
|
|
51
63
|
datatype: dd01v === null || dd01v === void 0 ? void 0 : dd01v.DATATYPE,
|
|
52
64
|
length: dd01v === null || dd01v === void 0 ? void 0 : dd01v.LENG,
|
|
53
65
|
decimals: dd01v === null || dd01v === void 0 ? void 0 : dd01v.DECIMALS,
|
|
66
|
+
values: values,
|
|
54
67
|
};
|
|
55
68
|
const end = Date.now();
|
|
56
69
|
return { updated: true, runtime: end - start };
|
|
57
70
|
}
|
|
71
|
+
getFixedValues() {
|
|
72
|
+
var _a, _b;
|
|
73
|
+
return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
|
|
74
|
+
}
|
|
58
75
|
}
|
|
59
76
|
exports.Domain = Domain;
|
|
60
77
|
//# sourceMappingURL=domain.js.map
|
package/build/src/registry.js
CHANGED
|
@@ -4,7 +4,9 @@ exports.CheckSyntax = exports.CheckSyntaxConf = void 0;
|
|
|
4
4
|
const syntax_1 = require("../abap/5_syntax/syntax");
|
|
5
5
|
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
6
6
|
const _abap_object_1 = require("../objects/_abap_object");
|
|
7
|
+
const issue_1 = require("../issue");
|
|
7
8
|
const _irule_1 = require("./_irule");
|
|
9
|
+
const severity_1 = require("../severity");
|
|
8
10
|
class CheckSyntaxConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
9
11
|
}
|
|
10
12
|
exports.CheckSyntaxConf = CheckSyntaxConf;
|
|
@@ -34,7 +36,17 @@ class CheckSyntax {
|
|
|
34
36
|
if (!(obj instanceof _abap_object_1.ABAPObject)) {
|
|
35
37
|
return [];
|
|
36
38
|
}
|
|
37
|
-
|
|
39
|
+
const issues = new syntax_1.SyntaxLogic(this.reg, obj).run().issues;
|
|
40
|
+
// the syntax logic does not know the rule severity when its run
|
|
41
|
+
if (this.conf.severity
|
|
42
|
+
&& this.conf.severity !== severity_1.Severity.Error) {
|
|
43
|
+
issues.forEach((value, index) => {
|
|
44
|
+
const data = value.getData();
|
|
45
|
+
data.severity = this.conf.severity;
|
|
46
|
+
issues[index] = new issue_1.Issue(data);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
return issues;
|
|
38
50
|
}
|
|
39
51
|
}
|
|
40
52
|
exports.CheckSyntax = CheckSyntax;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConstantClasses = exports.ConstantClassesConf = 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
|
+
/** Checks that constants classes are in sync with domain fixed values */
|
|
9
|
+
class ConstantClassesConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
10
|
+
}
|
|
11
|
+
exports.ConstantClassesConf = ConstantClassesConf;
|
|
12
|
+
class ConstantClasses {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.conf = new ConstantClassesConf();
|
|
15
|
+
}
|
|
16
|
+
getMetadata() {
|
|
17
|
+
return {
|
|
18
|
+
key: "constant_classes",
|
|
19
|
+
title: "Validate constant classes",
|
|
20
|
+
shortDescription: `Checks that a class contains exactly the constants corresponding to a domain's fixed values.`,
|
|
21
|
+
extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-enumeration-classes-to-constants-interfaces`,
|
|
22
|
+
tags: [_irule_1.RuleTag.Syntax, _irule_1.RuleTag.Styleguide, _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
|
+
if (this.conf
|
|
37
|
+
&& this.conf.mapping
|
|
38
|
+
&& obj instanceof __1.Objects.Domain) {
|
|
39
|
+
const configEntry = this.conf.mapping.find(x => x.domain.toUpperCase() === obj.getName().toUpperCase());
|
|
40
|
+
if (!configEntry) {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
const classWithConstants = this.reg.getObject("CLAS", configEntry === null || configEntry === void 0 ? void 0 : configEntry.class.toUpperCase());
|
|
44
|
+
if (!classWithConstants) {
|
|
45
|
+
return [issue_1.Issue.atIdentifier(obj.getIdentifier(), `Constant class pattern implementation ${configEntry.class} missing for domain ${configEntry.domain}`, this.getMetadata().key, this.conf.severity)];
|
|
46
|
+
// quickfix will implement the whole class
|
|
47
|
+
}
|
|
48
|
+
const classContents = classWithConstants.getMainABAPFile();
|
|
49
|
+
if (classContents === undefined) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
const def = classWithConstants.getClassDefinition();
|
|
53
|
+
if (!def) {
|
|
54
|
+
// this issue is checked by rule implement_methods.
|
|
55
|
+
// we will not issue errors that all constants are missing until there is a class implementation
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
const domainValueInfo = obj.getFixedValues();
|
|
59
|
+
const domainValues = domainValueInfo.map(x => x.value);
|
|
60
|
+
const issues = [];
|
|
61
|
+
if (obj.getFixedValues().length === 0) {
|
|
62
|
+
// possibly this is not even a domain with fixed values
|
|
63
|
+
issues.push(issue_1.Issue.atStatement(classContents, classContents.getStatements()[0], `Domain ${configEntry.domain} does not contain any fixed values. Either add some values or disable this check`, this.getMetadata().key, this.conf.severity));
|
|
64
|
+
}
|
|
65
|
+
// later we will raise an issue if we did not find it
|
|
66
|
+
let domainNameConstantFound = false;
|
|
67
|
+
for (const constant of def.constants) {
|
|
68
|
+
if (configEntry.constantForDomainName
|
|
69
|
+
&& constant.name === configEntry.constantForDomainName) {
|
|
70
|
+
// we require the constant value to be uppercase just in case
|
|
71
|
+
// in the config it does not matter
|
|
72
|
+
if (constant.value !== configEntry.domain.toLocaleUpperCase()) {
|
|
73
|
+
issues.push(this.issueAtConstant(constant, `Constant value ${constant.value} must match domain name ${configEntry.domain} `));
|
|
74
|
+
}
|
|
75
|
+
domainNameConstantFound = true;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (configEntry.useExactType && constant.typeName.toLowerCase() !== configEntry.domain.toLowerCase()) {
|
|
79
|
+
issues.push(this.issueAtConstant(constant, `Use exact type ${configEntry.domain} instead of ${constant.typeName}`));
|
|
80
|
+
// quickfix will change the type
|
|
81
|
+
}
|
|
82
|
+
if (constant.visibility !== __1.Visibility.Public) {
|
|
83
|
+
issues.push(this.issueAtConstant(constant, `Constant ${constant.name} should be public`));
|
|
84
|
+
// quickfix will move constant
|
|
85
|
+
}
|
|
86
|
+
if (!domainValues.includes(constant.value)) {
|
|
87
|
+
issues.push(this.issueAtConstant(constant, `Extra constant ${constant.name} found which is not present in domain ${configEntry.domain}`));
|
|
88
|
+
// quickfix will remove constant
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const d of domainValueInfo) {
|
|
92
|
+
if (!def.constants.find(c => c.value === d.value)) {
|
|
93
|
+
issues.push(issue_1.Issue.atStatement(classContents, classContents.getStatements()[0], `Missing constant for ${d.value} (domain ${configEntry.domain})`, this.getMetadata().key, this.conf.severity));
|
|
94
|
+
// quickfix will add constant
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (configEntry.constantForDomainName && !domainNameConstantFound) {
|
|
98
|
+
issues.push(issue_1.Issue.atStatement(classContents, classContents.getStatements()[0], `Missing constant ${configEntry.constantForDomainName} for name of domain ${configEntry.domain}`, this.getMetadata().key, this.conf.severity));
|
|
99
|
+
}
|
|
100
|
+
return issues;
|
|
101
|
+
}
|
|
102
|
+
return [];
|
|
103
|
+
}
|
|
104
|
+
issueAtConstant(constant, message) {
|
|
105
|
+
return issue_1.Issue.atIdentifier(constant.identifier, message, this.getMetadata().key, this.conf.severity);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
exports.ConstantClasses = ConstantClasses;
|
|
109
|
+
//# sourceMappingURL=constant_classes.js.map
|
package/build/src/rules/index.js
CHANGED
|
@@ -142,4 +142,5 @@ __exportStar(require("./use_new"), exports);
|
|
|
142
142
|
__exportStar(require("./when_others_last"), exports);
|
|
143
143
|
__exportStar(require("./whitespace_end"), exports);
|
|
144
144
|
__exportStar(require("./xml_consistency"), exports);
|
|
145
|
+
__exportStar(require("./constant_classes"), exports);
|
|
145
146
|
//# sourceMappingURL=index.js.map
|
|
@@ -61,6 +61,8 @@ class ObsoleteStatementConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
|
61
61
|
this.sortByFS = true;
|
|
62
62
|
/** Checks for CALL TRANSFORMATION OBJECTS */
|
|
63
63
|
this.callTransformation = true;
|
|
64
|
+
/** Check for POSIX REGEX usage */
|
|
65
|
+
this.regex = true;
|
|
64
66
|
}
|
|
65
67
|
}
|
|
66
68
|
exports.ObsoleteStatementConf = ObsoleteStatementConf;
|
|
@@ -109,7 +111,9 @@ FREE MEMORY: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-us/abapfree
|
|
|
109
111
|
|
|
110
112
|
SORT BY FS: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abapsort_itab_obsolete.htm
|
|
111
113
|
|
|
112
|
-
CALL TRANSFORMATION OBJECTS: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abapcall_transformation_objects.htm
|
|
114
|
+
CALL TRANSFORMATION OBJECTS: https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-US/abapcall_transformation_objects.htm
|
|
115
|
+
|
|
116
|
+
POSIX REGEX: https://help.sap.com/doc/abapdocu_755_index_htm/7.55/en-US/index.htm`,
|
|
113
117
|
};
|
|
114
118
|
}
|
|
115
119
|
getConfig() {
|
|
@@ -266,6 +270,35 @@ CALL TRANSFORMATION OBJECTS: https://help.sap.com/doc/abapdocu_752_index_htm/7.5
|
|
|
266
270
|
issues.push(issue);
|
|
267
271
|
}
|
|
268
272
|
}
|
|
273
|
+
if (configVersion >= version_1.Version.v756 && this.conf.regex) {
|
|
274
|
+
if (sta instanceof Statements.Find || sta instanceof Statements.Replace) {
|
|
275
|
+
const concat = staNode.concatTokens().toUpperCase();
|
|
276
|
+
if (concat.includes("REGEX")) {
|
|
277
|
+
const issue = issue_1.Issue.atStatement(file, staNode, "REGEX obsolete, use PCRE", this.getMetadata().key, this.conf.severity);
|
|
278
|
+
issues.push(issue);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
const classNameExpression = staNode.findAllExpressions(Expressions.ClassName);
|
|
283
|
+
const methodNameExpression = staNode.findAllExpressions(Expressions.MethodName);
|
|
284
|
+
if (classNameExpression.length !== 0 && methodNameExpression.length !== 0) {
|
|
285
|
+
const className = classNameExpression[0].concatTokens();
|
|
286
|
+
const methodName = methodNameExpression[0].concatTokens();
|
|
287
|
+
if (className === "cl_abap_regex") {
|
|
288
|
+
if (methodName === "create_posix") {
|
|
289
|
+
const issue = issue_1.Issue.atStatement(file, staNode, "create_posix obsolete, use create_pcre", this.getMetadata().key, this.conf.severity);
|
|
290
|
+
issues.push(issue);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
else if (className === "cl_abap_matcher") {
|
|
294
|
+
if (methodName.includes("posix")) {
|
|
295
|
+
const issue = issue_1.Issue.atStatement(file, staNode, "posix methods obsolete, use pcre methods", this.getMetadata().key, this.conf.severity);
|
|
296
|
+
issues.push(issue);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
269
302
|
}
|
|
270
303
|
return issues;
|
|
271
304
|
}
|
package/build/src/version.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.79.3",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
},
|
|
55
55
|
"homepage": "https://abaplint.org",
|
|
56
56
|
"devDependencies": {
|
|
57
|
-
"@microsoft/api-extractor": "^7.18.
|
|
57
|
+
"@microsoft/api-extractor": "^7.18.9",
|
|
58
58
|
"@types/chai": "^4.2.21",
|
|
59
59
|
"@types/mocha": "^9.0.0",
|
|
60
|
-
"@types/node": "^16.9.
|
|
60
|
+
"@types/node": "^16.9.2",
|
|
61
61
|
"chai": "^4.3.4",
|
|
62
62
|
"eslint": "^7.32.0",
|
|
63
63
|
"madge": "^5.0.1",
|