@abaplint/transpiler-cli 2.13.39 → 2.13.41

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 +951 -129
  2. package/package.json +3 -3
package/build/bundle.js CHANGED
@@ -327,31 +327,34 @@ async function writeObjects(outputFiles, config, outputFolder, files) {
327
327
  const writeSourceMaps = config.write_source_map || false;
328
328
  const filesToWrite = [];
329
329
  for (const output of outputFiles) {
330
+ const type = output.object.type.toUpperCase();
330
331
  let contents = output.chunk.getCode();
332
+ // PROG output gets a runtime bootstrap line prepended, which shifts every
333
+ // generated line down by one - the source map must account for this offset
334
+ let generatedLineOffset = 0;
335
+ if (type === "PROG") {
336
+ // hmm, will this work for INCLUDEs ?
337
+ contents = `if (!globalThis.abap) await import("./_init.mjs");\n` + contents;
338
+ generatedLineOffset = 1;
339
+ }
331
340
  if (writeSourceMaps === true
332
- && output.object.type.toUpperCase() === "PROG"
333
- && output.object.type.toUpperCase() === "FUGR"
334
- && output.object.type.toUpperCase() === "CLAS") {
341
+ && (type === "PROG" || type === "FUGR" || type === "CLAS")) {
335
342
  const name = output.filename + ".map";
336
343
  // SourceMappingUrl needs to be percent-encoded, ref https://github.com/microsoft/TypeScript/issues/40951
337
344
  contents = contents + `\n//# sourceMappingURL=` + name.replace(/#/g, "%23");
338
- let map = output.chunk.getMap(output.filename);
339
- for (const f of files) { // hack the paths to the original files
345
+ // map the bare abap filename each mapping carries to its path on disk;
346
+ // source map "sources" are URLs, so always forward slashes, also on Windows
347
+ const sourcePaths = {};
348
+ for (const f of files) {
340
349
  if (f.relative === undefined) {
341
350
  continue;
342
351
  }
343
- if (map.includes(`"${f.filename}"`)) {
344
- let withPath = `"${f.relative}${path.sep}${f.filename}"`;
345
- withPath = withPath.replace(/\\/g, "\\\\");
346
- map = map.replace(`"${f.filename}"`, withPath);
347
- }
352
+ const rel = f.relative.split(path.sep).join("/");
353
+ sourcePaths[f.filename] = rel === "" ? f.filename : `${rel}/${f.filename}`;
348
354
  }
355
+ const map = output.chunk.getMap(output.filename, { generatedLineOffset, sourcePaths });
349
356
  filesToWrite.push({ path: outputFolder + path.sep + name, contents: map });
350
357
  }
351
- if (output.object.type.toUpperCase() === "PROG") {
352
- // hmm, will this work for INCLUDEs ?
353
- contents = `if (!globalThis.abap) await import("./_init.mjs");\n` + contents;
354
- }
355
358
  filesToWrite.push({ path: outputFolder + path.sep + output.filename, contents });
356
359
  }
357
360
  await file_operations_1.FileOperations.writeFiles(filesToWrite);
@@ -26425,7 +26428,7 @@ class CurrentScope {
26425
26428
  return this.reg.getConfig().getLanguageVersion();
26426
26429
  }
26427
26430
  getOpenABAP() {
26428
- return this.reg.getConfig().getOpenABAP();
26431
+ return this.reg.getConfig().isOpenABAP();
26429
26432
  }
26430
26433
  getRegistry() {
26431
26434
  return this.reg;
@@ -27999,7 +28002,8 @@ class TypeUtils {
27999
28002
  console.dir(target);
28000
28003
  console.dir(calculated);
28001
28004
  */
28002
- if (calculated && source instanceof basic_1.StringType && target instanceof basic_1.XStringType) {
28005
+ if (calculated && source instanceof basic_1.StringType
28006
+ && (target instanceof basic_1.XStringType || target instanceof basic_1.XSequenceType)) {
28003
28007
  return false;
28004
28008
  }
28005
28009
  if (calculated) {
@@ -28020,7 +28024,7 @@ class TypeUtils {
28020
28024
  }
28021
28025
  else if (target instanceof basic_1.XStringType) {
28022
28026
  if (((_c = source.getAbstractTypeData()) === null || _c === void 0 ? void 0 : _c.derivedFromConstant) === true) {
28023
- return true;
28027
+ return (node === null || node === void 0 ? void 0 : node.concatTokens()) !== "''";
28024
28028
  }
28025
28029
  return false;
28026
28030
  }
@@ -29428,6 +29432,75 @@ exports.BasicTypes = BasicTypes;
29428
29432
 
29429
29433
  /***/ },
29430
29434
 
29435
+ /***/ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js"
29436
+ /*!*************************************************************************************************!*\
29437
+ !*** ./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js ***!
29438
+ \*************************************************************************************************/
29439
+ (__unused_webpack_module, exports, __webpack_require__) {
29440
+
29441
+ "use strict";
29442
+
29443
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
29444
+ if (k2 === undefined) k2 = k;
29445
+ var desc = Object.getOwnPropertyDescriptor(m, k);
29446
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
29447
+ desc = { enumerable: true, get: function() { return m[k]; } };
29448
+ }
29449
+ Object.defineProperty(o, k2, desc);
29450
+ }) : (function(o, m, k, k2) {
29451
+ if (k2 === undefined) k2 = k;
29452
+ o[k2] = m[k];
29453
+ }));
29454
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
29455
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
29456
+ }) : function(o, v) {
29457
+ o["default"] = v;
29458
+ });
29459
+ var __importStar = (this && this.__importStar) || (function () {
29460
+ var ownKeys = function(o) {
29461
+ ownKeys = Object.getOwnPropertyNames || function (o) {
29462
+ var ar = [];
29463
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29464
+ return ar;
29465
+ };
29466
+ return ownKeys(o);
29467
+ };
29468
+ return function (mod) {
29469
+ if (mod && mod.__esModule) return mod;
29470
+ var result = {};
29471
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
29472
+ __setModuleDefault(result, mod);
29473
+ return result;
29474
+ };
29475
+ })();
29476
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
29477
+ exports.checkOffsetLength = checkOffsetLength;
29478
+ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
29479
+ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
29480
+ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
29481
+ const _builtin_1 = __webpack_require__(/*! ../_builtin */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js");
29482
+ // Offsets or lengths cannot be specified for STRING or XSTRING fields
29483
+ // passed as a method parameter source. Returns true if an issue was reported.
29484
+ function checkOffsetLength(source, sourceType, method, input) {
29485
+ const chain = source.findDirectExpression(Expressions.FieldChain);
29486
+ const isCalculated = source.findDirectExpression(Expressions.Source) !== undefined;
29487
+ const hasOffsetOrLength = chain !== undefined
29488
+ && isCalculated === false
29489
+ && (chain.findDirectExpression(Expressions.FieldOffset) !== undefined
29490
+ || chain.findDirectExpression(Expressions.FieldLength) !== undefined);
29491
+ if (hasOffsetOrLength
29492
+ && !(method instanceof _builtin_1.BuiltInMethod)
29493
+ && (sourceType instanceof basic_1.StringType || sourceType instanceof basic_1.XStringType)) {
29494
+ const message = `Offsets or lengths cannot be specified for fields of type "STRING" or "XSTRING" in the current statement`;
29495
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, source.getFirstToken(), message));
29496
+ return true;
29497
+ }
29498
+ return false;
29499
+ }
29500
+ //# sourceMappingURL=_check_offset_length.js.map
29501
+
29502
+ /***/ },
29503
+
29431
29504
  /***/ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/attribute_chain.js"
29432
29505
  /*!********************************************************************************************!*\
29433
29506
  !*** ./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/attribute_chain.js ***!
@@ -32572,6 +32645,7 @@ const source_1 = __webpack_require__(/*! ./source */ "./node_modules/@abaplint/c
32572
32645
  const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_type_utils.js");
