@abaplint/cli 2.119.58 → 2.119.60

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/cli.js +207 -117
  2. package/package.json +2 -2
package/build/cli.js CHANGED
@@ -22,6 +22,37 @@ const ModeStr = 3;
22
22
  const ModeTemplate = 4;
23
23
  const ModeComment = 5;
24
24
  const ModePragma = 6;
25
+ // character codes, used for integer comparisons in the hot loop
26
+ const EOF = -1; // no character (start/end of file)
27
+ const CH_TAB = 9; // "\t"
28
+ const CH_NL = 10; // "\n"
29
+ const CH_SPACE = 32; // " "
30
+ const CH_DQUOTE = 34; // "\""
31
+ const CH_HASH = 35; // "#"
32
+ const CH_QUOTE = 39; // "'"
33
+ const CH_STAR = 42; // "*"
34
+ const CH_DASH = 45; // "-"
35
+ const CH_COMMA = 44; // ","
36
+ const CH_DOT = 46; // "."
37
+ const CH_COLON = 58; // ":"
38
+ const CH_EQUALS = 61; // "="
39
+ const CH_GT = 62; // ">"
40
+ const CH_AT = 64; // "@"
41
+ const CH_BACKSLASH = 92; // "\\"
42
+ const CH_BACKTICK = 96; // "`"
43
+ const CH_LBRACE = 123; // "{"
44
+ const CH_PIPE = 124; // "|"
45
+ const CH_RBRACE = 125; // "}"
46
+ // characters that terminate the current token
47
+ const SPLITS = new Set([
48
+ CH_SPACE, CH_COLON, CH_DOT, CH_COMMA, CH_DASH, 43 /* + */, 40 /* ( */,
49
+ 41 /* ) */, 91 /* [ */, 93 /* ] */, CH_BACKSLASH, CH_TAB, CH_NL
50
+ ]);
51
+ // single characters that are emitted as their own token
52
+ const BUFS = new Set([
53
+ CH_DOT, CH_COMMA, CH_COLON, 40 /* ( */, 41 /* ) */, 91 /* [ */,
54
+ 93 /* ] */, 43 /* + */, CH_AT
55
+ ]);
25
56
  class Lexer {
26
57
  run(file, virtual) {
27
58
  this.virtual = virtual;
@@ -36,15 +67,17 @@ class Lexer {
36
67
  const col = this.stream.getCol();
37
68
  const row = this.stream.getRow();
38
69
  let whiteBefore = false;
39
- if (this.stream.getOffset() - s.length >= 0) {
40
- const prev = this.stream.getRaw().substr(this.stream.getOffset() - s.length, 1);
41
- if (prev === " " || prev === "\n" || prev === "\t" || prev === ":") {
70
+ const beforeOffset = this.stream.getOffset() - s.length;
71
+ if (beforeOffset >= 0) {
72
+ const prev = this.stream.charCodeAt(beforeOffset);
73
+ if (prev === CH_SPACE || prev === CH_NL || prev === CH_TAB || prev === CH_COLON) {
42
74
  whiteBefore = true;
43
75
  }
44
76
  }
45
77
  let whiteAfter = false;
46
78
  const next = this.stream.nextChar();
47
- if (next === " " || next === "\n" || next === "\t" || next === ":" || next === "," || next === "." || next === "" || next === "\"") {
79
+ if (next === CH_SPACE || next === CH_NL || next === CH_TAB || next === CH_COLON
80
+ || next === CH_COMMA || next === CH_DOT || next === EOF || next === CH_DQUOTE) {
48
81
  whiteAfter = true;
49
82
  }
50
83
  let pos = new position_1.Position(row, col - s.length);
@@ -214,10 +247,10 @@ class Lexer {
214
247
  }
215
248
  }
216
249
  if (tok === undefined && this.m === ModeNormal && s.charAt(0) === "\\") {
217
- const adj = this.stream.nextChar() === "" ? 1 : 0;
250
+ const adj = this.stream.nextChar() === EOF ? 1 : 0;
218
251
  const prevOffset = this.stream.getOffset() - s.length - adj;
219
- const prevChar = prevOffset >= 0 ? this.stream.getRaw().substr(prevOffset, 1) : "";
220
- const whiteBeforeBackslash = prevChar === " " || prevChar === "\n" || prevChar === "\t" || prevChar === ":";
252
+ const prevChar = this.stream.charCodeAt(prevOffset);
253
+ const whiteBeforeBackslash = prevChar === CH_SPACE || prevChar === CH_NL || prevChar === CH_TAB || prevChar === CH_COLON;
221
254
  if (!whiteBeforeBackslash) {
222
255
  tok = new tokens_1.AssociationName(pos, s);
223
256
  }
@@ -230,100 +263,77 @@ class Lexer {
230
263
  this.buffer.clear();
231
264
  }
232
265
  process(raw) {
233
- this.stream = new lexer_stream_1.LexerStream(raw.replace(/\r/g, ""));
234
- this.buffer = new lexer_buffer_1.LexerBuffer();
235
- const splits = {};
236
- splits[" "] = true;
237
- splits[":"] = true;
238
- splits["."] = true;
239
- splits[","] = true;
240
- splits["-"] = true;
241
- splits["+"] = true;
242
- splits["("] = true;
243
- splits[")"] = true;
244
- splits["["] = true;
245
- splits["]"] = true;
246
- splits["\\"] = true;
247
- splits["\t"] = true;
248
- splits["\n"] = true;
249
- const bufs = {};
250
- bufs["."] = true;
251
- bufs[","] = true;
252
- bufs[":"] = true;
253
- bufs["("] = true;
254
- bufs[")"] = true;
255
- bufs["["] = true;
256
- bufs["]"] = true;
257
- bufs["+"] = true;
258
- bufs["@"] = true;
266
+ const stream = new lexer_stream_1.LexerStream(raw.replace(/\r/g, ""));
267
+ this.stream = stream;
268
+ this.buffer = new lexer_buffer_1.LexerBuffer(stream.getRaw());
259
269
  for (;;) {
260
- const current = this.stream.currentChar();
261
- const buf = this.buffer.add(current);
262
- const ahead = this.stream.nextChar();
263
- const aahead = this.stream.nextNextChar();
270
+ const current = stream.currentChar();
271
+ this.buffer.add(stream.getOffset());
272
+ const ahead = stream.nextChar();
273
+ const aahead = stream.nextNextChar();
264
274
  if (this.m === ModeNormal) {
265
- if (splits[ahead]) {
275
+ if (SPLITS.has(ahead)) {
266
276
  this.add();
267
277
  }
268
- else if (ahead === "'") {
278
+ else if (ahead === CH_QUOTE) {
269
279
  // start string
270
280
  this.add();
271
281
  this.m = ModeStr;
272
282
  }
273
- else if (ahead === "|" || ahead === "}") {
283
+ else if (ahead === CH_PIPE || ahead === CH_RBRACE) {
274
284
  // start template
275
285
  this.add();
276
286
  this.m = ModeTemplate;
277
287
  }
278
- else if (ahead === "`") {
288
+ else if (ahead === CH_BACKTICK) {
279
289
  // start ping
280
290
  this.add();
281
291
  this.m = ModePing;
282
292
  }
283
- else if (aahead === "##") {
293
+ else if (ahead === CH_HASH && aahead === CH_HASH) {
284
294
  // start pragma
285
295
  this.add();
286
296
  this.m = ModePragma;
287
297
  }
288
- else if (ahead === "\""
289
- || (ahead === "*" && current === "\n")) {
298
+ else if (ahead === CH_DQUOTE
299
+ || (ahead === CH_STAR && current === CH_NL)) {
290
300
  // start comment
291
301
  this.add();
292
302
  this.m = ModeComment;
293
303
  }
294
- else if (ahead === "@" && buf.trim().length === 0) {
304
+ else if (ahead === CH_AT && this.buffer.get().trim().length === 0) {
295
305
  this.add();
296
306
  }
297
- else if (aahead === "->"
298
- || aahead === "=>") {
307
+ else if ((ahead === CH_DASH || ahead === CH_EQUALS) && aahead === CH_GT) {
299
308
  this.add();
300
309
  }
301
- else if (current === ">"
302
- && ahead !== " "
303
- && (this.stream.prevChar() === "-" || this.stream.prevChar() === "=")) {
310
+ else if (current === CH_GT
311
+ && ahead !== CH_SPACE
312
+ && (stream.prevChar() === CH_DASH || stream.prevChar() === CH_EQUALS)) {
304
313
  // arrows
305
314
  this.add();
306
315
  }
307
- else if (buf.length === 1
308
- && (bufs[buf]
309
- || (buf === "-" && ahead !== ">"))) {
316
+ else if (this.buffer.length() === 1
317
+ && (BUFS.has(current)
318
+ || (current === CH_DASH && ahead !== CH_GT))) {
310
319
  this.add();
311
320
  }
312
321
  }
313
- else if (this.m === ModePragma && (ahead === "," || ahead === ":" || ahead === "." || ahead === " " || ahead === "\n")) {
322
+ else if (this.m === ModePragma && (ahead === CH_COMMA || ahead === CH_COLON
323
+ || ahead === CH_DOT || ahead === CH_SPACE || ahead === CH_NL)) {
314
324
  // end of pragma
315
325
  this.add();
316
326
  this.m = ModeNormal;
317
327
  }
318
328
  else if (this.m === ModePing
319
- && buf.length > 1
320
- && current === "`"
321
- && aahead !== "``"
322
- && ahead !== "`"
323
- && this.buffer.countIsEven("`")) {
329
+ && this.buffer.length() > 1
330
+ && current === CH_BACKTICK
331
+ && !(ahead === CH_BACKTICK && aahead === CH_BACKTICK)
332
+ && ahead !== CH_BACKTICK
333
+ && this.buffer.countIsEven(CH_BACKTICK)) {
324
334
  // end of ping
325
335
  this.add();
326
- if (ahead === `"`) {
336
+ if (ahead === CH_DQUOTE) {
327
337
  this.m = ModeComment;
328
338
  }
329
339
  else {
@@ -331,41 +341,41 @@ class Lexer {
331
341
  }
332
342
  }
333
343
  else if (this.m === ModeTemplate
334
- && buf.length > 1
335
- && (current === "|" || current === "{")
336
- && (this.stream.prevChar() !== "\\" || this.stream.prevPrevChar() === "\\\\")) {
344
+ && this.buffer.length() > 1
345
+ && (current === CH_PIPE || current === CH_LBRACE)
346
+ && (stream.prevChar() !== CH_BACKSLASH || (stream.prevPrevChar() === CH_BACKSLASH && stream.prevChar() === CH_BACKSLASH))) {
337
347
  // end of template
338
348
  this.add();
339
349
  this.m = ModeNormal;
340
350
  }
341
351
  else if (this.m === ModeTemplate
342
- && ahead === "}"
343
- && current !== "\\") {
352
+ && ahead === CH_RBRACE
353
+ && current !== CH_BACKSLASH) {
344
354
  this.add();
345
355
  }
346
356
  else if (this.m === ModeStr
347
- && current === "'"
348
- && buf.length > 1
349
- && aahead !== "''"
350
- && ahead !== "'"
351
- && this.buffer.countIsEven("'")) {
357
+ && current === CH_QUOTE
358
+ && this.buffer.length() > 1
359
+ && !(ahead === CH_QUOTE && aahead === CH_QUOTE)
360
+ && ahead !== CH_QUOTE
361
+ && this.buffer.countIsEven(CH_QUOTE)) {
352
362
  // end of string
353
363
  this.add();
354
- if (ahead === "\"") {
364
+ if (ahead === CH_DQUOTE) {
355
365
  this.m = ModeComment;
356
366
  }
357
367
  else {
358
368
  this.m = ModeNormal;
359
369
  }
360
370
  }
361
- else if (ahead === "\n" && this.m !== ModeTemplate) {
371
+ else if (ahead === CH_NL && this.m !== ModeTemplate) {
362
372
  this.add();
363
373
  this.m = ModeNormal;
364
374
  }
365
- else if (this.m === ModeTemplate && current === "\n") {
375
+ else if (this.m === ModeTemplate && current === CH_NL) {
366
376
  this.add();
367
377
  }
368
- if (!this.stream.advance()) {
378
+ if (!stream.advance()) {
369
379
  break;
370
380
  }
371
381
  }
@@ -387,24 +397,38 @@ exports.Lexer = Lexer;
387
397
 
388
398
  Object.defineProperty(exports, "__esModule", ({ value: true }));
389
399
  exports.LexerBuffer = void 0;
400
+ // The buffer holds a reference to the raw input and tracks the [start, end)
401
+ // offset range of the current token, so the token string can be sliced out with
402
+ // a single substring() instead of being concatenated one character at a time.
390
403
  class LexerBuffer {
391
- constructor() {
392
- this.buf = "";
404
+ constructor(raw) {
405
+ this.raw = raw;
406
+ this.start = 0;
407
+ this.end = 0;
408
+ this.empty = true;
393
409
  }
394
- add(s) {
395
- this.buf = this.buf + s;
396
- return this.buf;
410
+ add(offset) {
411
+ if (this.empty === true) {
412
+ this.start = offset < 0 ? 0 : offset;
413
+ this.empty = false;
414
+ }
415
+ this.end = offset + 1;
397
416
  }
398
417
  get() {
399
- return this.buf;
418
+ return this.raw.substring(this.start, this.end);
419
+ }
420
+ length() {
421
+ return this.end - this.start;
400
422
  }
401
423
  clear() {
402
- this.buf = "";
424
+ this.start = 0;
425
+ this.end = 0;
426
+ this.empty = true;
403
427
  }
404
428
  countIsEven(char) {
405
429
  let count = 0;
406
- for (let i = 0; i < this.buf.length; i += 1) {
407
- if (this.buf.charAt(i) === char) {
430
+ for (let i = this.start; i < this.end; i += 1) {
431
+ if (this.raw.charCodeAt(i) === char) {
408
432
  count += 1;
409
433
  }
410
434
  }
@@ -426,6 +450,8 @@ exports.LexerBuffer = LexerBuffer;
426
450
 
427
451
  Object.defineProperty(exports, "__esModule", ({ value: true }));
428
452
  exports.LexerStream = void 0;
453
+ const NL = 10; // "\n"
454
+ const EOF = -1; // no character (start/end of file)
429
455
  class LexerStream {
430
456
  constructor(raw) {
431
457
  this.offset = -1;
@@ -434,7 +460,7 @@ class LexerStream {
434
460
  this.col = 0;
435
461
  }
436
462
  advance() {
437
- if (this.currentChar() === "\n") {
463
+ if (this.currentChar() === NL) {
438
464
  this.col = 1;
439
465
  this.row = this.row + 1;
440
466
  }
@@ -452,38 +478,51 @@ class LexerStream {
452
478
  getRow() {
453
479
  return this.row;
454
480
  }
481
+ // the *Char() accessors return character codes (charCodeAt) rather than
482
+ // single character strings, to avoid allocating a string per input character
483
+ // in the lexer hot loop. EOF (-1) is returned when the offset is out of range.
455
484
  prevChar() {
456
- if (this.offset - 1 < 0) {
457
- return "";
485
+ const o = this.offset - 1;
486
+ if (o < 0) {
487
+ return EOF;
458
488
  }
459
- return this.raw.substr(this.offset - 1, 1);
489
+ return this.raw.charCodeAt(o);
460
490
  }
461
491
  prevPrevChar() {
462
- if (this.offset - 2 < 0) {
463
- return "";
492
+ const o = this.offset - 2;
493
+ if (o < 0) {
494
+ return EOF;
464
495
  }
465
- return this.raw.substr(this.offset - 2, 2);
496
+ return this.raw.charCodeAt(o);
466
497
  }
467
498
  currentChar() {
468
499
  if (this.offset < 0) {
469
- return "\n"; // simulate newline at start of file to handle star(*) comments
500
+ return NL; // simulate newline at start of file to handle star(*) comments
470
501
  }
471
502
  else if (this.offset >= this.raw.length) {
472
- return "";
503
+ return EOF;
473
504
  }
474
- return this.raw.substr(this.offset, 1);
505
+ return this.raw.charCodeAt(this.offset);
475
506
  }
476
507
  nextChar() {
477
- if (this.offset + 2 > this.raw.length) {
478
- return "";
508
+ const o = this.offset + 1;
509
+ if (o >= this.raw.length) {
510
+ return EOF;
479
511
  }
480
- return this.raw.substr(this.offset + 1, 1);
512
+ return this.raw.charCodeAt(o);
481
513
  }
482
514
  nextNextChar() {
483
- if (this.offset + 3 > this.raw.length) {
484
- return this.nextChar();
515
+ const o = this.offset + 2;
516
+ if (o >= this.raw.length) {
517
+ return EOF;
518
+ }
519
+ return this.raw.charCodeAt(o);
520
+ }
521
+ charCodeAt(o) {
522
+ if (o < 0 || o >= this.raw.length) {
523
+ return EOF;
485
524
  }
486
- return this.raw.substr(this.offset + 1, 2);
525
+ return this.raw.charCodeAt(o);
487
526
  }
488
527
  getRaw() {
489
528
  return this.raw;
@@ -1881,8 +1920,9 @@ class Word {
1881
1920
  }
1882
1921
  }
1883
1922
  class Token {
1884
- constructor(s) {
1885
- this.name = s;
1923
+ constructor(t) {
1924
+ this.tokenType = t;
1925
+ this.name = t.name;
1886
1926
  }
1887
1927
  listKeywords() {
1888
1928
  return [];
@@ -1894,7 +1934,7 @@ class Token {
1894
1934
  const result = [];
1895
1935
  for (const input of r) {
1896
1936
  if (input.remainingLength() !== 0
1897
- && input.peek().constructor.name === this.name) {
1937
+ && input.peek().constructor === this.tokenType) {
1898
1938
  result.push(input.shift(new nodes_1.TokenNode(input.peek())));
1899
1939
  }
1900
1940
  }
@@ -2090,7 +2130,12 @@ class Optional {
2090
2130
  for (const input of r) {
2091
2131
  result.push(input);
2092
2132
  const res = this.optional.run([input]);
2093
- result.push(...res);
2133
+ if (res.length === 1) {
2134
+ result.push(res[0]);
2135
+ }
2136
+ else {
2137
+ result.push(...res);
2138
+ }
2094
2139
  }
2095
2140
  return result;
2096
2141
  }
@@ -2129,6 +2174,9 @@ class Star {
2129
2174
  // avoid stack overflow
2130
2175
  result = result.concat(res);
2131
2176
  }
2177
+ else if (res.length === 1) {
2178
+ result.push(res[0]);
2179
+ }
2132
2180
  else {
2133
2181
  result.push(...res);
2134
2182
  }
@@ -2280,6 +2328,9 @@ class Sequence {
2280
2328
  // avoid stack overflow
2281
2329
  result = result.concat(temp);
2282
2330
  }
2331
+ else if (temp.length === 1) {
2332
+ result.push(temp[0]);
2333
+ }
2283
2334
  else {
2284
2335
  result.push(...temp);
2285
2336
  }
@@ -2504,7 +2555,12 @@ class Alternative {
2504
2555
  const result = [];
2505
2556
  for (const sequ of this.list) {
2506
2557
  const temp = sequ.run(r);
2507
- result.push(...temp);
2558
+ if (temp.length === 1) {
2559
+ result.push(temp[0]);
2560
+ }
2561
+ else {
2562
+ result.push(...temp);
2563
+ }
2508
2564
  }
2509
2565
  return result;
2510
2566
  }
@@ -2562,7 +2618,12 @@ class AlternativePriority {
2562
2618
  // console.log(seq.toStr());
2563
2619
  const temp = sequ.run(r);
2564
2620
  if (temp.length > 0) {
2565
- result.push(...temp);
2621
+ if (temp.length === 1) {
2622
+ result.push(temp[0]);
2623
+ }
2624
+ else {
2625
+ result.push(...temp);
2626
+ }
2566
2627
  break;
2567
2628
  }
2568
2629
  }
@@ -2678,7 +2739,7 @@ function regex(r) {
2678
2739
  return new Regex(r);
2679
2740
  }
2680
2741
  function tok(t) {
2681
- return new Token(t.name);
2742
+ return new Token(t);
2682
2743
  }
2683
2744
  const expressionSingletons = {};
2684
2745
  const stringSingletons = {};
@@ -11174,6 +11235,7 @@ const expand_macros_1 = __webpack_require__(/*! ./expand_macros */ "../core/buil
11174
11235
  const tokens_1 = __webpack_require__(/*! ../1_lexer/tokens */ "../core/build/src/abap/1_lexer/tokens/index.js");
11175
11236
  const _select_reclassify_1 = __webpack_require__(/*! ./_select_reclassify */ "../core/build/src/abap/2_statements/_select_reclassify.js");
11176
11237
  exports.STATEMENT_MAX_TOKENS = 20000;
11238
+ const EMPTY_PRAGMAS = Object.freeze([]);
11177
11239
  class StatementMap {
11178
11240
  constructor() {
11179
11241
  this.map = {};
@@ -11372,9 +11434,19 @@ class StatementParser {
11372
11434
  return statement;
11373
11435
  }
11374
11436
  removePragma(tokens) {
11437
+ let hasPragma = false;
11438
+ // skip the last token as it is the punctuation
11439
+ for (let i = 0; i < tokens.length - 1; i++) {
11440
+ if (tokens[i] instanceof Tokens.Pragma) {
11441
+ hasPragma = true;
11442
+ break;
11443
+ }
11444
+ }
11445
+ if (hasPragma === false) {
11446
+ return { tokens: tokens.slice(0, tokens.length - 1), pragmas: EMPTY_PRAGMAS };
11447
+ }
11375
11448
  const result = [];
11376
11449
  const pragmas = [];
11377
- // skip the last token as it is the punctuation
11378
11450
  for (let i = 0; i < tokens.length - 1; i++) {
11379
11451
  const t = tokens[i];
11380
11452
  if (t instanceof Tokens.Pragma) {
@@ -47928,6 +48000,7 @@ const _abstract_node_1 = __webpack_require__(/*! ./_abstract_node */ "../core/bu
47928
48000
  class ExpressionNode extends _abstract_node_1.AbstractNode {
47929
48001
  constructor(expression) {
47930
48002
  super();
48003
+ this.tokenCount = 0;
47931
48004
  this.expression = expression;
47932
48005
  }
47933
48006
  addChild(_n) {
@@ -47936,12 +48009,15 @@ class ExpressionNode extends _abstract_node_1.AbstractNode {
47936
48009
  get() {
47937
48010
  return this.expression;
47938
48011
  }
47939
- countTokens() {
47940
- let ret = 0;
47941
- for (const c of this.getChildren()) {
47942
- ret = ret + c.countTokens();
48012
+ setChildren(children) {
48013
+ super.setChildren(children);
48014
+ for (const child of this.getChildren()) {
48015
+ this.tokenCount = this.tokenCount + child.countTokens();
47943
48016
  }
47944
- return ret;
48017
+ return this;
48018
+ }
48019
+ countTokens() {
48020
+ return this.tokenCount;
47945
48021
  }
47946
48022
  getFirstToken() {
47947
48023
  for (const child of this.getChildren()) {
@@ -50944,6 +51020,7 @@ class ClassDefinition extends _identifier_1.Identifier {
50944
51020
  // perform checks after everything has been initialized
50945
51021
  this.checkMethodsFromSuperClasses(input);
50946
51022
  this.checkMethodNameLength(input);
51023
+ this.checkClassConstructorStatic(input);
50947
51024
  }
50948
51025
  getFriends() {
50949
51026
  return this.friends;
@@ -51007,6 +51084,13 @@ class ClassDefinition extends _identifier_1.Identifier {
51007
51084
  }
51008
51085
  }
51009
51086
  }
51087
+ checkClassConstructorStatic(input) {
51088
+ for (const m of this.methodDefs.getAll()) {
51089
+ if (m.getName().toUpperCase() === "CLASS_CONSTRUCTOR" && m.isStatic() === false) {
51090
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, m.getToken(), "CLASS_CONSTRUCTOR must be static"));
51091
+ }
51092
+ }
51093
+ }
51010
51094
  checkMethodsFromSuperClasses(input) {
51011
51095
  var _a;
51012
51096
  const scope = input.scope;
@@ -53634,7 +53718,7 @@ const cds_name_1 = __webpack_require__(/*! ./cds_name */ "../core/build/src/cds/
53634
53718
  class CDSDefineTableFunction extends combi_1.Expression {
53635
53719
  getRunnable() {
53636
53720
  const methodName = (0, combi_1.seq)(cds_name_1.CDSName, "=", ">", cds_name_1.CDSName);
53637
- return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.str)("DEFINE TABLE FUNCTION"), cds_name_1.CDSName, (0, combi_1.optPrio)(_1.CDSWithParameters), (0, combi_1.str)("RETURNS {"), (0, combi_1.plus)((0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.optPrio)("KEY"), cds_name_1.CDSName, ":", _1.CDSType, ";")), (0, combi_1.str)("} IMPLEMENTED BY METHOD"), methodName, (0, combi_1.opt)(";"));
53721
+ return (0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.str)("DEFINE TABLE FUNCTION"), cds_name_1.CDSName, (0, combi_1.optPrio)(_1.CDSWithParameters), (0, combi_1.str)("RETURNS {"), (0, combi_1.plus)((0, combi_1.seq)((0, combi_1.star)(_1.CDSAnnotation), (0, combi_1.optPrio)("KEY"), cds_name_1.CDSName, ":", _1.CDSType, (0, combi_1.star)(_1.CDSAnnotation), ";")), (0, combi_1.str)("} IMPLEMENTED BY METHOD"), methodName, (0, combi_1.opt)(";"));
53638
53722
  }
53639
53723
  }
53640
53724
  exports.CDSDefineTableFunction = CDSDefineTableFunction;
@@ -53699,7 +53783,7 @@ class CDSElement extends combi_1.Expression {
53699
53783
  const funcWithPath = (0, combi_1.seq)(_1.CDSFunction, (0, combi_1.plusPrio)(pathSegment));
53700
53784
  const body = (0, combi_1.altPrio)(extensionWildcard, includeElement, _1.CDSArithmetics, _1.CDSAggregate, _1.CDSString, _1.CDSArithParen, funcWithPath, _1.CDSFunction, cds_cast_1.CDSCast, _1.CDSCase, (0, combi_1.seq)("(", _1.CDSCase, ")"), (0, combi_1.seq)(_1.CDSPrefixedName, (0, combi_1.optPrio)(cds_as_1.CDSAs), (0, combi_1.optPrio)((0, combi_1.altPrio)(redirected, colonThing))), _1.CDSInteger);
53701
53785
  const elementBody = (0, combi_1.altPrio)(typedVirtual, (0, combi_1.seq)((0, combi_1.altPrio)("KEY", "VIRTUAL"), body), body);
53702
- return (0, combi_1.seq)((0, combi_1.starPrio)(_1.CDSAnnotation), elementBody, (0, combi_1.optPrio)(cds_as_1.CDSAs));
53786
+ return (0, combi_1.seq)((0, combi_1.starPrio)(_1.CDSAnnotation), elementBody, (0, combi_1.optPrio)(cds_as_1.CDSAs), (0, combi_1.starPrio)(_1.CDSAnnotation));
53703
53787
  }
53704
53788
  }
53705
53789
  exports.CDSElement = CDSElement;
@@ -53968,7 +54052,7 @@ const combi_1 = __webpack_require__(/*! ../../abap/2_statements/combi */ "../cor
53968
54052
  class CDSName extends combi_1.Expression {
53969
54053
  getRunnable() {
53970
54054
  const pre = (0, combi_1.seq)("/", (0, combi_1.regex)(/^[\w_]+$/), "/");
53971
- return (0, combi_1.seq)((0, combi_1.optPrio)(":"), (0, combi_1.optPrio)(pre), (0, combi_1.regex)(/^\$?#?[\w_]+$/));
54055
+ return (0, combi_1.altPrio)((0, combi_1.regex)(/^"(?:[^"]|"")*"$/), (0, combi_1.seq)((0, combi_1.optPrio)(":"), (0, combi_1.optPrio)(pre), (0, combi_1.regex)(/^\$?#?[\w_]+$/)));
53972
54056
  }
53973
54057
  }
53974
54058
  exports.CDSName = CDSName;
@@ -54183,7 +54267,7 @@ exports.CDSString = void 0;
54183
54267
  const combi_1 = __webpack_require__(/*! ../../abap/2_statements/combi */ "../core/build/src/abap/2_statements/combi.js");
54184
54268
  class CDSString extends combi_1.Expression {
54185
54269
  getRunnable() {
54186
- const reg = (0, combi_1.regex)(/^(?:'(?:[^'\\]|''|\\'|\\\\|\\(?!'))*'|"(?:[^"\\]|""|\\"|\\\\|\\(?!"))*")$/);
54270
+ const reg = (0, combi_1.regex)(/^'(?:[^'\\]|''|\\'|\\\\|\\(?!'))*'$/);
54187
54271
  const abapTypeName = (0, combi_1.regex)(/^(?:int[1-9]|int8|sstring|sstr|char|numc|dats|datn|tims|timn|utcl|utclong|fltp|decfloat\d+|dec|string|rawstring|rstr|raw|xstring|clnt|lang|unit|cuky|curr|quan|geom_ewkb|d34n|d16n|d34d|d16d|d34s|d16s|d34r|d16r|d|t|p|n|c|x|f)$/i);
54188
54272
  const abap = (0, combi_1.seq)("abap", ".", abapTypeName, (0, combi_1.optPrio)((0, combi_1.seq)("(", (0, combi_1.regex)(/^\d+$/), ")")), reg);
54189
54273
  return (0, combi_1.altPrio)(abap, reg);
@@ -68684,7 +68768,7 @@ class Registry {
68684
68768
  }
68685
68769
  static abaplintVersion() {
68686
68770
  // magic, see build script "version.js"
68687
- return "2.119.58";
68771
+ return "2.119.60";
68688
68772
  }
68689
68773
  getDDICReferences() {
68690
68774
  return this.ddicReferences;
@@ -74344,6 +74428,7 @@ class DangerousStatementConf extends _basic_rule_config_1.BasicRuleConfig {
74344
74428
  this.insertTextpool = true;
74345
74429
  this.deleteDynpro = true;
74346
74430
  this.exportDynpro = true;
74431
+ this.editorCallForReport = true;
74347
74432
  /** Finds instances of dynamic SQL: SELECT, UPDATE, DELETE, INSERT, MODIFY */
74348
74433
  this.dynamicSQL = true;
74349
74434
  /** Ignore dynamic SQL in IF_RAP_QUERY_PROVIDER~SELECT implementations */
@@ -74428,6 +74513,11 @@ dynamic SQL can potentially create SQL injection problems`,
74428
74513
  else if (this.conf.exportDynpro && statement instanceof Statements.ExportDynpro) {
74429
74514
  message = "EXPORT DYNPRO";
74430
74515
  }
74516
+ else if (this.conf.editorCallForReport
74517
+ && statement instanceof Statements.EditorCall
74518
+ && statementNode.findDirectTokenByText("REPORT")) {
74519
+ message = "EDITOR-CALL FOR REPORT";
74520
+ }
74431
74521
  if (message) {
74432
74522
  issues.push(issue_1.Issue.atStatement(file, statementNode, this.getDescription(message), this.getMetadata().key, this.conf.severity));
74433
74523
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/cli",
3
- "version": "2.119.58",
3
+ "version": "2.119.60",
4
4
  "description": "abaplint - Command Line Interface",
5
5
  "funding": "https://github.com/sponsors/larshp",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "homepage": "https://abaplint.org",
41
41
  "devDependencies": {
42
- "@abaplint/core": "^2.119.58",
42
+ "@abaplint/core": "^2.119.60",
43
43
  "@types/chai": "^4.3.20",
44
44
  "@types/minimist": "^1.2.5",
45
45
  "@types/mocha": "^10.0.10",