@abaplint/transpiler-cli 2.14.12 → 2.14.13

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.
package/README.md CHANGED
@@ -98,6 +98,29 @@ The transpiler library retains flat output unless its caller supplies an output
98
98
  folder map as the third argument to `Transpiler.run()`. This layout is enabled
99
99
  automatically by the CLI.
100
100
 
101
+ ## Pinning a library
102
+
103
+ A library given by `url` is cloned when the CLI runs, so without more the
104
+ default branch of that moment is used and the same project commit can build
105
+ differently from one day to the next. Set `libs[].ref` to a commit SHA, a tag
106
+ or a branch to make the build reproducible:
107
+
108
+ ```json
109
+ {
110
+ "libs": [
111
+ {"url": "https://github.com/open-abap/open-abap-core", "ref": "239b817e6fd05e62854fed25663f002c60dda07c"},
112
+ {"url": "https://github.com/example/utilities", "ref": "v1.2.0"}
113
+ ]
114
+ }
115
+ ```
116
+
117
+ A branch or tag is cloned shallow. A commit is fetched shallow by name; when
118
+ the server does not serve that, or the SHA is abbreviated, the full history is
119
+ fetched and the commit checked out from it. The CLI prints the commit of every
120
+ library it clones, and of every `folder` library that is a git checkout, as
121
+ `commit: <sha>` next to the file count, so the commits of a build can be
122
+ recorded.
123
+
101
124
  ## Duplicate dependencies
102
125
 
103
126
  By default, two libraries defining the same ABAP object (type and name) cause
package/build/bundle.js CHANGED
@@ -257,14 +257,101 @@ exports.FileOperations = FileOperations;
257
257
  /*!****************************!*\
258
258
  !*** ./build/git_clone.js ***!
259
259
  \****************************/
260
- (__unused_webpack_module, exports) {
260
+ (__unused_webpack_module, exports, __webpack_require__) {
261
261
 
262
262
  "use strict";
263
263
 
264
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
265
+ if (k2 === undefined) k2 = k;
266
+ var desc = Object.getOwnPropertyDescriptor(m, k);
267
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
268
+ desc = { enumerable: true, get: function() { return m[k]; } };
269
+ }
270
+ Object.defineProperty(o, k2, desc);
271
+ }) : (function(o, m, k, k2) {
272
+ if (k2 === undefined) k2 = k;
273
+ o[k2] = m[k];
274
+ }));
275
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
276
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
277
+ }) : function(o, v) {
278
+ o["default"] = v;
279
+ });
280
+ var __importStar = (this && this.__importStar) || (function () {
281
+ var ownKeys = function(o) {
282
+ ownKeys = Object.getOwnPropertyNames || function (o) {
283
+ var ar = [];
284
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
285
+ return ar;
286
+ };
287
+ return ownKeys(o);
288
+ };
289
+ return function (mod) {
290
+ if (mod && mod.__esModule) return mod;
291
+ var result = {};
292
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
293
+ __setModuleDefault(result, mod);
294
+ return result;
295
+ };
296
+ })();
264
297
  Object.defineProperty(exports, "__esModule", ({ value: true }));
298
+ exports.isCommitSha = isCommitSha;
265
299
  exports.buildGitCloneArguments = buildGitCloneArguments;
