@abaplint/transpiler 2.13.46 → 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
- let res = str.getFirstToken().getStr();
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
- if (res.startsWith("'")) {
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(traversal_1.Traversal.prefixVariable(traversal_1.Traversal.escapeNamespace(found.getName().toLowerCase())))
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
- const chunk = new statements_1.DataTranspiler().transpile(begin, traversal).ensureStartMapping(begin, traversal);
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
  }
@@ -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.46",
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.5",
32
+ "@abaplint/core": "^2.120.6",
33
33
  "source-map": "^0.7.6"
34
34
  },
35
35
  "devDependencies": {