@abaplint/core 2.120.9 → 2.120.11

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 (28) hide show
  1. package/build/abaplint.d.ts +31 -0
  2. package/build/src/abap/2_statements/expressions/for.js +1 -1
  3. package/build/src/abap/2_statements/expressions/inline_field_definition.js +2 -1
  4. package/build/src/abap/2_statements/expressions/reduce_next.js +1 -1
  5. package/build/src/abap/2_statements/statements/rollback_entities.js +1 -1
  6. package/build/src/abap/4_file_information/abap_file_information_parser.js +2 -1
  7. package/build/src/abap/5_syntax/_type_utils.js +13 -0
  8. package/build/src/abap/5_syntax/expressions/component_compare.js +15 -3
  9. package/build/src/abap/5_syntax/expressions/component_cond.js +3 -3
  10. package/build/src/abap/5_syntax/expressions/filter_body.js +6 -13
  11. package/build/src/abap/5_syntax/expressions/inline_field_definition.js +2 -1
  12. package/build/src/abap/5_syntax/expressions/method_param.js +3 -0
  13. package/build/src/abap/5_syntax/statements/move.js +4 -0
  14. package/build/src/abap/types/basic/index.js +1 -0
  15. package/build/src/abap/types/basic/pgeneric_type.js +30 -0
  16. package/build/src/abap/types/class_definition.js +7 -0
  17. package/build/src/ddl/expressions/ddl_clauses.js +7 -1
  18. package/build/src/ddl/expressions/ddl_table_field.js +1 -1
  19. package/build/src/objects/_abap_object.js +6 -4
  20. package/build/src/objects/domain.js +4 -2
  21. package/build/src/objects/rename/rename_icf_service.js +4 -3
  22. package/build/src/objects/table.js +31 -3
  23. package/build/src/objects/web_mime.js +2 -1
  24. package/build/src/registry.js +1 -1
  25. package/build/src/rules/index.js +1 -0
  26. package/build/src/rules/no_mandt_in_database_operations.js +133 -0
  27. package/build/src/rules/xml_consistency.js +25 -0
  28. package/package.json +6 -6
