@abaplint/core 2.115.1 → 2.115.3
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.
- package/build/abaplint.d.ts +8 -0
- package/build/src/abap/5_syntax/statements/insert_internal.js +9 -4
- package/build/src/objects/proxy_object.js +80 -2
- package/build/src/objects/rename/rename_icf_service.js +28 -3
- package/build/src/objects/rename/renamer.js +4 -1
- package/build/src/objects/rename/renamer_helper.js +34 -4
- package/build/src/registry.js +1 -1
- package/build/src/rules/identical_move.js +2 -1
- package/package.json +2 -2
package/build/abaplint.d.ts
CHANGED
|
@@ -5493,12 +5493,20 @@ declare class ProvideFieldName extends Expression {
|
|
|
5493
5493
|
}
|
|
5494
5494
|
|
|
5495
5495
|
declare class ProxyObject extends AbstractObject {
|
|
5496
|
+
private parsedXML;
|
|
5496
5497
|
getType(): string;
|
|
5497
5498
|
getAllowedNaming(): {
|
|
5498
5499
|
maxLength: number;
|
|
5499
5500
|
allowNamespace: boolean;
|
|
5500
5501
|
};
|
|
5501
5502
|
getDescription(): string | undefined;
|
|
5503
|
+
setDirty(): void;
|
|
5504
|
+
parse(_version?: Version, _globalMacros?: readonly string[], reg?: IRegistry): {
|
|
5505
|
+
updated: boolean;
|
|
5506
|
+
runtime: number;
|
|
5507
|
+
};
|
|
5508
|
+
private parseXML;
|
|
5509
|
+
generateABAPObjects(): AbstractObject[];
|
|
5502
5510
|
}
|
|
5503
5511
|
|
|
5504
5512
|
declare class Public implements IStatement {
|
|
@@ -55,13 +55,18 @@ class InsertInternal {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
if (node.findDirectTokenByText("INITIAL") === undefined) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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;
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ProxyObject = void 0;
|
|
4
|
+
const xml_utils_1 = require("../xml_utils");
|
|
4
5
|
const _abstract_object_1 = require("./_abstract_object");
|
|
6
|
+
const interface_1 = require("./interface");
|
|
7
|
+
const memory_file_1 = require("../files/memory_file");
|
|
5
8
|
class ProxyObject extends _abstract_object_1.AbstractObject {
|
|
6
9
|
getType() {
|
|
7
10
|
return "SPRX";
|
|
@@ -13,8 +16,83 @@ class ProxyObject extends _abstract_object_1.AbstractObject {
|
|
|
13
16
|
};
|
|
14
17
|
}
|
|
15
18
|
getDescription() {
|
|
16
|
-
|
|
17
|
-
|
|
19
|
+
var _a;
|
|
20
|
+
this.parse();
|
|
21
|
+
const intfItem = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.proxyData.find(i => i.R3_TYPE === "INTF");
|
|
22
|
+
return intfItem === null || intfItem === void 0 ? void 0 : intfItem.R3_TEXT;
|
|
23
|
+
}
|
|
24
|
+
setDirty() {
|
|
25
|
+
this.parsedXML = undefined;
|
|
26
|
+
super.setDirty();
|
|
27
|
+
}
|
|
28
|
+
parse(_version, _globalMacros, reg) {
|
|
29
|
+
if (this.parsedXML) {
|
|
30
|
+
return { updated: false, runtime: 0 };
|
|
31
|
+
}
|
|
32
|
+
const start = Date.now();
|
|
33
|
+
this.parsedXML = this.parseXML();
|
|
34
|
+
const end = Date.now();
|
|
35
|
+
const objects = this.generateABAPObjects();
|
|
36
|
+
for (const obj of objects) {
|
|
37
|
+
reg === null || reg === void 0 ? void 0 : reg.addDependencies(obj.getFiles());
|
|
38
|
+
}
|
|
39
|
+
return { updated: true, runtime: end - start };
|
|
40
|
+
}
|
|
41
|
+
parseXML() {
|
|
42
|
+
var _a, _b;
|
|
43
|
+
const result = { proxyData: [] };
|
|
44
|
+
const parsed = super.parseRaw2();
|
|
45
|
+
if (parsed === undefined
|
|
46
|
+
|| parsed.abapGit === undefined
|
|
47
|
+
|| ((_a = parsed.abapGit["asx:abap"]) === null || _a === void 0 ? void 0 : _a["asx:values"]) === undefined) {
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
const values = parsed.abapGit["asx:abap"]["asx:values"];
|
|
51
|
+
result.proxyData = (0, xml_utils_1.xmlToArray)((_b = values.PROXY_DATA) === null || _b === void 0 ? void 0 : _b.item);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
generateABAPObjects() {
|
|
55
|
+
var _a, _b, _c;
|
|
56
|
+
this.parse();
|
|
57
|
+
const result = [];
|
|
58
|
+
if (!this.parsedXML) {
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
// Find interface definition
|
|
62
|
+
const intfItem = this.parsedXML.proxyData.find(i => i.R3_TYPE === "INTF");
|
|
63
|
+
if (!intfItem || !intfItem.R3_NAME) {
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
const intfName = intfItem.R3_NAME.toLowerCase();
|
|
67
|
+
// Find methods
|
|
68
|
+
const methods = this.parsedXML.proxyData.filter(i => i.R3_TYPE === "METH");
|
|
69
|
+
// Build interface code
|
|
70
|
+
let code = `INTERFACE ${intfName} PUBLIC.\n`;
|
|
71
|
+
for (const method of methods) {
|
|
72
|
+
const methodName = (_a = method.R3_NAME) === null || _a === void 0 ? void 0 : _a.toLowerCase();
|
|
73
|
+
if (!methodName) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
// Find parameters for this method
|
|
77
|
+
const params = this.parsedXML.proxyData.filter(i => i.R3_TYPE === "PAIM" && i.OBJ_NAME1 === method.OBJ_NAME1);
|
|
78
|
+
code += ` METHODS ${methodName}\n`;
|
|
79
|
+
if (params.length > 0) {
|
|
80
|
+
code += ` IMPORTING\n`;
|
|
81
|
+
for (let i = 0; i < params.length; i++) {
|
|
82
|
+
const param = params[i];
|
|
83
|
+
const paramName = (_b = param.OBJ_NAME2) === null || _b === void 0 ? void 0 : _b.toLowerCase();
|
|
84
|
+
const paramType = (_c = param.OBJ_NAME_R) === null || _c === void 0 ? void 0 : _c.toLowerCase();
|
|
85
|
+
const isLast = i === params.length - 1;
|
|
86
|
+
code += ` ${paramName} TYPE ${paramType}${isLast ? "." : ""}\n`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
code += `ENDINTERFACE.`;
|
|
91
|
+
// Create the interface object
|
|
92
|
+
const intf = new interface_1.Interface(intfName.toUpperCase());
|
|
93
|
+
intf.addFile(new memory_file_1.MemoryFile(`${intfName}.intf.abap`, code));
|
|
94
|
+
result.push(intf);
|
|
95
|
+
return result;
|
|
18
96
|
}
|
|
19
97
|
}
|
|
20
98
|
exports.ProxyObject = ProxyObject;
|
|
@@ -8,14 +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.
|
|
17
|
-
changes = changes.concat(helper.buildXMLFileEdits(obj, "
|
|
18
|
-
changes = changes.concat(helper.
|
|
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));
|
|
19
44
|
return {
|
|
20
45
|
documentChanges: changes,
|
|
21
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
|
-
|
|
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
|
}
|
|
@@ -102,21 +102,51 @@ class RenamerHelper {
|
|
|
102
102
|
}
|
|
103
103
|
return changes;
|
|
104
104
|
}
|
|
105
|
-
buildXMLFileEdits(object, xmlTag, oldName, newName) {
|
|
105
|
+
buildXMLFileEdits(object, xmlTag, oldName, newName, useLowerCase = false) {
|
|
106
106
|
const changes = [];
|
|
107
107
|
const xml = object.getXMLFile();
|
|
108
108
|
if (xml === undefined) {
|
|
109
109
|
return [];
|
|
110
110
|
}
|
|
111
|
+
const originalValue = useLowerCase ? oldName.toLowerCase() : oldName.toUpperCase();
|
|
112
|
+
const replacementValue = useLowerCase ? newName.toLowerCase() : newName.toUpperCase();
|
|
111
113
|
const tag = xmlTag.toUpperCase();
|
|
112
|
-
const search = "<" + tag + ">" +
|
|
114
|
+
const search = "<" + tag + ">" + originalValue + "</" + tag + ">";
|
|
113
115
|
const length = tag.length + 2;
|
|
114
116
|
const rows = xml.getRawRows();
|
|
115
117
|
for (let i = 0; i < rows.length; i++) {
|
|
116
118
|
const index = rows[i].indexOf(search);
|
|
117
119
|
if (index >= 0) {
|
|
118
|
-
const range = vscode_languageserver_types_1.Range.create(i, index + length, i, index +
|
|
119
|
-
changes.push(vscode_languageserver_types_1.TextDocumentEdit.create({ uri: xml.getFilename(), version: 1 }, [vscode_languageserver_types_1.TextEdit.replace(range,
|
|
120
|
+
const range = vscode_languageserver_types_1.Range.create(i, index + length, i, index + originalValue.length + length);
|
|
121
|
+
changes.push(vscode_languageserver_types_1.TextDocumentEdit.create({ uri: xml.getFilename(), version: 1 }, [vscode_languageserver_types_1.TextEdit.replace(range, replacementValue)]));
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return changes;
|
|
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)]));
|
|
120
150
|
}
|
|
121
151
|
}
|
|
122
152
|
return changes;
|
package/build/src/registry.js
CHANGED
|
@@ -42,7 +42,8 @@ lv_value = 5.`,
|
|
|
42
42
|
const source = (_a = statement.findDirectExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
43
43
|
const target = (_b = statement.findDirectExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
|
|
44
44
|
if (source === target && source !== undefined) {
|
|
45
|
-
|
|
45
|
+
const message = `Identical MOVE from "${source}" to "${target}"`;
|
|
46
|
+
issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/core",
|
|
3
|
-
"version": "2.115.
|
|
3
|
+
"version": "2.115.3",
|
|
4
4
|
"description": "abaplint - Core API",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/abaplint.d.ts",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@types/mocha": "^10.0.10",
|
|
56
56
|
"@types/node": "^24.10.3",
|
|
57
57
|
"chai": "^4.5.0",
|
|
58
|
-
"eslint": "^9.39.
|
|
58
|
+
"eslint": "^9.39.2",
|
|
59
59
|
"mocha": "^11.7.5",
|
|
60
60
|
"c8": "^10.1.3",
|
|
61
61
|
"source-map-support": "^0.5.21",
|