@abaplint/transpiler-cli 2.13.40 → 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.
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) {
@@ -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);
@@ -32888,6 +32965,7 @@ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modu
32888
32965
  const assert_error_1 = __webpack_require__(/*! ../assert_error */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/assert_error.js");
32889
32966
  const field_chain_1 = __webpack_require__(/*! ./field_chain */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/field_chain.js");
32890
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");
32891
32969
  class MethodParameters {
32892
32970
  constructor() {
32893
32971
  this.requiredParameters = undefined;
@@ -33058,7 +33136,6 @@ class MethodParameters {
33058
33136
  }
33059
33137
  }
33060
33138
  parameterListS(node, input, method) {
33061
- var _a;
33062
33139
  if (node === undefined) {
33063
33140
  return [];
33064
33141
  }
@@ -33066,14 +33143,21 @@ class MethodParameters {
33066
33143
  throw new assert_error_1.AssertError("parameterListS, unexpected node");
33067
33144
  }
33068
33145
  const ret = [];
33146
+ const supplied = new Set();
33069
33147
  for (const c of node.getChildren()) {
33070
33148
  if (!(c.get() instanceof Expressions.ParameterS) || !(c instanceof nodes_1.ExpressionNode)) {
33071
33149
  throw new assert_error_1.AssertError("parameterListS, unexpected node, child");
33072
33150
  }
33073
- const name = (_a = c.findDirectExpression(Expressions.ParameterName)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr().toUpperCase();
33074
- 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) {
33075
33154
  throw new assert_error_1.AssertError("parameterListS, no name determined");
33076
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);
33077
33161
  const source = c.findDirectExpression(Expressions.Source);
33078
33162
  if (source === undefined) {
33079
33163
  throw new assert_error_1.AssertError("parameterListS, no source found");
@@ -33091,6 +33175,7 @@ class MethodParameters {
33091
33175
  targetType = method;
33092
33176
  }
33093
33177
  let sourceType = source_1.Source.runSyntax(source, input, targetType);
33178
+ (0, _check_offset_length_1.checkOffsetLength)(source, sourceType, method, input);
33094
33179
  if (sourceType === undefined) {
33095
33180
  if (method instanceof basic_1.VoidType) {
33096
33181
  sourceType = method;
@@ -33106,7 +33191,6 @@ class MethodParameters {
33106
33191
  return ret;
33107
33192
  }
33108
33193
  parameterListT(node, input) {
33109
- var _a;
33110
33194
  if (node === undefined) {
33111
33195
  return [];
33112
33196
  }
@@ -33114,14 +33198,21 @@ class MethodParameters {
33114
33198
  throw new assert_error_1.AssertError("parameterListT, unexpected node");
33115
33199
  }
33116
33200
  const ret = [];
33201
+ const supplied = new Set();
33117
33202
  for (const c of node.getChildren()) {
33118
33203
  if (!(c.get() instanceof Expressions.ParameterT) || !(c instanceof nodes_1.ExpressionNode)) {
33119
33204
  throw new assert_error_1.AssertError("parameterListT, unexpected node, child");
33120
33205
  }
33121
- const name = (_a = c.findDirectExpression(Expressions.ParameterName)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr().toUpperCase();
33122
- 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) {
33123
33209
  throw new assert_error_1.AssertError("parameterListT, no name determined");
33124
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);
33125
33216
  const target = c.findDirectExpression(Expressions.Target);
33126
33217
  if (target === undefined) {
33127
33218
  throw new assert_error_1.AssertError("parameterListT, no target found");
@@ -34392,6 +34483,7 @@ class Source {
34392
34483
  else {
34393
34484
  this.addIfInferred(node, input, foundType);
34394
34485
  }
34486
+ this.traverseRemainingChildren(children, input);
34395
34487
  return foundType ? foundType : bodyType;
34396
34488
  }
34397
34489
  case "SWITCH":
@@ -37462,8 +37554,10 @@ const inline_data_1 = __webpack_require__(/*! ../expressions/inline_data */ "./n
37462
37554
  const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/dynamic.js");
37463
37555
  class CallTransformation {
37464
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)) || []);
37465
37559
  for (const s of node.findAllExpressions(Expressions.SimpleSource3)) {
37466
- source_1.Source.runSyntax(s, input);
37560
+ source_1.Source.runSyntax(s, input, undefined, resultSources.has(s));
37467
37561
  }
37468
37562
  for (const d of node.findAllExpressions(Expressions.Dynamic)) {
37469
37563
  dynamic_1.Dynamic.runSyntax(d, input);
@@ -37650,6 +37744,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "./node_modules/@ab
37650
37744
  const target_1 = __webpack_require__(/*! ../expressions/target */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/target.js");
37651
37745
  const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
37652
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");
37653
37748
  class Catch {
37654
37749
  runSyntax(node, input) {
37655
37750
  var _a, _b;
@@ -37700,7 +37795,22 @@ class Catch {
37700
37795
  }
37701
37796
  }
37702
37797
  else if (target) {
37703
- 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
+ }
37704
37814
  }
37705
37815
  }
37706
37816
  }
@@ -38421,6 +38531,11 @@ class Concatenate {
38421
38531
  runSyntax(node, input) {
38422
38532
  const byteMode = node.findDirectTokenByText("BYTE") !== undefined;
38423
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
+ }
38424
38539
  const target = node.findFirstExpression(Expressions.Target);
38425
38540
  const inline = target === null || target === void 0 ? void 0 : target.findDirectExpression(Expressions.InlineData);
38426
38541
  if (inline) {
@@ -54019,7 +54134,7 @@ class CDSDefineAbstract extends combi_1.Expression {
54019
54134
  getRunnable() {
54020
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, ";");
54021
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), ";");
54022
- 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)(";"));
54023
54138
  }
54024
54139
  }
54025
54140
  exports.CDSDefineAbstract = CDSDefineAbstract;
@@ -54045,7 +54160,7 @@ class CDSDefineCustom extends combi_1.Expression {
54045
54160
  getRunnable() {
54046
54161
  const field = (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.str)("KEY")), cds_name_1.CDSName, ":", cds_type_1.CDSType, ";");
54047
54162
  const compsiOrAssoci = (0, combi_1.seq)(cds_name_1.CDSName, ":", (0, combi_1.alt)(_1.CDSComposition, _1.CDSAssociation), ";");
54048
- 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)(";"));
54049
54164
  }
54050
54165
  }
54051
54166
  exports.CDSDefineCustom = CDSDefineCustom;
@@ -54075,7 +54190,7 @@ class CDSDefineExternalEntity extends combi_1.Expression {
54075
54190
  const body = (0, combi_1.plus)((0, combi_1.alt)(field, assocOrComp));
54076
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));
54077
54192
  const staticEntity = (0, combi_1.seq)("STATIC", "ENTITY", _1.CDSName, (0, combi_1.opt)(externalName));
54078
- 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)(";"));
54079
54194
  }