32573
32646
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
32574
32647
  const constant_1 = __webpack_require__(/*! ./constant */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/constant.js");
32648
+ const _check_offset_length_1 = __webpack_require__(/*! ./_check_offset_length */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js");
32575
32649
  class MethodCallParam {
32576
32650
  static runSyntax(node, input, method) {
32577
32651
  if (!(node.get() instanceof Expressions.MethodCallParam)) {
@@ -32632,6 +32706,9 @@ class MethodCallParam {
32632
32706
  let sourceType = undefined;
32633
32707
  if (child.get() instanceof Expressions.Source) {
32634
32708
  sourceType = source_1.Source.runSyntax(child, input, targetType);
32709
+ if ((0, _check_offset_length_1.checkOffsetLength)(child, sourceType, method, input)) {
32710
+ return;
32711
+ }
32635
32712
  }
32636
32713
  else if (child.get() instanceof Expressions.ConstantString) {
32637
32714
  sourceType = constant_1.Constant.runSyntax(child);
@@ -32712,6 +32789,7 @@ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expr
32712
32789
  const _typed_identifier_1 = __webpack_require__(/*! ../../types/_typed_identifier */ "./node_modules/@abaplint/core/build/src/abap/types/_typed_identifier.js");
32713
32790
  const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
32714
32791
  const basic_types_1 = __webpack_require__(/*! ../basic_types */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/basic_types.js");
32792
+ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
32715
32793
  const assert_error_1 = __webpack_require__(/*! ../assert_error */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/assert_error.js");
32716
32794
  class MethodDefReturning {
32717
32795
  static runSyntax(node, input, meta) {
@@ -32724,8 +32802,11 @@ class MethodDefReturning {
32724
32802
  throw new assert_error_1.AssertError("method_parameter.ts, unexpected structure");
32725
32803
  }
32726
32804
  let found = new basic_types_1.BasicTypes(input).parseType(type);
32727
- if ((found === null || found === void 0 ? void 0 : found.isGeneric()) === true) {
32728
- found = new basic_1.UnknownType("RETURNING parameter must be fully specified");
32805
+ const message = "RETURNING parameter must be fully specified";
32806
+ const typeText = type.concatTokens().toUpperCase();
32807
+ if ((found === null || found === void 0 ? void 0 : found.isGeneric()) === true || typeText === "TYPE X" || typeText === "TYPE C") {
32808
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, type.getFirstToken(), message));
32809
+ found = new basic_1.UnknownType(message);
32729
32810
  }
32730
32811
  if (found) {
32731
32812
  return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, found, meta);
@@ -32884,6 +32965,7 @@ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modu
32884
32965
  const assert_error_1 = __webpack_require__(/*! ../assert_error */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/assert_error.js");
32885
32966
  const field_chain_1 = __webpack_require__(/*! ./field_chain */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/field_chain.js");
32886
32967
  const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
32968
+ const _check_offset_length_1 = __webpack_require__(/*! ./_check_offset_length */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js");
32887
32969
  class MethodParameters {
32888
32970
  constructor() {
32889
32971
  this.requiredParameters = undefined;
@@ -33054,7 +33136,6 @@ class MethodParameters {
33054
33136
  }
33055
33137
  }
33056
33138
  parameterListS(node, input, method) {
33057
- var _a;
33058
33139
  if (node === undefined) {
33059
33140
  return [];
33060
33141
  }
@@ -33062,14 +33143,21 @@ class MethodParameters {
33062
33143
  throw new assert_error_1.AssertError("parameterListS, unexpected node");
33063
33144
  }
33064
33145
  const ret = [];
33146
+ const supplied = new Set();
33065
33147
  for (const c of node.getChildren()) {
33066
33148
  if (!(c.get() instanceof Expressions.ParameterS) || !(c instanceof nodes_1.ExpressionNode)) {
33067
33149
  throw new assert_error_1.AssertError("parameterListS, unexpected node, child");
33068
33150
  }
33069
- const name = (_a = c.findDirectExpression(Expressions.ParameterName)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr().toUpperCase();
33070
- if (name === undefined) {
33151
+ const nameNode = c.findDirectExpression(Expressions.ParameterName);
33152
+ const name = nameNode === null || nameNode === void 0 ? void 0 : nameNode.getFirstToken().getStr().toUpperCase();
33153
+ if (name === undefined || nameNode === undefined) {
33071
33154
  throw new assert_error_1.AssertError("parameterListS, no name determined");
33072
33155
  }
33156
+ if (supplied.has(name)) {
33157
+ const message = `Method parameter "${name}" is supplied more than once`;
33158
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, nameNode.getFirstToken(), message));
33159
+ }
33160
+ supplied.add(name);
33073
33161
  const source = c.findDirectExpression(Expressions.Source);
33074
33162
  if (source === undefined) {
33075
33163
  throw new assert_error_1.AssertError("parameterListS, no source found");
@@ -33087,6 +33175,7 @@ class MethodParameters {
33087
33175
  targetType = method;
33088
33176
  }
33089
33177
  let sourceType = source_1.Source.runSyntax(source, input, targetType);
33178
+ (0, _check_offset_length_1.checkOffsetLength)(source, sourceType, method, input);
33090
33179
  if (sourceType === undefined) {
33091
33180
  if (method instanceof basic_1.VoidType) {
33092
33181
  sourceType = method;
@@ -33102,7 +33191,6 @@ class MethodParameters {
33102
33191
  return ret;
33103
33192
  }
33104
33193
  parameterListT(node, input) {
33105
- var _a;
33106
33194
  if (node === undefined) {
33107
33195
  return [];
33108
33196
  }
@@ -33110,14 +33198,21 @@ class MethodParameters {
33110
33198
  throw new assert_error_1.AssertError("parameterListT, unexpected node");
33111
33199
  }
33112
33200
  const ret = [];
33201
+ const supplied = new Set();
33113
33202
  for (const c of node.getChildren()) {
33114
33203
  if (!(c.get() instanceof Expressions.ParameterT) || !(c instanceof nodes_1.ExpressionNode)) {
33115
33204
  throw new assert_error_1.AssertError("parameterListT, unexpected node, child");
33116
33205
  }
33117
- const name = (_a = c.findDirectExpression(Expressions.ParameterName)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr().toUpperCase();
33118
- if (name === undefined) {
33206
+ const nameNode = c.findDirectExpression(Expressions.ParameterName);
33207
+ const name = nameNode === null || nameNode === void 0 ? void 0 : nameNode.getFirstToken().getStr().toUpperCase();
33208
+ if (name === undefined || nameNode === undefined) {
33119
33209
  throw new assert_error_1.AssertError("parameterListT, no name determined");
33120
33210
  }
33211
+ if (supplied.has(name)) {
33212
+ const message = `Method parameter "${name}" is supplied more than once`;
33213
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, nameNode.getFirstToken(), message));
33214
+ }
33215
+ supplied.add(name);
33121
33216
  const target = c.findDirectExpression(Expressions.Target);
33122
33217
  if (target === undefined) {
33123
33218
  throw new assert_error_1.AssertError("parameterListT, no target found");
@@ -34388,6 +34483,7 @@ class Source {
34388
34483
  else {
34389
34484
  this.addIfInferred(node, input, foundType);
34390
34485
  }
34486
+ this.traverseRemainingChildren(children, input);
34391
34487
  return foundType ? foundType : bodyType;
34392
34488
  }
34393
34489
  case "SWITCH":
@@ -37458,8 +37554,10 @@ const inline_data_1 = __webpack_require__(/*! ../expressions/inline_data */ "./n
37458
37554
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
37459
37555
  class CallTransformation {
37460
37556
  runSyntax(node, input) {
37557
+ const resultParameters = node.findExpressionAfterToken("RESULT");
37558
+ const resultSources = new Set((resultParameters === null || resultParameters === void 0 ? void 0 : resultParameters.findAllExpressions(Expressions.SimpleSource3)) || []);
37461
37559
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
37462
- source_1.Source.runSyntax(s, input);
37560
+ source_1.Source.runSyntax(s, input, undefined, resultSources.has(s));
37463
37561
  }
37464
37562
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
37465
37563
  dynamic_1.Dynamic.runSyntax(d, input);
@@ -37646,6 +37744,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@ab
37646
37744
  const target_1 = __webpack_require__(/*! ../expressions/target */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/target.js");
37647
37745
  const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
37648
37746
  const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
37747
+ const _type_utils_1 = __webpack_require__(/*! ../_type_utils */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_type_utils.js");
37649
37748
  class Catch {
37650
37749
  runSyntax(node, input) {
37651
37750
  var _a, _b;
@@ -37696,7 +37795,22 @@ class Catch {
37696
37795
  }
37697
37796
  }
37698
37797
  else if (target) {
37699
- target_1.Target.runSyntax(target, input);
37798
+ const targetType = target_1.Target.runSyntax(target, input);
37799
+ if (targetType instanceof basic_1.ObjectReferenceType) {
37800
+ for (const c of node.findDirectExpressions(Expressions.ClassName)) {
37801
+ const token = c.getFirstToken();
37802
+ const className = token.getStr().toUpperCase();
37803
+ const found = input.scope.existsObject(className);
37804
+ if (found === null || found === void 0 ? void 0 : found.id) {
37805
+ const catchType = new basic_1.ObjectReferenceType(found.id);
37806
+ if (new _type_utils_1.TypeUtils(input.scope).isAssignableStrict(catchType, targetType) === false) {
37807
+ const message = "CATCH target not compatible with " + className;
37808
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
37809
+ return;
37810
+ }
37811
+ }
37812
+ }
37813
+ }
37700
37814
  }
37701
37815
  }
37702
37816
  }
@@ -38417,6 +38531,11 @@ class Concatenate {
38417
38531
  runSyntax(node, input) {
38418
38532
  const byteMode = node.findDirectTokenByText("BYTE") !== undefined;
38419
38533
  const linesMode = node.findDirectTokenByText("LINES") !== undefined;
38534
+ if (node.findFirstExpression(Expressions.TableExpression) !== undefined) {
38535
+ const message = "CONCATENATE with table expression not possible";
38536
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
38537
+ return;
38538
+ }
38420
38539
  const target = node.findFirstExpression(Expressions.Target);
38421
38540
  const inline = target === null || target === void 0 ? void 0 : target.findDirectExpression(Expressions.InlineData);
38422
38541
  if (inline) {
@@ -54015,7 +54134,7 @@ class CDSDefineAbstract extends combi_1.Expression {
54015
54134
  getRunnable() {
54016
54135
  const field = (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.optPrio)((0, combi_1.str)("KEY")), cds_name_1.CDSName, ":", _1.CDSType, ";");
54017
54136
  const compsiOrAssoci = (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), cds_name_1.CDSName, ":", (0, combi_1.alt)(_1.CDSComposition, _1.CDSAssociation), ";");
54018
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), "ABSTRACT", "ENTITY", cds_name_1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.alt)(field, compsiOrAssoci)), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
54137
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), "ABSTRACT", "ENTITY", cds_name_1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.alt)(field, compsiOrAssoci)), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
54019
54138
  }
54020
54139
  }
54021
54140
  exports.CDSDefineAbstract = CDSDefineAbstract;
@@ -54041,7 +54160,7 @@ class CDSDefineCustom extends combi_1.Expression {
54041
54160
  getRunnable() {
54042
54161
  const field = (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.str)("KEY")), cds_name_1.CDSName, ":", cds_type_1.CDSType, ";");
54043
54162
  const compsiOrAssoci = (0, combi_1.seq)(cds_name_1.CDSName, ":", (0, combi_1.alt)(_1.CDSComposition, _1.CDSAssociation), ";");
54044
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.str)("DEFINE"), (0, combi_1.opt)((0, combi_1.str)("ROOT")), (0, combi_1.str)("CUSTOM ENTITY"), cds_name_1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.alt)(field, compsiOrAssoci))), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
54163
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), (0, combi_1.str)("CUSTOM ENTITY"), cds_name_1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.str)("{"), (0, combi_1.plus)((0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.alt)(field, compsiOrAssoci))), (0, combi_1.str)("}"), (0, combi_1.opt)(";"));
54045
54164
  }
54046
54165
  }
54047
54166
  exports.CDSDefineCustom = CDSDefineCustom;
@@ -54071,7 +54190,7 @@ class CDSDefineExternalEntity extends combi_1.Expression {
54071
54190
  const body = (0, combi_1.plus)((0, combi_1.alt)(field, assocOrComp));
54072
54191
  const externalEntity = (0, combi_1.seq)((0, combi_1.opt)("WRITABLE"), "EXTERNAL", "ENTITY", _1.CDSName, (0, combi_1.opt)(externalName), (0, combi_1.opt)(_1.CDSWithParameters));
54073
54192
  const staticEntity = (0, combi_1.seq)("STATIC", "ENTITY", _1.CDSName, (0, combi_1.opt)(externalName));
54074
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.alt)(externalEntity, staticEntity), (0, combi_1.str)("{"), body, (0, combi_1.str)("}"), (0, combi_1.opt)((0, combi_1.seq)("WITH", "FEDERATED", "DATA", (0, combi_1.optPrio)((0, combi_1.alt)((0, combi_1.seq)("PROVIDED", "AT", "RUNTIME"), (0, combi_1.seq)("PROVIDED", "BY", _1.CDSName))))), (0, combi_1.opt)(";"));
54193
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.alt)(externalEntity, staticEntity), (0, combi_1.str)("{"), body, (0, combi_1.str)("}"), (0, combi_1.opt)((0, combi_1.seq)("WITH", "FEDERATED", "DATA", (0, combi_1.optPrio)((0, combi_1.alt)((0, combi_1.seq)("PROVIDED", "AT", "RUNTIME"), (0, combi_1.seq)("PROVIDED", "BY", _1.CDSName))))), (0, combi_1.opt)(";"));
54075
54194
  }
54076
54195
  }
54077
54196
  exports.CDSDefineExternalEntity = CDSDefineExternalEntity;
@@ -54103,7 +54222,7 @@ class CDSDefineHierarchy extends combi_1.Expression {
54103
54222
  const depthValue = (0, combi_1.altPrio)(_1.CDSString, _1.CDSInteger, _1.CDSPrefixedName);
54104
54223
  const loadMode = (0, combi_1.altPrio)("BULK", "INCREMENTAL", _1.CDSPrefixedName);
54105
54224
  const hierarchyBody = (0, combi_1.seq)("SOURCE", _1.CDSName, (0, combi_1.opt)(_1.CDSParametersSelect), "CHILD", "TO", "PARENT", "ASSOCIATION", _1.CDSName, (0, combi_1.opt)(directory), (0, combi_1.opt)(datePeriod), (0, combi_1.opt)((0, combi_1.seq)("START", "WHERE", _1.CDSCondition)), (0, combi_1.opt)(siblingsOrder), (0, combi_1.opt)((0, combi_1.seq)("LOAD", loadMode)), (0, combi_1.opt)((0, combi_1.seq)("DEPTH", depthValue)), (0, combi_1.opt)((0, combi_1.seq)("NODETYPE", _1.CDSName)), (0, combi_1.opt)((0, combi_1.seq)("MULTIPLE", "PARENTS", (0, combi_1.altPrio)("NOT ALLOWED", "ALLOWED", (0, combi_1.seq)("LEAVES", (0, combi_1.optPrio)("ONLY"))))), (0, combi_1.opt)((0, combi_1.seq)("ORPHANS", (0, combi_1.altPrio)("IGNORE", "ROOT", "ERROR"))), (0, combi_1.opt)((0, combi_1.seq)("CYCLES", (0, combi_1.altPrio)("BREAKUP", "ERROR"))), (0, combi_1.opt)((0, combi_1.seq)("GENERATE", "SPANTREE")), (0, combi_1.opt)((0, combi_1.seq)("CACHE", (0, combi_1.altPrio)("ON", "OFF", "FORCE"))));
54106
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", "HIERARCHY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), "AS", "PARENT", "CHILD", "HIERARCHY", "(", hierarchyBody, ")", "{", (0, combi_1.seq)(field, (0, combi_1.star)((0, combi_1.seq)(",", field))), "}", (0, combi_1.opt)(";"));
54225
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), "HIERARCHY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), "AS", "PARENT", "CHILD", "HIERARCHY", "(", hierarchyBody, ")", "{", (0, combi_1.seq)(field, (0, combi_1.star)((0, combi_1.seq)(",", field))), "}", (0, combi_1.opt)(";"));
54107
54226
  }
54108
54227
  }
54109
54228
  exports.CDSDefineHierarchy = CDSDefineHierarchy;
@@ -54128,7 +54247,7 @@ class CDSDefineProjection extends combi_1.Expression {
54128
54247
  getRunnable() {
54129
54248
  // redefine association _Assoc redirected to [composition child | parent] Entity
54130
54249
  const redefineAssoc = (0, combi_1.seq)("REDEFINE", "ASSOCIATION", _1.CDSName, "REDIRECTED", "TO", (0, combi_1.optPrio)((0, combi_1.altPrio)((0, combi_1.seq)("COMPOSITION", "CHILD"), "PARENT")), _1.CDSName);
54131
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), (0, combi_1.opt)("TRANSIENT"), "VIEW", (0, combi_1.ver)(__1.Release.v755, (0, combi_1.opt)("ENTITY")), _1.CDSName, (0, combi_1.opt)(_1.CDSProviderContract), (0, combi_1.opt)(_1.CDSWithParameters), "AS PROJECTION ON", _1.CDSName, (0, combi_1.opt)(_1.CDSParametersSelect), (0, combi_1.opt)(_1.CDSAs), (0, combi_1.star)((0, combi_1.altPrio)(_1.CDSAssociation, redefineAssoc)), (0, combi_1.str)("{"), (0, combi_1.seq)(_1.CDSElement, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSElement)), (0, combi_1.opt)(",")), (0, combi_1.str)("}"), (0, combi_1.opt)(_1.CDSWhere), (0, combi_1.opt)(";"));
54250
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), (0, combi_1.opt)("TRANSIENT"), "VIEW", (0, combi_1.ver)(__1.Release.v755, (0, combi_1.opt)("ENTITY")), _1.CDSName, (0, combi_1.opt)(_1.CDSProviderContract), (0, combi_1.opt)(_1.CDSWithParameters), "AS PROJECTION ON", _1.CDSName, (0, combi_1.opt)(_1.CDSParametersSelect), (0, combi_1.opt)(_1.CDSAs), (0, combi_1.star)((0, combi_1.altPrio)(_1.CDSAssociation, redefineAssoc)), (0, combi_1.str)("{"), (0, combi_1.seq)(_1.CDSElement, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSElement)), (0, combi_1.opt)(",")), (0, combi_1.str)("}"), (0, combi_1.opt)(_1.CDSWhere), (0, combi_1.opt)(";"));
54132
54251
  }
