@abaplint/core 2.96.2 → 2.97.2

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.
@@ -401,6 +401,7 @@ declare namespace BasicTypes {
401
401
  IStructureComponent,
402
402
  StructureType,
403
403
  TableAccessType,
404
+ TableKeyType,
404
405
  ITableKey,
405
406
  ITableOptions,
406
407
  TableType_2 as TableType,
@@ -3626,13 +3627,14 @@ declare interface ISyntaxSettings {
3626
3627
 
3627
3628
  declare type ITableKey = {
3628
3629
  name: string;
3629
- type?: TableAccessType;
3630
+ type: TableAccessType;
3630
3631
  keyFields: string[];
3631
3632
  isUnique: boolean;
3632
3633
  };
3633
3634
 
3634
3635
  declare type ITableOptions = {
3635
3636
  withHeader: boolean;
3637
+ keyType: TableKeyType;
3636
3638
  primaryKey?: ITableKey;
3637
3639
  secondary?: ITableKey[];
3638
3640
  };
@@ -5959,6 +5961,12 @@ declare class TableExpression extends Expression {
5959
5961
  getRunnable(): IStatementRunnable;
5960
5962
  }
5961
5963
 
5964
+ declare enum TableKeyType {
5965
+ default = "DEFAULT",
5966
+ user = "USER",
5967
+ empty = "EMPTY"
5968
+ }
5969
+
5962
5970
  declare class Tables implements IStatement {
5963
5971
  getMatcher(): IStatementRunnable;
5964
5972
  }
@@ -388,7 +388,7 @@ BuiltIn.methods = [
388
388
  {
389
389
  name: "CONCAT_LINES_OF",
390
390
  mandatory: {
391
- "table": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false }),
391
+ "table": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false, keyType: basic_1.TableKeyType.default }),
392
392
  },
393
393
  optional: {
394
394
  "sep": new basic_1.StringType(),
@@ -684,7 +684,7 @@ BuiltIn.methods = [
684
684
  {
685
685
  name: "LINES",
686
686
  mandatory: {
687
- "val": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false }),
687
+ "val": new basic_1.TableType(new basic_1.AnyType(), { withHeader: false, keyType: basic_1.TableKeyType.default }),
688
688
  },
689
689
  return: new basic_1.IntegerType(),
690
690
  },
@@ -90,10 +90,10 @@ class Procedural {
90
90
  }
91
91
  if (param.direction === types_1.FunctionModuleParameterDirection.tables) {
92
92
  if (found instanceof basic_1.TableType) {
93
- found = new basic_1.TableType(found.getRowType(), { withHeader: true });
93
+ found = new basic_1.TableType(found.getRowType(), { withHeader: true, keyType: basic_1.TableKeyType.default });
94
94
  }
95
95
  else {
96
- found = new basic_1.TableType(found, { withHeader: true });
96
+ found = new basic_1.TableType(found, { withHeader: true, keyType: basic_1.TableKeyType.default });
97
97
  }
98
98
  }