@@ -534,6 +534,7 @@ declare namespace BasicTypes {
534
534
  NumericType,
535
535
  ObjectReferenceType,
536
536
  PackedType,
537
+ PGenericType,
537
538
  SimpleType,
538
539
  StringType,
539
540
  IStructureComponent,
@@ -1256,6 +1257,7 @@ declare class ClassDefinition_3 extends Identifier implements IClassDefinition {
1256
1257
  isAbstract(): boolean;
1257
1258
  isSharedMemory(): boolean;
1258
1259
  getCreateVisibility(): Visibility;
1260
+ private checkClassNameLength;
1259
1261
  private findSuper;
1260
1262
  private checkMethodNameLength;
1261
1263
  private checkClassConstructorStatic;
@@ -5676,6 +5678,17 @@ declare class PersonalizationObject extends AbstractObject {
5676
5678
  getDescription(): string | undefined;
5677
5679
  }
5678
5680
 
5681
+ declare class PGenericType extends AbstractType {
5682
+ private static readonly singleton;
5683
+ static get(): PGenericType;
5684
+ private constructor();
5685
+ toText(): string;
5686
+ isGeneric(): boolean;
5687
+ toABAP(): string;
5688
+ containsVoid(): boolean;
5689
+ toCDS(): string;
5690
+ }
5691
+
5679
5692
  declare class Plus extends Token {
5680
5693
  static railroad(): string;
5681
5694
  }
@@ -7879,12 +7892,30 @@ declare class Table extends AbstractObject {
7879
7892
  getType(): string;
7880
7893
  getDescription(): string | undefined;
7881
7894
  getSecondaryIndexes(): SecondaryIndex[] | undefined;
7895
+ getFields(): {
7896
+ FIELDNAME: string;
7897
+ ROLLNAME?: string;
7898
+ COMPTYPE?: string;
7899
+ PRECFIELD?: string;
7900
+ LENG?: string;
7901
+ INTLEN?: string;
7902
+ DATATYPE?: string;
7903
+ DECIMALS?: string;
7904
+ KEYFLAG?: string;
7905
+ GROUPNAME?: string;
7906
+ CHECKTABLE?: string;
7907
+ REFTABLE?: string;
7908
+ REFFIELD?: string;
7909
+ REFTYPE?: string;
7910
+ DDTEXT?: string;
7911
+ }[] | undefined;
7882
7912
  getAllowedNaming(): IAllowedNaming;
7883
7913
  setDirty(): void;
7884
7914
  listKeys(reg: IRegistry): string[];
7885
7915
  parseType(reg: IRegistry): AbstractType;
7886
7916
  getTableCategory(): TableCategory | undefined;
7887
7917
  getEnhancementCategory(): EnhancementCategory;
7918
+ private keyFieldsNotFirst;
7888
7919
  private parseXML;
7889
7920
  }
7890
7921
 
@@ -16,7 +16,7 @@ class For extends combi_1.Expression {
16
16
  const itera = (0, combi_1.seq)(_1.InlineFieldDefinition, (0, combi_1.opt)(then), whil);
17
17
  const groupBy = (0, combi_1.seq)("GROUP BY", (0, combi_1.alt)(field_chain_1.FieldChain, (0, combi_1.seq)("(", (0, combi_1.plus)(_1.LoopGroupByComponent), ")")), (0, combi_1.opt)((0, combi_1.seq)((0, combi_1.alt)("ASCENDING", "DESCENDING"), (0, combi_1.opt)("AS TEXT"))), (0, combi_1.opt)("WITHOUT MEMBERS"));
18
18
  const t = (0, combi_1.alt)(_1.TargetField, _1.TargetFieldSymbol);
19
- const groups = (0, combi_1.ver)(version_1.Release.v740sp08, (0, combi_1.seq)("GROUPS", t, "OF", t, "IN", _1.Source, (0, combi_1.optPrio)(groupBy)));
19
+ const groups = (0, combi_1.ver)(version_1.Release.v740sp08, (0, combi_1.seq)("GROUPS", t, "OF", t, "IN", _1.Source, (0, combi_1.optPrio)(groupBy)), { also: combi_1.AlsoIn.OpenABAP });
20
20
  const f = (0, combi_1.seq)("FOR", (0, combi_1.alt)(itera, inn, groups), (0, combi_1.optPrio)(_1.Let));
21
21
  return (0, combi_1.ver)(version_1.Release.v740sp05, f, { also: combi_1.AlsoIn.OpenABAP });
22
22
  }
@@ -5,7 +5,8 @@ const combi_1 = require("../combi");
5
5
  const _1 = require(".");
6
6
  class InlineFieldDefinition extends combi_1.Expression {
7
7
  getRunnable() {
8
- return (0, combi_1.altPrio)((0, combi_1.seq)(_1.Field, "=", _1.Source), (0, combi_1.seq)(_1.Field, "TYPE", _1.TypeName));
8
+ const field = (0, combi_1.altPrio)(_1.Field, _1.FieldSymbol);
9
+ return (0, combi_1.altPrio)((0, combi_1.seq)(field, "=", _1.Source), (0, combi_1.seq)(_1.Field, "TYPE", _1.TypeName));
9
10
  }
10
11
  }
11
12
  exports.InlineFieldDefinition = InlineFieldDefinition;
@@ -7,7 +7,7 @@ const tokens_1 = require("../../1_lexer/tokens");
7
7
  const version_1 = require("../../../version");
8
8
  class ReduceNext extends combi_1.Expression {
9
9
  getRunnable() {
10
- const calcAssign = (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.alt)((0, combi_1.seq)((0, combi_1.tok)(tokens_1.WPlus), "="), (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WDash), "="), "/=", "*=", "&&="));
10
+ const calcAssign = (0, combi_1.ver)(version_1.Release.v754, (0, combi_1.alt)((0, combi_1.seq)((0, combi_1.tok)(tokens_1.WPlus), "="), (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WDash), "="), "/=", "*=", "&&="), { also: combi_1.AlsoIn.OpenABAP });
11
11
  const fields = (0, combi_1.seq)(_1.SimpleTarget, (0, combi_1.altPrio)("=", calcAssign), _1.Source);
12
12
  return (0, combi_1.seq)("NEXT", (0, combi_1.plus)(fields));
13
13
  }
@@ -6,7 +6,7 @@ const version_1 = require("../../../version");
6
6
  class RollbackEntities {
7
7
  getMatcher() {
8
8
  const s = "ROLLBACK ENTITIES";
9
- return (0, combi_1.verNotLang)(version_1.LanguageVersion.KeyUser, (0, combi_1.ver)(version_1.Release.v754, s));
9
+ return (0, combi_1.verNotLang)(version_1.LanguageVersion.KeyUser, (0, combi_1.ver)(version_1.Release.v754, s, { also: combi_1.AlsoIn.OpenABAP }));
10
10
  }
11
11
  }
12
12
  exports.RollbackEntities = RollbackEntities;
@@ -234,7 +234,8 @@ class ABAPFileInformationParser {
234
234
  return ret;
235
235
  }
