@abaplint/transpiler 2.13.46 → 2.13.48
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/src/expressions/constant.d.ts +1 -0
- package/build/src/expressions/constant.js +9 -5
- package/build/src/expressions/sql_cond.js +22 -2
- package/build/src/statements/data.d.ts +15 -0
- package/build/src/statements/data.js +32 -3
- package/build/src/statements/perform.js +1 -1
- package/build/src/structures/data.js +6 -1
- package/build/src/traversal.js +1 -1
- package/package.json +2 -2
|
@@ -8,5 +8,6 @@ export declare class ConstantTranspiler implements IExpressionTranspiler {
|
|
|
8
8
|
private handleInteger;
|
|
9
9
|
transpile(node: Nodes.ExpressionNode, traversal: Traversal): Chunk;
|
|
10
10
|
private handleCharacter;
|
|
11
|
+
static trimTextFieldLiteral(str: string): string;
|
|
11
12
|
static escape(str: string): string;
|
|
12
13
|
}
|
|
@@ -44,7 +44,7 @@ class ConstantTranspiler {
|
|
|
44
44
|
str = node.findDirectExpression(core_1.Expressions.TextElementString);
|
|
45
45
|
}
|
|
46
46
|
if (str) {
|
|
47
|
-
|
|
47
|
+
const res = str.getFirstToken().getStr();
|
|
48
48
|
if (res.startsWith("'") && this.addGet === false) {
|
|
49
49
|
const code = this.handleCharacter(res);
|
|
50
50
|
return new chunk_1.Chunk().append(code, node, traversal);
|
|
@@ -54,10 +54,7 @@ class ConstantTranspiler {
|
|
|
54
54
|
return new chunk_1.Chunk().append(code, node, traversal);
|
|
55
55
|
}
|
|
56
56
|
else {
|
|
57
|
-
|
|
58
|
-
res = "'" + res.substring(1, res.length - 1).trimEnd() + "'";
|
|
59
|
-
}
|
|
60
|
-
const code = ConstantTranspiler.escape(res);
|
|
57
|
+
const code = ConstantTranspiler.escape(ConstantTranspiler.trimTextFieldLiteral(res));
|
|
61
58
|
return new chunk_1.Chunk().append(code, node, traversal);
|
|
62
59
|
}
|
|
63
60
|
}
|
|
@@ -98,6 +95,13 @@ class ConstantTranspiler {
|
|
|
98
95
|
// const code = "new abap.types.Character(" + length + ").set(" + ConstantTranspiler.escape(res) + ")";
|
|
99
96
|
return code;
|
|
100
97
|
}
|
|
98
|
+
// text field literals are of type c, trailing blanks are not part of the value
|
|
99
|
+
static trimTextFieldLiteral(str) {
|
|
100
|
+
if (str.startsWith("'") && str.endsWith("'") && str.length >= 2) {
|
|
101
|
+
return "'" + str.substring(1, str.length - 1).trimEnd() + "'";
|
|
102
|
+
}
|
|
103
|
+
return str;
|
|
104
|
+
}
|
|
101
105
|
static escape(str) {
|
|
102
106
|
str = str.replace(/\\/g, "\\\\");
|
|
103
107
|
if (str.startsWith("'")) {
|
|
@@ -188,14 +188,34 @@ class SQLCondTranspiler {
|
|
|
188
188
|
return sourceWithComponents;
|
|
189
189
|
}
|
|
190
190
|
let ret = "";
|
|
191
|
+
let hostExpression = false;
|
|
191
192
|
for (const child of node.getChildren()) {
|
|
193
|
+
if (!(child instanceof abaplint.Nodes.ExpressionNode) && child.getFirstToken().getStr() === "@") {
|
|
194
|
+
hostExpression = true;
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
192
197
|
if (ret !== "") {
|
|
193
198
|
ret += " ";
|
|
194
199
|
}
|
|
195
|
-
if (
|
|
200
|
+
if (hostExpression
|
|
201
|
+
&& child instanceof abaplint.Nodes.ExpressionNode
|
|
202
|
+
&& child.get() instanceof abaplint.Expressions.SimpleSource3) {
|
|
203
|
+
const code = new simple_source3_1.SimpleSource3Transpiler(true).transpile(child, traversal).getCode();
|
|
204
|
+
ret += `'" + ${code} + "'`;
|
|
205
|
+
hostExpression = false;
|
|
206
|
+
}
|
|
207
|
+
else if ((child.get() instanceof abaplint.Expressions.SQLFieldName
|
|
196
208
|
|| child.get() instanceof abaplint.Expressions.SQLAliasField)
|
|
197
209
|
&& child instanceof abaplint.Nodes.ExpressionNode) {
|
|
198
|
-
|
|
210
|
+
if (hostExpression) {
|
|
211
|
+
let name = traversal.prefixAndName(child.getFirstToken(), filename).replace("~", "$");
|
|
212
|
+
name = traversal_1.Traversal.prefixVariable(traversal_1.Traversal.escapeNamespace(name));
|
|
213
|
+
ret += `'" + ${name}.get() + "'`;
|
|
214
|
+
hostExpression = false;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
ret += new sql_field_name_1.SQLFieldNameTranspiler().transpile(child, traversal).getCode();
|
|
218
|
+
}
|
|
199
219
|
}
|
|
200
220
|
else if (child.get() instanceof abaplint.Expressions.SQLSource
|
|
201
221
|
&& child instanceof abaplint.Nodes.ExpressionNode) {
|
|
@@ -3,6 +3,21 @@ import { IStatementTranspiler } from "./_statement_transpiler";
|
|
|
3
3
|
import { Traversal } from "../traversal";
|
|
4
4
|
import { Chunk } from "../chunk";
|
|
5
5
|
export declare class DataTranspiler implements IStatementTranspiler {
|
|
6
|
+
private readonly skipLoopScoping;
|
|
7
|
+
private variableName;
|
|
8
|
+
private loopScoped;
|
|
9
|
+
constructor(options?: {
|
|
10
|
+
skipLoopScoping?: boolean;
|
|
11
|
+
});
|
|
12
|
+
/** name of the declared javascript variable, set by transpile() */
|
|
13
|
+
getVariableName(): string;
|
|
14
|
+
/** set by transpile(), true if the declaration is inside a loop */
|
|
15
|
+
isLoopScoped(): boolean;
|
|
16
|
+
/** DATA is scoped to the enclosing method/form/program, but when the statement is inside a
|
|
17
|
+
* loop the generated declaration ends up inside the javascript block of the loop. Declaring
|
|
18
|
+
* with "var" hoists it out of the block, and the guard makes sure its constructed only on the
|
|
19
|
+
* first pass, ie. contents are kept across iterations, matching ABAP */
|
|
20
|
+
static wrapLoopScoped(name: string, chunk: Chunk): Chunk;
|
|
6
21
|
transpile(node: abaplint.Nodes.StatementNode, traversal: Traversal): Chunk;
|
|
7
22
|
static findEnumDefault(scope: abaplint.ISpaghettiScopeNode, _enumType: abaplint.AbstractType): string | undefined;
|
|
8
23
|
static buildValue(node: abaplint.Nodes.StatementNode, name: string, traversal: Traversal): string;
|
|
@@ -41,6 +41,30 @@ const constant_1 = require("../expressions/constant");
|
|
|
41
41
|
const expressions_1 = require("../expressions");
|
|
42
42
|
const chunk_1 = require("../chunk");
|
|
43
43
|
class DataTranspiler {
|
|
44
|
+
skipLoopScoping;
|
|
45
|
+
variableName = "";
|
|
46
|
+
loopScoped = false;
|
|
47
|
+
constructor(options) {
|
|
48
|
+
this.skipLoopScoping = options?.skipLoopScoping === true;
|
|
49
|
+
}
|
|
50
|
+
/** name of the declared javascript variable, set by transpile() */
|
|
51
|
+
getVariableName() {
|
|
52
|
+
return this.variableName;
|
|
53
|
+
}
|
|
54
|
+
/** set by transpile(), true if the declaration is inside a loop */
|
|
55
|
+
isLoopScoped() {
|
|
56
|
+
return this.loopScoped;
|
|
57
|
+
}
|
|
58
|
+
/** DATA is scoped to the enclosing method/form/program, but when the statement is inside a
|
|
59
|
+
* loop the generated declaration ends up inside the javascript block of the loop. Declaring
|
|
60
|
+
* with "var" hoists it out of the block, and the guard makes sure its constructed only on the
|
|
61
|
+
* first pass, ie. contents are kept across iterations, matching ABAP */
|
|
62
|
+
static wrapLoopScoped(name, chunk) {
|
|
63
|
+
return new chunk_1.Chunk()
|
|
64
|
+
.appendString(`if (${name} === undefined) {\n`)
|
|
65
|
+
.appendChunk(chunk)
|
|
66
|
+
.appendString("\n}");
|
|
67
|
+
}
|
|
44
68
|
transpile(node, traversal) {
|
|
45
69
|
const token = node.findFirstExpression(abaplint.Expressions.DefinitionName)?.getFirstToken();
|
|
46
70
|
if (token === undefined) {
|
|
@@ -68,12 +92,17 @@ class DataTranspiler {
|
|
|
68
92
|
value = "\n" + traversal_1.Traversal.prefixVariable(found.getName().toLowerCase()) + ".set(\"" + enumDefault + "\");";
|
|
69
93
|
}
|
|
70
94
|
}
|
|
95
|
+
this.variableName = traversal_1.Traversal.prefixVariable(traversal_1.Traversal.escapeNamespace(found.getName().toLowerCase()));
|
|
96
|
+
this.loopScoped = traversal.isInsideLoop(node);
|
|
71
97
|
const ret = new chunk_1.Chunk()
|
|
72
|
-
.appendString("let ")
|
|
73
|
-
.appendString(
|
|
98
|
+
.appendString(this.loopScoped === true ? "var " : "let ")
|
|
99
|
+
.appendString(this.variableName)
|
|
74
100
|
.appendString(" = " + transpile_types_1.TranspileTypes.toType(found.getType()))
|
|
75
101
|
.appendString(";")
|
|
76
102
|
.appendString(value);
|
|
103
|
+
if (this.loopScoped === true && this.skipLoopScoping === false) {
|
|
104
|
+
return DataTranspiler.wrapLoopScoped(this.variableName, ret);
|
|
105
|
+
}
|
|
77
106
|
return ret;
|
|
78
107
|
}
|
|
79
108
|
static findEnumDefault(scope, _enumType) {
|
|
@@ -105,7 +134,7 @@ class DataTranspiler {
|
|
|
105
134
|
int = val.findFirstExpression(abaplint.Expressions.ConstantString);
|
|
106
135
|
}
|
|
107
136
|
if (int) {
|
|
108
|
-
const escaped = constant_1.ConstantTranspiler.escape(int.concatTokens());
|
|
137
|
+
const escaped = constant_1.ConstantTranspiler.escape(constant_1.ConstantTranspiler.trimTextFieldLiteral(int.concatTokens()));
|
|
109
138
|
value = "\n" + name + ".set(" + escaped + ");";
|
|
110
139
|
}
|
|
111
140
|
else if (val.getChildren()[1].get() instanceof abaplint.Expressions.SimpleFieldChain) {
|
|
@@ -90,7 +90,7 @@ class PerformTranspiler {
|
|
|
90
90
|
index++;
|
|
91
91
|
}
|
|
92
92
|
index = 0;
|
|
93
|
-
for (const u of node.findDirectExpression(abaplint.Expressions.PerformUsing)?.findDirectExpressions(abaplint.Expressions.
|
|
93
|
+
for (const u of node.findDirectExpression(abaplint.Expressions.PerformUsing)?.findDirectExpressions(abaplint.Expressions.SimpleSource3) || []) {
|
|
94
94
|
const name = def?.getUsingParameters()[index].getName().toLowerCase();
|
|
95
95
|
if (name === undefined) {
|
|
96
96
|
continue;
|
|
@@ -44,13 +44,18 @@ class DataTranspiler {
|
|
|
44
44
|
return new chunk_1.Chunk("");
|
|
45
45
|
}
|
|
46
46
|
const topName = begin.findDirectExpression(abaplint.Expressions.DefinitionName)?.concatTokens().toLowerCase();
|
|
47
|
-
|
|
47
|
+
// the component values are part of the declaration, so they must stay inside the loop guard
|
|
48
|
+
const statement = new statements_1.DataTranspiler({ skipLoopScoping: true });
|
|
49
|
+
let chunk = statement.transpile(begin, traversal).ensureStartMapping(begin, traversal);
|
|
48
50
|
for (const d of node.findDirectStatements(abaplint.Statements.Data)) {
|
|
49
51
|
const subName = d.findFirstExpression(abaplint.Expressions.DefinitionName)?.concatTokens().toLowerCase();
|
|
50
52
|
if (subName && topName) {
|
|
51
53
|
chunk.appendString(statements_1.DataTranspiler.buildValue(d, topName + ".get()." + subName, traversal));
|
|
52
54
|
}
|
|
53
55
|
}
|
|
56
|
+
if (statement.isLoopScoped() === true) {
|
|
57
|
+
chunk = statements_1.DataTranspiler.wrapLoopScoped(statement.getVariableName(), chunk);
|
|
58
|
+
}
|
|
54
59
|
chunk.appendString("\n");
|
|
55
60
|
return chunk;
|
|
56
61
|
}
|
package/build/src/traversal.js
CHANGED
|
@@ -842,7 +842,7 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
|
|
|
842
842
|
}
|
|
843
843
|
const handle = (val, name) => {
|
|
844
844
|
if (typeof val === "string") {
|
|
845
|
-
const e = expressions_1.ConstantTranspiler.escape(val);
|
|
845
|
+
const e = expressions_1.ConstantTranspiler.escape(expressions_1.ConstantTranspiler.trimTextFieldLiteral(val));
|
|
846
846
|
ret += name + ".set(" + e + ");\n";
|
|
847
847
|
}
|
|
848
848
|
else if (typeof val === "object") {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/transpiler",
|
|
3
|
-
"version": "2.13.
|
|
3
|
+
"version": "2.13.48",
|
|
4
4
|
"description": "Transpiler",
|
|
5
5
|
"main": "build/src/index.js",
|
|
6
6
|
"typings": "build/src/index.d.ts",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"author": "abaplint",
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@abaplint/core": "^2.120.
|
|
32
|
+
"@abaplint/core": "^2.120.9",
|
|
33
33
|
"source-map": "^0.7.6"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|