@abaplint/transpiler 2.13.45 → 2.13.47
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.
|
@@ -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("'")) {
|
|
@@ -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) {
|
|
@@ -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
|
@@ -482,10 +482,15 @@ class Traversal {
|
|
|
482
482
|
}
|
|
483
483
|
buildThisAttributes(def, cName) {
|
|
484
484
|
let ret = "";
|
|
485
|
+
const constants = def.getAttributes()?.getConstants() || [];
|
|
485
486
|
for (const a of def.getAttributes()?.getAll() || []) {
|
|
486
487
|
let escaped = Traversal.escapeNamespace(a.getName().toLowerCase());
|
|
487
488
|
if (a.getMeta().includes("static" /* abaplint.IdentifierMeta.Static */) === true) {
|
|
488
489
|
ret += "this." + escaped + " = " + cName + "." + escaped + ";\n";
|
|
490
|
+
const isConstant = constants.some(c => c.getName().toUpperCase() === a.getName().toUpperCase());
|
|
491
|
+
if (a.getVisibility() === abaplint.Visibility.Private && isConstant === false) {
|
|
492
|
+
ret += `this.FRIENDS_ACCESS_INSTANCE["${escaped}"] = this.${escaped};\n`;
|
|
493
|
+
}
|
|
489
494
|
}
|
|
490
495
|
else {
|
|
491
496
|
if (a.getVisibility() === abaplint.Visibility.Private) {
|
|
@@ -837,7 +842,7 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
|
|
|
837
842
|
}
|
|
838
843
|
const handle = (val, name) => {
|
|
839
844
|
if (typeof val === "string") {
|
|
840
|
-
const e = expressions_1.ConstantTranspiler.escape(val);
|
|
845
|
+
const e = expressions_1.ConstantTranspiler.escape(expressions_1.ConstantTranspiler.trimTextFieldLiteral(val));
|
|
841
846
|
ret += name + ".set(" + e + ");\n";
|
|
842
847
|
}
|
|
843
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.47",
|
|
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.6",
|
|
33
33
|
"source-map": "^0.7.6"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|