@abaplint/core 2.105.16 → 2.105.18

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.
@@ -1378,7 +1378,7 @@ export declare class CurrentScope {
1378
1378
  addInterfaceDefinition(i: IInterfaceDefinition): void;
1379
1379
  addNamedIdentifier(name: string, identifier: TypedIdentifier): void;
1380
1380
  addIdentifier(identifier: TypedIdentifier | undefined): void;
1381
- addDeferred(token: Token | undefined): void;
1381
+ addDeferred(token: Token | undefined, type: "CLAS" | "INTF"): void;
1382
1382
  addListPrefix(identifiers: readonly TypedIdentifier[], prefix: string): void;
1383
1383
  addList(identifiers: readonly TypedIdentifier[]): void;
1384
1384
  addReference(usage: Token | undefined, referencing: Identifier | undefined, type: ReferenceType | ReferenceType[] | undefined, filename: string, extra?: IReferenceExtras): void;
@@ -1631,6 +1631,11 @@ declare class Default extends Expression {
1631
1631
  getRunnable(): IStatementRunnable;
1632
1632
  }
1633
1633
 
1634
+ declare type DeferredInformation = {
1635
+ token: Token;
1636
+ ooType: "CLAS" | "INTF";
1637
+ };
1638
+
1634
1639
  declare class Define implements IStructure {
1635
1640
  getMatcher(): IStructureRunnable;
1636
1641
  }
@@ -2055,6 +2060,7 @@ declare class ExpressionNode extends AbstractNode<ExpressionNode | TokenNode> {
2055
2060
  get(): IStatementRunnable;
2056
2061
  countTokens(): number;
2057
2062
  getFirstToken(): Token;
2063
+ concatTokensWithLinebreaks(): string;
2058
2064
  concatTokens(): string;
2059
2065
  concatTokensWithoutStringsAndComments(): string;
2060
2066
  getTokens(): readonly Token[];
@@ -3704,7 +3710,7 @@ declare interface IScopeData {
3704
3710
  [name: string]: TypedIdentifier;
3705
3711
  };
3706
3712
  deferred: {
3707
- [name: string]: Token;
3713
+ [name: string]: DeferredInformation;
3708
3714
  };
3709
3715
  cdefs: {
3710
3716
  [name: string]: IClassDefinition;
@@ -5701,7 +5707,10 @@ export declare class SpaghettiScopeNode extends ScopeData implements ISpaghettiS
5701
5707
  end: Position;
5702
5708
  };
5703
5709
  setEnd(end: Position): void;
5704
- findDeferred(name: string): Identifier | undefined;
5710
+ findDeferred(name: string): {
5711
+ id: Identifier | undefined;
5712
+ ooType: "CLAS" | "INTF";
5713
+ } | undefined;
5705
5714
  findClassDefinition(name: string): IClassDefinition | undefined;
5706
5715
  listClassDefinitions(): IClassDefinition[];
5707
5716
  listInterfaceDefinitions(): IInterfaceDefinition[];
@@ -5,7 +5,7 @@ const combi_1 = require("../combi");
5
5
  const _1 = require(".");
6
6
  class RaiseWith extends combi_1.Expression {
7
7
  getRunnable() {
8
- const wit = (0, combi_1.seq)("WITH", _1.Source, (0, combi_1.opt)(_1.Source), (0, combi_1.opt)(_1.Source), (0, combi_1.opt)(_1.Source));
8
+ const wit = (0, combi_1.seq)("WITH", _1.SimpleSource3, (0, combi_1.opt)(_1.SimpleSource3), (0, combi_1.opt)(_1.SimpleSource3), (0, combi_1.opt)(_1.SimpleSource3));
9
9
  return wit;
10
10
  }
11
11
  }
@@ -126,11 +126,11 @@ class CurrentScope {
126
126
  }
127
127
  this.addNamedIdentifier(identifier.getName(), identifier);
128
128
  }
129
- addDeferred(token) {
129
+ addDeferred(token, type) {
130
130
  if (token === undefined) {
131
131
  return;
132
132
  }
133
- this.current.getData().deferred[token.getStr().toUpperCase()] = token;
133
+ this.current.getData().deferred[token.getStr().toUpperCase()] = { token, ooType: type };
134
134
  }
135
135
  addListPrefix(identifiers, prefix) {
136
136
  for (const id of identifiers) {
@@ -235,7 +235,16 @@ class CurrentScope {
235
235
  }
236
236
  const def = (_c = this.current) === null || _c === void 0 ? void 0 : _c.findDeferred(name);
237
237
  if (def !== undefined) {
238
- return { id: def };
238
+ let rttiName = prefixRTTI;
239
+ switch (def.ooType) {
240
+ case "INTF":
241
+ rttiName = rttiName + "\\INTERFACE=" + name;
242
+ break;
243
+ default:
244
+ rttiName = rttiName + "\\CLASS=" + name;
245
+ break;
246
+ }
247
+ return { id: def.id, ooType: def.ooType, RTTIName: rttiName };
239
248
  }
240
249
  return undefined;
241
250
  }
@@ -265,6 +274,11 @@ class CurrentScope {
265
274
  if (typePoolName.length <= 1 || typePoolName.length > 5) {
266
275
  return undefined;
267
276
  }
277
+ if (this.parentObj.getType() === "TYPE"
278
+ && this.parentObj.getName().toUpperCase() === typePoolName.toUpperCase()) {
279
+ // dont recurse into itself
280
+ return undefined;
281
+ }
268
282
  const typePool = this.reg.getObject("TYPE", typePoolName);
269
283
  if (typePool === undefined) {
270
284
  return undefined;
@@ -282,6 +296,11 @@ class CurrentScope {
282
296
  if (typePoolName.length <= 2 || typePoolName.length > 5) {
283
297
  return undefined;
284
298
  }
299
+ if (this.parentObj.getType() === "TYPE"
300
+ && this.parentObj.getName().toUpperCase() === typePoolName.toUpperCase()) {
301
+ // dont recurse into itself
302
+ return undefined;
303
+ }
285
304
  if (new ddic_1.DDIC(this.reg).lookupNoVoid(name) !== undefined) {
286
305
  // this is tricky, it should not do recursion when parsing the type pool itself,
287
306
  // think about DTEL ABAP_ENCOD vs TYPE ABAP
@@ -5,7 +5,7 @@ const Expressions = require("../../2_statements/expressions");
5
5
  const source_1 = require("./source");
6
6
  class RaiseWith {
7
7
  runSyntax(node, scope, filename) {
8
- for (const f of node.findDirectExpressions(Expressions.Source)) {
8
+ for (const f of node.findDirectExpressions(Expressions.SimpleSource3)) {
9
9
  new source_1.Source().runSyntax(f, scope, filename);
10
10
  }
11
11
  }
@@ -97,6 +97,11 @@ class Source {
97
97
  else {
98
98
  this.addIfInferred(node, scope, filename, foundType);
99
99
  }
100
+ children.shift();
101
+ children.shift();
102
+ children.shift();
103
+ children.shift();
104
+ this.traverseRemainingChildren(children, scope, filename);
100
105
  return foundType ? foundType : bodyType;
101
106
  }
102
107
  case "CONV":
@@ -213,6 +218,12 @@ class Source {
213
218
  return context;
214
219
  }
215
220
  ////////////////////////////////
221
+ traverseRemainingChildren(children, scope, filename) {
222
+ const last = children[children.length - 1];
223
+ if (last && last.get() instanceof Expressions.Source) {
224
+ new Source().runSyntax(last, scope, filename);
225
+ }
226
+ }
216
227
  infer(context, found) {
217
228
  if (context instanceof basic_1.FloatType && found instanceof basic_1.IntegerType) {
218
229
  return context;
@@ -61,7 +61,10 @@ class SpaghettiScopeNode extends ScopeData {
61
61
  while (search !== undefined) {
62
62
  const found = search.getData().deferred[name.toUpperCase()];
63
63
  if (found) {
64
- return new _identifier_1.Identifier(found, search.identifier.filename);
64
+ return {
65
+ id: new _identifier_1.Identifier(found.token, search.identifier.filename),
66
+ ooType: found.ooType,
67
+ };
65
68
  }
66
69
  search = search.getParent();
67
70
  }
@@ -6,7 +6,7 @@ class ClassDeferred {
6
6
  runSyntax(node, scope, _filename) {
7
7
  var _a;
8
8
  const name = (_a = node.findFirstExpression(Expressions.ClassName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
9
- scope.addDeferred(name);
9
+ scope.addDeferred(name, "CLAS");
10
10
  }
11
11
  }
12
12
  exports.ClassDeferred = ClassDeferred;
@@ -6,7 +6,7 @@ class InterfaceDeferred {
6
6
  runSyntax(node, scope, _filename) {
7
7
  var _a;
8
8
  const name = (_a = node.findFirstExpression(Expressions.InterfaceName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
9
- scope.addDeferred(name);
9
+ scope.addDeferred(name, "INTF");
10
10
  }
11
11
  }
12
12
  exports.InterfaceDeferred = InterfaceDeferred;
@@ -6,13 +6,33 @@ const source_1 = require("../expressions/source");
6
6
  const target_1 = require("../expressions/target");
7
7
  const fstarget_1 = require("../expressions/fstarget");
8
8
  const component_cond_1 = require("../expressions/component_cond");
9
+ const basic_1 = require("../../types/basic");
9
10
  class ModifyInternal {
10
11
  runSyntax(node, scope, filename) {
11
12
  for (const s of node.findDirectExpressions(Expressions.Source)) {
12
13
  new source_1.Source().runSyntax(s, scope, filename);
13
14
  }
14
- for (const t of node.findDirectExpressions(Expressions.Target)) {
15
- new target_1.Target().runSyntax(t, scope, filename);
15
+ // there is only one
16
+ const targetExpression = node.findFirstExpression(Expressions.Target);
17
+ if (targetExpression) {
18
+ // it might be a dynamic target
19
+ const targetType = new target_1.Target().runSyntax(targetExpression, scope, filename);
20
+ if (targetType instanceof basic_1.VoidType
21
+ || targetType instanceof basic_1.AnyType
22
+ || targetType instanceof basic_1.UnknownType) {
23
+ // ok
24
+ }
25
+ else if (targetType instanceof basic_1.TableType) {
26
+ if (node.findDirectTokenByText("TABLE")
27
+ && node.findDirectTokenByText("INDEX")
28
+ && targetType.isWithHeader() === false) {
29
+ // MODIFY TABLE INDEX
30
+ throw new Error("Table does not have header line");
31
+ }
32
+ }
33
+ else {
34
+ throw new Error("Not an internal table");
35
+ }
16
36
  }
17
37
  const target = node.findDirectExpression(Expressions.FSTarget);
18
38
  if (target) {
@@ -12,6 +12,9 @@ class Parameter {
12
12
  if (nameToken && nameToken.getStr().length > 8) {
13
13
  throw new Error("Parameter name too long, " + nameToken.getStr());
14
14
  }
15
+ if (node.findDirectTokenByText("RADIOBUTTON") && node.findDirectTokenByText("LENGTH")) {
16
+ throw new Error("RADIOBUTTON and LENGTH not possible together");
17
+ }
15
18
  const bfound = new basic_types_1.BasicTypes(filename, scope).parseType(node);
16
19
  if (nameToken && bfound) {
17
20
  scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, bfound));
@@ -25,6 +25,32 @@ class ExpressionNode extends _abstract_node_1.AbstractNode {
25
25
  }
26
26
  throw new Error("ExpressionNode, getFirstToken, no children");
27
27
  }
28
+ concatTokensWithLinebreaks() {
29
+ let str = "";
30
+ let prev;
31
+ for (const token of this.getTokens()) {
32
+ if (token instanceof tokens_1.Pragma) {
33
+ continue;
34
+ }
35
+ if (str === "") {
36
+ str = token.getStr();
37
+ }
38
+ else if (prev && prev.getStr().length + prev.getCol() === token.getCol()
39
+ && prev.getRow() === token.getRow()) {
40
+ str = str + token.getStr();
41
+ }
42
+ else {
43
+ if (prev && prev.getRow() !== token.getRow()) {
44
+ str = str + "\n" + token.getStr();
45
+ }
46
+ else {
47
+ str = str + " " + token.getStr();
48
+ }
49
+ }
50
+ prev = token;
51
+ }
52
+ return str;
53
+ }
28
54
  concatTokens() {
29
55
  let str = "";
30
56
  let prev;
@@ -65,7 +65,7 @@ class Registry {
65
65
  }
66
66
  static abaplintVersion() {
67
67
  // magic, see build script "version.sh"
68
- return "2.105.16";
68
+ return "2.105.18";
69
69
  }
70
70
  getDDICReferences() {
71
71
  return this.ddicReferences;
@@ -9,6 +9,7 @@ const expressions_1 = require("../abap/2_statements/expressions");
9
9
  const _irule_1 = require("./_irule");
10
10
  const version_1 = require("../version");
11
11
  const edit_helper_1 = require("../edit_helper");
12
+ const _statement_1 = require("../abap/2_statements/statements/_statement");
12
13
  class AvoidUseConf extends _basic_rule_config_1.BasicRuleConfig {
13
14
  constructor() {
14
15
  super(...arguments);
@@ -18,11 +19,11 @@ class AvoidUseConf extends _basic_rule_config_1.BasicRuleConfig {
18
19
  this.define = true;
19
20
  /** Detects statics */
20
21
  this.statics = true;
21
- /** Detects DEFAULT KEY definitions, from version v740sp02 and up */
22
+ /** Detects DEFAULT KEY definitions, from version v740sp02 and up. Use pseudo comment DEFAULT_KEY to ignore */
22
23
  this.defaultKey = true;
23
24
  /** Detects BREAK and BREAK-POINTS */
24
25
  this.break = true;
25
- /** Detects TEST SEAMS */
26
+ /** Detects TEST SEAMS. Use pseudo comment TEST_SEAM_USAGE to ignore */
26
27
  this.testSeams = true;
27
28
  /** Detects DESCRIBE TABLE LINES, use lines() instead */
28
29
  this.describeLines = true;
@@ -70,7 +71,9 @@ BREAK points`,
70
71
  var _a;
71
72
  const issues = [];
72
73
  let isStaticsBlock = false;
73
- for (const statementNode of file.getStatements()) {
74
+ const statements = file.getStatements();
75
+ for (let i = 0; i < statements.length; i++) {
76
+ const statementNode = statements[i];
74
77
  const statement = statementNode.get();
75
78
  let message = undefined;
76
79
  let fix = undefined;
@@ -98,6 +101,10 @@ BREAK points`,
98
101
  message = "EXPORT TO DATABASE";
99
102
  }
100
103
  else if (this.conf.testSeams && statement instanceof Statements.TestSeam) {
104
+ const next = statements[i + 1];
105
+ if ((next === null || next === void 0 ? void 0 : next.get()) instanceof _statement_1.Comment && next.concatTokens().includes("EC TEST_SEAM_USAGE")) {
106
+ continue;
107
+ }
101
108
  message = "TEST-SEAM";
102
109
  }
103
110
  else if (this.conf.statics && statement instanceof Statements.Static && isStaticsBlock === false) {
@@ -117,6 +124,10 @@ BREAK points`,
117
124
  const tt = (_a = statementNode.findFirstExpression(expressions_1.TypeTable)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.TypeTableKey);
118
125
  const token = tt === null || tt === void 0 ? void 0 : tt.findDirectTokenByText("DEFAULT");
119
126
  if (tt && token) {
127
+ const next = statements[i + 1];
128
+ if ((next === null || next === void 0 ? void 0 : next.get()) instanceof _statement_1.Comment && next.concatTokens().includes("EC DEFAULT_KEY")) {
129
+ continue;
130
+ }
120
131
  message = "DEFAULT KEY";
121
132
  issues.push(issue_1.Issue.atToken(file, token, this.getDescription(message), this.getMetadata().key, this.conf.severity));
122
133
  }
@@ -1152,7 +1152,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
1152
1152
  }
1153
1153
  startToken = node.getFirstToken();
1154
1154
  }
1155
- const withs = ((_f = node.findDirectExpression(Expressions.RaiseWith)) === null || _f === void 0 ? void 0 : _f.findDirectExpressions(Expressions.Source)) || [];
1155
+ const withs = ((_f = node.findDirectExpression(Expressions.RaiseWith)) === null || _f === void 0 ? void 0 : _f.findDirectExpressions(Expressions.SimpleSource3)) || [];
1156
1156
  const className = ((_g = node.findDirectExpression(Expressions.ClassName)) === null || _g === void 0 ? void 0 : _g.concatTokens()) || "ERROR";
1157
1157
  const uniqueName1 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
1158
1158
  const uniqueName2 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
@@ -1540,7 +1540,7 @@ LOOP AT ${groupTargetName}tab ${groupTarget}.`;
1540
1540
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
1541
1541
  let code = `CLEAR ${target.concatTokens()}.\n`;
1542
1542
  for (const fieldAssignment of fieldAssignments) {
1543
- code += indentation + target.concatTokens() + "-" + fieldAssignment.concatTokens() + `.\n`;
1543
+ code += indentation + target.concatTokens() + "-" + fieldAssignment.concatTokensWithLinebreaks() + `.\n`;
1544
1544
  }
1545
1545
  code = code.trimEnd();
1546
1546
  const start = high.getFirstToken().getStart();
@@ -2210,7 +2210,7 @@ ${indentation} output = ${uniqueName}.\n`;
2210
2210
  body += data;
2211
2211
  added = true;
2212
2212
  }
2213
- body += indentation + structureName + "-" + b.concatTokens() + ".\n";
2213
+ body += indentation + structureName + "-" + b.concatTokensWithLinebreaks() + ".\n";
2214
2214
  }
2215
2215
  else if (b.get() instanceof Expressions.Source) {
2216
2216
  // note: it wont work with APPEND for Hashed/Sorted Tables, so use INSERT,
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MethodLength = exports.MethodLengthConf = void 0;
4
4
  const issue_1 = require("../issue");
5
+ const Objects = require("../objects");
5
6
  const method_length_stats_1 = require("../utils/method_length_stats");
6
7
  const _irule_1 = require("./_irule");
7
8
  const _basic_rule_config_1 = require("./_basic_rule_config");
@@ -63,6 +64,12 @@ Abstract methods without statements are considered okay.`,
63
64
  return this;
64
65
  }
65
66
  run(obj) {
67
+ var _a;
68
+ if (this.conf.ignoreTestClasses === true
69
+ && obj instanceof Objects.Class
70
+ && ((_a = obj.getClassDefinition()) === null || _a === void 0 ? void 0 : _a.isForTesting) === true) {
71
+ return [];
72
+ }
66
73
  const methodStats = method_length_stats_1.MethodLengthStats.run(obj);
67
74
  const methodIssues = this.check(methodStats, "METHOD");
68
75
  let formIssues = [];
@@ -49,7 +49,7 @@ class UnnecessaryChaining extends _abap_rule_1.ABAPRule {
49
49
  j = 1;
50
50
  let prevStatement = statements[i - j];
51
51
  while ((prevStatement === null || prevStatement === void 0 ? void 0 : prevStatement.get()) instanceof _statement_1.Comment) {
52
- j--;
52
+ j++;
53
53
  prevStatement = statements[i - j];
54
54
  }
55
55
  const next = nextStatement === null || nextStatement === void 0 ? void 0 : nextStatement.getColon();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.105.16",
3
+ "version": "2.105.18",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",
@@ -50,13 +50,13 @@
50
50
  },
51
51
  "homepage": "https://abaplint.org",
52
52
  "devDependencies": {
53
- "@microsoft/api-extractor": "^7.39.4",
53
+ "@microsoft/api-extractor": "^7.40.2",
54
54
  "@types/chai": "^4.3.11",
55
55
  "@types/mocha": "^10.0.6",
56
- "@types/node": "^20.11.16",
56
+ "@types/node": "^20.11.19",
57
57
  "chai": "^4.4.1",
58
58
  "eslint": "^8.56.0",
59
- "mocha": "^10.2.0",
59
+ "mocha": "^10.3.0",
60
60
  "c8": "^9.1.0",
61
61
  "source-map-support": "^0.5.21",
62
62
  "ts-json-schema-generator": "^1.5.0",