@abaplint/cli 2.120.44 → 2.120.46

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 (2) hide show
  1. package/build/cli.js +166 -14
  2. package/package.json +2 -2
package/build/cli.js CHANGED
@@ -36347,6 +36347,19 @@ class ValueBody {
36347
36347
  const message = "VALUE, source type CharacterType not compatible with StringType";
36348
36348
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
36349
36349
  }
36350
+ else if (this.insertsUsingTableKey(targetType)) {
36351
+ // only STANDARD tables append the rows, and thus allow padding of shorter c and x values
36352
+ const row = this.characterOrHexLength(rowType);
36353
+ const source = this.characterOrHexLength(sourceType);
36354
+ if (row !== undefined
36355
+ && source !== undefined
36356
+ && row.abap === source.abap
36357
+ && row.length !== source.length) {
36358
+ const message = `VALUE, source type ${source.abap} LENGTH ${source.length} not compatible ` +
36359
+ `with row type ${row.abap} LENGTH ${row.length}`;
36360
+ input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
36361
+ }
36362
+ }
36350
36363
  }
36351
36364
  }
36352
36365
  if (letScoped === true) {
@@ -36360,6 +36373,25 @@ class ValueBody {
36360
36373
  }
36361
36374
  return targetType ? targetType : type;
36362
36375
  }
36376
+ /** SORTED and HASHED tables insert the constructed rows using the table key, which
36377
+ * requires the rows to be compatible with the row type. STANDARD tables only append
36378
+ * the rows, so shorter c and x values are padded on the right instead. */
36379
+ static insertsUsingTableKey(targetType) {
36380
+ if (!(targetType instanceof basic_1.TableType)) {
36381
+ return false;
36382
+ }
36383
+ const accessType = targetType.getAccessType();
36384
+ return accessType === basic_1.TableAccessType.sorted || accessType === basic_1.TableAccessType.hashed;
36385
+ }
36386
+ static characterOrHexLength(type) {
36387
+ if (type instanceof basic_1.CharacterType) {
36388
+ return { abap: "c", length: type.getLength() };
36389
+ }
36390
+ else if (type instanceof basic_1.HexType) {
36391
+ return { abap: "x", length: type.getLength() };
36392
+ }
36393
+ return undefined;
36394
+ }
36363
36395
  }
36364
36396
  exports.ValueBody = ValueBody;
36365
36397
  //# sourceMappingURL=value_body.js.map
@@ -68679,6 +68711,20 @@ class Table extends _abstract_object_1.AbstractObject {
68679
68711
  }
68680
68712
  return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.tableCategory;
68681
68713
  }
