@abaplint/transpiler-cli 2.13.86 → 2.13.87

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.
Files changed (2) hide show
  1. package/build/bundle.js +293 -23
  2. package/package.json +3 -3
package/build/bundle.js CHANGED
@@ -522,6 +522,13 @@ const BUFS = new Set([
522
522
  CH_DOT, CH_COMMA, CH_COLON, 40 /* ( */, 41 /* ) */, 91 /* [ */,
523
523
  93 /* ] */, 43 /* + */, CH_AT
524
524
  ]);
525
+ // characters that may follow the closing "'", "`" or "|" of a literal, anything else
526
+ // is a syntax error, "There must be a space or equivalent character after ...",
527
+ // note that "(" is allowed, ie. text elements like 'text'(001)
528
+ const AFTER_LITERAL = new Set([
529
+ EOF, CH_SPACE, CH_TAB, CH_NL, CH_DOT, CH_COMMA, CH_COLON, CH_DQUOTE,
530
+ 40 /* ( */, 41 /* ) */, 91 /* [ */, 93 /* ] */
531
+ ]);
525
532
  class Lexer {
526
533
  run(file, virtual) {
527
534
  this.virtual = virtual;
@@ -801,7 +808,11 @@ class Lexer {
801
808
  && ahead !== CH_BACKTICK
802
809
  && this.buffer.countIsEven(CH_BACKTICK)) {
803
810
  // end of ping
804
- this.add();
811
+ if (AFTER_LITERAL.has(ahead)) {
812
+ this.add();
813
+ }
814
+ // else: no separator after the literal, keep the buffer so the following
815
+ // characters are glued onto the token, the parser will report the error
805
816
  if (ahead === CH_DQUOTE) {
806
817
  this.m = ModeComment;
807
818
  }
@@ -814,7 +825,9 @@ class Lexer {
814
825
  && (current === CH_PIPE || current === CH_LBRACE)
815
826
  && (stream.prevChar() !== CH_BACKSLASH || (stream.prevPrevChar() === CH_BACKSLASH && stream.prevChar() === CH_BACKSLASH))) {
816
827
  // end of template
817
- this.add();
828
+ if (current === CH_LBRACE || AFTER_LITERAL.has(ahead)) {
829
+ this.add();
830
+ }
818
831
  this.m = ModeNormal;
819
832
  }
820
833
  else if (this.m === ModeTemplate
@@ -829,7 +842,9 @@ class Lexer {
829
842
  && ahead !== CH_QUOTE
830
843
  && this.buffer.countIsEven(CH_QUOTE)) {
831
844
  // end of string
832
- this.add();
845
+ if (AFTER_LITERAL.has(ahead)) {
846
+ this.add();
847
+ }
833
848
  if (ahead === CH_DQUOTE) {
834
849
  this.m = ModeComment;
835
850
  }
@@ -28183,6 +28198,20 @@ class TypeUtils {
28183
28198
  || node.findFirstExpression(Expressions.ArithOperator) !== undefined;
28184
28199
  return calculated;
28185
28200
  }
28201
+ // a character constant is only assignable to a hexadecimal target if it can be
28202
+ // interpreted as a hexadecimal value
28203
+ isHexConstant(node) {
28204
+ const constant = node === null || node === void 0 ? void 0 : node.concatTokens();
28205
+ if (constant === undefined) {
28206
+ return true;
28207
+ }
28208
+ if ((constant.startsWith("'") && constant.endsWith("'"))
28209
+ || (constant.startsWith("`") && constant.endsWith("`"))) {
28210
+ const value = constant.substring(1, constant.length - 1);
28211
+ return value.length > 0 && /^[0-9A-Fa-f]+$/.test(value);
28212
+ }
28213
+ return true;
28214
+ }
28186
28215
  isAssignableNew(source, target, node) {
28187
28216
  const calculated = (node === null || node === void 0 ? void 0 : node.findFirstExpression(Expressions.ArithOperator)) !== undefined;
28188
28217
  if (calculated && source instanceof basic_1.HexType && target instanceof basic_1.IntegerType) {
@@ -28248,7 +28277,7 @@ class TypeUtils {
28248
28277
  }
28249
28278
  else if (target instanceof basic_1.XStringType) {
28250
28279
  if (((_d = source.getAbstractTypeData()) === null || _d === void 0 ? void 0 : _d.derivedFromConstant) === true) {
28251
- return (node === null || node === void 0 ? void 0 : node.concatTokens()) !== "''";
28280
+ return this.isHexConstant(node);
28252
28281
  }
28253
28282
  return false;
28254
28283
  }
@@ -35180,6 +35209,7 @@ class Source {
35180
35209
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
35181
35210
  }
35182
35211
  this.addIfInferred(node, input, foundType);
35212
+ this.traverseRemainingChildren(children, input);
35183
35213
  return foundType;
35184
35214
  }
35185
35215
  case "REF":
@@ -71018,7 +71048,7 @@ class Registry {
71018
71048
  }
71019
71049
  static abaplintVersion() {
71020
71050
  // magic, see build script "version.js"
71021
- return "2.120.50";
71051
+ return "2.120.52";
71022
71052
  }
71023
71053
  getDDICReferences() {
71024
71054
  return this.ddicReferences;
@@ -79155,15 +79185,19 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
79155
79185
  continue;
79156
79186
  }
79157
79187
  const condition = this.tableCondition(tableExpression);
79158
- const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79188
+ // ASSIGNING, not INTO: from v740 a table expression in a read position addresses the
79189
+ // row rather than copying it, so "REF #( tab[ i ]-comp )" and "ASSIGN tab[ i ]-comp"
79190
+ // hand back an address INTO a work area would not preserve. The write path
79191
+ // (moveWithTableTarget) already lowers to ASSIGNING for the same reason.
79192
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
79159
79193
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79160
79194
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
79161
79195
  const firstToken = high.getFirstToken();
79162
79196
  // note that the tabix restore should be done before throwing the exception
79163
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
79197
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${pre}.
79164
79198
  ${indentation}DATA ${tabixBackup} LIKE sy-tabix.
79165
79199
  ${indentation}${tabixBackup} = sy-tabix.
79166
- ${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
79200
+ ${indentation}READ TABLE ${pre} ${condition}ASSIGNING ${uniqueName}.
79167
79201
  ${indentation}sy-tabix = ${tabixBackup}.
79168
79202
  ${indentation}IF sy-subrc <> 0.
79169
79203
  ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
@@ -79917,8 +79951,7 @@ CONSTANTS: BEGIN OF ${structureName},\n`;
79917
79951
  if (index === undefined) {
79918
79952
  return undefined;
79919
79953
  }
79920
- let uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79921
- uniqueName = `<${uniqueName}>`;
79954
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
79922
79955
  const tName = target.concatTokens().split("[")[0];
79923
79956
  const condition = this.tableCondition(tableExpression);
79924
79957
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
@@ -80930,12 +80963,16 @@ ${indentation} output = ${uniqueName}.\n`;
80930
80963
  }
80931
80964
  return undefined;
80932
80965
  }
80933
- uniqueName(position, filename, highSyntax) {
80966
+ /** a FIELD-SYMBOLS declaration is known to the scope under its bracketed spelling, so
80967
+ * the collision check has to use that spelling too - otherwise a second outline in the
80968
+ * same method is handed a name that is already taken and the result does not compile */
80969
+ uniqueName(position, filename, highSyntax, fieldSymbol = false) {
80970
+ const decorate = (name) => fieldSymbol === true ? `<${name}>` : name;
80934
80971
  const spag = highSyntax.spaghetti.lookupPosition(position, filename);
80935
80972
  if (spag === undefined) {
80936
80973
  const name = "temprr" + this.counter;
80937
80974
  this.counter++;
80938
- return name;
80975
+ return decorate(name);
80939
80976
  }
80940
80977
  let postfix = "";
80941
80978
  if (spag.getIdentifier().stype === _scope_type_1.ScopeType.ClassDefinition) {
@@ -80944,7 +80981,7 @@ ${indentation} output = ${uniqueName}.\n`;
80944
80981
  postfix = "_" + hash.substring(0, 10);
80945
80982
  }
80946
80983
  while (true) {
80947
- const name = "temp" + this.counter + postfix;
80984
+ const name = decorate("temp" + this.counter + postfix);
80948
80985
  const exists = this.existsRecursive(spag, name);
80949
80986
  this.counter++;
80950
80987
  if (exists === false) {
@@ -85426,6 +85463,7 @@ __exportStar(__webpack_require__(/*! ./use_line_exists */ "./node_modules/@abapl
85426
85463
  __exportStar(__webpack_require__(/*! ./use_new */ "./node_modules/@abaplint/core/build/src/rules/use_new.js"), exports);
85427
85464
  __exportStar(__webpack_require__(/*! ./when_others_last */ "./node_modules/@abaplint/core/build/src/rules/when_others_last.js"), exports);
85428
85465
  __exportStar(__webpack_require__(/*! ./whitespace_end */ "./node_modules/@abaplint/core/build/src/rules/whitespace_end.js"), exports);
85466
+ __exportStar(__webpack_require__(/*! ./wrong_abapdoc_position */ "./node_modules/@abaplint/core/build/src/rules/wrong_abapdoc_position.js"), exports);
85429
85467
  __exportStar(__webpack_require__(/*! ./xml_consistency */ "./node_modules/@abaplint/core/build/src/rules/xml_consistency.js"), exports);
85430
85468
  __exportStar(__webpack_require__(/*! ./no_exclamation_escape */ "./node_modules/@abaplint/core/build/src/rules/no_exclamation_escape.js"), exports);
85431
85469
  __exportStar(__webpack_require__(/*! ./xml_bom */ "./node_modules/@abaplint/core/build/src/rules/xml_bom.js"), exports);
@@ -100908,6 +100946,178 @@ exports.WhitespaceEnd = WhitespaceEnd;
100908
100946
 
100909
100947
  /***/ },
100910
100948
 
100949
+ /***/ "./node_modules/@abaplint/core/build/src/rules/wrong_abapdoc_position.js"
100950
+ /*!*******************************************************************************!*\
100951
+ !*** ./node_modules/@abaplint/core/build/src/rules/wrong_abapdoc_position.js ***!
100952
+ \*******************************************************************************/
100953
+ (__unused_webpack_module, exports, __webpack_require__) {
100954
+
100955
+ "use strict";
100956
+
100957
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
100958
+ if (k2 === undefined) k2 = k;
100959
+ var desc = Object.getOwnPropertyDescriptor(m, k);
100960
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
100961
+ desc = { enumerable: true, get: function() { return m[k]; } };
100962
+ }
100963
+ Object.defineProperty(o, k2, desc);
100964
+ }) : (function(o, m, k, k2) {
100965
+ if (k2 === undefined) k2 = k;
100966
+ o[k2] = m[k];
100967
+ }));
100968
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
100969
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
100970
+ }) : function(o, v) {
100971
+ o["default"] = v;
100972
+ });
100973
+ var __importStar = (this && this.__importStar) || (function () {
100974
+ var ownKeys = function(o) {
100975
+ ownKeys = Object.getOwnPropertyNames || function (o) {
100976
+ var ar = [];
100977
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
100978
+ return ar;
100979
+ };
100980
+ return ownKeys(o);
100981
+ };
100982
+ return function (mod) {
100983
+ if (mod && mod.__esModule) return mod;
100984
+ var result = {};
100985
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
100986
+ __setModuleDefault(result, mod);
100987
+ return result;
100988
+ };
100989
+ })();
100990
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
100991
+ exports.WrongAbapdocPosition = exports.WrongAbapdocPositionConf = void 0;
100992
+ const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
100993
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
100994
+ const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
100995
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
100996
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
100997
+ const _statement_1 = __webpack_require__(/*! ../abap/2_statements/statements/_statement */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/_statement.js");
100998
+ class WrongAbapdocPositionConf extends _basic_rule_config_1.BasicRuleConfig {
100999
+ }
101000
+ exports.WrongAbapdocPositionConf = WrongAbapdocPositionConf;
101001
+ class WrongAbapdocPosition extends _abap_rule_1.ABAPRule {
101002
+ constructor() {
101003
+ super(...arguments);
101004
+ this.conf = new WrongAbapdocPositionConf();
101005
+ }
101006
+ getMetadata() {
101007
+ return {
101008
+ key: "wrong_abapdoc_position",
101009
+ title: "Wrong ABAP Doc position",
101010
+ shortDescription: `ABAP Doc must be placed directly in front of the declaration it documents.`,
101011
+ extendedInformation: `ABAP Doc documents the single declaration following it, an ABAP Doc block placed
101012
+ elsewhere is silently ignored, leaving the declaration undocumented.
101013
+
101014
+ The following positions are reported,
101015
+ * in front of a chained keyword, ie. before "CONSTANTS:" instead of after the colon,
101016
+ * in the middle of a statement, ie. between the parameters of a METHODS definition,
101017
+ * directly in front of ENDCLASS, ENDINTERFACE or a SECTION statement.
101018
+
101019
+ Only checks ABAP Doc inside class definitions and interfaces.`,
101020
+ tags: [_irule_1.RuleTag.SingleFile],
101021
+ badExample: `CLASS zcl_foo DEFINITION PUBLIC.
101022
+ PUBLIC SECTION.
101023
+ "! Navigation modes
101024
+ CONSTANTS:
101025
+ BEGIN OF cs_nav_mode,
101026
+ back TYPE i VALUE 1,
101027
+ END OF cs_nav_mode.
101028
+ ENDCLASS.`,
101029
+ goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
101030
+ PUBLIC SECTION.
101031
+ CONSTANTS:
101032
+ "! Navigation modes
101033
+ BEGIN OF cs_nav_mode,
101034
+ back TYPE i VALUE 1,
101035
+ END OF cs_nav_mode.
101036
+ ENDCLASS.`,
101037
+ };
101038
+ }
101039
+ getConfig() {
101040
+ return this.conf;
101041
+ }
101042
+ setConfig(conf) {
101043
+ this.conf = conf;
101044
+ }
101045
+ runParsed(file) {
101046
+ const issues = [];
101047
+ const statements = file.getStatements();
101048
+ let definition = false;
101049
+ for (let i = 0; i < statements.length; i++) {
101050
+ const statement = statements[i];
101051
+ const type = statement.get();
101052
+ if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
101053
+ definition = true;
101054
+ continue;
101055
+ }
101056
+ else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
101057
+ definition = false;
101058
+ continue;
101059
+ }
101060
+ else if (definition === false || this.isAbapdoc(statement) === false) {
101061
+ continue;
101062
+ }
101063
+ else if (this.isAbapdoc(statements[i - 1]) === true
101064
+ && statements[i - 1].getStart().getRow() + 1 === statement.getStart().getRow()) {
101065
+ continue; // only report the first row of each block
101066
+ }
101067
+ let next = undefined;
101068
+ for (let j = i + 1; j < statements.length; j++) {
101069
+ if (statements[j].get() instanceof _statement_1.Comment) {
101070
+ continue;
101071
+ }
101072
+ next = statements[j];
101073
+ break;
101074
+ }
101075
+ if (next === undefined) {
101076
+ continue;
101077
+ }
101078
+ const message = this.check(statement, next);
101079
+ if (message !== undefined) {
101080
+ issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
101081
+ }
101082
+ }
101083
+ return issues;
101084
+ }
101085
+ isAbapdoc(statement) {
101086
+ return (statement === null || statement === void 0 ? void 0 : statement.get()) instanceof _statement_1.Comment
101087
+ && statement.getFirstToken().getStr().startsWith(`"!`);
101088
+ }
101089
+ check(abapdoc, next) {
101090
+ const type = next.get();
101091
+ if (type instanceof Statements.EndClass
101092
+ || type instanceof Statements.EndInterface
101093
+ || type instanceof Statements.Public
101094
+ || type instanceof Statements.Protected
101095
+ || type instanceof Statements.Private) {
101096
+ return "ABAP Doc does not document anything, move or delete it";
101097
+ }
101098
+ const position = abapdoc.getStart();
101099
+ const colon = next.getColon();
101100
+ if (colon === undefined) {
101101
+ if (position.isAfter(next.getStart()) === true) {
101102
+ return "ABAP Doc inside statement, move it in front of the statement";
101103
+ }
101104
+ return undefined;
101105
+ }
101106
+ if (position.isBefore(colon.getStart()) === true) {
101107
+ return "ABAP Doc in front of chained statement, move it after the colon";
101108
+ }
101109
+ const member = next.getTokens().find(t => t.getStart().isAfter(colon.getStart()));
101110
+ if (member !== undefined && position.isAfter(member.getStart()) === true) {
101111
+ return "ABAP Doc inside statement, move it in front of the chained declaration";
101112
+ }
101113
+ return undefined;
101114
+ }
101115
+ }
101116
+ exports.WrongAbapdocPosition = WrongAbapdocPosition;
101117
+ //# sourceMappingURL=wrong_abapdoc_position.js.map
101118
+
101119
+ /***/ },
101120
+
100911
101121
  /***/ "./node_modules/@abaplint/core/build/src/rules/xml_bom.js"
100912
101122
  /*!****************************************************************!*\
100913
101123
  !*** ./node_modules/@abaplint/core/build/src/rules/xml_bom.js ***!
@@ -107087,10 +107297,50 @@ class SourceTranspiler {
107087
107297
  constructor(addGet = false) {
107088
107298
  this.addGet = addGet;
107089
107299
  }
107300
+ // the operands of a chain of & / && (the rearranger leaves them as a binary
107301
+ // tree of Source nodes); an empty list when the node is not such a chain
107302
+ concatOperands(node) {
107303
+ const children = node.getChildren();
107304
+ if (children.length !== 3) {
107305
+ return [];
107306
+ }
107307
+ const op = children[1];
107308
+ if (!(op instanceof core_1.Nodes.TokenNode) || (op.getFirstToken().getStr() !== "&&" && op.getFirstToken().getStr() !== "&")) {
107309
+ return [];
107310
+ }
107311
+ const side = (c) => {
107312
+ if (c instanceof core_1.Nodes.ExpressionNode && c.get() instanceof core_1.Expressions.Source) {
107313
+ const inner = this.concatOperands(c);
107314
+ return inner.length > 0 ? inner : [c];
107315
+ }
107316
+ const wrapped = new core_1.Nodes.ExpressionNode(new core_1.Expressions.Source());
107317
+ wrapped.setChildren([c]);
107318
+ return [wrapped];
107319
+ };
107320
+ return [...side(children[0]), ...side(children[2])];
107321
+ }
107090
107322
  transpile(node, traversal, context) {
107091
107323
  let ret = new chunk_1.Chunk();
107092
107324
  const post = new chunk_1.Chunk();
107093
107325
  const children = node.getChildren();
107326
+ // a & b & c ... : one flat concat([a, b, c]) instead of one nested
107327
+ // concat( ) per operand (a long chain would otherwise exhaust the stack
107328
+ // of a parser with a small budget, e.g. a service worker's)
107329
+ const operands = this.concatOperands(node);
107330
+ if (operands.length > 2) {
107331
+ const flat = new chunk_1.Chunk().appendString("abap.operators.concat([");
107332
+ for (let i = 0; i < operands.length; i++) {
107333
+ if (i > 0) {
107334
+ flat.appendString(",");
107335
+ }
107336
+ flat.appendChunk(new SourceTranspiler(false).transpile(operands[i], traversal, context));
107337
+ }
107338
+ flat.appendString("])");
107339
+ if (this.addGet) {
107340
+ flat.appendString(".get()");
107341
+ }
107342
+ return flat;
107343
+ }
107094
107344
  // Pre-scan for unary prefix +/- tokens (WDashW / WPlusW) before any expression
107095
107345
  let prefixNegated = false;
107096
107346
  let startIdx = 0;
@@ -110895,9 +111145,13 @@ exports.DEFAULT_KEYWORDS = new Set([
110895
111145
  "throw", "throws", "transient", "true",
110896
111146
  "try", "typeof", "var", "void",
110897
111147
  "delete",
110898
- "volatile", "while", "yield"
111148
+ "volatile", "while", "yield",
111149
+ // both produce a SyntaxError in the emitted module: they are reserved words
111150
+ // in JavaScript and legal ABAP names. "super" is NOT in this list on purpose -
111151
+ // the emitted code uses the JS `super` for ABAP's `super->method( )`, and
111152
+ // escaping it turns that call into `$super.get().method()`
111153
+ "case", "with"
110899
111154
  ]);
110900
- // "with"
110901
111155
  //# sourceMappingURL=keywords.js.map
110902
111156
 
110903
111157
  /***/ },
@@ -111100,7 +111354,23 @@ class Rearranger {
111100
111354
  return node;
111101
111355
  }
111102
111356
  const withoutLast = node.getChildren().slice(0, children.length - 1);
111103
- const flat = withoutLast.concat(last.getChildren());
111357
+ // The nested children come up so that precedence can be decided across
111358
+ // the whole chain, and everything before the nested operator has to
111359
+ // arrive as one operand. For "a * b / c" that is already true, b being a
111360
+ // single Source. For "a * CONV f( b ) / c" it is not: CONV is five
111361
+ // children, and hoisting them one by one puts the type name and the
111362
+ // body beside the arithmetic, where the transpiler reads them as
111363
+ // operands and loses the rest of the expression. So the head is wrapped
111364
+ // back into one Source before it moves.
111365
+ const nested = last.getChildren();
111366
+ const firstOperator = nested.findIndex((c) => c instanceof core_1.Nodes.ExpressionNode && c.get() instanceof core_1.Expressions.ArithOperator);
111367
+ let head = nested.slice(0, firstOperator);
111368
+ if (head.length > 1) {
111369
+ const operand = new core_1.Nodes.ExpressionNode(last.get());
111370
+ operand.setChildren(head);
111371
+ head = [operand];
111372
+ }
111373
+ const flat = withoutLast.concat(head, nested.slice(firstOperator));
111104
111374
  node.setChildren(flat);
111105
111375
  return node;
111106
111376
  }
