@abaplint/core 2.120.74 → 2.120.75

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.
Files changed (39) hide show
  1. package/build/abaplint.d.ts +2 -1
  2. package/build/src/abap/2_statements/combi.js +143 -51
  3. package/build/src/abap/5_syntax/statements/append.js +6 -0
  4. package/build/src/ddic.js +1 -1
  5. package/build/src/objects/domain.js +4 -1
  6. package/build/src/registry.js +1 -1
  7. package/build/src/rules/abapdoc_html_tag.js +123 -0
  8. package/build/src/rules/abapdoc_leading_at.js +117 -0
  9. package/build/src/rules/abapdoc_parameter_names.js +149 -0
  10. package/build/src/rules/cds_check_syntax.js +4 -4
  11. package/build/src/rules/change_if_to_case.js +3 -2
  12. package/build/src/rules/changing_sorted_line.js +235 -0
  13. package/build/src/rules/class_attribute_names.js +15 -6
  14. package/build/src/rules/delete_index_in_loop.js +163 -0
  15. package/build/src/rules/final_newline.js +78 -0
  16. package/build/src/rules/forbidden_identifier.js +4 -3
  17. package/build/src/rules/forbidden_void_type.js +4 -9
  18. package/build/src/rules/index.js +11 -0
  19. package/build/src/rules/inline_packed_computation.js +220 -0
  20. package/build/src/rules/intf_referencing_clas.js +3 -1
  21. package/build/src/rules/line_only_punc.js +1 -1
  22. package/build/src/rules/local_class_naming.js +15 -2
  23. package/build/src/rules/local_variable_names.js +18 -9
  24. package/build/src/rules/macro_naming.js +3 -2
  25. package/build/src/rules/method_parameter_names.js +17 -7
  26. package/build/src/rules/modify_only_own_db_tables.js +3 -2
  27. package/build/src/rules/no_prefixes.js +25 -12
  28. package/build/src/rules/object_naming.js +18 -3
  29. package/build/src/rules/prefer_inline_cast.js +276 -0
  30. package/build/src/rules/range_row_values.js +200 -0
  31. package/build/src/rules/selection_screen_naming.js +21 -2
  32. package/build/src/rules/sicf_consistency.js +1 -2
  33. package/build/src/rules/sort_empty_key.js +188 -0
  34. package/build/src/rules/subrc_after_assign.js +220 -0
  35. package/build/src/rules/types_naming.js +3 -2
  36. package/build/src/rules/wrong_abapdoc_position.js +58 -11
  37. package/build/src/rules/xml_consistency.js +6 -2
  38. package/build/src/utils/name_validator.js +7 -3
  39. package/package.json +1 -1
@@ -2038,7 +2038,8 @@ declare class Domain extends AbstractObject {
2038
2038
  };
2039
2039
  getIdentifier(): Identifier | undefined;
2040
2040
  setDirty(): void;
