@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.
@@ -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
- private constructor();
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
  }
@@ -97,6 +97,9 @@ class Issue {
97
97
  fix,
98
98
  });
99
99
  }
100
+ getData() {
101
+ return this.data;
102
+ }
100
103
  getMessage() {
101
104
  return this.data.message;
102
105
  }
@@ -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.InterfaceDef
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
@@ -68,7 +68,7 @@ class Registry {
68
68
  }
69
69
  static abaplintVersion() {
70
70
  // magic, see build script "version.sh"
71
- return "2.78.13";
71
+ return "2.79.3";
72
72
  }
73
73
  getDDICReferences() {
74
74
  return this.references;
@@ -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
- return new syntax_1.SyntaxLogic(this.reg, obj).run().issues;
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
@@ -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
  }
@@ -15,6 +15,7 @@ var Version;
15
15
  Version["v753"] = "v753";
16
16
  Version["v754"] = "v754";
17
17
  Version["v755"] = "v755";
18
+ Version["v756"] = "v756";
18
19
  Version["Cloud"] = "Cloud";
19
20
  })(Version = exports.Version || (exports.Version = {}));
20
21
  exports.defaultVersion = Version.v755;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.78.13",
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.7",
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.1",
60
+ "@types/node": "^16.9.2",
61
61
  "chai": "^4.3.4",
62
62
  "eslint": "^7.32.0",
63
63
  "madge": "^5.0.1",