54080
54195
  }
54081
54196
  exports.CDSDefineExternalEntity = CDSDefineExternalEntity;
@@ -54107,7 +54222,7 @@ class CDSDefineHierarchy extends combi_1.Expression {
54107
54222
  const depthValue = (0, combi_1.altPrio)(_1.CDSString, _1.CDSInteger, _1.CDSPrefixedName);
54108
54223
  const loadMode = (0, combi_1.altPrio)("BULK", "INCREMENTAL", _1.CDSPrefixedName);
54109
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"))));
54110
- 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)(";"));
54111
54226
  }
54112
54227
  }
54113
54228
  exports.CDSDefineHierarchy = CDSDefineHierarchy;
@@ -54132,7 +54247,7 @@ class CDSDefineProjection extends combi_1.Expression {
54132
54247
  getRunnable() {
54133
54248
  // redefine association _Assoc redirected to [composition child | parent] Entity
54134
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);
54135
- 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)(";"));
54136
54251
  }
54137
54252
  }
54138
54253
  exports.CDSDefineProjection = CDSDefineProjection;
@@ -54161,7 +54276,7 @@ class CDSDefineTableEntity extends combi_1.Expression {
54161
54276
  const elementList = (0, combi_1.seq)(_1.CDSElement, (0, combi_1.star)((0, combi_1.seq)(",", _1.CDSElement)), (0, combi_1.opt)(","));
54162
54277
  const elements = (0, combi_1.seq)((0, combi_1.str)("{"), (0, combi_1.altPrio)("*", elementList), (0, combi_1.str)("}"));
54163
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));
54164
- 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)(";"));
54165
54280
  }
54166
54281
  }
54167
54282
  exports.CDSDefineTableEntity = CDSDefineTableEntity;
@@ -55103,7 +55218,7 @@ class Config {
55103
55218
  }
55104
55219
  return (0, version_1.versionToABAPRelease)(v);
55105
55220
  }