54133
54252
  }
54134
54253
  exports.CDSDefineProjection = CDSDefineProjection;
@@ -54157,7 +54276,7 @@ class CDSDefineTableEntity extends combi_1.Expression {
54157
54276
  const elementList = (0, combi_1.seq)(_1.CDSElement, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSElement)), (0, combi_1.opt)(","));
54158
54277
  const elements = (0, combi_1.seq)((0, combi_1.str)("{"), (0, combi_1.altPrio)("*", elementList), (0, combi_1.str)("}"));
54159
54278
  const selectBody = (0, combi_1.seq)("AS", "SELECT", "FROM", _1.CDSSource, (0, combi_1.star)(_1.CDSJoin), (0, combi_1.star)((0, combi_1.altPrio)(_1.CDSComposition, _1.CDSAssociation)), (0, combi_1.opt)(elements), (0, combi_1.optPrio)(_1.CDSWhere));
54160
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), "DEFINE", (0, combi_1.opt)("ROOT"), "TABLE", "ENTITY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.altPrio)((0, combi_1.seq)((0, combi_1.str)("{"), inlineBody, (0, combi_1.str)("}")), selectBody), (0, combi_1.opt)(";"));
54279
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.opt)("DEFINE"), (0, combi_1.opt)("ROOT"), "TABLE", "ENTITY", _1.CDSName, (0, combi_1.opt)(_1.CDSWithParameters), (0, combi_1.altPrio)((0, combi_1.seq)((0, combi_1.str)("{"), inlineBody, (0, combi_1.str)("}")), selectBody), (0, combi_1.opt)(";"));
54161
54280
  }
54162
54281
  }
54163
54282
  exports.CDSDefineTableEntity = CDSDefineTableEntity;
@@ -55099,7 +55218,7 @@ class Config {
55099
55218
  }
55100
55219
  return (0, version_1.versionToABAPRelease)(v);
55101
55220
  }