266
- function buildGitCloneArguments(url) {
267
- return ["clone", "--quiet", "--depth", "1", "--", url, "."];
300
+ exports.cloneRepository = cloneRepository;
301
+ exports.resolveHead = resolveHead;
302
+ const childProcess = __importStar(__webpack_require__(/*! child_process */ "child_process"));
303
+ /** a full or abbreviated commit SHA, as opposed to a branch or tag name */
304
+ function isCommitSha(ref) {
305
+ return /^[0-9a-f]{7,40}$/i.test(ref);
306
+ }
307
+ /** shallow clone of the default branch, or of the branch or tag `ref` */
308
+ function buildGitCloneArguments(url, ref) {
309
+ const branch = ref === undefined || ref === "" ? [] : ["--branch", ref];
310
+ return ["clone", "--quiet", "--depth", "1", ...branch, "--", url, "."];
311
+ }
312
+ function git(args, cwd, stderr = "inherit") {
313
+ childProcess.execFileSync("git", args, { cwd, stdio: ["ignore", "inherit", stderr] });
314
+ }
315
+ /** Clones `url` into the empty directory `dir` and returns the commit checked out.
316
+ *
317
+ * Without `ref` this is a shallow clone of the default branch. A branch or tag
318
+ * is cloned shallow with --branch. A commit SHA is fetched shallow by name,
319
+ * which GitHub and every server with uploadpack.allowReachableSHA1InWant
320
+ * serve; when the server refuses that, or the SHA is abbreviated, the full
321
+ * history is fetched and the commit checked out from it. */
322
+ function cloneRepository(url, dir, ref) {
323
+ if (ref === undefined || ref === "") {
324
+ git(buildGitCloneArguments(url), dir);
325
+ }
326
+ else if (ref.startsWith("-")) {
327
+ throw new Error("Invalid lib ref: " + JSON.stringify(ref));
328
+ }
329
+ else if (isCommitSha(ref)) {
330
+ git(["init", "--quiet"], dir);
331
+ git(["remote", "add", "origin", "--", url], dir);
332
+ try {
333
+ git(["fetch", "--quiet", "--depth", "1", "origin", ref], dir, "pipe");
334
+ git(["checkout", "--quiet", "--detach", "FETCH_HEAD"], dir);
335
+ }
336
+ catch {
337
+ console.log("\tshallow fetch of " + ref + " not served, fetching the full history");
338
+ git(["fetch", "--quiet", "--tags", "origin"], dir);
339
+ git(["checkout", "--quiet", "--detach", ref], dir);
340
+ }
341
+ }
342
+ else {
343
+ git(buildGitCloneArguments(url, ref), dir);
344
+ }
345
+ return resolveHead(dir);
346
+ }
347
+ /** the commit checked out in `dir`, undefined when it is not a git checkout */
348
+ function resolveHead(dir) {
349
+ try {
350
+ return childProcess.execFileSync("git", ["rev-parse", "HEAD"], { cwd: dir, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
351
+ }
352
+ catch {
353
+ return undefined;
354
+ }
268
355
  }
269
356
  //# sourceMappingURL=git_clone.js.map
270
357
 
@@ -485,7 +572,6 @@ exports.loadLibraries = loadLibraries;
485
572
  exports.libraryRegistry = libraryRegistry;
486
573
  const fs = __importStar(__webpack_require__(/*! fs */ "fs"));
487
574
  const path = __importStar(__webpack_require__(/*! path */ "path"));
488
- const childProcess = __importStar(__webpack_require__(/*! child_process */ "child_process"));
489
575
  const os = __importStar(__webpack_require__(/*! os */ "os"));
490
576
  const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_modules/@abaplint/core/build/src/index.js"));
491
577
  const file_operations_1 = __webpack_require__(/*! ./file_operations */ "./build/file_operations.js");
@@ -533,13 +619,14 @@ async function loadLibraries(config) {
533
619
  ? "Library must define a non-empty url or an existing folder"
534
620
  : "Library folder not found: " + folder);
535
621
  }
536
- console.log("Clone: " + lib.url);
622
+ console.log("Clone: " + lib.url + (lib.ref ? " at " + lib.ref : ""));
537
623
  dir = fs.mkdtempSync(path.join(os.tmpdir(), "abap_transpile-"));
538
624
  cleanupFolder = true;
539
625
  }
540
626
  try {
541
- if (cleanupFolder) {
542
- childProcess.execFileSync("git", (0, git_clone_1.buildGitCloneArguments)(lib.url), { cwd: dir, stdio: "inherit" });
627
+ const commit = cleanupFolder ? (0, git_clone_1.cloneRepository)(lib.url, dir, lib.ref) : (0, git_clone_1.resolveHead)(dir);
628
+ if (commit !== undefined) {
629
+ console.log("\tcommit: " + commit);
543
630
  }
544
631
  const patterns = typeof lib.files === "string" && lib.files !== "" ? [lib.files]
545
632
  : Array.isArray(lib.files) ? lib.files : ["/src/**"];
@@ -6282,10 +6369,15 @@ class FormParamType extends combi_1.Expression {
6282
6369
  getRunnable() {
6283
6370
  const def = (0, combi_1.seq)("DEFAULT", (0, combi_1.alt)(_1.Constant, _1.FieldChain));
6284
6371
  const table = (0, combi_1.seq)((0, combi_1.alt)("STANDARD", "HASHED", "INDEX", "SORTED", "ANY"), "TABLE");
6285
- const tabseq = (0, combi_1.seq)(table, (0, combi_1.optPrio)((0, combi_1.seq)("OF", _1.TypeName)));
6286
- const ret = (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.alt)("REF TO", "LINE OF")), _1.TypeName, (0, combi_1.opt)(def));
6287
- const like = (0, combi_1.seq)("LIKE", (0, combi_1.optPrio)((0, combi_1.alt)("REF TO", "LINE OF")), _1.FieldChain);
6288
- return (0, combi_1.alt)((0, combi_1.seq)("TYPE", (0, combi_1.altPrio)(tabseq, (0, combi_1.ver)(version_1.Release.v916, (0, combi_1.seq)("ANY", "STRUCTURE")), ret)), like);
6372
+ // the following are not valid FORM typings, fail instead of reading the
6373
+ // remaining words as additional parameters
6374
+ const inline = (0, combi_1.seq)((0, combi_1.alt)("TABLE", "RANGE"), "OF", (0, combi_1.failCombinator)());
6375
+ const tableKey = (0, combi_1.seq)("WITH", (0, combi_1.failCombinator)());
6376
+ const lengthDecimals = (0, combi_1.seq)((0, combi_1.alt)("LENGTH", "DECIMALS"), _1.Integer, (0, combi_1.failCombinator)());
6377
+ const tabseq = (0, combi_1.seq)(table, (0, combi_1.optPrio)((0, combi_1.seq)("OF", (0, combi_1.altPrio)((0, combi_1.seq)("REF TO", (0, combi_1.failCombinator)()), _1.TypeName))), (0, combi_1.optPrio)(tableKey));
6378
+ const ret = (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.alt)("REF TO", "LINE OF")), _1.TypeName, (0, combi_1.optPrio)(lengthDecimals), (0, combi_1.opt)(def));
6379
+ const like = (0, combi_1.seq)("LIKE", (0, combi_1.altPrio)(inline, (0, combi_1.seq)(table, (0, combi_1.failCombinator)()), (0, combi_1.seq)((0, combi_1.optPrio)((0, combi_1.alt)("REF TO", "LINE OF")), _1.FieldChain)));
6380
+ return (0, combi_1.alt)((0, combi_1.seq)("TYPE", (0, combi_1.altPrio)(tabseq, (0, combi_1.ver)(version_1.Release.v916, (0, combi_1.seq)("ANY", "STRUCTURE")), inline, ret)), like);
6289
6381
  }