236
236
  parseConstants(node, visibility) {
237
- var _a, _b;
237
+ var _a;
238
+ var _b;
238
239
  if (node === undefined) {
239
240
  return [];
240
241
  }
@@ -115,6 +115,7 @@ class TypeUtils {
115
115
  || type instanceof basic_1.DataType
116
116
  || type instanceof basic_1.CLikeType
117
117
  || type instanceof basic_1.PackedType
118
+ || type instanceof basic_1.PGenericType
118
119
  || type instanceof basic_1.TimeType
119
120
  || type instanceof enum_type_1.EnumType) {
120
121
  return true;
@@ -330,6 +331,14 @@ class TypeUtils {
330
331
  if (calculated) {
331
332
  return this.isAssignable(source, target);
332
333
  }
334
+ if (target instanceof basic_1.PGenericType) {
335
+ return source instanceof basic_1.PackedType
336
+ || source instanceof basic_1.PGenericType
337
+ || source instanceof basic_1.VoidType
338
+ || source instanceof basic_1.AnyType
339
+ || source instanceof basic_1.DataType
340
+ || source instanceof basic_1.UnknownType;
341
+ }
333
342
  if (source instanceof basic_1.CharacterType) {
334
343
  if (target instanceof basic_1.CharacterType) {
335
344
  if (((_a = source.getAbstractTypeData()) === null || _a === void 0 ? void 0 : _a.derivedFromConstant) === true) {
@@ -444,6 +453,10 @@ class TypeUtils {
444
453
  return false;
445
454
  }
446
455
  }
456
+ else if (source instanceof basic_1.PackedType && target instanceof basic_1.PackedType) {
457
+ return source.getLength() === target.getLength()
458
+ && source.getDecimals() === target.getDecimals();
459
+ }
447
460
  else if (source instanceof basic_1.FloatType) {
448
461
  if (target instanceof basic_1.IntegerType) {
449
462
  return false;
@@ -37,18 +37,30 @@ exports.ComponentCompare = void 0;
37
37
  const Expressions = __importStar(require("../../2_statements/expressions"));
38
38
  const _syntax_input_1 = require("../_syntax_input");
39
39
  const component_chain_1 = require("./component_chain");
40
+ const component_name_1 = require("./component_name");
40
41
  const source_1 = require("./source");
41
42
  class ComponentCompare {
42
- static runSyntax(node, input, type) {
43
+ static runSyntax(node, input, leftType, rightType) {
43
44
  const chain = node.findDirectExpression(Expressions.ComponentChainSimple);
44
45
  if (chain === undefined) {
45
46
  const message = "ComponentCompare, chain not found";
46
47
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
47
48
  return;
48
49
  }
49
- const fieldType = component_chain_1.ComponentChain.runSyntax(type, chain, input);
50
+ const fieldType = component_chain_1.ComponentChain.runSyntax(leftType, chain, input);
50
51
  for (const s of node.findDirectExpressions(Expressions.Source)) {
51
- source_1.Source.runSyntax(s, input, fieldType);
52
+ const fieldChain = s.findDirectExpression(Expressions.FieldChain);
53
+ const first = fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getFirstChild();
54
+ if (rightType && fieldChain && first) {
55
+ let sourceType = rightType;
56
+ if (first.concatTokens().toUpperCase() !== "TABLE_LINE") {
57
+ sourceType = component_name_1.ComponentName.runSyntax(sourceType, first, input);
58
+ }
59
+ component_chain_1.ComponentChain.runSyntax(sourceType, fieldChain, input);
60
+ }
61
+ else {
62
+ source_1.Source.runSyntax(s, input, fieldType);
63
+ }
52
64
  }
53
65
  }
54
66
  }
@@ -37,15 +37,15 @@ exports.ComponentCond = void 0;
37
37
  const Expressions = __importStar(require("../../2_statements/expressions"));
38
38
  const component_compare_1 = require("./component_compare");
39
39
  class ComponentCond {
40
- static runSyntax(node, input, type) {
40
+ static runSyntax(node, input, leftType, rightType) {
41
41
  for (const t of node.findDirectExpressions(Expressions.ComponentCondSub)) {
42
42
  const c = t.findDirectExpression(Expressions.ComponentCond);
43
43
  if (c) {
44
- ComponentCond.runSyntax(c, input, type);
44
+ ComponentCond.runSyntax(c, input, leftType, rightType);
45
45
  }
46
46
  }
47
47
  for (const t of node.findDirectExpressions(Expressions.ComponentCompare)) {
48
- component_compare_1.ComponentCompare.runSyntax(t, input, type);
48
+ component_compare_1.ComponentCompare.runSyntax(t, input, leftType, rightType);
49
49
  }
50
50
  }
51
51
  }
@@ -43,21 +43,14 @@ class FilterBody {
43
43
  if (node === undefined) {
44
44
  return targetType;
45
45
  }
46
- let type = undefined;
46
+ const types = [];
47
47
  for (const s of node.findDirectExpressions(Expressions.Source)) {
48
- if (type === undefined) {
49
- type = source_1.Source.runSyntax(s, input);
50
- }
51
- else {
52
- source_1.Source.runSyntax(s, input);
53
- }
48
+ types.push(source_1.Source.runSyntax(s, input));
54
49
  }
55
- // todo
56
- if (node.findDirectTokenByText("EXCEPT") === undefined) {
57
- const rowType = type instanceof basic_1.TableType ? type.getRowType() : undefined;
58
- component_cond_1.ComponentCond.runSyntax(node.findDirectExpression(Expressions.ComponentCond), input, rowType);
59
- }
60
- return type ? type : targetType;
50
+ const inputRowType = types[0] instanceof basic_1.TableType ? types[0].getRowType() : undefined;
51
+ const filterRowType = types[1] instanceof basic_1.TableType ? types[1].getRowType() : undefined;
52
+ component_cond_1.ComponentCond.runSyntax(node.findDirectExpression(Expressions.ComponentCond), input, inputRowType, filterRowType);
53
+ return types[0] ? types[0] : targetType;
61
54
  }
62
55
  }
63
56
  exports.FilterBody = FilterBody;
@@ -46,7 +46,8 @@ class InlineFieldDefinition {
46
46
  static runSyntax(node, input, targetType) {
47
47
  var _a;
48
48
  let type = undefined;
49
- const field = (_a = node.findDirectExpression(Expressions.Field)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
49
+ const field = (_a = (node.findDirectExpression(Expressions.Field)
50
+ || node.findDirectExpression(Expressions.FieldSymbol))) === null || _a === void 0 ? void 0 : _a.getFirstToken();
50
51
  if (field === undefined) {
51
52
  return undefined;
52
53
  }
@@ -67,6 +67,9 @@ class MethodParam {
67
67
  else if (concat === "TYPE X" || concat.startsWith("TYPE X ")) {
68
68
  return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, basic_1.XGenericType.get(), meta);
69
69
  }
70
+ else if (concat === "TYPE P" || concat.startsWith("TYPE P ")) {
71
+ return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, basic_1.PGenericType.get(), meta);
72
+ }
70
73
  const found = new basic_types_1.BasicTypes(input).parseType(type);
71
74
  if (found) {
72
75
  return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, found, meta);
@@ -41,6 +41,7 @@ const inline_data_1 = require("../expressions/inline_data");
41
41
  const _type_utils_1 = require("../_type_utils");
42
42
  const _syntax_input_1 = require("../_syntax_input");
43
43
  const dereference_1 = require("../expressions/dereference");
44
+ const basic_1 = require("../../types/basic");
44
45
  class Move {
45
46
  runSyntax(node, input) {
46
47
  const targets = node.findDirectExpressions(Expressions.Target);
@@ -76,6 +77,9 @@ class Move {
76
77
  sourceType = dereference_1.Dereference.runSyntax(node, sourceType, input);
77
78
  }
78
79
  if (inline) {
80
+ if (sourceType instanceof basic_1.PackedType && (source === null || source === void 0 ? void 0 : source.findDirectExpression(Expressions.ArithOperator))) {
81
+ sourceType = new basic_1.PackedType(8, 0);
82
+ }
79
83
  inline_data_1.InlineData.runSyntax(inline, input, sourceType);
80
84
  targetType = sourceType;
81
85
  }
@@ -36,6 +36,7 @@ __exportStar(require("./numeric_generic_type"), exports);
36
36
  __exportStar(require("./numeric_type"), exports);
37
37
  __exportStar(require("./object_reference_type"), exports);
38
38
  __exportStar(require("./packed_type"), exports);
39
+ __exportStar(require("./pgeneric_type"), exports);
39
40
  __exportStar(require("./simple_type"), exports);
40
41
  __exportStar(require("./string_type"), exports);
41
42
  __exportStar(require("./structure_type"), exports);
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PGenericType = void 0;
4
+ const _abstract_type_1 = require("./_abstract_type");
5
+ class PGenericType extends _abstract_type_1.AbstractType {
6
+ static get() {
7
+ return this.singleton;
8
+ }
9
+ constructor() {
10
+ super();
11
+ }
12
+ toText() {
13
+ return "```p```";
14
+ }
15
+ isGeneric() {
16
+ return true;
17
+ }
18
+ toABAP() {
19
+ throw new Error("p, generic");
20
+ }
21
+ containsVoid() {
22
+ return false;
23
+ }
24
+ toCDS() {
25
+ return "abap.TODO_PGENERIC";
26
+ }
27
+ }
28
+ exports.PGenericType = PGenericType;
29
+ PGenericType.singleton = new PGenericType();
30
+ //# sourceMappingURL=pgeneric_type.js.map
@@ -97,6 +97,7 @@ class ClassDefinition extends _identifier_1.Identifier {
97
97
  // perform checks after everything has been initialized
98
98
  this.checkInterfaceVisibility(input, node);
99
99
  this.checkMethodsFromSuperClasses(input);
100
+ this.checkClassNameLength(input);
100
101
  this.checkMethodNameLength(input);
101
102
  this.checkClassConstructorStatic(input);
102
103
  }
@@ -147,6 +148,12 @@ class ClassDefinition extends _identifier_1.Identifier {
147
148
  }
148
149
  */
149
150
  ///////////////////
151
+ checkClassNameLength(input) {
152
+ if (this.getName().length > 30) {
153
+ const message = `Class name "${this.getName()}" is too long, maximum length is 30 characters`;
154
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, this.getToken(), message));
155
+ }
156
+ }
150
157
  findSuper(def, input) {
151
158
  var _a;
152
159
  const token = (_a = def === null || def === void 0 ? void 0 : def.findDirectExpression(expressions_1.SuperClassName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DDLValueHelp = exports.DDLForeignKey = exports.DDLForeignKeyTarget = void 0;
3
+ exports.DDLReference = exports.DDLValueHelp = exports.DDLForeignKey = exports.DDLForeignKeyTarget = void 0;
4
4
  const combi_1 = require("../../abap/2_statements/combi");
5
5
  const ddl_literal_1 = require("./ddl_literal");
6
6
  const ddl_name_1 = require("./ddl_name");
@@ -24,4 +24,10 @@ class DDLValueHelp extends combi_1.Expression {
24
24
  }
25
25
  }
26
26
  exports.DDLValueHelp = DDLValueHelp;
27
+ class DDLReference extends combi_1.Expression {
28
+ getRunnable() {
29
+ return (0, combi_1.seq)("WITH", "REFERENCE", "TABLE", ddl_name_1.DDLName, "AND", "REFERENCE", "FIELD", ddl_name_1.DDLName);
30
+ }
31
+ }
32
+ exports.DDLReference = DDLReference;
27
33
  //# sourceMappingURL=ddl_clauses.js.map
@@ -8,7 +8,7 @@ const ddl_name_1 = require("./ddl_name");
8
8
  const ddl_type_1 = require("./ddl_type");
9
9
  class DDLTableField extends combi_1.Expression {
10
10
  getRunnable() {
11
- const trailingClause = (0, combi_1.alt)(ddl_clauses_1.DDLForeignKey, ddl_clauses_1.DDLValueHelp);
11
+ const trailingClause = (0, combi_1.alt)(ddl_clauses_1.DDLForeignKey, ddl_clauses_1.DDLReference, ddl_clauses_1.DDLValueHelp);
12
12
  return (0, combi_1.seq)((0, combi_1.star)(expressions_1.CDSAnnotation), (0, combi_1.optPrio)("KEY"), ddl_name_1.DDLName, ":", ddl_type_1.DDLType, (0, combi_1.optPrio)("NOT NULL"), (0, combi_1.star)(trailingClause), ";");
13
13
  }
14
14
  }
@@ -98,7 +98,8 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
98
98
  return this.textsTranslations;
99
99
  }
100
100
  findTexts(parsed) {
101
- var _a, _b, _c, _d, _e, _f, _g;
101
+ var _a, _b, _c, _d, _e, _f;
102
+ var _g;
102
103
  this.texts = {};
103
104
  if (((_d = (_c = (_b = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _a === void 0 ? void 0 : _a["asx:abap"]) === null || _b === void 0 ? void 0 : _b["asx:values"]) === null || _c === void 0 ? void 0 : _c.TPOOL) === null || _d === void 0 ? void 0 : _d.item) === undefined) {
104
105
  return;
@@ -111,7 +112,7 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
111
112
  if (id !== "R" && t.KEY === undefined) {
112
113
  continue;
113
114
  }
114
- const key = (_g = ((_f = t.KEY) !== null && _f !== void 0 ? _f : t.ID)) === null || _g === void 0 ? void 0 : _g.toUpperCase();
115
+ const key = (_f = ((_g = t.KEY) !== null && _g !== void 0 ? _g : t.ID)) === null || _f === void 0 ? void 0 : _f.toUpperCase();
115
116
  if (key === undefined) {
116
117
  continue;
117
118
  }
@@ -122,7 +123,8 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
122
123
  }
123
124
  }
124
125
  findTextsTranslations(parsed) {
125
- var _a, _b, _c, _d, _e, _f, _g;
126
+ var _a, _b, _c, _d, _e, _f;
127
+ var _g;
126
128
  this.textsTranslations = [];
127
129
  const values = (_d = (_c = (_b = (_a = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _a === void 0 ? void 0 : _a["asx:abap"]) === null || _b === void 0 ? void 0 : _b["asx:values"]) === null || _c === void 0 ? void 0 : _c.I18N_TPOOL) === null || _d === void 0 ? void 0 : _d.item;
128
130
  if (values === undefined) {
@@ -131,7 +133,7 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
131
133
  for (const langItem of (0, xml_utils_1.xmlToArray)(values)) {
132
134
  const textElements = {};
133
135
  for (const item of (0, xml_utils_1.xmlToArray)((_e = langItem.TEXTPOOL) === null || _e === void 0 ? void 0 : _e.item)) {
134
- const key = (_g = ((_f = item.KEY) !== null && _f !== void 0 ? _f : item.ID)) === null || _g === void 0 ? void 0 : _g.toUpperCase();
136
+ const key = (_f = ((_g = item.KEY) !== null && _g !== void 0 ? _g : item.ID)) === null || _f === void 0 ? void 0 : _f.toUpperCase();
135
137
  if (key !== undefined) {
136
138
  textElements[key] = { entry: (0, xml_utils_1.unescape)(item.ENTRY), maxLength: parseInt(item.LENGTH, 10) };
137
139
  }
@@ -126,11 +126,13 @@ class Domain extends _abstract_object_1.AbstractObject {
126
126
  return { updated: true, runtime: end - start };
127
127
  }
128
128
  getFixedValues() {
129
- var _a, _b;
129
+ var _a;
130
+ var _b;
130
131
  return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
131
132
  }
132
133
  getFixedValuesTranslations() {
133
- var _a, _b;
134
+ var _a;
135
+ var _b;
134
136
  return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.valuesTranslations) !== null && _b !== void 0 ? _b : [];
135
137
  }
136
138
  }
@@ -8,7 +8,8 @@ class RenameICFService {
8
8
  this.reg = reg;
9
9
  }
10
10
  buildEdits(obj, oldName, newName) {
11
- var _a, _b, _c, _d;
11
+ var _a, _b;
12
+ var _c, _d;
12
13
  if (!(obj instanceof __1.ICFService)) {
13
14
  throw new Error("RenameICFService, not a ICF Service");
14
15
  }
@@ -33,8 +34,8 @@ class RenameICFService {
33
34
  }
34
35
  return newName;
35
36
  })();
36
- const cleanOldName = (_b = (_a = oldName.match(/^[^ ]+/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : oldName;
37
- const cleanNewName = (_d = (_c = newName.match(/^[^ ]+/)) === null || _c === void 0 ? void 0 : _c[0]) !== null && _d !== void 0 ? _d : newName;
37
+ const cleanOldName = (_c = (_a = oldName.match(/^[^ ]+/)) === null || _a === void 0 ? void 0 : _a[0]) !== null && _c !== void 0 ? _c : oldName;
38
+ const cleanNewName = (_d = (_b = newName.match(/^[^ ]+/)) === null || _b === void 0 ? void 0 : _b[0]) !== null && _d !== void 0 ? _d : newName;
38
39
  let changes = [];
39
40
  const helper = new renamer_helper_1.RenamerHelper(this.reg);
40
41
  changes = changes.concat(helper.buildURLFileEdits(obj, cleanOldName, cleanNewName));
@@ -80,6 +80,13 @@ class Table extends _abstract_object_1.AbstractObject {
80
80
  }
81
81
  return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.secondaryIndexes;
82
82
  }
83
+ getFields() {
84
+ var _a;
85
+ if (this.parsedData === undefined) {
86
+ this.parseXML();
87
+ }
88
+ return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.fields;
89
+ }
83
90
  getAllowedNaming() {
84
91
  let length = 30;
85
92
  const regex = /^((\/[A-Z_\d]{3,8}\/)|[a-zA-Z0-9]{3}|CI_)\w+$/;
@@ -132,9 +139,13 @@ class Table extends _abstract_object_1.AbstractObject {
132
139
  && this.parsedData.dataClass === "USER3") {
133
140
  return new Types.UnknownType("Data class = USER3 not allowed in cloud");
134
141
  }
135
- if (this.getTableCategory() === TableCategory.Transparent
136
- && this.listKeys(reg).length === 0) {
137
- return new Types.UnknownType("Table " + this.getName() + " has no key fields");
142
+ if (this.getTableCategory() === TableCategory.Transparent) {
143
+ if (this.listKeys(reg).length === 0) {
144
+ return new Types.UnknownType("Table " + this.getName() + " has no key fields");
145
+ }
146
+ else if (this.keyFieldsNotFirst()) {
147
+ return new Types.UnknownType("Table " + this.getName() + " key fields must be first");
148
+ }
138
149
  }
139
150
  if (this.parsedType) {
140
151
  return this.parsedType;
@@ -310,6 +321,21 @@ class Table extends _abstract_object_1.AbstractObject {
310
321
  return this.parsedData.enhancementCategory;
311
322
  }
312
323
  ///////////////
324
+ keyFieldsNotFirst() {
325
+ var _a;
326
+ let seenNonKey = false;
327
+ for (const field of ((_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.fields) || []) {
328
+ if (field.KEYFLAG === "X") {
329
+ if (seenNonKey === true) {
330
+ return true;
331
+ }
332
+ }
333
+ else {
334
+ seenNonKey = true;
335
+ }
336
+ }
337
+ return false;
338
+ }
313
339
  parseXML() {
314
340
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
315
341
  const parsed = super.parseRaw2();
@@ -346,6 +372,8 @@ class Table extends _abstract_object_1.AbstractObject {
346
372
  KEYFLAG: field.KEYFLAG,
347
373
  GROUPNAME: field.GROUPNAME,
348
374
  CHECKTABLE: field.CHECKTABLE,
375
+ REFTABLE: field.REFTABLE,
376
+ REFFIELD: field.REFFIELD,
349
377
  REFTYPE: field.REFTYPE,
350
378
  DDTEXT: field.DDTEXT,
351
379
  });
@@ -25,7 +25,8 @@ class WebMIME extends _abstract_object_1.AbstractObject {
25
25
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.params[name.toLowerCase()];
26
26
  }
27
27
  getParameters() {
28
- var _a, _b;
28
+ var _a;
29
+ var _b;
29
30
  this.parse();
30
31
  return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.params) !== null && _b !== void 0 ? _b : {};
31
32
  }
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.9";
78
+ return "2.120.11";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -126,6 +126,7 @@ __exportStar(require("./no_comments_between_methods"), exports);
126
126
  __exportStar(require("./no_external_form_calls"), exports);
127
127
  __exportStar(require("./no_inline_in_optional_branches"), exports);
128
128
  __exportStar(require("./no_macros"), exports);
129
+ __exportStar(require("./no_mandt_in_database_operations"), exports);
129
130
  __exportStar(require("./no_prefixes"), exports);
130
131
  __exportStar(require("./no_public_attributes"), exports);
131
132
  __exportStar(require("./no_yoda_conditions"), exports);
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.NoMandtInDatabaseOperations = exports.NoMandtInDatabaseOperationsConf = void 0;
37
+ const Expressions = __importStar(require("../abap/2_statements/expressions"));
38
+ const Statements = __importStar(require("../abap/2_statements/statements"));
39
+ const issue_1 = require("../issue");
40
+ const _abap_rule_1 = require("./_abap_rule");
41
+ const _basic_rule_config_1 = require("./_basic_rule_config");
42
+ const _irule_1 = require("./_irule");
43
+ class NoMandtInDatabaseOperationsConf extends _basic_rule_config_1.BasicRuleConfig {
44
+ }
45
+ exports.NoMandtInDatabaseOperationsConf = NoMandtInDatabaseOperationsConf;
46
+ class NoMandtInDatabaseOperations extends _abap_rule_1.ABAPRule {
47
+ constructor() {
48
+ super(...arguments);
49
+ this.conf = new NoMandtInDatabaseOperationsConf();
50
+ }
51
+ getMetadata() {
52
+ return {
53
+ key: "no_mandt_in_database_operations",
54
+ title: "No MANDT in database operations",
55
+ shortDescription: "Do not specify the client in database operations; the ABAP runtime handles it automatically.",
56
+ extendedInformation: "Only check for the name MANDT, not for the field type. The rule does not check for dynamic SQL.",
57
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Syntax],
58
+ badExample: `SELECT * FROM zcustomers
59
+ CLIENT SPECIFIED
60
+ WHERE mandt = @sy-mandt
61
+ INTO TABLE @DATA(customers).`,
62
+ goodExample: `SELECT * FROM zcustomers
63
+ INTO TABLE @DATA(customers).`,
64
+ };
65
+ }
66
+ getConfig() {
67
+ return this.conf;
68
+ }
69
+ setConfig(conf) {
70
+ this.conf = conf;
71
+ }
72
+ runParsed(file) {
73
+ const issues = [];
74
+ for (const statement of file.getStatements()) {
75
+ if (this.isDatabaseOperation(statement) === false) {
76
+ continue;
77
+ }
78
+ const mandt = this.findMandtInCondition(statement);
79
+ if (mandt !== undefined) {
80
+ const issue = issue_1.Issue.atToken(file, mandt.getFirstToken(), this.getMetadata().title, this.getMetadata().key, this.conf.severity);
81
+ issues.push(issue);
82
+ continue;
83
+ }
84
+ const explicitClient = this.findExplicitClient(statement);
85
+ if (explicitClient !== undefined) {
86
+ const issue = issue_1.Issue.atToken(file, explicitClient, this.getMetadata().title, this.getMetadata().key, this.conf.severity);
87
+ issues.push(issue);
88
+ }
89
+ }
90
+ return issues;
91
+ }
92
+ isDatabaseOperation(statement) {
93
+ const type = statement.get();
94
+ return type instanceof Statements.DeleteDatabase
95
+ || type instanceof Statements.InsertDatabase
96
+ || type instanceof Statements.MergeDatabase
97
+ || type instanceof Statements.ModifyDatabase
98
+ || type instanceof Statements.OpenCursor
99
+ || type instanceof Statements.Select
100
+ || type instanceof Statements.SelectLoop
101
+ || type instanceof Statements.UpdateDatabase
102
+ || type instanceof Statements.With
103
+ || type instanceof Statements.WithLoop;
104
+ }
105
+ findMandtInCondition(statement) {
106
+ for (const condition of statement.findAllExpressions(Expressions.SQLCond)) {
107
+ for (const field of condition.findAllExpressions(Expressions.SQLFieldName)) {
108
+ const name = field.concatTokens().toUpperCase();
109
+ if (name === "MANDT" || name.endsWith("~MANDT")) {
110
+ return field;
111
+ }
112
+ }
113
+ }
114
+ return undefined;
115
+ }
116
+ findExplicitClient(statement) {
117
+ var _a, _b;
118
+ const tokens = statement.getTokens();
119
+ for (let index = 0; index < tokens.length; index++) {
120
+ const current = tokens[index].getStr().toUpperCase();
121
+ const next = (_a = tokens[index + 1]) === null || _a === void 0 ? void 0 : _a.getStr().toUpperCase();
122
+ const afterNext = (_b = tokens[index + 2]) === null || _b === void 0 ? void 0 : _b.getStr().toUpperCase();
123
+ if ((current === "CLIENT" && next === "SPECIFIED")
124
+ || (current === "USING" && (next === "CLIENT" || next === "CLIENTS"))
125
+ || (current === "USING" && next === "ALL" && afterNext === "CLIENTS")) {
126
+ return current === "CLIENT" ? tokens[index] : tokens[index + (next === "ALL" ? 2 : 1)];
127
+ }
128
+ }
129
+ return undefined;
130
+ }
131
+ }
132
+ exports.NoMandtInDatabaseOperations = NoMandtInDatabaseOperations;
133
+ //# sourceMappingURL=no_mandt_in_database_operations.js.map
@@ -61,6 +61,7 @@ class XMLConsistency {
61
61
  extendedInformation: `Checks:
62
62
  * XML is well-formed and parseable
63
63
  * Naming for CLAS and INTF objects
64
+ * QUAN fields in TABL objects have reference table and field values
64
65
  * Texts and translations do not exceed maximum allowed length.`,
65
66
  tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
66
67
  };
@@ -75,6 +76,7 @@ class XMLConsistency {
75
76
  return this;
76
77
  }
77
78
  run(obj) {
79
+ var _a;
78
80
  const issues = [];
79
81
  const file = obj.getXMLFile();
80
82
  if (file === undefined) {
@@ -86,6 +88,14 @@ class XMLConsistency {
86
88
  if (res !== true) {
87
89
  issues.push(issue_1.Issue.atRow(file, 1, "XML parser error: " + res.err.msg, this.getMetadata().key, this.conf.severity));
88
90
  }
91
+ else {
92
+ for (const attribute of ["version", "serializer_version"]) {
93
+ const value = (_a = xml.match(new RegExp(`<abapGit\\b[^>]*\\b${attribute}="([^"]+)"`))) === null || _a === void 0 ? void 0 : _a[1];
94
+ if (value !== undefined && value.match(/^v\d\.\d\.\d$/) === null) {
95
+ issues.push(issue_1.Issue.atRow(file, 1, `Unexpected abapGit ${attribute} "${value}"`, this.getMetadata().key, this.conf.severity));
96
+ }
97
+ }
98
+ }
89
99
  }
90
100
  // todo, have some XML validation in each object?
91
101
  if (obj instanceof Objects.Class) {
@@ -106,6 +116,9 @@ class XMLConsistency {
106
116
  else if (obj instanceof Objects.MessageClass) {
107
117
  issues.push(...this.runMessageClass(obj, file));
108
118
  }
119
+ else if (obj instanceof Objects.Table) {
120
+ issues.push(...this.runTable(obj, file));
121
+ }
109
122
  if (obj instanceof _abap_object_1.ABAPObject) {
110
123
  issues.push(...this.runTextPool(obj, file));
111
124
  }
@@ -249,6 +262,18 @@ class XMLConsistency {
249
262
  }
250
263
  return issues;
251
264
  }
265
+ runTable(obj, file) {
266
+ var _a, _b;
267
+ var _c;
268
+ const issues = [];
269
+ for (const field of (_c = obj.getFields()) !== null && _c !== void 0 ? _c : []) {
270
+ if (field.DATATYPE === "QUAN" && (!((_a = field.REFTABLE) === null || _a === void 0 ? void 0 : _a.trim()) || !((_b = field.REFFIELD) === null || _b === void 0 ? void 0 : _b.trim()))) {
271
+ const message = `QUAN field ${field.FIELDNAME} must have REFTABLE and REFFIELD set`;
272
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
273
+ }
274
+ }
275
+ return issues;
276
+ }
252
277
  }
253
278
  exports.XMLConsistency = XMLConsistency;
254
279
  //# sourceMappingURL=xml_consistency.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.120.9",
3
+ "version": "2.120.11",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",
@@ -52,20 +52,20 @@
52
52
  },
53
53
  "homepage": "https://abaplint.org",
54
54
  "devDependencies": {
55
- "@microsoft/api-extractor": "^7.58.9",
55
+ "@microsoft/api-extractor": "^7.58.12",
56
56
  "@types/chai": "^4.3.20",
57
57
  "@types/mocha": "^10.0.10",
58
- "@types/node": "^24.13.2",
58
+ "@types/node": "^24.13.3",
59
59
  "c8": "^11.0.0",
60
60
  "chai": "^4.5.0",
61
- "eslint": "^9.39.4",
61
+ "eslint": "^9.39.5",
62
62
  "mocha": "^11.7.6",
63
63
  "source-map-support": "^0.5.21",
64
64
  "ts-json-schema-generator": "^2.9.0",
65
- "typescript": "^6.0.3"
65
+ "typescript": "^7.0.2"
66
66
  },
67
67
  "dependencies": {
68
- "fast-xml-parser": "^5.9.3",
68
+ "fast-xml-parser": "^5.10.1",
69
69
  "json5": "^2.2.3",
70
70
  "vscode-languageserver-types": "^3.18.0"
71
71
  }