55102
- getOpenABAP() {
55221
+ isOpenABAP() {
55103
55222
  return this.getRelease() === version_1.Release["open-abap"];
55104
55223
  }
55105
55224
  getVersion() {
@@ -69246,7 +69365,7 @@ class Registry {
69246
69365
  }
69247
69366
  static abaplintVersion() {
69248
69367
  // magic, see build script "version.js"
69249
- return "2.119.64";
69368
+ return "2.120.2";
69250
69369
  }
69251
69370
  getDDICReferences() {
69252
69371
  return this.ddicReferences;
@@ -73949,6 +74068,270 @@ exports.ClassicExceptionsOverlap = ClassicExceptionsOverlap;
73949
74068
 
73950
74069
  /***/ },
73951
74070
 
74071
+ /***/ "./node_modules/@abaplint/core/build/src/rules/clear_exporting_parameters.js"
74072
+ /*!***********************************************************************************!*\
74073
+ !*** ./node_modules/@abaplint/core/build/src/rules/clear_exporting_parameters.js ***!
74074
+ \***********************************************************************************/
74075
+ (__unused_webpack_module, exports, __webpack_require__) {
74076
+
74077
+ "use strict";
74078
+
74079
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
74080
+ if (k2 === undefined) k2 = k;
74081
+ var desc = Object.getOwnPropertyDescriptor(m, k);
74082
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
74083
+ desc = { enumerable: true, get: function() { return m[k]; } };
74084
+ }
74085
+ Object.defineProperty(o, k2, desc);
74086
+ }) : (function(o, m, k, k2) {
74087
+ if (k2 === undefined) k2 = k;
74088
+ o[k2] = m[k];
74089
+ }));
74090
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
74091
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
74092
+ }) : function(o, v) {
74093
+ o["default"] = v;
74094
+ });
74095
+ var __importStar = (this && this.__importStar) || (function () {
74096
+ var ownKeys = function(o) {
74097
+ ownKeys = Object.getOwnPropertyNames || function (o) {
74098
+ var ar = [];
74099
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
74100
+ return ar;
74101
+ };
74102
+ return ownKeys(o);
74103
+ };
74104
+ return function (mod) {
74105
+ if (mod && mod.__esModule) return mod;
74106
+ var result = {};
74107
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
74108
+ __setModuleDefault(result, mod);
74109
+ return result;
74110
+ };
74111
+ })();
74112
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
74113
+ exports.ClearExportingParameters = exports.ClearExportingParametersConf = void 0;
74114
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
74115
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
74116
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
74117
+ const syntax_1 = __webpack_require__(/*! ../abap/5_syntax/syntax */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/syntax.js");
74118
+ const _abap_object_1 = __webpack_require__(/*! ../objects/_abap_object */ "./node_modules/@abaplint/core/build/src/objects/_abap_object.js");
74119
+ const _scope_type_1 = __webpack_require__(/*! ../abap/5_syntax/_scope_type */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_scope_type.js");
74120
+ const objects_1 = __webpack_require__(/*! ../objects */ "./node_modules/@abaplint/core/build/src/objects/index.js");
74121
+ const _reference_1 = __webpack_require__(/*! ../abap/5_syntax/_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
74122
+ const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
74123
+ const _statement_1 = __webpack_require__(/*! ../abap/2_statements/statements/_statement */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/_statement.js");
74124
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
74125
+ const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
74126
+ class ClearExportingParametersConf extends _basic_rule_config_1.BasicRuleConfig {
74127
+ constructor() {
74128
+ super(...arguments);
74129
+ /** Skip specific parameter names, case insensitive
74130
+ * @uniqueItems true
74131
+ */
74132
+ this.skipNames = [];
74133
+ }
74134
+ }
74135
+ exports.ClearExportingParametersConf = ClearExportingParametersConf;
74136
+ class ClearExportingParameters {
74137
+ constructor() {
74138
+ this.conf = new ClearExportingParametersConf();
74139
+ }
74140
+ getMetadata() {
74141
+ return {
74142
+ key: "clear_exporting_parameters",
74143
+ title: "Clear EXPORTING parameters",
74144
+ shortDescription: `Checks that EXPORTING parameters passed by reference are cleared or assigned before they are read`,
74145
+ extendedInformation: `An EXPORTING parameter passed by reference behaves like a CHANGING parameter: it is not
74146
+ initialized when the method is called, so it can still contain a value supplied by the caller. Clear or overwrite it
74147
+ before reading it, so a leftover value is not accidentally used.
74148
+
74149
+ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#clear-or-overwrite-exporting-reference-parameters
74150
+
74151
+ https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abenref_transf_output_param_guidl.htm
74152
+
74153
+ Note: EXPORTING parameters passed by VALUE are always initialized and are therefore not reported.
74154
+ Reading and writing the parameter in the same statement (e.g. "ev_result = ev_result + 1") is reported,
74155
+ as the source is evaluated before the parameter is assigned.
74156
+ Objects containing parser or syntax errors are not reported.
74157
+
74158
+ Only class and interface method implementations are checked, function module parameters are currently not supported.`,
74159
+ tags: [_irule_1.RuleTag.Styleguide],
74160
+ badExample: `CLASS lcl DEFINITION.
74161
+ PUBLIC SECTION.
74162
+ METHODS foo EXPORTING ev_result TYPE i.
74163
+ ENDCLASS.
74164
+ CLASS lcl IMPLEMENTATION.
74165
+ METHOD foo.
74166
+ ev_result = ev_result + 1.
74167
+ ENDMETHOD.
74168
+ ENDCLASS.`,
74169
+ goodExample: `CLASS lcl DEFINITION.
74170
+ PUBLIC SECTION.
74171
+ METHODS foo EXPORTING ev_result TYPE i.
74172
+ ENDCLASS.
74173
+ CLASS lcl IMPLEMENTATION.
74174
+ METHOD foo.
74175
+ CLEAR ev_result.
74176
+ ev_result = ev_result + 1.
74177
+ ENDMETHOD.
74178
+ ENDCLASS.`,
74179
+ };
74180
+ }
74181
+ getConfig() {
74182
+ return this.conf;
74183
+ }
74184
+ setConfig(conf) {
74185
+ this.conf = conf;
74186
+ if (this.conf.skipNames === undefined) {
74187
+ this.conf.skipNames = [];
74188
+ }
74189
+ }
74190
+ initialize(reg) {
74191
+ this.reg = reg;
74192
+ return this;
74193
+ }
74194
+ run(obj) {
74195
+ if (!(obj instanceof _abap_object_1.ABAPObject) || obj instanceof objects_1.Interface) {
74196
+ return [];
74197
+ }
74198
+ for (const file of obj.getABAPFiles()) {
74199
+ for (const statement of file.getStatements()) {
74200
+ if (statement.get() instanceof _statement_1.Unknown) {
74201
+ return []; // contains parser errors
74202
+ }
74203
+ }
74204
+ }
74205
+ const syntax = new syntax_1.SyntaxLogic(this.reg, obj).run();
74206
+ if (syntax.issues.length > 0) {
74207
+ return []; // contains syntax errors
74208
+ }
74209
+ const issues = [];
74210
+ this.traverse(syntax.spaghetti.getTop(), obj, issues);
74211
+ return issues;
74212
+ }
74213
+ traverse(node, obj, issues) {
74214
+ if (node.getIdentifier().stype === _scope_type_1.ScopeType.Method) {
74215
+ this.checkMethod(node, obj, issues);
74216
+ }
74217
+ for (const child of node.getChildren()) {
74218
+ this.traverse(child, obj, issues);
74219
+ }
74220
+ }
74221
+ checkMethod(node, obj, issues) {
74222
+ const parameters = this.findExportingByReference(node, obj);
74223
+ if (parameters.length === 0) {
74224
+ return;
74225
+ }
74226
+ const references = this.collectReferences(node);
74227
+ for (const parameter of parameters) {
74228
+ const issue = this.checkParameter(parameter, references, obj);
74229
+ if (issue !== undefined) {
74230
+ issues.push(issue);
74231
+ }
74232
+ }
74233
+ }
74234
+ findExportingByReference(node, obj) {
74235
+ var _a;
74236
+ const ret = [];
74237
+ const vars = node.getData().vars;
74238
+ for (const name in vars) {
74239
+ const parameter = vars[name];
74240
+ const meta = parameter.getMeta();
74241
+ if (meta.includes("exporting" /* IdentifierMeta.MethodExporting */) === false
74242
+ || meta.includes("pass_by_value" /* IdentifierMeta.PassByValue */) === true) {
74243
+ continue;
74244
+ }
74245
+ else if ((_a = this.conf.skipNames) === null || _a === void 0 ? void 0 : _a.some(s => s.toUpperCase() === name.toUpperCase())) {
74246
+ continue;
74247
+ }
74248
+ const type = parameter.getType();
74249
+ if (type instanceof basic_1.VoidType || type instanceof basic_1.UnknownType) {
74250
+ continue; // e.g. RAP magic parameters, or unresolved types
74251
+ }
74252
+ else if (this.isPassByValue(parameter, obj) === true) {
74253
+ continue; // VALUE(..) parameters are always initialized
74254
+ }
74255
+ ret.push(parameter);
74256
+ }
74257
+ return ret;
74258
+ }
74259
+ isPassByValue(parameter, obj) {
74260
+ var _a;
74261
+ // the PassByValue meta is not set for EXPORTING parameters, so determine it from the definition
74262
+ const file = obj.getABAPFileByName(parameter.getFilename());
74263
+ if (file === undefined) {
74264
+ return false;
74265
+ }
74266
+ const statement = edit_helper_1.EditHelper.findStatement(parameter.getToken(), file);
74267
+ if (statement === undefined) {
74268
+ return false;
74269
+ }
74270
+ for (const param of statement.findAllExpressions(Expressions.MethodParam)) {
74271
+ const nameToken = (_a = param.findFirstExpression(Expressions.MethodParamName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
74272
+ if (nameToken !== undefined && nameToken.getStart().equals(parameter.getStart())) {
74273
+ return param.getFirstToken().getStr().toUpperCase() === "VALUE";
74274
+ }
74275
+ }
74276
+ return false;
74277
+ }
74278
+ collectReferences(node) {
74279
+ // methods do not nest, so all descendant scopes (FOR, LET, ...) belong to this method
74280
+ const ret = [...node.getData().references];
74281
+ for (const child of node.getChildren()) {
74282
+ ret.push(...this.collectReferences(child));
74283
+ }
74284
+ return ret;
74285
+ }
74286
+ checkParameter(parameter, references, obj) {
74287
+ let firstRead = undefined;
74288
+ let earliestWrite = undefined;
74289
+ for (const reference of references) {
74290
+ if (reference.resolved === undefined || parameter.equals(reference.resolved) === false) {
74291
+ continue;
74292
+ }
74293
+ const pos = reference.position.getStart();
74294
+ if (reference.referenceType === _reference_1.ReferenceType.DataReadReference) {
74295
+ if (firstRead === undefined || pos.isBefore(firstRead.position.getStart())) {
74296
+ firstRead = reference;
74297
+ }
74298
+ }
74299
+ else if (reference.referenceType === _reference_1.ReferenceType.DataWriteReference) {
74300
+ if (earliestWrite === undefined || pos.isBefore(earliestWrite.position.getStart())) {
74301
+ earliestWrite = reference;
74302
+ }
74303
+ }
74304
+ }
74305
+ if (firstRead === undefined) {
74306
+ return undefined; // never read, no hazard
74307
+ }
74308
+ // the parameter is safe only if it is written in a statement strictly before the first read
74309
+ const readStatement = this.statementStart(firstRead, obj);
74310
+ const writeStatement = earliestWrite === undefined ? undefined : this.statementStart(earliestWrite, obj);
74311
+ if (writeStatement !== undefined && readStatement !== undefined && writeStatement.isBefore(readStatement)) {
74312
+ return undefined;
74313
+ }
74314
+ const message = `EXPORTING parameter "${parameter.getName().toLowerCase()}" read before it is cleared or assigned`;
74315
+ return issue_1.Issue.atIdentifier(firstRead.position, message, this.getMetadata().key, this.conf.severity);
74316
+ }
74317
+ statementStart(reference, obj) {
74318
+ const file = obj.getABAPFileByName(reference.position.getFilename());
74319
+ for (const statement of (file === null || file === void 0 ? void 0 : file.getStatements()) || []) {
74320
+ const pos = reference.position.getStart();
74321
+ const start = statement.getStart();
74322
+ const end = statement.getEnd();
74323
+ if (pos.equals(start) || (pos.isAfter(start) && pos.isBefore(end))) {
74324
+ return start;
74325
+ }
74326
+ }
74327
+ return undefined;
74328
+ }
74329
+ }
74330
+ exports.ClearExportingParameters = ClearExportingParameters;
74331
+ //# sourceMappingURL=clear_exporting_parameters.js.map
74332
+
74333
+ /***/ },
74334
+
73952
74335
  /***/ "./node_modules/@abaplint/core/build/src/rules/cloud_types.js"
73953
74336
  /*!********************************************************************!*\
73954
74337
  !*** ./node_modules/@abaplint/core/build/src/rules/cloud_types.js ***!
@@ -75864,7 +76247,7 @@ Make sure to test the downported code, it might not always be completely correct
75864
76247
  initialize(reg) {
75865
76248
  this.lowReg = reg;
75866
76249
  const config = this.lowReg.getConfig();
75867
- if (config.getRelease() === version_1.Release.v702 || config.getOpenABAP()) {
76250
+ if (config.getRelease() === version_1.Release.v702 || config.isOpenABAP()) {
75868
76251
  this.initHighReg();
75869
76252
  }
75870
76253
  return this;
@@ -75897,7 +76280,7 @@ Make sure to test the downported code, it might not always be completely correct
75897
76280
  const ret = [];
75898
76281
  this.counter = 1;
75899
76282
  const config = this.lowReg.getConfig();
75900
- if (config.getRelease() !== version_1.Release.v702 && !config.getOpenABAP()) {
76283
+ if (config.getRelease() !== version_1.Release.v702 && !config.isOpenABAP()) {
75901
76284
  return ret;
75902
76285
  }
75903
76286
  else if (!(lowObj instanceof _abap_object_1.ABAPObject)) {
@@ -75991,6 +76374,18 @@ Make sure to test the downported code, it might not always be completely correct
75991
76374
  }
75992
76375
  }
75993
76376
  }
76377
+ // INTO after WHERE parses as a valid SELECT in the low version, but is only allowed in
76378
+ // strict SQL syntax, so move it also when the statement is no longer Unknown
76379
+ if (ret.length === 0) {
76380
+ for (let i = 0; i < lowStatements.length; i++) {
76381
+ const low = lowStatements[i];
76382
+ const high = highStatements[i];
76383
+ const issue = this.downportSQLMoveInto(low, high, lowFile, highSyntax);
76384
+ if (issue) {
76385
+ ret.push(issue);
76386
+ }
76387
+ }
76388
+ }
75994
76389
  }
75995
76390
  return ret;
75996
76391
  }
@@ -76234,10 +76629,14 @@ Make sure to test the downported code, it might not always be completely correct
76234
76629
  return undefined;
76235
76630
  }
76236
76631
  //////////////////////////////////////////
76237
- /** move INTO from after WHERE to after FROM */
76632
+ /** move INTO from after WHERE to after FROM,
76633
+ * note that INTO after WHERE is only valid in strict SQL syntax, so it must be moved when
76634
+ * downporting; this can happen both while the statement is still Unknown(from the main loop)
76635
+ * and after the @ and FIELDS have been removed, leaving a SELECT that parses in the low version */
76238
76636
  downportSQLMoveInto(low, high, lowFile, _highSyntax) {
76239
76637
  var _a;
76240
- if (!(low.get() instanceof _statement_1.Unknown)) {
76638
+ if (!(high.get() instanceof Statements.Select)
76639
+ && !(high.get() instanceof Statements.SelectLoop)) {
76241
76640
  return undefined;
76242
76641
  }
76243
76642
  // note: SQLCond is also used in JOIN(FROM) conditions
@@ -76245,6 +76644,7 @@ Make sure to test the downported code, it might not always be completely correct
76245
76644
  if (where === undefined) {
76246
76645
  return undefined;
76247
76646
  }
76647
+ // the FIELDS list sits between FROM and WHERE, wait for it to be removed first
76248
76648
  if (high.findFirstExpression(Expressions.SQLFields) !== undefined) {
76249
76649
  return undefined;
76250
76650
  }
@@ -76752,7 +77152,7 @@ ${indentation}`);
76752
77152
  outlineCatchSimple(node, lowFile) {
76753
77153
  // outlines "CATCH cx_bcs INTO DATA(lx_bcs_excep).", note that this does not need to look at types
76754
77154
  var _a, _b;
76755
- if (this.lowReg.getConfig().getOpenABAP()) {
77155
+ if (this.lowReg.getConfig().isOpenABAP()) {
76756
77156
  return undefined;
76757
77157
  }
76758
77158
  if (!(node.get() instanceof Statements.Catch)) {
@@ -76801,7 +77201,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
76801
77201
  if (!(node.get() instanceof Statements.Move)) {
76802
77202
  return undefined;
76803
77203
  }
76804
- if (this.lowReg.getConfig().getOpenABAP()) {
77204
+ if (this.lowReg.getConfig().isOpenABAP()) {
76805
77205
  return undefined;
76806
77206
  }
76807
77207
  const target = node.findFirstExpression(Expressions.Target);
@@ -76857,7 +77257,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
76857
77257
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
76858
77258
  }
76859
77259
  partiallyImplemented(node, lowFile) {
76860
- if (this.lowReg.getConfig().getOpenABAP()) {
77260
+ if (this.lowReg.getConfig().isOpenABAP()) {
76861
77261
  return undefined;
76862
77262
  }
76863
77263
  if (node.get() instanceof Statements.InterfaceDef) {
@@ -77533,7 +77933,7 @@ ${indentation} output = ${uniqueName}.\n`;
77533
77933
  if (!(node.get() instanceof Statements.Loop)) {
77534
77934
  return undefined;
77535
77935
  }
77536
- if (this.lowReg.getConfig().getOpenABAP()) {
77936
+ if (this.lowReg.getConfig().isOpenABAP()) {
77537
77937
  return undefined;
77538
77938
  }
77539
77939
  const source = (_a = node.findDirectExpression(Expressions.LoopSource)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.SimpleSource2);
@@ -78209,7 +78609,7 @@ ${indentation} output = ${uniqueName}.\n`;
78209
78609
  outlineData(node, lowFile, highSyntax) {
78210
78610
  // hmm, no guard here, as DATA(SDF) is valid in 702
78211
78611
  var _a, _b;
78212
- if (this.lowReg.getConfig().getOpenABAP()) {
78612
+ if (this.lowReg.getConfig().isOpenABAP()) {
78213
78613
  return undefined;
78214
78614
  }
78215
78615
  for (const i of node.findAllExpressionsRecursive(Expressions.InlineData)) {
@@ -78428,7 +78828,7 @@ ${indentation} output = ${uniqueName}.\n`;
78428
78828
  return false;
78429
78829
  }
78430
78830
  replaceXsdBool(node, lowFile, highSyntax) {
78431
- if (this.lowReg.getConfig().getOpenABAP()) {
78831
+ if (this.lowReg.getConfig().isOpenABAP()) {
78432
78832
  return undefined;
78433
78833
  }
78434
78834
  const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
@@ -78557,7 +78957,7 @@ ${indentation} output = ${uniqueName}.\n`;
78557
78957
  }
78558
78958
  replaceLineFunctions(node, lowFile, highSyntax, highFile) {
78559
78959
  var _a, _b;
78560
- if (this.lowReg.getConfig().getOpenABAP()) {
78960
+ if (this.lowReg.getConfig().isOpenABAP()) {
78561
78961
  return undefined;
78562
78962
  }
78563
78963
  const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
@@ -82731,6 +83131,7 @@ __exportStar(__webpack_require__(/*! ./check_subrc */ "./node_modules/@abaplint/
82731
83131
  __exportStar(__webpack_require__(/*! ./check_syntax */ "./node_modules/@abaplint/core/build/src/rules/check_syntax.js"), exports);
82732
83132
  __exportStar(__webpack_require__(/*! ./check_text_elements */ "./node_modules/@abaplint/core/build/src/rules/check_text_elements.js"), exports);
82733
83133
  __exportStar(__webpack_require__(/*! ./check_transformation_exists */ "./node_modules/@abaplint/core/build/src/rules/check_transformation_exists.js"), exports);
83134
+ __exportStar(__webpack_require__(/*! ./clear_exporting_parameters */ "./node_modules/@abaplint/core/build/src/rules/clear_exporting_parameters.js"), exports);
82734
83135
  __exportStar(__webpack_require__(/*! ./class_attribute_names */ "./node_modules/@abaplint/core/build/src/rules/class_attribute_names.js"), exports);
82735
83136
  __exportStar(__webpack_require__(/*! ./classic_exceptions_overlap */ "./node_modules/@abaplint/core/build/src/rules/classic_exceptions_overlap.js"), exports);
82736
83137
  __exportStar(__webpack_require__(/*! ./cloud_types */ "./node_modules/@abaplint/core/build/src/rules/cloud_types.js"), exports);
@@ -82836,6 +83237,7 @@ __exportStar(__webpack_require__(/*! ./preferred_compare_operator */ "./node_mod
82836
83237
  __exportStar(__webpack_require__(/*! ./prefix_is_current_class */ "./node_modules/@abaplint/core/build/src/rules/prefix_is_current_class.js"), exports);
82837
83238
  __exportStar(__webpack_require__(/*! ./reduce_procedural_code */ "./node_modules/@abaplint/core/build/src/rules/reduce_procedural_code.js"), exports);
82838
83239
  __exportStar(__webpack_require__(/*! ./reduce_string_templates */ "./node_modules/@abaplint/core/build/src/rules/reduce_string_templates.js"), exports);
83240
+ __exportStar(__webpack_require__(/*! ./redundant_conversion */ "./node_modules/@abaplint/core/build/src/rules/redundant_conversion.js"), exports);
82839
83241
  __exportStar(__webpack_require__(/*! ./release_idoc */ "./node_modules/@abaplint/core/build/src/rules/release_idoc.js"), exports);
82840
83242
  __exportStar(__webpack_require__(/*! ./remove_descriptions */ "./node_modules/@abaplint/core/build/src/rules/remove_descriptions.js"), exports);
82841
83243
  __exportStar(__webpack_require__(/*! ./rfc_error_handling */ "./node_modules/@abaplint/core/build/src/rules/rfc_error_handling.js"), exports);
@@ -83041,7 +83443,7 @@ class InlineDataOldVersions extends _abap_rule_1.ABAPRule {
83041
83443
  runParsed(file) {
83042
83444
  const issues = [];
83043
83445
  if ((0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
83044
- || this.reg.getConfig().getOpenABAP()
83446
+ || this.reg.getConfig().isOpenABAP()
83045
83447
  || this.reg.getConfig().getLanguageVersion() === version_1.LanguageVersion.Cloud) {
83046
83448
  return [];
83047
83449
  }
@@ -87163,7 +87565,7 @@ Not considered optional branches:
87163
87565
  const release = this.reg.getConfig().getRelease();
87164
87566
  if (release === version_1.Release.v700
87165
87567
  || release === version_1.Release.v702
87166
- || this.reg.getConfig().getOpenABAP()) {
87568
+ || this.reg.getConfig().isOpenABAP()) {
87167
87569
  return [];
87168
87570
  }
87169
87571
  const struc = file.getStructure();
@@ -91314,6 +91716,269 @@ exports.ReduceStringTemplates = ReduceStringTemplates;
91314
91716
 
91315
91717
  /***/ },
91316
91718
 
91719
+ /***/ "./node_modules/@abaplint/core/build/src/rules/redundant_conversion.js"
91720
+ /*!*****************************************************************************!*\
91721
+ !*** ./node_modules/@abaplint/core/build/src/rules/redundant_conversion.js ***!
91722
+ \*****************************************************************************/
91723
+ (__unused_webpack_module, exports, __webpack_require__) {
91724
+
91725
+ "use strict";
91726
+
91727
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
91728
+ if (k2 === undefined) k2 = k;
91729
+ var desc = Object.getOwnPropertyDescriptor(m, k);
91730
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
91731
+ desc = { enumerable: true, get: function() { return m[k]; } };
91732
+ }
91733
+ Object.defineProperty(o, k2, desc);
91734
+ }) : (function(o, m, k, k2) {
91735
+ if (k2 === undefined) k2 = k;
91736
+ o[k2] = m[k];
91737
+ }));
91738
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
91739
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
91740
+ }) : function(o, v) {
91741
+ o["default"] = v;
91742
+ });
91743
+ var __importStar = (this && this.__importStar) || (function () {
91744
+ var ownKeys = function(o) {
91745
+ ownKeys = Object.getOwnPropertyNames || function (o) {
91746
+ var ar = [];
91747
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
91748
+ return ar;
91749
+ };
91750
+ return ownKeys(o);
91751
+ };
91752
+ return function (mod) {
91753
+ if (mod && mod.__esModule) return mod;
91754
+ var result = {};
91755
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
91756
+ __setModuleDefault(result, mod);
91757
+ return result;
91758
+ };
91759
+ })();
91760
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
91761
+ exports.RedundantConversion = exports.RedundantConversionConf = void 0;
91762
+ const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
91763
+ const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
91764
+ const _reference_1 = __webpack_require__(/*! ../abap/5_syntax/_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
91765
+ const constant_1 = __webpack_require__(/*! ../abap/5_syntax/expressions/constant */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/constant.js");
91766
+ const syntax_1 = __webpack_require__(/*! ../abap/5_syntax/syntax */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/syntax.js");
91767
+ const nodes_1 = __webpack_require__(/*! ../abap/nodes */ "./node_modules/@abaplint/core/build/src/abap/nodes/index.js");
91768
+ const _typed_identifier_1 = __webpack_require__(/*! ../abap/types/_typed_identifier */ "./node_modules/@abaplint/core/build/src/abap/types/_typed_identifier.js");
91769
+ const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
91770
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
91771
+ const _abap_object_1 = __webpack_require__(/*! ../objects/_abap_object */ "./node_modules/@abaplint/core/build/src/objects/_abap_object.js");
91772
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
91773
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
91774
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
91775
+ const version_1 = __webpack_require__(/*! ../version */ "./node_modules/@abaplint/core/build/src/version.js");
91776
+ class RedundantConversionConf extends _basic_rule_config_1.BasicRuleConfig {
91777
+ }
91778
+ exports.RedundantConversionConf = RedundantConversionConf;
91779
+ class RedundantConversion {
91780
+ constructor() {
91781
+ this.conf = new RedundantConversionConf();
91782
+ }
91783
+ getMetadata() {
91784
+ return {
91785
+ key: "redundant_conversion",
91786
+ title: "Redundant Conversion",
91787
+ shortDescription: `Find redundant CONV expressions`,
91788
+ extendedInformation: `Reports CONV expressions whose operand already has the conversion's target type.`,
91789
+ tags: [_irule_1.RuleTag.Quickfix],
91790
+ badExample: `DATA text TYPE string.
91791
+ text = CONV string( text ).`,
91792
+ goodExample: `DATA text TYPE string.
91793
+ text = text.`,
91794
+ };
91795
+ }
91796
+ getConfig() {
91797
+ return this.conf;
91798
+ }
91799
+ setConfig(conf) {
91800
+ this.conf = conf;
91801
+ }
91802
+ initialize(reg) {
91803
+ this.reg = reg;
91804
+ return this;
91805
+ }
91806
+ run(obj) {
91807
+ var _a, _b;
91808
+ if (!(0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
91809
+ && !this.reg.getConfig().isOpenABAP()) {
91810
+ return [];
91811
+ }
91812
+ if (!(obj instanceof _abap_object_1.ABAPObject)) {
91813
+ return [];
91814
+ }
91815
+ const syntax = new syntax_1.SyntaxLogic(this.reg, obj).run();
91816
+ if (syntax.issues.length > 0) {
91817
+ return [];
91818
+ }
91819
+ const issues = [];
91820
+ for (const file of obj.getABAPFiles()) {
91821
+ const structure = file.getStructure();
91822
+ if (structure === undefined) {
91823
+ continue;
91824
+ }
91825
+ for (const source of structure.findAllExpressions(Expressions.Source)) {
91826
+ if (source.getFirstToken().getStr().toUpperCase() !== "CONV") {
91827
+ continue;
91828
+ }
91829
+ const typeExpression = source.findDirectExpression(Expressions.TypeNameOrInfer);
91830
+ const bodySource = (_a = source.findDirectExpression(Expressions.ConvBody)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Source);
91831
+ if (typeExpression === undefined
91832
+ || bodySource === undefined) {
91833
+ continue;
91834
+ }
91835
+ const scope = syntax.spaghetti.lookupPosition(source.getFirstToken().getStart(), file.getFilename());
91836
+ if (scope === undefined) {
91837
+ continue;
91838
+ }
91839
+ const target = (_b = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.InferredType
91840
+ && reference.position.getStart().equals(typeExpression.getFirstToken().getStart()))) === null || _b === void 0 ? void 0 : _b.resolved;
91841
+ const operandType = this.sourceType(bodySource, scope);
91842
+ if (!(target instanceof _typed_identifier_1.TypedIdentifier)) {
91843
+ continue;
91844
+ }
91845
+ const operandHasSameType = operandType !== undefined && this.sameType(target.getType(), operandType);
91846
+ const arithmeticHasSameContext = this.arithmeticUsesSameTargetType(source, bodySource, file, scope, target.getType());
91847
+ if (operandHasSameType === false && arithmeticHasSameContext === false) {
91848
+ continue;
91849
+ }
91850
+ const closingParen = source.getDirectTokens().find(token => token.getStr() === ")" && token.getStart().isAfter(bodySource.getLastToken().getStart()));
91851
+ if (closingParen === undefined) {
91852
+ continue;
91853
+ }
91854
+ const preserveParentheses = bodySource.findDirectExpression(Expressions.ArithOperator) !== undefined
91855
+ || bodySource.findDirectTokenByText("&&") !== undefined;
91856
+ // Apply the later edit first so the original positions remain valid when
91857
+ // both parts of the CONV wrapper are changed on the same line.
91858
+ const fix = edit_helper_1.EditHelper.merge(edit_helper_1.EditHelper.replaceRange(file, bodySource.getLastToken().getEnd(), closingParen.getEnd(), preserveParentheses ? ")" : ""), edit_helper_1.EditHelper.replaceRange(file, source.getFirstToken().getStart(), bodySource.getFirstToken().getStart(), preserveParentheses ? "(" : ""));
91859
+ issues.push(issue_1.Issue.atRange(file, source.getFirstToken().getStart(), closingParen.getEnd(), "Redundant CONV expression", this.getMetadata().key, this.conf.severity, fix));
91860
+ }
91861
+ }
91862
+ return issues;
91863
+ }
91864
+ arithmeticUsesSameTargetType(conversion, bodySource, file, scope, conversionType) {
91865
+ var _a, _b;
91866
+ if (bodySource.findDirectExpression(Expressions.ArithOperator) === undefined) {
91867
+ return false;
91868
+ }
91869
+ const statement = file.getStatements().find(candidate => candidate.includesToken(conversion.getFirstToken()));
91870
+ if (!((statement === null || statement === void 0 ? void 0 : statement.get()) instanceof Statements.Move)) {
91871
+ return false;
91872
+ }
91873
+ const targetToken = (_a = statement.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
91874
+ if (targetToken === undefined) {
91875
+ return false;
91876
+ }
91877
+ const assignmentTarget = (_b = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.DataWriteReference
91878
+ && reference.position.getStart().equals(targetToken.getStart()))) === null || _b === void 0 ? void 0 : _b.resolved;
91879
+ return assignmentTarget instanceof _typed_identifier_1.TypedIdentifier
91880
+ && this.sameType(conversionType, assignmentTarget.getType());
91881
+ }
91882
+ sourceType(source, scope) {
91883
+ let context;
91884
+ for (const child of source.getChildren()) {
91885
+ if (!(child instanceof nodes_1.ExpressionNode)) {
91886
+ continue;
91887
+ }
91888
+ else if (child.get() instanceof Expressions.FieldChain) {
91889
+ context = this.fieldChainType(child, scope);
91890
+ if (context === undefined) {
91891
+ return undefined;
91892
+ }
91893
+ }
91894
+ else if (child.get() instanceof Expressions.Constant) {
91895
+ context = this.infer(context, constant_1.Constant.runSyntax(child));
91896
+ }
91897
+ else if (child.get() instanceof Expressions.Source) {
91898
+ context = this.infer(context, this.sourceType(child, scope));
91899
+ }
91900
+ else if (child.get() instanceof Expressions.ArithOperator) {
91901
+ if (child.concatTokens() === "**") {
91902
+ context = new basic_1.FloatType();
91903
+ }
91904
+ }
91905
+ else {
91906
+ return undefined;
91907
+ }
91908
+ }
91909
+ if (source.findDirectTokenByText("&&")) {
91910
+ return basic_1.StringType.get();
91911
+ }
91912
+ return context;
91913
+ }
91914
+ fieldChainType(fieldChain, scope) {
91915
+ var _a;
91916
+ const operand = (_a = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.DataReadReference
91917
+ && reference.position.getStart().equals(fieldChain.getFirstToken().getStart()))) === null || _a === void 0 ? void 0 : _a.resolved;
91918
+ if (!(operand instanceof _typed_identifier_1.TypedIdentifier)) {
91919
+ return undefined;
91920
+ }
91921
+ let type = operand.getType();
91922
+ for (const child of fieldChain.getChildren()) {
91923
+ if (!(child instanceof nodes_1.ExpressionNode)
91924
+ || child.get() instanceof Expressions.SourceField) {
91925
+ continue;
91926
+ }
91927
+ else if (child.get() instanceof Expressions.ComponentName) {
91928
+ if (type instanceof basic_1.TableType) {
91929
+ type = type.getRowType();
91930
+ }
91931
+ if (!(type instanceof basic_1.StructureType)) {
91932
+ return undefined;
91933
+ }
91934
+ type = type.getComponentByName(child.concatTokens());
91935
+ }
91936
+ else {
91937
+ // Offsets, table expressions, attributes, and dereferences need more
91938
+ // context than the initial data reference provides.
91939
+ return undefined;
91940
+ }
91941
+ }
91942
+ return type;
91943
+ }
91944
+ infer(context, found) {
91945
+ if (context instanceof basic_1.FloatType && found instanceof basic_1.IntegerType) {
91946
+ return context;
91947
+ }
91948
+ else if (context instanceof basic_1.IntegerType && found instanceof basic_1.HexType) {
91949
+ return context;
91950
+ }
91951
+ else if ((context instanceof basic_1.IntegerType || context instanceof basic_1.FloatType) && (found === null || found === void 0 ? void 0 : found.isGeneric())) {
91952
+ return context;
91953
+ }
91954
+ return found;
91955
+ }
91956
+ sameType(first, second) {
91957
+ var _a, _b;
91958
+ if (first instanceof basic_1.UnknownType
91959
+ || second instanceof basic_1.UnknownType
91960
+ || first instanceof basic_1.VoidType
91961
+ || second instanceof basic_1.VoidType
91962
+ || first.isGeneric()
91963
+ || second.isGeneric()) {
91964
+ return false;
91965
+ }
91966
+ if (first.constructor !== second.constructor) {
91967
+ return false;
91968
+ }
91969
+ if (first instanceof basic_1.StructureType || first instanceof basic_1.TableType) {
91970
+ const firstName = (_a = first.getQualifiedName()) === null || _a === void 0 ? void 0 : _a.toUpperCase();
91971
+ const secondName = (_b = second.getQualifiedName()) === null || _b === void 0 ? void 0 : _b.toUpperCase();
91972
+ return firstName !== undefined && firstName === secondName;
91973
+ }
91974
+ return first.toABAP() === second.toABAP();
91975
+ }
91976
+ }
91977
+ exports.RedundantConversion = RedundantConversion;
91978
+ //# sourceMappingURL=redundant_conversion.js.map
91979
+
91980
+ /***/ },
91981
+
91317
91982
  /***/ "./node_modules/@abaplint/core/build/src/rules/release_idoc.js"
91318
91983
  /*!*********************************************************************!*\
91319
91984
  !*** ./node_modules/@abaplint/core/build/src/rules/release_idoc.js ***!
@@ -93266,7 +93931,7 @@ class SQLEscapeHostVariables extends _abap_rule_1.ABAPRule {
93266
93931
  }
93267
93932
  if (!(0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
93268
93933
  && this.reg.getConfig().getLanguageVersion() !== version_1.LanguageVersion.Cloud
93269
- && !this.reg.getConfig().getOpenABAP()) {
93934
+ && !this.reg.getConfig().isOpenABAP()) {
93270
93935
  return [];
93271
93936
  }
93272
93937
  for (const s of file.getStatements()) {
@@ -97304,7 +97969,7 @@ ENDIF.`,
97304
97969
  }
97305
97970
  const release = this.reg.getConfig().getRelease();
97306
97971
  const langVers = this.reg.getConfig().getLanguageVersion();
97307
- if (this.reg.getConfig().getOpenABAP()) {
97972
+ if (this.reg.getConfig().isOpenABAP()) {
97308
97973
  return [];
97309
97974
  }
97310
97975
  else if (!(0, version_1.releaseAtLeast)(release, version_1.Release.v740sp02) && langVers !== version_1.LanguageVersion.Cloud) {
@@ -99367,9 +100032,14 @@ abaplint:
99367
100032
  // Keeps track of source maps as generated code is added
99368
100033
  class Chunk {
99369
100034
  raw;
100035
+ // tracked incrementally so appends never re-scan the whole buffer
100036
+ lineCount;
100037
+ lastLineLength;
99370
100038
  mappings = [];
99371
100039
  constructor(str) {
99372
100040
  this.raw = "";
100041
+ this.lineCount = 1;
100042
+ this.lastLineLength = 0;
99373
100043
  this.mappings = [];
99374
100044
  if (str) {
99375
100045
  this.appendString(str);
@@ -99388,63 +100058,85 @@ class Chunk {
99388
100058
  if (append.getCode() === "") {
99389
100059
  return this;
99390
100060
  }
99391
- const lines = this.raw.split("\n");
99392
- const lineCount = lines.length;
99393
- const lastLine = lines[lines.length - 1];
99394
100061
  for (const m of append.mappings) {
99395
- // original stays the same, but adjust the generated positions
99396
- const add = m;
99397
- if (add.generated.line === 1 && this.raw.endsWith("\n") === false) {
99398
- add.generated.column += lastLine.length;
99399
- }
99400
- else {
99401
- add.generated.line += lineCount - 1;
100062
+ // deep copy so the appended chunk's mappings are never mutated,
100063
+ // otherwise appending the same chunk twice double-shifts its positions
100064
+ const add = {
100065
+ source: m.source,
100066
+ name: m.name,
100067
+ generated: { line: m.generated.line, column: m.generated.column },
100068
+ original: { line: m.original.line, column: m.original.column },
100069
+ };
100070
+ // original stays the same, but adjust the generated positions:
100071
+ // the appended content begins at the end of the current buffer, so its
100072
+ // first line continues the current last line, and every line moves down
100073
+ if (add.generated.line === 1) {
100074
+ add.generated.column += this.lastLineLength;
99402
100075
  }
100076
+ add.generated.line += this.lineCount - 1;
99403
100077
  this.mappings.push(add);
99404
100078
  }
99405
- this.raw += append.getCode();
99406
- return this;
100079
+ return this.appendString(append.getCode());
100080
+ }
100081
+ originalPosition(pos) {
100082
+ if (pos instanceof abaplint.Position || pos instanceof abaplint.Token) {
100083
+ return { line: pos.getRow(), column: pos.getCol() - 1 };
100084
+ }
100085
+ else {
100086
+ return { line: pos.getFirstToken().getRow(), column: pos.getFirstToken().getCol() - 1 };
100087
+ }
99407
100088
  }
99408
100089
  append(input, pos, traversal) {
99409
100090
  if (input === "") {
99410
100091
  return this;
99411
100092
  }
99412
100093
  if (pos && input !== "\n") {
99413
- const lines = this.raw.split("\n");
99414
- const lastLine = lines[lines.length - 1];
99415
- let originalLine = 0;
99416
- let originalColumn = 0;
99417
- if (pos instanceof abaplint.Position || pos instanceof abaplint.Token) {
99418
- originalLine = pos.getRow();
99419
- originalColumn = pos.getCol() - 1;
99420
- }
99421
- else {
99422
- originalLine = pos.getFirstToken().getRow();
99423
- originalColumn = pos.getFirstToken().getCol() - 1;
99424
- }
99425
100094
  this.mappings.push({
99426
100095
  source: traversal.getFilename(),
99427
100096
  generated: {
99428
- line: lines.length,
99429
- column: lastLine.length,
99430
- },
99431
- original: {
99432
- line: originalLine,
99433
- column: originalColumn,
100097
+ line: this.lineCount,
100098
+ column: this.lastLineLength,
99434
100099
  },
100100
+ original: this.originalPosition(pos),
99435
100101
  });
99436
100102
  }
99437
- this.raw += input;
100103
+ return this.appendString(input);
100104
+ }
100105
+ /**
100106
+ * Baseline fallback so statements whose transpiler emitted no mappings still
100107
+ * resolve to their ABAP source. Adds a single mapping from the start of this
100108
+ * chunk (generated line 1, column 0) to `pos`. No-op if the chunk is empty or
100109
+ * already carries mappings, so it never overrides finer-grained mappings.
100110
+ */
100111
+ ensureStartMapping(pos, traversal) {
100112
+ if (this.raw === "" || this.mappings.length > 0) {
100113
+ return this;
100114
+ }
100115
+ this.mappings.push({
100116
+ source: traversal.getFilename(),
100117
+ generated: { line: 1, column: 0 },
100118
+ original: this.originalPosition(pos),
100119
+ });
99438
100120
  return this;
99439
100121
  }
99440
100122
  appendString(input) {
99441
100123
  this.raw += input;
100124
+ const lastNewline = input.lastIndexOf("\n");
100125
+ if (lastNewline < 0) {
100126
+ this.lastLineLength += input.length;
100127
+ }
100128
+ else {
100129
+ this.lineCount += input.split("\n").length - 1;
100130
+ this.lastLineLength = input.length - lastNewline - 1;
100131
+ }
99442
100132
  return this;
99443
100133
  }
99444
100134
  stripLastNewline() {
99445
100135
  // note: this will not change the source map
99446
100136
  if (this.raw.endsWith("\n")) {
99447
100137
  this.raw = this.raw.substring(0, this.raw.length - 1);
100138
+ this.lineCount--;
100139
+ this.lastLineLength = this.raw.length - this.raw.lastIndexOf("\n") - 1;
99448
100140
  }
99449
100141
  }
99450
100142
  getCode() {
@@ -99464,16 +100156,18 @@ class Chunk {
99464
100156
  if (l.startsWith("}")) {
99465
100157
  i = i - 1;
99466
100158
  }
99467
- if (i > 0) {
99468
- output.push(" ".repeat(i * 2) + l);
100159
+ // clamp so unbalanced braces never produce a negative indent/shift
100160
+ const indent = i > 0 ? i * 2 : 0;
100161
+ if (indent > 0) {
100162
+ output.push(" ".repeat(indent) + l);
99469
100163
  }
99470
100164
  else {
99471
100165
  output.push(l);
99472
100166
  }
99473
- // fix maps
100167
+ // fix maps: shift columns by the indentation actually applied to this line
99474
100168
  for (const m of this.mappings) {
99475
100169
  if (m.generated.line === line) {
99476
- m.generated.column += i * 2;
100170
+ m.generated.column += indent;
99477
100171
  }
99478
100172
  }
99479
100173
  if (l.endsWith(" {")) {
@@ -99482,11 +100176,28 @@ class Chunk {
99482
100176
  line++;
99483
100177
  }
99484
100178
  this.raw = output.join("\n");
100179
+ // line structure is unchanged, but the last line may have been indented
100180
+ this.lastLineLength = output[output.length - 1].length;
99485
100181
  return this;
99486
100182
  }
99487
- getMap(generatedFilename) {
100183
+ /**
100184
+ * @param generatedFilename name written to the "file" field of the map
100185
+ * @param options.generatedLineOffset number of lines prepended to the generated
100186
+ * output after this chunk was built (e.g. a runtime import line); every mapping
100187
+ * is shifted down by this amount so the map stays aligned with the file on disk
100188
+ * @param options.sourcePaths maps a mapping "source" (the bare abap filename) to
100189
+ * the path that should appear in the map, avoiding fragile post-hoc string edits
100190
+ */
100191
+ getMap(generatedFilename, options) {
100192
+ const offset = options?.generatedLineOffset ?? 0;
100193
+ const sourcePaths = options?.sourcePaths ?? {};
99488
100194
  const sourceMapGenerator = new sourceMap.SourceMapGenerator();
99489
- this.mappings.forEach(m => sourceMapGenerator.addMapping(m));
100195
+ this.mappings.forEach(m => sourceMapGenerator.addMapping({
100196
+ source: sourcePaths[m.source] ?? m.source,
100197
+ name: m.name,
100198
+ original: m.original,
100199
+ generated: { line: m.generated.line + offset, column: m.generated.column },
100200
+ }));
99490
100201
  const json = sourceMapGenerator.toJSON();
99491
100202
  json.file = generatedFilename;
99492
100203
  json.sourceRoot = "";
@@ -102988,6 +103699,7 @@ exports.ReceiveParametersTranspiler = ReceiveParametersTranspiler;
102988
103699
  Object.defineProperty(exports, "__esModule", ({ value: true }));
102989
103700
  exports.ReduceBodyTranspiler = void 0;
102990
103701
  const core_1 = __webpack_require__(/*! @abaplint/core */ "./node_modules/@abaplint/core/build/src/index.js");
103702
+ const traversal_1 = __webpack_require__(/*! ../traversal */ "./node_modules/@abaplint/transpiler/build/src/traversal.js");
102991
103703
  const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
102992
103704
  const transpile_types_1 = __webpack_require__(/*! ../transpile_types */ "./node_modules/@abaplint/transpiler/build/src/transpile_types.js");
102993
103705
  const target_1 = __webpack_require__(/*! ./target */ "./node_modules/@abaplint/transpiler/build/src/expressions/target.js");
@@ -103007,10 +103719,14 @@ class ReduceBodyTranspiler {
103007
103719
  else if (forExpressions.length > 1) {
103008
103720
  throw new Error("ReduceBodyTranspiler, multiple FOR not supported, " + body.concatTokens());
103009
103721
  }
103010
- else if (["THEN", "UNTIL", "WHILE", "FROM", "TO", "GROUPS"].some(token => forExpressions[0].findDirectTokenByText(token))) {
103722
+ const loopExpression = forExpression.findDirectExpression(core_1.Expressions.InlineLoopDefinition);
103723
+ if (loopExpression === undefined) {
103724
+ // index based FOR, eg. "FOR i = 1 WHILE i <= 5"
103725
+ return this.transpileIndex(body, forExpression, traversal);
103726
+ }
103727
+ else if (["THEN", "UNTIL", "WHILE", "FROM", "TO", "GROUPS"].some(token => forExpression.findDirectTokenByText(token))) {
103011
103728
  throw new Error("ValueBody FOR todo, " + body.concatTokens());
103012
103729
  }
103013
- const loopExpression = forExpression.findDirectExpression(core_1.Expressions.InlineLoopDefinition);
103014
103730
  const loopSource = traversal.traverse(loopExpression?.findDirectExpression(core_1.Expressions.Source)).getCode();
103015
103731
  const loopVariable = traversal.traverse(loopExpression?.findDirectExpression(core_1.Expressions.TargetField)
103016
103732
  || loopExpression?.findDirectExpression(core_1.Expressions.TargetFieldSymbol)).getCode();
@@ -103028,6 +103744,75 @@ class ReduceBodyTranspiler {
103028
103744
  const returnId = UniqueIdentifier.get();
103029
103745
  ret.appendString(`const ${returnId} = ${target};\n`);
103030
103746
  */
103747
+ const returnField = this.declareInit(body, traversal, ret);
103748
+ ret.appendString(`for await (const ${loopVariable} of abap.statements.loop(${loopSource}${loopWhere})) {\n`);
103749
+ ret.appendString(this.transpileNext(body, traversal));
103750
+ ret.appendString(`}\n`);
103751
+ ret.appendString(`return ${returnField};\n`);
103752
+ ret.appendString("})())");
103753
+ return ret;
103754
+ }
103755
+ transpileIndex(body, forExpression, traversal) {
103756
+ if (["FROM", "TO", "GROUPS"].some(token => forExpression.findDirectTokenByText(token))) {
103757
+ throw new Error("ValueBody FOR todo, " + body.concatTokens());
103758
+ }
103759
+ const counter = forExpression.findDirectExpression(core_1.Expressions.InlineFieldDefinition);
103760
+ if (counter === undefined) {
103761
+ throw new Error("ValueBody FOR todo, " + body.concatTokens());
103762
+ }
103763
+ const cond = forExpression.findDirectExpression(core_1.Expressions.Cond);
103764
+ if (cond === undefined) {
103765
+ throw new Error("ValueBody FOR missing condition, " + body.concatTokens());
103766
+ }
103767
+ const hasUntil = forExpression.findDirectTokenByText("UNTIL") !== undefined;
103768
+ const hasWhile = forExpression.findDirectTokenByText("WHILE") !== undefined;
103769
+ if ((hasUntil ? 1 : 0) + (hasWhile ? 1 : 0) !== 1) {
103770
+ throw new Error("ValueBody FOR todo, condition, " + body.concatTokens());
103771
+ }
103772
+ const fieldName = counter.findDirectExpression(core_1.Expressions.Field)?.concatTokens().toLowerCase();
103773
+ if (fieldName === undefined) {
103774
+ throw new Error("ValueBody FOR todo, inline field, " + body.concatTokens());
103775
+ }
103776
+ const scope = traversal.findCurrentScopeByToken(counter.getFirstToken());
103777
+ const variable = scope?.findVariable(fieldName);
103778
+ if (variable === undefined) {
103779
+ throw new Error("ValueBody FOR todo, variable, " + body.concatTokens());
103780
+ }
103781
+ const counterName = traversal_1.Traversal.prefixVariable(fieldName);
103782
+ const startSource = counter.findDirectExpression(core_1.Expressions.Source);
103783
+ if (startSource === undefined) {
103784
+ throw new Error("ValueBody FOR missing initial value, " + body.concatTokens());
103785
+ }
103786
+ const start = traversal.traverse(startSource).getCode();
103787
+ const thenExpr = forExpression.findExpressionAfterToken("THEN");
103788
+ let incrementExpression = "";
103789
+ if (thenExpr && thenExpr instanceof core_1.Nodes.ExpressionNode) {
103790
+ incrementExpression = traversal.traverse(thenExpr).getCode();
103791
+ }
103792
+ else {
103793
+ incrementExpression = `abap.operators.add(${counterName}, new abap.types.Integer().set(1))`;
103794
+ }
103795
+ const condCode = traversal.traverse(cond).getCode();
103796
+ const ret = new chunk_1.Chunk();
103797
+ ret.appendString("(await (async () => {\n");
103798
+ const returnField = this.declareInit(body, traversal, ret);
103799
+ ret.appendString(transpile_types_1.TranspileTypes.declare(variable) + `\n`);
103800
+ ret.appendString(`${counterName}.set(${start});\n`);
103801
+ ret.appendString(`while (true) {\n`);
103802
+ if (hasWhile) {
103803
+ ret.appendString(`if (!(${condCode})) {\nbreak;\n}\n`);
103804
+ }
103805
+ ret.appendString(this.transpileNext(body, traversal));
103806
+ ret.appendString(`${counterName}.set(${incrementExpression});\n`);
103807
+ if (hasUntil) {
103808
+ ret.appendString(`if (${condCode}) {\nbreak;\n}\n`);
103809
+ }
103810
+ ret.appendString(`}\n`);
103811
+ ret.appendString(`return ${returnField};\n`);
103812
+ ret.appendString("})())");
103813
+ return ret;
103814
+ }
103815
+ declareInit(body, traversal, ret) {
103031
103816
  let returnField = "";
103032
103817
  for (const init of body.findDirectExpressions(core_1.Expressions.InlineFieldDefinition)) {
103033
103818
  const fieldName = init.findDirectExpression(core_1.Expressions.Field).concatTokens().toLowerCase();
@@ -103039,18 +103824,18 @@ class ReduceBodyTranspiler {
103039
103824
  }
103040
103825
  ret.appendString(transpile_types_1.TranspileTypes.declare(variable) + `\n`);
103041
103826
  }
103042
- ret.appendString(`for await (const ${loopVariable} of abap.statements.loop(${loopSource}${loopWhere})) {\n`);
103827
+ return returnField;
103828
+ }
103829
+ transpileNext(body, traversal) {
103830
+ let ret = "";
103043
103831
  for (const nextChild of body.findDirectExpression(core_1.Expressions.ReduceNext)?.getChildren() || []) {
103044
103832
  if (nextChild.get() instanceof core_1.Expressions.SimpleTarget && nextChild instanceof core_1.Nodes.ExpressionNode) {
103045
- ret.appendString(new target_1.TargetTranspiler().transpile(nextChild, traversal).getCode() + ".set(");
103833
+ ret += new target_1.TargetTranspiler().transpile(nextChild, traversal).getCode() + ".set(";
103046
103834
  }
103047
103835
  else if (nextChild.get() instanceof core_1.Expressions.Source && nextChild instanceof core_1.Nodes.ExpressionNode) {
103048
- ret.appendString(traversal.traverse(nextChild).getCode() + ");\n");
103836
+ ret += traversal.traverse(nextChild).getCode() + ");\n";
103049
103837
  }
103050
103838
  }
103051
- ret.appendString(`}\n`);
103052
- ret.appendString(`return ${returnField};\n`);
103053
- ret.appendString("})())");
103054
103839
  return ret;
103055
103840
  }
103056
103841
  }
@@ -104874,6 +105659,9 @@ class SwitchBodyTranspiler {
104874
105659
  else if (c.concatTokens() === "THEN") {
104875
105660
  mode = "THEN";
104876
105661
  }
105662
+ else if (c.concatTokens() === "ELSE") {
105663
+ mode = "";
105664
+ }
104877
105665
  }
104878
105666
  else if (mode === "WHEN" && c instanceof core_1.Nodes.ExpressionNode) {
104879
105667
  currentWhenThen.whenOr.push(c);
@@ -105270,6 +106058,7 @@ class ValueBodyTranspiler {
105270
106058
  }
105271
106059
  let post = "";
105272
106060
  let extraFields = "";
106061
+ let baseCode = undefined;
105273
106062
  const hasLines = body.findDirectExpression(core_1.Expressions.ValueBodyLine) !== undefined;
105274
106063
  const children = body.getChildren();
105275
106064
  for (let i = 0; i < children.length; i++) {
@@ -105285,7 +106074,8 @@ class ValueBodyTranspiler {
105285
106074
  }
105286
106075
  else if (child.get() instanceof core_1.Expressions.ValueBase && child instanceof core_1.Nodes.ExpressionNode) {
105287
106076
  const source = traversal.traverse(child.findDirectExpression(core_1.Expressions.Source));
105288
- ret = new chunk_1.Chunk().appendString(source.getCode() + ".clone()");
106077
+ baseCode = source.getCode() + ".clone()";
106078
+ ret = new chunk_1.Chunk().appendString(baseCode);
105289
106079
  }
105290
106080
  else if (child.get() instanceof core_1.Expressions.ValueBodyLine && child instanceof core_1.Nodes.ExpressionNode) {
105291
106081
  if (!(context instanceof core_1.BasicTypes.TableType)) {
@@ -105312,7 +106102,7 @@ class ValueBodyTranspiler {
105312
106102
  }
105313
106103
  }
105314
106104
  i = idx - 1;
105315
- const result = this.buildForChain(forNodes, typ, traversal, body);
106105
+ const result = this.buildForChain(forNodes, typ, traversal, body, baseCode);
105316
106106
  ret = result.chunk;
105317
106107
  post = result.post;
105318
106108
  }
@@ -105323,6 +106113,8 @@ class ValueBodyTranspiler {
105323
106113
  const pre = `(await (async () => { try { return `;
105324
106114
  ret = new chunk_1.Chunk().appendString(pre + ret.getCode());
105325
106115
  post += `; } catch (error) { if (abap.isLineNotFound(error)) { return ${deflt}; } throw error; } })())`;
106116
+ // the default value Source is part of this DEFAULT handling, stop processing further children
106117
+ break;
105326
106118
  }
105327
106119
  else if (child instanceof core_1.Nodes.TokenNode && child.getFirstToken().getStr().toUpperCase() === "OPTIONAL") {
105328
106120
  // note: this is last in the body, so its okay to prepend and postpend
@@ -105336,8 +106128,8 @@ class ValueBodyTranspiler {
105336
106128
  }
105337
106129
  return ret.appendString(post);
105338
106130
  }
105339
- buildForChain(forNodes, typ, traversal, body) {
105340
- const val = new type_name_or_infer_1.TypeNameOrInfer().transpile(typ, traversal).getCode();
106131
+ buildForChain(forNodes, typ, traversal, body, baseCode) {
106132
+ const val = baseCode ?? new type_name_or_infer_1.TypeNameOrInfer().transpile(typ, traversal).getCode();
105341
106133
  const chunk = new chunk_1.Chunk();
105342
106134
  const preLoopDecls = [];
105343
106135
  const descriptors = [];
@@ -105953,8 +106745,11 @@ class HandleFUGR {
105953
106745
  const contents = new traversal_1.Traversal(spaghetti, file, obj, reg, this.options).traverse(rearranged);
105954
106746
  chunk.appendChunk(contents);
105955
106747
  chunk.stripLastNewline();
105956
- chunk.runIndentationLogic(this.options?.ignoreSourceMap);
105957
106748
  }
106749
+ // indentation must run once over the accumulated chunk: running it per
106750
+ // appended file re-indents the earlier files, drifting the brace counter
106751
+ // and shifting their mapping columns multiple times
106752
+ chunk.runIndentationLogic(this.options?.ignoreSourceMap);
105958
106753
  chunk.appendString("\n}");
105959
106754
  const output = {
105960
106755
  object: {
@@ -108585,17 +109380,14 @@ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/tr
108585
109380
  class ClearTranspiler {
108586
109381
  transpile(node, traversal) {
108587
109382
  const target = traversal.traverse(node.findDirectExpression(abaplint.Expressions.Target));
109383
+ // Reference implementation for the source-map convention:
109384
+ // - keep the target's own expression-level mappings by appending its Chunk
109385
+ // (do NOT flatten with target.getCode(), that discards the mappings)
109386
+ // - map the trailing generated syntax to the statement's last token, not
109387
+ // getEnd() which points one column past the statement
108588
109388
  const ret = new chunk_1.Chunk();
108589
- /*
108590
109389
  ret.appendChunk(target);
108591
- ret.append(".clear();", node.getLastToken().getEnd(), traversal);
108592
- */
108593
- ret.append(target.getCode() + ".clear();", node.getLastToken().getEnd(), traversal);
108594
- // ret.append(target.getCode() + ".clear();", node, traversal);
108595
- /*
108596
- ret.append(target.getCode(), node.getFirstToken().getStart(), traversal);
108597
- ret.append(".clear();", node.getLastToken().getEnd(), traversal);
108598
- */
109390
+ ret.append(".clear();", node.getLastToken(), traversal);
108599
109391
  return ret;
108600
109392
  }
108601
109393
  }
@@ -108905,6 +109697,9 @@ class ConcatenateTranspiler {
108905
109697
  if (concat.includes(" RESPECTING BLANKS")) {
108906
109698
  extra += ", respectingBlanks: true";
108907
109699
  }
109700
+ if (concat.includes(" IN BYTE MODE")) {
109701
+ extra += ", byteMode: true";
109702
+ }
108908
109703
  const target = traversal.traverse(node.findDirectExpression(abaplint.Expressions.Target));
108909
109704
  return new chunk_1.Chunk()
108910
109705
  .append("abap.statements.concatenate({source: [", node, traversal)
@@ -112000,8 +112795,11 @@ class LoopTranspiler {
112000
112795
  const source = traversal.traverse(loopSource).getCode();
112001
112796
  this.unique = unique_identifier_1.UniqueIdentifier.get();
112002
112797
  let target = "";
112798
+ // the abap expression the target-assignment line should map back to
112799
+ let targetNode = undefined;
112003
112800
  const into = this.determineInto(node);
112004
112801
  if (into && this.skipInto !== true) {
112802
+ targetNode = into;
112005
112803
  const concat = node.concatTokens().toUpperCase();
112006
112804
  const t = traversal.traverse(into).getCode();
112007
112805
  const scope = traversal.findCurrentScopeByToken(node.getFirstToken());
@@ -112021,6 +112819,7 @@ class LoopTranspiler {
112021
112819
  else if (this.skipInto !== true) {
112022
112820
  const assigning = node.findFirstExpression(abaplint.Expressions.FSTarget)?.findFirstExpression(abaplint.Expressions.FieldSymbol);
112023
112821
  if (assigning) {
112822
+ targetNode = assigning;
112024
112823
  target = traversal.traverse(assigning).getCode() + ".assign(" + this.unique + ");";
112025
112824
  }
112026
112825
  }
@@ -112101,7 +112900,15 @@ class LoopTranspiler {
112101
112900
  if (extra.length > 0) {
112102
112901
  concat = ",{" + extra.join(",") + "}";
112103
112902
  }
112104
- return new chunk_1.Chunk(`for await (const ${this.unique} of abap.statements.loop(${source}${concat})) {\n${target}`);
112903
+ // map the loop head to the statement start and the target-assignment line
112904
+ // (foo.set(unique)) back to the INTO/ASSIGNING target expression
112905
+ const ret = new chunk_1.Chunk();
112906
+ ret.append(`for await (const ${this.unique} of abap.statements.loop(${source}${concat})) {`, node, traversal);
112907
+ ret.appendString("\n");
112908
+ if (target !== "") {
112909
+ ret.append(target, targetNode ?? node, traversal);
112910
+ }
112911
+ return ret;
112105
112912
  }
112106
112913
  }
112107
112914
  exports.LoopTranspiler = LoopTranspiler;
@@ -114106,7 +114913,6 @@ exports.ReturnTranspiler = void 0;
114106
114913
  const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_modules/@abaplint/core/build/src/index.js"));
114107
114914
  const traversal_1 = __webpack_require__(/*! ../traversal */ "./node_modules/@abaplint/transpiler/build/src/traversal.js");
114108
114915
  const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
114109
- const unique_identifier_1 = __webpack_require__(/*! ../unique_identifier */ "./node_modules/@abaplint/transpiler/build/src/unique_identifier.js");
114110
114916
  class ReturnTranspiler {
114111
114917
  transpile(node, traversal) {
114112
114918
  const source = node.findDirectExpression(abaplint.Expressions.Source);
@@ -114120,8 +114926,9 @@ class ReturnTranspiler {
114120
114926
  }
114121
114927
  }
114122
114928
  let pre = "";
114123
- if (traversal.isInsideDoOrWhile(node)) {
114124
- pre = `abap.builtin.sy.get().index.set(${unique_identifier_1.UniqueIdentifier.getIndexBackup1()});\n`;
114929
+ const syIndexBackup = traversal.findCurrentDoOrWhileIndexBackup(node);
114930
+ if (syIndexBackup !== undefined) {
114931
+ pre = `abap.builtin.sy.get().index.set(${syIndexBackup});\n`;
114125
114932
  }
114126
114933
  if (scope?.getIdentifier().stype === abaplint.ScopeType.Method
114127
114934
  && scope?.getIdentifier().sname.toLowerCase() === "constructor") {
@@ -116936,9 +117743,11 @@ class ConstantsTranspiler {
116936
117743
  if (name === undefined) {
116937
117744
  throw "ConstantsTranspilerName";
116938
117745
  }
116939
- let ret = new statements_1.DataTranspiler().transpile(begin, traversal).getCode() + "\n";
116940
- ret += ConstantsTranspiler.handleValues(name, node, traversal);
116941
- return new chunk_1.Chunk(ret);
117746
+ const ret = new chunk_1.Chunk();
117747
+ ret.appendChunk(new statements_1.DataTranspiler().transpile(begin, traversal).ensureStartMapping(begin, traversal));
117748
+ ret.appendString("\n");
117749
+ ret.appendString(ConstantsTranspiler.handleValues(name, node, traversal));
117750
+ return ret;
116942
117751
  }
116943
117752
  static handleValues(prefix, node, traversal) {
116944
117753
  let ret = "";
@@ -117014,7 +117823,7 @@ class DataTranspiler {
117014
117823
  return new chunk_1.Chunk("");
117015
117824
  }
117016
117825
  const topName = begin.findDirectExpression(abaplint.Expressions.DefinitionName)?.concatTokens().toLowerCase();
117017
- const chunk = new statements_1.DataTranspiler().transpile(begin, traversal);
117826
+ const chunk = new statements_1.DataTranspiler().transpile(begin, traversal).ensureStartMapping(begin, traversal);
117018
117827
  for (const d of node.findDirectStatements(abaplint.Statements.Data)) {
117019
117828
  const subName = d.findFirstExpression(abaplint.Expressions.DefinitionName)?.concatTokens().toLowerCase();
117020
117829
  if (subName && topName) {
@@ -117105,7 +117914,8 @@ class DoTranspiler {
117105
117914
  const syIndexBackup = unique_identifier_1.UniqueIdentifier.getIndexBackup();
117106
117915
  for (const c of node.getChildren()) {
117107
117916
  if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.Do) {
117108
- ret.appendChunk(new statements_1.DoTranspiler(syIndexBackup).transpile(c, traversal));
117917
+ traversal.registerDoOrWhileIndexBackup(c, syIndexBackup);
117918
+ ret.appendChunk(new statements_1.DoTranspiler(syIndexBackup).transpile(c, traversal).ensureStartMapping(c, traversal));
117109
117919
  ret.appendString("\n");
117110
117920
  }
117111
117921
  else if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.EndDo) {
@@ -117242,7 +118052,7 @@ const transpile_types_1 = __webpack_require__(/*! ../transpile_types */ "./node_
117242
118052
  const unique_identifier_1 = __webpack_require__(/*! ../unique_identifier */ "./node_modules/@abaplint/transpiler/build/src/unique_identifier.js");
117243
118053
  class FunctionModuleTranspiler {
117244
118054
  transpile(node, traversal) {
117245
- let r = "";
118055
+ const chunk = new chunk_1.Chunk();
117246
118056
  let name = "";
117247
118057
  for (const c of node.getChildren()) {
117248
118058
  if (c.get() instanceof abaplint.Statements.FunctionModule && c instanceof abaplint.Nodes.StatementNode) {
@@ -117250,19 +118060,19 @@ class FunctionModuleTranspiler {
117250
118060
  if (name === undefined) {
117251
118061
  name = "FunctionModuleTranspilerNameNotFound";
117252
118062
  }
117253
- r += `async function ${traversal_1.Traversal.escapeNamespace(name)}(INPUT) {\n`;
117254
- r += this.findSignature(traversal, name, c);
118063
+ chunk.append(`async function ${traversal_1.Traversal.escapeNamespace(name)}(INPUT) {\n`, c, traversal);
118064
+ chunk.appendString(this.findSignature(traversal, name, c));
117255
118065
  }
117256
118066
  else if (c.get() instanceof abaplint.Statements.EndFunction) {
117257
- r += "}\n";
117258
- r += `abap.FunctionModules['${name.toUpperCase()}'] = ${traversal_1.Traversal.escapeNamespace(name)};\n`;
118067
+ chunk.append("}\n", c, traversal);
118068
+ chunk.appendString(`abap.FunctionModules['${name.toUpperCase()}'] = ${traversal_1.Traversal.escapeNamespace(name)};\n`);
117259
118069
  }
117260
118070
  else {
117261
- r += traversal.traverse(c).getCode();
118071
+ chunk.appendChunk(traversal.traverse(c));
117262
118072
  }
117263
118073
  }
117264
118074
  unique_identifier_1.UniqueIdentifier.resetIndexBackup();
117265
- return new chunk_1.Chunk(r);
118075
+ return chunk;
117266
118076
  }
117267
118077
  //////////////////////
117268
118078
  findSignature(traversal, name, node) {
@@ -117591,6 +118401,7 @@ class LoopTranspiler {
117591
118401
  ret.appendString(`let ${tabix} = undefined;\n`);
117592
118402
  }
117593
118403
  const loop = new statements_1.LoopTranspiler();
118404
+ // LoopStatementTranspiler maps its own head, so no ensureStartMapping needed here
117594
118405
  ret.appendChunk(loop.transpile(c, traversal));
117595
118406
  ret.appendString("\n");
117596
118407
  if (hasAt === true) {
@@ -117781,7 +118592,8 @@ class SelectTranspiler {
117781
118592
  const targetName = unique_identifier_1.UniqueIdentifier.get();
117782
118593
  const loopName = unique_identifier_1.UniqueIdentifier.get();
117783
118594
  ret.appendString(`let ${targetName} = new abap.types.Table(abap.DDIC["${from}"].type());\n`);
117784
- ret.appendChunk(new select_1.SelectTranspiler().transpile(selectStatement, traversal, targetName));
118595
+ const selectHead = new select_1.SelectTranspiler().transpile(selectStatement, traversal, targetName);
118596
+ ret.appendChunk(selectHead.ensureStartMapping(selectStatement, traversal));
117785
118597
  // todo: optimize, it should do real streaming?
117786
118598
  const packageSize = selectStatement.findFirstExpression(abaplint.Expressions.SQLPackageSize)
117787
118599
  ?.findFirstExpression(abaplint.Expressions.SQLSource);
@@ -118105,7 +118917,8 @@ class WhileTranspiler {
118105
118917
  const syIndexBackup = unique_identifier_1.UniqueIdentifier.getIndexBackup();
118106
118918
  for (const c of node.getChildren()) {
118107
118919
  if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.While) {
118108
- ret.appendChunk(new statements_1.WhileTranspiler(syIndexBackup).transpile(c, traversal));
118920
+ traversal.registerDoOrWhileIndexBackup(c, syIndexBackup);
118921
+ ret.appendChunk(new statements_1.WhileTranspiler(syIndexBackup).transpile(c, traversal).ensureStartMapping(c, traversal));
118109
118922
  ret.appendString("\n");
118110
118923
  }
118111
118924
  else if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.EndWhile) {
@@ -118445,6 +119258,7 @@ class Traversal {
118445
119258
  file;
118446
119259
  obj;
118447
119260
  sqlInferredType;
119261
+ doOrWhileIndexBackups = new Map();
118448
119262
  reg;
118449
119263
  options;
118450
119264
  constructor(spaghetti, file, obj, reg, options) {
@@ -119177,12 +119991,18 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
119177
119991
  return stack.length > 0;
119178
119992
  }
119179
119993
  isInsideDoOrWhile(node) {
119994
+ return this.findCurrentDoOrWhileIndexBackup(node) !== undefined;
119995
+ }
119996
+ registerDoOrWhileIndexBackup(node, name) {
119997
+ this.doOrWhileIndexBackups.set(node, name);
119998
+ }
119999
+ findCurrentDoOrWhileIndexBackup(node) {
119180
120000
  const stack = [];
119181
120001
  for (const statement of this.getFile().getStatements()) {
119182
120002
  const get = statement.get();
119183
120003
  if (get instanceof abaplint.Statements.While
119184
120004
  || get instanceof abaplint.Statements.Do) {
119185
- stack.push(statement);
120005
+ stack.push(this.doOrWhileIndexBackups.get(statement));
119186
120006
  }
119187
120007
  else if (get instanceof abaplint.Statements.EndWhile
119188
120008
  || get instanceof abaplint.Statements.EndDo) {
@@ -119192,7 +120012,7 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
119192
120012
  break;
119193
120013
  }
119194
120014
  }
119195
- return stack.length > 0;
120015
+ return stack[stack.length - 1];
119196
120016
  }
119197
120017
  registerClassOrInterface(def) {
119198
120018
  if (def === undefined) {
@@ -119305,6 +120125,8 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
119305
120125
  if (list[search]) {
119306
120126
  const transpiler = new list[search]();
119307
120127
  const chunk = transpiler.transpile(node, this);
120128
+ // baseline: statements that emitted no mappings still resolve to their source
120129
+ chunk.ensureStartMapping(node, this);
119308
120130
  chunk.appendString("\n");
119309
120131
  return chunk;
119310
120132
  }