@abaplint/transpiler-cli 2.14.5 → 2.14.7

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 +721 -97
  2. package/package.json +3 -3
package/build/bundle.js CHANGED
@@ -4135,7 +4135,7 @@ class ExpandMacros {
4135
4135
  listMacroNames() {
4136
4136
  return this.macros.listMacroNames();
4137
4137
  }
4138
- find(statements, file, clear = true) {
4138
+ find(statements, file, clear = true, includePath = new Set()) {
4139
4139
  var _a, _b, _c;
4140
4140
  let nameToken = undefined;
4141
4141
  let start = undefined;
@@ -4156,14 +4156,16 @@ class ExpandMacros {
4156
4156
  else if (type instanceof Statements.Include) {
4157
4157
  const includeName = (_b = statement.findDirectExpression(Expressions.IncludeName)) === null || _b === void 0 ? void 0 : _b.concatTokens();
4158
4158
  // todo, this does not take function module includes into account
4159
- // todo, workaround for cyclic includes?
4160
4159
  const prog = (_c = this.reg) === null || _c === void 0 ? void 0 : _c.getObject("PROG", includeName);
4161
4160
  if (prog) {
4162
4161
  prog.parse(this.release, this.globalMacros, this.reg, this.languageVersion);
4163
4162
  const includeMainFile = prog.getMainABAPFile();
4164
- if (includeMainFile) {
4163
+ // an include that is already on the current include path is not walked again
4164
+ if (includeMainFile && includePath.has(includeMainFile.getFilename()) === false) {
4165
+ includePath.add(includeMainFile.getFilename());
4165
4166
  // slow, this copies everything,
4166
- this.find([...includeMainFile.getStatements()], includeMainFile, false);
4167
+ this.find([...includeMainFile.getStatements()], includeMainFile, false, includePath);
4168
+ includePath.delete(includeMainFile.getFilename());
4167
4169
  }
4168
4170
  }
4169
4171
  }
@@ -14418,11 +14420,11 @@ class Convert {
14418
14420
  const dat = (0, combi_1.seq)("DATE", expressions_1.Source);
14419
14421
  const tim = (0, combi_1.seq)("TIME", expressions_1.Source);
14420
14422
  const stamp = (0, combi_1.seq)("INTO TIME STAMP", expressions_1.Target);
14421
- const intoutc = (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.seq)("INTO UTCLONG", expressions_1.Target));
14423
+ const intoutc = (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.seq)("INTO UTCLONG", expressions_1.Target), { also: combi_1.AlsoIn.OpenABAP });
14422
14424
  const invert = (0, combi_1.seq)("INTO INVERTED-DATE", expressions_1.Target);
14423
14425
  const date = (0, combi_1.seq)((0, combi_1.per)(dat, tim), (0, combi_1.per)(daylightSource, stamp, zone, invert, intoutc));
14424
14426
  const inv = (0, combi_1.seq)("INVERTED-DATE", expressions_1.Source, "INTO DATE", expressions_1.Target);
14425
- const utclong = (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.seq)("UTCLONG", expressions_1.Source, (0, combi_1.per)(zone, into, daylightSource)), { also: combi_1.AlsoIn.OpenABAP });
14427
+ const utclong = (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.seq)("UTCLONG", expressions_1.Source, (0, combi_1.per)(zone, into, daylightTarget)), { also: combi_1.AlsoIn.OpenABAP });
14426
14428
  return (0, combi_1.seq)("CONVERT", (0, combi_1.alt)(time, date, inv, utclong));
14427
14429
  }
14428
14430
  }