68714
+ getDeliveryClass() {
68715
+ var _a;
68716
+ if (this.parsedData === undefined) {
68717
+ this.parseXML();
68718
+ }
68719
+ return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.deliveryClass;
68720
+ }
68721
+ getSizeCategory() {
68722
+ var _a;
68723
+ if (this.parsedData === undefined) {
68724
+ this.parseXML();
68725
+ }
68726
+ return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.sizeCategory;
68727
+ }
68682
68728
  getEnhancementCategory() {
68683
68729
  var _a;
68684
68730
  if (this.parsedData === undefined) {
@@ -68706,7 +68752,7 @@ class Table extends _abstract_object_1.AbstractObject {
68706
68752
  return false;
68707
68753
  }
68708
68754
  parseXML() {
68709
- 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;
68755
+ 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;
68710
68756
  const parsed = super.parseRaw2();
68711
68757
  if (parsed === undefined) {
68712
68758
  return;
@@ -68726,8 +68772,10 @@ class Table extends _abstract_object_1.AbstractObject {
68726
68772
  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;
68727
68773
  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;
68728
68774
  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;
68775
+ 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;
68776
+ 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;
68729
68777
  // fields
68730
- 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;
68778
+ 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;
68731
68779
  for (const field of (0, xml_utils_1.xmlToArray)(fields === null || fields === void 0 ? void 0 : fields.DD03P)) {
68732
68780
  if (typeof (field === null || field === void 0 ? void 0 : field.FIELDNAME) !== "string") {
68733
68781
  continue;
@@ -68751,13 +68799,13 @@ class Table extends _abstract_object_1.AbstractObject {
68751
68799
  });
68752
68800
  }
68753
68801
  // secondary indexes
68754
- 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;
68802
+ 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;
68755
68803
  ;
68756
68804
  this.parsedData.secondaryIndexes = [];
68757
68805
  for (const index of (0, xml_utils_1.xmlToArray)(indexes === null || indexes === void 0 ? void 0 : indexes.DD12V)) {
68758
68806
  const indexName = index.INDEXNAME;
68759
68807
  const indexFields = [];
68760
- 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;
68808
+ 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;
68761
68809
  for (const indexField of (0, xml_utils_1.xmlToArray)(indexFieldsXml === null || indexFieldsXml === void 0 ? void 0 : indexFieldsXml.DD17V)) {
68762
68810
  if (indexField.INDEXNAME === indexName) {
68763
68811
  // assumption: fields are listed by POSITION in the xml
@@ -70295,7 +70343,7 @@ class Registry {
70295
70343
  }
70296
70344
  static abaplintVersion() {
70297
70345
  // magic, see build script "version.js"
70298
- return "2.120.44";
70346
+ return "2.120.46";
70299
70347
  }
70300
70348
  getDDICReferences() {
70301
70349
  return this.ddicReferences;
@@ -71926,7 +71974,7 @@ class AllowedObjectNaming {
71926
71974
  key: "allowed_object_naming",
71927
71975
  title: "Allowed object naming",
71928
71976
  shortDescription: `Enforces basic name length and namespace restrictions, see note SAP 104010`,
71929
- tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile],
71977
+ tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Syntax],
71930
71978
  };
71931
71979
  }
71932
71980
  initialize(_reg) {
@@ -77783,6 +77831,10 @@ Make sure to test the downported code, it might not always be completely correct
77783
77831
  if (found) {
77784
77832
  return found;
77785
77833
  }
77834
+ found = this.outlineTableExpressionKeyBuiltin(low, high, lowFile, highSyntax);
77835
+ if (found) {
77836
+ return found;
77837
+ }
77786
77838
  found = this.assignWithTable(low, high, lowFile);
77787
77839
  if (found) {
77788
77840
  return found;
@@ -78480,6 +78532,69 @@ ${indentation}`);
78480
78532
  }
78481
78533
  return condition;
78482
78534
  }
78535
+ /** A built-in function is only recognized as one in an operand position that admits an
78536
+ * expression, and "WITH KEY comp = ..." does not become such a position until v740. The
78537
+ * table expression rewrites carry the key operand over verbatim, so
78538
+ * "tab[ comp = to_upper( x ) ]" downports to a READ TABLE that a 702 or 731 compiler can
78539
+ * only read as a functional method call - "method TO_UPPER is unknown", reported as a
78540
+ * SYNTAX_ERROR of the whole class pool. Hoist the call into a variable first, an
78541
+ * assignment IS an expression position at 702.
78542
+ *
78543
+ * Built-ins that predate 702 (lines, strlen, numofchar, ...) carry no release in
78544
+ * BuiltIn.methods; they are accepted in the operand as they are and stay untouched. So do
78545
+ * functional method calls, which are exactly the reading that makes the built-in fail, and
78546
+ * the INDEX operand of "tab[ 1 ]", which is not a key operand. */
78547
+ outlineTableExpressionKeyBuiltin(low, high, lowFile, highSyntax) {
78548
+ if (!(low.get() instanceof _statement_1.Unknown)) {
78549
+ return undefined;
78550
+ }
78551
+ for (const tableExpression of high.findAllExpressionsRecursive(Expressions.TableExpression)) {
78552
+ let afterComponent = false;
78553
+ for (const child of tableExpression.getChildren()) {
78554
+ if (child.get() instanceof Expressions.ComponentChainSimple) {
78555
+ afterComponent = true;
78556
+ continue;
78557
+ }
78558
+ else if (afterComponent === false
78559
+ || !(child.get() instanceof Expressions.Source)
78560
+ || !(child instanceof nodes_1.ExpressionNode)) {
78561
+ continue;
78562
+ }
78563
+ const type = this.builtinReturnType(child, lowFile, highSyntax);
78564
+ if (type === undefined) {
78565
+ continue;
78566
+ }
78567
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
78568
+ const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
78569
+ const code = `DATA ${uniqueName} TYPE ${type}.\n` +
78570
+ indentation + `${uniqueName} = ${child.concatTokens()}.\n` +
78571
+ indentation;
78572
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);
78573
+ const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, child.getFirstToken().getStart(), child.getLastToken().getEnd(), uniqueName);
78574
+ const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
78575
+ return issue_1.Issue.atToken(lowFile, child.getFirstToken(), "Outline built-in function in table expression key", this.getMetadata().key, this.conf.severity, fix);
78576
+ }
78577
+ }
78578
+ return undefined;
78579
+ }
78580
+ /** the ABAP type returned by the built-in function this Source starts with, or undefined
78581
+ * if it does not start with one, or with one that predates 702 */
78582
+ builtinReturnType(source, lowFile, highSyntax) {
78583
+ var _a, _b, _c;
78584
+ const spag = highSyntax.spaghetti.lookupPosition(source.getFirstToken().getStart(), lowFile.getFilename());
78585
+ for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {
78586
+ if (r.referenceType !== _reference_1.ReferenceType.BuiltinMethodReference
78587
+ || r.position.getStart().equals(source.getFirstToken().getStart()) === false) {
78588
+ continue;
78589
+ }
78590
+ const name = r.position.getName().toUpperCase();
78591
+ if (((_a = _builtin_1.BuiltIn.methods[name]) === null || _a === void 0 ? void 0 : _a.release) === undefined) {
78592
+ return undefined;
78593
+ }
78594
+ return (_c = (_b = _builtin_1.BuiltIn.searchBuiltin(name)) === null || _b === void 0 ? void 0 : _b.getParameters().getReturning()) === null || _c === void 0 ? void 0 : _c.getType().toABAP();
78595
+ }
78596
+ return undefined;
78597
+ }
78483
78598
  outlineCatchSimple(node, lowFile) {
78484
78599
  // outlines "CATCH cx_bcs INTO DATA(lx_bcs_excep).", note that this does not need to look at types
78485
78600
  var _a, _b;
@@ -80090,9 +80205,13 @@ ${indentation} output = ${uniqueName}.\n`;
80090
80205
  continue;
80091
80206
  }
80092
80207
  const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
80093
- const type = this.findType(i, lowFile, highSyntax);
80094
80208
  const indent = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
80095
- const abap = `DATA ${uniqueName} TYPE ${type}.\n` +
80209
+ // the CONV type might just be a component of the row type, so prefer the row type
80210
+ const rowOf = this.findRowTypeOf(high, i);
80211
+ const declaration = rowOf === undefined
80212
+ ? `DATA ${uniqueName} TYPE ${this.findType(i, lowFile, highSyntax)}.`
80213
+ : `DATA ${uniqueName} LIKE LINE OF ${rowOf}.`;
80214
+ const abap = declaration + "\n" +
80096
80215
  indent + `${uniqueName} = ${body}.\n` +
80097
80216
  indent;
80098
80217
  const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);
@@ -80102,6 +80221,19 @@ ${indentation} output = ${uniqueName}.\n`;
80102
80221
  }
80103
80222
  return undefined;
80104
80223
  }
80224
+ /** if the source expression is the complete source of an INSERT or APPEND statement, then the
80225
+ * outlined variable must be typed via the row type of the table, returns the table name */
80226
+ findRowTypeOf(high, source) {
80227
+ var _a;
80228
+ if (!(high.get() instanceof Statements.InsertInternal)
80229
+ && !(high.get() instanceof Statements.Append)) {
80230
+ return undefined;
80231
+ }
80232
+ else if (high.getChildren()[1] !== source) {
80233
+ return undefined;
80234
+ }
80235
+ return (_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.concatTokens();
80236
+ }
80105
80237
  // "CAST" to "?="
80106
80238
  outlineCast(low, high, lowFile, highSyntax) {
80107
80239
  var _a;
@@ -85668,6 +85800,7 @@ exports.LineBreakStyle = exports.LineBreakStyleConf = void 0;
85668
85800
  const issue_1 = __webpack_require__(/*! ../issue */ "../core/build/src/issue.js");
85669
85801
  const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "../core/build/src/rules/_basic_rule_config.js");
85670
85802
  const _irule_1 = __webpack_require__(/*! ./_irule */ "../core/build/src/rules/_irule.js");
85803
+ const objects_1 = __webpack_require__(/*! ../objects */ "../core/build/src/objects/index.js");
85671
85804
  class LineBreakStyleConf extends _basic_rule_config_1.BasicRuleConfig {
85672
85805
  }
85673
85806
  exports.LineBreakStyleConf = LineBreakStyleConf;
@@ -85678,10 +85811,11 @@ class LineBreakStyle {
85678
85811
  getMetadata() {
85679
85812
  return {
85680
85813
  key: "line_break_style",
85681
- title: "Makes sure line breaks are consistent in the ABAP code",
85682
- shortDescription: `Enforces LF as newlines in ABAP files
85814
+ title: "Makes sure line breaks are consistent",
85815
+ shortDescription: `Enforces LF as newlines in ABAP and XML files
85683
85816
 
85684
85817
  abapGit does not work with CRLF`,
85818
+ extendedInformation: `SMIM and W3MI files are not checked.`,
85685
85819
  tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.SingleFile],
85686
85820
  };
85687
85821
  }
@@ -85696,8 +85830,15 @@ abapGit does not work with CRLF`,
85696
85830
  }
85697
85831
  run(obj) {
85698
85832
  const output = [];
85833
+ if (obj instanceof objects_1.MIMEObject || obj instanceof objects_1.WebMIME) {
85834
+ return output;
85835
+ }
85699
85836
  for (const file of obj.getFiles()) {
85700
- if (file.getFilename().endsWith(".abap")) {
85837
+ const filename = file.getFilename();
85838
+ if (filename.endsWith(".abap") || filename.endsWith(".xml")) {
85839
+ if (filename.endsWith(".xslt.source.xml")) {
85840
+ continue;
85841
+ }
85701
85842
  const rows = file.getRawRows();
85702
85843
  for (let i = 0; i < rows.length; i++) {
85703
85844
  if (rows[i].endsWith("\r") === true) {
@@ -100223,6 +100364,7 @@ class XMLConsistency {
100223
100364
  * XML is well-formed and parseable
100224
100365
  * Naming for CLAS and INTF objects
100225
100366
  * QUAN fields in TABL objects have reference table and field values
100367
+ * Transparent TABL objects have delivery class and size category set
100226
100368
  * Lock parameter names in ENQU objects are max 16 characters
100227
100369
  * Texts and translations do not exceed maximum allowed length.`,
100228
100370
  tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
@@ -100481,15 +100623,25 @@ class XMLConsistency {
100481
100623
  return issues;
100482
100624
  }
100483
100625
  runTable(obj, file) {
100484
- var _a, _b;
100485
- var _c;
100626
+ var _a, _b, _c, _d;
100627
+ var _e;
100486
100628
  const issues = [];
100487
- for (const field of (_c = obj.getFields()) !== null && _c !== void 0 ? _c : []) {
100629
+ for (const field of (_e = obj.getFields()) !== null && _e !== void 0 ? _e : []) {
100488
100630
  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()))) {
100489
100631
  const message = `QUAN field ${field.FIELDNAME} must have REFTABLE and REFFIELD set`;
100490
100632
  issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
100491
100633
  }
100492
100634
  }
100635
+ if (obj.getTableCategory() === Objects.TableCategory.Transparent) {
100636
+ if (!((_c = obj.getDeliveryClass()) === null || _c === void 0 ? void 0 : _c.trim())) {
100637
+ const message = `Transparent table must have delivery class(CONTFLAG in DD02V) set`;
100638
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
100639
+ }
100640
+ if (!((_d = obj.getSizeCategory()) === null || _d === void 0 ? void 0 : _d.trim())) {
100641
+ const message = `Transparent table must have size category(TABKAT in DD09L) set`;
100642
+ issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
100643
+ }
100644
+ }
100493
100645
  return issues;
100494
100646
  }
100495
100647
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/cli",
3
- "version": "2.120.44",
3
+ "version": "2.120.46",
4
4
  "description": "abaplint - Command Line Interface",
5
5
  "funding": "https://github.com/sponsors/larshp",
6
6
  "bin": {
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "homepage": "https://abaplint.org",
41
41
  "devDependencies": {
42
- "@abaplint/core": "^2.120.44",
42
+ "@abaplint/core": "^2.120.46",
43
43
  "@types/chai": "^4.3.20",
44
44
  "@types/minimist": "^1.2.5",
45
45
  "@types/mocha": "^10.0.10",