@abaplint/core 2.115.2 → 2.115.4

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.
@@ -5,7 +5,7 @@ const combi_1 = require("../combi");
5
5
  const expressions_1 = require("../expressions");
6
6
  class DataBegin {
7
7
  getMatcher() {
8
- const occurs = (0, combi_1.seq)("OCCURS", expressions_1.Integer);
8
+ const occurs = (0, combi_1.seq)("OCCURS", (0, combi_1.altPrio)(expressions_1.Integer, expressions_1.FieldChain));
9
9
  const common = (0, combi_1.seq)("COMMON PART", (0, combi_1.optPrio)(expressions_1.DefinitionName));
10
10
  const structure = (0, combi_1.seq)("BEGIN OF", (0, combi_1.altPrio)(common, (0, combi_1.seq)(expressions_1.DefinitionName, (0, combi_1.optPrio)("READ-ONLY"), (0, combi_1.optPrio)(occurs))));
11
11
  return (0, combi_1.seq)("DATA", structure);
@@ -12,7 +12,8 @@ class Write {
12
12
  const as = (0, combi_1.seq)("AS", (0, combi_1.altPrio)("LINE", "ICON", "CHECKBOX", "SYMBOL"));
13
13
  const to = (0, combi_1.seq)("TO", expressions_1.Target);
14
14
  const options = (0, combi_1.per)(mask, to, (0, combi_1.seq)("EXPONENT", expressions_1.Source), "NO-GROUPING", "NO-ZERO", "CENTERED", (0, combi_1.seq)("INPUT", (0, combi_1.opt)(onOff)), "NO-GAP", "LEFT-JUSTIFIED", as, (0, combi_1.seq)("FRAMES", onOff), (0, combi_1.seq)("HOTSPOT", (0, combi_1.opt)(onOff)), "RIGHT-JUSTIFIED", (0, combi_1.seq)("TIME ZONE", expressions_1.Source), (0, combi_1.seq)("UNDER", expressions_1.Source), (0, combi_1.seq)("STYLE", expressions_1.Source), (0, combi_1.seq)("ROUND", expressions_1.Source), (0, combi_1.seq)("QUICKINFO", expressions_1.Source), "ENVIRONMENT TIME FORMAT", dateFormat, (0, combi_1.seq)("UNIT", expressions_1.Source), (0, combi_1.seq)("INTENSIFIED", (0, combi_1.opt)(onOff)), (0, combi_1.seq)("INDEX", expressions_1.Source), (0, combi_1.seq)("DECIMALS", expressions_1.Source), (0, combi_1.seq)("INVERSE", (0, combi_1.opt)(onOff)), expressions_1.Color, (0, combi_1.seq)("CURRENCY", expressions_1.Source), "RESET", "NO-SIGN");
15
- const ret = (0, combi_1.seq)("WRITE", (0, combi_1.alt)("AT /", (0, combi_1.seq)((0, combi_1.opt)(expressions_1.WriteOffsetLength), (0, combi_1.alt)(expressions_1.Source, expressions_1.Dynamic, "/"), (0, combi_1.opt)(options))));
15
+ // Need to refactor all this sometime,
16
+ const ret = (0, combi_1.seq)("WRITE", (0, combi_1.alt)((0, combi_1.seq)("AT /", (0, combi_1.opt)(expressions_1.Source), (0, combi_1.opt)("NO-GAP")), (0, combi_1.seq)((0, combi_1.opt)(expressions_1.WriteOffsetLength), (0, combi_1.alt)(expressions_1.Source, expressions_1.Dynamic, "/"), (0, combi_1.opt)(options))));
16
17
  return (0, combi_1.verNot)(version_1.Version.Cloud, ret);
17
18
  }
18
19
  }
@@ -55,13 +55,18 @@ class InsertInternal {
55
55
  }
56
56
  }