@@ -122047,16 +122317,16 @@ class FunctionModuleTranspiler {
122047
122317
  direction = "importing";
122048
122318
  }
122049
122319
  // note: all directions are optional
122050
- let name = p.name.toLowerCase();
122051
- if (traversal.options?.keywords?.some(a => a === name)) {
122052
- name += "_";
122053
- }
122054
- ret += `let ${name} = INPUT.${direction}?.${name};\n`;
122320
+ const name = p.name.toLowerCase();
122321
+ // a parameter named like a JavaScript keyword, RETURN on every BAPI,
122322
+ // is declared the way the function body refers to it
122323
+ const variable = traversal_1.Traversal.prefixVariable(name);
122324
+ ret += `let ${variable} = INPUT.${direction}?.${name};\n`;
122055
122325
  const type = scope?.findVariable(name)?.getType();
122056
122326
  if (type !== undefined && p.optional === true) {
122057
122327
  // todo, set DEFAULT value
122058
- ret += `if (${name} === undefined) {
122059
- ${name} = ${transpile_types_1.TranspileTypes.toType(type)};
122328
+ ret += `if (${variable} === undefined) {
122329
+ ${variable} = ${transpile_types_1.TranspileTypes.toType(type)};
122060
122330
  }\n`;
122061
122331
  }
122062
122332
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler-cli",
3
- "version": "2.13.86",
3
+ "version": "2.13.87",
4
4
  "description": "Transpiler - Command Line Interface",
5
5
  "funding": "https://github.com/sponsors/larshp",
6
6
  "bin": {
@@ -27,8 +27,8 @@
27
27
  "author": "abaplint",
28
28
  "license": "MIT",
29
29
  "devDependencies": {
30
- "@abaplint/core": "^2.120.50",
31
- "@abaplint/transpiler": "^2.13.86",
30
+ "@abaplint/core": "^2.120.52",
31
+ "@abaplint/transpiler": "^2.13.87",
32
32
  "@types/glob": "^9.0.0",
33
33
  "@types/node": "^26.4.1",
34
34
  "@types/progress": "^2.0.7",