2041
- parseType(reg: IRegistry, dataElement?: string, description?: string): AbstractType;
2041
+ parseType(reg: IRegistry): AbstractType;
2042
+ parseDomainType(reg: IRegistry, dataElement?: string, description?: string): AbstractType;
2042
2043
  parse(): {
2043
2044
  updated: boolean;
2044
2045
  runtime: number;
@@ -58,6 +58,9 @@ const Tokens = __importStar(require("../1_lexer/tokens"));
58
58
  const nodes_1 = require("../nodes");
59
59
  const version_1 = require("../../version");
60
60
  const result_1 = require("./result");
61
+ // shared result for "nothing matched", frozen so accidental mutation throws instead of leaking between calls.
62
+ // Returned arrays are never mutated by callers, which allows returning shared/input arrays as is
63
+ const EMPTY = Object.freeze([]);
61
64
  class Regex {
62
65
  constructor(r) {
63
66
  this.regexp = r;
@@ -69,17 +72,23 @@ class Regex {
69
72
  return [];
70
73
  }
71
74
  run(r) {
72
- const result = [];
75
+ let result = undefined;
73
76
  for (const input of r) {
74
77
  if (input.remainingLength() === 0) {
75
78
  continue;
76
79
  }
77
80
  const token = input.peek();
78
81
  if (this.regexp.test(token.getStr()) === true) {
79
- result.push(input.shift(new nodes_1.TokenNodeRegex(token)));
82
+ const shifted = input.shift(new nodes_1.TokenNodeRegex(token));
83
+ if (result === undefined) {
84
+ result = [shifted];
85
+ }
86
+ else {
87
+ result.push(shifted);
88
+ }
80
89
  }
81
90
  }
82
- return result;
91
+ return result !== null && result !== void 0 ? result : EMPTY;
83
92
  }
84
93
  railroad() {
85
94
  return "Railroad.Terminal(\"" + this.regexp.source.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\")";
@@ -102,15 +111,20 @@ class Word {
102
111
  return [];
103
112
  }
104
113
  run(r) {
105
- const result = [];
114
+ let result = undefined;
106
115
  for (const input of r) {
107
116
  if (input.remainingLength() !== 0
108
117
  && input.peek().getUpperStr() === this.s) {
109
- // console.log("match, " + this.s + result.length);
110
- result.push(input.shift(new nodes_1.TokenNode(input.peek())));
118
+ const shifted = input.shift(new nodes_1.TokenNode(input.peek()));
119
+ if (result === undefined) {
120
+ result = [shifted];
121
+ }
122
+ else {
123
+ result.push(shifted);
124
+ }
111
125
  }
112
126
  }
113
- return result;
127
+ return result !== null && result !== void 0 ? result : EMPTY;
114
128
  }
115
129
  railroad() {
116
130
  return "Railroad.Terminal('\"" + this.s + "\"')";
@@ -134,14 +148,20 @@ class Token {
134
148
  return [];
135
149
  }
136
150
  run(r) {
137
- const result = [];
151
+ let result = undefined;
138
152
  for (const input of r) {
139
153
  if (input.remainingLength() !== 0
140
154
  && input.peek().constructor === this.tokenType) {
141
- result.push(input.shift(new nodes_1.TokenNode(input.peek())));
155
+ const shifted = input.shift(new nodes_1.TokenNode(input.peek()));
156
+ if (result === undefined) {
157
+ result = [shifted];
158
+ }
159
+ else {
160
+ result.push(shifted);
161
+ }
142
162
  }
143
163
  }
144
- return result;
164
+ return result !== null && result !== void 0 ? result : EMPTY;
145
165
  }
146
166
  railroad() {
147
167
  let text = this.name;
@@ -179,9 +199,9 @@ class Vers {
179
199
  if (this.also === AlsoIn.OpenABAP) {
180
200
  return this.runnable.run(r);
181
201
  }
182
- return (0, version_1.releaseAtLeast)(version_1.Release.v702, this.release) ? this.runnable.run(r) : [];
202
+ return (0, version_1.releaseAtLeast)(version_1.Release.v702, this.release) ? this.runnable.run(r) : EMPTY;
183
203
  }
184
- return (0, version_1.releaseAtLeast)(Combi.getRelease(), this.release) ? this.runnable.run(r) : [];
204
+ return (0, version_1.releaseAtLeast)(Combi.getRelease(), this.release) ? this.runnable.run(r) : EMPTY;
185
205
  }
186
206
  getUsing() {
187
207
  return this.runnable.getUsing();
@@ -229,7 +249,7 @@ class LangVers {
229
249
  return this.runnable.run(r);
230
250
  }
231
251
  else {
232
- return [];
252
+ return EMPTY;
233
253
  }
234
254
  }
235
255
  railroad() {
@@ -262,7 +282,7 @@ class LangVersNot {
262
282
  return this.runnable.run(r);
263
283
  }
264
284
  else {
265
- return [];
285
+ return EMPTY;
266
286
  }
267
287
  }
268
288
  railroad() {
@@ -290,6 +310,22 @@ class OptionalPriority {
290
310
  return this.optional.getUsing();
291
311
  }
292
312
  run(r) {
313
+ if (r.length === 1) {
314
+ // single input, pass and return the input array without wrapping
315
+ const res = this.optional.run(r);
316
+ if (res.length > 1) {
317
+ return res;
318
+ }
319
+ else if (res.length === 0) {
320
+ return r;
321
+ }
322
+ else if (res[0].remainingLength() < r[0].remainingLength()) {
323
+ return res;
324
+ }
325
+ else {
326
+ return r;
327
+ }
328
+ }
293
329
  const result = [];
294
330
  for (const input of r) {
295
331
  const res = this.optional.run([input]);
@@ -329,6 +365,11 @@ class Optional {
329
365
  return this.optional.getUsing();
330
366
  }
331
367
  run(r) {
368
+ if (r.length === 1) {
369
+ // single input, pass and return the input array without wrapping
370
+ const res = this.optional.run(r);
371
+ return res.length === 0 ? r : r.concat(res);
372
+ }
332
373
  const result = [];
333
374
  for (const input of r) {
334
375
  result.push(input);
@@ -366,14 +407,16 @@ class Star {
366
407
  let result = r;
367
408
  try {
368
409
  let res = r;
369
- let input = [];
370
410
  for (;;) {
371
- input = res;
372
- res = this.sta.run(input);
411
+ res = this.sta.run(res);
373
412
  if (res.length === 0) {
374
413
  break;
375
414
  }
376
- if (res.length > 1000) {
415
+ if (result === r) {
416
+ // copy on first match, the input array must not be mutated
417
+ result = r.concat(res);
418
+ }
419
+ else if (res.length > 1000) {
377
420
  // avoid stack overflow
378
421
  result = result.concat(res);
379
422
  }
@@ -515,6 +558,17 @@ class Sequence {
515
558
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
516
559
  }
517
560
  run(r) {
561
+ if (r.length === 1) {
562
+ // single input, pass it down without wrapping and return the last result as is
563
+ let temp = r;
564
+ for (const sequence of this.list) {
565
+ temp = sequence.run(temp);
566
+ if (temp.length === 0) {
567
+ return EMPTY;
568
+ }
569
+ }
570
+ return temp;
571
+ }
518
572
  let result = [];
519
573
  for (const input of r) {
520
574
  let temp = [input];
@@ -592,12 +646,33 @@ class Expression {
592
646
  this.runnable = undefined;
593
647
  }
594
648
  run(r) {
595
- const results = [];
596
649
  if (this.runnable === undefined) {
597
650
  this.runnable = this.getRunnable();
598
651
  }
652
+ if (r.length === 1) {
653
+ // single input, pass it down without wrapping
654
+ const input = r[0];
655
+ const temp = this.runnable.run(r);
656
+ if (temp.length === 0) {
657
+ return EMPTY;
658
+ }
659
+ const results = new Array(temp.length);
660
+ for (let i = 0; i < temp.length; i++) {
661
+ const t = temp[i];
662
+ const consumed = input.remainingLength() - t.remainingLength();
663
+ results[i] = consumed > 0 ? t.wrapConsumed(consumed, new nodes_1.ExpressionNode(this)) : t;
664
+ }
665
+ return results;
666
+ }
667
+ let results = undefined;
599
668
  for (const input of r) {
600
669
  const temp = this.runnable.run([input]);
670
+ if (temp.length === 0) {
671
+ continue;
672
+ }
673
+ else if (results === undefined) {
674
+ results = [];
675
+ }
601
676
  for (const t of temp) {
602
677
  const consumed = input.remainingLength() - t.remainingLength();
603
678
  if (consumed > 0) {
@@ -609,8 +684,7 @@ class Expression {
609
684
  }
610
685
  }
611
686
  }
612
- // console.dir(results);
613
- return results;
687
+ return results !== null && results !== void 0 ? results : EMPTY;
614
688
  }
615
689
  listKeywords() {
616
690
  // do not recurse, all Expressions are evaluated only on first level
@@ -651,12 +725,16 @@ class Permutation {
651
725
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
652
726
  }
653
727
  run(r) {
654
- const result = [];
655
- const copy = this.list.slice();
728
+ let result = undefined;
729
+ let copy = undefined;
656
730
  for (let index = 0; index < this.list.length; index++) {
657
731
  const temp = this.list[index].run(r);
658
732
  if (temp.length !== 0) {
659
733
  // match
734
+ if (result === undefined || copy === undefined) {
735
+ result = [];
736
+ copy = this.list.slice();
737
+ }
660
738
  result.push(...temp);
661
739
  const left = copy;
662
740
  left.splice(index, 1);
@@ -668,7 +746,7 @@ class Permutation {
668
746
  }
669
747
  }
670
748
  }
671
- return result;
749
+ return result !== null && result !== void 0 ? result : EMPTY;
672
750
  }
673
751
  railroad() {
674
752
  const children = this.list.map((e) => { return e.railroad(); });
@@ -745,17 +823,31 @@ class Alternative {
745
823
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
746
824
  }
747
825
  run(r) {
748
- const result = [];
826
+ var _a;
827
+ // only allocate a new array when more than one alternative matches
828
+ let single = undefined;
829
+ let result = undefined;
749
830
  for (const sequ of this.list) {
750
831
  const temp = sequ.run(r);
751
- if (temp.length === 1) {
752
- result.push(temp[0]);
832
+ if (temp.length === 0) {
833
+ continue;
834
+ }
835
+ else if (result !== undefined) {
836
+ if (temp.length === 1) {
837
+ result.push(temp[0]);
838
+ }
839
+ else {
840
+ result.push(...temp);
841
+ }
842
+ }
843
+ else if (single !== undefined) {
844
+ result = single.concat(temp);
753
845
  }
754
846
  else {
755
- result.push(...temp);
847
+ single = temp;
756
848
  }
757
849
  }
758
- return result;
850
+ return (_a = result !== null && result !== void 0 ? result : single) !== null && _a !== void 0 ? _a : EMPTY;
759
851
  }
760
852
  railroad() {
761
853
  const children = this.list.map((e) => { return e.railroad(); });
@@ -806,21 +898,13 @@ class AlternativePriority {
806
898
  return this.list.reduce((a, c) => { return a.concat(c.getUsing()); }, []);
807
899
  }
808
900
  run(r) {
809
- const result = [];
810
901
  for (const sequ of this.list) {
811
- // console.log(seq.toStr());
812
902
  const temp = sequ.run(r);
813
903
  if (temp.length > 0) {
814
- if (temp.length === 1) {
815
- result.push(temp[0]);
816
- }
817
- else {
818
- result.push(...temp);
819
- }
820
- break;
904
+ return temp;
821
905
  }
822
906
  }
823
- return result;
907
+ return EMPTY;
824
908
  }
825
909
  railroad() {
826
910
  const children = this.list.map((e) => { return e.railroad(); });
@@ -1026,18 +1110,21 @@ class StopBefore2 {
1026
1110
  getUsing() { return []; }
1027
1111
  run(r) {
1028
1112
  var _a;
1029
- const result = [];
1030
- for (const input of r) {
1113
+ // only copy when something is filtered out
1114
+ let result = undefined;
1115
+ for (let i = 0; i < r.length; i++) {
1116
+ const input = r[i];
1031
1117
  const next = input.peek();
1032
- if (next === undefined) {
1033
- continue;
1034
- }
1035
- if (next.getUpperStr() === this.t1 && ((_a = input.peekAt(1)) === null || _a === void 0 ? void 0 : _a.getUpperStr()) === this.t2) {
1118
+ if (next === undefined
1119
+ || (next.getUpperStr() === this.t1 && ((_a = input.peekAt(1)) === null || _a === void 0 ? void 0 : _a.getUpperStr()) === this.t2)) {
1120
+ if (result === undefined) {
1121
+ result = r.slice(0, i);
1122
+ }
1036
1123
  continue;
1037
1124
  }
1038
- result.push(input);
1125
+ result === null || result === void 0 ? void 0 : result.push(input);
1039
1126
  }
1040
- return result;
1127
+ return result !== null && result !== void 0 ? result : r;
1041
1128
  }
1042
1129
  railroad() { return "Railroad.Terminal('stopBefore(" + this.t1 + " " + this.t2 + ")')"; }
1043
1130
  toStr() { return "stopBefore(" + this.t1 + "," + this.t2 + ")"; }
@@ -1052,15 +1139,20 @@ class StopBefore1 {
1052
1139
  getUsing() { return []; }
1053
1140
  run(r) {
1054
1141
  var _a;
1055
- const result = [];
1056
- for (const input of r) {
1142
+ // only copy when something is filtered out
1143
+ let result = undefined;
1144
+ for (let i = 0; i < r.length; i++) {
1145
+ const input = r[i];
1057
1146
  const next = (_a = input.peek()) === null || _a === void 0 ? void 0 : _a.getUpperStr();
1058
1147
  if (next !== undefined && this.words.includes(next)) {
1148
+ if (result === undefined) {
1149
+ result = r.slice(0, i);
1150
+ }
1059
1151
  continue;
1060
1152
  }
1061
- result.push(input);
1153
+ result === null || result === void 0 ? void 0 : result.push(input);
1062
1154
  }
1063
- return result;
1155
+ return result !== null && result !== void 0 ? result : r;
1064
1156
  }
1065
1157
  railroad() { return "Railroad.Terminal('stopBefore(" + this.words.join("|") + ")')"; }
1066
1158
  toStr() { return "stopBefore(" + this.words.join(",") + ")"; }
@@ -50,6 +50,12 @@ class Append {
50
50
  if (target) {
51
51
  targetType = target_1.Target.runSyntax(target, input);
52
52
  }
53
+ // a hashed table has no index, APPEND adds at the end
54
+ if (targetType instanceof basic_1.TableType && targetType.getAccessType() === basic_1.TableAccessType.hashed) {
55
+ const message = "Implicit or explicit index operation on hashed table is not possible";
56
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
57
+ return;
58
+ }
53
59
  const fsTarget = node.findExpressionAfterToken("ASSIGNING");
54
60
  if (fsTarget && fsTarget.get() instanceof Expressions.FSTarget) {
55
61
  if (!(targetType instanceof basic_1.TableType) && !(targetType instanceof basic_1.VoidType) && !(targetType instanceof basic_1.UnknownType)) {
package/build/src/ddic.js CHANGED
@@ -256,7 +256,7 @@ class DDIC {
256
256
  lookupDomain(name, dataElement, description) {
257
257
  const found = this.reg.getObject("DOMA", name);
258
258
  if (found) {
259
- return { type: found.parseType(this.reg, dataElement, description), object: found };
259
+ return { type: found.parseDomainType(this.reg, dataElement, description), object: found };
260
260
  }
261
261
  else if (this.reg.inErrorNamespace(name)) {
262
262
  return { type: new Types.UnknownType(name + ", lookupDomain"), object: undefined };
@@ -81,7 +81,10 @@ class Domain extends _abstract_object_1.AbstractObject {
81
81
  this.parsedXML = undefined;
82
82
  super.setDirty();
83
83
  }
84
- parseType(reg, dataElement, description) {
84
+ parseType(reg) {
85
+ return this.parseDomainType(reg);
86
+ }
87
+ parseDomainType(reg, dataElement, description) {
85
88
  // dont cache the DOMA parsed type, they are cached on DTEL level
86
89
  // also note that the type carries the name of the DTEL
87
90
  if (this.parsedXML === undefined) {
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.74";
78
+ return "2.120.75";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AbapdocHtmlTag = exports.AbapdocHtmlTagConf = void 0;
37
+ const Statements = __importStar(require("../abap/2_statements/statements"));
38
+ const issue_1 = require("../issue");
39
+ const _abap_rule_1 = require("./_abap_rule");
40
+ const _basic_rule_config_1 = require("./_basic_rule_config");
41
+ const _irule_1 = require("./_irule");
42
+ const _statement_1 = require("../abap/2_statements/statements/_statement");
43
+ const position_1 = require("../position");
44
+ class AbapdocHtmlTagConf extends _basic_rule_config_1.BasicRuleConfig {
45
+ }
46
+ exports.AbapdocHtmlTagConf = AbapdocHtmlTagConf;
47
+ const ALLOWED = new Set(["p", "em", "strong", "ul", "ol", "li", "br", "h1", "h2", "h3"]);
48
+ class AbapdocHtmlTag extends _abap_rule_1.ABAPRule {
49
+ constructor() {
50
+ super(...arguments);
51
+ this.conf = new AbapdocHtmlTagConf();
52
+ }
53
+ getMetadata() {
54
+ return {
55
+ key: "abapdoc_html_tag",
56
+ title: "Unsupported HTML tag in ABAP Doc",
57
+ shortDescription: `Reports tag-like tokens in ABAP Doc which are not ABAP Doc HTML tags.`,
58
+ extendedInformation: `ABAP Doc is parsed as HTML, a field symbol or a placeholder written as <name> is an
59
+ unsupported and unclosed tag, the system warns and the rendered documentation drops the word.
60
+
61
+ Supported tags are p, em, strong, ul, ol, li, br, h1, h2 and h3, also as closing tags and with attributes.
62
+
63
+ Write &lt;name&gt; to show the angle brackets. A "<" which is not followed by a letter, like "a < b", is not reported.
64
+
65
+ Only checks ABAP Doc inside class definitions and interfaces.`,
66
+ tags: [_irule_1.RuleTag.SingleFile],
67
+ badExample: `INTERFACE zif_foo PUBLIC.
68
+ "! Returns the <name> of the selected row
69
+ METHODS name RETURNING VALUE(result) TYPE string.
70
+ ENDINTERFACE.`,
71
+ goodExample: `INTERFACE zif_foo PUBLIC.
72
+ "! Returns the &lt;name&gt; of the selected row
73
+ METHODS name RETURNING VALUE(result) TYPE string.
74
+ ENDINTERFACE.`,
75
+ };
76
+ }
77
+ getConfig() {
78
+ return this.conf;
79
+ }
80
+ setConfig(conf) {
81
+ this.conf = conf;
82
+ }
83
+ runParsed(file) {
84
+ const issues = [];
85
+ let definition = false;
86
+ for (const statement of file.getStatements()) {
87
+ const type = statement.get();
88
+ if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
89
+ definition = true;
90
+ continue;
91
+ }
92
+ else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
93
+ definition = false;
94
+ continue;
95
+ }
96
+ else if (definition === false || !(type instanceof _statement_1.Comment)) {
97
+ continue;
98
+ }
99
+ const token = statement.getFirstToken();
100
+ const str = token.getStr();
101
+ if (str.startsWith(`"!`) === false) {
102
+ continue;
103
+ }
104
+ const regex = /<\/?([a-zA-Z][\w-]*)(\s[^<>]*)?\/?>/g;
105
+ let match;
106
+ while ((match = regex.exec(str)) !== null) {
107
+ const name = match[1];
108
+ if (ALLOWED.has(name.toLowerCase())) {
109
+ continue;
110
+ }
111
+ const row = token.getStart().getRow();
112
+ const col = token.getStart().getCol() + match.index;
113
+ const start = new position_1.Position(row, col);
114
+ const end = new position_1.Position(row, col + match[0].length);
115
+ const message = `HTML tag <${name}> is not supported in ABAP Doc, write &lt;${name}&gt;`;
116
+ issues.push(issue_1.Issue.atRange(file, start, end, message, this.getMetadata().key, this.conf.severity));
117
+ }
118
+ }
119
+ return issues;
120
+ }
121
+ }
122
+ exports.AbapdocHtmlTag = AbapdocHtmlTag;
123
+ //# sourceMappingURL=abapdoc_html_tag.js.map
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.AbapdocLeadingAt = exports.AbapdocLeadingAtConf = void 0;
37
+ const Statements = __importStar(require("../abap/2_statements/statements"));
38
+ const issue_1 = require("../issue");
39
+ const _abap_rule_1 = require("./_abap_rule");
40
+ const _basic_rule_config_1 = require("./_basic_rule_config");
41
+ const _irule_1 = require("./_irule");
42
+ const _statement_1 = require("../abap/2_statements/statements/_statement");
43
+ class AbapdocLeadingAtConf extends _basic_rule_config_1.BasicRuleConfig {
44
+ }
45
+ exports.AbapdocLeadingAtConf = AbapdocLeadingAtConf;
46
+ class AbapdocLeadingAt extends _abap_rule_1.ABAPRule {
47
+ constructor() {
48
+ super(...arguments);
49
+ this.conf = new AbapdocLeadingAtConf();
50
+ }
51
+ getMetadata() {
52
+ return {
53
+ key: "abapdoc_leading_at",
54
+ title: "ABAP Doc line starting with @",
55
+ shortDescription: `Reports ABAP Doc lines starting with "@" which is not followed by a command.`,
56
+ extendedInformation: `In ABAP Doc, "@" at the start of a line introduces a command, the commands are
57
+ @parameter, @raising and @exception. Any other text after a leading "@", like a CDS annotation,
58
+ gives the syntax warning 'A command was expected after ABAP Doc symbol "@"'.
59
+
60
+ An "@" in the middle of a line is plain text and not reported.
61
+
62
+ Only checks ABAP Doc inside class definitions and interfaces.`,
63
+ tags: [_irule_1.RuleTag.SingleFile],
64
+ badExample: `CLASS zcl_foo DEFINITION PUBLIC.
65
+ PUBLIC SECTION.
66
+ "! the first of
67
+ "! @UI.presentationVariant sortOrder
68
+ DATA mv_sort_field TYPE string.
69
+ ENDCLASS.`,
70
+ goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
71
+ PUBLIC SECTION.
72
+ "! the first of @UI.presentationVariant
73
+ "! sortOrder
74
+ DATA mv_sort_field TYPE string.
75
+ ENDCLASS.`,
76
+ };
77
+ }
78
+ getConfig() {
79
+ return this.conf;
80
+ }
81
+ setConfig(conf) {
82
+ this.conf = conf;
83
+ }
84
+ runParsed(file) {
85
+ const issues = [];
86
+ let definition = false;
87
+ for (const statement of file.getStatements()) {
88
+ const type = statement.get();
89
+ if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
90
+ definition = true;
91
+ continue;
92
+ }
93
+ else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
94
+ definition = false;
95
+ continue;
96
+ }
97
+ else if (definition === false || !(type instanceof _statement_1.Comment)) {
98
+ continue;
99
+ }
100
+ const token = statement.getFirstToken();
101
+ const str = token.getStr();
102
+ if (str.startsWith(`"!`) === false) {
103
+ continue;
104
+ }
105
+ const text = str.substring(2).trimStart();
106
+ if (text.startsWith("@") === false
107
+ || text.match(/^@(parameter|raising|exception)(\s|$)/i) !== null) {
108
+ continue;
109
+ }
110
+ const message = `A command was expected after ABAP Doc symbol "@", move the "@" away from the start of the line`;
111
+ issues.push(issue_1.Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity));
112
+ }
113
+ return issues;
114
+ }
115
+ }
116
+ exports.AbapdocLeadingAt = AbapdocLeadingAt;
117
+ //# sourceMappingURL=abapdoc_leading_at.js.map