@abaplint/transpiler-cli 2.13.63 → 2.13.65

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/build/bundle.js +307 -93
  2. package/package.json +3 -3
package/build/bundle.js CHANGED
@@ -402,7 +402,12 @@ function loadPlugin() {
402
402
  }
403
403
  async function build(config, files) {
404
404
  const libFiles = await loadLib(config);
405
- const t = new Transpiler.Transpiler(config.options, loadPlugin());
405
+ const options = { ...config.options };
406
+ if (config.write_source_map !== true) {
407
+ // Do not pay to allocate and copy mappings that the CLI will not write.
408
+ options.ignoreSourceMap = true;
409
+ }
410
+ const t = new Transpiler.Transpiler(options, loadPlugin());
406
411
  const reg = new abaplint.Registry();
407
412
  for (const f of files) {
408
413
  reg.addFile(new abaplint.MemoryFile(f.filename, f.contents));
@@ -410,7 +415,6 @@ async function build(config, files) {
410
415
  for (const l of libFiles) {
411
416
  reg.addDependency(new abaplint.MemoryFile(l.filename, l.contents));
412
417
  }
413
- reg.parse();
414
418
  const output = await t.run(reg, new Progress());
415
419
  return output;
416
420
  }
@@ -9439,21 +9443,21 @@ class SQLFunction extends combi_1.Expression {
9439
9443
  const fn = (name, params, v) => {
9440
9444
  const nameReg = (0, combi_1.regex)(new RegExp("^" + name + "$", "i"));
9441
9445
  if (params === 0) {
9442
- return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), (0, combi_1.tok)(tokens_1.WParenRightW)));
9446
+ return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), (0, combi_1.tok)(tokens_1.WParenRightW)), { also: combi_1.AlsoIn.OpenABAP });
9443
9447
  }
9444
9448
  else if (params === VARIADIC) {
9445
- return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, (0, combi_1.starPrio)(commaParam), (0, combi_1.tok)(tokens_1.WParenRightW)));
9449
+ return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, (0, combi_1.starPrio)(commaParam), (0, combi_1.tok)(tokens_1.WParenRightW)), { also: combi_1.AlsoIn.OpenABAP });
9446
9450
  }
9447
9451
  else {
9448
9452
  const extra = [];
9449
9453
  for (let i = 1; i < params; i++) {
9450
9454
  extra.push(commaParam);
9451
9455
  }
9452
- return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, ...extra, (0, combi_1.tok)(tokens_1.WParenRightW)));
9456
+ return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, ...extra, (0, combi_1.tok)(tokens_1.WParenRightW)), { also: combi_1.AlsoIn.OpenABAP });
9453
9457
  }
9454
9458
  };
9455
9459
  const castInput = (0, combi_1.altPrio)(sql_case_1.SQLCase, sql_function_input_1.SQLFunctionInput);
9456
- const cast = (0, combi_1.ver)(version_1.Release.v750, (0, combi_1.seq)((0, combi_1.regex)(/^cast$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), castInput, "AS", castTypes, (0, combi_1.tok)(tokens_1.WParenRightW)));
9460
+ const cast = (0, combi_1.ver)(version_1.Release.v750, (0, combi_1.seq)((0, combi_1.regex)(/^cast$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), castInput, "AS", castTypes, (0, combi_1.tok)(tokens_1.WParenRightW)), { also: combi_1.AlsoIn.OpenABAP });
9457
9461
  const hostParen = (0, combi_1.seq)((0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, (0, combi_1.tok)(tokens_1.WParenRightW));
9458
9462
  const hostVar = (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WAt), (0, combi_1.altPrio)(simple_source3_1.SimpleSource3, hostParen));
9459
9463
  const abapOnly = (0, combi_1.altPrio)(constant_1.Constant, hostVar);
@@ -9463,7 +9467,7 @@ class SQLFunction extends combi_1.Expression {
9463
9467
  const kvs = params.map(p => (0, combi_1.seq)((0, combi_1.regex)(new RegExp("^" + p.name + "$", "i")), "=", valueFor(p)));
9464
9468
  const anyKv = kvs.length === 1 ? kvs[0] : (0, combi_1.altPrio)(kvs[0], kvs[1], ...kvs.slice(2));
9465
9469
  const body = (0, combi_1.optPrio)((0, combi_1.seq)(anyKv, (0, combi_1.starPrio)((0, combi_1.seq)(",", anyKv))));
9466
- return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), body, (0, combi_1.tok)(tokens_1.WParenRightW)));
9470
+ return (0, combi_1.ver)(v, (0, combi_1.seq)(nameReg, (0, combi_1.tok)(tokens_1.ParenLeftW), body, (0, combi_1.tok)(tokens_1.WParenRightW)), { also: combi_1.AlsoIn.OpenABAP });
9467
9471
  };
9468
9472
  return (0, combi_1.altPrio)(cast, sql_replace_regexpr_1.SQLReplaceRegexpr, sql_occurrences_regexpr_1.SQLOccurrencesRegexpr, sql_substring_regexpr_1.SQLSubstringRegexpr, sql_locate_regexpr_1.SQLLocateRegexpr, ...exports.sqlFunctionDefs.map(([name, params, v]) => fn(name, params, v)), ...exports.sqlNamedFunctionDefs.map(([name, v, params]) => namedFn(name, v, params)), ...exports.sqlSpatialFunctionDefs.map(([name, params, v]) => fn(name, params, v)), ...exports.sqlSpatialAggregateDefs.map(([name, params, v]) => fn(name, params, v)));
9469
9473
  }
@@ -11249,6 +11253,8 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
11249
11253
  exports.TypeParam = void 0;
11250
11254
  const combi_1 = __webpack_require__(/*! ../combi */ "./node_modules/@abaplint/core/build/src/abap/2_statements/combi.js");
