@abaplint/core 2.105.4 → 2.105.6

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.
@@ -7,7 +7,6 @@ const position_1 = require("../../position");
7
7
  const spaghetti_scope_1 = require("./spaghetti_scope");
8
8
  const _identifier_1 = require("../4_file_information/_identifier");
9
9
  const _scope_type_1 = require("./_scope_type");
10
- const _reference_1 = require("./_reference");
11
10
  const syntax_1 = require("./syntax");
12
11
  class CurrentScope {
13
12
  static buildDefault(reg, obj) {
@@ -99,8 +98,14 @@ class CurrentScope {
99
98
  this.current.getData().forms.push(...f);
100
99
  }
101
100
  addInterfaceDefinition(i) {
102
- var _a;
103
- (_a = this.current) === null || _a === void 0 ? void 0 : _a.getData().idefs.push(i);
101
+ if (this.current === undefined) {
102
+ return;
103
+ }
104
+ const name = i.getName().toUpperCase();
105
+ if (this.current.getData().cdefs[name] !== undefined) {
106
+ throw new Error(`Interface "${name}" already defined`);
107
+ }
108
+ this.current.getData().idefs[name] = i;
104
109
  }
105
110
  addNamedIdentifier(name, identifier) {
106
111
  if (this.current === undefined) {
@@ -195,11 +200,10 @@ class CurrentScope {
195
200
  }
196
201
  return false;
197
202
  }
198
- // todo, found + type can be removed from method output?
199
203
  existsObject(name) {
200
204
  var _a, _b, _c;
201
205
  if (name === undefined) {
202
- return { found: false };
206
+ return undefined;
203
207
  }
204
208
  let prefixRTTI = "";
205
209
  if (this.parentObj.getType() === "PROG") {
@@ -213,28 +217,28 @@ class CurrentScope {
213
217
  if (findLocalClass.isGlobal() === true) {
214
218
  prefixRTTI = "";
215
219
  }
216
- return { found: true, id: findLocalClass, type: _reference_1.ReferenceType.ObjectOrientedReference, ooType: "CLAS", RTTIName: prefixRTTI + "\\CLASS=" + findLocalClass.getName() };
220
+ return { id: findLocalClass, ooType: "CLAS", RTTIName: prefixRTTI + "\\CLASS=" + findLocalClass.getName() };
217
221
  }
218
222
  const globalClas = this.reg.getObject("CLAS", name);
219
223
  if (globalClas) {
220
- return { found: true, id: globalClas.getIdentifier(), type: _reference_1.ReferenceType.ObjectOrientedReference, ooType: "CLAS", RTTIName: "\\CLASS=" + globalClas.getName() };
224
+ return { id: globalClas.getIdentifier(), ooType: "CLAS", RTTIName: "\\CLASS=" + globalClas.getName() };
221
225
  }
222
226
  const findLocalInterface = (_b = this.current) === null || _b === void 0 ? void 0 : _b.findInterfaceDefinition(name);
223
227
  if (findLocalInterface) {
224
228
  if (findLocalInterface.isGlobal() === true) {
225
229
  prefixRTTI = "";
226
230
  }
227
- return { found: true, id: findLocalInterface, type: _reference_1.ReferenceType.ObjectOrientedReference, ooType: "INTF", RTTIName: prefixRTTI + "\\INTERFACE=" + findLocalInterface.getName() };
231
+ return { id: findLocalInterface, ooType: "INTF", RTTIName: prefixRTTI + "\\INTERFACE=" + findLocalInterface.getName() };
228
232
  }
229
233
  const globalIntf = this.reg.getObject("INTF", name);
230
234
  if (globalIntf) {
231
- return { found: true, id: globalIntf.getIdentifier(), type: _reference_1.ReferenceType.ObjectOrientedReference, ooType: "INTF", RTTIName: "\\INTERFACE=" + globalIntf.getName() };
235
+ return { id: globalIntf.getIdentifier(), ooType: "INTF", RTTIName: "\\INTERFACE=" + globalIntf.getName() };
232
236
  }
233
237
  const def = (_c = this.current) === null || _c === void 0 ? void 0 : _c.findDeferred(name);
234
238
  if (def !== undefined) {
235
- return { found: true, id: def };
239
+ return { id: def };
236
240
  }
237
- return { found: false };
241
+ return undefined;
238
242
  }
239
243
  ///////////////////////////
240
244
  /** Lookup class in local and global scope */
@@ -771,7 +771,7 @@ class BasicTypes {
771
771
  else if (firstNode.get() instanceof Expressions.ClassName) {
772
772
  const obj = this.scope.findObjectDefinition(firstName);
773
773
  if (obj === undefined) {
774
- if (this.scope.existsObject(firstName).found === true) {
774
+ if (this.scope.existsObject(firstName) !== undefined) {
775
775
  return undefined;
776
776
  }
777
777
  else if (this.scope.getDDIC().inErrorNamespace(firstName) === true) {
@@ -818,7 +818,7 @@ class BasicTypes {
818
818
  return new Types.GenericObjectReferenceType();
819
819
  }
820
820
  const search = this.scope.existsObject(name);
821
- if (search.found === true && search.id) {
821
+ if (search === null || search === void 0 ? void 0 : search.id) {
822
822
  this.scope.addReference(chain.getFirstToken(), search.id, _reference_1.ReferenceType.ObjectOrientedReference, this.filename, { ooType: search.ooType, ooName: name });
823
823
  return new Types.ObjectReferenceType(search.id, { qualifiedName: name, RTTIName: search.RTTIName });
824
824
  }
@@ -171,8 +171,8 @@ class FieldChain {
171
171
  return new basic_1.GenericObjectReferenceType();
172
172
  }
173
173
  const found = scope.existsObject(classNam);
174
- if (found.found === true && found.id) {
175
- scope.addReference(classTok, found.id, found.type, filename);
174
+ if (found === null || found === void 0 ? void 0 : found.id) {
175
+ scope.addReference(classTok, found.id, _reference_1.ReferenceType.ObjectOrientedReference, filename);
176
176
  return new basic_1.ObjectReferenceType(found.id);
177
177
  }
178
178
  else if (scope.getDDIC().inErrorNamespace(classNam) === false) {
@@ -29,8 +29,13 @@ class MethodCallParam {
29
29
  else if (child instanceof nodes_1.ExpressionNode
30
30
  && (child.get() instanceof Expressions.Source
31
31
  || child.get() instanceof Expressions.ConstantString)) {
32
- if (!(method instanceof basic_1.VoidType) && method.getParameters().getImporting().length === 0) {
33
- throw new Error("Method \"" + method.getName() + "\" has no importing parameters");
32
+ if (!(method instanceof basic_1.VoidType)) {
33
+ if (method.getParameters().getImporting().length === 0) {
34
+ throw new Error("Method \"" + method.getName() + "\" has no importing parameters");
35
+ }
36
+ else if (method.getParameters().getRequiredParameters().length > 1) {
37
+ throw new Error("Method \"" + method.getName() + "\" has more than one importing or changing parameter");
38
+ }
34
39
  }
35
40
  let targetType = undefined;
36
41
  if (!(method instanceof basic_1.VoidType)) {
@@ -23,6 +23,12 @@ class NewObject {
23
23
  if (clas) {
24
24
  scope.addReference(typeToken, clas, _reference_1.ReferenceType.InferredType, filename);
25
25
  }
26
+ else {
27
+ const intf = scope.findInterfaceDefinition(targetType.getIdentifierName());
28
+ if (intf) {
29
+ throw new Error(intf.getName() + " is an interface, cannot be instantiated");
30
+ }
31
+ }
26
32
  ret = targetType;
27
33
  if ((clas === null || clas === void 0 ? void 0 : clas.isAbstract()) === true) {
28
34
  throw new Error(clas.getName() + " is abstract, cannot be instantiated");
@@ -12,6 +12,7 @@ const field_offset_1 = require("./field_offset");
12
12
  const _reference_1 = require("../_reference");
13
13
  const table_expression_1 = require("./table_expression");
14
14
  const expressions_1 = require("../../2_statements/expressions");
15
+ const field_length_1 = require("./field_length");
15
16
  class Target {
16
17
  runSyntax(node, scope, filename) {
17
18
  const concat = node.concatTokens();
@@ -94,8 +95,18 @@ class Target {
94
95
  }
95
96
  const offset = node.findDirectExpression(Expressions.FieldOffset);
96
97
  if (offset) {
98
+ if (context instanceof basic_1.XStringType || context instanceof basic_1.StringType) {
99
+ throw new Error("xstring/string offset/length in writer position not possible");
100
+ }
97
101
  new field_offset_1.FieldOffset().runSyntax(offset, scope, filename);
98
102
  }
103
+ const length = node.findDirectExpression(Expressions.FieldLength);
104
+ if (length) {
105
+ if (context instanceof basic_1.XStringType || context instanceof basic_1.StringType) {
106
+ throw new Error("xstring/string offset/length in writer position not possible");
107
+ }
108
+ new field_length_1.FieldLength().runSyntax(length, scope, filename);
109
+ }
99
110
  return context;
100
111
  }
101
112
  /////////////////////////////////
@@ -9,7 +9,7 @@ class ScopeData {
9
9
  this.data = {
10
10
  vars: {},
11
11
  cdefs: {},
12
- idefs: [], // todo, refactor to object
12
+ idefs: {},
13
13
  forms: [], // todo, refactor to object
14
14
  types: {},
15
15
  extraLikeTypes: {},
@@ -111,26 +111,13 @@ class SpaghettiScopeNode extends ScopeData {
111
111
  }
112
112
  return undefined;
113
113
  }
114
- // todo, can be deleted, not called from anywhere?
115
- listFormDefinitions() {
116
- let search = this;
117
- const ret = [];
118
- while (search !== undefined) {
119
- for (const form of search.getData().forms) {
120
- ret.push(form);
121
- }
122
- search = search.getParent();
123
- }
124
- return ret;
125
- }
126
- // todo, optimize
127
114
  findInterfaceDefinition(name) {
128
115
  let search = this;
116
+ const upper = name.toUpperCase();
129
117
  while (search !== undefined) {
130
- for (const idef of search.getData().idefs) {
131
- if (idef.getName().toUpperCase() === name.toUpperCase()) {
132
- return idef;
133
- }
118
+ const idef = search.getData().idefs[upper];
119
+ if (idef) {
120
+ return idef;
134
121
  }
135
122
  search = search.getParent();
136
123
  }
@@ -140,9 +127,9 @@ class SpaghettiScopeNode extends ScopeData {
140
127
  let search = this;
141
128
  const upper = name.toUpperCase();
142
129
  while (search !== undefined) {
143
- const data = search.getData();
144
- if (data.types[upper]) {
145
- return data.types[upper];
130
+ const found = search.getData().types[upper];
131
+ if (found) {
132
+ return found;
146
133
  }
147
134
  search = search.getParent();
148
135
  }
@@ -19,9 +19,9 @@ class Assign {
19
19
  const thirdAssign = assignSource === null || assignSource === void 0 ? void 0 : assignSource.getChildren()[2];
20
20
  if ((secondAssign === null || secondAssign === void 0 ? void 0 : secondAssign.concatTokens()) === "=>" && firstAssign && (thirdAssign === null || thirdAssign === void 0 ? void 0 : thirdAssign.get()) instanceof Expressions.Dynamic) {
21
21
  const name = firstAssign.concatTokens();
22
- const found = scope.findObjectDefinition(name) === undefined || scope.findVariable(name);
23
- if (found === undefined && scope.getDDIC().inErrorNamespace(name)) {
24
- throw new Error(secondAssign.concatTokens() + " not found");
22
+ const found = scope.findClassDefinition(name) || scope.findVariable(name);
23
+ if (found === undefined && scope.getDDIC().inErrorNamespace(name) && name.startsWith("(") === false) {
24
+ throw new Error(name + " not found, dynamic");
25
25
  }
26
26
  sourceType = new basic_1.VoidType("Dynamic");
27
27
  }
@@ -15,8 +15,8 @@ class Catch {
15
15
  const token = c.getFirstToken();
16
16
  const className = token.getStr().toUpperCase();
17
17
  const found = scope.existsObject(className);
18
- if (found.found === true && found.id) {
19
- scope.addReference(token, found.id, found.type, filename);
18
+ if (found === null || found === void 0 ? void 0 : found.id) {
19
+ scope.addReference(token, found.id, _reference_1.ReferenceType.ObjectOrientedReference, filename);
20
20
  }
21
21
  else if (scope.getDDIC().inErrorNamespace(className) === false) {
22
22
  const extra = { ooName: className, ooType: "Void" };
@@ -35,7 +35,7 @@ class Catch {
35
35
  if (target === null || target === void 0 ? void 0 : target.findDirectExpression(Expressions.InlineData)) {
36
36
  const token = (_b = target.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.getFirstToken();
37
37
  const found = scope.existsObject(firstClassName);
38
- if (token && found.found === true && firstClassName && found.id) {
38
+ if (token && firstClassName && (found === null || found === void 0 ? void 0 : found.id)) {
39
39
  const identifier = new _typed_identifier_1.TypedIdentifier(token, filename, new basic_1.ObjectReferenceType(found.id), ["inline" /* IdentifierMeta.InlineDefinition */]);
40
40
  scope.addIdentifier(identifier);
41
41
  scope.addReference(token, identifier, _reference_1.ReferenceType.DataWriteReference, filename);
@@ -26,7 +26,7 @@ class ClassLocalFriends {
26
26
  const className = classNames[i].concatTokens();
27
27
  // make sure to check also DEFINITION DEFERRED
28
28
  const found = scope.existsObject(className);
29
- if (found.found === false) {
29
+ if (found === undefined) {
30
30
  throw new Error(`Class ${className.toUpperCase()} not found`);
31
31
  }
32
32
  }
@@ -20,8 +20,8 @@ class Raise {
20
20
  const className = classTok === null || classTok === void 0 ? void 0 : classTok.getStr();
21
21
  if (className) {
22
22
  const found = scope.existsObject(className);
23
- if (found.found === true && found.id) {
24
- scope.addReference(classTok, found.id, found.type, filename);
23
+ if (found === null || found === void 0 ? void 0 : found.id) {
24
+ scope.addReference(classTok, found.id, _reference_1.ReferenceType.ObjectOrientedReference, filename);
25
25
  const def = scope.findObjectDefinition(className);
26
26
  method = (_b = helper.searchMethodName(def, "CONSTRUCTOR")) === null || _b === void 0 ? void 0 : _b.method;
27
27
  }
@@ -3,8 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VoidType = void 0;
4
4
  const _abstract_type_1 = require("./_abstract_type");
5
5
  class VoidType extends _abstract_type_1.AbstractType {
6
- constructor(voided, name) {
7
- super({ qualifiedName: name });
6
+ constructor(voided, qualifiedName) {
7
+ super({ qualifiedName: qualifiedName });
8
8
  this.voided = voided;
9
9
  }
10
10
  getVoided() {
@@ -8,8 +8,9 @@ class NeptuneAPI extends _abstract_object_1.AbstractObject {
8
8
  }
9
9
  getAllowedNaming() {
10
10
  return {
11
- maxLength: 30,
11
+ maxLength: 100,
12
12
  allowNamespace: true,
13
+ customRegex: /.*/i,
13
14
  };
14
15
  }
15
16
  getDescription() {
@@ -65,7 +65,7 @@ class Registry {
65
65
  }
66
66
  static abaplintVersion() {
67
67
  // magic, see build script "version.sh"
68
- return "2.105.4";
68
+ return "2.105.6";
69
69
  }
70
70
  getDDICReferences() {
71
71
  return this.ddicReferences;
@@ -13,6 +13,8 @@ class AbapdocConf extends _basic_rule_config_1.BasicRuleConfig {
13
13
  this.checkLocal = false;
14
14
  this.classDefinition = false;
15
15
  this.interfaceDefinition = false;
16
+ /** Ignores classes flagged as FOR TESTING */
17
+ this.ignoreTestClasses = true;
16
18
  }
17
19
  }
18
20
  exports.AbapdocConf = AbapdocConf;
@@ -52,8 +54,11 @@ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#abap-doc-on
52
54
  if (this.conf.checkLocal === false && classDef.isLocal === true) {
53
55
  continue;
54
56
  }
57
+ if (this.conf.ignoreTestClasses === true && classDef.isForTesting === true) {
58
+ continue;
59
+ }
55
60
  methods = methods.concat(classDef.methods.filter(m => m.visibility === visibility_1.Visibility.Public));
56
- if (this.getConfig().classDefinition === true) {
61
+ if (this.conf.classDefinition === true) {
57
62
  const previousRow = classDef.identifier.getStart().getRow() - 2;
58
63
  if (((_a = rows[previousRow]) === null || _a === void 0 ? void 0 : _a.trim().substring(0, 2)) !== "\"!") {
59
64
  const message = "Missing ABAP Doc for class " + classDef.identifier.getToken().getStr();
@@ -67,7 +72,7 @@ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#abap-doc-on
67
72
  continue;
68
73
  }
69
74
  methods = methods.concat(interfaceDef.methods);
70
- if (this.getConfig().interfaceDefinition === true) {
75
+ if (this.conf.interfaceDefinition === true) {
71
76
  const previousRow = interfaceDef.identifier.getStart().getRow() - 2;
72
77
  if (((_b = rows[previousRow]) === null || _b === void 0 ? void 0 : _b.trim().substring(0, 2)) !== "\"!") {
73
78
  const message = "Missing ABAP Doc for interface " + interfaceDef.identifier.getToken().getStr();
@@ -4,6 +4,7 @@ exports.AllowedObjectNaming = exports.AllowedObjectNamingConf = void 0;
4
4
  const issue_1 = require("../issue");
5
5
  const _irule_1 = require("./_irule");
6
6
  const _basic_rule_config_1 = require("./_basic_rule_config");
7
+ const NAME_REGEX = /^(\/[A-Z_\d]{3,8}\/)?[A-Z_\d<> ]+$/i;
7
8
  class AllowedObjectNamingConf extends _basic_rule_config_1.BasicRuleConfig {
8
9
  }
9
10
  exports.AllowedObjectNamingConf = AllowedObjectNamingConf;
@@ -43,7 +44,7 @@ class AllowedObjectNaming {
43
44
  message = "Name not allowed";
44
45
  }
45
46
  }
46
- else if (name.match(/^(\/[A-Z_\d]{3,8}\/)?[A-Z_\d<> ]+$/i) === null) {
47
+ else if (name.match(NAME_REGEX) === null) {
47
48
  message = "Name not allowed";
48
49
  }
49
50
  if (message.length > 0) {
@@ -17,8 +17,8 @@ class Conditions {
17
17
  push(e) {
18
18
  this.arr.push(e.concatTokens());
19
19
  }
20
- hasDuplicates() {
21
- return this.arr.some(x => this.arr.indexOf(x) !== this.arr.lastIndexOf(x));
20
+ findFirstDuplicate() {
21
+ return this.arr.find(x => this.arr.indexOf(x) !== this.arr.lastIndexOf(x));
22
22
  }
23
23
  }
24
24
  class IdenticalConditionsConf extends _basic_rule_config_1.BasicRuleConfig {
@@ -77,8 +77,9 @@ Prerequsites: code is pretty printed with identical cAsE`,
77
77
  return [];
78
78
  }
79
79
  }
80
- if (conditions.hasDuplicates()) {
81
- const message = "Identical conditions";
80
+ const duplicate = conditions.findFirstDuplicate();
81
+ if (duplicate) {
82
+ const message = "Identical conditions: " + duplicate;
82
83
  const issue = issue_1.Issue.atToken(file, node.getFirstToken(), message, this.getMetadata().key, this.conf.severity);
83
84
  return [issue];
84
85
  }
@@ -101,8 +102,9 @@ Prerequsites: code is pretty printed with identical cAsE`,
101
102
  conditions.push(c);
102
103
  }
103
104
  }
104
- if (conditions.hasDuplicates()) {
105
- const message = "Identical conditions";
105
+ const duplicate = conditions.findFirstDuplicate();
106
+ if (duplicate) {
107
+ const message = "Identical conditions: " + duplicate;
106
108
  const issue = issue_1.Issue.atStatement(file, i, message, this.getMetadata().key, this.conf.severity);
107
109
  return [issue];
108
110
  }
@@ -123,8 +125,9 @@ Prerequsites: code is pretty printed with identical cAsE`,
123
125
  conditions.push(s);
124
126
  }
125
127
  }
126
- if (conditions.hasDuplicates()) {
127
- const message = "Identical conditions";
128
+ const duplicate = conditions.findFirstDuplicate();
129
+ if (duplicate) {
130
+ const message = "Identical conditions: " + duplicate;
128
131
  const issue = issue_1.Issue.atStatement(file, i, message, this.getMetadata().key, this.conf.severity);
129
132
  return [issue];
130
133
  }
@@ -98,7 +98,8 @@ class UnknownTypes {
98
98
  }
99
99
  }
100
100
  }
101
- for (const v of nodeData.idefs) {
101
+ for (const name in nodeData.idefs) {
102
+ const v = nodeData.idefs[name];
102
103
  const found = this.checkParameters(v);
103
104
  if (found) {
104
105
  const message = "Contains unknown, " + found.found;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.105.4",
3
+ "version": "2.105.6",
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
  },
51
51
  "homepage": "https://abaplint.org",
52
52
  "devDependencies": {
53
- "@microsoft/api-extractor": "^7.38.5",
53
+ "@microsoft/api-extractor": "^7.39.0",
54
54
  "@types/chai": "^4.3.11",
55
55
  "@types/mocha": "^10.0.6",
56
56
  "@types/node": "^20.10.5",