6290
6382
  }
6291
6383
  exports.FormParamType = FormParamType;
@@ -29558,6 +29650,15 @@ class TypeUtils {
29558
29650
  }
29559
29651
  return this.isAssignable(source, target);
29560
29652
  }
29653
+ // character-like arguments of built-in functions must be elementary, flat character-like structures are not allowed
29654
+ isAssignableBuiltin(source, target, node) {
29655
+ if (target instanceof basic_1.CLikeType
29656
+ && (source instanceof basic_1.StructureType
29657
+ || (source instanceof basic_1.TableType && source.isWithHeader() && source.getRowType() instanceof basic_1.StructureType))) {
29658
+ return false;
29659
+ }
29660
+ return this.isAssignableStrict(source, target, node);
29661
+ }
29561
29662
  // Typing with the classic STRUCTURE addition, ie. "FORM foo USING bar STRUCTURE zkey",
29562
29663
  // is not a compatibility check: ABAP only checks the fragment view up to the end of the
29563
29664
  // formal structure, so the actual parameter is allowed to be longer. For TABLES parameters
@@ -34847,6 +34948,7 @@ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modu
34847
34948
  const constant_1 = __webpack_require__(/*! ./constant */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/constant.js");
34848
34949
  const _check_offset_length_1 = __webpack_require__(/*! ./_check_offset_length */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js");
34849
34950
  const _check_text_symbol_1 = __webpack_require__(/*! ./_check_text_symbol */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_text_symbol.js");
34951
+ const _builtin_1 = __webpack_require__(/*! ../_builtin */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js");
34850
34952
  class MethodCallParam {
34851
34953
  /** returns the type of the unnamed argument, if any */
34852
34954
  static runSyntax(node, input, method) {
@@ -34923,7 +35025,7 @@ class MethodCallParam {
34923
35025
  else if ((0, _check_text_symbol_1.checkTextSymbol)(child, targetType, input)) {
34924
35026
  return;
34925
35027
  }
34926
- else if (new _type_utils_1.TypeUtils(input.scope).isAssignableStrict(sourceType, targetType, child) === false) {
35028
+ else if (this.isAssignable(sourceType, targetType, child, method, input) === false) {
34927
35029
  const message = "Method parameter type not compatible";
34928
35030
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
34929
35031
  return;
@@ -34943,6 +35045,12 @@ class MethodCallParam {
34943
35045
  }
34944
35046
  return undefined;
34945
35047
  }
35048
+ static isAssignable(sourceType, targetType, child, method, input) {
35049
+ const typeUtils = new _type_utils_1.TypeUtils(input.scope);
35050
+ return method instanceof _builtin_1.BuiltInMethod
35051
+ ? typeUtils.isAssignableBuiltin(sourceType, targetType, child)
35052
+ : typeUtils.isAssignableStrict(sourceType, targetType, child);
35053
+ }
34946
35054
  }
34947
35055
  exports.MethodCallParam = MethodCallParam;
34948
35056
  //# sourceMappingURL=method_call_param.js.map
@@ -35180,6 +35288,7 @@ const field_chain_1 = __webpack_require__(/*! ./field_chain */ "./node_modules/@
35180
35288
  const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
35181
35289
  const _check_offset_length_1 = __webpack_require__(/*! ./_check_offset_length */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_offset_length.js");
35182
35290
  const _check_text_symbol_1 = __webpack_require__(/*! ./_check_text_symbol */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/_check_text_symbol.js");
35291
+ const _builtin_1 = __webpack_require__(/*! ../_builtin */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js");
35183
35292
  function normalizeParameterName(name) {
35184
35293
  return name.replace(/^!/, "").toUpperCase();
35185
35294
  }
@@ -35327,6 +35436,10 @@ class MethodParameters {
35327
35436
  if (this.requiredParameters === undefined) {
35328
35437
  this.requiredParameters = new Set(method.getParameters().getRequiredParameters().map(i => i.getName().toUpperCase()));
35329
35438
  }
35439
+ const typeUtils = new _type_utils_1.TypeUtils(input.scope);
35440
+ const assignable = method instanceof _builtin_1.BuiltInMethod
35441
+ ? typeUtils.isAssignableBuiltin.bind(typeUtils)
35442
+ : typeUtils.isAssignableStrict.bind(typeUtils);
35330
35443
  for (const item of items) {
35331
35444
  const parameter = allImporting.find(p => p.getName().toUpperCase() === item.name);
35332
35445
  if (parameter === undefined) {
@@ -35337,7 +35450,7 @@ class MethodParameters {
35337
35450
  else if ((0, _check_text_symbol_1.checkTextSymbol)(item.source, parameter.getType(), input)) {
35338
35451
  return;
35339
35452
  }
35340
- else if (new _type_utils_1.TypeUtils(input.scope).isAssignableStrict(item.sourceType, parameter.getType(), item.source) === false) {
35453
+ else if (assignable(item.sourceType, parameter.getType(), item.source) === false) {
35341
35454
  const message = "Method parameter type not compatible, " + item.name;
35342
35455
  input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
35343
35456
  return;
@@ -57740,7 +57853,7 @@ const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "./node_modules/@
57740
57853
  const ddic_1 = __webpack_require__(/*! ../ddic */ "./node_modules/@abaplint/core/build/src/ddic.js");
57741
57854
  class CDSDetermineTypes {
57742
57855
  parseType(reg, parsedData, ddlsName) {
57743
- var _a;
57856
+ var _a, _b;
57744
57857
  const ddic = new ddic_1.DDIC(reg);
57745
57858
  if ((parsedData === null || parsedData === void 0 ? void 0 : parsedData.fields.length) === 0) {
57746
57859
  return basic_1.VoidType.get("DDLS:todo");
@@ -57819,13 +57932,29 @@ class CDSDetermineTypes {
57819
57932
  else {
57820
57933
  components.push({
57821
57934
  name: f.name,
57822
- type: basic_1.VoidType.get("DDLS:fieldname:" + ddlsName),
57935
+ type: (_b = this.findInSources(ddic, parsedData, f.nameInSource)) !== null && _b !== void 0 ? _b : basic_1.VoidType.get("DDLS:fieldname:" + ddlsName),
57823
57936
  });
57824
57937
  }
57825
57938
  }
57826
57939
  return new basic_1.StructureType(components, parsedData.definitionName, parsedData.definitionName, parsedData.description);
57827
57940
  }
57828
57941
  }
57942
+ /** unprefixed field, take the type from the first source containing it, void or unknown sources are skipped */
57943
+ findInSources(ddic, parsedData, nameInSource) {
57944
+ if (nameInSource === undefined) {
57945
+ return undefined;
57946
+ }
57947
+ for (const source of parsedData.sources) {
57948
+ const lookup = ddic.lookupTableOrView(source.name);
57949
+ if (lookup.type instanceof basic_1.StructureType) {
57950
+ const type = lookup.type.getComponentByName(nameInSource);
57951
+ if (type) {
57952
+ return type;
57953
+ }
57954
+ }
57955
+ }
57956
+ return undefined;
57957
+ }
57829
57958
  }
57830
57959
  exports.CDSDetermineTypes = CDSDetermineTypes;
57831
57960
  //# sourceMappingURL=cds_determine_types.js.map
@@ -61388,8 +61517,8 @@ var __importStar = (this && this.__importStar) || (function () {
61388
61517
  };
61389
61518
  })();
61390
61519
  Object.defineProperty(exports, "__esModule", ({ value: true }));
61391
- exports.ABAPObject = exports.Tokens = exports.ExpressionsCDS = exports.CDSParser = exports.LanguageServerTypes = exports.DDLKind = exports.DDLParser = exports.AbstractFile = exports.ABAPFile = exports.MemoryFile = exports.Edits = exports.ReferenceType = exports.NativeSQL = exports.MacroContent = exports.MacroCall = exports.SpaghettiScopeNode = exports.Token = exports.ScopeType = exports.BasicTypes = exports.TypedIdentifier = exports.AbstractType = exports.VirtualPosition = exports.Comment = exports.Unknown = exports.Empty = exports.Identifier = exports.Nodes = exports.Types = exports.Expressions = exports.Statements = exports.Structures = exports.SkipLogic = exports.Objects = exports.ArtifactsRules = exports.ArtifactsObjects = exports.ArtifactsABAP = exports.BuiltIn = exports.FormLengthStats = exports.FunctionLengthStats = exports.MethodLengthStats = exports.LanguageServer = exports.Registry = exports.CyclomaticComplexityStats = exports.versionToABAPRelease = exports.releaseAtLeast = exports.Release = exports.LanguageVersion = exports.Version = exports.Config = exports.Issue = void 0;
61392
- exports.LSPEdit = exports.RuleTag = exports.Severity = exports.Visibility = exports.Info = exports.Diagnostics = exports.Rename = exports.PrettyPrinter = exports.Position = exports.CurrentScope = exports.RulesRunner = exports.SpaghettiScope = exports.SyntaxLogic = void 0;
61520
+ exports.Tokens = exports.ABAPParser = exports.ExpressionsCDS = exports.CDSParser = exports.LanguageServerTypes = exports.DDLKind = exports.DDLParser = exports.AbstractFile = exports.ABAPFile = exports.MemoryFile = exports.Edits = exports.ReferenceType = exports.NativeSQL = exports.MacroContent = exports.MacroCall = exports.SpaghettiScopeNode = exports.Token = exports.ScopeType = exports.BasicTypes = exports.TypedIdentifier = exports.AbstractType = exports.VirtualPosition = exports.Comment = exports.Unknown = exports.Empty = exports.Identifier = exports.Nodes = exports.Types = exports.Expressions = exports.Statements = exports.Structures = exports.SkipLogic = exports.Objects = exports.ArtifactsRules = exports.ArtifactsObjects = exports.ArtifactsABAP = exports.BuiltIn = exports.FormLengthStats = exports.FunctionLengthStats = exports.MethodLengthStats = exports.LanguageServer = exports.Registry = exports.CyclomaticComplexityStats = exports.versionToABAPRelease = exports.releaseAtLeast = exports.Release = exports.LanguageVersion = exports.Version = exports.Config = exports.Issue = void 0;
61521
+ exports.LSPEdit = exports.RuleTag = exports.Severity = exports.Visibility = exports.Info = exports.Diagnostics = exports.Rename = exports.PrettyPrinter = exports.Position = exports.CurrentScope = exports.RulesRunner = exports.SpaghettiScope = exports.SyntaxLogic = exports.ABAPObject = void 0;
61393
61522
  const issue_1 = __webpack_require__(/*! ./issue */ "./node_modules/@abaplint/core/build/src/issue.js");
61394
61523
  Object.defineProperty(exports, "Issue", { enumerable: true, get: function () { return issue_1.Issue; } });
61395
61524
  const config_1 = __webpack_require__(/*! ./config */ "./node_modules/@abaplint/core/build/src/config.js");
@@ -61486,6 +61615,8 @@ Object.defineProperty(exports, "DDLParser", { enumerable: true, get: function ()
61486
61615
  Object.defineProperty(exports, "DDLKind", { enumerable: true, get: function () { return ddl_parser_1.DDLKind; } });
61487
61616
  const cds_parser_1 = __webpack_require__(/*! ./cds/cds_parser */ "./node_modules/@abaplint/core/build/src/cds/cds_parser.js");
61488
61617
  Object.defineProperty(exports, "CDSParser", { enumerable: true, get: function () { return cds_parser_1.CDSParser; } });
61618
+ const abap_parser_1 = __webpack_require__(/*! ./abap/abap_parser */ "./node_modules/@abaplint/core/build/src/abap/abap_parser.js");
61619
+ Object.defineProperty(exports, "ABAPParser", { enumerable: true, get: function () { return abap_parser_1.ABAPParser; } });
61489
61620
  const rules_runner_1 = __webpack_require__(/*! ./rules_runner */ "./node_modules/@abaplint/core/build/src/rules_runner.js");
61490
61621
  Object.defineProperty(exports, "RulesRunner", { enumerable: true, get: function () { return rules_runner_1.RulesRunner; } });
61491
61622
  const _irule_1 = __webpack_require__(/*! ./rules/_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
@@ -66538,12 +66669,16 @@ class DataDefinition extends _abstract_object_1.AbstractObject {
66538
66669
  let found = (_a = e.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
66539
66670
  const list = (_b = e.findDirectExpression(expressions_1.CDSPrefixedName)) === null || _b === void 0 ? void 0 : _b.findAllExpressions(expressions_1.CDSName);
66540
66671
  if (list !== undefined) {
66541
- const redirected = list.length > 1 && e.concatTokens().toUpperCase().includes(" REDIRECTED TO ");
66672
+ const redirected = e.concatTokens().toUpperCase().includes(" REDIRECTED TO ");
66542
66673
  if (list.length > 1 && redirected === false) {
66543
66674
  // "prefix.field" is looked up as "field" in "prefix", also when aliased via "as"
66544
66675
  prefix = list[0].concatTokens();
66545
66676
  nameInSource = list[list.length - 1].concatTokens();
66546
66677
  }
66678
+ else if (list.length === 1 && redirected === false) {
66679
+ // unprefixed "field" is looked up in the sources, also when aliased via "as"
66680
+ nameInSource = list[0].concatTokens();
66681
+ }
66547
66682
  if (found === undefined) {
66548
66683
  found = redirected === true ? list[0] : list[list.length - 1];
66549
66684
  }
@@ -73726,7 +73861,7 @@ class Registry {
73726
73861
  }
73727
73862
  static abaplintVersion() {
73728
73863
  // magic, see build script "version.js"
73729
- return "2.120.87";
73864
+ return "2.120.89";
73730
73865
  }
73731
73866
  getDDICReferences() {
73732
73867
  return this.ddicReferences;
@@ -85508,6 +85643,18 @@ Make sure to test the downported code, it might not always be completely correct
85508
85643
  }
85509
85644
  }
85510
85645
  }
85646
+ // a chained call with EXPORTING/IMPORTING/CHANGING/RECEIVING/EXCEPTIONS parses in the low
85647
+ // version, but 702 reads the last call of a chain as a functional call,
85648
+ // "Unexpected word CHANGING in functional method call"
85649
+ if (ret.length === 0) {
85650
+ for (let i = 0; i < lowStatements.length; i++) {
85651
+ const issue = this.outlineChainedCallParameters(lowStatements[i], highStatements[i], lowFile, highSyntax);
85652
+ if (issue) {
85653
+ ret.push(issue);
85654
+ break;
85655
+ }
85656
+ }
85657
+ }
85511
85658
  // INSERT with a 702 built-in function as the operand parses in the low version, but 702
85512
85659
  // reads the function as a method call, "Method SUBSTRING does not exist"
85513
85660
  if (ret.length === 0) {
@@ -88089,6 +88236,67 @@ ${indentation} output = ${uniqueName}.\n`;
88089
88236
  }
88090
88237
  return undefined;
88091
88238
  }
88239
+ /** a( )->b( CHANGING c = d ), the object the last method is called on is outlined into a
88240
+ * variable typed via the RETURNING parameter of the method before it */
88241
+ outlineChainedCallParameters(low, high, lowFile, highSyntax) {
88242
+ var _a, _b, _c, _d;
88243
+ if (!(high.get() instanceof Statements.Call)) {
88244
+ return undefined;
88245
+ }
88246
+ else if (this.lowReg.getConfig().isOpenABAP()) {
88247
+ return undefined;
88248
+ }
88249
+ else if (low.getFirstToken().getStart() instanceof virtual_position_1.VirtualPosition) {
88250
+ return undefined;
88251
+ }
88252
+ const chain = high.findDirectExpression(Expressions.MethodCallChain);
88253
+ const children = (chain === null || chain === void 0 ? void 0 : chain.getChildren()) || [];
88254
+ const last = children[children.length - 1];
88255
+ const arrow = children[children.length - 2];
88256
+ const previous = children[children.length - 3];
88257
+ if (chain === undefined
88258
+ || !(last instanceof nodes_1.ExpressionNode)
88259
+ || !(last.get() instanceof Expressions.MethodCall)
88260
+ || (arrow === null || arrow === void 0 ? void 0 : arrow.getFirstToken().getStr()) !== "->"
88261
+ || !(previous instanceof nodes_1.ExpressionNode)
88262
+ || !(previous.get() instanceof Expressions.MethodCall)) {
88263
+ return undefined;
88264
+ }
88265
+ const parameters = (_a = last.findDirectExpression(Expressions.MethodCallParam)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.MethodParameters);
88266
+ if (parameters === undefined) {
88267
+ return undefined;
88268
+ }
88269
+ // the type of the object, from the method that returns it
88270
+ const methodToken = (_b = previous.findDirectExpression(Expressions.MethodName)) === null || _b === void 0 ? void 0 : _b.getFirstToken();
88271
+ if (methodToken === undefined) {
88272
+ return undefined;
88273
+ }
88274
+ const spag = highSyntax.spaghetti.lookupPosition(methodToken.getStart(), lowFile.getFilename());
88275
+ let type = undefined;
88276
+ for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {
88277
+ if (r.referenceType === _reference_1.ReferenceType.MethodReference
88278
+ && r.position.getStart().equals(methodToken.getStart())) {
88279
+ const returning = (_d = (_c = r.resolved) === null || _c === void 0 ? void 0 : _c.getParameters().getReturning()) === null || _d === void 0 ? void 0 : _d.getType();
88280
+ if (returning instanceof basic_1.ObjectReferenceType) {
88281
+ type = returning.toABAP();
88282
+ }
88283
+ break;
88284
+ }
88285
+ }
88286
+ if (type === undefined) {
88287
+ return undefined;
88288
+ }
88289
+ const object = children.slice(0, children.length - 2).map(c => c.concatTokens()).join("");
88290
+ const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
88291
+ const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
88292
+ const code = `DATA ${uniqueName} TYPE ${type}.\n` +
88293
+ indentation + `${uniqueName} = ${object}.\n` +
88294
+ indentation;
88295
+ const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);
88296
+ const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, chain.getFirstToken().getStart(), previous.getLastToken().getEnd(), uniqueName);
88297
+ const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
88298
+ return issue_1.Issue.atToken(lowFile, chain.getFirstToken(), "Outline object of chained call with parameter keywords", this.getMetadata().key, this.conf.severity, fix);
88299
+ }
88092
88300
  /** if the source expression is the complete source of an INSERT or APPEND statement, then the
88093
88301
  * outlined variable must be typed via the row type of the table, returns the table name */
88094
88302
  findRowTypeOf(high, source) {
@@ -102915,7 +103123,7 @@ class PreferStringTemplate extends _abap_rule_1.ABAPRule {
102915
103123
  continue;
102916
103124
  }
102917
103125
  const operands = this.flattenChain(source);
102918
- if (!operands.some(op => { const c = op.getFirstToken().getStr()[0]; return c === "'" || c === "`"; })) {
103126
+ if (!operands.some(op => this.isLiteral(op))) {
102919
103127
  continue;
102920
103128
  }
102921
103129
  const template = this.buildTemplate(operands);
@@ -102940,10 +103148,11 @@ class PreferStringTemplate extends _abap_rule_1.ABAPRule {
102940
103148
  buildTemplate(operands) {
102941
103149
  let inner = "";
102942
103150
  for (const op of operands) {
102943
- const raw = op.getFirstToken().getStr();
102944
- const firstChar = raw[0];
102945
- if (firstChar === "'" || firstChar === "`") {
102946
- inner += raw.slice(1, -1);
103151
+ if (this.isLiteral(op)) {
103152
+ const raw = op.getFirstToken().getStr();
103153
+ const delimiter = raw[0];
103154
+ const value = raw.slice(1, -1).split(delimiter + delimiter).join(delimiter);
103155
+ inner += value.replace(/[\\|{}]/g, "\\$&");
102947
103156
  }
102948
103157
  else {
102949
103158
  inner += `{ ${op.concatTokens()} }`;
@@ -102951,6 +103160,14 @@ class PreferStringTemplate extends _abap_rule_1.ABAPRule {
102951
103160
  }
102952
103161
  return `|${inner}|`;
102953
103162
  }
103163
+ // plain character or string literal, ie. not text symbols or concatenated constants
103164
+ isLiteral(op) {
103165
+ if (op.getFirstToken() !== op.getLastToken()) {
103166
+ return false;
103167
+ }
103168
+ const firstChar = op.getFirstToken().getStr()[0];
103169
+ return firstChar === "'" || firstChar === "`";
103170
+ }
102954
103171
  }
102955
103172
  exports.PreferStringTemplate = PreferStringTemplate;
102956
103173
  //# sourceMappingURL=prefer_string_template.js.map
package/build/types.d.ts CHANGED
@@ -35,6 +35,8 @@ export interface ITranspilerConfig {
35
35
  */
36
36
  name?: string;
37
37
  url?: string;
38
+ /** commit SHA, tag or branch to check out from url; defaults to the default branch */
39
+ ref?: string;
38
40
  /** relative to the current working directory */
39
41
  folder?: string;
40
42
  files?: string | string[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abaplint/transpiler-cli",
3
- "version": "2.14.12",
3
+ "version": "2.14.13",
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.87",
31
- "@abaplint/transpiler": "^2.14.12",
30
+ "@abaplint/core": "^2.120.89",
31
+ "@abaplint/transpiler": "^2.14.13",
32
32
  "@types/glob": "^9.0.0",
33
33
  "@types/node": "^26.6.5",
34
34
  "@types/progress": "^2.0.7",