@abaplint/core 2.92.1 → 2.93.1

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.
@@ -572,6 +572,10 @@ declare class CDSAggregate extends Expression {
572
572
  getRunnable(): IStatementRunnable;
573
573
  }
574
574
 
575
+ declare class CDSAnnotate extends Expression {
576
+ getRunnable(): IStatementRunnable;
577
+ }
578
+
575
579
  declare class CDSAnnotation extends Expression {
576
580
  getRunnable(): IStatementRunnable;
577
581
  }
@@ -649,12 +653,17 @@ declare class CDSJoin extends Expression {
649
653
  }
650
654
 
651
655
  declare class CDSMetadataExtension extends AbstractObject {
656
+ private parserError;
657
+ private parsedData;
652
658
  getType(): string;
653
659
  getAllowedNaming(): {
654
660
  maxLength: number;
655
661
  allowNamespace: boolean;
656
662
  };
663
+ hasParserError(): boolean | undefined;
664
+ parse(): IParseResult;
657
665
  getDescription(): string | undefined;
666
+ findSourceFile(): IFile | undefined;
658
667
  }
659
668
 
660
669
  declare class CDSName extends Expression {
@@ -2002,6 +2011,7 @@ declare namespace Expressions {
2002
2011
  TypeTableKey,
2003
2012
  TypeTable,
2004
2013
  Type_2 as Type,
2014
+ ValueBodyLine,
2005
2015
  ValueBodyLines,
2006
2016
  ValueBody,
2007
2017
  Value,
@@ -2014,6 +2024,7 @@ export { Expressions }
2014
2024
  declare namespace ExpressionsCDS {
2015
2025
  export {
2016
2026
  CDSAggregate,
2027
+ CDSAnnotate,
2017
2028
  CDSAnnotationArray,
2018
2029
  CDSAnnotationObject,
2019
2030
  CDSAnnotationSimple,
@@ -3984,6 +3995,7 @@ declare namespace Objects {
3984
3995
  BusinessFunctionAssignment,
3985
3996
  BusinessFunctionSetAssignment,
3986
3997
  BusinessObjectModel,
3998
+ ParsedMetadataExtension,
3987
3999
  CDSMetadataExtension,
3988
4000
  ChangeDocument,
3989
4001
  ChapterOfBookStructure,
@@ -4228,6 +4240,10 @@ declare type ParsedDataDefinition = {
4228
4240
  tree: ExpressionNode | undefined;
4229
4241
  };
4230
4242
 
4243
+ declare type ParsedMetadataExtension = {
4244
+ tree: ExpressionNode | undefined;
4245
+ };
4246
+
4231
4247
  declare class PassByValue extends Expression {
4232
4248
  getRunnable(): IStatementRunnable;
4233
4249
  }
@@ -6106,6 +6122,10 @@ declare class ValueBody extends Expression {
6106
6122
  getRunnable(): IStatementRunnable;
6107
6123
  }
6108
6124
 
6125
+ declare class ValueBodyLine extends Expression {
6126
+ getRunnable(): IStatementRunnable;
6127
+ }
6128
+
6109
6129
  declare class ValueBodyLines extends Expression {
6110
6130
  getRunnable(): IStatementRunnable;
6111
6131
  }
@@ -210,6 +210,7 @@ __exportStar(require("./type_param"), exports);
210
210
  __exportStar(require("./type_table_key"), exports);
211
211
  __exportStar(require("./type_table"), exports);
212
212
  __exportStar(require("./type"), exports);
213
+ __exportStar(require("./value_body_line"), exports);
213
214
  __exportStar(require("./value_body_lines"), exports);
214
215
  __exportStar(require("./value_body"), exports);
215
216
  __exportStar(require("./value"), exports);
@@ -2,16 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ValueBody = void 0;
4
4
  const combi_1 = require("../combi");
5
- const tokens_1 = require("../../1_lexer/tokens");
6
5
  const _1 = require(".");
7
6
  const version_1 = require("../../../version");
8
- const value_body_lines_1 = require("./value_body_lines");
9
7
  class ValueBody extends combi_1.Expression {
10
8
  getRunnable() {
11
9
  const base = (0, combi_1.seq)("BASE", _1.Source);
12
- // missing spaces caught by rule "parser_missing_space"
13
- const foo = (0, combi_1.seq)((0, combi_1.altPrio)((0, combi_1.tok)(tokens_1.WParenLeftW), (0, combi_1.tok)(tokens_1.WParenLeft)), (0, combi_1.optPrio)((0, combi_1.altPrio)((0, combi_1.plusPrio)(_1.FieldAssignment), value_body_lines_1.ValueBodyLines, _1.Source)), (0, combi_1.altPrio)((0, combi_1.tok)(tokens_1.WParenRightW), (0, combi_1.tok)(tokens_1.ParenRightW)));
14
- const strucOrTab = (0, combi_1.seq)((0, combi_1.optPrio)(_1.Let), (0, combi_1.optPrio)(base), (0, combi_1.star)(_1.For), (0, combi_1.plusPrio)((0, combi_1.altPrio)(_1.FieldAssignment, foo)));
10
+ const strucOrTab = (0, combi_1.seq)((0, combi_1.optPrio)(_1.Let), (0, combi_1.optPrio)(base), (0, combi_1.star)(_1.For), (0, combi_1.plusPrio)((0, combi_1.altPrio)(_1.FieldAssignment, _1.ValueBodyLine)));
15
11
  const tabdef = (0, combi_1.ver)(version_1.Version.v740sp08, (0, combi_1.altPrio)("OPTIONAL", (0, combi_1.seq)("DEFAULT", _1.Source)));
16
12
  return (0, combi_1.optPrio)((0, combi_1.altPrio)(strucOrTab, (0, combi_1.seq)(_1.Source, (0, combi_1.optPrio)(tabdef))));
17
13
  }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ValueBodyLine = void 0;
4
+ const combi_1 = require("../combi");
5
+ const tokens_1 = require("../../1_lexer/tokens");
6
+ const _1 = require(".");
7
+ const value_body_lines_1 = require("./value_body_lines");
8
+ class ValueBodyLine extends combi_1.Expression {
9
+ getRunnable() {
10
+ // missing spaces caught by rule "parser_missing_space"
11
+ const ret = (0, combi_1.seq)((0, combi_1.altPrio)((0, combi_1.tok)(tokens_1.WParenLeftW), (0, combi_1.tok)(tokens_1.WParenLeft)), (0, combi_1.optPrio)((0, combi_1.altPrio)((0, combi_1.plusPrio)(_1.FieldAssignment), value_body_lines_1.ValueBodyLines, _1.Source)), (0, combi_1.altPrio)((0, combi_1.tok)(tokens_1.WParenRightW), (0, combi_1.tok)(tokens_1.ParenRightW)));
12
+ return ret;
13
+ }
14
+ }
15
+ exports.ValueBodyLine = ValueBodyLine;
16
+ //# sourceMappingURL=value_body_line.js.map
@@ -36,7 +36,10 @@ class FieldChain {
36
36
  if (current === undefined) {
37
37
  break;
38
38
  }
39
- if (current.get() instanceof tokens_1.Dash) {
39
+ if (current.get() instanceof tokens_1.DashW) {
40
+ throw new Error("Ending with dash");
41
+ }
42
+ else if (current.get() instanceof tokens_1.Dash) {
40
43
  if (context instanceof basic_1.UnknownType) {
41
44
  throw new Error("Not a structure, type unknown, FieldChain");
42
45
  }
@@ -27,8 +27,16 @@ class ValueBody {
27
27
  for (const s of node.findDirectExpressions(Expressions.Source)) {
28
28
  type = new source_1.Source().runSyntax(s, scope, filename);
29
29
  }
30
- for (const l of node.findDirectExpressions(Expressions.ValueBodyLines)) {
31
- for (const s of l.findDirectExpressions(Expressions.Source)) {
30
+ for (const foo of node.findDirectExpressions(Expressions.ValueBodyLine)) {
31
+ for (const l of foo.findDirectExpressions(Expressions.ValueBodyLines)) {
32
+ for (const s of l.findDirectExpressions(Expressions.Source)) {
33
+ new source_1.Source().runSyntax(s, scope, filename);
34
+ }
35
+ }
36
+ for (const s of foo.findDirectExpressions(Expressions.FieldAssignment)) {
37
+ new field_assignment_1.FieldAssignment().runSyntax(s, scope, filename, targetType);
38
+ }
39
+ for (const s of foo.findDirectExpressions(Expressions.Source)) {
32
40
  new source_1.Source().runSyntax(s, scope, filename);
33
41
  }
34
42
  }
@@ -22,13 +22,25 @@ class Stream {
22
22
  return this.buffer.length;
23
23
  }
24
24
  }
25
+ var Mode;
26
+ (function (Mode) {
27
+ Mode[Mode["Default"] = 0] = "Default";
28
+ Mode[Mode["String"] = 1] = "String";
29
+ Mode[Mode["SingleLineComment"] = 2] = "SingleLineComment";
30
+ Mode[Mode["MultiLineComment"] = 3] = "MultiLineComment";
31
+ })(Mode || (Mode = {}));
25
32
  class Result {
26
33
  constructor() {
27
34
  this.result = [];
28
35
  }
29
- add(text, row, col) {
36
+ add(text, row, col, mode) {
30
37
  if (text.length > 0) {
31
- this.result.push(new tokens_1.Identifier(new position_1.Position(row, col), text));
38
+ if (mode === Mode.SingleLineComment) {
39
+ this.result.push(new tokens_1.Comment(new position_1.Position(row, col), text));
40
+ }
41
+ else {
42
+ this.result.push(new tokens_1.Identifier(new position_1.Position(row, col), text));
43
+ }
32
44
  }
33
45
  return "";
34
46
  }
@@ -36,13 +48,6 @@ class Result {
36
48
  return this.result;
37
49
  }
38
50
  }
39
- var Mode;
40
- (function (Mode) {
41
- Mode[Mode["Default"] = 0] = "Default";
42
- Mode[Mode["String"] = 1] = "String";
43
- Mode[Mode["SingleLineComment"] = 2] = "SingleLineComment";
44
- Mode[Mode["MultiLineComment"] = 3] = "MultiLineComment";
45
- })(Mode || (Mode = {}));
46
51
  class CDSLexer {
47
52
  static run(file) {
48
53
  const result = new Result();
@@ -61,7 +66,7 @@ class CDSLexer {
61
66
  if (mode === Mode.String) {
62
67
  build += next;
63
68
  if (next === "'") {
64
- build = result.add(build, row, col);
69
+ build = result.add(build, row, col, mode);
65
70
  mode = Mode.Default;
66
71
  }
67
72
  continue;
@@ -69,20 +74,24 @@ class CDSLexer {
69
74
  // single line comment handling
70
75
  if (mode === Mode.SingleLineComment) {
71
76
  if (next === "\n") {
77
+ build = result.add(build, row, col, mode);
72
78
  mode = Mode.Default;
73
79
  }
74
80
  else {
81
+ build += next;
75
82
  continue;
76
83
  }
77
84
  }
78
85
  else if (mode === Mode.Default && next === "/" && nextNext === "/") {
79
86
  mode = Mode.SingleLineComment;
80
- build = result.add(build, row, col);
87
+ build = result.add(build, row, col, mode);
88
+ build += next;
81
89
  continue;
82
90
  }
83
91
  else if (mode === Mode.Default && next === "-" && nextNext === "-") {
84
92
  mode = Mode.SingleLineComment;
85
- build = result.add(build, row, col);
93
+ build = result.add(build, row, col, mode);
94
+ build += next;
86
95
  continue;
87
96
  }
88
97
  // multi line comment handling
@@ -97,7 +106,7 @@ class CDSLexer {
97
106
  }
98
107
  else if (mode === Mode.Default && next === "/" && nextNext === "*") {
99
108
  mode = Mode.MultiLineComment;
100
- build = result.add(build, row, col);
109
+ build = result.add(build, row, col, mode);
101
110
  continue;
102
111
  }
103
112
  switch (next) {
@@ -106,10 +115,10 @@ class CDSLexer {
106
115
  build += next;
107
116
  break;
108
117
  case " ":
109
- build = result.add(build, row, col);
118
+ build = result.add(build, row, col, mode);
110
119
  break;
111
120
  case "\n":
112
- build = result.add(build, row, col);
121
+ build = result.add(build, row, col, mode);
113
122
  row++;
114
123
  col = 0;
115
124
  break;
@@ -130,15 +139,15 @@ class CDSLexer {
130
139
  case "-":
131
140
  case "*":
132
141
  case "/":
133
- build = result.add(build, row, col);
134
- result.add(next, row, col);
142
+ build = result.add(build, row, col, mode);
143
+ result.add(next, row, col, mode);
135
144
  break;
136
145
  default:
137
146
  build += next;
138
147
  break;
139
148
  }
140
149
  }
141
- result.add(build, row, col);
150
+ result.add(build, row, col, mode);
142
151
  return result.get();
143
152
  }
144
153
  }
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CDSParser = void 0;
4
+ const tokens_1 = require("../abap/1_lexer/tokens");
4
5
  const combi_1 = require("../abap/2_statements/combi");
5
6
  const nodes_1 = require("../abap/nodes");
6
7
  const version_1 = require("../version");
@@ -12,7 +13,8 @@ class CDSParser {
12
13
  if (file === undefined) {
13
14
  return undefined;
14
15
  }
15
- const tokens = cds_lexer_1.CDSLexer.run(file);
16
+ let tokens = cds_lexer_1.CDSLexer.run(file);
17
+ tokens = tokens.filter(t => !(t instanceof tokens_1.Comment));
16
18
  // console.dir(tokens);
17
19
  let res = combi_1.Combi.run(new Expressions.CDSDefineView(), tokens, version_1.defaultVersion);
18
20
  if (res === undefined || !(res[0] instanceof nodes_1.ExpressionNode)) {
@@ -21,6 +23,9 @@ class CDSParser {
21
23
  if (res === undefined || !(res[0] instanceof nodes_1.ExpressionNode)) {
22
24
  res = combi_1.Combi.run(new Expressions.CDSDefineProjection(), tokens, version_1.defaultVersion);
23
25
  }
26
+ if (res === undefined || !(res[0] instanceof nodes_1.ExpressionNode)) {
27
+ res = combi_1.Combi.run(new Expressions.CDSAnnotate(), tokens, version_1.defaultVersion);
28
+ }
24
29
  if (res === undefined || !(res[0] instanceof nodes_1.ExpressionNode)) {
25
30
  return undefined;
26
31
  }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CDSAnnotate = void 0;
4
+ const _1 = require(".");
5
+ const combi_1 = require("../../abap/2_statements/combi");
6
+ class CDSAnnotate extends combi_1.Expression {
7
+ getRunnable() {
8
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "ANNOTATE", (0, combi_1.alt)("ENTITY", "VIEW"), _1.CDSName, "WITH", (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.seq)(_1.CDSElement, ";")), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
9
+ }
10
+ }
11
+ exports.CDSAnnotate = CDSAnnotate;
12
+ //# sourceMappingURL=cds_annotate.js.map
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  __exportStar(require("./cds_aggregate"), exports);
18
18
  __exportStar(require("./cds_aggregate"), exports);
19
+ __exportStar(require("./cds_annotate"), exports);
19
20
  __exportStar(require("./cds_annotation_array"), exports);
20
21
  __exportStar(require("./cds_annotation_object"), exports);
21
22
  __exportStar(require("./cds_annotation_simple"), exports);
@@ -1,8 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CDSMetadataExtension = void 0;
4
+ const cds_parser_1 = require("../cds/cds_parser");
4
5
  const _abstract_object_1 = require("./_abstract_object");
5
6
  class CDSMetadataExtension extends _abstract_object_1.AbstractObject {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.parserError = undefined;
10
+ this.parsedData = undefined;
11
+ }
6
12
  getType() {
7
13
  return "DDLX";
8
14
  }
@@ -12,10 +18,31 @@ class CDSMetadataExtension extends _abstract_object_1.AbstractObject {
12
18
  allowNamespace: true,
13
19
  };
14
20
  }
21
+ hasParserError() {
22
+ return this.parserError;
23
+ }
24
+ parse() {
25
+ if (this.isDirty() === false) {
26
+ return { updated: false, runtime: 0 };
27
+ }
28
+ const start = Date.now();
29
+ this.parsedData = {
30
+ tree: undefined,
31
+ };
32
+ this.parsedData.tree = new cds_parser_1.CDSParser().parse(this.findSourceFile());
33
+ if (this.parsedData.tree === undefined) {
34
+ this.parserError = true;
35
+ }
36
+ this.dirty = false;
37
+ return { updated: true, runtime: Date.now() - start };
38
+ }
15
39
  getDescription() {
16
40
  // todo
17
41
  return undefined;
18
42
  }
43
+ findSourceFile() {
44
+ return this.getFiles().find(f => f.getFilename().endsWith(".asddlxs") || f.getFilename().endsWith(".acds"));
45
+ }
19
46
  }
20
47
  exports.CDSMetadataExtension = CDSMetadataExtension;
21
48
  //# sourceMappingURL=cds_metadata_extension.js.map
@@ -52,7 +52,7 @@ class DataDefinition extends _abstract_object_1.AbstractObject {
52
52
  super.setDirty();
53
53
  }
54
54
  findSourceFile() {
55
- return this.getFiles().find(f => f.getFilename().endsWith(".asddls"));
55
+ return this.getFiles().find(f => f.getFilename().endsWith(".asddls") || f.getFilename().endsWith(".acds"));
56
56
  }
57
57
  hasParserError() {
58
58
  return this.parserError;
@@ -67,7 +67,7 @@ class Registry {
67
67
  }
68
68
  static abaplintVersion() {
69
69
  // magic, see build script "version.sh"
70
- return "2.92.1";
70
+ return "2.93.1";
71
71
  }
72
72
  getDDICReferences() {
73
73
  return this.references;
@@ -56,7 +56,13 @@ foobar( moo = 1
56
56
 
57
57
  foo = VALUE #(
58
58
  foo = bar
59
- moo = 2 ).`,
59
+ moo = 2 ).
60
+
61
+ DATA(sdf) = VALUE type(
62
+ common_val = 2
63
+ another_common = 5
64
+ ( row_value = 4
65
+ value_foo = 5 ) ).`,
60
66
  };
61
67
  }
62
68
  getConfig() {
@@ -169,6 +175,27 @@ foo = VALUE #(
169
175
  candidates.push({ parameters });
170
176
  }
171
177
  }
178
+ for (const vb of stru.findAllExpressionsRecursive(Expressions.ValueBodyLine)) {
179
+ const parameters = [];
180
+ const fieldAssignments = vb.findDirectExpressions(Expressions.FieldAssignment);
181
+ if (fieldAssignments.length <= 1) {
182
+ continue;
183
+ }
184
+ for (const fs of fieldAssignments) {
185
+ const children = fs.getChildren();
186
+ if (children.length < 3) {
187
+ continue; // unexpected
188
+ }
189
+ parameters.push({
190
+ left: children[0],
191
+ eq: children[1].getFirstToken().getStart(),
192
+ right: children[2],
193
+ });
194
+ }
195
+ if (parameters.length > 0) {
196
+ candidates.push({ parameters });
197
+ }
198
+ }
172
199
  return candidates;
173
200
  }
174
201
  raiseAndCreateCandidates(stru) {
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CDSCommentStyle = exports.CDSCommentStyleConf = void 0;
4
+ const issue_1 = require("../issue");
5
+ const _irule_1 = require("./_irule");
6
+ const _basic_rule_config_1 = require("./_basic_rule_config");
7
+ const objects_1 = require("../objects");
8
+ const cds_lexer_1 = require("../cds/cds_lexer");
9
+ const tokens_1 = require("../abap/1_lexer/tokens");
10
+ class CDSCommentStyleConf extends _basic_rule_config_1.BasicRuleConfig {
11
+ }
12
+ exports.CDSCommentStyleConf = CDSCommentStyleConf;
13
+ class CDSCommentStyle {
14
+ constructor() {
15
+ this.conf = new CDSCommentStyleConf();
16
+ }
17
+ getMetadata() {
18
+ return {
19
+ key: "cds_comment_style",
20
+ title: "CDS Comment Style",
21
+ shortDescription: `Check for obsolete comment style`,
22
+ extendedInformation: `Check for obsolete comment style
23
+
24
+ Comments starting with "--" are considered obsolete
25
+
26
+ https://help.sap.com/doc/abapdocu_752_index_htm/7.52/en-us/abencds_general_syntax_rules.htm`,
27
+ tags: [_irule_1.RuleTag.SingleFile],
28
+ badExample: "-- this is a comment",
29
+ goodExample: "// this is a comment",
30
+ };
31
+ }
32
+ getConfig() {
33
+ return this.conf;
34
+ }
35
+ setConfig(conf) {
36
+ this.conf = conf;
37
+ }
38
+ initialize(_reg) {
39
+ return this;
40
+ }
41
+ run(object) {
42
+ const issues = [];
43
+ if ((object.getType() === "DDLS" && object instanceof objects_1.DataDefinition) ||
44
+ (object.getType() === "DDLX" && object instanceof objects_1.CDSMetadataExtension)) {
45
+ const file = object.findSourceFile();
46
+ if (file === undefined) {
47
+ return issues;
48
+ }
49
+ const tokens = cds_lexer_1.CDSLexer.run(file);
50
+ for (const t of tokens) {
51
+ if (t instanceof tokens_1.Comment && t.getStr().startsWith("--")) {
52
+ issues.push(issue_1.Issue.atToken(file, t, `Use "//" for comments instead of "--"`, this.getMetadata().key, this.getConfig().severity));
53
+ }
54
+ }
55
+ }
56
+ return issues;
57
+ }
58
+ }
59
+ exports.CDSCommentStyle = CDSCommentStyle;
60
+ //# sourceMappingURL=cds_comment_style.js.map
@@ -24,7 +24,7 @@ class CDSLegacyView {
24
24
  https://blogs.sap.com/2021/10/16/a-new-generation-of-cds-views-how-to-migrate-your-cds-views-to-cds-view-entities/
25
25
 
26
26
  v755 and up`,
27
- tags: [_irule_1.RuleTag.SingleFile],
27
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Upport],
28
28
  };
29
29
  }
30
30
  getConfig() {
@@ -16,8 +16,8 @@ class CDSParserError {
16
16
  return {
17
17
  key: "cds_parser_error",
18
18
  title: "CDS Parser Error",
19
- shortDescription: `CDS parsing, experimental`,
20
- extendedInformation: ``,
19
+ shortDescription: `CDS parsing`,
20
+ extendedInformation: `Parses CDS and issues parser errors`,
21
21
  tags: [_irule_1.RuleTag.Syntax],
22
22
  };
23
23
  }
@@ -30,11 +30,12 @@ class CDSParserError {
30
30
  initialize(_reg) {
31
31
  return this;
32
32
  }
33
- run(o) {
33
+ run(object) {
34
34
  const issues = [];
35
- if (o.getType() === "DDLS" && o instanceof objects_1.DataDefinition) {
36
- const hasError = o.hasParserError();
37
- const file = o.findSourceFile();
35
+ if ((object.getType() === "DDLS" && object instanceof objects_1.DataDefinition) ||
36
+ (object.getType() === "DDLX" && object instanceof objects_1.CDSMetadataExtension)) {
37
+ const hasError = object.hasParserError();
38
+ const file = object.findSourceFile();
38
39
  if (hasError === true && file) {
39
40
  issues.push(issue_1.Issue.atRow(file, 1, "CDS Parser error", this.getMetadata().key, this.getConfig().severity));
40
41
  }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChangeIfToCase = exports.ChangeIfToCaseConf = void 0;
4
+ const issue_1 = require("../issue");
5
+ const Expressions = require("../abap/2_statements/expressions");
6
+ const Statements = require("../abap/2_statements/statements");
7
+ const Structures = require("../abap/3_structures/structures");
8
+ const _abap_rule_1 = require("./_abap_rule");
9
+ const _basic_rule_config_1 = require("./_basic_rule_config");
10
+ const _irule_1 = require("./_irule");
11
+ class ChangeIfToCaseConf extends _basic_rule_config_1.BasicRuleConfig {
12
+ }
13
+ exports.ChangeIfToCaseConf = ChangeIfToCaseConf;
14
+ class ChangeIfToCase extends _abap_rule_1.ABAPRule {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.conf = new ChangeIfToCaseConf();
18
+ }
19
+ getMetadata() {
20
+ return {
21
+ key: "change_if_to_case",
22
+ title: "Change IF to CASE",
23
+ shortDescription: `Finds IF constructs that can be changed to CASE`,
24
+ // eslint-disable-next-line max-len
25
+ extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-case-to-else-if-for-multiple-alternative-conditions`,
26
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Styleguide],
27
+ badExample: `IF l_fcat-fieldname EQ 'FOO'.
28
+ ELSEIF l_fcat-fieldname = 'BAR'
29
+ OR l_fcat-fieldname = 'MOO'.
30
+ ENDIF.`,
31
+ goodExample: `CASE l_fcat-fieldname.
32
+ WHEN 'FOO'.
33
+ WHEN 'BAR' OR 'MOO'.
34
+ ENDCASE.`,
35
+ };
36
+ }
37
+ getConfig() {
38
+ return this.conf;
39
+ }
40
+ setConfig(conf) {
41
+ this.conf = conf;
42
+ }
43
+ runParsed(file) {
44
+ var _a;
45
+ const issues = [];
46
+ const stru = file.getStructure();
47
+ if (stru === undefined) {
48
+ return issues;
49
+ }
50
+ for (const i of stru.findAllStructuresRecursive(Structures.If)) {
51
+ const conds = [];
52
+ const ifStatement = i.findDirectStatement(Statements.If);
53
+ if (ifStatement === undefined) {
54
+ continue;
55
+ }
56
+ conds.push(ifStatement === null || ifStatement === void 0 ? void 0 : ifStatement.findDirectExpression(Expressions.Cond));
57
+ for (const ei of i.findDirectStructures(Structures.ElseIf)) {
58
+ conds.push((_a = ei.findDirectStatement(Statements.ElseIf)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Cond));
59
+ }
60
+ if (conds.length === 1) {
61
+ continue;
62
+ }
63
+ const issue = this.analyze(conds);
64
+ if (issue === true) {
65
+ const message = "Change IF to CASE";
66
+ issues.push(issue_1.Issue.atStatement(file, ifStatement, message, this.getMetadata().key, this.getConfig().severity));
67
+ }
68
+ }
69
+ return issues;
70
+ }
71
+ analyze(conds) {
72
+ var _a, _b, _c, _d, _e;
73
+ const tuples = [];
74
+ for (const c of conds) {
75
+ if (c === undefined) {
76
+ continue;
77
+ }
78
+ if (c.findFirstExpression(Expressions.CondSub)) {
79
+ return false;
80
+ }
81
+ else if (c.findDirectTokenByText("AND") || c.findDirectTokenByText("EQUIV")) {
82
+ return false;
83
+ }
84
+ for (const compare of c.findAllExpressions(Expressions.Compare)) {
85
+ const op = (_a = compare.findDirectExpression(Expressions.CompareOperator)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
86
+ if (compare.getChildren().length !== 3) {
87
+ return false;
88
+ }
89
+ else if (op !== "=" && op !== "EQ") {
90
+ return false;
91
+ }
92
+ const left = (_c = (_b = compare.getChildren()[0]) === null || _b === void 0 ? void 0 : _b.concatTokens()) === null || _c === void 0 ? void 0 : _c.toUpperCase();
93
+ const right = (_e = (_d = compare.getChildren()[2]) === null || _d === void 0 ? void 0 : _d.concatTokens()) === null || _e === void 0 ? void 0 : _e.toUpperCase();
94
+ tuples.push({ left, right });
95
+ }
96
+ }
97
+ if (tuples.length === 1) {
98
+ return false;
99
+ }
100
+ let chain = "";
101
+ if (tuples[0].left === tuples[1].left) {
102
+ chain = tuples[0].left;
103
+ }
104
+ else if (tuples[0].left === tuples[1].right) {
105
+ chain = tuples[0].left;
106
+ }
107
+ else if (tuples[0].right === tuples[1].right) {
108
+ chain = tuples[0].right;
109
+ }
110
+ else if (tuples[0].right === tuples[1].left) {
111
+ chain = tuples[0].right;
112
+ }
113
+ else {
114
+ return false;
115
+ }
116
+ for (const t of tuples) {
117
+ if (t.left !== chain && t.right !== chain) {
118
+ return false;
119
+ }
120
+ }
121
+ return true;
122
+ }
123
+ }
124
+ exports.ChangeIfToCase = ChangeIfToCase;
125
+ //# sourceMappingURL=change_if_to_case.js.map
@@ -24,7 +24,7 @@ class ConstantClasses {
24
24
  title: "Validate constant classes",
25
25
  shortDescription: `Checks that a class contains exactly the constants corresponding to a domain's fixed values.`,
26
26
  extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-enumeration-classes-to-constants-interfaces`,
27
- tags: [_irule_1.RuleTag.Syntax, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Experimental],
27
+ tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Experimental],
28
28
  };
29
29
  }
30
30
  initialize(reg) {
@@ -83,10 +83,19 @@ Only one transformation is applied to a statement at a time, so multiple steps m
83
83
  const version = this.lowReg.getConfig().getVersion();
84
84
  if (version === version_1.Version.v702 || version === version_1.Version.OpenABAP) {
85
85
  this.initHighReg();
86
- this.graph = new include_graph_1.IncludeGraph(reg);
87
86
  }
88
87
  return this;
89
88
  }
89
+ listMainForInclude(filename) {
90
+ if (filename === undefined) {
91
+ return [];
92
+ }
93
+ // only initialize this.graph if needed
94
+ if (this.graph === undefined) {
95
+ this.graph = new include_graph_1.IncludeGraph(this.lowReg);
96
+ }
97
+ return this.graph.listMainForInclude(filename);
98
+ }
90
99
  run(lowObj) {
91
100
  var _a;
92
101
  const ret = [];
@@ -105,7 +114,7 @@ Only one transformation is applied to a statement at a time, so multiple steps m
105
114
  let highSyntaxObj = highObj;
106
115
  // for includes do the syntax check via a main program
107
116
  if (lowObj instanceof objects_1.Program && lowObj.isInclude()) {
108
- const mains = this.graph.listMainForInclude((_a = lowObj.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getFilename());
117
+ const mains = this.listMainForInclude((_a = lowObj.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getFilename());
109
118
  if (mains.length <= 0) {
110
119
  return [];
111
120
  }
@@ -115,8 +124,8 @@ Only one transformation is applied to a statement at a time, so multiple steps m
115
124
  }
116
125
  highSyntaxObj = this.highReg.findObjectForFile(f);
117
126
  }
118
- const highSyntax = new syntax_1.SyntaxLogic(this.highReg, highSyntaxObj).run();
119
127
  for (const lowFile of lowObj.getABAPFiles()) {
128
+ let highSyntax = undefined;
120
129
  const highFile = highObj.getABAPFileByName(lowFile.getFilename());
121
130
  if (highFile === undefined) {
122
131
  continue;
@@ -137,6 +146,9 @@ Only one transformation is applied to a statement at a time, so multiple steps m
137
146
  const high = highStatements[i];
138
147
  if ((low.get() instanceof _statement_1.Unknown && !(high.get() instanceof _statement_1.Unknown))
139
148
  || high.findFirstExpression(Expressions.InlineData)) {
149
+ if (highSyntax === undefined) {
150
+ highSyntax = new syntax_1.SyntaxLogic(this.highReg, highSyntaxObj).run();
151
+ }
140
152
  const issue = this.checkStatement(low, high, lowFile, highSyntax, highFile);
141
153
  if (issue) {
142
154
  ret.push(issue);
@@ -1500,54 +1512,65 @@ ${indentation} output = ${topTarget}.`;
1500
1512
  let end = "";
1501
1513
  let structureName = uniqueName;
1502
1514
  let added = false;
1503
- let skip = false;
1504
1515
  let data = "";
1505
1516
  let previous = undefined;
1506
- for (const b of (valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren()) || []) {
1507
- if (b.concatTokens() === "(" && added === false) {
1508
- structureName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
1509
- data = indentation + `DATA ${structureName} LIKE LINE OF ${uniqueName}.\n`;
1510
- }
1511
- if (b.get() instanceof Expressions.FieldAssignment) {
1517
+ for (const a of (valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren()) || []) {
1518
+ if (a.get() instanceof Expressions.FieldAssignment) {
1512
1519
  if (added === false) {
1513
1520
  body += data;
1514
1521
  added = true;
1515
1522
  }
1516
- body += indentation + structureName + "-" + b.concatTokens() + ".\n";
1523
+ body += indentation + structureName + "-" + a.concatTokens() + ".\n";
1517
1524
  }
1518
- else if (b instanceof nodes_1.ExpressionNode && b.get() instanceof Expressions.For) {
1519
- const outlineFor = this.outlineFor(b, indentation, lowFile, highSyntax);
1525
+ else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.For) {
1526
+ const outlineFor = this.outlineFor(a, indentation, lowFile, highSyntax);
1520
1527
  body += outlineFor.body;
1521
1528
  end = outlineFor.end + `.\n` + end;
1522
1529
  indentation += " ";
1523
1530
  }
1524
- else if (b.get() instanceof Expressions.Source) {
1531
+ else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.Source) {
1532
+ // special handling for superflous value expression
1525
1533
  if ((valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren().length) === 1) {
1526
- body += indentation + uniqueName + " = " + b.concatTokens() + `.\n`;
1527
- }
1528
- structureName = b.concatTokens();
1529
- if (base && (valueBody === null || valueBody === void 0 ? void 0 : valueBody.findDirectTokenByText("(")) === undefined) {
1530
- structureName = uniqueName;
1534
+ body += indentation + uniqueName + " = " + a.concatTokens() + `.\n`;
1531
1535
  }
1532
1536
  }
1533
- else if (b.get() instanceof Expressions.ValueBodyLines) {
1534
- body += indentation + "APPEND " + b.concatTokens() + ` TO ${uniqueName}.\n`;
1535
- skip = true;
1537
+ else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.Let) {
1538
+ body += this.outlineLet(a, indentation, highSyntax, lowFile);
1536
1539
  }
1537
- else if (b instanceof nodes_1.ExpressionNode && b.get() instanceof Expressions.Let) {
1538
- body += this.outlineLet(b, indentation, highSyntax, lowFile);
1539
- }
1540
- else if (b.concatTokens() === ")") {
1541
- if (added === false && (previous === null || previous === void 0 ? void 0 : previous.concatTokens()) === "(") {
1542
- body += data;
1543
- added = true;
1544
- }
1545
- if (skip === false) {
1546
- body += indentation + `APPEND ${structureName} TO ${uniqueName}.\n`;
1540
+ if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.ValueBodyLine) {
1541
+ let skip = false;
1542
+ for (const b of (a === null || a === void 0 ? void 0 : a.getChildren()) || []) {
1543
+ if (b.concatTokens() === "(" && added === false) {
1544
+ structureName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);
1545
+ data = indentation + `DATA ${structureName} LIKE LINE OF ${uniqueName}.\n`;
1546
+ }
1547
+ if (b.get() instanceof Expressions.FieldAssignment) {
1548
+ if (added === false) {
1549
+ body += data;
1550
+ added = true;
1551
+ }
1552
+ body += indentation + structureName + "-" + b.concatTokens() + ".\n";
1553
+ }
1554
+ else if (b.get() instanceof Expressions.Source) {
1555
+ body += indentation + "APPEND " + b.concatTokens() + ` TO ${uniqueName}.\n`;
1556
+ skip = true;
1557
+ }
1558
+ else if (b.get() instanceof Expressions.ValueBodyLines) {
1559
+ body += indentation + "APPEND " + b.concatTokens() + ` TO ${uniqueName}.\n`;
1560
+ skip = true;
1561
+ }
1562
+ else if (b.concatTokens() === ")") {
1563
+ if (added === false && (previous === null || previous === void 0 ? void 0 : previous.concatTokens()) === "(") {
1564
+ body += data;
1565
+ added = true;
1566
+ }
1567
+ if (skip === false) {
1568
+ body += indentation + `APPEND ${structureName} TO ${uniqueName}.\n`;
1569
+ }
1570
+ }
1571
+ previous = b;
1547
1572
  }
1548
- skip = false;
1549
1573
  }
1550
- previous = b;
1551
1574
  }
1552
1575
  if (body === "" && ((_b = valueBody === null || valueBody === void 0 ? void 0 : valueBody.getLastChild()) === null || _b === void 0 ? void 0 : _b.getFirstToken().getStr().toUpperCase()) === "OPTIONAL") {
1553
1576
  const fieldChain = valueBody.findFirstExpression(Expressions.FieldChain);
@@ -24,21 +24,21 @@ __exportStar(require("./avoid_use"), exports);
24
24
  __exportStar(require("./begin_end_names"), exports);
25
25
  __exportStar(require("./begin_single_include"), exports);
26
26
  __exportStar(require("./call_transaction_authority_check"), exports);
27
- __exportStar(require("./cds_parser_error"), exports);
27
+ __exportStar(require("./cds_comment_style"), exports);
28
28
  __exportStar(require("./cds_legacy_view"), exports);
29
+ __exportStar(require("./cds_parser_error"), exports);
29
30
  __exportStar(require("./chain_mainly_declarations"), exports);
31
+ __exportStar(require("./change_if_to_case"), exports);
30
32
  __exportStar(require("./check_abstract"), exports);
31
33
  __exportStar(require("./check_comments"), exports);
32
34
  __exportStar(require("./check_ddic"), exports);
33
35
  __exportStar(require("./check_include"), exports);
34
36
  __exportStar(require("./check_subrc"), exports);
35
- __exportStar(require("./no_external_form_calls"), exports);
36
37
  __exportStar(require("./check_syntax"), exports);
37
- __exportStar(require("./classic_exceptions_overlap"), exports);
38
38
  __exportStar(require("./check_text_elements"), exports);
39
39
  __exportStar(require("./check_transformation_exists"), exports);
40
- __exportStar(require("./superfluous_value"), exports);
41
40
  __exportStar(require("./class_attribute_names"), exports);
41
+ __exportStar(require("./classic_exceptions_overlap"), exports);
42
42
  __exportStar(require("./cloud_types"), exports);
43
43
  __exportStar(require("./colon_missing_space"), exports);
44
44
  __exportStar(require("./commented_code"), exports);
@@ -102,6 +102,7 @@ __exportStar(require("./nesting"), exports);
102
102
  __exportStar(require("./newline_between_methods"), exports);
103
103
  __exportStar(require("./no_aliases"), exports);
104
104
  __exportStar(require("./no_chained_assignment"), exports);
105
+ __exportStar(require("./no_external_form_calls"), exports);
105
106
  __exportStar(require("./no_inline_in_optional_branches"), exports);
106
107
  __exportStar(require("./no_public_attributes"), exports);
107
108
  __exportStar(require("./no_yoda_conditions"), exports);
@@ -140,6 +141,7 @@ __exportStar(require("./sql_escape_host_variables"), exports);
140
141
  __exportStar(require("./start_at_tab"), exports);
141
142
  __exportStar(require("./static_call_via_instance"), exports);
142
143
  __exportStar(require("./superclass_final"), exports);
144
+ __exportStar(require("./superfluous_value"), exports);
143
145
  __exportStar(require("./sy_modification"), exports);
144
146
  __exportStar(require("./tabl_enhancement_category"), exports);
145
147
  __exportStar(require("./try_without_catch"), exports);
@@ -50,7 +50,7 @@ This rule makes sure the spaces are consistently required across the language.`,
50
50
  }
51
51
  missingSpace(statement) {
52
52
  const found = statement.findAllExpressionsMulti([Expressions.CondSub, Expressions.SQLCond,
53
- Expressions.ValueBody, Expressions.NewObject, Expressions.Cond,
53
+ Expressions.ValueBodyLine, Expressions.NewObject, Expressions.Cond,
54
54
  Expressions.ComponentCond, Expressions.ComponentCondSub, Expressions.MethodCallParam], true);
55
55
  let pos = undefined;
56
56
  for (const f of found) {
@@ -70,8 +70,8 @@ This rule makes sure the spaces are consistently required across the language.`,
70
70
  else if (type instanceof Expressions.SQLCond) {
71
71
  pos = this.checkSQLCond(f);
72
72
  }
73
- else if (type instanceof Expressions.ValueBody) {
74
- pos = this.checkValueBody(f);
73
+ else if (type instanceof Expressions.ValueBodyLine) {
74
+ pos = this.checkValueBodyLine(f);
75
75
  }
76
76
  else if (type instanceof Expressions.NewObject) {
77
77
  pos = this.checkNewObject(f);
@@ -173,7 +173,7 @@ This rule makes sure the spaces are consistently required across the language.`,
173
173
  }
174
174
  return undefined;
175
175
  }
176
- checkValueBody(vb) {
176
+ checkValueBodyLine(vb) {
177
177
  var _a, _b;
178
178
  const children = vb.getChildren();
179
179
  for (let i = 0; i < children.length; i++) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.92.1",
3
+ "version": "2.93.1",
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
  "@types/mocha": "^9.1.1",
51
51
  "@types/node": "^18.7.13",
52
52
  "chai": "^4.3.6",
53
- "eslint": "^8.22.0",
53
+ "eslint": "^8.23.0",
54
54
  "mocha": "^10.0.0",
55
55
  "c8": "^7.12.0",
56
56
  "source-map-support": "^0.5.21",