@@ -26338,28 +26340,28 @@ BuiltIn.methods = {
26338
26340
  "ABS": {
26339
26341
  counter: BuiltIn.counter++,
26340
26342
  mandatory: {
26341
- "val": new basic_1.FloatType(),
26343
+ "val": new basic_1.NumericGenericType(),
26342
26344
  },
26343
26345
  return: basic_1.IntegerType.get(),
26344
26346
  },
26345
26347
  "ACOS": {
26346
26348
  counter: BuiltIn.counter++,
26347
26349
  mandatory: {
26348
- "val": new basic_1.FloatType(),
26350
+ "val": new basic_1.NumericGenericType(),
26349
26351
  },
26350
26352
  return: new basic_1.FloatType(),
26351
26353
  },
26352
26354
  "ASIN": {
26353
26355
  counter: BuiltIn.counter++,
26354
26356
  mandatory: {
26355
- "val": new basic_1.FloatType(),
26357
+ "val": new basic_1.NumericGenericType(),
26356
26358
  },
26357
26359
  return: new basic_1.FloatType(),
26358
26360
  },
26359
26361
  "ATAN": {
26360
26362
  counter: BuiltIn.counter++,
26361
26363
  mandatory: {
26362
- "val": new basic_1.FloatType(),
26364
+ "val": new basic_1.NumericGenericType(),
26363
26365
  },
26364
26366
  return: new basic_1.FloatType(),
26365
26367
  },
@@ -26393,7 +26395,7 @@ BuiltIn.methods = {
26393
26395
  "CEIL": {
26394
26396
  counter: BuiltIn.counter++,
26395
26397
  mandatory: {
26396
- "val": new basic_1.FloatType(),
26398
+ "val": new basic_1.NumericGenericType(),
26397
26399
  },
26398
26400
  return: basic_1.IntegerType.get(),
26399
26401
  },
@@ -26530,14 +26532,14 @@ BuiltIn.methods = {
26530
26532
  "COS": {
26531
26533
  counter: BuiltIn.counter++,
26532
26534
  mandatory: {
26533
- "val": new basic_1.FloatType(),
26535
+ "val": new basic_1.NumericGenericType(),
26534
26536
  },
26535
26537
  return: new basic_1.FloatType(),
26536
26538
  },
26537
26539
  "COSH": {
26538
26540
  counter: BuiltIn.counter++,
26539
26541
  mandatory: {
26540
- "val": new basic_1.FloatType(),
26542
+ "val": new basic_1.NumericGenericType(),
26541
26543
  },
26542
26544
  return: new basic_1.FloatType(),
26543
26545
  },
@@ -26617,7 +26619,7 @@ BuiltIn.methods = {
26617
26619
  "EXP": {
26618
26620
  counter: BuiltIn.counter++,
26619
26621
  mandatory: {
26620
- "val": new basic_1.FloatType(),
26622
+ "val": new basic_1.NumericGenericType(),
26621
26623
  },
26622
26624
  return: new basic_1.FloatType(),
26623
26625
  },
@@ -26686,14 +26688,14 @@ BuiltIn.methods = {
26686
26688
  "FLOOR": {
26687
26689
  counter: BuiltIn.counter++,
26688
26690
  mandatory: {
26689
- "val": new basic_1.FloatType(),
26691
+ "val": new basic_1.NumericGenericType(),
26690
26692
  },
26691
26693
  return: basic_1.IntegerType.get(),
26692
26694
  },
26693
26695
  "FRAC": {
26694
26696
  counter: BuiltIn.counter++,
26695
26697
  mandatory: {
26696
- "val": new basic_1.FloatType(),
26698
+ "val": new basic_1.NumericGenericType(),
26697
26699
  },
26698
26700
  return: basic_1.IntegerType.get(),
26699
26701
  },
@@ -26725,8 +26727,8 @@ BuiltIn.methods = {
26725
26727
  "IPOW": {
26726
26728
  counter: BuiltIn.counter++,
26727
26729
  mandatory: {
26728
- "base": new basic_1.FloatType(),
26729
- "exp": new basic_1.FloatType(),
26730
+ "base": new basic_1.NumericGenericType(),
26731
+ "exp": new basic_1.NumericGenericType(),
26730
26732
  },
26731
26733
  return: basic_1.IntegerType.get(),
26732
26734
  release: version_1.Release.v740sp02,
@@ -26758,14 +26760,14 @@ BuiltIn.methods = {
26758
26760
  "LOG": {
26759
26761
  counter: BuiltIn.counter++,
26760
26762
  mandatory: {
26761
- "val": new basic_1.FloatType(),
26763
+ "val": new basic_1.NumericGenericType(),
26762
26764
  },
26763
26765
  return: new basic_1.FloatType(),
26764
26766
  },
26765
26767
  "LOG10": {
26766
26768
  counter: BuiltIn.counter++,
26767
26769
  mandatory: {
26768
- "val": new basic_1.FloatType(),
26770
+ "val": new basic_1.NumericGenericType(),
26769
26771
  },
26770
26772
  return: new basic_1.FloatType(),
26771
26773
  },
@@ -26871,7 +26873,7 @@ BuiltIn.methods = {
26871
26873
  "RESCALE": {
26872
26874
  counter: BuiltIn.counter++,
26873
26875
  mandatory: {
26874
- "val": new basic_1.FloatType(),
26876
+ "val": new basic_1.NumericGenericType(),
26875
26877
  },
26876
26878
  optional: {
26877
26879
  "dec": basic_1.IntegerType.get(),
@@ -26892,7 +26894,7 @@ BuiltIn.methods = {
26892
26894
  "ROUND": {
26893
26895
  counter: BuiltIn.counter++,
26894
26896
  mandatory: {
26895
- "val": new basic_1.FloatType(),
26897
+ "val": new basic_1.NumericGenericType(),
26896
26898
  },
26897
26899
  optional: {
26898
26900
  "dec": basic_1.IntegerType.get(),
@@ -26944,28 +26946,28 @@ BuiltIn.methods = {
26944
26946
  "SIGN": {
26945
26947
  counter: BuiltIn.counter++,
26946
26948
  mandatory: {
26947
- "val": new basic_1.FloatType(),
26949
+ "val": new basic_1.NumericGenericType(),
26948
26950
  },
26949
26951
  return: basic_1.IntegerType.get(),
26950
26952
  },
26951
26953
  "SIN": {
26952
26954
  counter: BuiltIn.counter++,
26953
26955
  mandatory: {
26954
- "val": new basic_1.FloatType(),
26956
+ "val": new basic_1.NumericGenericType(),
26955
26957
  },
26956
26958
  return: new basic_1.FloatType(),
26957
26959
  },
26958
26960
  "SINH": {
26959
26961
  counter: BuiltIn.counter++,
26960
26962
  mandatory: {
26961
- "val": new basic_1.FloatType(),
26963
+ "val": new basic_1.NumericGenericType(),
26962
26964
  },
26963
26965
  return: new basic_1.FloatType(),
26964
26966
  },
26965
26967
  "SQRT": {
26966
26968
  counter: BuiltIn.counter++,
26967
26969
  mandatory: {
26968
- "val": new basic_1.FloatType(),
26970
+ "val": new basic_1.NumericGenericType(),
26969
26971
  },
26970
26972
  return: new basic_1.FloatType(),
26971
26973
  },
@@ -27055,14 +27057,14 @@ BuiltIn.methods = {
27055
27057
  "TAN": {
27056
27058
  counter: BuiltIn.counter++,
27057
27059
  mandatory: {
27058
- "val": new basic_1.FloatType(),
27060
+ "val": new basic_1.NumericGenericType(),
27059
27061
  },
27060
27062
  return: new basic_1.FloatType(),
27061
27063
  },
27062
27064
  "TANH": {
27063
27065
  counter: BuiltIn.counter++,
27064
27066
  mandatory: {
27065
- "val": new basic_1.FloatType(),
27067
+ "val": new basic_1.NumericGenericType(),
27066
27068
  },
27067
27069
  return: new basic_1.FloatType(),
27068
27070
  },
@@ -27106,7 +27108,7 @@ BuiltIn.methods = {
27106
27108
  "TRUNC": {
27107
27109
  counter: BuiltIn.counter++,
27108
27110
  mandatory: {
27109
- "val": new basic_1.FloatType(),
27111
+ "val": new basic_1.NumericGenericType(),
27110
27112
  },
27111
27113
  return: basic_1.IntegerType.get(),
27112
27114
  },
@@ -27117,9 +27119,9 @@ BuiltIn.methods = {
27117
27119
  },
27118
27120
  optional: {
27119
27121
  "days": basic_1.IntegerType.get(),
27120
- "hour": basic_1.IntegerType.get(),
27121
- "minutes": basic_1.IntegerType.get(),
27122
- "seconds": new basic_1.FloatType(),
27122
+ "hours": basic_1.IntegerType.get(),
27123
+ "minutes": new basic_1.Integer8Type(),
27124
+ "seconds": new basic_1.DecFloat34Type(),
27123
27125
  },
27124
27126
  return: new basic_1.UTCLongType(),
27125
27127
  release: version_1.Release.v754,
@@ -27135,7 +27137,7 @@ BuiltIn.methods = {
27135
27137
  "high": new basic_1.UTCLongType(),
27136
27138
  "low": new basic_1.UTCLongType(),
27137
27139
  },
27138
- return: new basic_1.FloatType(),
27140
+ return: new basic_1.DecFloat34Type(),
27139
27141
  release: version_1.Release.v754,
27140
27142
  },
27141
27143
  "XSDBOOL": {
@@ -28487,7 +28489,12 @@ class Procedural {
28487
28489
  this.scope = scope;
28488
28490
  this.reg = reg;
28489
28491
  }
28490
- addAllFormDefinitions(file, obj) {
28492
+ addAllFormDefinitions(file, obj, visited = new Set()) {
28493
+ // an include reached again through a cycle of INCLUDEs is not walked twice
28494
+ if (visited.has(file.getFilename())) {
28495
+ return;
28496
+ }
28497
+ visited.add(file.getFilename());
28491
28498
  const structure = file.getStructure();
28492
28499
  if (structure) {
28493
28500
  const input = {
@@ -28508,12 +28515,12 @@ class Procedural {
28508
28515
  for (const node of includes) {
28509
28516
  const found = this.findInclude(node, obj);
28510
28517
  if (found) {
28511
- this.addAllFormDefinitions(found, obj);
28518
+ this.addAllFormDefinitions(found, obj, visited);
28512
28519
  }
28513
28520
  }
28514
28521
  }
28515
28522
  findInclude(node, obj) {
28516
- // assumption: no cyclic includes, includes not found are reported by rule "check_include"
28523
+ // cyclic includes are cut by the callers, includes not found are reported by rule "check_include"
28517
28524
  // todo: how to make sure code is not duplicated here and in rule "check_include" / include graph?
28518
28525
  const expr = node.findFirstExpression(Expressions.IncludeName);
28519
28526
  if (expr === undefined) {
@@ -29315,7 +29322,9 @@ class TypeUtils {
29315
29322
  return false;
29316
29323
  }
29317
29324
  else if (source instanceof basic_1.Integer8Type) {
29318
- if (target instanceof basic_1.IntegerType || target instanceof basic_1.StringType) {
29325
+ if (target instanceof basic_1.IntegerType
29326
+ || target instanceof basic_1.StringType
29327
+ || target instanceof basic_1.FloatType) {
29319
29328
  return false;
29320
29329
  }
29321
29330
  }
@@ -31183,7 +31192,11 @@ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modu
31183
31192
  // On a character or byte field of fixed length the substring must lie inside the field, else it is
31184
31193
  // a syntax error. Other types, a dynamic offset or length and "*" (undefined) are left alone, as is
31185
31194
  // length 0. The offset is applied first, so the length is compared to what remains after the offset.
31195
+ // A substring of a date, time or numeric text field has type n; its bounds are not checked.
31186
31196
  function substringType(context, offset, length, node, input) {
31197
+ if (context instanceof basic_1.DateType || context instanceof basic_1.TimeType || context instanceof basic_1.NumericType) {
31198
+ return numericSubstringType(context, offset, length);
31199
+ }
31187
31200
  if (!(context instanceof basic_1.CharacterType) && !(context instanceof basic_1.HexType)) {
31188
31201
  return context;
31189
31202
  }
@@ -31206,6 +31219,24 @@ function substringType(context, offset, length, node, input) {
31206
31219
  }
31207
31220
  return context;
31208
31221
  }
31222
+ function numericSubstringType(context, offset, length) {
31223
+ const hasOffset = offset !== undefined && offset > 0;
31224
+ const hasLength = length !== undefined && length > 0;
31225
+ if (hasOffset === false && hasLength === false) {
31226
+ return context;
31227
+ }
31228
+ let remaining = context instanceof basic_1.DateType ? 8 : context instanceof basic_1.TimeType ? 6 : context.getLength();
31229
+ if (hasOffset) {
31230
+ remaining = remaining - offset;
31231
+ }
31232
+ if (hasLength) {
31233
+ remaining = Math.min(remaining, length);
31234
+ }
31235
+ if (remaining <= 0) {
31236
+ return context;
31237
+ }
31238
+ return new basic_1.NumericType(remaining);
31239
+ }
31209
31240
  // A field symbol typed "c" or "x" is generic, but its type is represented with length 1, so the
31210
31241
  // offset or length at "index" is not checked when it directly follows the field symbol
31211
31242
  function isFieldSymbolItself(children, index) {
@@ -41338,6 +41369,16 @@ class Convert {
41338
41369
  target_1.Target.runSyntax(stampTarget, input);
41339
41370
  }
41340
41371
  }
41372
+ const utclongTarget = node.findExpressionAfterToken("UTCLONG");
41373
+ if ((utclongTarget === null || utclongTarget === void 0 ? void 0 : utclongTarget.get()) instanceof Expressions.Target) {
41374
+ const inline = utclongTarget === null || utclongTarget === void 0 ? void 0 : utclongTarget.findDirectExpression(Expressions.InlineData);
41375
+ if (inline) {
41376
+ inline_data_1.InlineData.runSyntax(inline, input, new basic_1.UTCLongType());
41377
+ }
41378
+ else {
41379
+ target_1.Target.runSyntax(utclongTarget, input);
41380
+ }
41381
+ }
41341
41382
  }
41342
41383
  }
41343
41384
  exports.Convert = Convert;
@@ -50858,6 +50899,8 @@ if (Object.keys(map).length === 0) {
50858
50899
  // -----------------------------------
50859
50900
  class SyntaxLogic {
50860
50901
  constructor(reg, object) {
50902
+ // files the traversal walked into through INCLUDEs, outermost first
50903
+ this.includeStack = [];
50861
50904
  this.reg = reg;
50862
50905
  this.issues = [];
50863
50906
  this.deferred = [];
@@ -50965,11 +51008,20 @@ class SyntaxLogic {
50965
51008
  // walk into INCLUDEs
50966
51009
  if (isStatement && child.get() instanceof Statements.Include) {
50967
51010
  const file = this.helpers.proc.findInclude(child, this.object);
50968
- if (file !== undefined && file.getStructure() !== undefined) {
51011
+ // an INCLUDE that leads back to a file already being walked is not followed again
51012
+ const cyclic = file !== undefined && (file.getFilename() === this.currentFile.getFilename()
51013
+ || this.includeStack.includes(file.getFilename()));
51014
+ if (file !== undefined && file.getStructure() !== undefined && cyclic === false) {
50969
51015
  const old = this.currentFile;
51016
+ this.includeStack.push(old.getFilename());
50970
51017
  this.currentFile = file;
50971
- this.traverse(file.getStructure());
50972
- this.currentFile = old;
51018
+ try {
51019
+ this.traverse(file.getStructure());
51020
+ }
51021
+ finally {
51022
+ this.currentFile = old;
51023
+ this.includeStack.pop();
51024
+ }
50973
51025
  }
50974
51026
  }
50975
51027
  if (isStructure || isStatement) {
@@ -51379,11 +51431,46 @@ exports.ArtifactsABAP = ArtifactsABAP;
51379
51431
 
51380
51432
  "use strict";
51381
51433
 
51434
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
51435
+ if (k2 === undefined) k2 = k;
51436
+ var desc = Object.getOwnPropertyDescriptor(m, k);
51437
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
51438
+ desc = { enumerable: true, get: function() { return m[k]; } };
51439
+ }
51440
+ Object.defineProperty(o, k2, desc);
51441
+ }) : (function(o, m, k, k2) {
51442
+ if (k2 === undefined) k2 = k;
51443
+ o[k2] = m[k];
51444
+ }));
51445
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
51446
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
51447
+ }) : function(o, v) {
51448
+ o["default"] = v;
51449
+ });
51450
+ var __importStar = (this && this.__importStar) || (function () {
51451
+ var ownKeys = function(o) {
51452
+ ownKeys = Object.getOwnPropertyNames || function (o) {
51453
+ var ar = [];
51454
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
51455
+ return ar;
51456
+ };
51457
+ return ownKeys(o);
51458
+ };
51459
+ return function (mod) {
51460
+ if (mod && mod.__esModule) return mod;
51461
+ var result = {};
51462
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
51463
+ __setModuleDefault(result, mod);
51464
+ return result;
51465
+ };
51466
+ })();
51382
51467
  Object.defineProperty(exports, "__esModule", ({ value: true }));
51383
51468
  exports.CrossIncludeMacros = void 0;
51384
51469
  const _abap_object_1 = __webpack_require__(/*! ../objects/_abap_object */ "./node_modules/@abaplint/core/build/src/objects/_abap_object.js");
51385
51470
  const program_1 = __webpack_require__(/*! ../objects/program */ "./node_modules/@abaplint/core/build/src/objects/program.js");
51386
51471
  const _statement_1 = __webpack_require__(/*! ./2_statements/statements/_statement */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/_statement.js");
51472
+ const statements_1 = __webpack_require__(/*! ./2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js");
51473
+ const Expressions = __importStar(__webpack_require__(/*! ./2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
51387
51474
  const expand_macros_1 = __webpack_require__(/*! ./2_statements/expand_macros */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expand_macros.js");
51388
51475
  const include_graph_1 = __webpack_require__(/*! ../utils/include_graph */ "./node_modules/@abaplint/core/build/src/utils/include_graph.js");
51389
51476
  // Macros can be defined in one include and used in a sibling include, connected
@@ -51396,6 +51483,7 @@ class CrossIncludeMacros {
51396
51483
  this.reg = reg;
51397
51484
  }
51398
51485
  run() {
51486
+ this.reparseCyclicPrograms();
51399
51487
  const candidates = this.findCandidates();
51400
51488
  if (candidates.length === 0) {
51401
51489
  return;
@@ -51423,6 +51511,45 @@ class CrossIncludeMacros {
51423
51511
  }
51424
51512
  }
51425
51513
  //////////////////////////////
51514
+ // A program or include in an INCLUDE cycle can be parsed while the include defining its macros is still
51515
+ // being parsed, depending on the order the files were added. Everything is parsed now, so parse it again.
51516
+ reparseCyclicPrograms() {
51517
+ const config = this.reg.getConfig();
51518
+ for (const obj of this.reg.getObjects()) {
51519
+ if (obj instanceof program_1.Program && this.hasUnknown(obj) && this.isInIncludeCycle(obj)) {
51520
+ obj.setDirty();
51521
+ obj.parse(config.getRelease(), config.getSyntaxSetttings().globalMacros, this.reg, config.getLanguageVersion());
51522
+ }
51523
+ }
51524
+ }
51525
+ hasUnknown(prog) {
51526
+ return prog.getABAPFiles().some(f => f.getStatements().some(s => s.get() instanceof _statement_1.Unknown));
51527
+ }
51528
+ // the include graph does not link INCLUDEs of main programs, so follow the INCLUDEs from the program
51529
+ isInIncludeCycle(prog) {
51530
+ var _a;
51531
+ const seen = new Set();
51532
+ const stack = [prog];
51533
+ while (stack.length > 0) {
51534
+ for (const file of stack.pop().getABAPFiles()) {
51535
+ for (const statement of file.getStatements()) {
51536
+ if (!(statement.get() instanceof statements_1.Include)) {
51537
+ continue;
51538
+ }
51539
+ const name = (_a = statement.findDirectExpression(Expressions.IncludeName)) === null || _a === void 0 ? void 0 : _a.concatTokens();
51540
+ const included = this.reg.getObject("PROG", name);
51541
+ if (included === prog) {
51542
+ return true;
51543
+ }
51544
+ else if (included instanceof program_1.Program && seen.has(included) === false) {
51545
+ seen.add(included);
51546
+ stack.push(included);
51547
+ }
51548
+ }
51549
+ }
51550
+ }
51551
+ return false;
51552
+ }
51426
51553
  findCandidates() {
51427
51554
  const ret = [];
51428
51555
  for (const obj of this.reg.getObjects()) {
@@ -63196,6 +63323,7 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
63196
63323
  }
63197
63324
  constructor(name) {
63198
63325
  super(name);
63326
+ this.parsing = false;
63199
63327
  this.parsed = [];
63200
63328
  this.texts = undefined;
63201
63329
  this.rawXMLCache = undefined;
@@ -63204,11 +63332,19 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
63204
63332
  return !!x && x instanceof ABAPObject;
63205
63333
  }
63206
63334
  parse(release, globalMacros, reg, languageVersion = version_1.LanguageVersion.Normal) {
63207
- if (this.isDirty() === false) {
63335
+ // an INCLUDE that leads back to this object while it is being parsed is not followed again
63336
+ if (this.isDirty() === false || this.parsing === true) {
63208
63337
  return { updated: false, runtime: 0 };
63209
63338
  }
63210
63339
  const abapFiles = this.getFiles().filter(f => f.getFilename().endsWith(".abap"));
63211
- const result = new abap_parser_1.ABAPParser({ release, globalMacros, reg, languageVersion }).parse(abapFiles);
63340
+ let result;
63341
+ this.parsing = true;
63342
+ try {
63343
+ result = new abap_parser_1.ABAPParser({ release, globalMacros, reg, languageVersion }).parse(abapFiles);
63344
+ }
63345
+ finally {
63346
+ this.parsing = false;
63347
+ }
63212
63348
  this.parsed = result.output;
63213
63349
  this.old = result.issues;
63214
63350
  this.dirty = false;
@@ -72425,7 +72561,7 @@ class Registry {
72425
72561
  }
72426
72562
  static abaplintVersion() {
72427
72563
  // magic, see build script "version.js"
72428
- return "2.120.77";
72564
+ return "2.120.80";
72429
72565
  }
72430
72566
  getDDICReferences() {
72431
72567
  return this.ddicReferences;
@@ -88174,6 +88310,7 @@ __exportStar(__webpack_require__(/*! ./inline_data_old_versions */ "./node_modul
88174
88310
  __exportStar(__webpack_require__(/*! ./inline_packed_computation */ "./node_modules/@abaplint/core/build/src/rules/inline_packed_computation.js"), exports);
88175
88311
  __exportStar(__webpack_require__(/*! ./intf_referencing_clas */ "./node_modules/@abaplint/core/build/src/rules/intf_referencing_clas.js"), exports);
88176
88312
  __exportStar(__webpack_require__(/*! ./invalid_table_index */ "./node_modules/@abaplint/core/build/src/rules/invalid_table_index.js"), exports);
88313
+ __exportStar(__webpack_require__(/*! ./is_assigned_in_loop */ "./node_modules/@abaplint/core/build/src/rules/is_assigned_in_loop.js"), exports);
88177
88314
  __exportStar(__webpack_require__(/*! ./keep_single_parameter_on_one_line */ "./node_modules/@abaplint/core/build/src/rules/keep_single_parameter_on_one_line.js"), exports);
88178
88315
  __exportStar(__webpack_require__(/*! ./keyword_case */ "./node_modules/@abaplint/core/build/src/rules/keyword_case.js"), exports);
88179
88316
  __exportStar(__webpack_require__(/*! ./line_break_multiple_parameters */ "./node_modules/@abaplint/core/build/src/rules/line_break_multiple_parameters.js"), exports);
@@ -88239,6 +88376,7 @@ __exportStar(__webpack_require__(/*! ./prefix_is_current_class */ "./node_module
88239
88376
  __exportStar(__webpack_require__(/*! ./range_row_values */ "./node_modules/@abaplint/core/build/src/rules/range_row_values.js"), exports);
88240
88377
  __exportStar(__webpack_require__(/*! ./reduce_procedural_code */ "./node_modules/@abaplint/core/build/src/rules/reduce_procedural_code.js"), exports);
88241
88378
  __exportStar(__webpack_require__(/*! ./reduce_string_templates */ "./node_modules/@abaplint/core/build/src/rules/reduce_string_templates.js"), exports);
88379
+ __exportStar(__webpack_require__(/*! ./redundant_cast */ "./node_modules/@abaplint/core/build/src/rules/redundant_cast.js"), exports);
88242
88380
  __exportStar(__webpack_require__(/*! ./redundant_conversion */ "./node_modules/@abaplint/core/build/src/rules/redundant_conversion.js"), exports);
88243
88381
  __exportStar(__webpack_require__(/*! ./release_idoc */ "./node_modules/@abaplint/core/build/src/rules/release_idoc.js"), exports);
88244
88382
  __exportStar(__webpack_require__(/*! ./remove_descriptions */ "./node_modules/@abaplint/core/build/src/rules/remove_descriptions.js"), exports);
@@ -88923,6 +89061,258 @@ exports.InvalidTableIndex = InvalidTableIndex;
88923
89061
 
88924
89062
  /***/ },
88925
89063
 
89064
+ /***/ "./node_modules/@abaplint/core/build/src/rules/is_assigned_in_loop.js"
89065
+ /*!****************************************************************************!*\
89066
+ !*** ./node_modules/@abaplint/core/build/src/rules/is_assigned_in_loop.js ***!
89067
+ \****************************************************************************/
89068
+ (__unused_webpack_module, exports, __webpack_require__) {
89069
+
89070
+ "use strict";
89071
+
89072
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
89073
+ if (k2 === undefined) k2 = k;
89074
+ var desc = Object.getOwnPropertyDescriptor(m, k);
89075
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
89076
+ desc = { enumerable: true, get: function() { return m[k]; } };
89077
+ }
89078
+ Object.defineProperty(o, k2, desc);
89079
+ }) : (function(o, m, k, k2) {
89080
+ if (k2 === undefined) k2 = k;
89081
+ o[k2] = m[k];
89082
+ }));
89083
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
89084
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
89085
+ }) : function(o, v) {
89086
+ o["default"] = v;
89087
+ });
89088
+ var __importStar = (this && this.__importStar) || (function () {
89089
+ var ownKeys = function(o) {
89090
+ ownKeys = Object.getOwnPropertyNames || function (o) {
89091
+ var ar = [];
89092
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
89093
+ return ar;
89094
+ };
89095
+ return ownKeys(o);
89096
+ };
89097
+ return function (mod) {
89098
+ if (mod && mod.__esModule) return mod;
89099
+ var result = {};
89100
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
89101
+ __setModuleDefault(result, mod);
89102
+ return result;
89103
+ };
89104
+ })();
89105
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
89106
+ exports.IsAssignedInLoop = exports.IsAssignedInLoopConf = void 0;
89107
+ const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
89108
+ const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
89109
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
89110
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
89111
+ const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
89112
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
89113
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
89114
+ const severity_1 = __webpack_require__(/*! ../severity */ "./node_modules/@abaplint/core/build/src/severity.js");
89115
+ class IsAssignedInLoopConf extends _basic_rule_config_1.BasicRuleConfig {
89116
+ constructor() {
89117
+ super(...arguments);
89118
+ this.severity = severity_1.Severity.Warning;
89119
+ }
89120
+ }
89121
+ exports.IsAssignedInLoopConf = IsAssignedInLoopConf;
89122
+ class IsAssignedInLoop extends _abap_rule_1.ABAPRule {
89123
+ constructor() {
89124
+ super(...arguments);
89125
+ this.conf = new IsAssignedInLoopConf();
89126
+ }
89127
+ getMetadata() {
89128
+ return {
89129
+ key: "is_assigned_in_loop",
89130
+ title: "IS ASSIGNED after READ TABLE or ASSIGN in a loop",
89131
+ shortDescription: `Reports IS [NOT] ASSIGNED after a READ TABLE ... ASSIGNING or ASSIGN inside a loop, without UNASSIGN before it`,
89132
+ extendedInformation: `A failed READ TABLE ... ASSIGNING or ASSIGN keeps the previous binding of the field symbol. Inside a
89133
+ loop, the field symbol still points to the row of an earlier iteration, so IS ASSIGNED is true
89134
+ although the statement failed, and the code goes on with the wrong row.
89135
+
89136
+ Add UNASSIGN <fs> before the statement, inside the loop, or check sy-subrc after a READ TABLE.
89137
+ The quick fix inserts the UNASSIGN; it is not offered for a field symbol declared inline in
89138
+ the statement, or for a chained statement.
89139
+
89140
+ Not reported: a check that also reads sy-subrc, an ASSIGN that cannot fail (a static source
89141
+ without dereference, table expression or dynamic part), and loops outside of the
89142
+ method, form or function module of the statement. See also subrc_after_assign.`,
89143
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Quickfix],
89144
+ badExample: `LOOP AT lt_cells INTO ls_cell.
89145
+ READ TABLE lt_styles ASSIGNING <style> WITH KEY id = ls_cell-style.
89146
+ IF <style> IS ASSIGNED.
89147
+ ls_cell-format = <style>-format.
89148
+ ENDIF.
89149
+ ENDLOOP.`,
89150
+ goodExample: `LOOP AT lt_cells INTO ls_cell.
89151
+ UNASSIGN <style>.
89152
+ READ TABLE lt_styles ASSIGNING <style> WITH KEY id = ls_cell-style.
89153
+ IF <style> IS ASSIGNED.
89154
+ ls_cell-format = <style>-format.
89155
+ ENDIF.
89156
+ ENDLOOP.`,
89157
+ };
89158
+ }
89159
+ getConfig() {
89160
+ return this.conf;
89161
+ }
89162
+ setConfig(conf) {
89163
+ this.conf = conf;
89164
+ }
89165
+ runParsed(file) {
89166
+ const issues = [];
89167
+ const statements = file.getStatements();
89168
+ for (let i = 0; i < statements.length; i++) {
89169
+ const statement = statements[i];
89170
+ const name = this.boundByFailable(statement);
89171
+ if (name === undefined) {
89172
+ continue;
89173
+ }
89174
+ const fs = name.toUpperCase();
89175
+ const loop = this.innermostLoop(i, statements);
89176
+ if (loop === undefined || this.unassignedBefore(loop, i, statements, fs) === true) {
89177
+ continue;
89178
+ }
89179
+ const check = this.nextCheck(i, statements, fs);
89180
+ if (check === undefined) {
89181
+ continue;
89182
+ }
89183
+ const read = statement.get() instanceof Statements.ReadTable;
89184
+ const message = `${read ? "READ TABLE" : "ASSIGN"} in a loop keeps the previous binding of ${name} when it fails, `
89185
+ + `UNASSIGN ${name} before it` + (read ? " or check sy-subrc" : "");
89186
+ const fix = this.buildFix(file, statement, name);
89187
+ issues.push(issue_1.Issue.atStatement(file, check, message, this.getMetadata().key, this.conf.severity, fix));
89188
+ }
89189
+ return issues;
89190
+ }
89191
+ ////////////////
89192
+ /** the field symbol bound by a READ TABLE ... ASSIGNING or an ASSIGN that can fail */
89193
+ boundByFailable(statement) {
89194
+ var _a, _b, _c;
89195
+ const s = statement.get();
89196
+ if (s instanceof Statements.ReadTable) {
89197
+ const target = (_a = statement.findDirectExpression(Expressions.ReadTableTarget)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.FSTarget);
89198
+ return (_b = target === null || target === void 0 ? void 0 : target.findFirstExpression(Expressions.FieldSymbol)) === null || _b === void 0 ? void 0 : _b.concatTokens();
89199
+ }
89200
+ else if (s instanceof Statements.Assign) {
89201
+ const source = statement.findDirectExpression(Expressions.AssignSource);
89202
+ if (source === undefined) {
89203
+ return undefined;
89204
+ }
89205
+ const first = source.getFirstToken().getStr().toUpperCase();
89206
+ const failable = first === "COMPONENT"
89207
+ || first === "TABLE"
89208
+ || source.findFirstExpression(Expressions.Dynamic) !== undefined
89209
+ || source.findFirstExpression(Expressions.Dereference) !== undefined
89210
+ || source.findFirstExpression(Expressions.TableExpression) !== undefined
89211
+ || statement.findDirectTokenByText("INCREMENT") !== undefined;
89212
+ if (failable === false) {
89213
+ return undefined;
89214
+ }
89215
+ const target = statement.findDirectExpression(Expressions.FSTarget);
89216
+ return (_c = target === null || target === void 0 ? void 0 : target.findFirstExpression(Expressions.FieldSymbol)) === null || _c === void 0 ? void 0 : _c.concatTokens();
89217
+ }
89218
+ return undefined;
89219
+ }
89220
+ /** index of the innermost LOOP, DO, WHILE or SELECT loop around the statement, in the same block */
89221
+ innermostLoop(index, statements) {
89222
+ let depth = 0;
89223
+ for (let i = index - 1; i >= 0 && this.startsBlock(statements[i]) === false; i--) {
89224
+ if (this.endsLoop(statements[i])) {
89225
+ depth++;
89226
+ }
89227
+ else if (this.startsLoop(statements[i])) {
89228
+ if (depth === 0) {
89229
+ return i;
89230
+ }
89231
+ depth--;
89232
+ }
89233
+ }
89234
+ return undefined;
89235
+ }
89236
+ unassignedBefore(loop, index, statements, fs) {
89237
+ for (let i = loop + 1; i < index; i++) {
89238
+ if (statements[i].get() instanceof Statements.Unassign && this.mentions(statements[i], fs)) {
89239
+ return true;
89240
+ }
89241
+ }
89242
+ return false;
89243
+ }
89244
+ /** the first IS [NOT] ASSIGNED of the field symbol after the statement, before the end of the loop
89245
+ * or another UNASSIGN or binding of it; a check that also reads sy-subrc is fine */
89246
+ nextCheck(index, statements, fs) {
89247
+ let depth = 0;
89248
+ for (let i = index + 1; i < statements.length && this.startsBlock(statements[i]) === false; i++) {
89249
+ const statement = statements[i];
89250
+ if (this.startsLoop(statement)) {
89251
+ depth++;
89252
+ }
89253
+ else if (this.endsLoop(statement)) {
89254
+ if (depth === 0) {
89255
+ return undefined;
89256
+ }
89257
+ depth--;
89258
+ }
89259
+ const concat = statement.concatTokens().toUpperCase();
89260
+ if (concat.includes(fs + " IS ASSIGNED") || concat.includes(fs + " IS NOT ASSIGNED")) {
89261
+ return concat.includes("SY-SUBRC") ? undefined : statement;
89262
+ }
89263
+ if ((statement.get() instanceof Statements.Unassign && this.mentions(statement, fs))
89264
+ || this.binds(statement, fs)) {
89265
+ return undefined;
89266
+ }
89267
+ }
89268
+ return undefined;
89269
+ }
89270
+ mentions(statement, fs) {
89271
+ return statement.findAllExpressions(Expressions.FieldSymbol).some(e => e.concatTokens().toUpperCase() === fs);
89272
+ }
89273
+ binds(statement, fs) {
89274
+ return statement.findAllExpressions(Expressions.FSTarget)
89275
+ .some(t => { var _a; return ((_a = t.findFirstExpression(Expressions.FieldSymbol)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase()) === fs; });
89276
+ }
89277
+ startsLoop(statement) {
89278
+ const s = statement.get();
89279
+ return s instanceof Statements.Loop
89280
+ || s instanceof Statements.Do
89281
+ || s instanceof Statements.While
89282
+ || s instanceof Statements.SelectLoop;
89283
+ }
89284
+ endsLoop(statement) {
89285
+ const s = statement.get();
89286
+ return s instanceof Statements.EndLoop
89287
+ || s instanceof Statements.EndDo
89288
+ || s instanceof Statements.EndWhile
89289
+ || s instanceof Statements.EndSelect;
89290
+ }
89291
+ startsBlock(statement) {
89292
+ const s = statement.get();
89293
+ return s instanceof Statements.MethodImplementation
89294
+ || s instanceof Statements.Form
89295
+ || s instanceof Statements.FunctionModule
89296
+ || s instanceof Statements.Module
89297
+ || s instanceof Statements.EndMethod
89298
+ || s instanceof Statements.EndForm
89299
+ || s instanceof Statements.EndFunction
89300
+ || s instanceof Statements.EndModule;
89301
+ }
89302
+ /** UNASSIGN on a line of its own before the statement, with the same indentation */
89303
+ buildFix(file, statement, name) {
89304
+ if (statement.getColon() !== undefined || statement.findFirstExpression(Expressions.InlineFS) !== undefined) {
89305
+ return undefined;
89306
+ }
89307
+ const start = statement.getStart();
89308
+ return edit_helper_1.EditHelper.insertAt(file, start, `UNASSIGN ${name}.\n` + " ".repeat(start.getCol() - 1));
89309
+ }
89310
+ }
89311
+ exports.IsAssignedInLoop = IsAssignedInLoop;
89312
+ //# sourceMappingURL=is_assigned_in_loop.js.map
89313
+
89314
+ /***/ },
89315
+
88926
89316
  /***/ "./node_modules/@abaplint/core/build/src/rules/keep_single_parameter_on_one_line.js"
88927
89317
  /*!******************************************************************************************!*\
88928
89318
  !*** ./node_modules/@abaplint/core/build/src/rules/keep_single_parameter_on_one_line.js ***!
@@ -90622,7 +91012,11 @@ ENDIF.
90622
91012
  && lastChildren[1].getChildren().length === 1
90623
91013
  && lastChildren[1].getFirstToken().getStr().startsWith("-") === false
90624
91014
  && lastChildren[2].getFirstToken().getStr() === ")") {
90625
- const issue = issue_1.Issue.atToken(file, lastChildren[0].getFirstToken(), "Too many parentheses", this.getMetadata().key, this.conf.severity);
91015
+ const fixText = lastChildren[1].concatTokens();
91016
+ const start = lastChildren[0].getFirstToken().getStart();
91017
+ const end = lastChildren[2].getLastToken().getEnd();
91018
+ const fix = edit_helper_1.EditHelper.replaceRange(file, start, end, fixText);
91019
+ const issue = issue_1.Issue.atToken(file, lastChildren[0].getFirstToken(), "Too many parentheses", this.getMetadata().key, this.conf.severity, fix);
90626
91020
  issues.push(issue);
90627
91021
  }
90628
91022
  }
@@ -90751,6 +91145,7 @@ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/co
90751
91145
  const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
90752
91146
  const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
90753
91147
  const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
91148
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
90754
91149
  class MaxOneMethodParameterPerLineConf extends _basic_rule_config_1.BasicRuleConfig {
90755
91150
  }
90756
91151
  exports.MaxOneMethodParameterPerLineConf = MaxOneMethodParameterPerLineConf;
@@ -90764,7 +91159,7 @@ class MaxOneMethodParameterPerLine extends _abap_rule_1.ABAPRule {
90764
91159
  key: "max_one_method_parameter_per_line",
90765
91160
  title: "Max one method parameter definition per line",
90766
91161
  shortDescription: `Keep max one method parameter description per line`,
90767
- tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Whitespace],
91162
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix],
90768
91163
  badExample: `
90769
91164
  METHODS apps_scope_token
90770
91165
  IMPORTING
@@ -90793,7 +91188,8 @@ METHODS apps_scope_token
90793
91188
  continue;
90794
91189
  }
90795
91190
  if (prev.getFirstToken().getStart().getRow() === p.getFirstToken().getStart().getRow()) {
90796
- const issue = issue_1.Issue.atToken(file, prev.getFirstToken(), this.getMetadata().title, this.getMetadata().key, this.conf.severity);
91191
+ const fix = this.buildFix(file, statement, p);
91192
+ const issue = issue_1.Issue.atToken(file, prev.getFirstToken(), this.getMetadata().title, this.getMetadata().key, this.conf.severity, fix);
90797
91193
  issues.push(issue);
90798
91194
  }
90799
91195
  prev = p;
@@ -90801,8 +91197,32 @@ METHODS apps_scope_token
90801
91197
  }
90802
91198
  return issues;
90803
91199
  }
91200
+ /** moves the parameter, or its preceding section keyword, to a new line */
91201
+ buildFix(file, statement, param) {
91202
+ const tokens = statement.getTokens();
91203
+ const index = tokens.indexOf(param.getFirstToken());
91204
+ if (index < 1) {
91205
+ return undefined;
91206
+ }
91207
+ let target = tokens[index];
91208
+ let indent = statement.findFirstExpression(Expressions.MethodParam).getFirstToken().getStart().getCol();
91209
+ const before = tokens[index - 1];
91210
+ if (MaxOneMethodParameterPerLine.SECTIONS.includes(before.getStr().toUpperCase())) {
91211
+ if (index < 2) {
91212
+ return undefined;
91213
+ }
91214
+ target = before;
91215
+ indent = tokens.find(t => MaxOneMethodParameterPerLine.SECTIONS.includes(t.getStr().toUpperCase())).getStart().getCol();
91216
+ }
91217
+ const previous = tokens[tokens.indexOf(target) - 1];
91218
+ if (previous.getEnd().getRow() !== target.getStart().getRow()) {
91219
+ return undefined;
91220
+ }
91221
+ return edit_helper_1.EditHelper.replaceRange(file, previous.getEnd(), target.getStart(), "\n" + " ".repeat(indent - 1));
91222
+ }
90804
91223
  }
90805
91224
  exports.MaxOneMethodParameterPerLine = MaxOneMethodParameterPerLine;
91225
+ MaxOneMethodParameterPerLine.SECTIONS = ["IMPORTING", "EXPORTING", "CHANGING", "RETURNING"];
90806
91226
  //# sourceMappingURL=max_one_method_parameter_per_line.js.map
90807
91227
 
90808
91228
  /***/ },
@@ -92214,6 +92634,8 @@ const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@ab
92214
92634
  const sequential_blank_1 = __webpack_require__(/*! ./sequential_blank */ "./node_modules/@abaplint/core/build/src/rules/sequential_blank.js");
92215
92635
  const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
92216
92636
  const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
92637
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
92638
+ const position_1 = __webpack_require__(/*! ../position */ "./node_modules/@abaplint/core/build/src/position.js");
92217
92639
  var NewlineLogic;
92218
92640
  (function (NewlineLogic) {
92219
92641
  NewlineLogic["Exact"] = "exact";
@@ -92243,7 +92665,7 @@ class NewlineBetweenMethods extends _abap_rule_1.ABAPRule {
92243
92665
  key: "newline_between_methods",
92244
92666
  title: "New line between methods",
92245
92667
  shortDescription: `Checks for newlines between method implementations.`,
92246
- tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.SingleFile],
92668
+ tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.SingleFile],
92247
92669
  };
92248
92670
  }
92249
92671
  getMessage() {
@@ -92272,18 +92694,35 @@ class NewlineBetweenMethods extends _abap_rule_1.ABAPRule {
92272
92694
  continue;
92273
92695
  }
92274
92696
  let counter = 0;
92275
- while (sequential_blank_1.SequentialBlank.isBlankOrWhitespace(rows[nextRow]) && (counter <= this.conf.count + 1)) {
92697
+ while (sequential_blank_1.SequentialBlank.isBlankOrWhitespace(rows[nextRow])) {
92276
92698
  counter++;
92277
92699
  nextRow++;
92278
92700
  }
92279
92701
  if ((counter !== this.conf.count && this.conf.logic === NewlineLogic.Exact)
92280
92702
  || (counter >= this.conf.count && this.conf.logic === NewlineLogic.Less)
92281
92703
  || counter === 0) {
92282
- issues.push(issue_1.Issue.atStatement(file, statement, this.getMessage(), this.getMetadata().key, this.conf.severity));
92704
+ const fix = this.buildFix(file, rows, statement.getStart().getRow(), counter);
92705
+ issues.push(issue_1.Issue.atStatement(file, statement, this.getMessage(), this.getMetadata().key, this.conf.severity, fix));
92283
92706
  }
92284
92707
  }
92285
92708
  return issues;
92286
92709
  }
92710
+ buildFix(file, rows, row, blanks) {
92711
+ let target = this.conf.count;
92712
+ if (this.conf.logic === NewlineLogic.Less) {
92713
+ target = blanks === 0 ? 1 : this.conf.count - 1;
92714
+ }
92715
+ if (blanks < target) {
92716
+ const end = new position_1.Position(row, rows[row - 1].length + 1);
92717
+ return edit_helper_1.EditHelper.insertAt(file, end, "\n".repeat(target - blanks));
92718
+ }
92719
+ else if (blanks > target) {
92720
+ const start = new position_1.Position(row + target, rows[row + target - 1].length + 1);
92721
+ const end = new position_1.Position(row + blanks, rows[row + blanks - 1].length + 1);
92722
+ return edit_helper_1.EditHelper.deleteRange(file, start, end);
92723
+ }
92724
+ return undefined;
92725
+ }
92287
92726
  isConfigurationValid() {
92288
92727
  if (this.conf.count < 1 || (this.conf.count === 1 && this.conf.logic === NewlineLogic.Less)) {
92289
92728
  return false;
@@ -97208,7 +97647,7 @@ class PreferPragmas extends _abap_rule_1.ABAPRule {
97208
97647
  return {
97209
97648
  key: "prefer_pragmas",
97210
97649
  title: "prefer pragmas over pseudo comments ",
97211
- shortDescription: `prefer pragmas over pseudo comments `,
97650
+ shortDescription: `prefer pragmas over pseudo comments`,
97212
97651
  extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-pragmas-to-pseudo-comments`,
97213
97652
  tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Styleguide],
97214
97653
  badExample: `DATA foo1 TYPE i. "#EC NEEDED`,
@@ -98725,6 +99164,173 @@ exports.ReduceStringTemplates = ReduceStringTemplates;
98725
99164
 
98726
99165
  /***/ },
98727
99166
 
99167
+ /***/ "./node_modules/@abaplint/core/build/src/rules/redundant_cast.js"
99168
+ /*!***********************************************************************!*\
99169
+ !*** ./node_modules/@abaplint/core/build/src/rules/redundant_cast.js ***!
99170
+ \***********************************************************************/
99171
+ (__unused_webpack_module, exports, __webpack_require__) {
99172
+
99173
+ "use strict";
99174
+
99175
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
99176
+ if (k2 === undefined) k2 = k;
99177
+ var desc = Object.getOwnPropertyDescriptor(m, k);
99178
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
99179
+ desc = { enumerable: true, get: function() { return m[k]; } };
99180
+ }
99181
+ Object.defineProperty(o, k2, desc);
99182
+ }) : (function(o, m, k, k2) {
99183
+ if (k2 === undefined) k2 = k;
99184
+ o[k2] = m[k];
99185
+ }));
99186
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
99187
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
99188
+ }) : function(o, v) {
99189
+ o["default"] = v;
99190
+ });
99191
+ var __importStar = (this && this.__importStar) || (function () {
99192
+ var ownKeys = function(o) {
99193
+ ownKeys = Object.getOwnPropertyNames || function (o) {
99194
+ var ar = [];
99195
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
99196
+ return ar;
99197
+ };
99198
+ return ownKeys(o);
99199
+ };
99200
+ return function (mod) {
99201
+ if (mod && mod.__esModule) return mod;
99202
+ var result = {};
99203
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
99204
+ __setModuleDefault(result, mod);
99205
+ return result;
99206
+ };
99207
+ })();
99208
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
99209
+ exports.RedundantCast = exports.RedundantCastConf = void 0;
99210
+ const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/expressions */ "./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js"));
99211
+ const _reference_1 = __webpack_require__(/*! ../abap/5_syntax/_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
99212
+ const syntax_1 = __webpack_require__(/*! ../abap/5_syntax/syntax */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/syntax.js");
99213
+ const nodes_1 = __webpack_require__(/*! ../abap/nodes */ "./node_modules/@abaplint/core/build/src/abap/nodes/index.js");
99214
+ const _typed_identifier_1 = __webpack_require__(/*! ../abap/types/_typed_identifier */ "./node_modules/@abaplint/core/build/src/abap/types/_typed_identifier.js");
99215
+ const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js");
99216
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
99217
+ const _abap_object_1 = __webpack_require__(/*! ../objects/_abap_object */ "./node_modules/@abaplint/core/build/src/objects/_abap_object.js");
99218
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
99219
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
99220
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
99221
+ const version_1 = __webpack_require__(/*! ../version */ "./node_modules/@abaplint/core/build/src/version.js");
99222
+ class RedundantCastConf extends _basic_rule_config_1.BasicRuleConfig {
99223
+ }
99224
+ exports.RedundantCastConf = RedundantCastConf;
99225
+ class RedundantCast {
99226
+ constructor() {
99227
+ this.conf = new RedundantCastConf();
99228
+ }
99229
+ getMetadata() {
99230
+ return {
99231
+ key: "redundant_cast",
99232
+ title: "Redundant Cast",
99233
+ shortDescription: `Find redundant CAST expressions`,
99234
+ extendedInformation: `Reports CAST expressions whose operand is already a reference to the cast's target class or interface.`,
99235
+ tags: [_irule_1.RuleTag.Quickfix],
99236
+ badExample: `DATA ref TYPE REF TO lcl.
99237
+ DATA(copy) = CAST lcl( ref ).`,
99238
+ goodExample: `DATA ref TYPE REF TO lcl.
99239
+ DATA(copy) = ref.`,
99240
+ };
99241
+ }
99242
+ getConfig() {
99243
+ return this.conf;
99244
+ }
99245
+ setConfig(conf) {
99246
+ this.conf = conf;
99247
+ }
99248
+ initialize(reg) {
99249
+ this.reg = reg;
99250
+ return this;
99251
+ }
99252
+ run(obj) {
99253
+ var _a;
99254
+ if (!(0, version_1.releaseAtLeast)(this.reg.getConfig().getRelease(), version_1.Release.v740sp02)
99255
+ && !this.reg.getConfig().isOpenABAP()) {
99256
+ return [];
99257
+ }
99258
+ if (!(obj instanceof _abap_object_1.ABAPObject)) {
99259
+ return [];
99260
+ }
99261
+ const syntax = new syntax_1.SyntaxLogic(this.reg, obj).run();
99262
+ if (syntax.issues.length > 0) {
99263
+ return [];
99264
+ }
99265
+ const issues = [];
99266
+ for (const file of obj.getABAPFiles()) {
99267
+ const structure = file.getStructure();
99268
+ if (structure === undefined) {
99269
+ continue;
99270
+ }
99271
+ for (const cast of structure.findAllExpressionsRecursive(Expressions.Cast)) {
99272
+ const typeExpression = cast.findDirectExpression(Expressions.TypeNameOrInfer);
99273
+ const source = cast.findDirectExpression(Expressions.Source);
99274
+ if (typeExpression === undefined
99275
+ || source === undefined
99276
+ || cast.findDirectExpression(Expressions.Let) !== undefined) {
99277
+ continue;
99278
+ }
99279
+ const scope = syntax.spaghetti.lookupPosition(cast.getFirstToken().getStart(), file.getFilename());
99280
+ if (scope === undefined) {
99281
+ continue;
99282
+ }
99283
+ const target = (_a = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.InferredType
99284
+ && reference.position.getStart().equals(typeExpression.getFirstToken().getStart()))) === null || _a === void 0 ? void 0 : _a.resolved;
99285
+ if (!(target instanceof _typed_identifier_1.TypedIdentifier)) {
99286
+ continue;
99287
+ }
99288
+ const operandType = this.sourceType(source, scope);
99289
+ if (operandType === undefined || this.sameType(target.getType(), operandType) === false) {
99290
+ continue;
99291
+ }
99292
+ const closingParen = cast.getDirectTokens().find(token => token.getStr() === ")" && token.getStart().isAfter(source.getLastToken().getStart()));
99293
+ if (closingParen === undefined) {
99294
+ continue;
99295
+ }
99296
+ const fix = edit_helper_1.EditHelper.replaceRange(file, cast.getFirstToken().getStart(), closingParen.getEnd(), source.concatTokens());
99297
+ issues.push(issue_1.Issue.atRange(file, cast.getFirstToken().getStart(), closingParen.getEnd(), "Redundant CAST expression", this.getMetadata().key, this.conf.severity, fix));
99298
+ }
99299
+ }
99300
+ return issues;
99301
+ }
99302
+ /** The type of a plain variable or attribute, undefined for anything more complex */
99303
+ sourceType(source, scope) {
99304
+ var _a;
99305
+ const children = source.getChildren();
99306
+ if (children.length !== 1 || !(children[0].get() instanceof Expressions.FieldChain)) {
99307
+ return undefined;
99308
+ }
99309
+ const fieldChain = children[0];
99310
+ const last = fieldChain.getLastChild();
99311
+ if (!(last instanceof nodes_1.ExpressionNode)
99312
+ || !(last.get() instanceof Expressions.SourceField || last.get() instanceof Expressions.AttributeName)) {
99313
+ return undefined;
99314
+ }
99315
+ const operand = (_a = scope.getData().references.find(reference => reference.referenceType === _reference_1.ReferenceType.DataReadReference
99316
+ && reference.position.getStart().equals(last.getFirstToken().getStart()))) === null || _a === void 0 ? void 0 : _a.resolved;
99317
+ if (!(operand instanceof _typed_identifier_1.TypedIdentifier)) {
99318
+ return undefined;
99319
+ }
99320
+ return operand.getType();
99321
+ }
99322
+ sameType(first, second) {
99323
+ if (!(first instanceof basic_1.ObjectReferenceType) || !(second instanceof basic_1.ObjectReferenceType)) {
99324
+ return false;
99325
+ }
99326
+ return first.getIdentifierName().toUpperCase() === second.getIdentifierName().toUpperCase();
99327
+ }
99328
+ }
99329
+ exports.RedundantCast = RedundantCast;
99330
+ //# sourceMappingURL=redundant_cast.js.map
99331
+
99332
+ /***/ },
99333
+
98728
99334
  /***/ "./node_modules/@abaplint/core/build/src/rules/redundant_conversion.js"
98729
99335
  /*!*****************************************************************************!*\
98730
99336
  !*** ./node_modules/@abaplint/core/build/src/rules/redundant_conversion.js ***!
@@ -98930,9 +99536,9 @@ text = text.`,
98930
99536
  context = this.infer(context, this.sourceType(child, scope));
98931
99537
  }
98932
99538
  else if (child.get() instanceof Expressions.ArithOperator) {
98933
- if (child.concatTokens() === "**") {
98934
- context = new basic_1.FloatType();
98935
- }
99539
+ // the CONV sets the calculation type of arithmetic expressions, only redundant
99540
+ // if the assignment target has the same type, see arithmeticUsesSameTargetType
99541
+ return undefined;
98936
99542
  }
98937
99543
  else {
98938
99544
  return undefined;
@@ -107611,7 +108217,6 @@ const position_1 = __webpack_require__(/*! ../position */ "./node_modules/@abapl
107611
108217
  const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
107612
108218
  const _abap_object_1 = __webpack_require__(/*! ../objects/_abap_object */ "./node_modules/@abaplint/core/build/src/objects/_abap_object.js");
107613
108219
  const severity_1 = __webpack_require__(/*! ../severity */ "./node_modules/@abaplint/core/build/src/severity.js");
107614
- // todo, check for cycles/circular dependencies, method findTop
107615
108220
  // todo, add configurable error for multiple use includes
107616
108221
  const FMXXINCLUDE = /^(\/\w+\/)?L.+XX$/;
107617
108222
  function getABAPObjects(reg) {
@@ -107647,11 +108252,33 @@ class Graph {
107647
108252
  }
107648
108253
  this.edges[from.filename].push(toFilename);
107649
108254
  }
107650
- findTop(filename) {
108255
+ // true if "to" is reachable from "from" via the edges, "from" itself counts
108256
+ isReachable(from, to) {
108257
+ const seen = new Set();
108258
+ const stack = [from];
108259
+ while (stack.length > 0) {
108260
+ const current = stack.pop();
108261
+ if (current === to) {
108262
+ return true;
108263
+ }
108264
+ if (seen.has(current) === false) {
108265
+ seen.add(current);
108266
+ stack.push(...this.edges[current] || []);
108267
+ }
108268
+ }
108269
+ return false;
108270
+ }
108271
+ findTop(filename, path = new Set()) {
107651
108272
  const ret = [];
108273
+ path.add(filename);
107652
108274
  for (const to of this.edges[filename] || []) {
107653
- ret.push(...this.findTop(to));
108275
+ // an INCLUDE cycle, the file is already on the current path
108276
+ if (path.has(to)) {
108277
+ continue;
108278
+ }
108279
+ ret.push(...this.findTop(to, path));
107654
108280
  }
108281
+ path.delete(filename);
107655
108282
  if (ret.length === 0) {
107656
108283
  const found = this.findVertexByFilename(filename);
107657
108284
  if (found !== undefined) {
@@ -107706,6 +108333,7 @@ class IncludeGraph {
107706
108333
  ///////////////////////////////
107707
108334
  build() {
107708
108335
  this.addVertices();
108336
+ const included = [];
107709
108337
  for (const o of getABAPObjects(this.reg)) {
107710
108338
  for (const f of o.getABAPFiles()) {
107711
108339
  if (f.getFilename().includes(".prog.screen_") || f.getFilename().includes(".fugr.screen_")) {
@@ -107736,11 +108364,19 @@ class IncludeGraph {
107736
108364
  }
107737
108365
  else {
107738
108366
  this.graph.addEdge(found, f.getFilename());
108367
+ included.push({ file: f, statement: s, vertex: found, name });
107739
108368
  }
107740
108369
  }
107741
108370
  }
107742
108371
  }
107743
108372
  }
108373
+ // cycles are not followed, but ABAP rejects them, so report them
108374
+ for (const i of included) {
108375
+ if (this.graph.isReachable(i.file.getFilename(), i.vertex.filename)) {
108376
+ const issue = issue_1.Issue.atStatement(i.file, i.statement, "Cyclic INCLUDE, " + i.name, new check_include_1.CheckInclude().getMetadata().key, this.severity);
108377
+ this.issues.push(issue);
108378
+ }
108379
+ }
107744
108380
  }
107745
108381
  addVertices() {
107746
108382
  for (const o of getABAPObjects(this.reg)) {
@@ -112454,7 +113090,7 @@ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/tr
112454
113090
  class ParameterNameTranspiler {
112455
113091
  transpile(node, traversal) {
112456
113092
  const nameToken = node.getFirstToken();
112457
- const name = traversal_1.Traversal.escapeNamespace(nameToken.getStr().toLowerCase());
113093
+ const name = traversal_1.Traversal.escapeNamespace(nameToken.getStr().toLowerCase().replace(/^!/, ""));
112458
113094
  return new chunk_1.Chunk().append(name, nameToken, traversal);
112459
113095
  }
112460
113096
  }
@@ -112478,7 +113114,7 @@ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/tr
112478
113114
  class ParameterSTranspiler {
112479
113115
  transpile(node, traversal) {
112480
113116
  const nameToken = node.findDirectExpression(core_1.Expressions.ParameterName)?.getFirstToken();
112481
- const name = nameToken?.getStr().toLowerCase();
113117
+ const name = nameToken?.getStr().toLowerCase().replace(/^!/, "");
112482
113118
  const source = traversal.traverse(node.findDirectExpression(core_1.Expressions.Source));
112483
113119
  return new chunk_1.Chunk().append(name + ": ", nameToken || node, traversal).appendChunk(source);
112484
113120
  }
@@ -112503,7 +113139,7 @@ const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/tr
112503
113139
  class ParameterTTranspiler {
112504
113140
  transpile(node, traversal) {
112505
113141
  const nameToken = node.findDirectExpression(core_1.Expressions.ParameterName)?.getFirstToken();
112506
- const name = nameToken?.getStr();
113142
+ const name = nameToken?.getStr().replace(/^!/, "");
112507
113143
  const source = traversal.traverse(node.findDirectExpression(core_1.Expressions.Target));
112508
113144
  return new chunk_1.Chunk().append(name + ": ", nameToken || node, traversal).appendChunk(source);
112509
113145
  }
@@ -119607,46 +120243,34 @@ exports.ConvertTranspiler = void 0;
119607
120243
  const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_modules/@abaplint/core/build/src/index.js"));
119608
120244
  const expressions_1 = __webpack_require__(/*! ../expressions */ "./node_modules/@abaplint/transpiler/build/src/expressions/index.js");
119609
120245
  const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
120246
+ const OPERANDS = ["date", "time", "stamp", "utclong", "zone", "daylight"];
119610
120247
  class ConvertTranspiler {
119611
120248
  transpile(node, traversal) {
119612
- const source = [];
119613
- const target = [];
119614
- const date = node.findExpressionAfterToken("DATE");
119615
- if (date?.get() instanceof abaplint.Expressions.Source) {
119616
- source.push("date: " + new expressions_1.SourceTranspiler().transpile(date, traversal).getCode());
119617
- }
119618
- else if (date?.get() instanceof abaplint.Expressions.Target) {
119619
- target.push("date: " + new expressions_1.TargetTranspiler().transpile(date, traversal).getCode());
119620
- }
119621
- const time = node.findExpressionAfterToken("TIME");
119622
- if (time?.get() instanceof abaplint.Expressions.Source) {
119623
- source.push("time: " + new expressions_1.SourceTranspiler().transpile(time, traversal).getCode());
119624
- }
119625
- else if (time?.get() instanceof abaplint.Expressions.Target) {
119626
- target.push("time: " + new expressions_1.TargetTranspiler().transpile(time, traversal).getCode());
119627
- }
119628
- const stamp = node.findExpressionAfterToken("STAMP");
119629
- if (stamp?.get() instanceof abaplint.Expressions.Source) {
119630
- source.push("stamp: " + new expressions_1.SourceTranspiler().transpile(stamp, traversal).getCode());
119631
- }
119632
- else if (stamp?.get() instanceof abaplint.Expressions.Target) {
119633
- target.push("stamp: " + new expressions_1.TargetTranspiler().transpile(stamp, traversal).getCode());
119634
- }
119635
- const utclong = node.findExpressionAfterToken("UTCLONG");
119636
- if (utclong?.get() instanceof abaplint.Expressions.Source) {
119637
- source.push("utclong: " + new expressions_1.SourceTranspiler().transpile(utclong, traversal).getCode());
119638
- }
119639
- else if (utclong?.get() instanceof abaplint.Expressions.Target) {
119640
- target.push("utclong: " + new expressions_1.TargetTranspiler().transpile(utclong, traversal).getCode());
119641
- }
119642
- const zone = node.findExpressionAfterToken("ZONE");
119643
- if (zone?.get() instanceof abaplint.Expressions.Source) {
119644
- source.push("zone: " + new expressions_1.SourceTranspiler().transpile(zone, traversal).getCode());
119645
- }
119646
- else if (zone?.get() instanceof abaplint.Expressions.Target) {
119647
- target.push("zone: " + new expressions_1.TargetTranspiler().transpile(zone, traversal).getCode());
120249
+ const source = {};
120250
+ const target = {};
120251
+ // each operand is named by the keyword in front of it; "TIME" after "SAVING" is the
120252
+ // daylight saving flag, which may come before or after the TIME operand
120253
+ const children = node.getChildren();
120254
+ for (let i = 1; i < children.length; i++) {
120255
+ const child = children[i];
120256
+ if (!(child instanceof abaplint.Nodes.ExpressionNode)) {
120257
+ continue;
120258
+ }
120259
+ const keyword = children[i - 1].concatTokens().toUpperCase();
120260
+ const before = i >= 2 ? children[i - 2].concatTokens().toUpperCase() : "";
120261
+ const name = keyword === "TIME" && before === "SAVING" ? "daylight" : keyword.toLowerCase();
120262
+ if (OPERANDS.includes(name) === false || source[name] !== undefined || target[name] !== undefined) {
120263
+ continue;
120264
+ }
120265
+ if (child.get() instanceof abaplint.Expressions.Source) {
120266
+ source[name] = new expressions_1.SourceTranspiler().transpile(child, traversal).getCode();
120267
+ }
120268
+ else if (child.get() instanceof abaplint.Expressions.Target) {
120269
+ target[name] = new expressions_1.TargetTranspiler().transpile(child, traversal).getCode();
120270
+ }
119648
120271
  }
119649
- return new chunk_1.Chunk(`abap.statements.convert({${source.join(",")}}, {${target.join(",")}});`);
120272
+ const list = (operands) => OPERANDS.filter(n => operands[n] !== undefined).map(n => n + ": " + operands[n]).join(",");
120273
+ return new chunk_1.Chunk(`abap.statements.convert({${list(source)}}, {${list(target)}});`);
119650
120274
  }
119651
120275
  }
119652
120276
  exports.ConvertTranspiler = ConvertTranspiler;
@@ -130453,7 +131077,7 @@ class Traversal {
130453
131077
  return false;
130454
131078
  }
130455
131079
  prefixAndName(t, filename) {
130456
- let name = t.getStr().toLowerCase();
131080
+ let name = t.getStr().toLowerCase().replace(/^!/, "");
130457
131081
  if (filename && this.getCurrentObject().getABAPFileByName(filename) === undefined) {
130458
131082
  // the prefix is from a different object
130459
131083
  const file = this.reg.getFileByName(filename);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler-cli",
3
- "version": "2.14.5",
3
+ "version": "2.14.7",
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.77",
31
- "@abaplint/transpiler": "^2.14.5",
30
+ "@abaplint/core": "^2.120.80",
31
+ "@abaplint/transpiler": "^2.14.7",
32
32
  "@types/glob": "^9.0.0",
33
33
  "@types/node": "^26.6.2",
34
34
  "@types/progress": "^2.0.7",