99
99
  if ((found instanceof basic_1.UnknownType || found instanceof basic_1.VoidType) && ((_a = param.type) === null || _a === void 0 ? void 0 : _a.includes("-"))) {
@@ -143,7 +143,7 @@ class BasicTypes {
143
143
  }
144
144
  else if (child.concatTokens() === "[]") {
145
145
  if (type instanceof Types.TableType) {
146
- type = new basic_1.TableType(type.getRowType(), { withHeader: false });
146
+ type = new basic_1.TableType(type.getRowType(), { withHeader: false, keyType: Types.TableKeyType.default });
147
147
  }
148
148
  }
149
149
  else { // field name
@@ -269,7 +269,7 @@ class BasicTypes {
269
269
  return undefined;
270
270
  }
271
271
  parseTable(node, name) {
272
- var _a, _b, _c;
272
+ var _a, _b, _c, _d;
273
273
  const typename = node.findFirstExpression(Expressions.TypeName);
274
274
  const text = (_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
275
275
  if (text === undefined) {
@@ -292,10 +292,11 @@ class BasicTypes {
292
292
  }
293
293
  const typeTableKeys = node.findAllExpressions(expressions_1.TypeTableKey);
294
294
  const firstKey = typeTableKeys[0];
295
- const isNamed = (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpression(expressions_1.Field)) !== undefined;
295
+ const isNamed = (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpression(expressions_1.Field)) !== undefined
296
+ && ((_b = firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpression(expressions_1.Field)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase()) !== "PRIMARY_KEY";
296
297
  const primaryKey = {
297
298
  name: "primary_key",
298
- type: type,
299
+ type: type || basic_1.TableAccessType.standard,
299
300
  isUnique: isNamed ? false : (firstKey === null || firstKey === void 0 ? void 0 : firstKey.concatTokens().toUpperCase().includes("WITH UNIQUE ")) === true,
300
301
  keyFields: [],
301
302
  };
@@ -304,9 +305,6 @@ class BasicTypes {
304
305
  for (const k of (firstKey === null || firstKey === void 0 ? void 0 : firstKey.findDirectExpressions(expressions_1.FieldSub)) || []) {
305
306
  primaryKey.keyFields.push(k.concatTokens().toUpperCase());
306
307
  }
307
- if (primaryKey.keyFields.length === 0 && text.includes(" DEFAULT KEY")) {
308
- primaryKey.keyFields.push("TABLE_LINE");
309
- }
310
308
  }
311
309
  else {
312
310
  start = 0;
@@ -314,7 +312,7 @@ class BasicTypes {
314
312
  const secondaryKeys = [];
315
313
  for (let i = start; i < typeTableKeys.length; i++) {
316
314
  const row = typeTableKeys[i];
317
- const name = (_b = row.findDirectExpression(expressions_1.Field)) === null || _b === void 0 ? void 0 : _b.concatTokens();
315
+ const name = (_c = row.findDirectExpression(expressions_1.Field)) === null || _c === void 0 ? void 0 : _c.concatTokens();
318
316
  if (name === undefined) {
319
317
  continue;
320
318
  }
@@ -329,8 +327,16 @@ class BasicTypes {
329
327
  }
330
328
  secondaryKeys.push(secondary);
331
329
  }
330
+ let keyType = Types.TableKeyType.user;
331
+ if (text.includes(" EMPTY KEY")) {
332
+ keyType = Types.TableKeyType.empty;
333
+ }
334
+ else if (text.includes(" DEFAULT KEY")) {
335
+ keyType = Types.TableKeyType.default;
336
+ }
332
337
  const options = {
333
338
  withHeader: text.includes(" WITH HEADER LINE"),
339
+ keyType: keyType,
334
340
  primaryKey: primaryKey,
335
341
  secondary: secondaryKeys,
336
342
  };
@@ -402,7 +408,7 @@ class BasicTypes {
402
408
  else if (typename && (text.startsWith("TYPE TABLE FOR CREATE ")
403
409
  || text.startsWith("TYPE TABLE FOR UPDATE "))) {
404
410
  const name = typename.concatTokens();
405
- const type = (_c = this.scope.getDDIC().lookupDDLS(name)) === null || _c === void 0 ? void 0 : _c.type;
411
+ const type = (_d = this.scope.getDDIC().lookupDDLS(name)) === null || _d === void 0 ? void 0 : _d.type;
406
412
  if (type) {
407
413
  return new Types.TableType(new basic_1.VoidType("RapTodo"), options);
408
414
  }
@@ -477,7 +483,7 @@ class BasicTypes {
477
483
  || text === "TYPE HASHED TABLE"
478
484
  || text === "TYPE INDEX TABLE"
479
485
  || text === "TYPE ANY TABLE") {
480
- return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes("WITH HEADER LINE") });
486
+ return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes("WITH HEADER LINE"), keyType: Types.TableKeyType.default });
481
487
  }
482
488
  else if (text.startsWith("LIKE ")) {
483
489
  let sub = node.findFirstExpression(Expressions.Type);
@@ -495,7 +501,7 @@ class BasicTypes {
495
501
  }
496
502
  found = this.resolveLikeName(sub);
497
503
  if (found && this.isOccurs(node)) {
498
- found = new Types.TableType(found, { withHeader: text.includes("WITH HEADER LINE") }, qualifiedName);
504
+ found = new Types.TableType(found, { withHeader: text.includes("WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
499
505
  }
500
506
  }
501
507
  else if (text.startsWith("TYPE LINE OF ")) {
@@ -524,17 +530,17 @@ class BasicTypes {
524
530
  found = this.resolveTypeName(typeName, this.findLength(node), this.findDecimals(node), qualifiedName);
525
531
  const concat = node.concatTokens().toUpperCase();
526
532
  if (found && this.isOccurs(node)) {
527
- found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE") }, qualifiedName);
533
+ found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
528
534
  }
529
535
  else if (found && concat.includes(" WITH HEADER LINE")) {
530
536
  if (found instanceof Types.VoidType) {
531
- found = new Types.TableType(found, { withHeader: true });
537
+ found = new Types.TableType(found, { withHeader: true, keyType: Types.TableKeyType.default });
532
538
  }
533
539
  else if (!(found instanceof Types.TableType)) {
534
540
  throw new Error("WITH HEADER LINE can only be used with internal table");
535
541
  }
536
542
  else {
537
- found = new Types.TableType(found.getRowType(), { withHeader: true });
543
+ found = new Types.TableType(found.getRowType(), { withHeader: true, keyType: Types.TableKeyType.default });
538
544
  }
539
545
  }
540
546
  if (found === undefined && typeName === undefined) {
@@ -548,7 +554,7 @@ class BasicTypes {
548
554
  }
549
555
  found = new Types.CharacterType(length, { qualifiedName: qualifiedName }); // fallback
550
556
  if (this.isOccurs(node)) {
551
- found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE") }, qualifiedName);
557
+ found = new Types.TableType(found, { withHeader: concat.includes(" WITH HEADER LINE"), keyType: Types.TableKeyType.default }, qualifiedName);
552
558
  }
553
559
  }
554
560
  }
@@ -32,7 +32,7 @@ class Controls {
32
32
  { name: "LINE_SELECTOR", type: new basic_1.CharacterType(1) },
33
33
  { name: "H_GRID", type: new basic_1.CharacterType(1) },
34
34
  { name: "V_GRID", type: new basic_1.CharacterType(1) },
35
- { name: "COLS", type: new basic_1.TableType(cols, { withHeader: false }) },
35
+ { name: "COLS", type: new basic_1.TableType(cols, { withHeader: false, keyType: basic_1.TableKeyType.default }) },
36
36
  { name: "INVISIBLE", type: new basic_1.CharacterType(1) },
37
37
  ]);
38
38
  const id = new _typed_identifier_1.TypedIdentifier(token, filename, type);
@@ -21,13 +21,13 @@ class Find {
21
21
  { name: "LINE", type: new basic_1.IntegerType() },
22
22
  { name: "OFFSET", type: new basic_1.IntegerType() },
23
23
  { name: "LENGTH", type: new basic_1.IntegerType() },
24
- { name: "SUBMATCHES", type: new basic_1.TableType(sub, { withHeader: false }) },
24
+ { name: "SUBMATCHES", type: new basic_1.TableType(sub, { withHeader: false, keyType: basic_1.TableKeyType.default }) },
25
25
  ], "MATCH_RESULT", "MATCH_RESULT");
26
26
  if (node.concatTokens().toUpperCase().startsWith("FIND FIRST")) {
27
27
  this.inline(rfound, scope, filename, type);
28
28
  }
29
29
  else {
30
- this.inline(rfound, scope, filename, new basic_1.TableType(type, { withHeader: false }, "MATCH_RESULT_TAB"));
30
+ this.inline(rfound, scope, filename, new basic_1.TableType(type, { withHeader: false, keyType: basic_1.TableKeyType.default }, "MATCH_RESULT_TAB"));
31
31
  }
32
32
  }
33
33
  const ofound = node.findExpressionsAfterToken("OFFSET");
@@ -21,7 +21,7 @@ class Ranges {
21
21
  { name: "low", type: found },
22
22
  { name: "high", type: found },
23
23
  ]);
24
- const type = new basic_1.TableType(structure, { withHeader: true });
24
+ const type = new basic_1.TableType(structure, { withHeader: true, keyType: basic_1.TableKeyType.default });
25
25
  const id = new _typed_identifier_1.TypedIdentifier(nameToken, filename, type);
26
26
  scope.addIdentifier(id);
27
27
  }
@@ -39,7 +39,7 @@ class SelectOption {
39
39
  { name: "LOW", type: found },
40
40
  { name: "HIGH", type: found },
41
41
  ]);
42
- scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, new basic_1.TableType(stru, { withHeader: true })));
42
+ scope.addIdentifier(new _typed_identifier_1.TypedIdentifier(nameToken, filename, new basic_1.TableType(stru, { withHeader: true, keyType: basic_1.TableKeyType.default })));
43
43
  return;
44
44
  }
45
45
  if (nameToken) {
@@ -10,7 +10,7 @@ const _type_utils_1 = require("../_type_utils");
10
10
  class Split {
11
11
  runSyntax(node, scope, filename) {
12
12
  const intoTable = node.findTokenSequencePosition("INTO", "TABLE") !== undefined;
13
- const type = intoTable ? new basic_1.TableType(new basic_1.StringType(), { withHeader: false }) : new basic_1.StringType();
13
+ const type = intoTable ? new basic_1.TableType(new basic_1.StringType(), { withHeader: false, keyType: basic_1.TableKeyType.default }) : new basic_1.StringType();
14
14
  for (const target of node.findAllExpressions(Expressions.Target)) {
15
15
  const inline = target.findDirectExpression(Expressions.InlineData);
16
16
  if (inline) {
@@ -58,7 +58,7 @@ class Data {
58
58
  }
59
59
  if (found instanceof Basic.VoidType) {
60
60
  if (table === true) {
61
- return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true }));
61
+ return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true, keyType: Basic.TableKeyType.default }));
62
62
  }
63
63
  else {
64
64
  return new _typed_identifier_1.TypedIdentifier(name, filename, found);
@@ -76,7 +76,7 @@ class Data {
76
76
  }
77
77
  }
78
78
  if (table === true) {
79
- return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true }));
79
+ return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true, keyType: Basic.TableKeyType.default }));
80
80
  }
