@abaplint/transpiler-cli 2.14.11 → 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 +23 -0
- package/build/bundle.js +514 -56
- package/build/types.d.ts +2 -0
- package/package.json +3 -3
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
|
-
|
|
267
|
-
|
|
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
|
-
|
|
542
|
-
|
|
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
|
-
|
|
6286
|
-
|
|
6287
|
-
const
|
|
6288
|
-
|
|
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
|
|
@@ -29854,6 +29955,7 @@ const expressions_1 = __webpack_require__(/*! ../2_statements/expressions */ "./
|
|
|
29854
29955
|
const _builtin_1 = __webpack_require__(/*! ./_builtin */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js");
|
|
29855
29956
|
const position_1 = __webpack_require__(/*! ../../position */ "./node_modules/@abaplint/core/build/src/position.js");
|
|
29856
29957
|
const _syntax_input_1 = __webpack_require__(/*! ./_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
|
|
29958
|
+
const version_1 = __webpack_require__(/*! ../../version */ "./node_modules/@abaplint/core/build/src/version.js");
|
|
29857
29959
|
class BasicTypes {
|
|
29858
29960
|
constructor(input) {
|
|
29859
29961
|
this.input = input;
|
|
@@ -30079,7 +30181,14 @@ class BasicTypes {
|
|
|
30079
30181
|
}
|
|
30080
30182
|
const chainText = typeName.concatTokens().toUpperCase();
|
|
30081
30183
|
const f = this.input.scope.getDDIC().lookupBuiltinType(chainText, length, decimals, qualifiedName);
|
|
30082
|
-
if (f
|
|
30184
|
+
if (f instanceof Types.Integer8Type
|
|
30185
|
+
&& !(0, version_1.releaseAtLeast)(this.input.scope.getRelease(), version_1.Release.v750)
|
|
30186
|
+
&& !this.input.scope.getOpenABAP()) {
|
|
30187
|
+
const message = "Type INT8 requires 7.50";
|
|
30188
|
+
this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, typeName.getFirstToken(), message));
|
|
30189
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
30190
|
+
}
|
|
30191
|
+
else if (f !== undefined) {
|
|
30083
30192
|
return f;
|
|
30084
30193
|
}
|
|
30085
30194
|
const typ = this.input.scope.findType(chainText);
|
|
@@ -34839,6 +34948,7 @@ const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "./node_modu
|
|
|
34839
34948
|
const constant_1 = __webpack_require__(/*! ./constant */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/constant.js");
|
|
34840
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");
|
|
34841
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");
|
|
34842
34952
|
class MethodCallParam {
|
|
34843
34953
|
/** returns the type of the unnamed argument, if any */
|
|
34844
34954
|
static runSyntax(node, input, method) {
|
|
@@ -34915,7 +35025,7 @@ class MethodCallParam {
|
|
|
34915
35025
|
else if ((0, _check_text_symbol_1.checkTextSymbol)(child, targetType, input)) {
|
|
34916
35026
|
return;
|
|
34917
35027
|
}
|
|
34918
|
-
else if (
|
|
35028
|
+
else if (this.isAssignable(sourceType, targetType, child, method, input) === false) {
|
|
34919
35029
|
const message = "Method parameter type not compatible";
|
|
34920
35030
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
34921
35031
|
return;
|
|
@@ -34935,6 +35045,12 @@ class MethodCallParam {
|
|
|
34935
35045
|
}
|
|
34936
35046
|
return undefined;
|
|
34937
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
|
+
}
|
|
34938
35054
|
}
|
|
34939
35055
|
exports.MethodCallParam = MethodCallParam;
|
|
34940
35056
|
//# sourceMappingURL=method_call_param.js.map
|
|
@@ -35172,6 +35288,7 @@ const field_chain_1 = __webpack_require__(/*! ./field_chain */ "./node_modules/@
|
|
|
35172
35288
|
const _reference_1 = __webpack_require__(/*! ../_reference */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js");
|
|
35173
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");
|
|
35174
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");
|
|
35175
35292
|
function normalizeParameterName(name) {
|
|
35176
35293
|
return name.replace(/^!/, "").toUpperCase();
|
|
35177
35294
|
}
|
|
@@ -35319,6 +35436,10 @@ class MethodParameters {
|
|
|
35319
35436
|
if (this.requiredParameters === undefined) {
|
|
35320
35437
|
this.requiredParameters = new Set(method.getParameters().getRequiredParameters().map(i => i.getName().toUpperCase()));
|
|
35321
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);
|
|
35322
35443
|
for (const item of items) {
|
|
35323
35444
|
const parameter = allImporting.find(p => p.getName().toUpperCase() === item.name);
|
|
35324
35445
|
if (parameter === undefined) {
|
|
@@ -35329,7 +35450,7 @@ class MethodParameters {
|
|
|
35329
35450
|
else if ((0, _check_text_symbol_1.checkTextSymbol)(item.source, parameter.getType(), input)) {
|
|
35330
35451
|
return;
|
|
35331
35452
|
}
|
|
35332
|
-
else if (
|
|
35453
|
+
else if (assignable(item.sourceType, parameter.getType(), item.source) === false) {
|
|
35333
35454
|
const message = "Method parameter type not compatible, " + item.name;
|
|
35334
35455
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
35335
35456
|
return;
|
|
@@ -44563,6 +44684,10 @@ class InsertInternal {
|
|
|
44563
44684
|
if (sourceType instanceof basic_1.IntegerType && targetType instanceof basic_1.Integer8Type) {
|
|
44564
44685
|
error = true;
|
|
44565
44686
|
}
|
|
44687
|
+
else if (targetType instanceof basic_1.TableType && targetType.isWithHeader() && sourceType instanceof basic_1.TableType) {
|
|
44688
|
+
// LINES OF into a table with header line, compare the row types
|
|
44689
|
+
error = new _type_utils_1.TypeUtils(input.scope).isAssignable(sourceType.getRowType(), targetType.getRowType()) === false;
|
|
44690
|
+
}
|
|
44566
44691
|
else if (new _type_utils_1.TypeUtils(input.scope).isAssignable(sourceType, targetType) === false) {
|
|
44567
44692
|
error = true;
|
|
44568
44693
|
}
|
|
@@ -57728,7 +57853,7 @@ const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "./node_modules/@
|
|
|
57728
57853
|
const ddic_1 = __webpack_require__(/*! ../ddic */ "./node_modules/@abaplint/core/build/src/ddic.js");
|
|
57729
57854
|
class CDSDetermineTypes {
|
|
57730
57855
|
parseType(reg, parsedData, ddlsName) {
|
|
57731
|
-
var _a;
|
|
57856
|
+
var _a, _b;
|
|
57732
57857
|
const ddic = new ddic_1.DDIC(reg);
|
|
57733
57858
|
if ((parsedData === null || parsedData === void 0 ? void 0 : parsedData.fields.length) === 0) {
|
|
57734
57859
|
return basic_1.VoidType.get("DDLS:todo");
|
|
@@ -57807,13 +57932,29 @@ class CDSDetermineTypes {
|
|
|
57807
57932
|
else {
|
|
57808
57933
|
components.push({
|
|
57809
57934
|
name: f.name,
|
|
57810
|
-
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),
|
|
57811
57936
|
});
|
|
57812
57937
|
}
|
|
57813
57938
|
}
|
|
57814
57939
|
return new basic_1.StructureType(components, parsedData.definitionName, parsedData.definitionName, parsedData.description);
|
|
57815
57940
|
}
|
|
57816
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
|
+
}
|
|
57817
57958
|
}
|
|
57818
57959
|
exports.CDSDetermineTypes = CDSDetermineTypes;
|
|
57819
57960
|
//# sourceMappingURL=cds_determine_types.js.map
|
|
@@ -61376,8 +61517,8 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
61376
61517
|
};
|
|
61377
61518
|
})();
|
|
61378
61519
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
61379
|
-
exports.
|
|
61380
|
-
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;
|
|
61381
61522
|
const issue_1 = __webpack_require__(/*! ./issue */ "./node_modules/@abaplint/core/build/src/issue.js");
|
|
61382
61523
|
Object.defineProperty(exports, "Issue", { enumerable: true, get: function () { return issue_1.Issue; } });
|
|
61383
61524
|
const config_1 = __webpack_require__(/*! ./config */ "./node_modules/@abaplint/core/build/src/config.js");
|
|
@@ -61474,6 +61615,8 @@ Object.defineProperty(exports, "DDLParser", { enumerable: true, get: function ()
|
|
|
61474
61615
|
Object.defineProperty(exports, "DDLKind", { enumerable: true, get: function () { return ddl_parser_1.DDLKind; } });
|
|
61475
61616
|
const cds_parser_1 = __webpack_require__(/*! ./cds/cds_parser */ "./node_modules/@abaplint/core/build/src/cds/cds_parser.js");
|
|
61476
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; } });
|
|
61477
61620
|
const rules_runner_1 = __webpack_require__(/*! ./rules_runner */ "./node_modules/@abaplint/core/build/src/rules_runner.js");
|
|
61478
61621
|
Object.defineProperty(exports, "RulesRunner", { enumerable: true, get: function () { return rules_runner_1.RulesRunner; } });
|
|
61479
61622
|
const _irule_1 = __webpack_require__(/*! ./rules/_irule */ "./node_modules/@abaplint/core/build/src/rules/_irule.js");
|
|
@@ -66526,12 +66669,16 @@ class DataDefinition extends _abstract_object_1.AbstractObject {
|
|
|
66526
66669
|
let found = (_a = e.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
|
|
66527
66670
|
const list = (_b = e.findDirectExpression(expressions_1.CDSPrefixedName)) === null || _b === void 0 ? void 0 : _b.findAllExpressions(expressions_1.CDSName);
|
|
66528
66671
|
if (list !== undefined) {
|
|
66529
|
-
const redirected =
|
|
66672
|
+
const redirected = e.concatTokens().toUpperCase().includes(" REDIRECTED TO ");
|
|
66530
66673
|
if (list.length > 1 && redirected === false) {
|
|
66531
66674
|
// "prefix.field" is looked up as "field" in "prefix", also when aliased via "as"
|
|
66532
66675
|
prefix = list[0].concatTokens();
|
|
66533
66676
|
nameInSource = list[list.length - 1].concatTokens();
|
|
66534
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
|
+
}
|
|
66535
66682
|
if (found === undefined) {
|
|
66536
66683
|
found = redirected === true ? list[0] : list[list.length - 1];
|
|
66537
66684
|
}
|
|
@@ -73714,7 +73861,7 @@ class Registry {
|
|
|
73714
73861
|
}
|
|
73715
73862
|
static abaplintVersion() {
|
|
73716
73863
|
// magic, see build script "version.js"
|
|
73717
|
-
return "2.120.
|
|
73864
|
+
return "2.120.89";
|
|
73718
73865
|
}
|
|
73719
73866
|
getDDICReferences() {
|
|
73720
73867
|
return this.ddicReferences;
|
|
@@ -77371,6 +77518,7 @@ const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/ex
|
|
|
77371
77518
|
const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
|
|
77372
77519
|
const Structures = __importStar(__webpack_require__(/*! ../abap/3_structures/structures */ "./node_modules/@abaplint/core/build/src/abap/3_structures/structures/index.js"));
|
|
77373
77520
|
const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
|
|
77521
|
+
const tokens_1 = __webpack_require__(/*! ../abap/1_lexer/tokens */ "./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/index.js");
|
|
77374
77522
|
class AlignTypeExpressionsConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
77375
77523
|
constructor() {
|
|
77376
77524
|
super(...arguments);
|
|
@@ -77538,12 +77686,18 @@ ENDINTERFACE.`,
|
|
|
77538
77686
|
let column = 0;
|
|
77539
77687
|
const st = t.findDirectStatements(Statements.Type);
|
|
77540
77688
|
for (const s of st) {
|
|
77541
|
-
const
|
|
77689
|
+
const children = s.getChildren();
|
|
77690
|
+
const length = s.findDirectExpression(Expressions.ConstantFieldLength);
|
|
77691
|
+
const nameEnd = (length !== null && length !== void 0 ? length : children[1]).getLastToken().getEnd();
|
|
77692
|
+
const after = children[length ? 3 : 2];
|
|
77693
|
+
if (after === undefined || after.getFirstToken() instanceof tokens_1.Punctuation) {
|
|
77694
|
+
continue; // no TYPE clause, eg. "foo(1)," with implicit type
|
|
77695
|
+
}
|
|
77542
77696
|
fields.push({
|
|
77543
|
-
nameEnd:
|
|
77544
|
-
after:
|
|
77697
|
+
nameEnd: nameEnd,
|
|
77698
|
+
after: after.getFirstToken().getStart()
|
|
77545
77699
|
});
|
|
77546
|
-
column = Math.max(column,
|
|
77700
|
+
column = Math.max(column, nameEnd.getCol() + 1);
|
|
77547
77701
|
}
|
|
77548
77702
|
issues.push(...this.check(fields, column, file));
|
|
77549
77703
|
}
|
|
@@ -85489,6 +85643,29 @@ Make sure to test the downported code, it might not always be completely correct
|
|
|
85489
85643
|
}
|
|
85490
85644
|
}
|
|
85491
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
|
+
}
|
|
85658
|
+
// INSERT with a 702 built-in function as the operand parses in the low version, but 702
|
|
85659
|
+
// reads the function as a method call, "Method SUBSTRING does not exist"
|
|
85660
|
+
if (ret.length === 0) {
|
|
85661
|
+
for (let i = 0; i < lowStatements.length; i++) {
|
|
85662
|
+
const issue = this.outlineInsertBuiltin(lowStatements[i], highStatements[i], lowFile, highSyntax);
|
|
85663
|
+
if (issue) {
|
|
85664
|
+
ret.push(issue);
|
|
85665
|
+
break;
|
|
85666
|
+
}
|
|
85667
|
+
}
|
|
85668
|
+
}
|
|
85492
85669
|
// INTO after WHERE parses as a valid SELECT in the low version, but is only allowed in
|
|
85493
85670
|
// strict SQL syntax, so move it also when the statement is no longer Unknown
|
|
85494
85671
|
if (ret.length === 0) {
|
|
@@ -86321,6 +86498,40 @@ ${indentation}`);
|
|
|
86321
86498
|
}
|
|
86322
86499
|
return undefined;
|
|
86323
86500
|
}
|
|
86501
|
+
/** INSERT substring( ... ) INTO TABLE tab, the operand is outlined into a variable */
|
|
86502
|
+
outlineInsertBuiltin(low, high, lowFile, highSyntax) {
|
|
86503
|
+
var _a;
|
|
86504
|
+
if (!(high.get() instanceof Statements.InsertInternal)) {
|
|
86505
|
+
return undefined;
|
|
86506
|
+
}
|
|
86507
|
+
else if (this.lowReg.getConfig().isOpenABAP()) {
|
|
86508
|
+
return undefined;
|
|
86509
|
+
}
|
|
86510
|
+
else if (low.getFirstToken().getStart() instanceof virtual_position_1.VirtualPosition) {
|
|
86511
|
+
return undefined;
|
|
86512
|
+
}
|
|
86513
|
+
// the whole operand is the call, a longer expression is outlined by replaceInsertExpression
|
|
86514
|
+
const source = high.getChildren()[1];
|
|
86515
|
+
if (!(source instanceof nodes_1.ExpressionNode)
|
|
86516
|
+
|| !(source.get() instanceof Expressions.SimpleSource4 || source.get() instanceof Expressions.Source)
|
|
86517
|
+
|| source.getChildren().length !== 1
|
|
86518
|
+
|| !(((_a = source.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.MethodCallChain)) {
|
|
86519
|
+
return undefined;
|
|
86520
|
+
}
|
|
86521
|
+
const type = this.builtinReturnType(source, lowFile, highSyntax);
|
|
86522
|
+
if (type === undefined) {
|
|
86523
|
+
return undefined;
|
|
86524
|
+
}
|
|
86525
|
+
const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
|
|
86526
|
+
const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
|
|
86527
|
+
const code = `DATA ${uniqueName} TYPE ${type}.\n` +
|
|
86528
|
+
indentation + `${uniqueName} = ${source.concatTokens()}.\n` +
|
|
86529
|
+
indentation;
|
|
86530
|
+
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);
|
|
86531
|
+
const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, source.getFirstToken().getStart(), source.getLastToken().getEnd(), uniqueName);
|
|
86532
|
+
const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
|
|
86533
|
+
return issue_1.Issue.atToken(lowFile, source.getFirstToken(), "Outline built-in function in INSERT", this.getMetadata().key, this.conf.severity, fix);
|
|
86534
|
+
}
|
|
86324
86535
|
/** the ABAP type returned by the built-in function this Source starts with, or undefined
|
|
86325
86536
|
* if it does not start with one, or with one that predates 702 */
|
|
86326
86537
|
builtinReturnType(source, lowFile, highSyntax) {
|
|
@@ -88025,6 +88236,67 @@ ${indentation} output = ${uniqueName}.\n`;
|
|
|
88025
88236
|
}
|
|
88026
88237
|
return undefined;
|
|
88027
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
|
+
}
|
|
88028
88300
|
/** if the source expression is the complete source of an INSERT or APPEND statement, then the
|
|
88029
88301
|
* outlined variable must be typed via the row type of the table, returns the table name */
|
|
88030
88302
|
findRowTypeOf(high, source) {
|
|
@@ -102851,7 +103123,7 @@ class PreferStringTemplate extends _abap_rule_1.ABAPRule {
|
|
|
102851
103123
|
continue;
|
|
102852
103124
|
}
|
|
102853
103125
|
const operands = this.flattenChain(source);
|
|
102854
|
-
if (!operands.some(op =>
|
|
103126
|
+
if (!operands.some(op => this.isLiteral(op))) {
|
|
102855
103127
|
continue;
|
|
102856
103128
|
}
|
|
102857
103129
|
const template = this.buildTemplate(operands);
|
|
@@ -102876,10 +103148,11 @@ class PreferStringTemplate extends _abap_rule_1.ABAPRule {
|
|
|
102876
103148
|
buildTemplate(operands) {
|
|
102877
103149
|
let inner = "";
|
|
102878
103150
|
for (const op of operands) {
|
|
102879
|
-
|
|
102880
|
-
|
|
102881
|
-
|
|
102882
|
-
|
|
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, "\\$&");
|
|
102883
103156
|
}
|
|
102884
103157
|
else {
|
|
102885
103158
|
inner += `{ ${op.concatTokens()} }`;
|
|
@@ -102887,6 +103160,14 @@ class PreferStringTemplate extends _abap_rule_1.ABAPRule {
|
|
|
102887
103160
|
}
|
|
102888
103161
|
return `|${inner}|`;
|
|
102889
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
|
+
}
|
|
102890
103171
|
}
|
|
102891
103172
|
exports.PreferStringTemplate = PreferStringTemplate;
|
|
102892
103173
|
//# sourceMappingURL=prefer_string_template.js.map
|
|
@@ -115623,6 +115904,7 @@ exports.PopulateTables = PopulateTables;
|
|
|
115623
115904
|
|
|
115624
115905
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
115625
115906
|
exports.DatabaseSchemaReuse = void 0;
|
|
115907
|
+
const OPERATORS = { EQ: "=", NE: "<>", LT: "<", LE: "<=", GT: ">", GE: ">=" };
|
|
115626
115908
|
class DatabaseSchemaReuse {
|
|
115627
115909
|
myQuote;
|
|
115628
115910
|
constructor(quote) {
|
|
@@ -115632,31 +115914,68 @@ class DatabaseSchemaReuse {
|
|
|
115632
115914
|
return this.myQuote + name.toLowerCase() + this.myQuote;
|
|
115633
115915
|
}
|
|
115634
115916
|
buildVIEW(view) {
|
|
115635
|
-
const fields = view.getFields();
|
|
115636
|
-
|
|
115637
|
-
|
|
115638
|
-
firstTabname = this.quote(f.TABNAME.toLowerCase());
|
|
115639
|
-
return firstTabname + "." + f.FIELDNAME.toLowerCase() + " AS " + f.VIEWFIELD.toLowerCase();
|
|
115917
|
+
const fields = view.getFields() || [];
|
|
115918
|
+
const columns = fields.map((f) => {
|
|
115919
|
+
return this.quote(f.TABNAME) + "." + f.FIELDNAME.toLowerCase() + " AS " + f.VIEWFIELD.toLowerCase();
|
|
115640
115920
|
}).join(", ");
|
|
115641
|
-
|
|
115642
|
-
|
|
115643
|
-
|
|
115644
|
-
|
|
115645
|
-
|
|
115646
|
-
|
|
115647
|
-
|
|
115648
|
-
|
|
115649
|
-
|
|
115650
|
-
|
|
115651
|
-
|
|
115652
|
-
|
|
115653
|
-
|
|
115654
|
-
}
|
|
115655
|
-
|
|
115656
|
-
|
|
115657
|
-
|
|
115658
|
-
|
|
115659
|
-
|
|
115921
|
+
// a DD28J row compares two fields, or without RFIELD a field to the constant in RTAB, eg. 'EN'
|
|
115922
|
+
const joins = view.getJoin() || [];
|
|
115923
|
+
let pending = joins.filter(j => j.RFIELD !== undefined && j.RFIELD !== "");
|
|
115924
|
+
const constants = joins.filter(j => j.RFIELD === undefined || j.RFIELD === "");
|
|
115925
|
+
// start from the table of the first view field, typically the root table, then repeatedly
|
|
115926
|
+
// join a table that has conditions on the tables already joined, LTAB is not always the new one
|
|
115927
|
+
const tables = [];
|
|
115928
|
+
const conditions = {};
|
|
115929
|
+
const add = (table) => {
|
|
115930
|
+
tables.push(table);
|
|
115931
|
+
const on = pending.filter(j => tables.includes(j.LTAB) && tables.includes(j.RTAB));
|
|
115932
|
+
pending = pending.filter(j => on.includes(j) === false);
|
|
115933
|
+
conditions[table] = [...on, ...constants.filter(j => j.LTAB === table)].map(j => this.condition(view, j));
|
|
115934
|
+
};
|
|
115935
|
+
const first = fields[0]?.TABNAME;
|
|
115936
|
+
const root = first !== undefined && (pending.length === 0 || pending.some(j => j.LTAB === first || j.RTAB === first))
|
|
115937
|
+
? first : (pending[0] || constants[0])?.LTAB;
|
|
115938
|
+
if (root === undefined) {
|
|
115939
|
+
throw new Error(`View ${view.getName()}: no tables`);
|
|
115940
|
+
}
|
|
115941
|
+
add(root);
|
|
115942
|
+
while (pending.length > 0) {
|
|
115943
|
+
// tables without conditions on the joined ones are cross joined
|
|
115944
|
+
const next = pending.find(j => tables.includes(j.LTAB) || tables.includes(j.RTAB)) || pending[0];
|
|
115945
|
+
add(tables.includes(next.LTAB) ? next.RTAB : next.LTAB);
|
|
115946
|
+
}
|
|
115947
|
+
for (const c of constants) {
|
|
115948
|
+
if (tables.includes(c.LTAB) === false) {
|
|
115949
|
+
add(c.LTAB);
|
|
115950
|
+
}
|
|
115951
|
+
}
|
|
115952
|
+
let from = this.quote(tables[0]);
|
|
115953
|
+
for (const table of tables.slice(1)) {
|
|
115954
|
+
from += conditions[table].length === 0
|
|
115955
|
+
? " CROSS JOIN " + this.quote(table)
|
|
115956
|
+
: " INNER JOIN " + this.quote(table) + " ON " + conditions[table].join(" AND ");
|
|
115957
|
+
}
|
|
115958
|
+
if (conditions[tables[0]].length > 0) {
|
|
115959
|
+
from += " WHERE " + conditions[tables[0]].join(" AND ");
|
|
115960
|
+
}
|
|
115961
|
+
return `CREATE VIEW ${this.quote(view.getName())} AS SELECT ${columns} FROM ${from};\n`;
|
|
115962
|
+
}
|
|
115963
|
+
condition(view, j) {
|
|
115964
|
+
const operator = OPERATORS[j.OPERATOR];
|
|
115965
|
+
if (operator === undefined) {
|
|
115966
|
+
throw new Error(`View ${view.getName()}: join operator ${j.OPERATOR} not supported`);
|
|
115967
|
+
}
|
|
115968
|
+
const right = j.RFIELD === undefined || j.RFIELD === ""
|
|
115969
|
+
? this.escape(j.RTAB)
|
|
115970
|
+
: this.quote(j.RTAB) + "." + j.RFIELD.toLowerCase();
|
|
115971
|
+
return this.quote(j.LTAB) + "." + j.LFIELD.toLowerCase() + " " + operator + " " + right;
|
|
115972
|
+
}
|
|
115973
|
+
// the constant keeps its single quotes, statements are inside a javascript string template
|
|
115974
|
+
escape(value) {
|
|
115975
|
+
let ret = value.replace(/\\/g, "\\\\");
|
|
115976
|
+
ret = ret.replace(/`/g, "\\`");
|
|
115977
|
+
ret = ret.replace(/\${/g, "\\${");
|
|
115978
|
+
return ret;
|
|
115660
115979
|
}
|
|
115661
115980
|
}
|
|
115662
115981
|
exports.DatabaseSchemaReuse = DatabaseSchemaReuse;
|
|
@@ -118863,6 +119182,7 @@ const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_
|
|
|
118863
119182
|
const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
|
|
118864
119183
|
const type_name_or_infer_1 = __webpack_require__(/*! ./type_name_or_infer */ "./node_modules/@abaplint/transpiler/build/src/expressions/type_name_or_infer.js");
|
|
118865
119184
|
const types_1 = __webpack_require__(/*! ../types */ "./node_modules/@abaplint/transpiler/build/src/types.js");
|
|
119185
|
+
const field_assignment_1 = __webpack_require__(/*! ./field_assignment */ "./node_modules/@abaplint/transpiler/build/src/expressions/field_assignment.js");
|
|
118866
119186
|
class NewObjectTranspiler {
|
|
118867
119187
|
transpile(node, traversal) {
|
|
118868
119188
|
const ret = new chunk_1.Chunk();
|
|
@@ -118907,10 +119227,48 @@ class NewObjectTranspiler {
|
|
|
118907
119227
|
ret.appendString(traversal.toType(type) + ".set(await (new " + clas + "()).constructor_(" + para + "))");
|
|
118908
119228
|
}
|
|
118909
119229
|
else {
|
|
118910
|
-
|
|
119230
|
+
// a new data object with a copy of the value, never the source itself; async, as sources can await
|
|
118911
119231
|
const typeCode = traversal.toType(type);
|
|
118912
|
-
const
|
|
118913
|
-
ret.appendString("((() => {const r = new abap.types.DataReference(" + typeCode + "); r.assign(" +
|
|
119232
|
+
const setCode = this.buildValue(node, type, traversal);
|
|
119233
|
+
ret.appendString("(await (async () => {const r = new abap.types.DataReference(" + typeCode + "); r.assign(" + typeCode + ");" + setCode + " return r; })())");
|
|
119234
|
+
}
|
|
119235
|
+
return ret;
|
|
119236
|
+
}
|
|
119237
|
+
buildValue(node, type, traversal) {
|
|
119238
|
+
let ret = "";
|
|
119239
|
+
const parameters = node.findDirectExpression(core_1.Expressions.ParameterListS);
|
|
119240
|
+
if (parameters) {
|
|
119241
|
+
// NEW ty( a = 1 b = 2 ), components of a structure
|
|
119242
|
+
for (const p of parameters.findDirectExpressions(core_1.Expressions.ParameterS)) {
|
|
119243
|
+
const name = p.findDirectExpression(core_1.Expressions.ParameterName).concatTokens().toLowerCase();
|
|
119244
|
+
const source = traversal.traverse(p.findDirectExpression(core_1.Expressions.Source)).getCode();
|
|
119245
|
+
ret += ` r.getPointer().setField("${name}", ${source});`;
|
|
119246
|
+
}
|
|
119247
|
+
return ret;
|
|
119248
|
+
}
|
|
119249
|
+
const single = node.getChildren()[3];
|
|
119250
|
+
if (single instanceof core_1.Nodes.ExpressionNode && single.get() instanceof core_1.Expressions.Source) {
|
|
119251
|
+
return ` r.getPointer().set(${traversal.traverse(single).getCode()});`;
|
|
119252
|
+
}
|
|
119253
|
+
else if (!(type instanceof abaplint.BasicTypes.TableType)) {
|
|
119254
|
+
return ret;
|
|
119255
|
+
}
|
|
119256
|
+
// NEW tab( ( 1 ) ( a = 2 ) ), table lines
|
|
119257
|
+
const rowType = traversal.toType(type.getRowType());
|
|
119258
|
+
let row = "";
|
|
119259
|
+
for (const c of node.getChildren().slice(3)) {
|
|
119260
|
+
if (c instanceof core_1.Nodes.TokenNode) {
|
|
119261
|
+
if (c.getFirstToken().getStr() === ")" && row !== "") {
|
|
119262
|
+
ret += ` r.getPointer().appendThis(${rowType}${row});`;
|
|
119263
|
+
row = "";
|
|
119264
|
+
}
|
|
119265
|
+
}
|
|
119266
|
+
else if (c.get() instanceof core_1.Expressions.Source) {
|
|
119267
|
+
row += `.set(${traversal.traverse(c).getCode()})`;
|
|
119268
|
+
}
|
|
119269
|
+
else if (c.get() instanceof core_1.Expressions.FieldAssignment && c instanceof core_1.Nodes.ExpressionNode) {
|
|
119270
|
+
row += new field_assignment_1.FieldAssignmentTranspiler().transpile(c, traversal).getCode();
|
|
119271
|
+
}
|
|
118914
119272
|
}
|
|
118915
119273
|
return ret;
|
|
118916
119274
|
}
|
|
@@ -135039,6 +135397,9 @@ class ClassImplementationTranspiler {
|
|
|
135039
135397
|
transpile(node, traversal) {
|
|
135040
135398
|
const ret = new chunk_1.Chunk();
|
|
135041
135399
|
for (const c of node.getChildren()) {
|
|
135400
|
+
if (c.get() instanceof abaplint.Statements.EndClass) {
|
|
135401
|
+
ret.appendString(this.buildPartiallyImplementedStubs(node, traversal));
|
|
135402
|
+
}
|
|
135042
135403
|
ret.appendChunk(traversal.traverse(c));
|
|
135043
135404
|
if (c.get() instanceof abaplint.Statements.ClassImplementation) {
|
|
135044
135405
|
ret.appendString(this.buildConstructor(node.getFirstStatement(), traversal));
|
|
@@ -135054,6 +135415,103 @@ class ClassImplementationTranspiler {
|
|
|
135054
135415
|
return ret;
|
|
135055
135416
|
}
|
|
135056
135417
|
///////////////////////////////
|
|
135418
|
+
/** INTERFACES ... PARTIALLY IMPLEMENTED: the interface methods the test class
|
|
135419
|
+
* does not implement exist on a system and raise CX_SY_DYN_CALL_ILLEGAL_METHOD
|
|
135420
|
+
* when called. Emits a method of that shape under the name the implementation
|
|
135421
|
+
* would have had, so the call ends in that exception and not in a TypeError */
|
|
135422
|
+
buildPartiallyImplementedStubs(node, traversal) {
|
|
135423
|
+
const token = node.findFirstExpression(abaplint.Expressions.ClassName)?.getFirstToken();
|
|
135424
|
+
if (token === undefined) {
|
|
135425
|
+
return "";
|
|
135426
|
+
}
|
|
135427
|
+
const cdef = traversal.getClassDefinition(token);
|
|
135428
|
+
const scope = traversal.findCurrentScopeByToken(token);
|
|
135429
|
+
if (cdef === undefined || scope === undefined) {
|
|
135430
|
+
return "";
|
|
135431
|
+
}
|
|
135432
|
+
const partial = cdef.getImplementing().filter(i => i.partial === true);
|
|
135433
|
+
if (partial.length === 0) {
|
|
135434
|
+
return "";
|
|
135435
|
+
}
|
|
135436
|
+
// the methods the class implements itself, by the emitted name
|
|
135437
|
+
const implemented = new Set();
|
|
135438
|
+
for (const m of node.findAllStatements(abaplint.Statements.MethodImplementation)) {
|
|
135439
|
+
const name = m.findFirstExpression(abaplint.Expressions.MethodName)?.getFirstToken().getStr();
|
|
135440
|
+
if (name !== undefined) {
|
|
135441
|
+
implemented.add(traversal_1.Traversal.escapeNamespace(name.replace("~", "$").toLowerCase()));
|
|
135442
|
+
}
|
|
135443
|
+
}
|
|
135444
|
+
// an interface a superclass implements is inherited, with the real implementations,
|
|
135445
|
+
// a stub for one of its methods would override those
|
|
135446
|
+
const inherited = new Set();
|
|
135447
|
+
let sup = cdef.getSuperClass();
|
|
135448
|
+
while (sup !== undefined) {
|
|
135449
|
+
const sdef = traversal.findClassDefinition(sup, scope);
|
|
135450
|
+
for (const name of this.findIncludedInterfaces(sdef?.getImplementing().map(i => i.name) || [], scope, traversal)) {
|
|
135451
|
+
inherited.add(name);
|
|
135452
|
+
}
|
|
135453
|
+
sup = sdef?.getSuperClass();
|
|
135454
|
+
}
|
|
135455
|
+
let ret = "";
|
|
135456
|
+
for (const name of this.findIncludedInterfaces(partial.map(i => i.name), scope, traversal)) {
|
|
135457
|
+
if (inherited.has(name)) {
|
|
135458
|
+
continue;
|
|
135459
|
+
}
|
|
135460
|
+
const intf = traversal.findInterfaceDefinition(name, scope);
|
|
135461
|
+
if (intf === undefined) {
|
|
135462
|
+
continue;
|
|
135463
|
+
}
|
|
135464
|
+
const prefix = traversal_1.Traversal.escapeNamespace(intf.getName().toLowerCase()) + "$";
|
|
135465
|
+
for (const m of intf.getMethodDefinitions().getAll()) {
|
|
135466
|
+
const emitted = prefix + traversal_1.Traversal.escapeNamespace(m.getName().toLowerCase());
|
|
135467
|
+
if (implemented.has(emitted)) {
|
|
135468
|
+
continue;
|
|
135469
|
+
}
|
|
135470
|
+
implemented.add(emitted);
|
|
135471
|
+
ret += this.buildNotImplementedMethod(emitted, m, token.getStr().toLowerCase(), intf.getName(), token, traversal);
|
|
135472
|
+
}
|
|
135473
|
+
}
|
|
135474
|
+
return ret;
|
|
135475
|
+
}
|
|
135476
|
+
/** the interfaces, upper cased, with the interfaces they include, recursively */
|
|
135477
|
+
findIncludedInterfaces(names, scope, traversal) {
|
|
135478
|
+
const ret = [];
|
|
135479
|
+
const queue = [...names];
|
|
135480
|
+
while (queue.length > 0) {
|
|
135481
|
+
const name = queue.shift().toUpperCase();
|
|
135482
|
+
if (ret.includes(name)) {
|
|
135483
|
+
continue;
|
|
135484
|
+
}
|
|
135485
|
+
ret.push(name);
|
|
135486
|
+
const intf = traversal.findInterfaceDefinition(name, scope);
|
|
135487
|
+
queue.push(...(intf?.getImplementing().map(i => i.name) || []));
|
|
135488
|
+
}
|
|
135489
|
+
return ret;
|
|
135490
|
+
}
|
|
135491
|
+
/** the method a system generates for an interface method the test class leaves
|
|
135492
|
+
* out under PARTIALLY IMPLEMENTED: calling it raises CX_SY_DYN_CALL_ILLEGAL_METHOD
|
|
135493
|
+
* (ABAP keyword documentation, INTERFACES - PARTIALLY IMPLEMENTED), the class and
|
|
135494
|
+
* method named, instead of a JavaScript TypeError no CATCH sees */
|
|
135495
|
+
buildNotImplementedMethod(emitted, m, className, interfaceName, token, traversal) {
|
|
135496
|
+
const unique = m.getParameters().getAll().length > 0 ? "INPUT" : "";
|
|
135497
|
+
const exception = traversal.lookupClassOrInterface("'CX_SY_DYN_CALL_ILLEGAL_METHOD'", token, true);
|
|
135498
|
+
const classUpper = className.toUpperCase();
|
|
135499
|
+
const methodUpper = interfaceName.toUpperCase() + "~" + m.getName().toUpperCase();
|
|
135500
|
+
const notFound = `CX_SY_DYN_CALL_ILLEGAL_METHOD not found, ${classUpper}->${methodUpper} is not implemented`;
|
|
135501
|
+
const body = `if (${exception} === undefined) { throw new Error("${notFound}"); }\n` +
|
|
135502
|
+
`throw await new ${exception}().constructor_({` +
|
|
135503
|
+
`classname: new abap.types.String().set("${classUpper}"), ` +
|
|
135504
|
+
`methodname: new abap.types.String().set("${methodUpper}")});\n`;
|
|
135505
|
+
let ret = "";
|
|
135506
|
+
if (m.isStatic() === true) {
|
|
135507
|
+
// in ABAP static methods can be called with instance arrows, "->"
|
|
135508
|
+
ret += "async " + emitted + "(" + unique + ") {\n" +
|
|
135509
|
+
"return " + traversal_1.Traversal.escapeNamespace(className) + "." + emitted + "(" + unique + ");\n" +
|
|
135510
|
+
"}\n" + "static ";
|
|
135511
|
+
}
|
|
135512
|
+
ret += "async " + emitted + "(" + unique + ") {\n" + body + "}\n";
|
|
135513
|
+
return ret;
|
|
135514
|
+
}
|
|
135057
135515
|
hasConstructor(node) {
|
|
135058
135516
|
for (const m of node.findAllStatements(abaplint.Statements.MethodImplementation)) {
|
|
135059
135517
|
const name = m.findFirstExpression(abaplint.Expressions.MethodName)?.getFirstToken().getStr();
|
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.
|
|
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.
|
|
31
|
-
"@abaplint/transpiler": "^2.14.
|
|
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",
|