57
57
  if (node.findDirectTokenByText("INITIAL") === undefined) {
58
- if (new _type_utils_1.TypeUtils(input.scope).isAssignableStrict(sourceType, targetType) === false) {
59
- const message = "Types not compatible";
60
- input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
61
- return;
58
+ let error = false;
59
+ if (sourceType instanceof basic_1.IntegerType && targetType instanceof basic_1.Integer8Type) {
60
+ error = true;
61
+ }
62
+ else if (new _type_utils_1.TypeUtils(input.scope).isAssignable(sourceType, targetType) === false) {
63
+ error = true;
62
64
  }
63
65
  else if (sourceType instanceof basic_1.CharacterType && targetType instanceof basic_1.StringType) {
64
66
  // yea, well, INSERT doesnt convert the values automatically, like everything else?
67
+ error = true;
68
+ }
69
+ if (error === true) {
65
70
  const message = "Types not compatible";
66
71
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
67
72
  return;
package/build/src/ddic.js CHANGED
@@ -50,8 +50,22 @@ class DDIC {
50
50
  case "XSTRING":
51
51
  return Types.XStringType.get({ qualifiedName: qualifiedName || name });
52
52
  case "D":
53
+ /*
54
+ if (length && length > 0) {
55
+ throw new Error("Length for type D not possible");
56
+ } else if (decimals && decimals > 0) {
57
+ throw new Error("Decimals for type D not possible");
58
+ }
59
+ */
53
60
  return new Types.DateType({ qualifiedName: qualifiedName || name });
54
61
  case "T":
62
+ /*
63
+ if (length && length > 0) {
64
+ throw new Error("Length for type T not possible");
65
+ } else if (decimals && decimals > 0) {
66
+ throw new Error("Decimals for type T not possible");
67
+ }
68
+ */
55
69
  return new Types.TimeType({ qualifiedName: qualifiedName || name });
56
70
  case "XSEQUENCE":
57
71
  return new Types.XSequenceType({ qualifiedName: qualifiedName });
@@ -84,6 +98,13 @@ class DDIC {
84
98
  case "INT8": // todo, take version into account
85
99
  return new Types.Integer8Type({ qualifiedName: qualifiedName || name });
86
100
  case "F":
101
+ /*
102
+ if (length && length > 0) {
103
+ throw new Error("Length for type F not possible");
104
+ } else if (decimals && decimals > 0) {
105
+ throw new Error("Decimals for type F not possible");
106
+ }
107
+ */
87
108
  return new Types.FloatType({ qualifiedName: qualifiedName || name });
88
109
  case "P":
89
110
  if (length && decimals) {
@@ -8,15 +8,39 @@ class RenameICFService {
8
8
  this.reg = reg;
9
9
  }
10
10
  buildEdits(obj, oldName, newName) {
11
+ var _a, _b, _c, _d;
11
12
  if (!(obj instanceof __1.ICFService)) {
12
13
  throw new Error("RenameICFService, not a ICF Service");
13
14
  }
15
+ // Preserve GUID suffix from the stored object/file name for the filename rename
16
+ // SICF files follow pattern: servicename.sicf or servicename {GUID}.sicf
17
+ const fileNewName = (() => {
18
+ // Look for pattern: space + GUID (32 hex chars in braces) + optional extension
19
+ const guidPattern = / \{[0-9A-Fa-f]{16,32}\}/;
20
+ const match = oldName.match(guidPattern);
21
+ if (match) {
22
+ // Extract everything from the GUID onwards (includes .sicf extension if present)
23
+ const guidIndex = match.index;
24
+ const suffix = oldName.substring(guidIndex);
25
+ // Only append suffix if newName doesn't already contain it
26
+ return newName.includes(suffix) ? newName : newName + suffix;
27
+ }
28
+ // Fallback: preserve any suffix after first space (legacy behavior)
29
+ const space = oldName.indexOf(" ");
30
+ if (space > -1) {
31
+ const suffix = oldName.substring(space);
32
+ return newName.includes(suffix) ? newName : newName + suffix;
33
+ }
34
+ return newName;
35
+ })();
36
+ const cleanOldName = (_b = (_a = oldName.match(/^[^ ]+/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : oldName;
37
+ const cleanNewName = (_d = (_c = newName.match(/^[^ ]+/)) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : newName;
14
38
  let changes = [];
15
39
  const helper = new renamer_helper_1.RenamerHelper(this.reg);
16
- changes = changes.concat(helper.buildXMLFileEdits(obj, "URL", oldName, newName, true));
17
- changes = changes.concat(helper.buildXMLFileEdits(obj, "ICF_NAME", oldName, newName));
18
- changes = changes.concat(helper.buildXMLFileEdits(obj, "ORIG_NAME", oldName, newName, true));
19
- changes = changes.concat(helper.renameFiles(obj, oldName, newName));
40
+ changes = changes.concat(helper.buildURLFileEdits(obj, cleanOldName, cleanNewName));
41
+ changes = changes.concat(helper.buildXMLFileEdits(obj, "ICF_NAME", cleanOldName, cleanNewName));
42
+ changes = changes.concat(helper.buildXMLFileEdits(obj, "ORIG_NAME", cleanOldName, cleanNewName, true));
43
+ changes = changes.concat(helper.renameFiles(obj, oldName, fileNewName));
20
44
  return {
21
45
  documentChanges: changes,
22
46
  };
@@ -32,7 +32,10 @@ class Renamer {
32
32
  /** Builds edits, but does not apply to registry, used by LSP */
33
33
  buildEdits(type, oldName, newName) {
34
34
  this.reg.parse(); // the registry must be parsed to dermine references
35
- const obj = this.reg.getObject(type, oldName);
35
+ let obj = this.reg.getObject(type, oldName);
36
+ if (obj === undefined && type === "SICF") {
37
+ obj = Array.from(this.reg.getObjects()).find(o => o.getType() === "SICF" && o.getName().toUpperCase().startsWith(oldName.toUpperCase() + " "));
38
+ }
36
39
  if (obj === undefined) {
37
40
  throw new Error("rename, object not found");
38
41
  }
@@ -123,6 +123,34 @@ class RenamerHelper {
123
123
  }
124
124
  return changes;
125
125
  }
126
+ buildURLFileEdits(object, oldName, newName) {
127
+ const changes = [];
128
+ const xml = object.getXMLFile();
129
+ if (xml === undefined) {
130
+ return [];
131
+ }
132
+ const oldNameLower = oldName.toLowerCase();
133
+ const newNameLower = newName.toLowerCase();
134
+ const rows = xml.getRawRows();
135
+ for (let i = 0; i < rows.length; i++) {
136
+ const row = rows[i];
137
+ const urlTagStart = row.indexOf("<URL>");
138
+ if (urlTagStart === -1) {
139
+ continue;
140
+ }
141
+ const urlTagEnd = row.indexOf("</URL>");
142
+ if (urlTagEnd === -1) {
143
+ continue;
144
+ }
145
+ const urlContent = row.substring(urlTagStart + 5, urlTagEnd);
146
+ const updatedUrl = urlContent.replace(oldNameLower, newNameLower);
147
+ if (updatedUrl !== urlContent) {
148
+ const range = vscode_languageserver_types_1.Range.create(i, urlTagStart + 5, i, urlTagEnd);
149
+ changes.push(vscode_languageserver_types_1.TextDocumentEdit.create({ uri: xml.getFilename(), version: 1 }, [vscode_languageserver_types_1.TextEdit.replace(range, updatedUrl)]));
150
+ }
151
+ }
152
+ return changes;
153
+ }
126
154
  renameFiles(obj, oldName, name) {
127
155
  const list = [];
128
156
  const newName = name.toLowerCase().replace(/\//g, "#");
@@ -74,7 +74,7 @@ class Registry {
74
74
  }
75
75
  static abaplintVersion() {
76
76
  // magic, see build script "version.sh"
77
- return "2.115.2";
77
+ return "2.115.4";
78
78
  }
79
79
  getDDICReferences() {
80
80
  return this.ddicReferences;
@@ -50,7 +50,7 @@ ENDIF.
50
50
  return [];
51
51
  }
52
52
  for (const cond of structure.findAllExpressionsMulti([Expressions.Cond, Expressions.ComponentCond])) {
53
- issues.push(...this.analyze(file, cond));
53
+ issues.push(...this.analyzeCondition(file, cond));
54
54
  }
55
55
  for (const sub of structure.findAllExpressionsMulti([Expressions.CondSub, Expressions.ComponentCondSub])) {
56
56
  let cond = [];
@@ -104,18 +104,20 @@ ENDIF.
104
104
  }
105
105
  analyzeMove(file, m) {
106
106
  const issues = [];
107
- const children = m.getChildren();
108
- const last = children[children.length - 2];
109
- const lastChildren = last.getChildren();
110
- if (lastChildren.length === 3
111
- && lastChildren[0].getFirstToken().getStr() === "("
112
- && lastChildren[2].getFirstToken().getStr() === ")") {
113
- const issue = issue_1.Issue.atToken(file, last.getFirstToken(), "Too many parentheses", this.getMetadata().key, this.conf.severity);
114
- issues.push(issue);
107
+ for (const source of m.findAllExpressionsRecursive(Expressions.Source)) {
108
+ const lastChildren = source.getChildren();
109
+ if (lastChildren.length === 3
110
+ && lastChildren[0].getFirstToken().getStr() === "("
111
+ && lastChildren[1].getChildren().length === 1
112
+ && lastChildren[1].getFirstToken().getStr().startsWith("-") === false
113
+ && lastChildren[2].getFirstToken().getStr() === ")") {
114
+ const issue = issue_1.Issue.atToken(file, lastChildren[0].getFirstToken(), "Too many parentheses", this.getMetadata().key, this.conf.severity);
115
+ issues.push(issue);
116
+ }
115
117
  }
116
118
  return issues;
117
119
  }
118
- analyze(file, cond) {
120
+ analyzeCondition(file, cond) {
119
121
  var _a, _b;
120
122
  const issues = [];
121
123
  let comparator = "";
@@ -77,6 +77,8 @@ class ObsoleteStatementConf extends _basic_rule_config_1.BasicRuleConfig {
77
77
  this.fieldGroups = true;
78
78
  /** Check for REPLACE INTO */
79
79
  this.replaceInto = true;
80
+ this.loopExtract = true;
81
+ this.sortExtract = true;
80
82
  }
81
83
  }
82
84
  exports.ObsoleteStatementConf = ObsoleteStatementConf;
@@ -330,6 +332,14 @@ ENDIF.`,
330
332
  issues.push(issue);
331
333
  }
332
334
  }
335
+ if (this.conf.loopExtract && sta instanceof Statements.LoopExtract) {
336
+ const issue = issue_1.Issue.atStatement(file, staNode, "LOOP extract", this.getMetadata().key, this.conf.severity);
337
+ issues.push(issue);
338
+ }
339
+ if (this.conf.sortExtract && sta instanceof Statements.SortDataset && staNode.getChildren().length === 2) {
340
+ const issue = issue_1.Issue.atStatement(file, staNode, "SORT extract", this.getMetadata().key, this.conf.severity);
341
+ issues.push(issue);
342
+ }
333
343
  if (configVersion >= version_1.Version.v754 && this.conf.clientSpecified
334
344
  && (sta instanceof Statements.Select
335
345
  || sta instanceof Statements.SelectLoop
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.115.2",
3
+ "version": "2.115.4",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",