81
81
  else {
82
82
  const val = Object.keys(values).length > 0 ? values : undefined;
@@ -49,7 +49,7 @@ class Statics {
49
49
  }
50
50
  if (found instanceof Basic.VoidType) {
51
51
  if (table === true) {
52
- return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true }));
52
+ return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(found, { withHeader: true, keyType: Basic.TableKeyType.default }));
53
53
  }
54
54
  else {
55
55
  return new _typed_identifier_1.TypedIdentifier(name, filename, found);
@@ -67,7 +67,7 @@ class Statics {
67
67
  }
68
68
  }
69
69
  if (table === true) {
70
- return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true }));
70
+ return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.TableType(new Basic.StructureType(components), { withHeader: true, keyType: Basic.TableKeyType.default }));
71
71
  }
72
72
  else {
73
73
  return new _typed_identifier_1.TypedIdentifier(name, filename, new Basic.StructureType(components));
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TableType = exports.TableAccessType = void 0;
3
+ exports.TableType = exports.TableKeyType = exports.TableAccessType = void 0;
4
4
  const _abstract_type_1 = require("./_abstract_type");
5
5
  var TableAccessType;
6
6
  (function (TableAccessType) {
@@ -10,6 +10,12 @@ var TableAccessType;
10
10
  TableAccessType["index"] = "INDEX";
11
11
  TableAccessType["any"] = "ANY";
12
12
  })(TableAccessType = exports.TableAccessType || (exports.TableAccessType = {}));
13
+ var TableKeyType;
14
+ (function (TableKeyType) {
15
+ TableKeyType["default"] = "DEFAULT";
16
+ TableKeyType["user"] = "USER";
17
+ TableKeyType["empty"] = "EMPTY";
18
+ })(TableKeyType = exports.TableKeyType || (exports.TableKeyType = {}));
13
19
  class TableType extends _abstract_type_1.AbstractType {
14
20
  constructor(rowType, options, qualifiedName) {
15
21
  var _a;
@@ -49,6 +55,7 @@ class TableType extends _abstract_type_1.AbstractType {
49
55
  isGeneric() {
50
56
  var _a, _b;
51
57
  if (((_a = this.options.primaryKey) === null || _a === void 0 ? void 0 : _a.type) !== TableAccessType.standard
58
+ && this.options.keyType === TableKeyType.user
52
59
  && ((_b = this.options.primaryKey) === null || _b === void 0 ? void 0 : _b.keyFields.length) === 0) {
53
60
  return true;
54
61
  }
@@ -49,10 +49,10 @@ class FormDefinition extends _identifier_1.Identifier {
49
49
  let type = p.getType();
50
50
  const isStructure = param.findDirectTokenByText("STRUCTURE") !== undefined;
51
51
  if (isStructure) {
52
- type = new basic_1.TableType(type, { withHeader: true });
52
+ type = new basic_1.TableType(type, { withHeader: true, keyType: basic_1.TableKeyType.default });
53
53
  }
54
54
  if (type instanceof basic_1.TableType) {
55
- type = new basic_1.TableType(type.getRowType(), { withHeader: true });
55
+ type = new basic_1.TableType(type.getRowType(), { withHeader: true, keyType: basic_1.TableKeyType.default });
56
56
  }
57
57
  else if (!(type instanceof basic_1.UnknownType) && !(type instanceof basic_1.VoidType)) {
58
58
  type = new basic_1.UnknownType("FORM TABLES type must be table type");
package/build/src/ddic.js CHANGED
@@ -66,7 +66,7 @@ class DDIC {
66
66
  case "%_C_POINTER":
67
67
  return new Types.HexType(8, qualifiedName);
68
68
  case "TABLE":
69
- return new Types.TableType(new Types.AnyType(), { withHeader: false });
69
+ return new Types.TableType(new Types.AnyType(), { withHeader: false, keyType: Types.TableKeyType.default });
70
70
  case "DATA":
71
71
  return new Types.AnyType({ qualifiedName: qualifiedName });
72
72
  case "NUMERIC":
@@ -32,6 +32,7 @@ class TableType extends _abstract_object_1.AbstractObject {
32
32
  var _a, _b, _c;
33
33
  const tableOptions = {
34
34
  withHeader: false,
35
+ keyType: Types.TableKeyType.user,
35
36
  secondary: [],
36
37
  };
37
38
  for (const k of ((_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.dd43v) || []) {
@@ -63,7 +63,7 @@ class Registry {
63
63
  }
64
64
  static abaplintVersion() {
65
65
  // magic, see build script "version.sh"
66
- return "2.96.2";
66
+ return "2.97.2";
67
67
  }
68
68
  getDDICReferences() {
69
69
  return this.references;
@@ -24,7 +24,7 @@ class ConstantClasses {
24
24
  title: "Validate constant classes",
25
25
  shortDescription: `Checks that a class contains exactly the constants corresponding to a domain's fixed values.`,
26
26
  extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#prefer-enumeration-classes-to-constants-interfaces`,
27
- tags: [_irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Experimental],
27
+ tags: [_irule_1.RuleTag.Styleguide],
28
28
  };
29
29
  }
30
30
  initialize(reg) {
@@ -122,7 +122,7 @@ class Downport {
122
122
  return {
123
123
  key: "downport",
124
124
  title: "Downport statement",
125
- shortDescription: `Experimental downport functionality`,
125
+ shortDescription: `Downport functionality`,
126
126
  extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with
127
127
  a higher level language version. If successful, various rules are applied to downport the statement.
128
128
  Target downport version is always v702, thus rule is only enabled if target version is v702.
@@ -155,7 +155,7 @@ Current rules:
155
155
  * MESSAGE with non simple source
156
156
 
157
157
  Only one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,
158
- tags: [_irule_1.RuleTag.Experimental, _irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],
158
+ tags: [_irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],
159
159
  };
160
160
  }
161
161
  getConfig() {
@@ -142,6 +142,7 @@ __exportStar(require("./space_before_dot"), exports);
142
142
  __exportStar(require("./sql_escape_host_variables"), exports);
143
143
  __exportStar(require("./start_at_tab"), exports);
144
144
  __exportStar(require("./static_call_via_instance"), exports);
145
+ __exportStar(require("./strict_sql"), exports);
145
146
  __exportStar(require("./superclass_final"), exports);
146
147
  __exportStar(require("./superfluous_value"), exports);
147
148
  __exportStar(require("./sy_modification"), exports);
@@ -23,7 +23,7 @@ class SQLEscapeHostVariables extends _abap_rule_1.ABAPRule {
23
23
  title: "Escape SQL host variables",
24
24
  shortDescription: `Escape SQL host variables, from 740sp05`,
25
25
  extendedInformation: `https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md#avoid-obsolete-language-elements`,
26
- tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix],
26
+ tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix, _irule_1.RuleTag.Syntax],
27
27
  badExample: `SELECT * FROM tab INTO TABLE res WHERE field = val.`,
28
28
  goodExample: `SELECT * FROM tab INTO TABLE @res WHERE field = @val.`,
29
29
  };
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.StrictSQL = exports.StrictSQLConf = void 0;
4
+ const Statements = require("../abap/2_statements/statements");
5
+ const Expressions = require("../abap/2_statements/expressions");
6
+ const issue_1 = require("../issue");
7
+ const _abap_rule_1 = require("./_abap_rule");
8
+ const _basic_rule_config_1 = require("./_basic_rule_config");
9
+ const version_1 = require("../version");
10
+ const _irule_1 = require("./_irule");
11
+ class StrictSQLConf extends _basic_rule_config_1.BasicRuleConfig {
12
+ }
13
+ exports.StrictSQLConf = StrictSQLConf;
14
+ class StrictSQL extends _abap_rule_1.ABAPRule {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.conf = new StrictSQLConf();
18
+ }
19
+ getMetadata() {
20
+ return {
21
+ key: "strict_sql",
22
+ title: "Strict SQL",
23
+ shortDescription: `Strict SQL`,
24
+ extendedInformation: `https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-US/abapinto_clause.htm
25
+
26
+ https://help.sap.com/doc/abapdocu_751_index_htm/7.51/en-us/abenopensql_strict_mode_750.htm
27
+
28
+ Also see separate rule sql_escape_host_variables`,
29
+ tags: [_irule_1.RuleTag.Upport, _irule_1.RuleTag.Syntax],
30
+ };
31
+ }
32
+ getConfig() {
33
+ return this.conf;
34
+ }
35
+ setConfig(conf) {
36
+ this.conf = conf;
37
+ }
38
+ runParsed(file, obj) {
39
+ const issues = [];
40
+ const type = obj.getType();
41
+ if (type === "INTF" || type === "TYPE") {
42
+ return [];
43
+ }
44
+ if (this.reg.getConfig().getVersion() < version_1.Version.v740sp02
45
+ && this.reg.getConfig().getVersion() !== version_1.Version.Cloud) {
46
+ return [];
47
+ }
48
+ for (const s of file.getStatements()) {
49
+ if (s.get() instanceof Statements.Select
50
+ || s.get() instanceof Statements.SelectLoop) {
51
+ const expr = s.findDirectExpression(Expressions.Select);
52
+ const where = expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLCond);
53
+ const into = (expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLIntoStructure))
54
+ || (expr === null || expr === void 0 ? void 0 : expr.findDirectExpression(Expressions.SQLIntoTable));
55
+ if (into === undefined || where === undefined) {
56
+ continue;
57
+ }
58
+ if (where.getFirstToken().getStart().isBefore(into.getFirstToken().getStart())) {
59
+ continue;
60
+ }
61
+ const message = "INTO/APPENDING must be last in strict SQL";
62
+ const issue = issue_1.Issue.atToken(file, s.getFirstToken(), message, this.getMetadata().key, this.conf.severity);
63
+ issues.push(issue);
64
+ break;
65
+ }
66
+ }
67
+ return issues;
68
+ }
69
+ }
70
+ exports.StrictSQL = StrictSQL;
71
+ //# sourceMappingURL=strict_sql.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.96.2",
3
+ "version": "2.97.2",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",