@abaplint/core 2.120.49 → 2.120.51

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.
@@ -2080,6 +2080,7 @@ declare class Domain extends AbstractObject {
2080
2080
  maxLength: number;
2081
2081
  allowNamespace: boolean;
2082
2082
  };
2083
+ getIdentifier(): Identifier | undefined;
2083
2084
  setDirty(): void;
2084
2085
  parseType(reg: IRegistry, dataElement?: string, description?: string): AbstractType;
2085
2086
  parse(): {
@@ -2088,6 +2089,7 @@ declare class Domain extends AbstractObject {
2088
2089
  };
2089
2090
  getFixedValues(): DomainValue[];
2090
2091
  getFixedValuesTranslations(): DomainValueTranslation[];
2092
+ private getAFFFile;
2091
2093
  }
2092
2094
 
2093
2095
  declare interface DomainValue {
@@ -337,6 +337,20 @@ class TypeUtils {
337
337
  || node.findFirstExpression(Expressions.ArithOperator) !== undefined;
338
338
  return calculated;
339
339
  }
340
+ // a character constant is only assignable to a hexadecimal target if it can be
341
+ // interpreted as a hexadecimal value
342
+ isHexConstant(node) {
343
+ const constant = node === null || node === void 0 ? void 0 : node.concatTokens();
344
+ if (constant === undefined) {
345
+ return true;
346
+ }
347
+ if ((constant.startsWith("'") && constant.endsWith("'"))
348
+ || (constant.startsWith("`") && constant.endsWith("`"))) {
349
+ const value = constant.substring(1, constant.length - 1);
350
+ return value.length > 0 && /^[0-9A-Fa-f]+$/.test(value);
351
+ }
352
+ return true;
353
+ }
340
354
  isAssignableNew(source, target, node) {
341
355
  const calculated = (node === null || node === void 0 ? void 0 : node.findFirstExpression(Expressions.ArithOperator)) !== undefined;
342
356
  if (calculated && source instanceof basic_1.HexType && target instanceof basic_1.IntegerType) {
@@ -402,7 +416,7 @@ class TypeUtils {
402
416
  }
403
417
  else if (target instanceof basic_1.XStringType) {
404
418
  if (((_d = source.getAbstractTypeData()) === null || _d === void 0 ? void 0 : _d.derivedFromConstant) === true) {
405
- return (node === null || node === void 0 ? void 0 : node.concatTokens()) !== "''";
419
+ return this.isHexConstant(node);
406
420
  }
407
421
  return false;
408
422
  }
@@ -38,16 +38,21 @@ const _abstract_object_1 = require("./_abstract_object");
38
38
  const Types = __importStar(require("../abap/types/basic"));
39
39
  const ddic_1 = require("../ddic");
40
40
  const xml_utils_1 = require("../xml_utils");
41
+ const _identifier_1 = require("../abap/4_file_information/_identifier");
42
+ const identifier_1 = require("../abap/1_lexer/tokens/identifier");
43
+ const position_1 = require("../position");
41
44
  class Domain extends _abstract_object_1.AbstractObject {
42
45
  getType() {
43
46
  return "DOMA";
44
47
  }
45
48
  getDescription() {
46
49
  var _a;
50
+ this.parse();
47
51
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.description;
48
52
  }
49
53
  getConversionExit() {
50
54
  var _a;
55
+ this.parse();
51
56
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.conversionExit;
52
57
  }
53
58
  getDataType() {
@@ -61,6 +66,17 @@ class Domain extends _abstract_object_1.AbstractObject {
61
66
  allowNamespace: true,
62
67
  };
63
68
  }
69
+ getIdentifier() {
70
+ const xmlIdentifier = super.getIdentifier();
71
+ if (xmlIdentifier) {
72
+ return xmlIdentifier;
73
+ }
74
+ const file = this.getAFFFile();
75
+ if (file === undefined) {
76
+ return undefined;
77
+ }
78
+ return new _identifier_1.Identifier(new identifier_1.Identifier(new position_1.Position(1, 1), this.getName()), file.getFilename());
79
+ }
64
80
  setDirty() {
65
81
  this.parsedXML = undefined;
66
82
  super.setDirty();
@@ -87,18 +103,57 @@ class Domain extends _abstract_object_1.AbstractObject {
87
103
  });
88
104
  }
89
105
  parse() {
90
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
106
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
107
+ var _v, _w;
91
108
  if (this.parsedXML) {
92
109
  return { updated: false, runtime: 0 };
93
110
  }
94
111
  const start = Date.now();
95
112
  this.parsedXML = {};
113
+ const jsonFile = this.getAFFFile();
114
+ if (jsonFile) {
115
+ try {
116
+ const parsed = JSON.parse(jsonFile.getRaw());
117
+ const language = (_a = parsed.header) === null || _a === void 0 ? void 0 : _a.originalLanguage;
118
+ const values = [];
119
+ for (const fixedValue of (_v = parsed.fixedValues) !== null && _v !== void 0 ? _v : []) {
120
+ values.push({
121
+ low: fixedValue === null || fixedValue === void 0 ? void 0 : fixedValue.fixedValue,
122
+ high: "",
123
+ description: fixedValue === null || fixedValue === void 0 ? void 0 : fixedValue.description,
124
+ language: language,
125
+ });
126
+ }
127
+ for (const interval of (_w = parsed.fixedValueIntervals) !== null && _w !== void 0 ? _w : []) {
128
+ values.push({
129
+ low: interval === null || interval === void 0 ? void 0 : interval.lowLimit,
130
+ high: interval === null || interval === void 0 ? void 0 : interval.highLimit,
131
+ description: interval === null || interval === void 0 ? void 0 : interval.description,
132
+ language: language,
133
+ });
134
+ }
135
+ this.parsedXML = {
136
+ description: (_b = parsed.header) === null || _b === void 0 ? void 0 : _b.description,
137
+ datatype: (_c = parsed.format) === null || _c === void 0 ? void 0 : _c.dataType,
138
+ length: (_e = (_d = parsed.format) === null || _d === void 0 ? void 0 : _d.length) === null || _e === void 0 ? void 0 : _e.toString(),
139
+ decimals: (_g = (_f = parsed.format) === null || _f === void 0 ? void 0 : _f.decimals) === null || _g === void 0 ? void 0 : _g.toString(),
140
+ conversionExit: (_h = parsed.outputCharacteristics) === null || _h === void 0 ? void 0 : _h.conversionRoutine,
141
+ values: values,
142
+ valuesTranslations: [],
143
+ };
144
+ }
145
+ catch (_x) {
146
+ // handled by parseType()
147
+ }
148
+ const end = Date.now();
149
+ return { updated: true, runtime: end - start };
150
+ }
96
151
  const parsed = super.parseRaw2();
97
152
  if (parsed === undefined) {
98
153
  return { updated: false, runtime: 0 };
99
154
  }
100
- const dd01v = (_c = (_b = (_a = 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.DD01V;
101
- const dd07v_tab = (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.DD07V_TAB) === null || _g === void 0 ? void 0 : _g.DD07V);
155
+ const dd01v = (_l = (_k = (_j = 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.DD01V;
156
+ const dd07v_tab = (0, xml_utils_1.xmlToArray)((_q = (_p = (_o = (_m = parsed.abapGit) === null || _m === void 0 ? void 0 : _m["asx:abap"]) === null || _o === void 0 ? void 0 : _o["asx:values"]) === null || _p === void 0 ? void 0 : _p.DD07V_TAB) === null || _q === void 0 ? void 0 : _q.DD07V);
102
157
  const values = [];
103
158
  for (const ddo7v of dd07v_tab) {
104
159
  const value = {
@@ -109,7 +164,7 @@ class Domain extends _abstract_object_1.AbstractObject {
109
164
  };
110
165
  values.push(value);
111
166
  }
112
- 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);
167
+ const dd07v_texts = (0, xml_utils_1.xmlToArray)((_u = (_t = (_s = (_r = parsed.abapGit) === null || _r === void 0 ? void 0 : _r["asx:abap"]) === null || _s === void 0 ? void 0 : _s["asx:values"]) === null || _t === void 0 ? void 0 : _t.DD07_TEXTS) === null || _u === void 0 ? void 0 : _u.item);
113
168
  const translationValues = [];
114
169
  for (const dd07v of dd07v_texts) {
115
170
  const value = {
@@ -140,6 +195,9 @@ class Domain extends _abstract_object_1.AbstractObject {
140
195
  var _b;
141
196
  return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.valuesTranslations) !== null && _b !== void 0 ? _b : [];
142
197
  }
198
+ getAFFFile() {
199
+ return this.getFiles().find(file => file.getFilename().toLowerCase().endsWith(".doma.json"));
200
+ }
143
201
  }
144
202
  exports.Domain = Domain;
145
203
  //# sourceMappingURL=domain.js.map
@@ -75,7 +75,7 @@ class Registry {
75
75
  }
76
76
  static abaplintVersion() {
77
77
  // magic, see build script "version.js"
78
- return "2.120.49";
78
+ return "2.120.51";
79
79
  }
80
80
  getDDICReferences() {
81
81
  return this.ddicReferences;
@@ -1058,15 +1058,19 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
1058
1058
  continue;
1059
1059
  }
1060
1060
  const condition = this.tableCondition(tableExpression);
1061
- const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
1061
+ // ASSIGNING, not INTO: from v740 a table expression in a read position addresses the
1062
+ // row rather than copying it, so "REF #( tab[ i ]-comp )" and "ASSIGN tab[ i ]-comp"
1063
+ // hand back an address INTO a work area would not preserve. The write path
1064
+ // (moveWithTableTarget) already lowers to ASSIGNING for the same reason.
1065
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
1062
1066
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
1063
1067
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
1064
1068
  const firstToken = high.getFirstToken();
1065
1069
  // note that the tabix restore should be done before throwing the exception
1066
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
1070
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${pre}.
1067
1071
  ${indentation}DATA ${tabixBackup} LIKE sy-tabix.
1068
1072
  ${indentation}${tabixBackup} = sy-tabix.
1069
- ${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
1073
+ ${indentation}READ TABLE ${pre} ${condition}ASSIGNING ${uniqueName}.
1070
1074
  ${indentation}sy-tabix = ${tabixBackup}.
1071
1075
  ${indentation}IF sy-subrc <> 0.
1072
1076
  ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
@@ -1820,8 +1824,7 @@ CONSTANTS: BEGIN OF ${structureName},\n`;
1820
1824
  if (index === undefined) {
1821
1825
  return undefined;
1822
1826
  }
1823
- let uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
1824
- uniqueName = `<${uniqueName}>`;
1827
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
1825
1828
  const tName = target.concatTokens().split("[")[0];
1826
1829
  const condition = this.tableCondition(tableExpression);
1827
1830
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
@@ -2833,12 +2836,16 @@ ${indentation} output = ${uniqueName}.\n`;
2833
2836
  }
2834
2837
  return undefined;
2835
2838
  }
2836
- uniqueName(position, filename, highSyntax) {
2839
+ /** a FIELD-SYMBOLS declaration is known to the scope under its bracketed spelling, so
2840
+ * the collision check has to use that spelling too - otherwise a second outline in the
2841
+ * same method is handed a name that is already taken and the result does not compile */
2842
+ uniqueName(position, filename, highSyntax, fieldSymbol = false) {
2843
+ const decorate = (name) => fieldSymbol === true ? `<${name}>` : name;
2837
2844
  const spag = highSyntax.spaghetti.lookupPosition(position, filename);
2838
2845
  if (spag === undefined) {
2839
2846
  const name = "temprr" + this.counter;
2840
2847
  this.counter++;
2841
- return name;
2848
+ return decorate(name);
2842
2849
  }
2843
2850
  let postfix = "";
2844
2851
  if (spag.getIdentifier().stype === _scope_type_1.ScopeType.ClassDefinition) {
@@ -2847,7 +2854,7 @@ ${indentation} output = ${uniqueName}.\n`;
2847
2854
  postfix = "_" + hash.substring(0, 10);
2848
2855
  }
2849
2856
  while (true) {
2850
- const name = "temp" + this.counter + postfix;
2857
+ const name = decorate("temp" + this.counter + postfix);
2851
2858
  const exists = this.existsRecursive(spag, name);
2852
2859
  this.counter++;
2853
2860
  if (exists === false) {
@@ -202,6 +202,7 @@ __exportStar(require("./use_line_exists"), exports);
202
202
  __exportStar(require("./use_new"), exports);
203
203
  __exportStar(require("./when_others_last"), exports);
204
204
  __exportStar(require("./whitespace_end"), exports);
205
+ __exportStar(require("./wrong_abapdoc_position"), exports);
205
206
  __exportStar(require("./xml_consistency"), exports);
206
207
  __exportStar(require("./no_exclamation_escape"), exports);
207
208
  __exportStar(require("./xml_bom"), exports);
@@ -0,0 +1,162 @@
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.WrongAbapdocPosition = exports.WrongAbapdocPositionConf = void 0;
37
+ const Statements = __importStar(require("../abap/2_statements/statements"));
38
+ const issue_1 = require("../issue");
39
+ const _abap_rule_1 = require("./_abap_rule");
40
+ const _basic_rule_config_1 = require("./_basic_rule_config");
41
+ const _irule_1 = require("./_irule");
42
+ const _statement_1 = require("../abap/2_statements/statements/_statement");
43
+ class WrongAbapdocPositionConf extends _basic_rule_config_1.BasicRuleConfig {
44
+ }
45
+ exports.WrongAbapdocPositionConf = WrongAbapdocPositionConf;
46
+ class WrongAbapdocPosition extends _abap_rule_1.ABAPRule {
47
+ constructor() {
48
+ super(...arguments);
49
+ this.conf = new WrongAbapdocPositionConf();
50
+ }
51
+ getMetadata() {
52
+ return {
53
+ key: "wrong_abapdoc_position",
54
+ title: "Wrong ABAP Doc position",
55
+ shortDescription: `ABAP Doc must be placed directly in front of the declaration it documents.`,
56
+ extendedInformation: `ABAP Doc documents the single declaration following it, an ABAP Doc block placed
57
+ elsewhere is silently ignored, leaving the declaration undocumented.
58
+
59
+ The following positions are reported,
60
+ * in front of a chained keyword, ie. before "CONSTANTS:" instead of after the colon,
61
+ * in the middle of a statement, ie. between the parameters of a METHODS definition,
62
+ * directly in front of ENDCLASS, ENDINTERFACE or a SECTION statement.
63
+
64
+ Only checks ABAP Doc inside class definitions and interfaces.`,
65
+ tags: [_irule_1.RuleTag.SingleFile],
66
+ badExample: `CLASS zcl_foo DEFINITION PUBLIC.
67
+ PUBLIC SECTION.
68
+ "! Navigation modes
69
+ CONSTANTS:
70
+ BEGIN OF cs_nav_mode,
71
+ back TYPE i VALUE 1,
72
+ END OF cs_nav_mode.
73
+ ENDCLASS.`,
74
+ goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
75
+ PUBLIC SECTION.
76
+ CONSTANTS:
77
+ "! Navigation modes
78
+ BEGIN OF cs_nav_mode,
79
+ back TYPE i VALUE 1,
80
+ END OF cs_nav_mode.
81
+ ENDCLASS.`,
82
+ };
83
+ }
84
+ getConfig() {
85
+ return this.conf;
86
+ }
87
+ setConfig(conf) {
88
+ this.conf = conf;
89
+ }
90
+ runParsed(file) {
91
+ const issues = [];
92
+ const statements = file.getStatements();
93
+ let definition = false;
94
+ for (let i = 0; i < statements.length; i++) {
95
+ const statement = statements[i];
96
+ const type = statement.get();
97
+ if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
98
+ definition = true;
99
+ continue;
100
+ }
101
+ else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
102
+ definition = false;
103
+ continue;
104
+ }
105
+ else if (definition === false || this.isAbapdoc(statement) === false) {
106
+ continue;
107
+ }
108
+ else if (this.isAbapdoc(statements[i - 1]) === true
109
+ && statements[i - 1].getStart().getRow() + 1 === statement.getStart().getRow()) {
110
+ continue; // only report the first row of each block
111
+ }
112
+ let next = undefined;
113
+ for (let j = i + 1; j < statements.length; j++) {
114
+ if (statements[j].get() instanceof _statement_1.Comment) {
115
+ continue;
116
+ }
117
+ next = statements[j];
118
+ break;
119
+ }
120
+ if (next === undefined) {
121
+ continue;
122
+ }
123
+ const message = this.check(statement, next);
124
+ if (message !== undefined) {
125
+ issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
126
+ }
127
+ }
128
+ return issues;
129
+ }
130
+ isAbapdoc(statement) {
131
+ return (statement === null || statement === void 0 ? void 0 : statement.get()) instanceof _statement_1.Comment
132
+ && statement.getFirstToken().getStr().startsWith(`"!`);
133
+ }
134
+ check(abapdoc, next) {
135
+ const type = next.get();
136
+ if (type instanceof Statements.EndClass
137
+ || type instanceof Statements.EndInterface
138
+ || type instanceof Statements.Public
139
+ || type instanceof Statements.Protected
140
+ || type instanceof Statements.Private) {
141
+ return "ABAP Doc does not document anything, move or delete it";
142
+ }
143
+ const position = abapdoc.getStart();
144
+ const colon = next.getColon();
145
+ if (colon === undefined) {
146
+ if (position.isAfter(next.getStart()) === true) {
147
+ return "ABAP Doc inside statement, move it in front of the statement";
148
+ }
149
+ return undefined;
150
+ }
151
+ if (position.isBefore(colon.getStart()) === true) {
152
+ return "ABAP Doc in front of chained statement, move it after the colon";
153
+ }
154
+ const member = next.getTokens().find(t => t.getStart().isAfter(colon.getStart()));
155
+ if (member !== undefined && position.isAfter(member.getStart()) === true) {
156
+ return "ABAP Doc inside statement, move it in front of the chained declaration";
157
+ }
158
+ return undefined;
159
+ }
160
+ }
161
+ exports.WrongAbapdocPosition = WrongAbapdocPosition;
162
+ //# sourceMappingURL=wrong_abapdoc_position.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/core",
3
- "version": "2.120.49",
3
+ "version": "2.120.51",
4
4
  "description": "abaplint - Core API",
5
5
  "main": "build/src/index.js",
6
6
  "typings": "build/abaplint.d.ts",