11251
11255
  const _1 = __webpack_require__(/*! . */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js");
11256
+ const version_1 = __webpack_require__(/*! ../../../version */ "./node_modules/@abaplint/core/build/src/version.js");
11257
+ const _derived_types_1 = __webpack_require__(/*! ./_derived_types */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/_derived_types.js");
11252
11258
  class TypeParam extends combi_1.Expression {
11253
11259
  getRunnable() {
11254
11260
  const table = (0, combi_1.seq)((0, combi_1.altPrio)("STANDARD", "HASHED", "INDEX", "SORTED", "ANY"), "TABLE");
@@ -11256,7 +11262,10 @@ class TypeParam extends combi_1.Expression {
11256
11262
  const typeLine = "LINE OF";
11257
11263
  const ret = (0, combi_1.seq)((0, combi_1.alt)(foo, typeLine), _1.TypeNameOrInfer, (0, combi_1.opt)(_1.Default));
11258
11264
  const like = (0, combi_1.seq)("LIKE", (0, combi_1.opt)("LINE OF"), _1.FieldChain, (0, combi_1.optPrio)(_1.Default));
11259
- return (0, combi_1.alt)((0, combi_1.seq)("TYPE", (0, combi_1.alt)(table, ret)), like);
11265
+ const entity = (0, combi_1.alt)(_1.TypeName, _1.EntityAssociation);
11266
+ const rapTable = (0, combi_1.ver)(version_1.Release.v770, (0, combi_1.seq)("TYPE", "TABLE FOR", (0, _derived_types_1.derivedTypesAlt)((0, combi_1.ver)(version_1.Release.v773, (0, combi_1.seq)("ACTION IMPORT", entity), { also: combi_1.AlsoIn.OpenABAP }), (0, combi_1.ver)(version_1.Release.v774, (0, combi_1.seq)("READ LINK", entity), { also: combi_1.AlsoIn.OpenABAP }), (0, combi_1.ver)(version_1.Release.v787, (0, combi_1.seq)("EVENT", entity), { also: combi_1.AlsoIn.OpenABAP })), (0, combi_1.optPrio)("VALUE IS INITIAL")), { also: combi_1.AlsoIn.OpenABAP });
11267
+ // Method parameters also allow the RAP table and response type forms.
11268
+ return (0, combi_1.altPrio)(rapTable, _1.TypeStructure, (0, combi_1.seq)("TYPE", (0, combi_1.alt)(table, ret)), like);
11260
11269
  }
11261
11270
  }
11262
11271
  exports.TypeParam = TypeParam;
@@ -26522,6 +26531,21 @@ class CurrentScope {
26522
26531
  }
26523
26532
  this.current.getData().forms.push(...f);
26524
26533
  }
26534
+ /** The FORM definitions are built up front, at that point the program level types are not known.
26535
+ * When the FORM statement is traversed it is replaced with one resolved in the scope of the FORM */
26536
+ updateFormDefinition(f) {
26537
+ let search = this.current;
26538
+ while (search !== undefined) {
26539
+ const forms = search.getData().forms;
26540
+ for (let i = 0; i < forms.length; i++) {
26541
+ if (forms[i].equals(f)) {
26542
+ forms[i] = f;
26543
+ return;
26544
+ }
26545
+ }
26546
+ search = search.getParent();
26547
+ }
26548
+ }
26525
26549
  addInterfaceDefinition(i) {
26526
26550
  if (this.current === undefined) {
26527
26551
  return;
@@ -27468,6 +27492,7 @@ class Procedural {
27468
27492
  scope: _current_scope_1.CurrentScope.buildDefault(this.reg, obj),
27469
27493
  filename: file.getFilename(),
27470
27494
  issues: [],
27495
+ deferred: [],
27471
27496
  };
27472
27497
  for (const found of structure.findAllStructures(Structures.Form)) {
27473
27498
  this.scope.addFormDefinitions([new types_1.FormDefinition(found, input)]);
@@ -36913,6 +36938,7 @@ class FindGlobalDefinitions {
36913
36938
  filename: file.getFilename(),
36914
36939
  scope: _current_scope_1.CurrentScope.buildDefault(this.reg, obj),
36915
36940
  issues: [],
36941
+ deferred: [],
36916
36942
  };
36917
36943
  if (obj instanceof interface_1.Interface) {
36918
36944
  const found = struc.findFirstStructure(Structures.Interface);
@@ -41141,6 +41167,9 @@ class Form {
41141
41167
  }
41142
41168
  input.scope.push(_scope_type_1.ScopeType.Form, name, node.getFirstToken().getStart(), input.filename);
41143
41169
  const form = new form_definition_1.FormDefinition(node, input);
41170
+ // the definitions are built up front, before the program level types are known, replace it
41171
+ // with this one, which is resolved in the scope of the FORM
41172
+ input.scope.updateFormDefinition(form);
41144
41173
  input.scope.addList(form.getUsingParameters());
41145
41174
  input.scope.addList(form.getChangingParameters());
41146
41175
  input.scope.addList(form.getTablesParameters());
@@ -44175,12 +44204,19 @@ class Perform {
44175
44204
  input.scope.addReference(expr.getFirstToken(), found, _reference_1.ReferenceType.FormReference, input.filename);
44176
44205
  ////////////////////////////
44177
44206
  // check parameters match
44178
- // USING and CHANGING are interchangeable, the actual parameters form a single positional list
44179
- if (this.checkParameters(node, tables, found.getTablesParameters(), "TABLES", input) === false) {
44180
- return;
44181
- }
44182
- const formal = found.getUsingParameters().concat(found.getChangingParameters());
44183
- this.checkParameters(node, using.concat(changing), formal, "USING/CHANGING", input);
44207
+ // deferred, the FORM might be defined after the PERFORM, its parameters are only typed
44208
+ // once the FORM statement itself has been traversed
44209
+ input.deferred.push(() => {
44210
+ var _a;
44211
+ // look up again, the definition is replaced when the FORM statement is traversed
44212
+ const def = (_a = input.scope.findFormDefinition(name)) !== null && _a !== void 0 ? _a : found;
44213
+ if (this.checkParameters(node, tables, def.getTablesParameters(), "TABLES", input) === false) {
44214
+ return;
44215
+ }
44216
+ // USING and CHANGING are interchangeable, the actual parameters form a single positional list
44217
+ const formal = def.getUsingParameters().concat(def.getChangingParameters());
44218
+ this.checkParameters(node, using.concat(changing), formal, "USING/CHANGING", input);
44219
+ });
44184
44220
  }
44185
44221
  // returns false if an issue was reported
44186
44222
  checkParameters(node, actual, formal, kind, input) {
@@ -45576,22 +45612,8 @@ class SelectOption {
45576
45612
  return;
45577
45613
  }
45578
45614
  const nameChain = node.findFirstExpression(Expressions.FieldChain);
45579
- let found = new basic_types_1.BasicTypes(input).resolveLikeName(nameChain);
45615
+ const found = new basic_types_1.BasicTypes(input).resolveLikeName(nameChain);
45580
45616
  if (found) {
45581
- if (found instanceof basic_1.StructureType) {
45582
- let length = 0;
45583
- for (const c of found.getComponents()) {
45584
- if (c.type instanceof basic_1.CharacterType) {
45585
- length += c.type.getLength();
45586
- }
45587
- }
45588
- if (length === 0) {
45589
- found = basic_1.VoidType.get("Selectoption, fallback");
45590
- }
45591
- else {
45592
- found = new basic_1.CharacterType(length);
45593
- }
45594
- }
45595
45617
  const stru = new basic_1.StructureType([
45596
45618
  { name: "SIGN", type: new basic_1.CharacterType(1) },
45597
45619
  { name: "OPTION", type: new basic_1.CharacterType(2) },
@@ -48845,6 +48867,7 @@ class SyntaxLogic {
48845
48867
  constructor(reg, object) {
48846
48868
  this.reg = reg;
48847
48869
  this.issues = [];
48870
+ this.deferred = [];
48848
48871
  this.object = object;
48849
48872
  }
48850
48873
  run() {
@@ -48858,6 +48881,7 @@ class SyntaxLogic {
48858
48881
  proc: new _procedural_1.Procedural(this.reg, this.scope),
48859
48882
  };
48860
48883
  this.issues = [];
48884
+ this.deferred = [];
48861
48885
  this.reg.getDDICReferences().clear(this.object);
48862
48886
  this.reg.getMSAGReferences().clear(this.object);
48863
48887
  if (this.object instanceof objects_1.Program && this.object.isInclude()) {
@@ -48865,6 +48889,11 @@ class SyntaxLogic {
48865
48889
  return { issues: [], spaghetti: this.scope.pop(new position_1.Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)) };
48866
48890
  }
48867
48891
  this.traverseObject();
48892
+ // the FORM definitions are now all traversed, ie. their parameters are typed
48893
+ for (const d of this.deferred) {
48894
+ d();
48895
+ }
48896
+ this.deferred = [];
48868
48897
  for (;;) {
48869
48898
  const spaghetti = this.scope.pop(new position_1.Position(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER)); // pop built-in scopes
48870
48899
  if (spaghetti.getTop().getIdentifier().stype === _scope_type_1.ScopeType.BuiltIn) {
@@ -48964,6 +48993,7 @@ class SyntaxLogic {
48964
48993
  scope: this.scope,
48965
48994
  filename,
48966
48995
  issues: this.issues,
48996
+ deferred: this.deferred,
48967
48997
  };
48968
48998
  if (stru instanceof Structures.ClassDefinition) {
48969
48999
  new class_definition_1.ClassDefinition(node, input);
@@ -49015,6 +49045,7 @@ class SyntaxLogic {
49015
49045
  scope: this.scope,
49016
49046
  filename,
49017
49047
  issues: this.issues,
49048
+ deferred: this.deferred,
49018
49049
  };
49019
49050
  // todo, refactor
49020
49051
  if (s instanceof Statements.Type) {
@@ -70595,7 +70626,7 @@ class Registry {
70595
70626
  }
70596
70627
  static abaplintVersion() {
70597
70628
  // magic, see build script "version.js"
70598
- return "2.120.37";
70629
+ return "2.120.42";
70599
70630
  }
70600
70631
  getDDICReferences() {
70601
70632
  return this.ddicReferences;
@@ -73286,7 +73317,7 @@ const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
73286
73317
  const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION"];
73287
73318
  const MAX_LABEL_LENGTH = 40;
73288
73319
  // Annotations which are not supported in CDS view entities
73289
- const VIEW_ENTITY_FORBIDDEN_ANNOTATIONS = ["Semantics.unitOfMeasure"];
73320
+ const VIEW_ENTITY_FORBIDDEN_ANNOTATIONS = ["Semantics.unitOfMeasure", "Semantics.currencyCode"];
73290
73321
  class CDSCheckSyntax {
73291
73322
  constructor() {
73292
73323
  this.conf = new CDSCheckSyntaxConf();
@@ -73330,6 +73361,7 @@ Missing objects are only reported when their names match the configured errorNam
73330
73361
  this.checkFieldAnnotations(tree, ddic, issues, file);
73331
73362
  this.checkLabels(tree, issues, file);
73332
73363
  this.checkViewEntityAnnotations(tree, issues, file);
73364
+ this.checkSearchable(tree, issues, file);
73333
73365
  this.checkReservedNames(tree, issues, file);
73334
73366
  this.checkFields(tree, sources, object, issues, file);
73335
73367
  return issues;
@@ -73551,6 +73583,29 @@ Missing objects are only reported when their names match the configured errorNam
73551
73583
  }
73552
73584
  }
73553
73585
  }
73586
+ checkSearchable(tree, issues, file) {
73587
+ let searchable;
73588
+ for (const annotation of tree.findAllExpressionsRecursive(expressions_1.CDSAnnotation)) {
73589
+ const normalized = annotation.concatTokens().replace(/\s/g, "").toUpperCase().replace(/^@</, "@");
73590
+ if (this.hasSearchAnnotation(normalized, "defaultSearchElement")) {
73591
+ return;
73592
+ }
73593
+ else if (searchable === undefined && this.hasSearchAnnotation(normalized, "searchable")) {
73594
+ searchable = annotation;
73595
+ }
73596
+ }
73597
+ if (searchable !== undefined) {
73598
+ const message = "@Search.defaultSearchElement: true required on at least one element " +
73599
+ "when @Search.searchable: true";
73600
+ issues.push(issue_1.Issue.atToken(file, searchable.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
73601
+ }
73602
+ }
73603
+ hasSearchAnnotation(normalized, name) {
73604
+ if (normalized.startsWith("@SEARCH") === false) {
73605
+ return false;
73606
+ }
73607
+ return new RegExp("[.{,]" + name.toUpperCase() + ":TRUE").test(normalized);
73608
+ }
73554
73609
  checkReservedNames(tree, issues, file) {
73555
73610
  var _a, _b;
73556
73611
  for (const element of tree.findAllExpressionsRecursive(expressions_1.CDSElement)) {
@@ -74242,6 +74297,7 @@ https://help.sap.com/doc/abapdocu_latest_index_htm/latest/en-US/abenchained_stat
74242
74297
  || statement instanceof Statements.Ranges
74243
74298
  || statement instanceof Statements.TypePools
74244
74299
  || statement instanceof Statements.FieldSymbol
74300
+ || statement instanceof Statements.Nodes
74245
74301
  || statement instanceof Statements.Data
74246
74302
  || statement instanceof Statements.DataBegin
74247
74303
  || statement instanceof Statements.DataEnd)) {
@@ -101138,6 +101194,7 @@ exports.DECLARATION_STUFF = exports.SELECTION_EVENTS = void 0;
101138
101194
  const Statements = __importStar(__webpack_require__(/*! ./abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
101139
101195
  exports.SELECTION_EVENTS = [
101140
101196
  Statements.StartOfSelection,
101197
+ Statements.Get,
101141
101198
  Statements.AtSelectionScreen,
101142
101199
  Statements.AtLineSelection,
101143
101200
  Statements.AtPF,
@@ -102234,7 +102291,7 @@ class Chunk {
102234
102291
  if (input === "") {
102235
102292
  return this;
102236
102293
  }
102237
- if (pos && input !== "\n") {
102294
+ if (pos && input !== "\n" && traversal.isSourceMapEnabled?.() !== false) {
102238
102295
  this.mappings.push({
102239
102296
  source: traversal.getFilename(),
102240
102297
  generated: {
@@ -102253,7 +102310,7 @@ class Chunk {
102253
102310
  * already carries mappings, so it never overrides finer-grained mappings.
102254
102311
  */
102255
102312
  ensureStartMapping(pos, traversal) {
102256
- if (this.raw === "" || this.mappings.length > 0) {
102313
+ if (this.raw === "" || this.mappings.length > 0 || traversal.isSourceMapEnabled?.() === false) {
102257
102314
  return this;
102258
102315
  }
102259
102316
  this.mappings.push({
@@ -102296,29 +102353,32 @@ class Chunk {
102296
102353
  if (ignoreSourceMap === true) {
102297
102354
  this.mappings = [];
102298
102355
  }
102356
+ const indentationByLine = this.mappings.length > 0 ? [] : undefined;
102299
102357
  for (const l of this.raw.split("\n")) {
102300
102358
  if (l.startsWith("}")) {
102301
102359
  i = i - 1;
102302
102360
  }
102303
102361
  // clamp so unbalanced braces never produce a negative indent/shift
102304
102362
  const indent = i > 0 ? i * 2 : 0;
102363
+ if (indentationByLine !== undefined) {
102364
+ indentationByLine[line] = indent;
102365
+ }
102305
102366
  if (indent > 0) {
102306
102367
  output.push(" ".repeat(indent) + l);
102307
102368
  }
102308
102369
  else {
102309
102370
  output.push(l);
102310
102371
  }
102311
- // fix maps: shift columns by the indentation actually applied to this line
102312
- for (const m of this.mappings) {
102313
- if (m.generated.line === line) {
102314
- m.generated.column += indent;
102315
- }
102316
- }
102317
102372
  if (l.endsWith(" {")) {
102318
102373
  i = i + 1;
102319
102374
  }
102320
102375
  line++;
102321
102376
  }
102377
+ // Shift every mapping once. The previous line-major implementation
102378
+ // inspected every mapping for every generated line (O(lines * mappings)).
102379
+ for (const m of this.mappings) {
102380
+ m.generated.column += indentationByLine?.[m.generated.line] || 0;
102381
+ }
102322
102382
  this.raw = output.join("\n");
102323
102383
  // line structure is unchanged, but the last line may have been indented
102324
102384
  this.lastLineLength = output[output.length - 1].length;
@@ -102445,39 +102505,49 @@ class DatabaseSetup {
102445
102505
  // note: avoid hitting maximum statement size by splitting into multiple statements
102446
102506
  const insert = [];
102447
102507
  const populateTables = new populate_tables_1.PopulateTables(this.reg);
102508
+ const add = (statement) => {
102509
+ if (statement.length > 0) {
102510
+ insert.push(statement);
102511
+ }
102512
+ };
102513
+ const addAll = (statements) => {
102514
+ for (const statement of statements) {
102515
+ add(statement);
102516
+ }
102517
+ };
102448
102518
  // INSERT data
102449
102519
  for (const obj of this.reg.getObjects()) {
102450
102520
  if (options?.populateTables?.tadir !== false) {
102451
- insert.push(populateTables.insertTADIR(obj));
102521
+ add(populateTables.insertTADIR(obj));
102452
102522
  }
102453
102523
  if (obj instanceof abaplint.Objects.MessageClass) {
102454
- insert.push(...populateTables.insertT100(obj));
102524
+ addAll(populateTables.insertT100(obj));
102455
102525
  }
102456
102526
  else if (options?.populateTables?.wwwparams !== false
102457
102527
  && obj instanceof abaplint.Objects.WebMIME) {
102458
- insert.push(...populateTables.insertWWWPARAMS(obj));
102528
+ addAll(populateTables.insertWWWPARAMS(obj));
102459
102529
  }
102460
102530
  else if (obj instanceof abaplint.Objects.Class
102461
102531
  || obj instanceof abaplint.Objects.Interface
102462
102532
  || obj instanceof abaplint.Objects.Program) {
102463
102533
  if (options?.populateTables?.reposrc !== false) {
102464
- insert.push(populateTables.insertREPOSRC(obj));
102534
+ add(populateTables.insertREPOSRC(obj));
102465
102535
  }
102466
102536
  if ((obj instanceof abaplint.Objects.Class || obj instanceof abaplint.Objects.Interface)
102467
102537
  && options?.populateTables?.seosubco !== false) {
102468
- insert.push(...populateTables.insertSEOSUBCO(obj));
102538
+ addAll(populateTables.insertSEOSUBCO(obj));
102469
102539
  }
102470
102540
  if ((obj instanceof abaplint.Objects.Class || obj instanceof abaplint.Objects.Interface)
102471
102541
  && options?.populateTables?.seosubcodf !== false) {
102472
- insert.push(...populateTables.insertSEOSUBCODF(obj));
102542
+ addAll(populateTables.insertSEOSUBCODF(obj));
102473
102543
  }
102474
102544
  if ((obj instanceof abaplint.Objects.Class || obj instanceof abaplint.Objects.Interface)
102475
102545
  && options?.populateTables?.seosubcotx !== false) {
102476
- insert.push(...populateTables.insertSEOSUBCOTX(obj));
102546
+ addAll(populateTables.insertSEOSUBCOTX(obj));
102477
102547
  }
102478
102548
  }
102479
102549
  }
102480
- insert.push(populateTables.insertT000());
102550
+ add(populateTables.insertT000());
102481
102551
  return insert;
102482
102552
  }
102483
102553
  }
@@ -109790,11 +109860,13 @@ class Transpiler {
109790
109860
  // workaround for web/webpack
109791
109861
  async runRaw(files) {
109792
109862
  const memory = files.map(f => new abaplint.MemoryFile(f.filename, f.contents));
109793
- const reg = new abaplint.Registry().addFiles(memory).parse();
109794
- return new Transpiler().run(reg);
109863
+ const reg = new abaplint.Registry().addFiles(memory);
109864
+ return this.run(reg);
109795
109865
  }
109796
109866
  async run(reg, progress) {
109797
- reg.parse();
109867
+ // Validation installs the transpiler configuration and findIssues() parses
109868
+ // dirty registries. Parsing before that would be wasted because setConfig()
109869
+ // marks every registry object dirty again.
109798
109870
  this.validate(reg);
109799
109871
  const dbSetup = new db_1.DatabaseSetup(reg).run(this.options);
109800
109872
  this.plugin?.amendDatabaseSetup?.(dbSetup, reg, this.options || {});
@@ -110880,7 +110952,14 @@ class AssignTranspiler {
110880
110952
  }
110881
110953
  else {
110882
110954
  let dynamicName = "";
110883
- for (const c of assignSource?.getChildren() || []) {
110955
+ const first = assignSource?.getFirstChild();
110956
+ // dynamicSource below already contains the first source expression.
110957
+ // Keep only the dynamic suffix in dynamicName, otherwise structure
110958
+ // components in that expression are resolved a second time at runtime.
110959
+ const dynamicNameChildren = first?.get() instanceof abaplint.Expressions.Source
110960
+ ? assignSource?.getChildren().slice(1)
110961
+ : assignSource?.getChildren();
110962
+ for (const c of dynamicNameChildren || []) {
110884
110963
  if (c instanceof abaplint.Nodes.ExpressionNode
110885
110964
  && c.get() instanceof abaplint.Expressions.Dynamic
110886
110965
  && c.findFirstExpression(abaplint.Expressions.ConstantString)) {
@@ -110901,7 +110980,10 @@ class AssignTranspiler {
110901
110980
  continue;
110902
110981
  }
110903
110982
  else if (c.concatTokens() === "=>" || c.concatTokens() === "->") {
110904
- dynamicName += " + '" + c.concatTokens() + "'";
110983
+ if (dynamicName !== "") {
110984
+ dynamicName += " + ";
110985
+ }
110986
+ dynamicName += "'" + c.concatTokens() + "'";
110905
110987
  }
110906
110988
  else {
110907
110989
  if (dynamicName !== "") {
@@ -110912,7 +110994,6 @@ class AssignTranspiler {
110912
110994
  }
110913
110995
  options.push(`dynamicName: ` + dynamicName);
110914
110996
  // dynamicSource is the first part of the dynamic part
110915
- const first = assignSource?.getFirstChild();
110916
110997
  if (first?.get() instanceof abaplint.Expressions.Dynamic && first instanceof abaplint.Nodes.ExpressionNode) {
110917
110998
  const firstFirst = first.getChildren()[1];
110918
110999
  if (firstFirst?.get() instanceof abaplint.Expressions.Constant) {
@@ -110996,6 +111077,27 @@ exports.AtLineSelectionTranspiler = AtLineSelectionTranspiler;
110996
111077
 
110997
111078
  /***/ },
110998
111079
 
111080
+ /***/ "./node_modules/@abaplint/transpiler/build/src/statements/at_pf.js"
111081
+ /*!*************************************************************************!*\
111082
+ !*** ./node_modules/@abaplint/transpiler/build/src/statements/at_pf.js ***!
111083
+ \*************************************************************************/
111084
+ (__unused_webpack_module, exports, __webpack_require__) {
111085
+
111086
+ "use strict";
111087
+
111088
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
111089
+ exports.AtPFTranspiler = void 0;
111090
+ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
111091
+ class AtPFTranspiler {
111092
+ transpile(_node, _traversal) {
111093
+ return new chunk_1.Chunk(`throw new Error("AT PFnn, not supported, transpiler");`);
111094
+ }
111095
+ }
111096
+ exports.AtPFTranspiler = AtPFTranspiler;
111097
+ //# sourceMappingURL=at_pf.js.map
111098
+
111099
+ /***/ },
111100
+
110999
111101
  /***/ "./node_modules/@abaplint/transpiler/build/src/statements/at_selection_screen.js"
111000
111102
  /*!***************************************************************************************!*\
111001
111103
  !*** ./node_modules/@abaplint/transpiler/build/src/statements/at_selection_screen.js ***!
@@ -111017,6 +111119,27 @@ exports.AtSelectionScreenTranspiler = AtSelectionScreenTranspiler;
111017
111119
 
111018
111120
  /***/ },
111019
111121
 
111122
+ /***/ "./node_modules/@abaplint/transpiler/build/src/statements/at_user_command.js"
111123
+ /*!***********************************************************************************!*\
111124
+ !*** ./node_modules/@abaplint/transpiler/build/src/statements/at_user_command.js ***!
111125
+ \***********************************************************************************/
111126
+ (__unused_webpack_module, exports, __webpack_require__) {
111127
+
111128
+ "use strict";
111129
+
111130
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
111131
+ exports.AtUserCommandTranspiler = void 0;
111132
+ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
111133
+ class AtUserCommandTranspiler {
111134
+ transpile(_node, _traversal) {
111135
+ return new chunk_1.Chunk(`throw new Error("AT USER-COMMAND, not supported, transpiler");`);
111136
+ }
111137
+ }
111138
+ exports.AtUserCommandTranspiler = AtUserCommandTranspiler;
111139
+ //# sourceMappingURL=at_user_command.js.map
111140
+
111141
+ /***/ },
111142
+
111020
111143
  /***/ "./node_modules/@abaplint/transpiler/build/src/statements/authority_check.js"
111021
111144
  /*!***********************************************************************************!*\
111022
111145
  !*** ./node_modules/@abaplint/transpiler/build/src/statements/authority_check.js ***!
@@ -111487,6 +111610,27 @@ exports.CallScreenTranspiler = CallScreenTranspiler;
111487
111610
 
111488
111611
  /***/ },
111489
111612
 
111613
+ /***/ "./node_modules/@abaplint/transpiler/build/src/statements/call_selection_screen.js"
111614
+ /*!*****************************************************************************************!*\
111615
+ !*** ./node_modules/@abaplint/transpiler/build/src/statements/call_selection_screen.js ***!
111616
+ \*****************************************************************************************/
111617
+ (__unused_webpack_module, exports, __webpack_require__) {
111618
+
111619
+ "use strict";
111620
+
111621
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
111622
+ exports.CallSelectionScreenTranspiler = void 0;
111623
+ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
111624
+ class CallSelectionScreenTranspiler {
111625
+ transpile(_node, _traversal) {
111626
+ return new chunk_1.Chunk(`throw new Error("CALL SELECTION-SCREEN, not supported, transpiler");`);
111627
+ }
111628
+ }
111629
+ exports.CallSelectionScreenTranspiler = CallSelectionScreenTranspiler;
111630
+ //# sourceMappingURL=call_selection_screen.js.map
111631
+
111632
+ /***/ },
111633
+
111490
111634
  /***/ "./node_modules/@abaplint/transpiler/build/src/statements/call_transaction.js"
111491
111635
  /*!************************************************************************************!*\
111492
111636
  !*** ./node_modules/@abaplint/transpiler/build/src/statements/call_transaction.js ***!
@@ -114699,6 +114843,27 @@ exports.GetTimeTranspiler = GetTimeTranspiler;
114699
114843
 
114700
114844
  /***/ },
114701
114845
 
114846
+ /***/ "./node_modules/@abaplint/transpiler/build/src/statements/hide.js"
114847
+ /*!************************************************************************!*\
114848
+ !*** ./node_modules/@abaplint/transpiler/build/src/statements/hide.js ***!
114849
+ \************************************************************************/
114850
+ (__unused_webpack_module, exports, __webpack_require__) {
114851
+
114852
+ "use strict";
114853
+
114854
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
114855
+ exports.HideTranspiler = void 0;
114856
+ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
114857
+ class HideTranspiler {
114858
+ transpile(_node, _traversal) {
114859
+ return new chunk_1.Chunk(`throw new Error("HIDE, not supported, transpiler");`);
114860
+ }
114861
+ }
114862
+ exports.HideTranspiler = HideTranspiler;
114863
+ //# sourceMappingURL=hide.js.map
114864
+
114865
+ /***/ },
114866
+
114702
114867
  /***/ "./node_modules/@abaplint/transpiler/build/src/statements/if.js"
114703
114868
  /*!**********************************************************************!*\
114704
114869
  !*** ./node_modules/@abaplint/transpiler/build/src/statements/if.js ***!
@@ -114883,14 +115048,17 @@ __exportStar(__webpack_require__(/*! ./add */ "./node_modules/@abaplint/transpil
114883
115048
  __exportStar(__webpack_require__(/*! ./append */ "./node_modules/@abaplint/transpiler/build/src/statements/append.js"), exports);
114884
115049
  __exportStar(__webpack_require__(/*! ./assert */ "./node_modules/@abaplint/transpiler/build/src/statements/assert.js"), exports);
114885
115050
  __exportStar(__webpack_require__(/*! ./assign */ "./node_modules/@abaplint/transpiler/build/src/statements/assign.js"), exports);
115051
+ __exportStar(__webpack_require__(/*! ./at_pf */ "./node_modules/@abaplint/transpiler/build/src/statements/at_pf.js"), exports);
114886
115052
  __exportStar(__webpack_require__(/*! ./at_selection_screen */ "./node_modules/@abaplint/transpiler/build/src/statements/at_selection_screen.js"), exports);
114887
115053
  __exportStar(__webpack_require__(/*! ./at */ "./node_modules/@abaplint/transpiler/build/src/statements/at.js"), exports);
115054
+ __exportStar(__webpack_require__(/*! ./at_user_command */ "./node_modules/@abaplint/transpiler/build/src/statements/at_user_command.js"), exports);
114888
115055
  __exportStar(__webpack_require__(/*! ./authority_check */ "./node_modules/@abaplint/transpiler/build/src/statements/authority_check.js"), exports);
114889
115056
  __exportStar(__webpack_require__(/*! ./break_id */ "./node_modules/@abaplint/transpiler/build/src/statements/break_id.js"), exports);
114890
115057
  __exportStar(__webpack_require__(/*! ./break */ "./node_modules/@abaplint/transpiler/build/src/statements/break.js"), exports);
114891
115058
  __exportStar(__webpack_require__(/*! ./call_function */ "./node_modules/@abaplint/transpiler/build/src/statements/call_function.js"), exports);
114892
115059
  __exportStar(__webpack_require__(/*! ./call_kernel */ "./node_modules/@abaplint/transpiler/build/src/statements/call_kernel.js"), exports);
114893
115060
  __exportStar(__webpack_require__(/*! ./call_screen */ "./node_modules/@abaplint/transpiler/build/src/statements/call_screen.js"), exports);
115061
+ __exportStar(__webpack_require__(/*! ./call_selection_screen */ "./node_modules/@abaplint/transpiler/build/src/statements/call_selection_screen.js"), exports);
114894
115062
  __exportStar(__webpack_require__(/*! ./call_transaction */ "./node_modules/@abaplint/transpiler/build/src/statements/call_transaction.js"), exports);
114895
115063
  __exportStar(__webpack_require__(/*! ./call_transformation */ "./node_modules/@abaplint/transpiler/build/src/statements/call_transformation.js"), exports);
114896
115064
  __exportStar(__webpack_require__(/*! ./call */ "./node_modules/@abaplint/transpiler/build/src/statements/call.js"), exports);
@@ -114958,6 +115126,7 @@ __exportStar(__webpack_require__(/*! ./get_parameter */ "./node_modules/@abaplin
114958
115126
  __exportStar(__webpack_require__(/*! ./get_reference */ "./node_modules/@abaplint/transpiler/build/src/statements/get_reference.js"), exports);
114959
115127
  __exportStar(__webpack_require__(/*! ./get_run_time */ "./node_modules/@abaplint/transpiler/build/src/statements/get_run_time.js"), exports);
114960
115128
  __exportStar(__webpack_require__(/*! ./get_time */ "./node_modules/@abaplint/transpiler/build/src/statements/get_time.js"), exports);
115129
+ __exportStar(__webpack_require__(/*! ./hide */ "./node_modules/@abaplint/transpiler/build/src/statements/hide.js"), exports);
114961
115130
  __exportStar(__webpack_require__(/*! ./if */ "./node_modules/@abaplint/transpiler/build/src/statements/if.js"), exports);
114962
115131
  __exportStar(__webpack_require__(/*! ./import */ "./node_modules/@abaplint/transpiler/build/src/statements/import.js"), exports);
114963
115132
  __exportStar(__webpack_require__(/*! ./include */ "./node_modules/@abaplint/transpiler/build/src/statements/include.js"), exports);
@@ -114979,6 +115148,7 @@ __exportStar(__webpack_require__(/*! ./modify_internal */ "./node_modules/@abapl
114979
115148
  __exportStar(__webpack_require__(/*! ./modify_screen */ "./node_modules/@abaplint/transpiler/build/src/statements/modify_screen.js"), exports);
114980
115149
  __exportStar(__webpack_require__(/*! ./move_corresponding */ "./node_modules/@abaplint/transpiler/build/src/statements/move_corresponding.js"), exports);
114981
115150
  __exportStar(__webpack_require__(/*! ./move */ "./node_modules/@abaplint/transpiler/build/src/statements/move.js"), exports);
115151
+ __exportStar(__webpack_require__(/*! ./new_page */ "./node_modules/@abaplint/transpiler/build/src/statements/new_page.js"), exports);
114982
115152
  __exportStar(__webpack_require__(/*! ./open_cursor */ "./node_modules/@abaplint/transpiler/build/src/statements/open_cursor.js"), exports);
114983
115153
  __exportStar(__webpack_require__(/*! ./open_dataset */ "./node_modules/@abaplint/transpiler/build/src/statements/open_dataset.js"), exports);
114984
115154
  __exportStar(__webpack_require__(/*! ./overlay */ "./node_modules/@abaplint/transpiler/build/src/statements/overlay.js"), exports);
@@ -116393,6 +116563,27 @@ exports.MoveCorrespondingTranspiler = MoveCorrespondingTranspiler;
116393
116563
 
116394
116564
  /***/ },
116395
116565
 
116566
+ /***/ "./node_modules/@abaplint/transpiler/build/src/statements/new_page.js"
116567
+ /*!****************************************************************************!*\
116568
+ !*** ./node_modules/@abaplint/transpiler/build/src/statements/new_page.js ***!
116569
+ \****************************************************************************/
116570
+ (__unused_webpack_module, exports, __webpack_require__) {
116571
+
116572
+ "use strict";
116573
+
116574
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
116575
+ exports.NewPageTranspiler = void 0;
116576
+ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
116577
+ class NewPageTranspiler {
116578
+ transpile(_node, _traversal) {
116579
+ return new chunk_1.Chunk(`throw new Error("NEW-PAGE, not supported, transpiler");`);
116580
+ }
116581
+ }
116582
+ exports.NewPageTranspiler = NewPageTranspiler;
116583
+ //# sourceMappingURL=new_page.js.map
116584
+
116585
+ /***/ },
116586
+
116396
116587
  /***/ "./node_modules/@abaplint/transpiler/build/src/statements/open_cursor.js"
116397
116588
  /*!*******************************************************************************!*\
116398
116589
  !*** ./node_modules/@abaplint/transpiler/build/src/statements/open_cursor.js ***!
@@ -122034,6 +122225,8 @@ class Traversal {
122034
122225
  obj;
122035
122226
  sqlInferredType;
122036
122227
  doOrWhileIndexBackups = new Map();
122228
+ statementsInsideLoop = new WeakSet();
122229
+ enclosingDoOrWhile = new WeakMap();
122037
122230
  reg;
122038
122231
  options;
122039
122232
  constructor(spaghetti, file, obj, reg, options) {
@@ -122042,6 +122235,43 @@ class Traversal {
122042
122235
  this.obj = obj;
122043
122236
  this.reg = reg;
122044
122237
  this.options = options;
122238
+ this.buildStatementContext();
122239
+ }
122240
+ /** Build file-level control-flow context once instead of rescanning all
122241
+ * preceding statements for every DATA, CHECK, EXIT, and RETURN. */
122242
+ buildStatementContext() {
122243
+ const loopStack = [];
122244
+ const doOrWhileStack = [];
122245
+ for (const statement of this.file.getStatements()) {
122246
+ const get = statement.get();
122247
+ if (get instanceof abaplint.Statements.Loop
122248
+ || get instanceof abaplint.Statements.While
122249
+ || get instanceof abaplint.Statements.SelectLoop
122250
+ || get instanceof abaplint.Statements.Do) {
122251
+ loopStack.push(statement);
122252
+ }
122253
+ else if (get instanceof abaplint.Statements.EndLoop
122254
+ || get instanceof abaplint.Statements.EndWhile
122255
+ || get instanceof abaplint.Statements.EndSelect
122256
+ || get instanceof abaplint.Statements.EndDo) {
122257
+ loopStack.pop();
122258
+ }
122259
+ if (loopStack.length > 0) {
122260
+ this.statementsInsideLoop.add(statement);
122261
+ }
122262
+ if (get instanceof abaplint.Statements.While
122263
+ || get instanceof abaplint.Statements.Do) {
122264
+ doOrWhileStack.push(statement);
122265
+ }
122266
+ else if (get instanceof abaplint.Statements.EndWhile
122267
+ || get instanceof abaplint.Statements.EndDo) {
122268
+ doOrWhileStack.pop();
122269
+ }
122270
+ const enclosing = doOrWhileStack[doOrWhileStack.length - 1];
122271
+ if (enclosing !== undefined) {
122272
+ this.enclosingDoOrWhile.set(statement, enclosing);
122273
+ }
122274
+ }
122045
122275
  }
122046
122276
  static escapeNamespace(name) {
122047
122277
  return name?.replace(/\//g, "$");
@@ -122088,6 +122318,9 @@ class Traversal {
122088
122318
  getSpaghetti() {
122089
122319
  return this.spaghetti;
122090
122320
  }
122321
+ isSourceMapEnabled() {
122322
+ return this.options?.ignoreSourceMap !== true;
122323
+ }
122091
122324
  /** finds a statement in the _current_ file given a position */
122092
122325
  findStatementInFile(pos) {
122093
122326
  for (const s of this.file.getStatements()) {
@@ -122550,9 +122783,16 @@ class Traversal {
122550
122783
  return ret;
122551
122784
  }
122552
122785
  buildFriendsAccess(def, hasSuperClass) {
122553
- let ret = "this.FRIENDS_ACCESS_INSTANCE = {\n";
122786
+ let ret = "";
122554
122787
  if (hasSuperClass === true) {
122555
- ret += `"SUPER": sup.FRIENDS_ACCESS_INSTANCE,\n`;
122788
+ // A subclass instance can be held through a superclass reference. In
122789
+ // that case friend access must still find private members declared by
122790
+ // the superclass.
122791
+ ret += "this.FRIENDS_ACCESS_INSTANCE = Object.create(sup.FRIENDS_ACCESS_INSTANCE || null);\n";
122792
+ ret += `this.FRIENDS_ACCESS_INSTANCE["SUPER"] = sup.FRIENDS_ACCESS_INSTANCE;\n`;
122793
+ }
122794
+ else {
122795
+ ret += "this.FRIENDS_ACCESS_INSTANCE = {\n";
122556
122796
  }
122557
122797
  for (const method of def.getMethodDefinitions()?.getAll() || []) {
122558
122798
  const name = method.getName().toLowerCase();
@@ -122565,9 +122805,16 @@ class Traversal {
122565
122805
  }
122566
122806
  const methodName = privateHash + Traversal.escapeNamespace(name.replace("~", "$"));
122567
122807
  // NOTE: currently all are needed in the unit test setup
122568
- ret += `"${name.replace("~", "$")}": this.${methodName}.bind(this),\n`;
122808
+ if (hasSuperClass === true) {
122809
+ ret += `this.FRIENDS_ACCESS_INSTANCE["${name.replace("~", "$")}"] = this.${methodName}.bind(this);\n`;
122810
+ }
122811
+ else {
122812
+ ret += `"${name.replace("~", "$")}": this.${methodName}.bind(this),\n`;
122813
+ }
122814
+ }
122815
+ if (hasSuperClass === false) {
122816
+ ret += "};\n";
122569
122817
  }
122570
- ret += "};\n";
122571
122818
  return ret;
122572
122819
  }
122573
122820
  buildConstructorContents(scope, def) {
@@ -122806,26 +123053,7 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
122806
123053
  return context;
122807
123054
  }
122808
123055
  isInsideLoop(node) {
122809
- const stack = [];
122810
- for (const statement of this.getFile().getStatements()) {
122811
- const get = statement.get();
122812
- if (get instanceof abaplint.Statements.Loop
122813
- || get instanceof abaplint.Statements.While
122814
- || get instanceof abaplint.Statements.SelectLoop
122815
- || get instanceof abaplint.Statements.Do) {
122816
- stack.push(statement);
122817
- }
122818
- else if (get instanceof abaplint.Statements.EndLoop
122819
- || get instanceof abaplint.Statements.EndWhile
122820
- || get instanceof abaplint.Statements.EndSelect
122821
- || get instanceof abaplint.Statements.EndDo) {
122822
- stack.pop();
122823
- }
122824
- if (statement === node) {
122825
- break;
122826
- }
122827
- }
122828
- return stack.length > 0;
123056
+ return this.statementsInsideLoop.has(node);
122829
123057
  }
122830
123058
  isInsideDoOrWhile(node) {
122831
123059
  return this.findCurrentDoOrWhileIndexBackup(node) !== undefined;
@@ -122834,22 +123062,8 @@ this.INTERNAL_ID = abap.internalIdCounter++;\n`;
122834
123062
  this.doOrWhileIndexBackups.set(node, name);
122835
123063
  }
122836
123064
  findCurrentDoOrWhileIndexBackup(node) {
122837
- const stack = [];
122838
- for (const statement of this.getFile().getStatements()) {
122839
- const get = statement.get();
122840
- if (get instanceof abaplint.Statements.While
122841
- || get instanceof abaplint.Statements.Do) {
122842
- stack.push(this.doOrWhileIndexBackups.get(statement));
122843
- }
122844
- else if (get instanceof abaplint.Statements.EndWhile
122845
- || get instanceof abaplint.Statements.EndDo) {
122846
- stack.pop();
122847
- }
122848
- if (statement === node) {
122849
- break;
122850
- }
122851
- }
122852
- return stack[stack.length - 1];
123065
+ const enclosing = this.enclosingDoOrWhile.get(node);
123066
+ return enclosing === undefined ? undefined : this.doOrWhileIndexBackups.get(enclosing);
122853
123067
  }
122854
123068
  registerClassOrInterface(def) {
122855
123069
  if (def === undefined) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler-cli",
3
- "version": "2.13.63",
3
+ "version": "2.13.65",
4
4
  "description": "Transpiler - Command Line Interface",
5
5
  "funding": "https://github.com/sponsors/larshp",
6
6
  "bin": {
@@ -27,8 +27,8 @@
27
27
  "author": "abaplint",
28
28
  "license": "MIT",
29
29
  "devDependencies": {
30
- "@abaplint/core": "^2.120.37",
31
- "@abaplint/transpiler": "^2.13.63",
30
+ "@abaplint/core": "^2.120.42",
31
+ "@abaplint/transpiler": "^2.13.65",
32
32
  "@types/glob": "^8.1.0",
33
33
  "@types/node": "^24.13.3",
34
34
  "@types/progress": "^2.0.7",