@abaplint/transpiler-cli 2.13.85 → 2.13.87

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/bundle.js +476 -56
  2. package/package.json +3 -3
package/build/bundle.js CHANGED
@@ -522,6 +522,13 @@ const BUFS = new Set([
522
522
  CH_DOT, CH_COMMA, CH_COLON, 40 /* ( */, 41 /* ) */, 91 /* [ */,
523
523
  93 /* ] */, 43 /* + */, CH_AT
524
524
  ]);
525
+ // characters that may follow the closing "'", "`" or "|" of a literal, anything else
526
+ // is a syntax error, "There must be a space or equivalent character after ...",
527
+ // note that "(" is allowed, ie. text elements like 'text'(001)
528
+ const AFTER_LITERAL = new Set([
529
+ EOF, CH_SPACE, CH_TAB, CH_NL, CH_DOT, CH_COMMA, CH_COLON, CH_DQUOTE,
530
+ 40 /* ( */, 41 /* ) */, 91 /* [ */, 93 /* ] */
531
+ ]);
525
532
  class Lexer {
526
533
  run(file, virtual) {
527
534
  this.virtual = virtual;
@@ -801,7 +808,11 @@ class Lexer {
801
808
  && ahead !== CH_BACKTICK
802
809
  && this.buffer.countIsEven(CH_BACKTICK)) {
803
810
  // end of ping
804
- this.add();
811
+ if (AFTER_LITERAL.has(ahead)) {
812
+ this.add();
813
+ }
814
+ // else: no separator after the literal, keep the buffer so the following
815
+ // characters are glued onto the token, the parser will report the error
805
816
  if (ahead === CH_DQUOTE) {
806
817
  this.m = ModeComment;
807
818
  }
@@ -814,7 +825,9 @@ class Lexer {
814
825
  && (current === CH_PIPE || current === CH_LBRACE)
815
826
  && (stream.prevChar() !== CH_BACKSLASH || (stream.prevPrevChar() === CH_BACKSLASH && stream.prevChar() === CH_BACKSLASH))) {
816
827
  // end of template
817
- this.add();
828
+ if (current === CH_LBRACE || AFTER_LITERAL.has(ahead)) {
829
+ this.add();
830
+ }
818
831
  this.m = ModeNormal;
819
832
  }
820
833
  else if (this.m === ModeTemplate
@@ -829,7 +842,9 @@ class Lexer {
829
842
  && ahead !== CH_QUOTE
830
843
  && this.buffer.countIsEven(CH_QUOTE)) {
831
844
  // end of string
832
- this.add();
845
+ if (AFTER_LITERAL.has(ahead)) {
846
+ this.add();
847
+ }
833
848
  if (ahead === CH_DQUOTE) {
834
849
  this.m = ModeComment;
835
850
  }
@@ -28183,6 +28198,20 @@ class TypeUtils {
28183
28198
  || node.findFirstExpression(Expressions.ArithOperator) !== undefined;
28184
28199
  return calculated;
28185
28200
  }
28201
+ // a character constant is only assignable to a hexadecimal target if it can be
28202
+ // interpreted as a hexadecimal value
28203
+ isHexConstant(node) {
28204
+ const constant = node === null || node === void 0 ? void 0 : node.concatTokens();
28205
+ if (constant === undefined) {
28206
+ return true;
28207
+ }
28208
+ if ((constant.startsWith("'") && constant.endsWith("'"))
28209
+ || (constant.startsWith("`") && constant.endsWith("`"))) {
28210
+ const value = constant.substring(1, constant.length - 1);
28211
+ return value.length > 0 && /^[0-9A-Fa-f]+$/.test(value);
28212
+ }
28213
+ return true;
28214
+ }
28186
28215
  isAssignableNew(source, target, node) {
28187
28216
  const calculated = (node === null || node === void 0 ? void 0 : node.findFirstExpression(Expressions.ArithOperator)) !== undefined;
28188
28217
  if (calculated && source instanceof basic_1.HexType && target instanceof basic_1.IntegerType) {
@@ -28248,7 +28277,7 @@ class TypeUtils {
28248
28277
  }
28249
28278
  else if (target instanceof basic_1.XStringType) {
28250
28279
  if (((_d = source.getAbstractTypeData()) === null || _d === void 0 ? void 0 : _d.derivedFromConstant) === true) {
28251
- return (node === null || node === void 0 ? void 0 : node.concatTokens()) !== "''";
28280
+ return this.isHexConstant(node);
28252
28281
  }
28253
28282
  return false;
28254
28283
  }
@@ -35180,6 +35209,7 @@ class Source {
35180
35209
  return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
35181
35210
  }
35182
35211
  this.addIfInferred(node, input, foundType);
35212
+ this.traverseRemainingChildren(children, input);
35183
35213
  return foundType;
35184
35214
  }
35185
35215
  case "REF":
@@ -63578,6 +63608,9 @@ const ddic_1 = __webpack_require__(/*! ../ddic */ "./node_modules/@abaplint/core
63578
63608
  const Types = __importStar(__webpack_require__(/*! ../abap/types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js"));
63579
63609
  const xml_utils_1 = __webpack_require__(/*! ../xml_utils */ "./node_modules/@abaplint/core/build/src/xml_utils.js");
63580
63610
  const domain_1 = __webpack_require__(/*! ./domain */ "./node_modules/@abaplint/core/build/src/objects/domain.js");
63611
+ const _identifier_1 = __webpack_require__(/*! ../abap/4_file_information/_identifier */ "./node_modules/@abaplint/core/build/src/abap/4_file_information/_identifier.js");
63612
+ const identifier_1 = __webpack_require__(/*! ../abap/1_lexer/tokens/identifier */ "./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/identifier.js");
63613
+ const position_1 = __webpack_require__(/*! ../position */ "./node_modules/@abaplint/core/build/src/position.js");
63581
63614
  class DataElement extends _abstract_object_1.AbstractObject {
63582
63615
  constructor() {
63583
63616
  super(...arguments);
@@ -63598,6 +63631,17 @@ class DataElement extends _abstract_object_1.AbstractObject {
63598
63631
  allowNamespace: true,
63599
63632
  };
63600
63633
  }
63634
+ getIdentifier() {
63635
+ const xmlIdentifier = super.getIdentifier();
63636
+ if (xmlIdentifier) {
63637
+ return xmlIdentifier;
63638
+ }
63639
+ const file = this.getAFFFile();
63640
+ if (file === undefined) {
63641
+ return undefined;
63642
+ }
63643
+ return new _identifier_1.Identifier(new identifier_1.Identifier(new position_1.Position(1, 1), this.getName()), file.getFilename());
63644
+ }
63601
63645
  setDirty() {
63602
63646
  this.parsedXML = undefined;
63603
63647
  this.parsedType = undefined;
@@ -63645,7 +63689,6 @@ class DataElement extends _abstract_object_1.AbstractObject {
63645
63689
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.dtelmaster;
63646
63690
  }
63647
63691
  parseType(reg) {
63648
- var _a;
63649
63692
  const references = [];
63650
63693
  let lookup = undefined;
63651
63694
  this.parse();
@@ -63657,7 +63700,53 @@ class DataElement extends _abstract_object_1.AbstractObject {
63657
63700
  return this.parsedType;
63658
63701
  }
63659
63702
  const ddic = new ddic_1.DDIC(reg);
63660
- if (this.parsedXML.refkind === "D") {
63703
+ const lookupPredefinedType = () => {
63704
+ var _a, _b;
63705
+ if (((_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.datatype) === undefined || this.parsedXML.datatype === "") {
63706
+ return { type: new Types.UnknownType("DATATYPE unexpectely empty in " + this.getName()) };
63707
+ }
63708
+ return { type: ddic.textToType({
63709
+ text: this.parsedXML.datatype,
63710
+ length: this.parsedXML.leng,
63711
+ decimals: this.parsedXML.decimals,
63712
+ infoText: this.getName(),
63713
+ qualifiedName: this.getName(),
63714
+ conversionExit: undefined,
63715
+ ddicName: this.getName(),
63716
+ description: (_b = this.parsedXML.texts) === null || _b === void 0 ? void 0 : _b.heading,
63717
+ }) };
63718
+ };
63719
+ if (this.parsedXML.affCategory === "referenceToPredefinedType") {
63720
+ const predefined = lookupPredefinedType();
63721
+ lookup = predefined.type instanceof Types.UnknownType
63722
+ ? predefined
63723
+ : { type: new Types.DataReference(predefined.type, this.getName()) };
63724
+ }
63725
+ else if (this.parsedXML.affCategory === "referenceDictionaryType") {
63726
+ if (this.parsedXML.domname === undefined || this.parsedXML.domname === "") {
63727
+ lookup = { type: new Types.UnknownType("Type name unexpectely empty in " + this.getName()) };
63728
+ }
63729
+ else {
63730
+ const referenced = ddic.lookup(this.parsedXML.domname);
63731
+ lookup = referenced.type instanceof Types.UnknownType
63732
+ ? referenced
63733
+ : Object.assign(Object.assign({}, referenced), { type: new Types.DataReference(referenced.type, this.getName()) });
63734
+ }
63735
+ }
63736
+ else if (this.parsedXML.affCategory === "referenceClasIntType") {
63737
+ if (this.parsedXML.domname === undefined || this.parsedXML.domname === "") {
63738
+ lookup = { type: new Types.UnknownType("Type name unexpectely empty in " + this.getName()) };
63739
+ }
63740
+ else {
63741
+ lookup = ddic.lookupObject(this.parsedXML.domname);
63742
+ }
63743
+ }
63744
+ else if (this.parsedXML.affCategory !== undefined
63745
+ && this.parsedXML.affCategory !== "domain"
63746
+ && this.parsedXML.affCategory !== "predefinedType") {
63747
+ lookup = { type: new Types.UnknownType("Unknown AFF data type category " + this.parsedXML.affCategory + " in " + this.getName()) };
63748
+ }
63749
+ else if (this.parsedXML.refkind === "D") {
63661
63750
  if (this.parsedXML.domname === undefined || this.parsedXML.domname === "") {
63662
63751
  lookup = { type: new Types.UnknownType("DOMNAME unexpectely empty in " + this.getName()) };
63663
63752
  }
@@ -63674,21 +63763,7 @@ class DataElement extends _abstract_object_1.AbstractObject {
63674
63763
  }
63675
63764
  }
63676
63765
  else {
63677
- if (this.parsedXML.datatype === undefined || this.parsedXML.datatype === "") {
63678
- lookup = { type: new Types.UnknownType("DATATYPE unexpectely empty in " + this.getName()) };
63679
- }
63680
- else {
63681
- lookup = { type: ddic.textToType({
63682
- text: this.parsedXML.datatype,
63683
- length: this.parsedXML.leng,
63684
- decimals: this.parsedXML.decimals,
63685
- infoText: this.getName(),
63686
- qualifiedName: this.getName(),
63687
- conversionExit: undefined,
63688
- ddicName: this.getName(),
63689
- description: (_a = this.parsedXML.texts) === null || _a === void 0 ? void 0 : _a.heading,
63690
- }) };
63691
- }
63766
+ lookup = lookupPredefinedType();
63692
63767
  }
63693
63768
  }
63694
63769
  if (lookup.object) {
@@ -63703,17 +63778,52 @@ class DataElement extends _abstract_object_1.AbstractObject {
63703
63778
  return lookup.type;
63704
63779
  }
63705
63780
  parse() {
63706
- var _a, _b, _c, _d, _e, _f, _g;
63781
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
63707
63782
  if (this.parsedXML !== undefined) {
63708
63783
  return { updated: false, runtime: 0 };
63709
63784
  }
63710
63785
  const start = Date.now();
63711
63786
  this.parsedXML = {};
63787
+ const jsonFile = this.getAFFFile();
63788
+ if (jsonFile) {
63789
+ try {
63790
+ const parsed = JSON.parse(jsonFile.getRaw());
63791
+ const typeInformation = parsed.dataTypeInformation;
63792
+ const predefinedType = typeInformation === null || typeInformation === void 0 ? void 0 : typeInformation.predefinedType;
63793
+ const fieldLabels = parsed.fieldLabels;
63794
+ this.parsedXML = {
63795
+ description: (_a = parsed.header) === null || _a === void 0 ? void 0 : _a.description,
63796
+ affCategory: typeInformation === null || typeInformation === void 0 ? void 0 : typeInformation.category,
63797
+ refkind: (typeInformation === null || typeInformation === void 0 ? void 0 : typeInformation.category) === "domain" ? "D" : undefined,
63798
+ domname: typeInformation === null || typeInformation === void 0 ? void 0 : typeInformation.typeName,
63799
+ datatype: predefinedType === null || predefinedType === void 0 ? void 0 : predefinedType.dataType,
63800
+ leng: (_b = predefinedType === null || predefinedType === void 0 ? void 0 : predefinedType.length) === null || _b === void 0 ? void 0 : _b.toString(),
63801
+ decimals: (_c = predefinedType === null || predefinedType === void 0 ? void 0 : predefinedType.decimals) === null || _c === void 0 ? void 0 : _c.toString(),
63802
+ texts: {
63803
+ short: fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.short,
63804
+ medium: fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.medium,
63805
+ long: fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.long,
63806
+ heading: fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.heading,
63807
+ },
63808
+ textMaxLengths: {
63809
+ short: (_d = fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.shortLength) === null || _d === void 0 ? void 0 : _d.toString(),
63810
+ medium: (_e = fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.mediumLength) === null || _e === void 0 ? void 0 : _e.toString(),
63811
+ long: (_f = fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.longLength) === null || _f === void 0 ? void 0 : _f.toString(),
63812
+ heading: (_g = fieldLabels === null || fieldLabels === void 0 ? void 0 : fieldLabels.headingLength) === null || _g === void 0 ? void 0 : _g.toString(),
63813
+ },
63814
+ };
63815
+ }
63816
+ catch (_q) {
63817
+ // handled by parseType()
63818
+ }
63819
+ const end = Date.now();
63820
+ return { updated: true, runtime: end - start };
63821
+ }
63712
63822
  const parsed = super.parseRaw2();
63713
63823
  if (parsed === undefined) {
63714
63824
  return { updated: false, runtime: 0 };
63715
63825
  }
63716
- const dd04v = (_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.DD04V;
63826
+ const dd04v = (_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.DD04V;
63717
63827
  this.parsedXML = {
63718
63828
  description: dd04v === null || dd04v === void 0 ? void 0 : dd04v.DDTEXT,
63719
63829
  refkind: dd04v === null || dd04v === void 0 ? void 0 : dd04v.REFKIND,
@@ -63736,7 +63846,7 @@ class DataElement extends _abstract_object_1.AbstractObject {
63736
63846
  },
63737
63847
  };
63738
63848
  this.parsedXML.textsTranslations = [];
63739
- 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)) {
63849
+ for (const item of (0, xml_utils_1.xmlToArray)((_p = (_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.DD04_TEXTS) === null || _p === void 0 ? void 0 : _p.item)) {
63740
63850
  this.parsedXML.textsTranslations.push({
63741
63851
  language: item.DDLANGUAGE,
63742
63852
  description: item.DDTEXT,
@@ -63749,6 +63859,9 @@ class DataElement extends _abstract_object_1.AbstractObject {
63749
63859
  const end = Date.now();
63750
63860
  return { updated: true, runtime: end - start };
63751
63861
  }
63862
+ getAFFFile() {
63863
+ return this.getFiles().find(file => file.getFilename().toLowerCase().endsWith(".dtel.json"));
63864
+ }
63752
63865
  }
63753
63866
  exports.DataElement = DataElement;
63754
63867
  //# sourceMappingURL=data_element.js.map
@@ -63895,16 +64008,21 @@ const _abstract_object_1 = __webpack_require__(/*! ./_abstract_object */ "./node
63895
64008
  const Types = __importStar(__webpack_require__(/*! ../abap/types/basic */ "./node_modules/@abaplint/core/build/src/abap/types/basic/index.js"));
63896
64009
  const ddic_1 = __webpack_require__(/*! ../ddic */ "./node_modules/@abaplint/core/build/src/ddic.js");
63897
64010
  const xml_utils_1 = __webpack_require__(/*! ../xml_utils */ "./node_modules/@abaplint/core/build/src/xml_utils.js");
64011
+ const _identifier_1 = __webpack_require__(/*! ../abap/4_file_information/_identifier */ "./node_modules/@abaplint/core/build/src/abap/4_file_information/_identifier.js");
64012
+ const identifier_1 = __webpack_require__(/*! ../abap/1_lexer/tokens/identifier */ "./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/identifier.js");
64013
+ const position_1 = __webpack_require__(/*! ../position */ "./node_modules/@abaplint/core/build/src/position.js");
63898
64014
  class Domain extends _abstract_object_1.AbstractObject {
63899
64015
  getType() {
63900
64016
  return "DOMA";
63901
64017
  }
63902
64018
  getDescription() {
63903
64019
  var _a;
64020
+ this.parse();
63904
64021
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.description;
63905
64022
  }
63906
64023
  getConversionExit() {
63907
64024
  var _a;
64025
+ this.parse();
63908
64026
  return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.conversionExit;
63909
64027
  }
63910
64028
  getDataType() {
@@ -63918,6 +64036,17 @@ class Domain extends _abstract_object_1.AbstractObject {
63918
64036
  allowNamespace: true,
63919
64037
  };
63920
64038
  }
64039
+ getIdentifier() {
64040
+ const xmlIdentifier = super.getIdentifier();
64041
+ if (xmlIdentifier) {
64042
+ return xmlIdentifier;
64043
+ }
64044
+ const file = this.getAFFFile();
64045
+ if (file === undefined) {
64046
+ return undefined;
64047
+ }
64048
+ return new _identifier_1.Identifier(new identifier_1.Identifier(new position_1.Position(1, 1), this.getName()), file.getFilename());
64049
+ }
63921
64050
  setDirty() {
63922
64051
  this.parsedXML = undefined;
63923
64052
  super.setDirty();
@@ -63944,18 +64073,57 @@ class Domain extends _abstract_object_1.AbstractObject {
63944
64073
  });
63945
64074
  }
63946
64075
  parse() {
63947
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
64076
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u;
64077
+ var _v, _w;
63948
64078
  if (this.parsedXML) {
63949
64079
  return { updated: false, runtime: 0 };
63950
64080
  }
63951
64081
  const start = Date.now();
63952
64082
  this.parsedXML = {};
64083
+ const jsonFile = this.getAFFFile();
64084
+ if (jsonFile) {
64085
+ try {
64086
+ const parsed = JSON.parse(jsonFile.getRaw());
64087
+ const language = (_a = parsed.header) === null || _a === void 0 ? void 0 : _a.originalLanguage;
64088
+ const values = [];
64089
+ for (const fixedValue of (_v = parsed.fixedValues) !== null && _v !== void 0 ? _v : []) {
64090
+ values.push({
64091
+ low: fixedValue === null || fixedValue === void 0 ? void 0 : fixedValue.fixedValue,
64092
+ high: "",
64093
+ description: fixedValue === null || fixedValue === void 0 ? void 0 : fixedValue.description,
64094
+ language: language,
64095
+ });
64096
+ }
64097
+ for (const interval of (_w = parsed.fixedValueIntervals) !== null && _w !== void 0 ? _w : []) {
64098
+ values.push({
64099
+ low: interval === null || interval === void 0 ? void 0 : interval.lowLimit,
64100
+ high: interval === null || interval === void 0 ? void 0 : interval.highLimit,
64101
+ description: interval === null || interval === void 0 ? void 0 : interval.description,
64102
+ language: language,
64103
+ });
64104
+ }
64105
+ this.parsedXML = {
64106
+ description: (_b = parsed.header) === null || _b === void 0 ? void 0 : _b.description,
64107
+ datatype: (_c = parsed.format) === null || _c === void 0 ? void 0 : _c.dataType,
64108
+ length: (_e = (_d = parsed.format) === null || _d === void 0 ? void 0 : _d.length) === null || _e === void 0 ? void 0 : _e.toString(),
64109
+ decimals: (_g = (_f = parsed.format) === null || _f === void 0 ? void 0 : _f.decimals) === null || _g === void 0 ? void 0 : _g.toString(),
64110
+ conversionExit: (_h = parsed.outputCharacteristics) === null || _h === void 0 ? void 0 : _h.conversionRoutine,
64111
+ values: values,
64112
+ valuesTranslations: [],
64113
+ };
64114
+ }
64115
+ catch (_x) {
64116
+ // handled by parseType()
64117
+ }
64118
+ const end = Date.now();
64119
+ return { updated: true, runtime: end - start };
64120
+ }
63953
64121
  const parsed = super.parseRaw2();
63954
64122
  if (parsed === undefined) {
63955
64123
  return { updated: false, runtime: 0 };
63956
64124
  }
63957
- 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;
63958
- 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);
64125
+ 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;
64126
+ 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);
63959
64127
  const values = [];
63960
64128
  for (const ddo7v of dd07v_tab) {
63961
64129
  const value = {
@@ -63966,7 +64134,7 @@ class Domain extends _abstract_object_1.AbstractObject {
63966
64134
  };
63967
64135
  values.push(value);
63968
64136
  }
63969
- 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);
64137
+ 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);
63970
64138
  const translationValues = [];
63971
64139
  for (const dd07v of dd07v_texts) {
63972
64140
  const value = {
@@ -63997,6 +64165,9 @@ class Domain extends _abstract_object_1.AbstractObject {
63997
64165
  var _b;
63998
64166
  return (_b = (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.valuesTranslations) !== null && _b !== void 0 ? _b : [];
63999
64167
  }
64168
+ getAFFFile() {
64169
+ return this.getFiles().find(file => file.getFilename().toLowerCase().endsWith(".doma.json"));
64170
+ }
64000
64171
  }
64001
64172
  exports.Domain = Domain;
64002
64173
  //# sourceMappingURL=domain.js.map
@@ -70877,7 +71048,7 @@ class Registry {
70877
71048
  }
70878
71049
  static abaplintVersion() {
70879
71050
  // magic, see build script "version.js"
70880
- return "2.120.48";
71051
+ return "2.120.52";
70881
71052
  }
70882
71053
  getDDICReferences() {
70883
71054
  return this.ddicReferences;
@@ -79014,15 +79185,19 @@ ${indentation}${uniqueName} = ${source.concatTokens()}.\n${indentation}`);
79014
79185
  continue;
79015
79186
  }
79016
79187
  const condition = this.tableCondition(tableExpression);
79017
- const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79188
+ // ASSIGNING, not INTO: from v740 a table expression in a read position addresses the
79189
+ // row rather than copying it, so "REF #( tab[ i ]-comp )" and "ASSIGN tab[ i ]-comp"
79190
+ // hand back an address INTO a work area would not preserve. The write path
79191
+ // (moveWithTableTarget) already lowers to ASSIGNING for the same reason.
79192
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
79018
79193
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79019
79194
  const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
79020
79195
  const firstToken = high.getFirstToken();
79021
79196
  // note that the tabix restore should be done before throwing the exception
79022
- const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.
79197
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${pre}.
79023
79198
  ${indentation}DATA ${tabixBackup} LIKE sy-tabix.
79024
79199
  ${indentation}${tabixBackup} = sy-tabix.
79025
- ${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.
79200
+ ${indentation}READ TABLE ${pre} ${condition}ASSIGNING ${uniqueName}.
79026
79201
  ${indentation}sy-tabix = ${tabixBackup}.
79027
79202
  ${indentation}IF sy-subrc <> 0.
79028
79203
  ${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.
@@ -79776,8 +79951,7 @@ CONSTANTS: BEGIN OF ${structureName},\n`;
79776
79951
  if (index === undefined) {
79777
79952
  return undefined;
79778
79953
  }
79779
- let uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
79780
- uniqueName = `<${uniqueName}>`;
79954
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax, true);
79781
79955
  const tName = target.concatTokens().split("[")[0];
79782
79956
  const condition = this.tableCondition(tableExpression);
79783
79957
  const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
@@ -80789,12 +80963,16 @@ ${indentation} output = ${uniqueName}.\n`;
80789
80963
  }
80790
80964
  return undefined;
80791
80965
  }
80792
- uniqueName(position, filename, highSyntax) {
80966
+ /** a FIELD-SYMBOLS declaration is known to the scope under its bracketed spelling, so
80967
+ * the collision check has to use that spelling too - otherwise a second outline in the
80968
+ * same method is handed a name that is already taken and the result does not compile */
80969
+ uniqueName(position, filename, highSyntax, fieldSymbol = false) {
80970
+ const decorate = (name) => fieldSymbol === true ? `<${name}>` : name;
80793
80971
  const spag = highSyntax.spaghetti.lookupPosition(position, filename);
80794
80972
  if (spag === undefined) {
80795
80973
  const name = "temprr" + this.counter;
80796
80974
  this.counter++;
80797
- return name;
80975
+ return decorate(name);
80798
80976
  }
80799
80977
  let postfix = "";
80800
80978
  if (spag.getIdentifier().stype === _scope_type_1.ScopeType.ClassDefinition) {
@@ -80803,7 +80981,7 @@ ${indentation} output = ${uniqueName}.\n`;
80803
80981
  postfix = "_" + hash.substring(0, 10);
80804
80982
  }
80805
80983
  while (true) {
80806
- const name = "temp" + this.counter + postfix;
80984
+ const name = decorate("temp" + this.counter + postfix);
80807
80985
  const exists = this.existsRecursive(spag, name);
80808
80986
  this.counter++;
80809
80987
  if (exists === false) {
@@ -85285,6 +85463,7 @@ __exportStar(__webpack_require__(/*! ./use_line_exists */ "./node_modules/@abapl
85285
85463
  __exportStar(__webpack_require__(/*! ./use_new */ "./node_modules/@abaplint/core/build/src/rules/use_new.js"), exports);
85286
85464
  __exportStar(__webpack_require__(/*! ./when_others_last */ "./node_modules/@abaplint/core/build/src/rules/when_others_last.js"), exports);
85287
85465
  __exportStar(__webpack_require__(/*! ./whitespace_end */ "./node_modules/@abaplint/core/build/src/rules/whitespace_end.js"), exports);
85466
+ __exportStar(__webpack_require__(/*! ./wrong_abapdoc_position */ "./node_modules/@abaplint/core/build/src/rules/wrong_abapdoc_position.js"), exports);
85288
85467
  __exportStar(__webpack_require__(/*! ./xml_consistency */ "./node_modules/@abaplint/core/build/src/rules/xml_consistency.js"), exports);
85289
85468
  __exportStar(__webpack_require__(/*! ./no_exclamation_escape */ "./node_modules/@abaplint/core/build/src/rules/no_exclamation_escape.js"), exports);
85290
85469
  __exportStar(__webpack_require__(/*! ./xml_bom */ "./node_modules/@abaplint/core/build/src/rules/xml_bom.js"), exports);
@@ -100767,6 +100946,178 @@ exports.WhitespaceEnd = WhitespaceEnd;
100767
100946
 
100768
100947
  /***/ },
100769
100948
 
100949
+ /***/ "./node_modules/@abaplint/core/build/src/rules/wrong_abapdoc_position.js"
100950
+ /*!*******************************************************************************!*\
100951
+ !*** ./node_modules/@abaplint/core/build/src/rules/wrong_abapdoc_position.js ***!
100952
+ \*******************************************************************************/
100953
+ (__unused_webpack_module, exports, __webpack_require__) {
100954
+
100955
+ "use strict";
100956
+
100957
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
100958
+ if (k2 === undefined) k2 = k;
100959
+ var desc = Object.getOwnPropertyDescriptor(m, k);
100960
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
100961
+ desc = { enumerable: true, get: function() { return m[k]; } };
100962
+ }
100963
+ Object.defineProperty(o, k2, desc);
100964
+ }) : (function(o, m, k, k2) {
100965
+ if (k2 === undefined) k2 = k;
100966
+ o[k2] = m[k];
100967
+ }));
100968
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
100969
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
100970
+ }) : function(o, v) {
100971
+ o["default"] = v;
100972
+ });
100973
+ var __importStar = (this && this.__importStar) || (function () {
100974
+ var ownKeys = function(o) {
100975
+ ownKeys = Object.getOwnPropertyNames || function (o) {
100976
+ var ar = [];
100977
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
100978
+ return ar;
100979
+ };
100980
+ return ownKeys(o);
100981
+ };
100982
+ return function (mod) {
100983
+ if (mod && mod.__esModule) return mod;
100984
+ var result = {};
100985
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
100986
+ __setModuleDefault(result, mod);
100987
+ return result;
100988
+ };
100989
+ })();
100990
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
100991
+ exports.WrongAbapdocPosition = exports.WrongAbapdocPositionConf = void 0;
100992
+ const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
100993
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
100994
+ const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
100995
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
100996
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
100997
+ const _statement_1 = __webpack_require__(/*! ../abap/2_statements/statements/_statement */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/_statement.js");
100998
+ class WrongAbapdocPositionConf extends _basic_rule_config_1.BasicRuleConfig {
100999
+ }
101000
+ exports.WrongAbapdocPositionConf = WrongAbapdocPositionConf;
101001
+ class WrongAbapdocPosition extends _abap_rule_1.ABAPRule {
101002
+ constructor() {
101003
+ super(...arguments);
101004
+ this.conf = new WrongAbapdocPositionConf();
101005
+ }
101006
+ getMetadata() {
101007
+ return {
101008
+ key: "wrong_abapdoc_position",
101009
+ title: "Wrong ABAP Doc position",
101010
+ shortDescription: `ABAP Doc must be placed directly in front of the declaration it documents.`,
101011
+ extendedInformation: `ABAP Doc documents the single declaration following it, an ABAP Doc block placed
101012
+ elsewhere is silently ignored, leaving the declaration undocumented.
101013
+
101014
+ The following positions are reported,
101015
+ * in front of a chained keyword, ie. before "CONSTANTS:" instead of after the colon,
101016
+ * in the middle of a statement, ie. between the parameters of a METHODS definition,
101017
+ * directly in front of ENDCLASS, ENDINTERFACE or a SECTION statement.
101018
+
101019
+ Only checks ABAP Doc inside class definitions and interfaces.`,
101020
+ tags: [_irule_1.RuleTag.SingleFile],
101021
+ badExample: `CLASS zcl_foo DEFINITION PUBLIC.
101022
+ PUBLIC SECTION.
101023
+ "! Navigation modes
101024
+ CONSTANTS:
101025
+ BEGIN OF cs_nav_mode,
101026
+ back TYPE i VALUE 1,
101027
+ END OF cs_nav_mode.
101028
+ ENDCLASS.`,
101029
+ goodExample: `CLASS zcl_foo DEFINITION PUBLIC.
101030
+ PUBLIC SECTION.
101031
+ CONSTANTS:
101032
+ "! Navigation modes
101033
+ BEGIN OF cs_nav_mode,
101034
+ back TYPE i VALUE 1,
101035
+ END OF cs_nav_mode.
101036
+ ENDCLASS.`,
101037
+ };
101038
+ }
101039
+ getConfig() {
101040
+ return this.conf;
101041
+ }
101042
+ setConfig(conf) {
101043
+ this.conf = conf;
101044
+ }
101045
+ runParsed(file) {
101046
+ const issues = [];
101047
+ const statements = file.getStatements();
101048
+ let definition = false;
101049
+ for (let i = 0; i < statements.length; i++) {
101050
+ const statement = statements[i];
101051
+ const type = statement.get();
101052
+ if (type instanceof Statements.ClassDefinition || type instanceof Statements.Interface) {
101053
+ definition = true;
101054
+ continue;
101055
+ }
101056
+ else if (type instanceof Statements.EndClass || type instanceof Statements.EndInterface) {
101057
+ definition = false;
101058
+ continue;
101059
+ }
101060
+ else if (definition === false || this.isAbapdoc(statement) === false) {
101061
+ continue;
101062
+ }
101063
+ else if (this.isAbapdoc(statements[i - 1]) === true
101064
+ && statements[i - 1].getStart().getRow() + 1 === statement.getStart().getRow()) {
101065
+ continue; // only report the first row of each block
101066
+ }
101067
+ let next = undefined;
101068
+ for (let j = i + 1; j < statements.length; j++) {
101069
+ if (statements[j].get() instanceof _statement_1.Comment) {
101070
+ continue;
101071
+ }
101072
+ next = statements[j];
101073
+ break;
101074
+ }
101075
+ if (next === undefined) {
101076
+ continue;
101077
+ }
101078
+ const message = this.check(statement, next);
101079
+ if (message !== undefined) {
101080
+ issues.push(issue_1.Issue.atStatement(file, statement, message, this.getMetadata().key, this.conf.severity));
101081
+ }
101082
+ }
101083
+ return issues;
101084
+ }
101085
+ isAbapdoc(statement) {
101086
+ return (statement === null || statement === void 0 ? void 0 : statement.get()) instanceof _statement_1.Comment
101087
+ && statement.getFirstToken().getStr().startsWith(`"!`);
101088
+ }
101089
+ check(abapdoc, next) {
101090
+ const type = next.get();
101091
+ if (type instanceof Statements.EndClass
101092
+ || type instanceof Statements.EndInterface
101093
+ || type instanceof Statements.Public
101094
+ || type instanceof Statements.Protected
101095
+ || type instanceof Statements.Private) {
101096
+ return "ABAP Doc does not document anything, move or delete it";
101097
+ }
101098
+ const position = abapdoc.getStart();
101099
+ const colon = next.getColon();
101100
+ if (colon === undefined) {
101101
+ if (position.isAfter(next.getStart()) === true) {
101102
+ return "ABAP Doc inside statement, move it in front of the statement";
101103
+ }
101104
+ return undefined;
101105
+ }
101106
+ if (position.isBefore(colon.getStart()) === true) {
101107
+ return "ABAP Doc in front of chained statement, move it after the colon";
101108
+ }
101109
+ const member = next.getTokens().find(t => t.getStart().isAfter(colon.getStart()));
101110
+ if (member !== undefined && position.isAfter(member.getStart()) === true) {
101111
+ return "ABAP Doc inside statement, move it in front of the chained declaration";
101112
+ }
101113
+ return undefined;
101114
+ }
101115
+ }
101116
+ exports.WrongAbapdocPosition = WrongAbapdocPosition;
101117
+ //# sourceMappingURL=wrong_abapdoc_position.js.map
101118
+
101119
+ /***/ },
101120
+
100770
101121
  /***/ "./node_modules/@abaplint/core/build/src/rules/xml_bom.js"
100771
101122
  /*!****************************************************************!*\
100772
101123
  !*** ./node_modules/@abaplint/core/build/src/rules/xml_bom.js ***!
@@ -104661,8 +105012,10 @@ class ConstantTranspiler {
104661
105012
  return new chunk_1.Chunk(`todo, Constant`);
104662
105013
  }
104663
105014
  handleCharacter(res) {
104664
- const foo = res.replace(/''/g, "'");
104665
- let length = foo.length - 2;
105015
+ // length of the value: strip the enclosing quotes first, an escaped
105016
+ // quote ('') inside counts as one character and must not merge with them
105017
+ const inner = res.substring(1, res.length - 1).replace(/''/g, "'");
105018
+ let length = inner.length;
104666
105019
  if (length <= 0) {
104667
105020
  // note: Characters cannot have length = zero, 1 is minimum
104668
105021
  length = 1;
@@ -106944,10 +107297,50 @@ class SourceTranspiler {
106944
107297
  constructor(addGet = false) {
106945
107298
  this.addGet = addGet;
106946
107299
  }
107300
+ // the operands of a chain of & / && (the rearranger leaves them as a binary
107301
+ // tree of Source nodes); an empty list when the node is not such a chain
107302
+ concatOperands(node) {
107303
+ const children = node.getChildren();
107304
+ if (children.length !== 3) {
107305
+ return [];
107306
+ }
107307
+ const op = children[1];
107308
+ if (!(op instanceof core_1.Nodes.TokenNode) || (op.getFirstToken().getStr() !== "&&" && op.getFirstToken().getStr() !== "&")) {
107309
+ return [];
107310
+ }
107311
+ const side = (c) => {
107312
+ if (c instanceof core_1.Nodes.ExpressionNode && c.get() instanceof core_1.Expressions.Source) {
107313
+ const inner = this.concatOperands(c);
107314
+ return inner.length > 0 ? inner : [c];
107315
+ }
107316
+ const wrapped = new core_1.Nodes.ExpressionNode(new core_1.Expressions.Source());
107317
+ wrapped.setChildren([c]);
107318
+ return [wrapped];
107319
+ };
107320
+ return [...side(children[0]), ...side(children[2])];
107321
+ }
106947
107322
  transpile(node, traversal, context) {
106948
107323
  let ret = new chunk_1.Chunk();
106949
107324
  const post = new chunk_1.Chunk();
106950
107325
  const children = node.getChildren();
107326
+ // a & b & c ... : one flat concat([a, b, c]) instead of one nested
107327
+ // concat( ) per operand (a long chain would otherwise exhaust the stack
107328
+ // of a parser with a small budget, e.g. a service worker's)
107329
+ const operands = this.concatOperands(node);
107330
+ if (operands.length > 2) {
107331
+ const flat = new chunk_1.Chunk().appendString("abap.operators.concat([");
107332
+ for (let i = 0; i < operands.length; i++) {
107333
+ if (i > 0) {
107334
+ flat.appendString(",");
107335
+ }
107336
+ flat.appendChunk(new SourceTranspiler(false).transpile(operands[i], traversal, context));
107337
+ }
107338
+ flat.appendString("])");
107339
+ if (this.addGet) {
107340
+ flat.appendString(".get()");
107341
+ }
107342
+ return flat;
107343
+ }
106951
107344
  // Pre-scan for unary prefix +/- tokens (WDashW / WPlusW) before any expression
106952
107345
  let prefixNegated = false;
106953
107346
  let startIdx = 0;
@@ -110585,7 +110978,8 @@ globalThis.abap = new runtime.ABAP();\n`;
110585
110978
  || obj instanceof abaplint.Objects.Oauth2Profile
110586
110979
  || obj instanceof abaplint.Objects.WebMIME
110587
110980
  || obj instanceof abaplint.Objects.TypePool
110588
- || obj instanceof abaplint.Objects.TableType) {
110981
+ || obj instanceof abaplint.Objects.TableType
110982
+ || obj instanceof abaplint.Objects.View) {
110589
110983
  list.push(imp(`${escapeNamespaceFilename(obj.getName().toLowerCase())}.${obj.getType().toLowerCase()}`));
110590
110984
  }
110591
110985
  }
@@ -110751,9 +111145,13 @@ exports.DEFAULT_KEYWORDS = new Set([
110751
111145
  "throw", "throws", "transient", "true",
110752
111146
  "try", "typeof", "var", "void",
110753
111147
  "delete",
110754
- "volatile", "while", "yield"
111148
+ "volatile", "while", "yield",
111149
+ // both produce a SyntaxError in the emitted module: they are reserved words
111150
+ // in JavaScript and legal ABAP names. "super" is NOT in this list on purpose -
111151
+ // the emitted code uses the JS `super` for ABAP's `super->method( )`, and
111152
+ // escaping it turns that call into `$super.get().method()`
111153
+ "case", "with"
110755
111154
  ]);
110756
- // "with"
110757
111155
  //# sourceMappingURL=keywords.js.map
110758
111156
 
110759
111157
  /***/ },
@@ -110956,7 +111354,23 @@ class Rearranger {
110956
111354
  return node;
110957
111355
  }
110958
111356
  const withoutLast = node.getChildren().slice(0, children.length - 1);
110959
- const flat = withoutLast.concat(last.getChildren());
111357
+ // The nested children come up so that precedence can be decided across
111358
+ // the whole chain, and everything before the nested operator has to
111359
+ // arrive as one operand. For "a * b / c" that is already true, b being a
111360
+ // single Source. For "a * CONV f( b ) / c" it is not: CONV is five
111361
+ // children, and hoisting them one by one puts the type name and the
111362
+ // body beside the arithmetic, where the transpiler reads them as
111363
+ // operands and loses the rest of the expression. So the head is wrapped
111364
+ // back into one Source before it moves.
111365
+ const nested = last.getChildren();
111366
+ const firstOperator = nested.findIndex((c) => c instanceof core_1.Nodes.ExpressionNode && c.get() instanceof core_1.Expressions.ArithOperator);
111367
+ let head = nested.slice(0, firstOperator);
111368
+ if (head.length > 1) {
111369
+ const operand = new core_1.Nodes.ExpressionNode(last.get());
111370
+ operand.setChildren(head);
111371
+ head = [operand];
111372
+ }
111373
+ const flat = withoutLast.concat(head, nested.slice(firstOperator));
110960
111374
  node.setChildren(flat);
110961
111375
  return node;
110962
111376
  }
@@ -118788,9 +119202,11 @@ class SelectTranspiler {
118788
119202
  where = sqlCond;
118789
119203
  }
118790
119204
  }
119205
+ let whereClause = "";
118791
119206
  if (where) {
118792
- select += "WHERE " + new expressions_1.SQLCondTranspiler().transpile(where, traversal, table).getCode() + " ";
119207
+ whereClause = "WHERE " + new expressions_1.SQLCondTranspiler().transpile(where, traversal, table).getCode() + " ";
118793
119208
  }
119209
+ select += whereClause;
118794
119210
  const groupBy = node.findFirstExpression(abaplint.Expressions.SQLGroupBy);
118795
119211
  if (groupBy) {
118796
119212
  select += new sql_group_by_1.SQLGroupByTranspiler().transpile(groupBy, traversal).getCode() + " ";
@@ -118831,6 +119247,7 @@ class SelectTranspiler {
118831
119247
  else {
118832
119248
  const code = new expressions_1.FieldChainTranspiler(true).transpile(chain, traversal).getCode();
118833
119249
  select = select.replace(search, `" + ${code} + "`);
119250
+ whereClause = whereClause.replace(search, `" + ${code} + "`);
118834
119251
  }
118835
119252
  }
118836
119253
  }
@@ -118858,14 +119275,17 @@ class SelectTranspiler {
118858
119275
  const unique2 = unique_identifier_1.UniqueIdentifier.get();
118859
119276
  const fn = node.findFirstExpression(abaplint.Expressions.SQLForAllEntries)?.findDirectExpression(abaplint.Expressions.SQLSource);
118860
119277
  const faeTranspiled = new expressions_1.SQLSourceTranspiler().transpile(fn, traversal).getCode();
119278
+ // ABAP semantics: with an empty driving table the whole WHERE condition is ignored
119279
+ const selectEmpty = select.replace(whereClause, "");
118861
119280
  select = select.replace(new RegExp(" " + escapeRegExp(faeTranspiled), "g"), " " + unique);
118862
119281
  select = select.replace(unique + ".get().table_line.get()", unique + ".get()"); // there can be only one?
118863
- let by = `Object.keys(${target}.getRowType().get())`;
118864
- if (keys.length > 0) {
118865
- by = JSON.stringify(keys);
118866
- }
119282
+ // FOR ALL ENTRIES removes duplicate rows from the result: duplicates of
119283
+ // the selected columns, so de-duplicate by the target's components. The
119284
+ // DB key alone is wrong for projections (INTO CORRESPONDING FIELDS
119285
+ // without the key fields crashed on the missing component names)
119286
+ const by = `Object.keys(${target}.getRowType().get())`;
118867
119287
  const code = `if (${faeTranspiled}.array().length === 0) {
118868
- throw new Error("FAE, todo, empty table");
119288
+ await abap.statements.select(${target}, {select: "${selectEmpty.trim()}"${extra}});
118869
119289
  } else {
118870
119290
  const ${unique2} = ${faeTranspiled}.array();
118871
119291
  ${target}.clear();
@@ -121897,16 +122317,16 @@ class FunctionModuleTranspiler {
121897
122317
  direction = "importing";
121898
122318
  }
121899
122319
  // note: all directions are optional
121900
- let name = p.name.toLowerCase();
121901
- if (traversal.options?.keywords?.some(a => a === name)) {
121902
- name += "_";
121903
- }
121904
- ret += `let ${name} = INPUT.${direction}?.${name};\n`;
122320
+ const name = p.name.toLowerCase();
122321
+ // a parameter named like a JavaScript keyword, RETURN on every BAPI,
122322
+ // is declared the way the function body refers to it
122323
+ const variable = traversal_1.Traversal.prefixVariable(name);
122324
+ ret += `let ${variable} = INPUT.${direction}?.${name};\n`;
121905
122325
  const type = scope?.findVariable(name)?.getType();
121906
122326
  if (type !== undefined && p.optional === true) {
121907
122327
  // todo, set DEFAULT value
121908
- ret += `if (${name} === undefined) {
121909
- ${name} = ${transpile_types_1.TranspileTypes.toType(type)};
122328
+ ret += `if (${variable} === undefined) {
122329
+ ${variable} = ${transpile_types_1.TranspileTypes.toType(type)};
121910
122330
  }\n`;
121911
122331
  }
121912
122332
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler-cli",
3
- "version": "2.13.85",
3
+ "version": "2.13.87",
4
4
  "description": "Transpiler - Command Line Interface",
5
5
  "funding": "https://github.com/sponsors/larshp",
6
6
  "bin": {
@@ -27,8 +27,8 @@
27
27
  "author": "abaplint",
28
28
  "license": "MIT",
29
29
  "devDependencies": {
30
- "@abaplint/core": "^2.120.48",
31
- "@abaplint/transpiler": "^2.13.85",
30
+ "@abaplint/core": "^2.120.52",
31
+ "@abaplint/transpiler": "^2.13.87",
32
32
  "@types/glob": "^9.0.0",
33
33
  "@types/node": "^26.4.1",
34
34
  "@types/progress": "^2.0.7",