@abaplint/core 2.116.1 → 2.117.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.
@@ -1993,6 +1993,9 @@ declare type DynproField = {
1993
1993
  name: string;
1994
1994
  type: string;
1995
1995
  length: number;
1996
+ line: number;
1997
+ column: number;
1998
+ height: number;
1996
1999
  };
1997
2000
 
1998
2001
  declare type DynproHeader = {
@@ -5534,6 +5537,7 @@ declare class Program extends ABAPObject {
5534
5537
  isInclude(): boolean;
5535
5538
  isModulePool(): boolean;
5536
5539
  getDynpros(): DynproList;
5540
+ getSelectionTexts(): ITextElements;
5537
5541
  private parseXML;
5538
5542
  }
5539
5543
 
@@ -5,9 +5,10 @@ const combi_1 = require("../combi");
5
5
  const _1 = require(".");
6
6
  const wparen_leftw_1 = require("../../1_lexer/tokens/wparen_leftw");
7
7
  const wparen_left_1 = require("../../1_lexer/tokens/wparen_left");
8
+ const version_1 = require("../../../version");
8
9
  class SQLIntoList extends combi_1.Expression {
9
10
  getRunnable() {
10
- const intoList = (0, combi_1.seq)((0, combi_1.altPrio)((0, combi_1.tok)(wparen_left_1.WParenLeft), (0, combi_1.tok)(wparen_leftw_1.WParenLeftW)), (0, combi_1.starPrio)((0, combi_1.seq)(_1.SQLTarget, ",")), _1.SQLTarget, ")");
11
+ const intoList = (0, combi_1.seq)((0, combi_1.altPrio)((0, combi_1.tok)(wparen_left_1.WParenLeft), (0, combi_1.ver)(version_1.Version.v740sp02, (0, combi_1.tok)(wparen_leftw_1.WParenLeftW))), (0, combi_1.starPrio)((0, combi_1.seq)(_1.SQLTarget, ",")), _1.SQLTarget, ")");
11
12
  return (0, combi_1.seq)("INTO", intoList);
12
13
  }
13
14
  }
@@ -33,36 +33,36 @@ class SQLCompare {
33
33
  if (sqlin) {
34
34
  sql_in_1.SQLIn.runSyntax(sqlin, input);
35
35
  }
36
- const fieldName = (_b = node.findDirectExpression(Expressions.SQLFieldName)) === null || _b === void 0 ? void 0 : _b.concatTokens();
36
+ const fieldName = (_b = node.findDirectExpression(Expressions.SQLFieldName)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
37
37
  if (fieldName && sourceType && token) {
38
38
  // check compatibility for rule sql_value_conversion
39
39
  const targetType = this.findType(fieldName, tables, input.scope);
40
40
  let message = "";
41
41
  if (sourceType instanceof basic_1.IntegerType
42
42
  && targetType instanceof basic_1.CharacterType) {
43
- message = "Integer to CHAR conversion";
43
+ message = `${fieldName}: Integer to CHAR conversion`;
44
44
  }
45
45
  else if (sourceType instanceof basic_1.IntegerType
46
46
  && targetType instanceof basic_1.NumericType) {
47
- message = "Integer to NUMC conversion";
47
+ message = `${fieldName}: Integer to NUMC conversion`;
48
48
  }
49
49
  else if (sourceType instanceof basic_1.NumericType
50
50
  && targetType instanceof basic_1.IntegerType) {
51
- message = "NUMC to Integer conversion";
51
+ message = `${fieldName}: NUMC to Integer conversion`;
52
52
  }
53
53
  else if (sourceType instanceof basic_1.CharacterType
54
54
  && targetType instanceof basic_1.IntegerType) {
55
- message = "CHAR to Integer conversion";
55
+ message = `${fieldName}: CHAR to Integer conversion`;
56
56
  }
57
57
  else if (sourceType instanceof basic_1.CharacterType
58
58
  && targetType instanceof basic_1.CharacterType
59
59
  && sourceType.getLength() > targetType.getLength()) {
60
- message = "Source field longer than database field, CHAR -> CHAR";
60
+ message = `${fieldName}: Source field longer than database field, CHAR -> CHAR`;
61
61
  }
62
62
  else if (sourceType instanceof basic_1.NumericType
63
63
  && targetType instanceof basic_1.NumericType
64
64
  && sourceType.getLength() > targetType.getLength()) {
65
- message = "Source field longer than database field, NUMC -> NUMC";
65
+ message = `${fieldName}: Source field longer than database field, NUMC -> NUMC`;
66
66
  }
67
67
  if (message !== "") {
68
68
  input.scope.addSQLConversion(fieldName, message, token);
@@ -2,6 +2,12 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseDynpros = parseDynpros;
4
4
  const xml_utils_1 = require("../xml_utils");
5
+ function parseNumber(value) {
6
+ if (value === undefined) {
7
+ return 0;
8
+ }
9
+ return parseInt(value, 10);
10
+ }
5
11
  function parseDynpros(parsed) {
6
12
  var _a, _b, _c, _d;
7
13
  const dynpros = [];
@@ -13,7 +19,10 @@ function parseDynpros(parsed) {
13
19
  fields.push({
14
20
  name: f.NAME,
15
21
  type: f.TYPE,
16
- length: f.LENGTH,
22
+ length: parseNumber(f.LENGTH),
23
+ line: parseNumber(f.LINE),
24
+ column: parseNumber(f.COLUMN),
25
+ height: parseNumber(f.HEIGHT),
17
26
  });
18
27
  }
19
28
  dynpros.push({
@@ -42,6 +42,10 @@ class Program extends _abap_object_1.ABAPObject {
42
42
  this.parseXML();
43
43
  return this.parsedXML.dynpros || [];
44
44
  }
45
+ getSelectionTexts() {
46
+ this.parseXML();
47
+ return this.parsedXML.selectionTexts;
48
+ }
45
49
  ////////////////////////////
46
50
  parseXML() {
47
51
  var _a, _b, _c;
@@ -56,14 +60,19 @@ class Program extends _abap_object_1.ABAPObject {
56
60
  isModulePool: false,
57
61
  description: undefined,
58
62
  dynpros: [],
63
+ selectionTexts: {},
59
64
  };
60
65
  return;
61
66
  }
62
67
  let description = "";
68
+ const selectionTexts = {};
63
69
  for (const t of (0, xml_utils_1.xmlToArray)((_c = (_b = (_a = parsed.abapGit) === null || _a === void 0 ? void 0 : _a["asx:abap"]["asx:values"]) === null || _b === void 0 ? void 0 : _b.TPOOL) === null || _c === void 0 ? void 0 : _c.item)) {
64
70
  if ((t === null || t === void 0 ? void 0 : t.ID) === "R") {
65
71
  description = t.ENTRY ? (0, xml_utils_1.unescape)(t.ENTRY) : "";
66
72
  }
73
+ else if ((t === null || t === void 0 ? void 0 : t.ID) === "S" && t.KEY !== undefined) {
74
+ selectionTexts[t.KEY.toUpperCase()] = t.ENTRY ? (0, xml_utils_1.unescape)(t.ENTRY) : "";
75
+ }
67
76
  }
68
77
  const dynpros = (0, _dynpros_1.parseDynpros)(parsed);
69
78
  this.parsedXML = {
@@ -71,6 +80,7 @@ class Program extends _abap_object_1.ABAPObject {
71
80
  isModulePool: file ? file.getRaw().includes("<SUBC>M</SUBC>") : false,
72
81
  dynpros: dynpros,
73
82
  description: description,
83
+ selectionTexts: selectionTexts,
74
84
  };
75
85
  }
76
86
  }
@@ -74,7 +74,7 @@ class Registry {
74
74
  }
75
75
  static abaplintVersion() {
76
76
  // magic, see build script "version.sh"
77
- return "2.116.1";
77
+ return "2.117.1";
78
78
  }
79
79
  getDDICReferences() {
80
80
  return this.ddicReferences;
@@ -18,7 +18,7 @@ class DynproChecks {
18
18
  key: "dynpro_checks",
19
19
  title: "Dynpro Checks",
20
20
  shortDescription: `Various Dynpro checks`,
21
- extendedInformation: `* Check length of PUSH elements less than 132`,
21
+ extendedInformation: `* Check length of PUSH elements less than 132\n* Check for overlapping screen elements`,
22
22
  tags: [_irule_1.RuleTag.Syntax],
23
23
  };
24
24
  }
@@ -47,9 +47,43 @@ class DynproChecks {
47
47
  ret.push(issue_1.Issue.atPosition(file, new position_1.Position(1, 1), message, this.getMetadata().key, this.getConfig().severity));
48
48
  }
49
49
  }
50
+ ret.push(...this.findOverlappingFields(dynpro, file));
50
51
  }
51
52
  return ret;
52
53
  }
54
+ findOverlappingFields(dynpro, file) {
55
+ const ret = [];
56
+ for (let index = 0; index < dynpro.fields.length; index++) {
57
+ const current = dynpro.fields[index];
58
+ if (current.name === undefined) {
59
+ continue;
60
+ }
61
+ for (let compare = index + 1; compare < dynpro.fields.length; compare++) {
62
+ const other = dynpro.fields[compare];
63
+ if (other.name === undefined || this.overlaps(current, other) === false) {
64
+ continue;
65
+ }
66
+ const message = `Screen ${dynpro.number}, fields ${current.name} and ${other.name} are overlapping`;
67
+ ret.push(issue_1.Issue.atPosition(file, new position_1.Position(1, 1), message, this.getMetadata().key, this.getConfig().severity));
68
+ }
69
+ }
70
+ return ret;
71
+ }
72
+ overlaps(first, second) {
73
+ if (first.line === 0 || second.line === 0 || first.column === 0 || second.column === 0) {
74
+ return false;
75
+ }
76
+ const firstHeight = Math.max(first.height, 1);
77
+ const secondHeight = Math.max(second.height, 1);
78
+ const firstLastLine = first.line + firstHeight - 1;
79
+ const secondLastLine = second.line + secondHeight - 1;
80
+ if (firstLastLine < second.line || secondLastLine < first.line) {
81
+ return false;
82
+ }
83
+ const firstLastColumn = first.column + Math.max(first.length, 1) - 1;
84
+ const secondLastColumn = second.column + Math.max(second.length, 1) - 1;
85
+ return first.column <= secondLastColumn && second.column <= firstLastColumn;
86
+ }
53
87
  }
54
88
  exports.DynproChecks = DynproChecks;
55
89
  //# sourceMappingURL=dynpro_checks.js.map
@@ -152,6 +152,7 @@ __exportStar(require("./select_add_order_by"), exports);
152
152
  __exportStar(require("./select_performance"), exports);
153
153
  __exportStar(require("./select_single_full_key"), exports);
154
154
  __exportStar(require("./selection_screen_naming"), exports);
155
+ __exportStar(require("./selection_screen_texts_missing"), exports);
155
156
  __exportStar(require("./sequential_blank"), exports);
156
157
  __exportStar(require("./short_case"), exports);
157
158
  __exportStar(require("./sicf_consistency"), exports);
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SelectionScreenTextsMissing = exports.SelectionScreenTextsMissingConf = void 0;
4
+ const issue_1 = require("../issue");
5
+ const _basic_rule_config_1 = require("./_basic_rule_config");
6
+ const statements_1 = require("../abap/2_statements/statements");
7
+ const expressions_1 = require("../abap/2_statements/expressions");
8
+ const objects_1 = require("../objects");
9
+ class SelectionScreenTextsMissingConf extends _basic_rule_config_1.BasicRuleConfig {
10
+ }
11
+ exports.SelectionScreenTextsMissingConf = SelectionScreenTextsMissingConf;
12
+ class SelectionScreenTextsMissing {
13
+ constructor() {
14
+ this.conf = new SelectionScreenTextsMissingConf();
15
+ }
16
+ getMetadata() {
17
+ return {
18
+ key: "selection_screen_texts_missing",
19
+ title: "Selection screen texts missing",
20
+ shortDescription: `Checks that selection screen parameters and select-options have selection texts`,
21
+ };
22
+ }
23
+ getConfig() {
24
+ return this.conf;
25
+ }
26
+ setConfig(conf) {
27
+ this.conf = conf;
28
+ }
29
+ initialize(reg) {
30
+ this.reg = reg;
31
+ return this;
32
+ }
33
+ run(obj) {
34
+ if (!(obj instanceof objects_1.Program)) {
35
+ return [];
36
+ }
37
+ if (obj.isInclude()) {
38
+ return [];
39
+ }
40
+ const selTexts = obj.getSelectionTexts();
41
+ const output = [];
42
+ const checked = new Set();
43
+ this.checkFile(obj.getMainABAPFile(), selTexts, output, checked);
44
+ return output;
45
+ }
46
+ checkFile(file, selTexts, output, checked) {
47
+ if (file === undefined) {
48
+ return;
49
+ }
50
+ if (checked.has(file.getFilename())) {
51
+ return;
52
+ }
53
+ checked.add(file.getFilename());
54
+ for (const stat of file.getStatements()) {
55
+ const s = stat.get();
56
+ if (s instanceof statements_1.Parameter || s instanceof statements_1.SelectOption) {
57
+ const fieldNode = stat.findFirstExpression(expressions_1.FieldSub);
58
+ if (fieldNode) {
59
+ const fieldName = fieldNode.getFirstToken().getStr().toUpperCase();
60
+ if (selTexts[fieldName] === undefined) {
61
+ output.push(issue_1.Issue.atToken(file, fieldNode.getFirstToken(), `Selection text missing for "${fieldName}"`, this.getMetadata().key, this.conf.severity));
62
+ }
63
+ }
64
+ }
65
+ else if (s instanceof statements_1.Include) {
66
+ const nameNode = stat.findFirstExpression(expressions_1.IncludeName);
67
+ if (nameNode) {
68
+ const inclName = nameNode.getFirstToken().getStr().toUpperCase();
69
+ const inclObj = this.reg.getObject("PROG", inclName);
70
+ if (inclObj) {
71
+ this.checkFile(inclObj.getMainABAPFile(), selTexts, output, checked);
72
+ }
73
+ }
74
+ }
75
+ }
76
+ }
77
+ }
78
+ exports.SelectionScreenTextsMissing = SelectionScreenTextsMissing;
79
+ //# sourceMappingURL=selection_screen_texts_missing.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.116.1",
3
+ "version": "2.117.1",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",
@@ -37,7 +37,7 @@
37
37
  "url": "git+https://github.com/abaplint/abaplint.git"
38
38
  },
39
39
  "engines": {
40
- "node": ">=12.0.0"
40
+ "node": ">=18.0.0"
41
41
  },
42
42
  "keywords": [
43
43
  "ABAP",
@@ -63,7 +63,7 @@
63
63
  "typescript": "^5.9.3"
64
64
  },
65
65
  "dependencies": {
66
- "fast-xml-parser": "^5.5.3",
66
+ "fast-xml-parser": "^5.5.5",
67
67
  "json5": "^2.2.3",
68
68
  "vscode-languageserver-types": "^3.17.5"
69
69
  }