@abaplint/core 2.119.18 → 2.119.21

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.
@@ -18,7 +18,11 @@ export declare class ABAPFile extends AbstractFile implements IABAPFile {
18
18
 
19
19
  export declare abstract class ABAPObject extends AbstractObject {
20
20
  private parsed;
21
- protected texts: ITextElements | undefined;
21
+ protected texts: {
22
+ [id: string]: ITextElements;
23
+ } | undefined;
24
+ private textsTranslations;
25
+ private rawXMLCache;
22
26
  syntaxResult: ISyntaxResult | undefined;
23
27
  abstract getSequencedFiles(): readonly ABAPFile[];
24
28
  abstract getDescription(): string | undefined;
@@ -26,11 +30,15 @@ export declare abstract class ABAPObject extends AbstractObject {
26
30
  static is(x: any): x is ABAPObject;
27
31
  parse(version: Version, globalMacros?: readonly string[], reg?: IRegistry): IParseResult;
28
32
  setDirty(): void;
33
+ private getParsedXML;
29
34
  getABAPFiles(): readonly ABAPFile[];
30
35
  getABAPFileByName(filename: string): ABAPFile | undefined;
31
36
  getMainABAPFile(): ABAPFile | undefined;
32
- getTexts(): ITextElements;
37
+ getTextSymbols(): ITextElements;
38
+ getTextElements(): ITextElements;
39
+ getTextElementsTranslations(): ITranslationTextElements[];
33
40
  protected findTexts(parsed: any): void;
41
+ private findTextsTranslations;
34
42
  }
35
43
 
36
44
  declare class ABAPQueryFunctionalArea extends AbstractObject {
@@ -1731,6 +1739,20 @@ declare class DataElement extends AbstractObject {
1731
1739
  long?: string;
1732
1740
  heading?: string;
1733
1741
  } | undefined;
1742
+ getTextMaxLengths(): {
1743
+ short?: string;
1744
+ medium?: string;
1745
+ long?: string;
1746
+ heading?: string;
1747
+ } | undefined;
1748
+ getTextsTranslations(): {
1749
+ language: string;
1750
+ description?: string;
1751
+ short?: string;
1752
+ medium?: string;
1753
+ long?: string;
1754
+ heading?: string;
1755
+ }[] | undefined;
1734
1756
  parseType(reg: IRegistry): AbstractType;
1735
1757
  parse(): {
1736
1758
  updated: boolean;
@@ -1978,6 +2000,7 @@ declare class Domain extends AbstractObject {
1978
2000
  runtime: number;
1979
2001
  };
1980
2002
  getFixedValues(): DomainValue[];
2003
+ getFixedValuesTranslations(): DomainValueTranslation[];
1981
2004
  }
1982
2005
 
1983
2006
  declare interface DomainValue {
@@ -1987,6 +2010,11 @@ declare interface DomainValue {
1987
2010
  description: string;
1988
2011
  }
1989
2012
 
2013
+ declare interface DomainValueTranslation {
2014
+ language: string;
2015
+ description: string;
2016
+ }
2017
+
1990
2018
  declare enum Duration {
1991
2019
  short = "SHORT",
1992
2020
  medium = "MEDIUM",
@@ -2912,7 +2940,7 @@ declare class FunctionGroup extends ABAPObject {
2912
2940
  getMainABAPFile(): ABAPFile | undefined;
2913
2941
  getIncludes(): string[];
2914
2942
  getModule(name: string): FunctionModuleDefinition | undefined;
2915
- getTexts(): ITextElements;
2943
+ getTextSymbols(): ITextElements;
2916
2944
  private parseXML;
2917
2945
  private findTextFile;
2918
2946
  }
@@ -4289,7 +4317,15 @@ declare interface ITextEdit {
4289
4317
  }
4290
4318
 
4291
4319
  declare interface ITextElements {
4292
- [key: string]: string;
4320
+ [key: string]: {
4321
+ entry: string;
4322
+ maxLength: number;
4323
+ };
4324
+ }
4325
+
4326
+ declare interface ITranslationTextElements {
4327
+ language: string;
4328
+ textElements: ITextElements;
4293
4329
  }
4294
4330
 
4295
4331
  declare interface ITypeDefinitions {
@@ -4513,6 +4549,11 @@ declare class MessageClass extends AbstractObject {
4513
4549
  allowNamespace: boolean;
4514
4550
  };
4515
4551
  getParsed(): parsedMessageClass | undefined;
4552
+ getTextsTranslations(): {
4553
+ language: string;
4554
+ number: string;
4555
+ text?: string;
4556
+ }[] | undefined;
4516
4557
  setDirty(): void;
4517
4558
  getMessages(): readonly Message[];
4518
4559
  getByNumber(num: string): Message | undefined;
@@ -5142,6 +5183,7 @@ declare namespace Objects {
5142
5183
  DialogModule,
5143
5184
  Documentation,
5144
5185
  DomainValue,
5186
+ DomainValueTranslation,
5145
5187
  Domain,
5146
5188
  EcattTestConfiguration,
5147
5189
  EcattTestDataContainer,
@@ -5431,6 +5473,11 @@ declare type parsedMessageClass = {
5431
5473
  topName: string | undefined;
5432
5474
  description: string | undefined;
5433
5475
  parsedMessages: Message[] | undefined;
5476
+ textsTranslations: {
5477
+ language: string;
5478
+ number: string;
5479
+ text?: string;
5480
+ }[] | undefined;
5434
5481
  };
5435
5482
 
5436
5483
  declare type ParsedMetadataExtension = {
@@ -7330,6 +7377,10 @@ declare class Transaction extends AbstractObject {
7330
7377
  getCInfo(): string | undefined;
7331
7378
  getProgramName(): string | undefined;
7332
7379
  getDescription(): string | undefined;
7380
+ getTextsTranslations(): {
7381
+ language: string;
7382
+ description?: string;
7383
+ }[] | undefined;
7333
7384
  parse(): {
7334
7385
  updated: boolean;
7335
7386
  runtime: number;
@@ -6,6 +6,7 @@ const tokens_1 = require("../../1_lexer/tokens");
6
6
  const combi_1 = require("../combi");
7
7
  const integer_1 = require("./integer");
8
8
  const sql_function_input_1 = require("./sql_function_input");
9
+ const sql_case_1 = require("./sql_case");
9
10
  class SQLFunction extends combi_1.Expression {
10
11
  getRunnable() {
11
12
  const castTypes = (0, combi_1.altPrio)((0, combi_1.seq)("CHAR", (0, combi_1.optPrio)((0, combi_1.seq)((0, combi_1.tok)(tokens_1.ParenLeftW), integer_1.Integer, (0, combi_1.tok)(tokens_1.WParenRightW)))), (0, combi_1.seq)("DEC", (0, combi_1.tok)(tokens_1.ParenLeftW), integer_1.Integer, ",", integer_1.Integer, (0, combi_1.tok)(tokens_1.WParenRightW)), (0, combi_1.seq)("NUMC", (0, combi_1.optPrio)((0, combi_1.seq)((0, combi_1.tok)(tokens_1.ParenLeftW), integer_1.Integer, (0, combi_1.tok)(tokens_1.WParenRightW)))), "DATS", "FLTP", "INT2", "INT4", "INT8");
@@ -13,7 +14,8 @@ class SQLFunction extends combi_1.Expression {
13
14
  // note: the function names are not keywords, they are usually in lower case
14
15
  const abs = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)((0, combi_1.regex)(/^abs$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, (0, combi_1.tok)(tokens_1.WParenRightW)));
15
16
  // yea, 750 is correct, but it also works technically in version v740sp05
16
- const cast = (0, combi_1.ver)(version_1.Version.v750, (0, combi_1.seq)((0, combi_1.regex)(/^cast$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, "AS", castTypes, (0, combi_1.tok)(tokens_1.WParenRightW)));
17
+ const castInput = (0, combi_1.altPrio)(sql_case_1.SQLCase, sql_function_input_1.SQLFunctionInput);
18
+ const cast = (0, combi_1.ver)(version_1.Version.v750, (0, combi_1.seq)((0, combi_1.regex)(/^cast$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), castInput, "AS", castTypes, (0, combi_1.tok)(tokens_1.WParenRightW)));
17
19
  const ceil = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)((0, combi_1.regex)(/^ceil$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, (0, combi_1.tok)(tokens_1.WParenRightW)));
18
20
  const coalesce = (0, combi_1.ver)(version_1.Version.v740sp05, (0, combi_1.seq)((0, combi_1.regex)(/^coalesce$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, commaParam, (0, combi_1.optPrio)(commaParam), (0, combi_1.tok)(tokens_1.WParenRightW)));
19
21
  const concat = (0, combi_1.ver)(version_1.Version.v750, (0, combi_1.seq)((0, combi_1.regex)(/^concat$/i), (0, combi_1.tok)(tokens_1.ParenLeftW), sql_function_input_1.SQLFunctionInput, commaParam, (0, combi_1.tok)(tokens_1.WParenRightW)));
@@ -5,7 +5,9 @@ const Expressions = require("../../2_statements/expressions");
5
5
  const basic_types_1 = require("../basic_types");
6
6
  const _typed_identifier_1 = require("../../types/_typed_identifier");
7
7
  const basic_1 = require("../../types/basic");
8
+ const _syntax_input_1 = require("../_syntax_input");
8
9
  const assert_error_1 = require("../assert_error");
10
+ const basic_2 = require("../../types/basic");
9
11
  class Constant {
10
12
  runSyntax(node, input) {
11
13
  const basic = new basic_types_1.BasicTypes(input);
@@ -13,14 +15,29 @@ class Constant {
13
15
  if (found) {
14
16
  const val = basic.findValue(node);
15
17
  const meta = ["read_only" /* IdentifierMeta.ReadOnly */, "static" /* IdentifierMeta.Static */];
18
+ if (this.isOnlyDigits(found.getName()) && this.allowOnlyDigitsName(node, input) === false) {
19
+ const message = "not possible to have a name with only digits";
20
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, found.getToken(), message));
21
+ return new _typed_identifier_1.TypedIdentifier(found.getToken(), input.filename, basic_2.VoidType.get(_syntax_input_1.CheckSyntaxKey), meta, val);
22
+ }
16
23
  return new _typed_identifier_1.TypedIdentifier(found.getToken(), input.filename, found.getType(), meta, val);
17
24
  }
18
25
  const fallback = node.findFirstExpression(Expressions.DefinitionName);
19
26
  if (fallback) {
27
+ if (this.isOnlyDigits(fallback.concatTokens()) && this.allowOnlyDigitsName(node, input) === false) {
28
+ const message = "not possible to have a name with only digits";
29
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, fallback.getFirstToken(), message));
30
+ }
20
31
  return new _typed_identifier_1.TypedIdentifier(fallback.getFirstToken(), input.filename, new basic_1.UnknownType("constant, fallback"));
21
32
  }
22
33
  throw new assert_error_1.AssertError("Statement Constant: unexpected structure");
23
34
  }
35
+ isOnlyDigits(name) {
36
+ return /^[0-9]+$/.test(name);
37
+ }
38
+ allowOnlyDigitsName(node, input) {
39
+ return input.scope.isAnyOO() === false && node.getColon() !== undefined;
40
+ }
24
41
  }
25
42
  exports.Constant = Constant;
26
43
  //# sourceMappingURL=constant.js.map
@@ -13,6 +13,11 @@ class Data {
13
13
  const dd = node.findFirstExpression(Expressions.DataDefinition);
14
14
  if (dd) {
15
15
  const id = data_definition_1.DataDefinition.runSyntax(dd, input);
16
+ if (id && this.isOnlyDigits(id.getName())) {
17
+ const message = "not possible to have a name with only digits";
18
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, id.getToken(), message));
19
+ return new _typed_identifier_1.TypedIdentifier(id.getToken(), input.filename, basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey));
20
+ }
16
21
  if ((id === null || id === void 0 ? void 0 : id.getType().isGeneric()) === true
17
22
  && (id === null || id === void 0 ? void 0 : id.getType().containsVoid()) === false) {
18
23
  const message = "DATA definition cannot be generic, " + (name === null || name === void 0 ? void 0 : name.concatTokens());
@@ -22,10 +27,17 @@ class Data {
22
27
  return id;
23
28
  }
24
29
  if (name) {
30
+ if (this.isOnlyDigits(name.concatTokens())) {
31
+ const message = "not possible to have a name with only digits";
32
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, name.getFirstToken(), message));
33
+ }
25
34
  return new _typed_identifier_1.TypedIdentifier(name.getFirstToken(), input.filename, new unknown_type_1.UnknownType("data, fallback"));
26
35
  }
27
36
  return undefined;
28
37
  }
38
+ isOnlyDigits(name) {
39
+ return /^[0-9]+$/.test(name);
40
+ }
29
41
  }
30
42
  exports.Data = Data;
31
43
  //# sourceMappingURL=data.js.map
@@ -12,6 +12,7 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
12
12
  super(name);
13
13
  this.parsed = [];
14
14
  this.texts = undefined;
15
+ this.rawXMLCache = undefined;
15
16
  }
16
17
  static is(x) {
17
18
  return !!x && x instanceof ABAPObject;
@@ -30,9 +31,18 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
30
31
  setDirty() {
31
32
  this.syntaxResult = undefined;
32
33
  this.texts = undefined;
34
+ this.textsTranslations = undefined;
35
+ this.rawXMLCache = undefined;
33
36
  this.parsed = [];
34
37
  super.setDirty();
35
38
  }
39
+ getParsedXML() {
40
+ var _a, _b;
41
+ if (this.rawXMLCache === undefined) {
42
+ this.rawXMLCache = (_a = this.parseRaw2()) !== null && _a !== void 0 ? _a : null;
43
+ }
44
+ return (_b = this.rawXMLCache) !== null && _b !== void 0 ? _b : undefined;
45
+ }
36
46
  getABAPFiles() {
37
47
  return this.parsed;
38
48
  }
@@ -63,29 +73,67 @@ class ABAPObject extends _abstract_object_1.AbstractObject {
63
73
  }
64
74
  return undefined;
65
75
  }
66
- getTexts() {
76
+ getTextSymbols() {
77
+ var _a;
67
78
  if (this.texts === undefined) {
68
- this.findTexts(this.parseRaw2());
79
+ this.findTexts(this.getParsedXML());
69
80
  }
70
- return this.texts;
81
+ return (_a = this.texts["I"]) !== null && _a !== void 0 ? _a : {};
82
+ }
83
+ getTextElements() {
84
+ if (this.texts === undefined) {
85
+ this.findTexts(this.getParsedXML());
86
+ }
87
+ const result = {};
88
+ for (const elements of Object.values(this.texts)) {
89
+ Object.assign(result, elements);
90
+ }
91
+ return result;
92
+ }
93
+ getTextElementsTranslations() {
94
+ if (this.textsTranslations === undefined) {
95
+ this.findTextsTranslations(this.getParsedXML());
96
+ }
97
+ return this.textsTranslations;
71
98
  }
72
99
  findTexts(parsed) {
73
- var _a, _b, _c, _d;
100
+ var _a, _b, _c, _d, _e, _f, _g;
74
101
  this.texts = {};
75
102
  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) {
76
103
  return;
77
104
  }
78
105
  for (const t of (0, xml_utils_1.xmlToArray)(parsed.abapGit["asx:abap"]["asx:values"].TPOOL.item)) {
79
- if ((t === null || t === void 0 ? void 0 : t.ID) === "I") {
80
- if (t.KEY === undefined) {
81
- throw new Error("findTexts, undefined");
82
- }
83
- const key = t.KEY;
84
- if (key === undefined) {
85
- continue;
106
+ const id = (_e = t.ID) === null || _e === void 0 ? void 0 : _e.toUpperCase();
107
+ if (id === undefined
108
+ || (id !== "R" && t.KEY === undefined)) {
109
+ throw new Error("findTexts, undefined");
110
+ }
111
+ const key = (_g = ((_f = t.KEY) !== null && _f !== void 0 ? _f : t.ID)) === null || _g === void 0 ? void 0 : _g.toUpperCase();
112
+ if (key === undefined) {
113
+ continue;
114
+ }
115
+ if (this.texts[id] === undefined) {
116
+ this.texts[id] = {};
117
+ }
118
+ this.texts[id][key] = { entry: t.ENTRY ? (0, xml_utils_1.unescape)(t.ENTRY) : "", maxLength: parseInt(t.LENGTH, 10) };
119
+ }
120
+ }
121
+ findTextsTranslations(parsed) {
122
+ var _a, _b, _c, _d, _e, _f;
123
+ this.textsTranslations = [];
124
+ const values = (_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"].I18N_TPOOL) === null || _c === void 0 ? void 0 : _c.item;
125
+ if (values === undefined) {
126
+ return;
127
+ }
128
+ for (const langItem of (0, xml_utils_1.xmlToArray)(values)) {
129
+ const textElements = {};
130
+ for (const item of (0, xml_utils_1.xmlToArray)((_d = langItem.TEXTPOOL) === null || _d === void 0 ? void 0 : _d.item)) {
131
+ const key = (_f = ((_e = item.KEY) !== null && _e !== void 0 ? _e : item.ID)) === null || _f === void 0 ? void 0 : _f.toUpperCase();
132
+ if (key !== undefined) {
133
+ textElements[key] = { entry: (0, xml_utils_1.unescape)(item.ENTRY), maxLength: parseInt(item.LENGTH, 10) };
86
134
  }
87
- this.texts[key.toUpperCase()] = t.ENTRY ? (0, xml_utils_1.unescape)(t.ENTRY) : "";
88
135
  }
136
+ this.textsTranslations.push({ language: langItem.LANGUAGE, textElements });
89
137
  }
90
138
  }
91
139
  }
@@ -4,6 +4,7 @@ exports.DataElement = void 0;
4
4
  const _abstract_object_1 = require("./_abstract_object");
5
5
  const ddic_1 = require("../ddic");
6
6
  const Types = require("../abap/types/basic");
7
+ const xml_utils_1 = require("../xml_utils");
7
8
  class DataElement extends _abstract_object_1.AbstractObject {
8
9
  constructor() {
9
10
  super(...arguments);
@@ -39,6 +40,16 @@ class DataElement extends _abstract_object_1.AbstractObject {
39
40
  this.parse();
40
41
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.texts;
41
42
  }
43
+ getTextMaxLengths() {
44
+ var _a;
45
+ this.parse();
46
+ return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.textMaxLengths;
47
+ }
48
+ getTextsTranslations() {
49
+ var _a;
50
+ this.parse();
51
+ return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.textsTranslations;
52
+ }
42
53
  parseType(reg) {
43
54
  var _a;
44
55
  const references = [];
@@ -98,7 +109,7 @@ class DataElement extends _abstract_object_1.AbstractObject {
98
109
  return lookup.type;
99
110
  }
100
111
  parse() {
101
- var _a, _b, _c;
112
+ var _a, _b, _c, _d, _e, _f, _g;
102
113
  if (this.parsedXML !== undefined) {
103
114
  return { updated: false, runtime: 0 };
104
115
  }
@@ -122,7 +133,24 @@ class DataElement extends _abstract_object_1.AbstractObject {
122
133
  long: dd04v === null || dd04v === void 0 ? void 0 : dd04v.SCRTEXT_L,
123
134
  heading: dd04v === null || dd04v === void 0 ? void 0 : dd04v.REPTEXT,
124
135
  },
136
+ textMaxLengths: {
137
+ short: dd04v === null || dd04v === void 0 ? void 0 : dd04v.SCRLEN1,
138
+ medium: dd04v === null || dd04v === void 0 ? void 0 : dd04v.SCRLEN2,
139
+ long: dd04v === null || dd04v === void 0 ? void 0 : dd04v.SCRLEN3,
140
+ heading: dd04v === null || dd04v === void 0 ? void 0 : dd04v.HEADLEN,
141
+ },
125
142
  };
143
+ this.parsedXML.textsTranslations = [];
144
+ for (const item of (0, xml_utils_1.xmlToArray)((_g = (_f = (_e = (_d = parsed.abapGit) === null || _d === void 0 ? void 0 : _d["asx:abap"]) === null || _e === void 0 ? void 0 : _e["asx:values"]) === null || _f === void 0 ? void 0 : _f.DD04_TEXTS) === null || _g === void 0 ? void 0 : _g.item)) {
145
+ this.parsedXML.textsTranslations.push({
146
+ language: item.DDLANGUAGE,
147
+ description: item.DDTEXT,
148
+ short: item.SCRTEXT_S,
149
+ medium: item.SCRTEXT_M,
150
+ long: item.SCRTEXT_L,
151
+ heading: item.REPTEXT,
152
+ });
153
+ }
126
154
  const end = Date.now();
127
155
  return { updated: true, runtime: end - start };
128
156
  }
@@ -49,7 +49,7 @@ class Domain extends _abstract_object_1.AbstractObject {
49
49
  });
50
50
  }
51
51
  parse() {
52
- var _a, _b, _c, _d, _e, _f, _g;
52
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
53
53
  if (this.parsedXML) {
54
54
  return { updated: false, runtime: 0 };
55
55
  }
@@ -71,6 +71,15 @@ class Domain extends _abstract_object_1.AbstractObject {
71
71
  };
72
72
  values.push(value);
73
73
  }
74
+ const dd07v_texts = (0, xml_utils_1.xmlToArray)((_l = (_k = (_j = (_h = parsed.abapGit) === null || _h === void 0 ? void 0 : _h["asx:abap"]) === null || _j === void 0 ? void 0 : _j["asx:values"]) === null || _k === void 0 ? void 0 : _k.DD07_TEXTS) === null || _l === void 0 ? void 0 : _l.item);
75
+ const translationValues = [];
76
+ for (const dd07v of dd07v_texts) {
77
+ const value = {
78
+ language: dd07v === null || dd07v === void 0 ? void 0 : dd07v.DDLANGUAGE,
79
+ description: dd07v === null || dd07v === void 0 ? void 0 : dd07v.DDTEXT,
80
+ };
81
+ translationValues.push(value);
82
+ }
74
83
  this.parsedXML = {
75
84
  description: dd01v === null || dd01v === void 0 ? void 0 : dd01v.DDTEXT,
76
85
  datatype: dd01v === null || dd01v === void 0 ? void 0 : dd01v.DATATYPE,
@@ -78,6 +87,7 @@ class Domain extends _abstract_object_1.AbstractObject {
78
87
  conversionExit: dd01v === null || dd01v === void 0 ? void 0 : dd01v.CONVEXIT,
79
88
  decimals: dd01v === null || dd01v === void 0 ? void 0 : dd01v.DECIMALS,
80
89
  values: values,
90
+ valuesTranslations: translationValues,
81
91
  };
82
92
  const end = Date.now();
83
93
  return { updated: true, runtime: end - start };
@@ -86,6 +96,10 @@ class Domain extends _abstract_object_1.AbstractObject {
86
96
  var _a, _b;
87
97
  return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.values) !== null && _b !== void 0 ? _b : [];
88
98
  }
99
+ getFixedValuesTranslations() {
100
+ var _a, _b;
101
+ return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.valuesTranslations) !== null && _b !== void 0 ? _b : [];
102
+ }
89
103
  }
90
104
  exports.Domain = Domain;
91
105
  //# sourceMappingURL=domain.js.map
@@ -132,7 +132,8 @@ class FunctionGroup extends _abap_object_1.ABAPObject {
132
132
  }
133
133
  return undefined;
134
134
  }
135
- getTexts() {
135
+ getTextSymbols() {
136
+ var _a;
136
137
  if (this.texts === undefined) {
137
138
  const found = this.findTextFile();
138
139
  if (found === undefined) {
@@ -141,7 +142,7 @@ class FunctionGroup extends _abap_object_1.ABAPObject {
141
142
  const parsed = new fast_xml_parser_1.XMLParser({ parseTagValue: false, ignoreAttributes: true, trimValues: false }).parse(found.getRaw());
142
143
  this.findTexts(parsed);
143
144
  }
144
- return this.texts;
145
+ return (_a = this.texts["I"]) !== null && _a !== void 0 ? _a : {};
145
146
  }
146
147
  /////////////////////////////////
147
148
  parseXML() {
@@ -27,6 +27,11 @@ class MessageClass extends _abstract_object_1.AbstractObject {
27
27
  this.parseXML();
28
28
  return this.xml;
29
29
  }
30
+ getTextsTranslations() {
31
+ var _a;
32
+ this.parseXML();
33
+ return (_a = this.xml) === null || _a === void 0 ? void 0 : _a.textsTranslations;
34
+ }
30
35
  setDirty() {
31
36
  this.xml = undefined;
32
37
  super.setDirty();
@@ -49,7 +54,7 @@ class MessageClass extends _abstract_object_1.AbstractObject {
49
54
  }
50
55
  /////////////////////////////////
51
56
  parseXML() {
52
- var _a, _b, _c, _d, _e, _f, _g, _h;
57
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
53
58
  if (this.xml !== undefined) {
54
59
  return;
55
60
  }
@@ -57,6 +62,7 @@ class MessageClass extends _abstract_object_1.AbstractObject {
57
62
  topName: undefined,
58
63
  description: undefined,
59
64
  parsedMessages: [],
65
+ textsTranslations: [],
60
66
  };
61
67
  const parsed = super.parseRaw2();
62
68
  if (parsed === undefined) {
@@ -71,6 +77,13 @@ class MessageClass extends _abstract_object_1.AbstractObject {
71
77
  for (const msg of (0, xml_utils_1.xmlToArray)(t100.T100)) {
72
78
  this.xml.parsedMessages.push(new message_1.Message(msg.MSGNR, (0, xml_utils_1.unescape)(msg.TEXT), msg.ARBGB));
73
79
  }
80
+ const t100_texts = (_k = (_j = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _j === void 0 ? void 0 : _j["asx:abap"]["asx:values"]) === null || _k === void 0 ? void 0 : _k.T100_TEXTS;
81
+ if (t100_texts === undefined) {
82
+ return;
83
+ }
84
+ for (const item of (0, xml_utils_1.xmlToArray)(t100_texts === null || t100_texts === void 0 ? void 0 : t100_texts.item)) {
85
+ this.xml.textsTranslations.push({ language: item.SPRSL, number: item.MSGNR, text: (0, xml_utils_1.unescape)(item.TEXT) });
86
+ }
74
87
  }
75
88
  }
76
89
  exports.MessageClass = MessageClass;
@@ -71,7 +71,7 @@ class Program extends _abap_object_1.ABAPObject {
71
71
  description = t.ENTRY ? (0, xml_utils_1.unescape)(t.ENTRY) : "";
72
72
  }
73
73
  else if ((t === null || t === void 0 ? void 0 : t.ID) === "S" && t.KEY !== undefined) {
74
- selectionTexts[t.KEY.toUpperCase()] = t.ENTRY ? (0, xml_utils_1.unescape)(t.ENTRY) : "";
74
+ selectionTexts[t.KEY.toUpperCase()] = { entry: t.ENTRY ? (0, xml_utils_1.unescape)(t.ENTRY) : "", maxLength: parseInt(t.LENGTH, 10) };
75
75
  }
76
76
  }
77
77
  const dynpros = (0, _dynpros_1.parseDynpros)(parsed);
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Transaction = void 0;
4
4
  const _abstract_object_1 = require("./_abstract_object");
5
+ const xml_utils_1 = require("../xml_utils");
5
6
  class Transaction extends _abstract_object_1.AbstractObject {
6
7
  getType() {
7
8
  return "TRAN";
@@ -31,8 +32,13 @@ class Transaction extends _abstract_object_1.AbstractObject {
31
32
  this.parse();
32
33
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.description;
33
34
  }
35
+ getTextsTranslations() {
36
+ var _a;
37
+ this.parse();
38
+ return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.textsTranslations;
39
+ }
34
40
  parse() {
35
- var _a, _b, _c;
41
+ var _a, _b, _c, _d;
36
42
  if (this.parsedXML) {
37
43
  return { updated: false, runtime: 0 };
38
44
  }
@@ -47,6 +53,10 @@ class Transaction extends _abstract_object_1.AbstractObject {
47
53
  this.parsedXML.description = (_a = parsed.abapGit["asx:abap"]["asx:values"].TSTCT) === null || _a === void 0 ? void 0 : _a.TTEXT;
48
54
  this.parsedXML.programName = (_b = parsed.abapGit["asx:abap"]["asx:values"].TSTC) === null || _b === void 0 ? void 0 : _b.PGMNA;
49
55
  this.parsedXML.cinfo = (_c = parsed.abapGit["asx:abap"]["asx:values"].TSTC) === null || _c === void 0 ? void 0 : _c.CINFO;
56
+ this.parsedXML.textsTranslations = [];
57
+ for (const item of (0, xml_utils_1.xmlToArray)((_d = parsed.abapGit["asx:abap"]["asx:values"].I18N_TPOOL) === null || _d === void 0 ? void 0 : _d.TSTCT)) {
58
+ this.parsedXML.textsTranslations.push({ language: item.SPRSL, description: item.TTEXT });
59
+ }
50
60
  const end = Date.now();
51
61
  return { updated: true, runtime: end - start };
52
62
  }
@@ -74,7 +74,7 @@ class Registry {
74
74
  }
75
75
  static abaplintVersion() {
76
76
  // magic, see build script "version.sh"
77
- return "2.119.18";
77
+ return "2.119.21";
78
78
  }
79
79
  getDDICReferences() {
80
80
  return this.ddicReferences;
@@ -190,13 +190,13 @@ class Registry {
190
190
  continue;
191
191
  }
192
192
  let found = this.findOrCreate(f.getObjectName(), f.getObjectType());
193
+ if (this.conf.getGlobal().errorOnDuplicateFilenames === true) {
194
+ this.checkDuplicateFilename(filename, found.getFiles());
195
+ }
193
196
  if (dependency === false && found && this.isDependency(found)) {
194
197
  this.removeDependency(found);
195
198
  found = this.findOrCreate(f.getObjectName(), f.getObjectType());
196
199
  }
197
- if (this.conf.getGlobal().errorOnDuplicateFilenames === true) {
198
- this.checkDuplicateFilename(filename, found.getFiles());
199
- }
200
200
  found.addFile(f);
201
201
  }
202
202
  return this;
@@ -32,6 +32,7 @@ class CheckTextElements {
32
32
  return this;
33
33
  }
34
34
  run(obj) {
35
+ var _a;
35
36
  if (!(obj instanceof _abap_object_1.ABAPObject)) {
36
37
  return [];
37
38
  }
@@ -51,10 +52,10 @@ class CheckTextElements {
51
52
  // todo, this only checks the first main
52
53
  mainName = mains[0];
53
54
  const main1 = this.reg.findObjectForFile(this.reg.getFileByName(mains[0]));
54
- texts = main1.getTexts();
55
+ texts = main1.getTextSymbols();
55
56
  }
56
57
  else {
57
- texts = obj.getTexts();
58
+ texts = obj.getTextSymbols();
58
59
  }
59
60
  }
60
61
  for (const e of expressions) {
@@ -71,8 +72,8 @@ class CheckTextElements {
71
72
  const token = e.findFirstExpression(Expressions.TextElementKey).getFirstToken();
72
73
  const code = e.getFirstToken().getStr();
73
74
  const key = token.getStr().toUpperCase();
74
- let found = texts[key];
75
- if (found && code.startsWith("'")) {
75
+ let found = (_a = texts[key]) === null || _a === void 0 ? void 0 : _a.entry;
76
+ if (found !== undefined && code.startsWith("'")) {
76
77
  found = found.replace(/'/g, "''");
77
78
  }
78
79
  if (found === undefined) {
@@ -4,6 +4,7 @@ exports.XMLConsistency = exports.XMLConsistencyConf = void 0;
4
4
  const issue_1 = require("../issue");
5
5
  const _irule_1 = require("./_irule");
6
6
  const Objects = require("../objects");
7
+ const _abap_object_1 = require("../objects/_abap_object");
7
8
  const _basic_rule_config_1 = require("./_basic_rule_config");
8
9
  const fast_xml_parser_1 = require("fast-xml-parser");
9
10
  class XMLConsistencyConf extends _basic_rule_config_1.BasicRuleConfig {
@@ -17,7 +18,11 @@ class XMLConsistency {
17
18
  return {
18
19
  key: "xml_consistency",
19
20
  title: "XML consistency",
20
- shortDescription: `Checks the consistency of main XML files, eg. naming for CLAS and INTF objects`,
21
+ shortDescription: `Checks the consistency of main XML files`,
22
+ extendedInformation: `Checks:
23
+ * XML is well-formed and parseable
24
+ * Naming for CLAS and INTF objects
25
+ * Texts and translations do not exceed maximum allowed length.`,
21
26
  tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
22
27
  };
23
28
  }
@@ -31,7 +36,6 @@ class XMLConsistency {
31
36
  return this;
32
37
  }
33
38
  run(obj) {
34
- var _a, _b;
35
39
  const issues = [];
36
40
  const file = obj.getXMLFile();
37
41
  if (file === undefined) {
@@ -46,37 +50,166 @@ class XMLConsistency {
46
50
  }
47
51
  // todo, have some XML validation in each object?
48
52
  if (obj instanceof Objects.Class) {
49
- const name = obj.getNameFromXML();
50
- if (name === undefined) {
51
- issues.push(issue_1.Issue.atRow(file, 1, "Name undefined in XML", this.getMetadata().key, this.conf.severity));
52
- }
53
- else if (obj.getDescription() && obj.getDescription().length > 60) {
54
- issues.push(issue_1.Issue.atRow(file, 1, "Description too long", this.getMetadata().key, this.conf.severity));
55
- }
56
- else if (name !== obj.getName().toUpperCase()) {
57
- issues.push(issue_1.Issue.atRow(file, 1, "Name in XML does not match object", this.getMetadata().key, this.conf.severity));
58
- }
59
- else if (((_a = obj.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getStructure()) !== undefined && obj.getClassDefinition() === undefined) {
60
- issues.push(issue_1.Issue.atRow(file, 1, "Class matching XML name not found in ABAP file", this.getMetadata().key, this.conf.severity));
61
- }
53
+ issues.push(...this.runClass(obj, file));
62
54
  }
63
55
  else if (obj instanceof Objects.Interface) {
64
- const name = obj.getNameFromXML();
65
- if (name === undefined) {
66
- issues.push(issue_1.Issue.atRow(file, 1, "Name undefined in XML", this.getMetadata().key, this.conf.severity));
67
- }
68
- else if (obj.getDescription() && obj.getDescription().length > 60) {
69
- issues.push(issue_1.Issue.atRow(file, 1, "Description too long", this.getMetadata().key, this.conf.severity));
56
+ issues.push(...this.runInterface(obj, file));
57
+ }
58
+ else if (obj instanceof Objects.DataElement) {
59
+ issues.push(...this.runDataElement(obj, file));
60
+ }
61
+ else if (obj instanceof Objects.Domain) {
62
+ issues.push(...this.runDomain(obj, file));
63
+ }
64
+ else if (obj instanceof Objects.Transaction) {
65
+ issues.push(...this.runTransaction(obj, file));
66
+ }
67
+ else if (obj instanceof Objects.MessageClass) {
68
+ issues.push(...this.runMessageClass(obj, file));
69
+ }
70
+ if (obj instanceof _abap_object_1.ABAPObject) {
71
+ issues.push(...this.runTextPool(obj, file));
72
+ }
73
+ return issues;
74
+ }
75
+ runClass(obj, file) {
76
+ var _a;
77
+ const issues = [];
78
+ const name = obj.getNameFromXML();
79
+ if (name === undefined) {
80
+ issues.push(issue_1.Issue.atRow(file, 1, "Name undefined in XML", this.getMetadata().key, this.conf.severity));
81
+ }
82
+ else if (obj.getDescription() && obj.getDescription().length > 60) {
83
+ issues.push(issue_1.Issue.atRow(file, 1, "Description too long", this.getMetadata().key, this.conf.severity));
84
+ }
85
+ else if (name !== obj.getName().toUpperCase()) {
86
+ issues.push(issue_1.Issue.atRow(file, 1, "Name in XML does not match object", this.getMetadata().key, this.conf.severity));
87
+ }
88
+ else if (((_a = obj.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getStructure()) !== undefined && obj.getClassDefinition() === undefined) {
89
+ issues.push(issue_1.Issue.atRow(file, 1, "Class matching XML name not found in ABAP file", this.getMetadata().key, this.conf.severity));
90
+ }
91
+ return issues;
92
+ }
93
+ runTextPool(obj, file) {
94
+ const issues = [];
95
+ const push = (issue) => { if (issue) {
96
+ issues.push(issue);
97
+ } };
98
+ for (const [key, el] of Object.entries(obj.getTextElements())) {
99
+ push(this.checkTextLength(file, `ENTRY[${key}]`, el.entry, el.maxLength));
100
+ }
101
+ for (const translation of obj.getTextElementsTranslations()) {
102
+ for (const [key, el] of Object.entries(translation.textElements)) {
103
+ push(this.checkTextLength(file, `ENTRY[${key}]`, el.entry, el.maxLength, translation.language));
70
104
  }
71
- else if (name !== obj.getName().toUpperCase()) {
72
- issues.push(issue_1.Issue.atRow(file, 1, "Name in XML does not match object", this.getMetadata().key, this.conf.severity));
105
+ }
106
+ return issues;
107
+ }
108
+ runInterface(obj, file) {
109
+ var _a;
110
+ const issues = [];
111
+ const name = obj.getNameFromXML();
112
+ if (name === undefined) {
113
+ issues.push(issue_1.Issue.atRow(file, 1, "Name undefined in XML", this.getMetadata().key, this.conf.severity));
114
+ }
115
+ else if (obj.getDescription() && obj.getDescription().length > 60) {
116
+ issues.push(issue_1.Issue.atRow(file, 1, "Description too long", this.getMetadata().key, this.conf.severity));
117
+ }
118
+ else if (name !== obj.getName().toUpperCase()) {
119
+ issues.push(issue_1.Issue.atRow(file, 1, "Name in XML does not match object", this.getMetadata().key, this.conf.severity));
120
+ }
121
+ else if (obj.getDefinition() !== undefined && ((_a = obj.getDefinition()) === null || _a === void 0 ? void 0 : _a.getName().toUpperCase()) !== name.toUpperCase()) {
122
+ issues.push(issue_1.Issue.atRow(file, 1, "Interface matching XML name not found in ABAP file", this.getMetadata().key, this.conf.severity));
123
+ }
124
+ return issues;
125
+ }
126
+ checkTextLength(file, fieldName, text, maxLength, lang) {
127
+ if (text === undefined || maxLength === undefined) {
128
+ return undefined;
129
+ }
130
+ const max = typeof maxLength === "number" ? maxLength : parseInt(maxLength, 10);
131
+ if (text.length > max) {
132
+ const prefix = lang ? `[${lang}] ` : "";
133
+ return issue_1.Issue.atRow(file, 1, `${prefix}${fieldName} "${text}" exceeds maximum length of ${max} characters (actual: ${text.length})`, this.getMetadata().key, this.conf.severity);
134
+ }
135
+ return undefined;
136
+ }
137
+ runDataElement(obj, file) {
138
+ var _a;
139
+ const issues = [];
140
+ const texts = obj.getTexts();
141
+ const maxLengths = obj.getTextMaxLengths();
142
+ for (const issue of [
143
+ this.checkTextLength(file, "DDTEXT", obj.getDescription(), 60),
144
+ this.checkTextLength(file, "SCRTEXT_S", texts === null || texts === void 0 ? void 0 : texts.short, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.short),
145
+ this.checkTextLength(file, "SCRTEXT_M", texts === null || texts === void 0 ? void 0 : texts.medium, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.medium),
146
+ this.checkTextLength(file, "SCRTEXT_L", texts === null || texts === void 0 ? void 0 : texts.long, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.long),
147
+ this.checkTextLength(file, "REPTEXT", texts === null || texts === void 0 ? void 0 : texts.heading, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.heading),
148
+ ]) {
149
+ if (issue) {
150
+ issues.push(issue);
73
151
  }
74
- else if (obj.getDefinition() !== undefined && ((_b = obj.getDefinition()) === null || _b === void 0 ? void 0 : _b.getName().toUpperCase()) !== name.toUpperCase()) {
75
- issues.push(issue_1.Issue.atRow(file, 1, "Interface matching XML name not found in ABAP file", this.getMetadata().key, this.conf.severity));
152
+ }
153
+ for (const translation of (_a = obj.getTextsTranslations()) !== null && _a !== void 0 ? _a : []) {
154
+ const lang = translation.language;
155
+ for (const issue of [
156
+ this.checkTextLength(file, "DDTEXT", translation.description, 60, lang),
157
+ this.checkTextLength(file, "SCRTEXT_S", translation.short, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.short, lang),
158
+ this.checkTextLength(file, "SCRTEXT_M", translation.medium, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.medium, lang),
159
+ this.checkTextLength(file, "SCRTEXT_L", translation.long, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.long, lang),
160
+ this.checkTextLength(file, "REPTEXT", translation.heading, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.heading, lang),
161
+ ]) {
162
+ if (issue) {
163
+ issues.push(issue);
164
+ }
76
165
  }
77
166
  }
78
167
  return issues;
79
168
  }
169
+ runDomain(obj, file) {
170
+ var _a, _b;
171
+ const maxTextLength = 60;
172
+ const issues = [];
173
+ const push = (issue) => { if (issue) {
174
+ issues.push(issue);
175
+ } };
176
+ push(this.checkTextLength(file, "DDTEXT", obj.getDescription(), maxTextLength));
177
+ for (const fixedValue of (_a = obj.getFixedValues()) !== null && _a !== void 0 ? _a : []) {
178
+ push(this.checkTextLength(file, "DDTEXT", fixedValue.description, maxTextLength, fixedValue.language));
179
+ }
180
+ for (const translationFixedValue of (_b = obj.getFixedValuesTranslations()) !== null && _b !== void 0 ? _b : []) {
181
+ push(this.checkTextLength(file, "DDTEXT", translationFixedValue.description, maxTextLength, translationFixedValue.language));
182
+ }
183
+ return issues;
184
+ }
185
+ runTransaction(obj, file) {
186
+ var _a;
187
+ const maxTextLength = 36;
188
+ const issues = [];
189
+ const push = (issue) => { if (issue) {
190
+ issues.push(issue);
191
+ } };
192
+ push(this.checkTextLength(file, "TTEXT", obj.getDescription(), maxTextLength));
193
+ for (const translation of (_a = obj.getTextsTranslations()) !== null && _a !== void 0 ? _a : []) {
194
+ push(this.checkTextLength(file, "TTEXT", translation.description, maxTextLength, translation.language));
195
+ }
196
+ return issues;
197
+ }
198
+ runMessageClass(obj, file) {
199
+ var _a;
200
+ const maxTextLength = 73;
201
+ const issues = [];
202
+ const push = (issue) => { if (issue) {
203
+ issues.push(issue);
204
+ } };
205
+ for (const msg of obj.getMessages()) {
206
+ push(this.checkTextLength(file, `TEXT[${msg.getNumber()}]`, msg.getMessage(), maxTextLength));
207
+ }
208
+ for (const translation of (_a = obj.getTextsTranslations()) !== null && _a !== void 0 ? _a : []) {
209
+ push(this.checkTextLength(file, `TEXT[${translation.number}]`, translation.text, maxTextLength, translation.language));
210
+ }
211
+ return issues;
212
+ }
80
213
  }
81
214
  exports.XMLConsistency = XMLConsistency;
82
215
  //# sourceMappingURL=xml_consistency.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.119.18",
3
+ "version": "2.119.21",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",