55106
- getOpenABAP() {
55221
+ isOpenABAP() {
55107
55222
  return this.getRelease() === version_1.Release["open-abap"];
55108
55223
  }
55109
55224
  getVersion() {
@@ -69250,7 +69365,7 @@ class Registry {
69250
69365
  }
69251
69366
  static abaplintVersion() {
69252
69367
  // magic, see build script "version.js"
69253
- return "2.119.65";
69368
+ return "2.120.2";
69254
69369
  }
69255
69370
  getDDICReferences() {
69256
69371
  return this.ddicReferences;
@@ -73953,6 +74068,270 @@ exports.ClassicExceptionsOverlap = ClassicExceptionsOverlap;
73953
74068
 
73954
74069
  /***/ },
73955
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
+
73956
74335
  /***/ "./node_modules/@abaplint/core/build/src/rules/cloud_types.js"
73957
74336
  /*!********************************************************************!*\
73958
74337
  !*** ./node_modules/@abaplint/core/build/src/rules/cloud_types.js ***!
@@ -75868,7 +76247,7 @@ Make sure to test the downported code, it might not always be completely correct
75868
76247
  initialize(reg) {
75869
76248
  this.lowReg = reg;
75870
76249
  const config = this.lowReg.getConfig();
75871
- if (config.getRelease() === version_1.Release.v702 || config.getOpenABAP()) {
76250
+ if (config.getRelease() === version_1.Release.v702 || config.isOpenABAP()) {
75872
76251
  this.initHighReg();
75873
76252
  }
75874
76253
  return this;
@@ -75901,7 +76280,7 @@ Make sure to test the downported code, it might not always be completely correct
75901
76280
  const ret = [];
75902
76281
  this.counter = 1;
75903
76282
  const config = this.lowReg.getConfig();
75904
- if (config.getRelease() !== version_1.Release.v702 && !config.getOpenABAP()) {
76283
+ if (config.getRelease() !== version_1.Release.v702 && !config.isOpenABAP()) {
75905
76284
  return ret;
75906
76285
  }
75907
76286
  else if (!(lowObj instanceof _abap_object_1.ABAPObject)) {
@@ -75995,6 +76374,18 @@ Make sure to test the downported code, it might not always be completely correct
75995
76374
  }
75996
76375
  }
75997
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
+ }
75998
76389
  }
75999
76390
  return ret;
76000
76391
  }
@@ -76238,10 +76629,14 @@ Make sure to test the downported code, it might not always be completely correct
76238
76629
  return undefined;
76239
76630
  }
76240
76631
  //////////////////////////////////////////
76241
- /** 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 */
76242
76636
  downportSQLMoveInto(low, high, lowFile, _highSyntax) {
76243
76637
  var _a;
76244
- if (!(low.get() instanceof _statement_1.Unknown)) {
76638
+ if (!(high.get() instanceof Statements.Select)
76639
+ && !(high.get() instanceof Statements.SelectLoop)) {
76245
76640
  return undefined;
76246
76641
  }
76247
76642
  // note: SQLCond is also used in JOIN(FROM) conditions
@@ -76249,6 +76644,7 @@ Make sure to test the downported code, it might not always be completely correct
76249
76644
  if (where === undefined) {
76250
76645
  return undefined;
76251
76646
  }
76647
+ // the FIELDS list sits between FROM and WHERE, wait for it to be removed first
76252
76648
  if (high.findFirstExpression(Expressions.SQLFields) !== undefined) {
76253
76649
  return undefined;
76254
76650
  }
@@ -76756,7 +77152,7 @@ ${indentation}`);
76756
77152
  outlineCatchSimple(node, lowFile) {
76757
77153
  // outlines "CATCH cx_bcs INTO DATA(lx_bcs_excep).", note that this does not need to look at types
76758
77154
  var _a, _b;
76759
- if (this.lowReg.getConfig().getOpenABAP()) {
77155
+ if (this.lowReg.getConfig().isOpenABAP()) {
76760
77156
  return undefined;
76761
77157
  }
76762
77158
  if (!(node.get() instanceof Statements.Catch)) {
@@ -76805,7 +77201,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
76805
77201
  if (!(node.get() instanceof Statements.Move)) {
76806
77202
  return undefined;
76807
77203
  }
76808
- if (this.lowReg.getConfig().getOpenABAP()) {
77204
+ if (this.lowReg.getConfig().isOpenABAP()) {
76809
77205
  return undefined;
76810
77206
  }
76811
77207
  const target = node.findFirstExpression(Expressions.Target);
@@ -76861,7 +77257,7 @@ ${indentation}CATCH ${className} INTO ${targetName}.`;
76861
77257
  return issue_1.Issue.atToken(lowFile, node.getFirstToken(), "Outline DATA", this.getMetadata().key, this.conf.severity, fix);
76862
77258
  }
76863
77259
  partiallyImplemented(node, lowFile) {
76864
- if (this.lowReg.getConfig().getOpenABAP()) {
77260
+ if (this.lowReg.getConfig().isOpenABAP()) {
76865
77261
  return undefined;
76866
77262
  }
76867
77263
  if (node.get() instanceof Statements.InterfaceDef) {
@@ -77537,7 +77933,7 @@ ${indentation} output = ${uniqueName}.\n`;
77537
77933
  if (!(node.get() instanceof Statements.Loop)) {
77538
77934
  return undefined;
77539
77935
  }
77540
- if (this.lowReg.getConfig().getOpenABAP()) {
77936
+ if (this.lowReg.getConfig().isOpenABAP()) {
77541
77937
  return undefined;
77542
77938
  }
77543
77939
  const source = (_a = node.findDirectExpression(Expressions.LoopSource)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.SimpleSource2);
@@ -78213,7 +78609,7 @@ ${indentation} output = ${uniqueName}.\n`;
78213
78609
  outlineData(node, lowFile, highSyntax) {
78214
78610
  // hmm, no guard here, as DATA(SDF) is valid in 702
78215
78611
  var _a, _b;
78216
- if (this.lowReg.getConfig().getOpenABAP()) {
78612
+ if (this.lowReg.getConfig().isOpenABAP()) {
78217
78613
  return undefined;
78218
78614
  }
78219
78615
  for (const i of node.findAllExpressionsRecursive(Expressions.InlineData)) {
@@ -78432,7 +78828,7 @@ ${indentation} output = ${uniqueName}.\n`;
78432
78828
  return false;
78433
78829
  }
78434
78830
  replaceXsdBool(node, lowFile, highSyntax) {
78435
- if (this.lowReg.getConfig().getOpenABAP()) {
78831
+ if (this.lowReg.getConfig().isOpenABAP()) {
78436
78832
  return undefined;
78437
78833
  }
78438
78834
  const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
@@ -78561,7 +78957,7 @@ ${indentation} output = ${uniqueName}.\n`;
78561
78957
  }
78562
78958
  replaceLineFunctions(node, lowFile, highSyntax, highFile) {
78563
78959
  var _a, _b;
78564
- if (this.lowReg.getConfig().getOpenABAP()) {
78960
+ if (this.lowReg.getConfig().isOpenABAP()) {
78565
78961
  return undefined;
78566
78962
  }
78567
78963
  const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());
@@ -82735,6 +83131,7 @@ __exportStar(__webpack_require__(/*! ./check_subrc */ "./node_modules/@abaplint/
82735
83131
  __exportStar(__webpack_require__(/*! ./check_syntax */ "./node_modules/@abaplint/core/build/src/rules/check_syntax.js"), exports);
82736
83132
  __exportStar(__webpack_require__(/*! ./check_text_elements */ "./node_modules/@abaplint/core/build/src/rules/check_text_elements.js"), exports);
82737
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);
82738
83135
  __exportStar(__webpack_require__(/*! ./class_attribute_names */ "./node_modules/@abaplint/core/build/src/rules/class_attribute_names.js"), exports);
82739
83136
  __exportStar(__webpack_require__(/*! ./classic_exceptions_overlap */ "./node_modules/@abaplint/core/build/src/rules/classic_exceptions_overlap.js"), exports);
82740
83137
  __exportStar(__webpack_require__(/*! ./cloud_types */ "./node_modules/@abaplint/core/build/src/rules/cloud_types.js"), exports);
@@ -82840,6 +83237,7 @@ __exportStar(__webpack_require__(/*! ./preferred_compare_operator */ "./node_mod
82840
83237
  __exportStar(__webpack_require__(/*! ./prefix_is_current_class */ "./node_modules/@abaplint/core/build/src/rules/prefix_is_current_class.js"), exports);
82841
83238
  __exportStar(__webpack_require__(/*! ./reduce_procedural_code */ "./node_modules/@abaplint/core/build/src/rules/reduce_procedural_code.js"), exports);
82842
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);
82843
83241
  __exportStar(__webpack_require__(/*! ./release_idoc */ "./node_modules/@abaplint/core/build/src/rules/release_idoc.js"), exports);
82844
83242
  __exportStar(__webpack_require__(/*! ./remove_descriptions */ "./node_modules/@abaplint/core/build/src/rules/remove_descriptions.js"), exports);
82845
83243
  __exportStar(__webpack_require__(/*! ./rfc_error_handling */ "./node_modules/@abaplint/core/build/src/rules/rfc_error_handling.js"), exports);
@@ -83045,7 +83443,7 @@ class InlineDataOldVersions extends _abap_rule_1.ABAPRule {
83045
83443
  runParsed(file) {
83046
83444
  const issues = [];
83047
83445
  if ((0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
83048
- || this.reg.getConfig().getOpenABAP()
83446
+ || this.reg.getConfig().isOpenABAP()
83049
83447
  || this.reg.getConfig().getLanguageVersion() === version_1.LanguageVersion.Cloud) {
83050
83448
  return [];
83051
83449
  }
@@ -87167,7 +87565,7 @@ Not considered optional branches:
87167
87565
  const release = this.reg.getConfig().getRelease();
87168
87566
  if (release === version_1.Release.v700
87169
87567
  || release === version_1.Release.v702
87170
- || this.reg.getConfig().getOpenABAP()) {
87568
+ || this.reg.getConfig().isOpenABAP()) {
87171
87569
  return [];
87172
87570
  }
87173
87571
  const struc = file.getStructure();
@@ -91318,6 +91716,269 @@ exports.ReduceStringTemplates = ReduceStringTemplates;
91318
91716
 
91319
91717
  /***/ },
91320
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
+
91321
91982
  /***/ "./node_modules/@abaplint/core/build/src/rules/release_idoc.js"
91322
91983
  /*!*********************************************************************!*\
91323
91984
  !*** ./node_modules/@abaplint/core/build/src/rules/release_idoc.js ***!
@@ -93270,7 +93931,7 @@ class SQLEscapeHostVariables extends _abap_rule_1.ABAPRule {
93270
93931
  }
93271
93932
  if (!(0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
93272
93933
  && this.reg.getConfig().getLanguageVersion() !== version_1.LanguageVersion.Cloud
93273
- && !this.reg.getConfig().getOpenABAP()) {
93934
+ && !this.reg.getConfig().isOpenABAP()) {
93274
93935
  return [];
93275
93936
  }
93276
93937
  for (const s of file.getStatements()) {
@@ -97308,7 +97969,7 @@ ENDIF.`,
97308
97969
  }
97309
97970
  const release = this.reg.getConfig().getRelease();
97310
97971
  const langVers = this.reg.getConfig().getLanguageVersion();
97311
- if (this.reg.getConfig().getOpenABAP()) {
97972
+ if (this.reg.getConfig().isOpenABAP()) {
97312
97973
  return [];
97313
97974
  }
97314
97975
  else if (!(0, version_1.releaseAtLeast)(release, version_1.Release.v740sp02) && langVers !== version_1.LanguageVersion.Cloud) {
@@ -99371,9 +100032,14 @@ abaplint:
99371
100032
  // Keeps track of source maps as generated code is added
99372
100033
  class Chunk {
99373
100034
  raw;
100035
+ // tracked incrementally so appends never re-scan the whole buffer
100036
+ lineCount;
100037
+ lastLineLength;
99374
100038
  mappings = [];
99375
100039
  constructor(str) {
99376
100040
  this.raw = "";
100041
+ this.lineCount = 1;
100042
+ this.lastLineLength = 0;
99377
100043
  this.mappings = [];
99378
100044
  if (str) {
99379
100045
  this.appendString(str);
@@ -99392,63 +100058,85 @@ class Chunk {
99392
100058
  if (append.getCode() === "") {
99393
100059
  return this;
99394
100060
  }
99395
- const lines = this.raw.split("\n");
99396
- const lineCount = lines.length;
99397
- const lastLine = lines[lines.length - 1];
99398
100061
  for (const m of append.mappings) {
99399
- // original stays the same, but adjust the generated positions
99400
- const add = m;
99401
- if (add.generated.line === 1 && this.raw.endsWith("\n") === false) {
99402
- add.generated.column += lastLine.length;
99403
- }
99404
- else {
99405
- 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;
99406
100075
  }
100076
+ add.generated.line += this.lineCount - 1;
99407
100077
  this.mappings.push(add);
99408
100078
  }
99409
- this.raw += append.getCode();
99410
- 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
+ }
99411
100088
  }
99412
100089
  append(input, pos, traversal) {
99413
100090
  if (input === "") {
99414
100091
  return this;
99415
100092
  }
99416
100093
  if (pos && input !== "\n") {
99417
- const lines = this.raw.split("\n");
99418
- const lastLine = lines[lines.length - 1];
99419
- let originalLine = 0;
99420
- let originalColumn = 0;
99421
- if (pos instanceof abaplint.Position || pos instanceof abaplint.Token) {
99422
- originalLine = pos.getRow();
99423
- originalColumn = pos.getCol() - 1;
99424
- }
99425
- else {
99426
- originalLine = pos.getFirstToken().getRow();
99427
- originalColumn = pos.getFirstToken().getCol() - 1;
99428
- }
99429
100094
  this.mappings.push({
99430
100095
  source: traversal.getFilename(),
99431
100096
  generated: {
99432
- line: lines.length,
99433
- column: lastLine.length,
99434
- },
99435
- original: {
99436
- line: originalLine,
99437
- column: originalColumn,
100097
+ line: this.lineCount,
100098
+ column: this.lastLineLength,
99438
100099
  },
100100
+ original: this.originalPosition(pos),
99439
100101
  });
99440
100102
  }
99441
- 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
+ });
99442
100120
  return this;
99443
100121
  }
99444
100122
  appendString(input) {
99445
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
+ }
99446
100132
  return this;
99447
100133
  }
99448
100134
  stripLastNewline() {
99449
100135
  // note: this will not change the source map
99450
100136
  if (this.raw.endsWith("\n")) {
99451
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;
99452
100140
  }
99453
100141
  }
99454
100142
  getCode() {
@@ -99468,16 +100156,18 @@ class Chunk {
99468
100156
  if (l.startsWith("}")) {
99469
100157
  i = i - 1;
99470
100158
  }
99471
- if (i > 0) {
99472
- 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);
99473
100163
  }
99474
100164
  else {
99475
100165
  output.push(l);
99476
100166
  }
99477
- // fix maps
100167
+ // fix maps: shift columns by the indentation actually applied to this line
99478
100168
  for (const m of this.mappings) {
99479
100169
  if (m.generated.line === line) {
99480
- m.generated.column += i * 2;
100170
+ m.generated.column += indent;
99481
100171
  }
99482
100172
  }
99483
100173
  if (l.endsWith(" {")) {
@@ -99486,11 +100176,28 @@ class Chunk {
99486
100176
  line++;
99487
100177
  }
99488
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;
99489
100181
  return this;
99490
100182
  }
99491
- 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 ?? {};
99492
100194
  const sourceMapGenerator = new sourceMap.SourceMapGenerator();
99493
- 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
+ }));
99494
100201
  const json = sourceMapGenerator.toJSON();
99495
100202
  json.file = generatedFilename;
99496
100203
  json.sourceRoot = "";
@@ -102992,6 +103699,7 @@ exports.ReceiveParametersTranspiler = ReceiveParametersTranspiler;
102992
103699
  Object.defineProperty(exports, "__esModule", ({ value: true }));
102993
103700
  exports.ReduceBodyTranspiler = void 0;
102994
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");
102995
103703
  const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
102996
103704
  const transpile_types_1 = __webpack_require__(/*! ../transpile_types */ "./node_modules/@abaplint/transpiler/build/src/transpile_types.js");
102997
103705
  const target_1 = __webpack_require__(/*! ./target */ "./node_modules/@abaplint/transpiler/build/src/expressions/target.js");
@@ -103011,10 +103719,14 @@ class ReduceBodyTranspiler {
103011
103719
  else if (forExpressions.length > 1) {
103012
103720
  throw new Error("ReduceBodyTranspiler, multiple FOR not supported, " + body.concatTokens());
103013
103721
  }
103014
- 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))) {
103015
103728
  throw new Error("ValueBody FOR todo, " + body.concatTokens());
103016
103729
  }
103017
- const loopExpression = forExpression.findDirectExpression(core_1.Expressions.InlineLoopDefinition);
103018
103730
  const loopSource = traversal.traverse(loopExpression?.findDirectExpression(core_1.Expressions.Source)).getCode();
103019
103731
  const loopVariable = traversal.traverse(loopExpression?.findDirectExpression(core_1.Expressions.TargetField)
103020
103732
  || loopExpression?.findDirectExpression(core_1.Expressions.TargetFieldSymbol)).getCode();
@@ -103032,6 +103744,75 @@ class ReduceBodyTranspiler {
103032
103744
  const returnId = UniqueIdentifier.get();
103033
103745
  ret.appendString(`const ${returnId} = ${target};\n`);
103034
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) {
103035
103816
  let returnField = "";
103036
103817
  for (const init of body.findDirectExpressions(core_1.Expressions.InlineFieldDefinition)) {
103037
103818
  const fieldName = init.findDirectExpression(core_1.Expressions.Field).concatTokens().toLowerCase();
@@ -103043,18 +103824,18 @@ class ReduceBodyTranspiler {
103043
103824
  }
103044
103825
  ret.appendString(transpile_types_1.TranspileTypes.declare(variable) + `\n`);
103045
103826
  }
103046
- ret.appendString(`for await (const ${loopVariable} of abap.statements.loop(${loopSource}${loopWhere})) {\n`);
103827
+ return returnField;
103828
+ }
103829
+ transpileNext(body, traversal) {
103830
+ let ret = "";
103047
103831
  for (const nextChild of body.findDirectExpression(core_1.Expressions.ReduceNext)?.getChildren() || []) {
103048
103832
  if (nextChild.get() instanceof core_1.Expressions.SimpleTarget && nextChild instanceof core_1.Nodes.ExpressionNode) {
103049
- ret.appendString(new target_1.TargetTranspiler().transpile(nextChild, traversal).getCode() + ".set(");
103833
+ ret += new target_1.TargetTranspiler().transpile(nextChild, traversal).getCode() + ".set(";
103050
103834
  }
103051
103835
  else if (nextChild.get() instanceof core_1.Expressions.Source && nextChild instanceof core_1.Nodes.ExpressionNode) {
103052
- ret.appendString(traversal.traverse(nextChild).getCode() + ");\n");
103836
+ ret += traversal.traverse(nextChild).getCode() + ");\n";
103053
103837
  }
103054
103838
  }
103055
- ret.appendString(`}\n`);
103056
- ret.appendString(`return ${returnField};\n`);
103057
- ret.appendString("})())");
103058
103839
  return ret;
103059
103840
  }
103060
103841
  }
@@ -104878,6 +105659,9 @@ class SwitchBodyTranspiler {
104878
105659
  else if (c.concatTokens() === "THEN") {
104879
105660
  mode = "THEN";
104880
105661
  }
105662
+ else if (c.concatTokens() === "ELSE") {
105663
+ mode = "";
105664
+ }
104881
105665
  }
104882
105666
  else if (mode === "WHEN" && c instanceof core_1.Nodes.ExpressionNode) {
104883
105667
  currentWhenThen.whenOr.push(c);
@@ -105274,6 +106058,7 @@ class ValueBodyTranspiler {
105274
106058
  }
105275
106059
  let post = "";
105276
106060
  let extraFields = "";
106061
+ let baseCode = undefined;
105277
106062
  const hasLines = body.findDirectExpression(core_1.Expressions.ValueBodyLine) !== undefined;
105278
106063
  const children = body.getChildren();
105279
106064
  for (let i = 0; i < children.length; i++) {
@@ -105289,7 +106074,8 @@ class ValueBodyTranspiler {
105289
106074
  }
105290
106075
  else if (child.get() instanceof core_1.Expressions.ValueBase && child instanceof core_1.Nodes.ExpressionNode) {
105291
106076
  const source = traversal.traverse(child.findDirectExpression(core_1.Expressions.Source));
105292
- ret = new chunk_1.Chunk().appendString(source.getCode() + ".clone()");
106077
+ baseCode = source.getCode() + ".clone()";
106078
+ ret = new chunk_1.Chunk().appendString(baseCode);
105293
106079
  }
105294
106080
  else if (child.get() instanceof core_1.Expressions.ValueBodyLine && child instanceof core_1.Nodes.ExpressionNode) {
105295
106081
  if (!(context instanceof core_1.BasicTypes.TableType)) {
@@ -105316,7 +106102,7 @@ class ValueBodyTranspiler {
105316
106102
  }
105317
106103
  }
105318
106104
  i = idx - 1;
105319
- const result = this.buildForChain(forNodes, typ, traversal, body);
106105
+ const result = this.buildForChain(forNodes, typ, traversal, body, baseCode);
105320
106106
  ret = result.chunk;
105321
106107
  post = result.post;
105322
106108
  }
@@ -105327,6 +106113,8 @@ class ValueBodyTranspiler {
105327
106113
  const pre = `(await (async () => { try { return `;
105328
106114
  ret = new chunk_1.Chunk().appendString(pre + ret.getCode());
105329
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;
105330
106118
  }
105331
106119
  else if (child instanceof core_1.Nodes.TokenNode && child.getFirstToken().getStr().toUpperCase() === "OPTIONAL") {
105332
106120
  // note: this is last in the body, so its okay to prepend and postpend
@@ -105340,8 +106128,8 @@ class ValueBodyTranspiler {
105340
106128
  }
105341
106129
  return ret.appendString(post);
105342
106130
  }
105343
- buildForChain(forNodes, typ, traversal, body) {
105344
- 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();
105345
106133
  const chunk = new chunk_1.Chunk();
105346
106134
  const preLoopDecls = [];
105347
106135
  const descriptors = [];
@@ -105957,8 +106745,11 @@ class HandleFUGR {
105957
106745
  const contents = new traversal_1.Traversal(spaghetti, file, obj, reg, this.options).traverse(rearranged);
105958
106746
  chunk.appendChunk(contents);
105959
106747
  chunk.stripLastNewline();
105960
- chunk.runIndentationLogic(this.options?.ignoreSourceMap);
105961
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);
105962
106753
  chunk.appendString("\n}");
105963
106754
  const output = {
105964
106755
  object: {
@@ -108589,17 +109380,14 @@ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/tr
108589
109380
  class ClearTranspiler {
108590
109381
  transpile(node, traversal) {
108591
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
108592
109388
  const ret = new chunk_1.Chunk();
108593
- /*
108594
109389
  ret.appendChunk(target);
108595
- ret.append(".clear();", node.getLastToken().getEnd(), traversal);
108596
- */
108597
- ret.append(target.getCode() + ".clear();", node.getLastToken().getEnd(), traversal);
108598
- // ret.append(target.getCode() + ".clear();", node, traversal);
108599
- /*
108600
- ret.append(target.getCode(), node.getFirstToken().getStart(), traversal);
108601
- ret.append(".clear();", node.getLastToken().getEnd(), traversal);
108602
- */
109390
+ ret.append(".clear();", node.getLastToken(), traversal);
108603
109391
  return ret;
108604
109392
  }
108605
109393
  }
@@ -112007,8 +112795,11 @@ class LoopTranspiler {
112007
112795
  const source = traversal.traverse(loopSource).getCode();
112008
112796
  this.unique = unique_identifier_1.UniqueIdentifier.get();
112009
112797
  let target = "";
112798
+ // the abap expression the target-assignment line should map back to
112799
+ let targetNode = undefined;
112010
112800
  const into = this.determineInto(node);
112011
112801
  if (into && this.skipInto !== true) {
112802
+ targetNode = into;
112012
112803
  const concat = node.concatTokens().toUpperCase();
112013
112804
  const t = traversal.traverse(into).getCode();
112014
112805
  const scope = traversal.findCurrentScopeByToken(node.getFirstToken());
@@ -112028,6 +112819,7 @@ class LoopTranspiler {
112028
112819
  else if (this.skipInto !== true) {
112029
112820
  const assigning = node.findFirstExpression(abaplint.Expressions.FSTarget)?.findFirstExpression(abaplint.Expressions.FieldSymbol);
112030
112821
  if (assigning) {
112822
+ targetNode = assigning;
112031
112823
  target = traversal.traverse(assigning).getCode() + ".assign(" + this.unique + ");";
112032
112824
  }
112033
112825
  }
@@ -112108,7 +112900,15 @@ class LoopTranspiler {
112108
112900
  if (extra.length > 0) {
112109
112901
  concat = ",{" + extra.join(",") + "}";
112110
112902
  }
112111
- 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;
112112
112912
  }
112113
112913
  }
112114
112914
  exports.LoopTranspiler = LoopTranspiler;
@@ -116943,9 +117743,11 @@ class ConstantsTranspiler {
116943
117743
  if (name === undefined) {
116944
117744
  throw "ConstantsTranspilerName";
116945
117745
  }
116946
- let ret = new statements_1.DataTranspiler().transpile(begin, traversal).getCode() + "\n";
116947
- ret += ConstantsTranspiler.handleValues(name, node, traversal);
116948
- 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;
116949
117751
  }
116950
117752
  static handleValues(prefix, node, traversal) {
116951
117753
  let ret = "";
@@ -117021,7 +117823,7 @@ class DataTranspiler {
117021
117823
  return new chunk_1.Chunk("");
117022
117824
  }
117023
117825
  const topName = begin.findDirectExpression(abaplint.Expressions.DefinitionName)?.concatTokens().toLowerCase();
117024
- const chunk = new statements_1.DataTranspiler().transpile(begin, traversal);
117826
+ const chunk = new statements_1.DataTranspiler().transpile(begin, traversal).ensureStartMapping(begin, traversal);
117025
117827
  for (const d of node.findDirectStatements(abaplint.Statements.Data)) {
117026
117828
  const subName = d.findFirstExpression(abaplint.Expressions.DefinitionName)?.concatTokens().toLowerCase();
117027
117829
  if (subName && topName) {
@@ -117113,7 +117915,7 @@ class DoTranspiler {
117113
117915
  for (const c of node.getChildren()) {
117114
117916
  if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.Do) {
117115
117917
  traversal.registerDoOrWhileIndexBackup(c, syIndexBackup);
117116
- ret.appendChunk(new statements_1.DoTranspiler(syIndexBackup).transpile(c, traversal));
117918
+ ret.appendChunk(new statements_1.DoTranspiler(syIndexBackup).transpile(c, traversal).ensureStartMapping(c, traversal));
117117
117919
  ret.appendString("\n");
117118
117920
  }
117119
117921
  else if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.EndDo) {
@@ -117250,7 +118052,7 @@ const transpile_types_1 = __webpack_require__(/*! ../transpile_types */ "./node_
117250
118052
  const unique_identifier_1 = __webpack_require__(/*! ../unique_identifier */ "./node_modules/@abaplint/transpiler/build/src/unique_identifier.js");
117251
118053
  class FunctionModuleTranspiler {
117252
118054
  transpile(node, traversal) {
117253
- let r = "";
118055
+ const chunk = new chunk_1.Chunk();
117254
118056
  let name = "";
117255
118057
  for (const c of node.getChildren()) {
117256
118058
  if (c.get() instanceof abaplint.Statements.FunctionModule && c instanceof abaplint.Nodes.StatementNode) {
@@ -117258,19 +118060,19 @@ class FunctionModuleTranspiler {
117258
118060
  if (name === undefined) {
117259
118061
  name = "FunctionModuleTranspilerNameNotFound";
117260
118062
  }
117261
- r += `async function ${traversal_1.Traversal.escapeNamespace(name)}(INPUT) {\n`;
117262
- 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));
117263
118065
  }
117264
118066
  else if (c.get() instanceof abaplint.Statements.EndFunction) {
117265
- r += "}\n";
117266
- 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`);
117267
118069
  }
117268
118070
  else {
117269
- r += traversal.traverse(c).getCode();
118071
+ chunk.appendChunk(traversal.traverse(c));
117270
118072
  }
117271
118073
  }
117272
118074
  unique_identifier_1.UniqueIdentifier.resetIndexBackup();
117273
- return new chunk_1.Chunk(r);
118075
+ return chunk;
117274
118076
  }
117275
118077
  //////////////////////
117276
118078
  findSignature(traversal, name, node) {
@@ -117599,6 +118401,7 @@ class LoopTranspiler {
117599
118401
  ret.appendString(`let ${tabix} = undefined;\n`);
117600
118402
  }
117601
118403
  const loop = new statements_1.LoopTranspiler();
118404
+ // LoopStatementTranspiler maps its own head, so no ensureStartMapping needed here
117602
118405
  ret.appendChunk(loop.transpile(c, traversal));
117603
118406
  ret.appendString("\n");
117604
118407
  if (hasAt === true) {
@@ -117789,7 +118592,8 @@ class SelectTranspiler {
117789
118592
  const targetName = unique_identifier_1.UniqueIdentifier.get();
117790
118593
  const loopName = unique_identifier_1.UniqueIdentifier.get();
117791
118594
  ret.appendString(`let ${targetName} = new abap.types.Table(abap.DDIC["${from}"].type());\n`);
117792
- 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));
117793
118597
  // todo: optimize, it should do real streaming?
117794
118598
  const packageSize = selectStatement.findFirstExpression(abaplint.Expressions.SQLPackageSize)
117795
118599
  ?.findFirstExpression(abaplint.Expressions.SQLSource);
@@ -118114,7 +118918,7 @@ class WhileTranspiler {
118114
118918
  for (const c of node.getChildren()) {
118115
118919
  if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.While) {
118116
118920
  traversal.registerDoOrWhileIndexBackup(c, syIndexBackup);
118117
- ret.appendChunk(new statements_1.WhileTranspiler(syIndexBackup).transpile(c, traversal));
118921
+ ret.appendChunk(new statements_1.WhileTranspiler(syIndexBackup).transpile(c, traversal).ensureStartMapping(c, traversal));
118118
118922
  ret.appendString("\n");
118119
118923
  }
118120
118924
  else if (c instanceof abaplint.Nodes.StatementNode && c.get() instanceof abaplint.Statements.EndWhile) {
@@ -119321,6 +120125,8 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
119321
120125
  if (list[search]) {
119322
120126
  const transpiler = new list[search]();
119323
120127
  const chunk = transpiler.transpile(node, this);
120128
+ // baseline: statements that emitted no mappings still resolve to their source
120129
+ chunk.ensureStartMapping(node, this);
119324
120130
  chunk.appendString("\n");
119325
120131
  return chunk;
119326
120132
  }