@abaplint/transpiler-cli 2.13.87 → 2.13.88

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 +389 -21
  2. package/package.json +3 -3
package/build/bundle.js CHANGED
@@ -177,15 +177,32 @@ class FileOperations {
177
177
  }
178
178
  return (0, p_limit_1.default)(concurrency);
179
179
  }
180
+ // abapGit stores the content of a Web Repository or MIME object beside its
181
+ // XML, in a file whose name says .w3mi.data. or .smim.data. That content is
182
+ // bytes, and reading it as UTF-8 destroys it: every byte above 0x7F fails to
183
+ // decode and comes back as the replacement character, so a PNG arrives
184
+ // starting ef bf bd rather than 89 50 4e 47 and is served, with a plausible
185
+ // size and the right content type, as a broken image.
186
+ //
187
+ // latin1 rather than a Buffer because the whole pipeline carries a file as a
188
+ // string; latin1 maps every byte to the code point of the same value, so a
189
+ // read and a write of it are exact. Node's "binary" is the same encoding
190
+ // under its old name, so there is nothing more faithful to switch to: the
191
+ // only stronger answer is to carry a Buffer end to end and never make it a
192
+ // string at all, which is a change to every file the transpiler touches.
193
+ // Measured on an 11770 byte PNG: latin1 and binary both return it
194
+ // unchanged, utf8 returns 20175 bytes and no longer a PNG.
195
+ static isBinaryFilename(filename) {
196
+ return /\.(w3mi|smim)\.data\./i.test(filename);
197
+ }
180
198
  static async readAllFiles(filesToRead, outputFolder) {
181
199
  const limit = this.setupPLimit();
182
200
  const promises = filesToRead.map((filename) => {
183
201
  return limit(async () => {
184
- // const isBinary = filename.includes(".w3mi.data.");
185
202
  return {
186
203
  filename: path.basename(filename),
187
204
  relative: path.relative(outputFolder, path.dirname(filename)),
188
- contents: await fsPromises.readFile(filename, "utf8"),
205
+ contents: await fsPromises.readFile(filename, this.isBinaryFilename(filename) ? "latin1" : "utf8"),
189
206
  };
190
207
  });
191
208
  });
@@ -221,7 +238,9 @@ class FileOperations {
221
238
  const limit = this.setupPLimit();
222
239
  const promises = files.map((file) => {
223
240
  return limit(async () => {
224
- await fsPromises.writeFile(file.path, file.contents);
241
+ // read as latin1, written as latin1: anything else re-encodes the
242
+ // bytes on the way out and undoes the careful read
243
+ await fsPromises.writeFile(file.path, file.contents, this.isBinaryFilename(file.path) ? { encoding: "latin1" } : undefined);
225
244
  });
226
245
  });
227
246
  await Promise.all(promises);
@@ -380,7 +399,7 @@ async function writeObjects(outputFiles, config, outputFolder, files) {
380
399
  && (type === "PROG" || type === "FUGR" || type === "CLAS")) {
381
400
  const name = output.filename + ".map";
382
401
  // SourceMappingUrl needs to be percent-encoded, ref https://github.com/microsoft/TypeScript/issues/40951
383
- contents = contents + `\n//# sourceMappingURL=` + name.replace(/#/g, "%23");
402
+ contents = contents + `\n//# sourceMappingURL=` + name.replace(/%/g, "%25").replace(/#/g, "%23");
384
403
  // map the bare abap filename each mapping carries to its path on disk;
385
404
  // source map "sources" are URLs, so always forward slashes, also on Windows
386
405
  const sourcePaths = {};
@@ -12856,7 +12875,7 @@ class CallTransaction {
12856
12875
  getMatcher() {
12857
12876
  const options = (0, combi_1.seq)("OPTIONS FROM", expressions_1.Source);
12858
12877
  const messages = (0, combi_1.seq)("MESSAGES INTO", expressions_1.Target);
12859
- const auth = (0, combi_1.seq)((0, combi_1.altPrio)("WITH", "WITHOUT"), "AUTHORITY-CHECK");
12878
+ const auth = (0, combi_1.ver)(version_1.Release.v740sp02, (0, combi_1.seq)((0, combi_1.altPrio)("WITH", "WITHOUT"), "AUTHORITY-CHECK"));
12860
12879
  const perm = (0, combi_1.per)((0, combi_1.seq)("UPDATE", expressions_1.Source), "AND SKIP FIRST SCREEN", options, messages, (0, combi_1.seq)("MODE", expressions_1.Source));
12861
12880
  const ret = (0, combi_1.seq)("CALL TRANSACTION", expressions_1.Source, (0, combi_1.optPrio)(auth), (0, combi_1.optPrio)((0, combi_1.seq)("USING", expressions_1.Source)), (0, combi_1.opt)(perm));
12862
12881
  return (0, combi_1.verNotLang)(version_1.LanguageVersion.Cloud, ret);
@@ -25134,12 +25153,15 @@ class ABAPFileInformationParser {
25134
25153
  continue;
25135
25154
  }
25136
25155
  const parameters = this.parseMethodParameters(def);
25156
+ const concatenated = def.concatTokens().toUpperCase();
25137
25157
  methods.push({
25138
25158
  name: methodName.getStr(),
25139
25159
  identifier: new _identifier_1.Identifier(methodName, this.filename),
25140
25160
  isRedefinition: def.findDirectExpression(Expressions.Redefinition) !== undefined,
25141
- isForTesting: def.concatTokens().toUpperCase().includes(" FOR TESTING"),
25142
- isFinal: def.concatTokens().toUpperCase().includes(" FINAL"),
25161
+ isForTesting: concatenated.includes(" FOR TESTING"),
25162
+ isFinal: concatenated.includes(" FINAL"),
25163
+ isDefaultIgnore: concatenated.includes(" DEFAULT IGNORE"),
25164
+ isDefaultFail: concatenated.includes(" DEFAULT FAIL"),
25143
25165
  isAbstract: def.findDirectExpression(Expressions.Abstract) !== undefined,
25144
25166
  isEventHandler: def.findDirectExpression(Expressions.EventHandler) !== undefined,
25145
25167
  visibility,
@@ -35305,11 +35327,15 @@ class Source {
35305
35327
  }
35306
35328
  let hexExpected = false;
35307
35329
  let hexNext = false;
35330
+ // an arithmetic operator has been seen, so the operands that follow
35331
+ // determine a calculation type rather than simply replacing the context
35332
+ let arithmetic = false;
35308
35333
  while (children.length >= 0) {
35309
35334
  if (first instanceof nodes_1.ExpressionNode) {
35310
35335
  const get = first.get();
35311
35336
  if (get instanceof Expressions.MethodCallChain) {
35312
- context = method_call_chain_1.MethodCallChain.runSyntax(first, input, targetType);
35337
+ const found = method_call_chain_1.MethodCallChain.runSyntax(first, input, targetType);
35338
+ context = arithmetic === true ? this.infer(context, found, true) : found;
35313
35339
  if (context === undefined) {
35314
35340
  const message = "Method has no RETURNING value";
35315
35341
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
@@ -35317,18 +35343,19 @@ class Source {
35317
35343
  }
35318
35344
  }
35319
35345
  else if (get instanceof Expressions.FieldChain) {
35320
- context = field_chain_1.FieldChain.runSyntax(first, input, type, allowGenericDeference);
35346
+ const found = field_chain_1.FieldChain.runSyntax(first, input, type, allowGenericDeference);
35347
+ context = arithmetic === true ? this.infer(context, found, true) : found;
35321
35348
  }
35322
35349
  else if (get instanceof Expressions.StringTemplate) {
35323
35350
  context = string_template_1.StringTemplate.runSyntax(first, input);
35324
35351
  }
35325
35352
  else if (get instanceof Expressions.Source) {
35326
35353
  const found = Source.runSyntax(first, input);
35327
- context = this.infer(context, found);
35354
+ context = this.infer(context, found, arithmetic);
35328
35355
  }
35329
35356
  else if (get instanceof Expressions.Constant) {
35330
35357
  const found = constant_1.Constant.runSyntax(first);
35331
- context = this.infer(context, found);
35358
+ context = this.infer(context, found, arithmetic);
35332
35359
  }
35333
35360
  else if (get instanceof Expressions.Dereference) {
35334
35361
  context = dereference_1.Dereference.runSyntax(first, context, input);
@@ -35337,6 +35364,7 @@ class Source {
35337
35364
  context = component_chain_1.ComponentChain.runSyntax(context, first, input);
35338
35365
  }
35339
35366
  else if (get instanceof Expressions.ArithOperator) {
35367
+ arithmetic = true;
35340
35368
  if (first.concatTokens() === "**") {
35341
35369
  context = new basic_1.FloatType();
35342
35370
  }
@@ -35383,7 +35411,13 @@ class Source {
35383
35411
  Source.runSyntax(last, input);
35384
35412
  }
35385
35413
  }
35386
- static infer(context, found) {
35414
+ static infer(context, found, arithmetic = false) {
35415
+ if (arithmetic === true) {
35416
+ const calculation = this.calculationType(context, found);
35417
+ if (calculation !== undefined) {
35418
+ return calculation;
35419
+ }
35420
+ }
35387
35421
  if (context instanceof basic_1.FloatType && found instanceof basic_1.IntegerType) {
35388
35422
  return context;
35389
35423
  }
@@ -35397,6 +35431,56 @@ class Source {
35397
35431
  return found;
35398
35432
  }
35399
35433
  }
35434
+ /** The calculation type of an arithmetic expression is the most general of the
35435
+ * operand types. An operand of type c, n, d, t or string is converted into it and
35436
+ * never becomes the result: "lv_f * '0.25'" is a float, not a character field of
35437
+ * length four. Returns undefined when neither operand is numeric, leaving the
35438
+ * decision to the caller. */
35439
+ static calculationType(left, right) {
35440
+ if (left === undefined || right === undefined) {
35441
+ return undefined;
35442
+ }
35443
+ else if (left instanceof basic_1.VoidType || left instanceof unknown_type_1.UnknownType) {
35444
+ // not knowing an operand means not knowing the result
35445
+ return left;
35446
+ }
35447
+ else if (right instanceof basic_1.VoidType || right instanceof unknown_type_1.UnknownType) {
35448
+ return right;
35449
+ }
35450
+ const leftRank = this.numericRank(left);
35451
+ const rightRank = this.numericRank(right);
35452
+ if (leftRank === undefined && rightRank === undefined) {
35453
+ return undefined;
35454
+ }
35455
+ else if (rightRank === undefined) {
35456
+ return left;
35457
+ }
35458
+ else if (leftRank === undefined) {
35459
+ return right;
35460
+ }
35461
+ return leftRank >= rightRank ? left : right;
35462
+ }
35463
+ static numericRank(type) {
35464
+ if (type instanceof basic_1.DecFloat34Type) {
35465
+ return 6;
35466
+ }
35467
+ else if (type instanceof basic_1.DecFloat16Type) {
35468
+ return 5;
35469
+ }
35470
+ else if (type instanceof basic_1.FloatType) {
35471
+ return 4;
35472
+ }
35473
+ else if (type instanceof basic_1.PackedType) {
35474
+ return 3;
35475
+ }
35476
+ else if (type instanceof basic_1.Integer8Type) {
35477
+ return 2;
35478
+ }
35479
+ else if (type instanceof basic_1.IntegerType) {
35480
+ return 1;
35481
+ }
35482
+ return undefined;
35483
+ }
35400
35484
  static addIfInferred(node, input, inferredType) {
35401
35485
  const basic = new basic_types_1.BasicTypes(input);
35402
35486
  const typeExpression = node.findDirectExpression(Expressions.TypeNameOrInfer);
@@ -71048,7 +71132,7 @@ class Registry {
71048
71132
  }
71049
71133
  static abaplintVersion() {
71050
71134
  // magic, see build script "version.js"
71051
- return "2.120.52";
71135
+ return "2.120.54";
71052
71136
  }
71053
71137
  getDDICReferences() {
71054
71138
  return this.ddicReferences;
@@ -78508,7 +78592,11 @@ Make sure to test the downported code, it might not always be completely correct
78508
78592
  return found;
78509
78593
  }
78510
78594
  */
78511
- let found = this.downportEnum(low, high, lowFile, highSyntax, highFile);
78595
+ let found = this.stripCallTransactionAuthorityCheck(high, lowFile);
78596
+ if (found) {
78597
+ return found;
78598
+ }
78599
+ found = this.downportEnum(low, high, lowFile, highSyntax, highFile);
78512
78600
  if (found) {
78513
78601
  return found;
78514
78602
  }
@@ -81002,6 +81090,27 @@ ${indentation} output = ${uniqueName}.\n`;
81002
81090
  }
81003
81091
  return false;
81004
81092
  }
81093
+ /** WITH/WITHOUT AUTHORITY-CHECK on CALL TRANSACTION requires v740sp02, so the statement is
81094
+ * Unknown in the low version, note that only WITHOUT is handled here */
81095
+ stripCallTransactionAuthorityCheck(high, lowFile) {
81096
+ if (!(high.get() instanceof Statements.CallTransaction)) {
81097
+ return undefined;
81098
+ }
81099
+ const tokens = high.getTokens();
81100
+ // the lexer splits "AUTHORITY-CHECK" into three tokens: AUTHORITY, -, CHECK
81101
+ for (let i = 1; i < tokens.length - 3; i++) {
81102
+ if (tokens[i].getStr().toUpperCase() === "WITHOUT"
81103
+ && tokens[i + 1].getStr().toUpperCase() === "AUTHORITY"
81104
+ && tokens[i + 2].getStr() === "-"
81105
+ && tokens[i + 3].getStr().toUpperCase() === "CHECK") {
81106
+ // also remove the preceding space so no double space is left behind
81107
+ const fix = edit_helper_1.EditHelper.deleteRange(lowFile, tokens[i - 1].getEnd(), tokens[i + 3].getEnd());
81108
+ const message = "Remove WITHOUT AUTHORITY-CHECK from CALL TRANSACTION";
81109
+ return issue_1.Issue.atToken(lowFile, tokens[i], message, this.getMetadata().key, this.conf.severity, fix);
81110
+ }
81111
+ }
81112
+ return undefined;
81113
+ }
81005
81114
  replaceXsdBool(node, lowFile, highSyntax) {
81006
81115
  if (this.lowReg.getConfig().isOpenABAP()) {
81007
81116
  return undefined;
@@ -84655,6 +84764,11 @@ class ImplementMethods extends _abap_rule_1.ABAPRule {
84655
84764
  return [idef];
84656
84765
  }
84657
84766
  for (const m of this.findInterfaceMethods(idef)) {
84767
+ if (m.method.isDefaultIgnore === true || m.method.isDefaultFail === true) {
84768
+ // the interface says an implementation is optional, so asking for one
84769
+ // reports an error where ABAP reports none
84770
+ continue;
84771
+ }
84658
84772
  if (this.isAbstract(m, interfaceInfo, def)) {
84659
84773
  if (def.isAbstract) {
84660
84774
  continue;
@@ -85406,6 +85520,7 @@ __exportStar(__webpack_require__(/*! ./parser_missing_space */ "./node_modules/@
85406
85520
  __exportStar(__webpack_require__(/*! ./pragma_style */ "./node_modules/@abaplint/core/build/src/rules/pragma_style.js"), exports);
85407
85521
  __exportStar(__webpack_require__(/*! ./prefer_corresponding */ "./node_modules/@abaplint/core/build/src/rules/prefer_corresponding.js"), exports);
85408
85522
  __exportStar(__webpack_require__(/*! ./prefer_inline */ "./node_modules/@abaplint/core/build/src/rules/prefer_inline.js"), exports);
85523
+ __exportStar(__webpack_require__(/*! ./prefer_insert_into_table */ "./node_modules/@abaplint/core/build/src/rules/prefer_insert_into_table.js"), exports);
85409
85524
  __exportStar(__webpack_require__(/*! ./prefer_is_not */ "./node_modules/@abaplint/core/build/src/rules/prefer_is_not.js"), exports);
85410
85525
  __exportStar(__webpack_require__(/*! ./prefer_pragmas */ "./node_modules/@abaplint/core/build/src/rules/prefer_pragmas.js"), exports);
85411
85526
  __exportStar(__webpack_require__(/*! ./prefer_raise_exception_new */ "./node_modules/@abaplint/core/build/src/rules/prefer_raise_exception_new.js"), exports);
@@ -93085,6 +93200,127 @@ exports.PreferInline = PreferInline;
93085
93200
 
93086
93201
  /***/ },
93087
93202
 
93203
+ /***/ "./node_modules/@abaplint/core/build/src/rules/prefer_insert_into_table.js"
93204
+ /*!*********************************************************************************!*\
93205
+ !*** ./node_modules/@abaplint/core/build/src/rules/prefer_insert_into_table.js ***!
93206
+ \*********************************************************************************/
93207
+ (__unused_webpack_module, exports, __webpack_require__) {
93208
+
93209
+ "use strict";
93210
+
93211
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
93212
+ if (k2 === undefined) k2 = k;
93213
+ var desc = Object.getOwnPropertyDescriptor(m, k);
93214
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
93215
+ desc = { enumerable: true, get: function() { return m[k]; } };
93216
+ }
93217
+ Object.defineProperty(o, k2, desc);
93218
+ }) : (function(o, m, k, k2) {
93219
+ if (k2 === undefined) k2 = k;
93220
+ o[k2] = m[k];
93221
+ }));
93222
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
93223
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
93224
+ }) : function(o, v) {
93225
+ o["default"] = v;
93226
+ });
93227
+ var __importStar = (this && this.__importStar) || (function () {
93228
+ var ownKeys = function(o) {
93229
+ ownKeys = Object.getOwnPropertyNames || function (o) {
93230
+ var ar = [];
93231
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
93232
+ return ar;
93233
+ };
93234
+ return ownKeys(o);
93235
+ };
93236
+ return function (mod) {
93237
+ if (mod && mod.__esModule) return mod;
93238
+ var result = {};
93239
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
93240
+ __setModuleDefault(result, mod);
93241
+ return result;
93242
+ };
93243
+ })();
93244
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
93245
+ exports.PreferInsertIntoTable = exports.PreferInsertIntoTableConf = void 0;
93246
+ const issue_1 = __webpack_require__(/*! ../issue */ "./node_modules/@abaplint/core/build/src/issue.js");
93247
+ const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
93248
+ const _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ "./node_modules/@abaplint/core/build/src/rules/_abap_rule.js");
93249
+ const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js");
93250
+ const _irule_1 = __webpack_require__(/*! ./_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
93251
+ const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
93252
+ class PreferInsertIntoTableConf extends _basic_rule_config_1.BasicRuleConfig {
93253
+ }
93254
+ exports.PreferInsertIntoTableConf = PreferInsertIntoTableConf;
93255
+ class PreferInsertIntoTable extends _abap_rule_1.ABAPRule {
93256
+ constructor() {
93257
+ super(...arguments);
93258
+ this.conf = new PreferInsertIntoTableConf();
93259
+ }
93260
+ getMetadata() {
93261
+ return {
93262
+ key: "prefer_insert_into_table",
93263
+ title: "Prefer INSERT INTO TABLE over APPEND",
93264
+ shortDescription: `Prefer INSERT INTO TABLE over APPEND`,
93265
+ extendedInformation: `INSERT INTO TABLE respects the table type, while APPEND always adds to the end regardless of table type.
93266
+
93267
+ https://github.com/SAP/styleguides/blob/main/clean-abap/CleanABAP.md`,
93268
+ tags: [_irule_1.RuleTag.SingleFile, _irule_1.RuleTag.Styleguide, _irule_1.RuleTag.Quickfix],
93269
+ badExample: `APPEND row TO itab.`,
93270
+ goodExample: `INSERT row INTO TABLE itab.`,
93271
+ };
93272
+ }
93273
+ getConfig() { return this.conf; }
93274
+ setConfig(conf) { this.conf = conf; }
93275
+ runParsed(file) {
93276
+ const issues = [];
93277
+ for (const stat of file.getStatements()) {
93278
+ if (!(stat.get() instanceof Statements.Append)) {
93279
+ continue;
93280
+ }
93281
+ if (stat.concatTokens().toUpperCase().includes(" SORTED BY ")) {
93282
+ continue;
93283
+ }
93284
+ const fix = this.buildFix(file, stat);
93285
+ const message = "Prefer INSERT INTO TABLE over APPEND";
93286
+ issues.push(issue_1.Issue.atStatement(file, stat, message, this.getMetadata().key, this.conf.severity, fix));
93287
+ }
93288
+ return issues;
93289
+ }
93290
+ buildFix(file, stat) {
93291
+ const tokens = stat.getTokens();
93292
+ // Find the APPEND token (first token)
93293
+ const appendToken = tokens[0];
93294
+ if (appendToken.getStr().toUpperCase() !== "APPEND") {
93295
+ return undefined;
93296
+ }
93297
+ // Find the last "TO" token that precedes the table target.
93298
+ // In all fixable forms the table target follows the last standalone "TO":
93299
+ // APPEND row TO itab
93300
+ // APPEND LINES OF itab2 TO itab
93301
+ // APPEND LINES OF itab2 FROM 1 TO 3 TO itab <- last TO is the table
93302
+ // APPEND INITIAL LINE TO itab
93303
+ let lastToIndex = -1;
93304
+ for (let i = tokens.length - 1; i >= 0; i--) {
93305
+ if (tokens[i].getStr().toUpperCase() === "TO") {
93306
+ lastToIndex = i;
93307
+ break;
93308
+ }
93309
+ }
93310
+ if (lastToIndex < 0) {
93311
+ return undefined;
93312
+ }
93313
+ const toToken = tokens[lastToIndex];
93314
+ const fix1 = edit_helper_1.EditHelper.replaceToken(file, appendToken, "INSERT");
93315
+ const fix2 = edit_helper_1.EditHelper.replaceToken(file, toToken, "INTO TABLE");
93316
+ return edit_helper_1.EditHelper.merge(fix1, fix2);
93317
+ }
93318
+ }
93319
+ exports.PreferInsertIntoTable = PreferInsertIntoTable;
93320
+ //# sourceMappingURL=prefer_insert_into_table.js.map
93321
+
93322
+ /***/ },
93323
+
93088
93324
  /***/ "./node_modules/@abaplint/core/build/src/rules/prefer_is_not.js"
93089
93325
  /*!**********************************************************************!*\
93090
93326
  !*** ./node_modules/@abaplint/core/build/src/rules/prefer_is_not.js ***!
@@ -103285,12 +103521,48 @@ exports.DatabaseSetup = DatabaseSetup;
103285
103521
  /*!***************************************************************************!*\
103286
103522
  !*** ./node_modules/@abaplint/transpiler/build/src/db/populate_tables.js ***!
103287
103523
  \***************************************************************************/
103288
- (__unused_webpack_module, exports) {
103524
+ (__unused_webpack_module, exports, __webpack_require__) {
103289
103525
 
103290
103526
  "use strict";
103291
103527
 
103528
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
103529
+ if (k2 === undefined) k2 = k;
103530
+ var desc = Object.getOwnPropertyDescriptor(m, k);
103531
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
103532
+ desc = { enumerable: true, get: function() { return m[k]; } };
103533
+ }
103534
+ Object.defineProperty(o, k2, desc);
103535
+ }) : (function(o, m, k, k2) {
103536
+ if (k2 === undefined) k2 = k;
103537
+ o[k2] = m[k];
103538
+ }));
103539
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
103540
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
103541
+ }) : function(o, v) {
103542
+ o["default"] = v;
103543
+ });
103544
+ var __importStar = (this && this.__importStar) || (function () {
103545
+ var ownKeys = function(o) {
103546
+ ownKeys = Object.getOwnPropertyNames || function (o) {
103547
+ var ar = [];
103548
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
103549
+ return ar;
103550
+ };
103551
+ return ownKeys(o);
103552
+ };
103553
+ return function (mod) {
103554
+ if (mod && mod.__esModule) return mod;
103555
+ var result = {};
103556
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
103557
+ __setModuleDefault(result, mod);
103558
+ return result;
103559
+ };
103560
+ })();
103292
103561
  Object.defineProperty(exports, "__esModule", ({ value: true }));
103293
103562
  exports.PopulateTables = void 0;
103563
+ /* eslint-disable max-len */
103564
+ const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_modules/@abaplint/core/build/src/index.js"));
103565
+ const w3mi_name_1 = __webpack_require__(/*! ../w3mi_name */ "./node_modules/@abaplint/transpiler/build/src/w3mi_name.js");
103294
103566
  class PopulateTables {
103295
103567
  hasREPOSRC;
103296
103568
  hasSEOSUBCO;
@@ -103426,7 +103698,9 @@ class PopulateTables {
103426
103698
  return "";
103427
103699
  }
103428
103700
  const type = obj.getType().toUpperCase();
103429
- const name = obj.getName().toUpperCase();
103701
+ const name = obj instanceof abaplint.Objects.WebMIME
103702
+ ? (0, w3mi_name_1.w3miObjectName)(obj)
103703
+ : obj.getName().toUpperCase();
103430
103704
  return `INSERT INTO "tadir" ("pgmid", "object", "obj_name", "devclass", "korrnum", "srcsystem", "delflag", "genflag", "edtflag", "masterlang")
103431
103705
  VALUES ('R3TR', '${type}', '${this.escape(name)}', '$TMP', '', 'ABC', '', '', '', 'E');`;
103432
103706
  }
@@ -103435,7 +103709,7 @@ class PopulateTables {
103435
103709
  return [];
103436
103710
  }
103437
103711
  const ret = [];
103438
- const name = obj.getName().toUpperCase();
103712
+ const name = (0, w3mi_name_1.w3miObjectName)(obj);
103439
103713
  for (const [key, value] of Object.entries(obj.getParameters())) {
103440
103714
  ret.push(`INSERT INTO "wwwparams" ("relid", "objid", "name", "value") VALUES ('MI', '${name}', '${this.escape(key)}', '${this.escape(value)}');`);
103441
103715
  }
@@ -109920,6 +110194,7 @@ const traversal_1 = __webpack_require__(/*! ../traversal */ "./node_modules/@aba
109920
110194
  const requires_1 = __webpack_require__(/*! ../requires */ "./node_modules/@abaplint/transpiler/build/src/requires.js");
109921
110195
  const rearranger_1 = __webpack_require__(/*! ../rearranger */ "./node_modules/@abaplint/transpiler/build/src/rearranger.js");
109922
110196
  const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
110197
+ const initialization_1 = __webpack_require__(/*! ../initialization */ "./node_modules/@abaplint/transpiler/build/src/initialization.js");
109923
110198
  class HandleABAP {
109924
110199
  options;
109925
110200
  constructor(options) {
@@ -110024,10 +110299,10 @@ class HandleABAP {
110024
110299
  continue;
110025
110300
  }
110026
110301
  if (name) {
110027
- contents.appendString("const {" + traversal_1.Traversal.escapeNamespace(name) + "} = await import(\"./" + filename.replace(/#/g, "%23") + "\");\n");
110302
+ contents.appendString("const {" + traversal_1.Traversal.escapeNamespace(name) + "} = await import(\"./" + (0, initialization_1.escapeFilenameForImport)(filename) + "\");\n");
110028
110303
  }
110029
110304
  else {
110030
- contents.appendString("await import(\"./" + filename.replace(/#/g, "%23") + "\");\n");
110305
+ contents.appendString("await import(\"./" + (0, initialization_1.escapeFilenameForImport)(filename) + "\");\n");
110031
110306
  }
110032
110307
  }
110033
110308
  contents.appendChunk(output.chunk);
@@ -110638,6 +110913,7 @@ exports.HandleView = HandleView;
110638
110913
  Object.defineProperty(exports, "__esModule", ({ value: true }));
110639
110914
  exports.HandleW3MI = void 0;
110640
110915
  const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
110916
+ const w3mi_name_1 = __webpack_require__(/*! ../w3mi_name */ "./node_modules/@abaplint/transpiler/build/src/w3mi_name.js");
110641
110917
  class HandleW3MI {
110642
110918
  runObject(obj, _reg) {
110643
110919
  const filename = obj.getXMLFile()?.getFilename().replace(".xml", ".mjs").toLowerCase();
@@ -110646,7 +110922,7 @@ class HandleW3MI {
110646
110922
  }
110647
110923
  obj.parse();
110648
110924
  const dataFile = obj.getDataFile();
110649
- const chunk = new chunk_1.Chunk().appendString(`abap.W3MI["${obj.getName().toUpperCase()}"] = {
110925
+ const chunk = new chunk_1.Chunk().appendString(`abap.W3MI["${(0, w3mi_name_1.w3miObjectName)(obj)}"] = {
110650
110926
  "objectType": "W3MI",
110651
110927
  "filename": ${JSON.stringify(dataFile?.getFilename())},
110652
110928
  };`);
@@ -110896,12 +111172,24 @@ var __importStar = (this && this.__importStar) || (function () {
110896
111172
  Object.defineProperty(exports, "__esModule", ({ value: true }));
110897
111173
  exports.Initialization = void 0;
110898
111174
  exports.escapeNamespaceFilename = escapeNamespaceFilename;
111175
+ exports.escapeFilenameForImport = escapeFilenameForImport;
110899
111176
  const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_modules/@abaplint/core/build/src/index.js"));
110900
111177
  const handle_fugr_1 = __webpack_require__(/*! ./handlers/handle_fugr */ "./node_modules/@abaplint/transpiler/build/src/handlers/handle_fugr.js");
110901
111178
  function escapeNamespaceFilename(filename) {
110902
111179
  // ES modules are resolved and cached as URLs. This means that special characters must be
110903
111180
  // percent-encoded, such as # with %23 and ? with %3F.
110904
- return filename.replace(/\//g, "%23");
111181
+ //
111182
+ // The percent sign goes first, and the order is the whole point. A URL is
111183
+ // percent-decoded before it is resolved, so a file whose *name* contains a
111184
+ // percent has to carry it escaped or the decoding eats it: abapGit stores
111185
+ // ZO4D_06_PLASMA.PNG as zo4d_06_plasma%2epng, and "./zo4d_06_plasma%2epng.w3mi.mjs"
111186
+ // resolves to zo4d_06_plasma.png.w3mi.mjs, which is not there. Escaping the
111187
+ // percent after the slash would corrupt the %23 this function just wrote.
111188
+ return filename.replace(/%/g, "%25").replace(/\//g, "%23");
111189
+ }
111190
+ // The same rule for a name that already carries abapGit's # rather than a slash
111191
+ function escapeFilenameForImport(filename) {
111192
+ return filename.replace(/%/g, "%25").replace(/#/g, "%23");
110905
111193
  }
110906
111194
  class Initialization {
110907
111195
  script(reg, dbSetup, options, useImport, pluginOutputs) {
@@ -113780,11 +114068,39 @@ class CreateObjectTranspiler {
113780
114068
  ret += ` ${id} = abap.Classes[${internalName}.get().trimEnd()];\n`;
113781
114069
  ret += `}\n`;
113782
114070
  ret += `if (${id} === undefined) { throw new ${cx}; }\n`;
114071
+ // ...and it has to be compatible with the STATIC type of the target.
114072
+ // A system raises CX_SY_CREATE_OBJECT_ERROR for a class that is not,
114073
+ // before the constructor runs; without this the class was assigned to
114074
+ // the reference whatever it was, and the mismatch surfaced later as a
114075
+ // javascript TypeError on the first member access - which no CATCH
114076
+ // takes, so a caller that guards its dynamic CREATE OBJECT the way the
114077
+ // documentation asks for was not guarded at all
114078
+ const staticName = this.findTargetTypeName(node, traversal);
114079
+ if (staticName !== undefined) {
114080
+ const staticType = traversal.lookupClassOrInterface(staticName, node.getFirstToken());
114081
+ ret += `abap.statements.checkCreateObjectType(${id}, ${staticType}, "${staticName.toUpperCase()}");\n`;
114082
+ }
113783
114083
  clas = id;
113784
114084
  }
113785
114085
  ret += target + ".set(await (new " + clas + "()).constructor_(" + para + "));";
113786
114086
  return new chunk_1.Chunk(ret);
113787
114087
  }
114088
+ /** The name of the target reference's STATIC type, or undefined when there
114089
+ * is nothing to check against - a generic `REF TO object`, or a target this
114090
+ * cannot resolve (which is reported by findClassName on the static path and
114091
+ * must not turn a working dynamic CREATE OBJECT into a transpile error
114092
+ * here). */
114093
+ findTargetTypeName(node, traversal) {
114094
+ const scope = traversal.findCurrentScopeByToken(node.getFirstToken());
114095
+ if (scope === undefined) {
114096
+ return undefined;
114097
+ }
114098
+ const type = traversal.determineType(node, scope);
114099
+ if (type instanceof abaplint.BasicTypes.ObjectReferenceType) {
114100
+ return type.getIdentifierName();
114101
+ }
114102
+ return undefined;
114103
+ }
113788
114104
  findClassName(node, traversal) {
113789
114105
  const c = node.findDirectExpression(abaplint.Expressions.ClassName);
113790
114106
  if (c) {
@@ -124987,6 +125303,58 @@ exports.Validation = Validation;
124987
125303
 
124988
125304
  /***/ },
124989
125305
 
125306
+ /***/ "./node_modules/@abaplint/transpiler/build/src/w3mi_name.js"
125307
+ /*!******************************************************************!*\
125308
+ !*** ./node_modules/@abaplint/transpiler/build/src/w3mi_name.js ***!
125309
+ \******************************************************************/
125310
+ (__unused_webpack_module, exports) {
125311
+
125312
+ "use strict";
125313
+
125314
+ Object.defineProperty(exports, "__esModule", ({ value: true }));
125315
+ exports.w3miObjectName = w3miObjectName;
125316
+ /**
125317
+ * The name a system knows a Web Repository object by: `wwwdata-objid`.
125318
+ *
125319
+ * It is not the file name. abapGit percent-escapes the characters a file name
125320
+ * cannot hold, so `ZOISEE-EAR-02.MP3` is stored as `zoisee-ear-02%2emp3`, and
125321
+ * abaplint derives an object's name from the file it was read from. Keying
125322
+ * anything a caller sees on that spelling turns an abapGit storage detail into
125323
+ * an API: ABAP that asks `SELECT ... FROM wwwparams WHERE objid = 'X.MP3'`,
125324
+ * which is how the object is addressed on a system, then finds nothing.
125325
+ *
125326
+ * The real name is in the object's own XML, and abapGit puts it there from the
125327
+ * key itself — `io_xml->add( iv_name = 'NAME' ig_data = ms_key-objid )` in
125328
+ * `zcl_abapgit_object_w3xx_super`, in both serializer versions.
125329
+ */
125330
+ function w3miObjectName(obj) {
125331
+ const raw = obj.getXMLFile()?.getRaw();
125332
+ if (raw !== undefined) {
125333
+ // every entry of <PARAMS> carries a <NAME> of its own, so only the part
125334
+ // before the parameter list can be searched for the object's
125335
+ const head = raw.split(/<PARAMS[\s/>]/)[0];
125336
+ const found = /<NAME>([^<]*)<\/NAME>/.exec(head);
125337
+ const name = found === null ? "" : unescapeXML(found[1]).trim();
125338
+ if (name.length > 0) {
125339
+ return name.toUpperCase();
125340
+ }
125341
+ }
125342
+ // an object with no XML, or an XML from something that is not abapGit: the
125343
+ // file name is the only name there is, and a wrong key beats no key
125344
+ return obj.getName().toUpperCase();
125345
+ }
125346
+ function unescapeXML(value) {
125347
+ // a W3MI name may hold < and > and &, which reach the file escaped
125348
+ return value.replace(/&lt;/g, "<")
125349
+ .replace(/&gt;/g, ">")
125350
+ .replace(/&quot;/g, "\"")
125351
+ .replace(/&apos;/g, "'")
125352
+ .replace(/&amp;/g, "&");
125353
+ }
125354
+ //# sourceMappingURL=w3mi_name.js.map
125355
+
125356
+ /***/ },
125357
+
124990
125358
  /***/ "./node_modules/progress/index.js"
124991
125359
  /*!****************************************!*\
124992
125360
  !*** ./node_modules/progress/index.js ***!
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler-cli",
3
- "version": "2.13.87",
3
+ "version": "2.13.88",
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.52",
31
- "@abaplint/transpiler": "^2.13.87",
30
+ "@abaplint/core": "^2.120.54",
31
+ "@abaplint/transpiler": "^2.13.88",
32
32
  "@types/glob": "^9.0.0",
33
33
  "@types/node": "^26.4.1",
34
34
  "@types/progress": "^2.0.7",