@abaplint/core 2.120.43 → 2.120.45

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.
@@ -558,12 +558,22 @@ declare namespace BasicTypes {
558
558
  export { BasicTypes }
559
559
 
560
560
  declare class BehaviorDefinition extends AbstractObject {
561
+ private parsedData;
561
562
  getType(): string;
562
563
  getAllowedNaming(): {
563
564
  maxLength: number;
564
565
  allowNamespace: boolean;
565
566
  };
566
567
  getDescription(): string | undefined;
568
+ setDirty(): void;
569
+ findSourceFile(): IFile | undefined;
570
+ listEntities(): readonly {
571
+ name: string;
572
+ alias: string | undefined;
573
+ }[];
574
+ /** finds the entity name for a given alias, undefined if the alias is not defined */
575
+ findEntityNameByAlias(alias: string): string | undefined;
576
+ private parseSource;
567
577
  }
568
578
 
569
579
  declare class BehaviorDefinitionName extends Expression {
@@ -1626,6 +1636,8 @@ export declare class CurrentScope {
1626
1636
  addSQLConversion(fieldName: string, message: string, token: Token): void;
1627
1637
  findFunctionModule(name: string | undefined): FunctionModuleDefinition | undefined;
1628
1638
  findObjectDefinition(name: string | undefined): IClassDefinition | IInterfaceDefinition | undefined;
1639
+ /** the BDEF from "FOR BEHAVIOR OF" of the enclosing global class, undefined if not a behavior pool */
1640
+ findBehaviorDefinition(): BehaviorDefinition | undefined;
1629
1641
  isBadiDef(name: string): boolean;
1630
1642
  existsObject(name: string | undefined): {
1631
1643
  id: Identifier | undefined;
@@ -3888,6 +3900,8 @@ declare interface InfoClassDefinition extends InfoInterfaceDefinition {
3888
3900
  duration: Duration | undefined;
3889
3901
  riskLevel: RiskLevel | undefined;
3890
3902
  isSharedMemory: boolean;
3903
+ /** name of the BDEF from "FOR BEHAVIOR OF", undefined if not a behavior pool */
3904
+ behaviorDefinitionName: string | undefined;
3891
3905
  }
3892
3906
 
3893
3907
  declare interface InfoClassImplementation {
@@ -4599,6 +4613,11 @@ declare class LockObject extends AbstractObject {
4599
4613
  getAllowedNaming(): IAllowedNaming;
4600
4614
  setDirty(): void;
4601
4615
  getPrimaryTable(): string | undefined;
4616
+ getParameters(): {
4617
+ VIEWFIELD: string;
4618
+ TABNAME?: string;
4619
+ FIELDNAME?: string;
4620
+ }[] | undefined;
4602
4621
  parseType(reg: IRegistry): AbstractType;
4603
4622
  parse(): {
4604
4623
  updated: boolean;
@@ -5324,6 +5343,7 @@ declare namespace Objects {
5324
5343
  AuthorizationObjectExtension,
5325
5344
  AuthorizationObject,
5326
5345
  BADIDefinition,
5346
+ ParsedBehaviorDefinition,
5327
5347
  BehaviorDefinition,
5328
5348
  BRFPlusSystemApplication,
5329
5349
  BSPApplication,
@@ -5624,6 +5644,14 @@ declare class ParenRightW extends Token {
5624
5644
  static railroad(): string;
5625
5645
  }
5626
5646
 
5647
+ declare type ParsedBehaviorDefinition = {
5648
+ /** entities defined in the behavior definition, alias is undefined if not specified */
5649
+ entities: {
5650
+ name: string;
5651
+ alias: string | undefined;
5652
+ }[];
5653
+ };
5654
+
5627
5655
  declare type ParsedDataDefinition = {
5628
5656
  sqlViewName: string | undefined;
5629
5657
  definitionName: string | undefined;
@@ -7938,6 +7966,8 @@ declare class Table extends AbstractObject {
7938
7966
  listKeys(reg: IRegistry): string[];
7939
7967
  parseType(reg: IRegistry): AbstractType;
7940
7968
  getTableCategory(): TableCategory | undefined;
7969
+ getDeliveryClass(): string | undefined;
7970
+ getSizeCategory(): string | undefined;
7941
7971
  getEnhancementCategory(): EnhancementCategory;
7942
7972
  private keyFieldsNotFirst;
7943
7973
  private parseXML;
@@ -37,6 +37,7 @@ exports.ABAPFileInformationParser = void 0;
37
37
  const Structures = __importStar(require("../3_structures/structures"));
38
38
  const Expressions = __importStar(require("../2_statements/expressions"));
39
39
  const Statements = __importStar(require("../2_statements/statements"));
40
+ const nodes_1 = require("../nodes");
40
41
  const _identifier_1 = require("./_identifier");
41
42
  const Tokens = __importStar(require("../1_lexer/tokens"));
42
43
  const visibility_1 = require("./visibility");
@@ -176,6 +177,7 @@ class ABAPFileInformationParser {
176
177
  riskLevel,
177
178
  isAbstract: (cdef === null || cdef === void 0 ? void 0 : cdef.findDirectTokenByText("ABSTRACT")) !== undefined,
178
179
  isSharedMemory: concat.includes(" SHARED MEMORY ENABLED"),
180
+ behaviorDefinitionName: this.findBehaviorDefinitionName(cdef),
179
181
  isFinal: found.findFirstExpression(Expressions.ClassFinal) !== undefined,
180
182
  aliases,
181
183
  attributes,
@@ -185,6 +187,20 @@ class ABAPFileInformationParser {
185
187
  return classes;
186
188
  }
187
189
  ///////////////////
190
+ /** "FOR BEHAVIOR OF" and "FOR EVENTS OF" both use the BehaviorDefinitionName expression,
191
+ * so look at the token two positions before the expression to tell them apart */
192
+ findBehaviorDefinitionName(cdef) {
193
+ const children = (cdef === null || cdef === void 0 ? void 0 : cdef.getChildren()) || [];
194
+ for (let i = 2; i < children.length; i++) {
195
+ const child = children[i];
196
+ if (child instanceof nodes_1.ExpressionNode
197
+ && child.get() instanceof Expressions.BehaviorDefinitionName
198
+ && children[i - 2].concatTokens().toUpperCase() === "BEHAVIOR") {
199
+ return child.concatTokens();
200
+ }
201
+ }
202
+ return undefined;
203
+ }
188
204
  getImplementing(input) {
189
205
  const ret = [];
190
206
  for (const node of input.findAllStatements(Statements.InterfaceDef)) {
@@ -232,6 +232,18 @@ class CurrentScope {
232
232
  }
233
233
  return undefined;
234
234
  }
235
+ /** the BDEF from "FOR BEHAVIOR OF" of the enclosing global class, undefined if not a behavior pool */
236
+ findBehaviorDefinition() {
237
+ var _a;
238
+ if (this.parentObj.getType() !== "CLAS") {
239
+ return undefined;
240
+ }
241
+ const name = (_a = this.parentObj.getClassDefinition()) === null || _a === void 0 ? void 0 : _a.behaviorDefinitionName;
242
+ if (name === undefined) {
243
+ return undefined;
244
+ }
245
+ return this.reg.getObject("BDEF", name);
246
+ }
235
247
  isBadiDef(name) {
236
248
  const upper = name.toUpperCase();
237
249
  for (const enhs of this.reg.getObjectsByType("ENHS")) {
@@ -345,7 +345,7 @@ class BasicTypes {
345
345
  return undefined;
346
346
  }
347
347
  parseTable(node, name) {
348
- var _a, _b, _c, _d;
348
+ var _a, _b, _c;
349
349
  const typename = node.findFirstExpression(Expressions.TypeName) || node.findFirstExpression(Expressions.EntityAssociation);
350
350
  const text = (_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
351
351
  if (text === undefined) {
@@ -482,25 +482,31 @@ class BasicTypes {
482
482
  return new Types.TableType(structure, options);
483
483
  }
484
484
  else if (typename && this.isRAPTableFor(text)) {
485
- const name = typename.concatTokens();
486
- const ddlsName = this.getRAPBaseEntityName(name);
487
- const type = (_d = this.input.scope.getDDIC().lookupDDLS(ddlsName)) === null || _d === void 0 ? void 0 : _d.type;
488
- if (type) {
489
- return new Types.TableType(basic_1.VoidType.get("RAP-TODO"), options);
490
- }
491
- else if (this.isRAPDerivedEntityName(name)) {
492
- return Types.VoidType.get(name);
493
- }
494
- else if (this.input.scope.getDDIC().inErrorNamespace(ddlsName)) {
495
- return new Types.UnknownType(`DDLS ${ddlsName} not found`);
496
- }
497
- else {
498
- return Types.VoidType.get(name);
499
- }
485
+ return this.rapTableFor(typename.concatTokens(), options);
500
486
  }
501
487
  // fallback to old style syntax, OCCURS etc
502
488
  return this.parseType(node, name);
503
489
  }
490
+ /** type of a RAP derived table type, ie the "TABLE FOR LOCK zentity" part of a type */
491
+ rapTableFor(entityName, options) {
492
+ var _a;
493
+ const ddlsName = this.resolveRAPAlias(this.getRAPBaseEntityName(entityName));
494
+ if ((_a = this.input.scope.getDDIC().lookupDDLS(ddlsName)) === null || _a === void 0 ? void 0 : _a.type) {
495
+ return new Types.TableType(basic_1.VoidType.get("RAP-TODO"), options !== null && options !== void 0 ? options : {
496
+ withHeader: false,
497
+ keyType: Types.TableKeyType.user,
498
+ primaryKey: { name: "primary_key", type: basic_1.TableAccessType.standard, isUnique: false, keyFields: [] },
499
+ secondary: [],
500
+ });
501
+ }
502
+ else if (this.isRAPDerivedEntityName(entityName)) {
503
+ return Types.VoidType.get(entityName);
504
+ }
505
+ else if (this.input.scope.getDDIC().inErrorNamespace(ddlsName)) {
506
+ return new Types.UnknownType(`DDLS ${ddlsName} not found`);
507
+ }
508
+ return Types.VoidType.get(entityName);
509
+ }
504
510
  parseType(node, qualifiedName) {
505
511
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
506
512
  const typeName = node.findFirstExpression(Expressions.TypeName);
@@ -694,6 +700,12 @@ class BasicTypes {
694
700
  const splitAt = Math.min(...candidates);
695
701
  return name.substring(0, splitAt);
696
702
  }
703
+ /** inside a behavior pool the entities are referenced via the aliases defined in the BDEF */
704
+ resolveRAPAlias(name) {
705
+ var _a;
706
+ var _b;
707
+ return (_b = (_a = this.input.scope.findBehaviorDefinition()) === null || _a === void 0 ? void 0 : _a.findEntityNameByAlias(name)) !== null && _b !== void 0 ? _b : name;
708
+ }
697
709
  isRAPDerivedEntityName(name) {
698
710
  return name.includes("\\") || name.includes("~");
699
711
  }
@@ -131,6 +131,19 @@ class ValueBody {
131
131
  const message = "VALUE, source type CharacterType not compatible with StringType";
132
132
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
133
133
  }
134
+ else if (this.insertsUsingTableKey(targetType)) {
135
+ // only STANDARD tables append the rows, and thus allow padding of shorter c and x values
136
+ const row = this.characterOrHexLength(rowType);
137
+ const source = this.characterOrHexLength(sourceType);
138
+ if (row !== undefined
139
+ && source !== undefined
140
+ && row.abap === source.abap
141
+ && row.length !== source.length) {
142
+ const message = `VALUE, source type ${source.abap} LENGTH ${source.length} not compatible ` +
143
+ `with row type ${row.abap} LENGTH ${row.length}`;
144
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
145
+ }
146
+ }
134
147
  }
135
148
  }
136
149
  if (letScoped === true) {
@@ -144,6 +157,25 @@ class ValueBody {
144
157
  }
145
158
  return targetType ? targetType : type;
146
159
  }
160
+ /** SORTED and HASHED tables insert the constructed rows using the table key, which
161
+ * requires the rows to be compatible with the row type. STANDARD tables only append
162
+ * the rows, so shorter c and x values are padded on the right instead. */
163
+ static insertsUsingTableKey(targetType) {
164
+ if (!(targetType instanceof basic_1.TableType)) {
165
+ return false;
166
+ }
167
+ const accessType = targetType.getAccessType();
168
+ return accessType === basic_1.TableAccessType.sorted || accessType === basic_1.TableAccessType.hashed;
169
+ }
170
+ static characterOrHexLength(type) {
171
+ if (type instanceof basic_1.CharacterType) {
172
+ return { abap: "c", length: type.getLength() };
173
+ }
174
+ else if (type instanceof basic_1.HexType) {
175
+ return { abap: "x", length: type.getLength() };
176
+ }
177
+ return undefined;
178
+ }
147
179
  }
148
180
  exports.ValueBody = ValueBody;
149
181
  //# sourceMappingURL=value_body.js.map
@@ -41,6 +41,7 @@ const _typed_identifier_1 = require("./_typed_identifier");
41
41
  const basic_1 = require("./basic");
42
42
  const method_def_returning_1 = require("../5_syntax/expressions/method_def_returning");
43
43
  const method_param_1 = require("../5_syntax/expressions/method_param");
44
+ const basic_types_1 = require("../5_syntax/basic_types");
44
45
  const _object_oriented_1 = require("../5_syntax/_object_oriented");
45
46
  const _reference_1 = require("../5_syntax/_reference");
46
47
  const identifier_1 = require("../1_lexer/tokens/identifier");
@@ -228,24 +229,37 @@ class MethodParameters {
228
229
  }
229
230
  }
230
231
  workaroundRAP(node, input, parentName) {
232
+ var _a;
231
233
  const resultName = node.findExpressionAfterToken("RESULT");
232
234
  const concat = node.concatTokens().toUpperCase();
233
235
  const isRap = node.findExpressionAfterToken("IMPORTING")
234
236
  || (concat.includes(" IMPORTING REQUEST ") ? node.findExpressionAfterToken("REQUEST") : undefined);
235
237
  if (isRap) {
238
+ // "FOR LOCK" handlers have a well defined signature, so the types can be derived
239
+ const lockEntity = concat.includes(" FOR LOCK ")
240
+ ? (_a = node.findExpressionAfterToken("LOCK")) === null || _a === void 0 ? void 0 : _a.concatTokens()
241
+ : undefined;
236
242
  for (const foo of node.findDirectExpressions(Expressions.MethodParamName)) {
237
243
  if (foo === resultName) {
238
244
  continue;
239
245
  }
240
- this.importing.push(new _typed_identifier_1.TypedIdentifier(foo.getFirstToken(), input.filename, basic_1.VoidType.get("RapMethodParameter"), ["importing" /* IdentifierMeta.MethodImporting */]));
246
+ const type = lockEntity === undefined
247
+ ? basic_1.VoidType.get("RapMethodParameter")
248
+ : new basic_types_1.BasicTypes(input).rapTableFor(lockEntity);
249
+ this.importing.push(new _typed_identifier_1.TypedIdentifier(foo.getFirstToken(), input.filename, type, ["importing" /* IdentifierMeta.MethodImporting */]));
250
+ }
251
+ if (lockEntity !== undefined) {
252
+ // note: "mapped" is not part of the signature for "FOR LOCK"
253
+ const token = isRap.getFirstToken();
254
+ this.exporting.push(new _typed_identifier_1.TypedIdentifier(new identifier_1.Identifier(token.getStart(), "failed"), input.filename, basic_1.VoidType.get(`RESPONSE FOR FAILED EARLY ${lockEntity}`), ["exporting" /* IdentifierMeta.MethodExporting */]));
255
+ this.exporting.push(new _typed_identifier_1.TypedIdentifier(new identifier_1.Identifier(token.getStart(), "reported"), input.filename, basic_1.VoidType.get(`RESPONSE FOR REPORTED EARLY ${lockEntity}`), ["exporting" /* IdentifierMeta.MethodExporting */]));
241
256
  }
242
- if (concat.includes(" FOR VALIDATE ")
257
+ else if (concat.includes(" FOR VALIDATE ")
243
258
  || concat.includes(" FOR BEHAVIOR ")
244
259
  || concat.includes(" FOR DETERMINE ")
245
260
  || concat.includes(" FOR FEATURES ")
246
261
  || concat.includes(" FOR INSTANCE FEATURES ")
247
262
  || concat.includes(" FOR GLOBAL AUTHORIZATION ")
248
- || concat.includes(" FOR LOCK ")
249
263
  || concat.includes(" FOR PRECHECK ")
250
264
  || concat.includes(" FOR NUMBERING ")
251
265
  || concat.includes(" FOR READ ")
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BehaviorDefinition = void 0;
4
4
  const _abstract_object_1 = require("./_abstract_object");
5
5
  class BehaviorDefinition extends _abstract_object_1.AbstractObject {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.parsedData = undefined;
9
+ }
6
10
  getType() {
7
11
  return "BDEF";
8
12
  }
@@ -16,6 +20,49 @@ class BehaviorDefinition extends _abstract_object_1.AbstractObject {
16
20
  // todo
17
21
  return undefined;
18
22
  }
23
+ setDirty() {
24
+ this.parsedData = undefined;
25
+ super.setDirty();
26
+ }
27
+ findSourceFile() {
28
+ return this.getFiles().find(f => f.getFilename().endsWith(".asbdef"));
29
+ }
30
+ listEntities() {
31
+ return this.parseSource().entities;
32
+ }
33
+ /** finds the entity name for a given alias, undefined if the alias is not defined */
34
+ findEntityNameByAlias(alias) {
35
+ var _a;
36
+ const upper = alias.toUpperCase();
37
+ for (const entity of this.listEntities()) {
38
+ if (((_a = entity.alias) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === upper) {
39
+ return entity.name;
40
+ }
41
+ }
42
+ return undefined;
43
+ }
44
+ /////////////////////////
45
+ parseSource() {
46
+ var _a;
47
+ if (this.parsedData !== undefined) {
48
+ return this.parsedData;
49
+ }
50
+ this.parsedData = { entities: [] };
51
+ const raw = (_a = this.findSourceFile()) === null || _a === void 0 ? void 0 : _a.getRaw();
52
+ if (raw === undefined) {
53
+ return this.parsedData;
54
+ }
55
+ // BDEF uses "//" for line comments
56
+ const stripped = raw.replace(/\/\/.*$/gm, "");
57
+ // eg. "define behavior for ZI_Booking alias Booking", also "define abstract behavior for ..."
58
+ const regex = /\bdefine\s+(?:\w+\s+)*?behavior\s+for\s+([\w/]+)(?:\s+alias\s+(\w+))?/gi;
59
+ let match = regex.exec(stripped);
60
+ while (match !== null) {
61
+ this.parsedData.entities.push({ name: match[1], alias: match[2] });
62
+ match = regex.exec(stripped);
63
+ }
64
+ return this.parsedData;
65
+ }
19
66
  }
20
67
  exports.BehaviorDefinition = BehaviorDefinition;
21
68
  //# sourceMappingURL=behavior_definition.js.map
@@ -4,6 +4,7 @@ exports.LockObject = void 0;
4
4
  const basic_1 = require("../abap/types/basic");
5
5
  const ddic_1 = require("../ddic");
6
6
  const _abstract_object_1 = require("./_abstract_object");
7
+ const xml_utils_1 = require("../xml_utils");
7
8
  class LockObject extends _abstract_object_1.AbstractObject {
8
9
  getType() {
9
10
  return "ENQU";
@@ -24,6 +25,11 @@ class LockObject extends _abstract_object_1.AbstractObject {
24
25
  this.parse();
25
26
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.primaryTable;
26
27
  }
28
+ getParameters() {
29
+ var _a;
30
+ this.parse();
31
+ return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.parameters;
32
+ }
27
33
  parseType(reg) {
28
34
  var _a;
29
35
  this.parse();
@@ -48,7 +54,7 @@ class LockObject extends _abstract_object_1.AbstractObject {
48
54
  }
49
55
  }
50
56
  parse() {
51
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
57
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
52
58
  if (this.parsedXML) {
53
59
  return { updated: false, runtime: 0 };
54
60
  }
@@ -62,6 +68,18 @@ class LockObject extends _abstract_object_1.AbstractObject {
62
68
  }
63
69
  this.parsedXML.primaryTable = (_f = (_e = (_d = (_c = parsed.abapGit) === null || _c === void 0 ? void 0 : _c["asx:abap"]) === null || _d === void 0 ? void 0 : _d["asx:values"]) === null || _e === void 0 ? void 0 : _e.DD25V) === null || _f === void 0 ? void 0 : _f.ROOTTAB;
64
70
  this.parsedXML.description = (_k = (_j = (_h = (_g = parsed.abapGit) === null || _g === void 0 ? void 0 : _g["asx:abap"]) === null || _h === void 0 ? void 0 : _h["asx:values"]) === null || _j === void 0 ? void 0 : _j.DD25V) === null || _k === void 0 ? void 0 : _k.DDTEXT;
71
+ this.parsedXML.parameters = [];
72
+ const parameters = (_o = (_m = (_l = parsed.abapGit) === null || _l === void 0 ? void 0 : _l["asx:abap"]) === null || _m === void 0 ? void 0 : _m["asx:values"]) === null || _o === void 0 ? void 0 : _o.DD27P_TABLE;
73
+ for (const parameter of (0, xml_utils_1.xmlToArray)(parameters === null || parameters === void 0 ? void 0 : parameters.DD27P)) {
74
+ if (typeof (parameter === null || parameter === void 0 ? void 0 : parameter.VIEWFIELD) !== "string") {
75
+ continue;
76
+ }
77
+ this.parsedXML.parameters.push({
78
+ VIEWFIELD: parameter.VIEWFIELD,
79
+ TABNAME: parameter.TABNAME,
80
+ FIELDNAME: parameter.FIELDNAME,
81
+ });
82
+ }
65
83
  const end = Date.now();
66
84
  return { updated: true, runtime: end - start };
67
85
  }
@@ -310,6 +310,20 @@ class Table extends _abstract_object_1.AbstractObject {
310
310
  }
311
311
  return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.tableCategory;
312
312
  }
313
+ getDeliveryClass() {
314
+ var _a;
315
+ if (this.parsedData === undefined) {
316
+ this.parseXML();
317
+ }
318
+ return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.deliveryClass;
319
+ }
320
+ getSizeCategory() {
321
+ var _a;
322
+ if (this.parsedData === undefined) {
323
+ this.parseXML();
324
+ }
325
+ return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.sizeCategory;
326
+ }
313
327
  getEnhancementCategory() {
314
328
  var _a;
315
329
  if (this.parsedData === undefined) {
@@ -337,7 +351,7 @@ class Table extends _abstract_object_1.AbstractObject {
337
351
  return false;
338
352
  }
339
353
  parseXML() {
340
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
354
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
341
355
  const parsed = super.parseRaw2();
342
356
  if (parsed === undefined) {
343
357
  return;
@@ -357,8 +371,10 @@ class Table extends _abstract_object_1.AbstractObject {
357
371
  this.parsedData.tableCategory = (_m = (_l = (_k = (_j = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _j === void 0 ? void 0 : _j["asx:abap"]) === null || _k === void 0 ? void 0 : _k["asx:values"]) === null || _l === void 0 ? void 0 : _l.DD02V) === null || _m === void 0 ? void 0 : _m.TABCLASS;
358
372
  this.parsedData.description = (_r = (_q = (_p = (_o = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _o === void 0 ? void 0 : _o["asx:abap"]) === null || _p === void 0 ? void 0 : _p["asx:values"]) === null || _q === void 0 ? void 0 : _q.DD02V) === null || _r === void 0 ? void 0 : _r.DDTEXT;
359
373
  this.parsedData.dataClass = (_v = (_u = (_t = (_s = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _s === void 0 ? void 0 : _s["asx:abap"]) === null || _t === void 0 ? void 0 : _t["asx:values"]) === null || _u === void 0 ? void 0 : _u.DD09L) === null || _v === void 0 ? void 0 : _v.TABART;
374
+ this.parsedData.deliveryClass = (_z = (_y = (_x = (_w = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _w === void 0 ? void 0 : _w["asx:abap"]) === null || _x === void 0 ? void 0 : _x["asx:values"]) === null || _y === void 0 ? void 0 : _y.DD02V) === null || _z === void 0 ? void 0 : _z.CONTFLAG;
375
+ this.parsedData.sizeCategory = (_3 = (_2 = (_1 = (_0 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _0 === void 0 ? void 0 : _0["asx:abap"]) === null || _1 === void 0 ? void 0 : _1["asx:values"]) === null || _2 === void 0 ? void 0 : _2.DD09L) === null || _3 === void 0 ? void 0 : _3.TABKAT;
360
376
  // fields
361
- const fields = (_y = (_x = (_w = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _w === void 0 ? void 0 : _w["asx:abap"]) === null || _x === void 0 ? void 0 : _x["asx:values"]) === null || _y === void 0 ? void 0 : _y.DD03P_TABLE;
377
+ const fields = (_6 = (_5 = (_4 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _4 === void 0 ? void 0 : _4["asx:abap"]) === null || _5 === void 0 ? void 0 : _5["asx:values"]) === null || _6 === void 0 ? void 0 : _6.DD03P_TABLE;
362
378
  for (const field of (0, xml_utils_1.xmlToArray)(fields === null || fields === void 0 ? void 0 : fields.DD03P)) {
363
379
  if (typeof (field === null || field === void 0 ? void 0 : field.FIELDNAME) !== "string") {
364
380
  continue;
@@ -382,13 +398,13 @@ class Table extends _abstract_object_1.AbstractObject {
382
398
  });
383
399
  }
384
400
  // secondary indexes
385
- const indexes = (_1 = (_0 = (_z = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _z === void 0 ? void 0 : _z["asx:abap"]) === null || _0 === void 0 ? void 0 : _0["asx:values"]) === null || _1 === void 0 ? void 0 : _1.DD12V;
401
+ const indexes = (_9 = (_8 = (_7 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _7 === void 0 ? void 0 : _7["asx:abap"]) === null || _8 === void 0 ? void 0 : _8["asx:values"]) === null || _9 === void 0 ? void 0 : _9.DD12V;
386
402
  ;
387
403
  this.parsedData.secondaryIndexes = [];
388
404
  for (const index of (0, xml_utils_1.xmlToArray)(indexes === null || indexes === void 0 ? void 0 : indexes.DD12V)) {
389
405
  const indexName = index.INDEXNAME;
390
406
  const indexFields = [];
391
- const indexFieldsXml = (_4 = (_3 = (_2 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _2 === void 0 ? void 0 : _2["asx:abap"]) === null || _3 === void 0 ? void 0 : _3["asx:values"]) === null || _4 === void 0 ? void 0 : _4.DD17V;
407
+ const indexFieldsXml = (_12 = (_11 = (_10 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _10 === void 0 ? void 0 : _10["asx:abap"]) === null || _11 === void 0 ? void 0 : _11["asx:values"]) === null || _12 === void 0 ? void 0 : _12.DD17V;
392
408
  for (const indexField of (0, xml_utils_1.xmlToArray)(indexFieldsXml === null || indexFieldsXml === void 0 ? void 0 : indexFieldsXml.DD17V)) {
393
409
  if (indexField.INDEXNAME === indexName) {
394
410
  // assumption: fields are listed by POSITION in the xml
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.43";
78
+ return "2.120.45";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -4,6 +4,7 @@ exports.LineBreakStyle = exports.LineBreakStyleConf = void 0;
4
4
  const issue_1 = require("../issue");
5
5
  const _basic_rule_config_1 = require("./_basic_rule_config");
6
6
  const _irule_1 = require("./_irule");
7
+ const objects_1 = require("../objects");
7
8
  class LineBreakStyleConf extends _basic_rule_config_1.BasicRuleConfig {
8
9
  }
9
10
  exports.LineBreakStyleConf = LineBreakStyleConf;
@@ -14,10 +15,11 @@ class LineBreakStyle {
14
15
  getMetadata() {
15
16
  return {
16
17
  key: "line_break_style",
17
- title: "Makes sure line breaks are consistent in the ABAP code",
18
- shortDescription: `Enforces LF as newlines in ABAP files
18
+ title: "Makes sure line breaks are consistent",
19
+ shortDescription: `Enforces LF as newlines in ABAP and XML files
19
20
 
20
21
  abapGit does not work with CRLF`,
22
+ extendedInformation: `SMIM and W3MI files are not checked.`,
21
23
  tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.SingleFile],
22
24
  };
23
25
  }
@@ -32,8 +34,15 @@ abapGit does not work with CRLF`,
32
34
  }
33
35
  run(obj) {
34
36
  const output = [];
37
+ if (obj instanceof objects_1.MIMEObject || obj instanceof objects_1.WebMIME) {
38
+ return output;
39
+ }
35
40
  for (const file of obj.getFiles()) {
36
- if (file.getFilename().endsWith(".abap")) {
41
+ const filename = file.getFilename();
42
+ if (filename.endsWith(".abap") || filename.endsWith(".xml")) {
43
+ if (filename.endsWith(".xslt.source.xml")) {
44
+ continue;
45
+ }
37
46
  const rows = file.getRawRows();
38
47
  for (let i = 0; i < rows.length; i++) {
39
48
  if (rows[i].endsWith("\r") === true) {
@@ -64,6 +64,8 @@ class XMLConsistency {
64
64
  * XML is well-formed and parseable
65
65
  * Naming for CLAS and INTF objects
66
66
  * QUAN fields in TABL objects have reference table and field values
67
+ * Transparent TABL objects have delivery class and size category set
68
+ * Lock parameter names in ENQU objects are max 16 characters
67
69
  * Texts and translations do not exceed maximum allowed length.`,
68
70
  tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
69
71
  };
@@ -121,6 +123,9 @@ class XMLConsistency {
121
123
  else if (obj instanceof Objects.Table) {
122
124
  issues.push(...this.runTable(obj, file));
123
125
  }
126
+ else if (obj instanceof Objects.LockObject) {
127
+ issues.push(...this.runLockObject(obj, file));
128
+ }
124
129
  if (obj instanceof _abap_object_1.ABAPObject) {
125
130
  issues.push(...this.runTextPool(obj, file));
126
131
  }
@@ -304,16 +309,39 @@ class XMLConsistency {
304
309
  }
305
310
  return issues;
306
311
  }
312
+ runLockObject(obj, file) {
313
+ var _a;
314
+ const maxParameterLength = 16;
315
+ const issues = [];
316
+ for (const parameter of (_a = obj.getParameters()) !== null && _a !== void 0 ? _a : []) {
317
+ if (parameter.VIEWFIELD.length > maxParameterLength) {
318
+ const message = `Lock parameter ${parameter.VIEWFIELD} exceeds maximum length of ` +
319
+ `${maxParameterLength} characters (actual: ${parameter.VIEWFIELD.length})`;
320
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
321
+ }
322
+ }
323
+ return issues;
324
+ }
307
325
  runTable(obj, file) {
308
- var _a, _b;
309
- var _c;
326
+ var _a, _b, _c, _d;
327
+ var _e;
310
328
  const issues = [];
311
- for (const field of (_c = obj.getFields()) !== null && _c !== void 0 ? _c : []) {
329
+ for (const field of (_e = obj.getFields()) !== null && _e !== void 0 ? _e : []) {
312
330
  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()))) {
313
331
  const message = `QUAN field ${field.FIELDNAME} must have REFTABLE and REFFIELD set`;
314
332
  issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
315
333
  }
316
334
  }
335
+ if (obj.getTableCategory() === Objects.TableCategory.Transparent) {
336
+ if (!((_c = obj.getDeliveryClass()) === null || _c === void 0 ? void 0 : _c.trim())) {
337
+ const message = `Transparent table must have delivery class(CONTFLAG in DD02V) set`;
338
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
339
+ }
340
+ if (!((_d = obj.getSizeCategory()) === null || _d === void 0 ? void 0 : _d.trim())) {
341
+ const message = `Transparent table must have size category(TABKAT in DD09L) set`;
342
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
343
+ }
344
+ }
317
345
  return issues;
318
346
  }
319
347
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.120.43",
3
+ "version": "2.120.45",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",