@abaplint/transpiler-cli 2.14.11 → 2.14.12
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/build/bundle.js +274 -33
- package/package.json +3 -3
package/build/bundle.js
CHANGED
|
@@ -29854,6 +29854,7 @@ const expressions_1 = __webpack_require__(/*! ../2_statements/expressions */ "./
|
|
|
29854
29854
|
const _builtin_1 = __webpack_require__(/*! ./_builtin */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js");
|
|
29855
29855
|
const position_1 = __webpack_require__(/*! ../../position */ "./node_modules/@abaplint/core/build/src/position.js");
|
|
29856
29856
|
const _syntax_input_1 = __webpack_require__(/*! ./_syntax_input */ "./node_modules/@abaplint/core/build/src/abap/5_syntax/_syntax_input.js");
|
|
29857
|
+
const version_1 = __webpack_require__(/*! ../../version */ "./node_modules/@abaplint/core/build/src/version.js");
|
|
29857
29858
|
class BasicTypes {
|
|
29858
29859
|
constructor(input) {
|
|
29859
29860
|
this.input = input;
|
|
@@ -30079,7 +30080,14 @@ class BasicTypes {
|
|
|
30079
30080
|
}
|
|
30080
30081
|
const chainText = typeName.concatTokens().toUpperCase();
|
|
30081
30082
|
const f = this.input.scope.getDDIC().lookupBuiltinType(chainText, length, decimals, qualifiedName);
|
|
30082
|
-
if (f
|
|
30083
|
+
if (f instanceof Types.Integer8Type
|
|
30084
|
+
&& !(0, version_1.releaseAtLeast)(this.input.scope.getRelease(), version_1.Release.v750)
|
|
30085
|
+
&& !this.input.scope.getOpenABAP()) {
|
|
30086
|
+
const message = "Type INT8 requires 7.50";
|
|
30087
|
+
this.input.issues.push((0, _syntax_input_1.syntaxIssue)(this.input, typeName.getFirstToken(), message));
|
|
30088
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
30089
|
+
}
|
|
30090
|
+
else if (f !== undefined) {
|
|
30083
30091
|
return f;
|
|
30084
30092
|
}
|
|
30085
30093
|
const typ = this.input.scope.findType(chainText);
|
|
@@ -44563,6 +44571,10 @@ class InsertInternal {
|
|
|
44563
44571
|
if (sourceType instanceof basic_1.IntegerType && targetType instanceof basic_1.Integer8Type) {
|
|
44564
44572
|
error = true;
|
|
44565
44573
|
}
|
|
44574
|
+
else if (targetType instanceof basic_1.TableType && targetType.isWithHeader() && sourceType instanceof basic_1.TableType) {
|
|
44575
|
+
// LINES OF into a table with header line, compare the row types
|
|
44576
|
+
error = new _type_utils_1.TypeUtils(input.scope).isAssignable(sourceType.getRowType(), targetType.getRowType()) === false;
|
|
44577
|
+
}
|
|
44566
44578
|
else if (new _type_utils_1.TypeUtils(input.scope).isAssignable(sourceType, targetType) === false) {
|
|
44567
44579
|
error = true;
|
|
44568
44580
|
}
|
|
@@ -73714,7 +73726,7 @@ class Registry {
|
|
|
73714
73726
|
}
|
|
73715
73727
|
static abaplintVersion() {
|
|
73716
73728
|
// magic, see build script "version.js"
|
|
73717
|
-
return "2.120.
|
|
73729
|
+
return "2.120.87";
|
|
73718
73730
|
}
|
|
73719
73731
|
getDDICReferences() {
|
|
73720
73732
|
return this.ddicReferences;
|
|
@@ -77371,6 +77383,7 @@ const Expressions = __importStar(__webpack_require__(/*! ../abap/2_statements/ex
|
|
|
77371
77383
|
const Statements = __importStar(__webpack_require__(/*! ../abap/2_statements/statements */ "./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js"));
|
|
77372
77384
|
const Structures = __importStar(__webpack_require__(/*! ../abap/3_structures/structures */ "./node_modules/@abaplint/core/build/src/abap/3_structures/structures/index.js"));
|
|
77373
77385
|
const edit_helper_1 = __webpack_require__(/*! ../edit_helper */ "./node_modules/@abaplint/core/build/src/edit_helper.js");
|
|
77386
|
+
const tokens_1 = __webpack_require__(/*! ../abap/1_lexer/tokens */ "./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/index.js");
|
|
77374
77387
|
class AlignTypeExpressionsConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
77375
77388
|
constructor() {
|
|
77376
77389
|
super(...arguments);
|
|
@@ -77538,12 +77551,18 @@ ENDINTERFACE.`,
|
|
|
77538
77551
|
let column = 0;
|
|
77539
77552
|
const st = t.findDirectStatements(Statements.Type);
|
|
77540
77553
|
for (const s of st) {
|
|
77541
|
-
const
|
|
77554
|
+
const children = s.getChildren();
|
|
77555
|
+
const length = s.findDirectExpression(Expressions.ConstantFieldLength);
|
|
77556
|
+
const nameEnd = (length !== null && length !== void 0 ? length : children[1]).getLastToken().getEnd();
|
|
77557
|
+
const after = children[length ? 3 : 2];
|
|
77558
|
+
if (after === undefined || after.getFirstToken() instanceof tokens_1.Punctuation) {
|
|
77559
|
+
continue; // no TYPE clause, eg. "foo(1)," with implicit type
|
|
77560
|
+
}
|
|
77542
77561
|
fields.push({
|
|
77543
|
-
nameEnd:
|
|
77544
|
-
after:
|
|
77562
|
+
nameEnd: nameEnd,
|
|
77563
|
+
after: after.getFirstToken().getStart()
|
|
77545
77564
|
});
|
|
77546
|
-
column = Math.max(column,
|
|
77565
|
+
column = Math.max(column, nameEnd.getCol() + 1);
|
|
77547
77566
|
}
|
|
77548
77567
|
issues.push(...this.check(fields, column, file));
|
|
77549
77568
|
}
|
|
@@ -85489,6 +85508,17 @@ Make sure to test the downported code, it might not always be completely correct
|
|
|
85489
85508
|
}
|
|
85490
85509
|
}
|
|
85491
85510
|
}
|
|
85511
|
+
// INSERT with a 702 built-in function as the operand parses in the low version, but 702
|
|
85512
|
+
// reads the function as a method call, "Method SUBSTRING does not exist"
|
|
85513
|
+
if (ret.length === 0) {
|
|
85514
|
+
for (let i = 0; i < lowStatements.length; i++) {
|
|
85515
|
+
const issue = this.outlineInsertBuiltin(lowStatements[i], highStatements[i], lowFile, highSyntax);
|
|
85516
|
+
if (issue) {
|
|
85517
|
+
ret.push(issue);
|
|
85518
|
+
break;
|
|
85519
|
+
}
|
|
85520
|
+
}
|
|
85521
|
+
}
|
|
85492
85522
|
// INTO after WHERE parses as a valid SELECT in the low version, but is only allowed in
|
|
85493
85523
|
// strict SQL syntax, so move it also when the statement is no longer Unknown
|
|
85494
85524
|
if (ret.length === 0) {
|
|
@@ -86321,6 +86351,40 @@ ${indentation}`);
|
|
|
86321
86351
|
}
|
|
86322
86352
|
return undefined;
|
|
86323
86353
|
}
|
|
86354
|
+
/** INSERT substring( ... ) INTO TABLE tab, the operand is outlined into a variable */
|
|
86355
|
+
outlineInsertBuiltin(low, high, lowFile, highSyntax) {
|
|
86356
|
+
var _a;
|
|
86357
|
+
if (!(high.get() instanceof Statements.InsertInternal)) {
|
|
86358
|
+
return undefined;
|
|
86359
|
+
}
|
|
86360
|
+
else if (this.lowReg.getConfig().isOpenABAP()) {
|
|
86361
|
+
return undefined;
|
|
86362
|
+
}
|
|
86363
|
+
else if (low.getFirstToken().getStart() instanceof virtual_position_1.VirtualPosition) {
|
|
86364
|
+
return undefined;
|
|
86365
|
+
}
|
|
86366
|
+
// the whole operand is the call, a longer expression is outlined by replaceInsertExpression
|
|
86367
|
+
const source = high.getChildren()[1];
|
|
86368
|
+
if (!(source instanceof nodes_1.ExpressionNode)
|
|
86369
|
+
|| !(source.get() instanceof Expressions.SimpleSource4 || source.get() instanceof Expressions.Source)
|
|
86370
|
+
|| source.getChildren().length !== 1
|
|
86371
|
+
|| !(((_a = source.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.MethodCallChain)) {
|
|
86372
|
+
return undefined;
|
|
86373
|
+
}
|
|
86374
|
+
const type = this.builtinReturnType(source, lowFile, highSyntax);
|
|
86375
|
+
if (type === undefined) {
|
|
86376
|
+
return undefined;
|
|
86377
|
+
}
|
|
86378
|
+
const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);
|
|
86379
|
+
const indentation = " ".repeat(high.getFirstToken().getStart().getCol() - 1);
|
|
86380
|
+
const code = `DATA ${uniqueName} TYPE ${type}.\n` +
|
|
86381
|
+
indentation + `${uniqueName} = ${source.concatTokens()}.\n` +
|
|
86382
|
+
indentation;
|
|
86383
|
+
const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);
|
|
86384
|
+
const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, source.getFirstToken().getStart(), source.getLastToken().getEnd(), uniqueName);
|
|
86385
|
+
const fix = edit_helper_1.EditHelper.merge(fix2, fix1);
|
|
86386
|
+
return issue_1.Issue.atToken(lowFile, source.getFirstToken(), "Outline built-in function in INSERT", this.getMetadata().key, this.conf.severity, fix);
|
|
86387
|
+
}
|
|
86324
86388
|
/** the ABAP type returned by the built-in function this Source starts with, or undefined
|
|
86325
86389
|
* if it does not start with one, or with one that predates 702 */
|
|
86326
86390
|
builtinReturnType(source, lowFile, highSyntax) {
|
|
@@ -115623,6 +115687,7 @@ exports.PopulateTables = PopulateTables;
|
|
|
115623
115687
|
|
|
115624
115688
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
115625
115689
|
exports.DatabaseSchemaReuse = void 0;
|
|
115690
|
+
const OPERATORS = { EQ: "=", NE: "<>", LT: "<", LE: "<=", GT: ">", GE: ">=" };
|
|
115626
115691
|
class DatabaseSchemaReuse {
|
|
115627
115692
|
myQuote;
|
|
115628
115693
|
constructor(quote) {
|
|
@@ -115632,31 +115697,68 @@ class DatabaseSchemaReuse {
|
|
|
115632
115697
|
return this.myQuote + name.toLowerCase() + this.myQuote;
|
|
115633
115698
|
}
|
|
115634
115699
|
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();
|
|
115700
|
+
const fields = view.getFields() || [];
|
|
115701
|
+
const columns = fields.map((f) => {
|
|
115702
|
+
return this.quote(f.TABNAME) + "." + f.FIELDNAME.toLowerCase() + " AS " + f.VIEWFIELD.toLowerCase();
|
|
115640
115703
|
}).join(", ");
|
|
115641
|
-
|
|
115642
|
-
|
|
115643
|
-
|
|
115644
|
-
|
|
115645
|
-
|
|
115646
|
-
|
|
115647
|
-
|
|
115648
|
-
|
|
115649
|
-
|
|
115650
|
-
|
|
115651
|
-
|
|
115652
|
-
|
|
115653
|
-
|
|
115654
|
-
}
|
|
115655
|
-
|
|
115656
|
-
|
|
115657
|
-
|
|
115658
|
-
|
|
115659
|
-
|
|
115704
|
+
// a DD28J row compares two fields, or without RFIELD a field to the constant in RTAB, eg. 'EN'
|
|
115705
|
+
const joins = view.getJoin() || [];
|
|
115706
|
+
let pending = joins.filter(j => j.RFIELD !== undefined && j.RFIELD !== "");
|
|
115707
|
+
const constants = joins.filter(j => j.RFIELD === undefined || j.RFIELD === "");
|
|
115708
|
+
// start from the table of the first view field, typically the root table, then repeatedly
|
|
115709
|
+
// join a table that has conditions on the tables already joined, LTAB is not always the new one
|
|
115710
|
+
const tables = [];
|
|
115711
|
+
const conditions = {};
|
|
115712
|
+
const add = (table) => {
|
|
115713
|
+
tables.push(table);
|
|
115714
|
+
const on = pending.filter(j => tables.includes(j.LTAB) && tables.includes(j.RTAB));
|
|
115715
|
+
pending = pending.filter(j => on.includes(j) === false);
|
|
115716
|
+
conditions[table] = [...on, ...constants.filter(j => j.LTAB === table)].map(j => this.condition(view, j));
|
|
115717
|
+
};
|
|
115718
|
+
const first = fields[0]?.TABNAME;
|
|
115719
|
+
const root = first !== undefined && (pending.length === 0 || pending.some(j => j.LTAB === first || j.RTAB === first))
|
|
115720
|
+
? first : (pending[0] || constants[0])?.LTAB;
|
|
115721
|
+
if (root === undefined) {
|
|
115722
|
+
throw new Error(`View ${view.getName()}: no tables`);
|
|
115723
|
+
}
|
|
115724
|
+
add(root);
|
|
115725
|
+
while (pending.length > 0) {
|
|
115726
|
+
// tables without conditions on the joined ones are cross joined
|
|
115727
|
+
const next = pending.find(j => tables.includes(j.LTAB) || tables.includes(j.RTAB)) || pending[0];
|
|
115728
|
+
add(tables.includes(next.LTAB) ? next.RTAB : next.LTAB);
|
|
115729
|
+
}
|
|
115730
|
+
for (const c of constants) {
|
|
115731
|
+
if (tables.includes(c.LTAB) === false) {
|
|
115732
|
+
add(c.LTAB);
|
|
115733
|
+
}
|
|
115734
|
+
}
|
|
115735
|
+
let from = this.quote(tables[0]);
|
|
115736
|
+
for (const table of tables.slice(1)) {
|
|
115737
|
+
from += conditions[table].length === 0
|
|
115738
|
+
? " CROSS JOIN " + this.quote(table)
|
|
115739
|
+
: " INNER JOIN " + this.quote(table) + " ON " + conditions[table].join(" AND ");
|
|
115740
|
+
}
|
|
115741
|
+
if (conditions[tables[0]].length > 0) {
|
|
115742
|
+
from += " WHERE " + conditions[tables[0]].join(" AND ");
|
|
115743
|
+
}
|
|
115744
|
+
return `CREATE VIEW ${this.quote(view.getName())} AS SELECT ${columns} FROM ${from};\n`;
|
|
115745
|
+
}
|
|
115746
|
+
condition(view, j) {
|
|
115747
|
+
const operator = OPERATORS[j.OPERATOR];
|
|
115748
|
+
if (operator === undefined) {
|
|
115749
|
+
throw new Error(`View ${view.getName()}: join operator ${j.OPERATOR} not supported`);
|
|
115750
|
+
}
|
|
115751
|
+
const right = j.RFIELD === undefined || j.RFIELD === ""
|
|
115752
|
+
? this.escape(j.RTAB)
|
|
115753
|
+
: this.quote(j.RTAB) + "." + j.RFIELD.toLowerCase();
|
|
115754
|
+
return this.quote(j.LTAB) + "." + j.LFIELD.toLowerCase() + " " + operator + " " + right;
|
|
115755
|
+
}
|
|
115756
|
+
// the constant keeps its single quotes, statements are inside a javascript string template
|
|
115757
|
+
escape(value) {
|
|
115758
|
+
let ret = value.replace(/\\/g, "\\\\");
|
|
115759
|
+
ret = ret.replace(/`/g, "\\`");
|
|
115760
|
+
ret = ret.replace(/\${/g, "\\${");
|
|
115761
|
+
return ret;
|
|
115660
115762
|
}
|
|
115661
115763
|
}
|
|
115662
115764
|
exports.DatabaseSchemaReuse = DatabaseSchemaReuse;
|
|
@@ -118863,6 +118965,7 @@ const abaplint = __importStar(__webpack_require__(/*! @abaplint/core */ "./node_
|
|
|
118863
118965
|
const chunk_1 = __webpack_require__(/*! ../chunk */ "./node_modules/@abaplint/transpiler/build/src/chunk.js");
|
|
118864
118966
|
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
118967
|
const types_1 = __webpack_require__(/*! ../types */ "./node_modules/@abaplint/transpiler/build/src/types.js");
|
|
118968
|
+
const field_assignment_1 = __webpack_require__(/*! ./field_assignment */ "./node_modules/@abaplint/transpiler/build/src/expressions/field_assignment.js");
|
|
118866
118969
|
class NewObjectTranspiler {
|
|
118867
118970
|
transpile(node, traversal) {
|
|
118868
118971
|
const ret = new chunk_1.Chunk();
|
|
@@ -118907,10 +119010,48 @@ class NewObjectTranspiler {
|
|
|
118907
119010
|
ret.appendString(traversal.toType(type) + ".set(await (new " + clas + "()).constructor_(" + para + "))");
|
|
118908
119011
|
}
|
|
118909
119012
|
else {
|
|
118910
|
-
|
|
119013
|
+
// a new data object with a copy of the value, never the source itself; async, as sources can await
|
|
118911
119014
|
const typeCode = traversal.toType(type);
|
|
118912
|
-
const
|
|
118913
|
-
ret.appendString("((() => {const r = new abap.types.DataReference(" + typeCode + "); r.assign(" +
|
|
119015
|
+
const setCode = this.buildValue(node, type, traversal);
|
|
119016
|
+
ret.appendString("(await (async () => {const r = new abap.types.DataReference(" + typeCode + "); r.assign(" + typeCode + ");" + setCode + " return r; })())");
|
|
119017
|
+
}
|
|
119018
|
+
return ret;
|
|
119019
|
+
}
|
|
119020
|
+
buildValue(node, type, traversal) {
|
|
119021
|
+
let ret = "";
|
|
119022
|
+
const parameters = node.findDirectExpression(core_1.Expressions.ParameterListS);
|
|
119023
|
+
if (parameters) {
|
|
119024
|
+
// NEW ty( a = 1 b = 2 ), components of a structure
|
|
119025
|
+
for (const p of parameters.findDirectExpressions(core_1.Expressions.ParameterS)) {
|
|
119026
|
+
const name = p.findDirectExpression(core_1.Expressions.ParameterName).concatTokens().toLowerCase();
|
|
119027
|
+
const source = traversal.traverse(p.findDirectExpression(core_1.Expressions.Source)).getCode();
|
|
119028
|
+
ret += ` r.getPointer().setField("${name}", ${source});`;
|
|
119029
|
+
}
|
|
119030
|
+
return ret;
|
|
119031
|
+
}
|
|
119032
|
+
const single = node.getChildren()[3];
|
|
119033
|
+
if (single instanceof core_1.Nodes.ExpressionNode && single.get() instanceof core_1.Expressions.Source) {
|
|
119034
|
+
return ` r.getPointer().set(${traversal.traverse(single).getCode()});`;
|
|
119035
|
+
}
|
|
119036
|
+
else if (!(type instanceof abaplint.BasicTypes.TableType)) {
|
|
119037
|
+
return ret;
|
|
119038
|
+
}
|
|
119039
|
+
// NEW tab( ( 1 ) ( a = 2 ) ), table lines
|
|
119040
|
+
const rowType = traversal.toType(type.getRowType());
|
|
119041
|
+
let row = "";
|
|
119042
|
+
for (const c of node.getChildren().slice(3)) {
|
|
119043
|
+
if (c instanceof core_1.Nodes.TokenNode) {
|
|
119044
|
+
if (c.getFirstToken().getStr() === ")" && row !== "") {
|
|
119045
|
+
ret += ` r.getPointer().appendThis(${rowType}${row});`;
|
|
119046
|
+
row = "";
|
|
119047
|
+
}
|
|
119048
|
+
}
|
|
119049
|
+
else if (c.get() instanceof core_1.Expressions.Source) {
|
|
119050
|
+
row += `.set(${traversal.traverse(c).getCode()})`;
|
|
119051
|
+
}
|
|
119052
|
+
else if (c.get() instanceof core_1.Expressions.FieldAssignment && c instanceof core_1.Nodes.ExpressionNode) {
|
|
119053
|
+
row += new field_assignment_1.FieldAssignmentTranspiler().transpile(c, traversal).getCode();
|
|
119054
|
+
}
|
|
118914
119055
|
}
|
|
118915
119056
|
return ret;
|
|
118916
119057
|
}
|
|
@@ -135039,6 +135180,9 @@ class ClassImplementationTranspiler {
|
|
|
135039
135180
|
transpile(node, traversal) {
|
|
135040
135181
|
const ret = new chunk_1.Chunk();
|
|
135041
135182
|
for (const c of node.getChildren()) {
|
|
135183
|
+
if (c.get() instanceof abaplint.Statements.EndClass) {
|
|
135184
|
+
ret.appendString(this.buildPartiallyImplementedStubs(node, traversal));
|
|
135185
|
+
}
|
|
135042
135186
|
ret.appendChunk(traversal.traverse(c));
|
|
135043
135187
|
if (c.get() instanceof abaplint.Statements.ClassImplementation) {
|
|
135044
135188
|
ret.appendString(this.buildConstructor(node.getFirstStatement(), traversal));
|
|
@@ -135054,6 +135198,103 @@ class ClassImplementationTranspiler {
|
|
|
135054
135198
|
return ret;
|
|
135055
135199
|
}
|
|
135056
135200
|
///////////////////////////////
|
|
135201
|
+
/** INTERFACES ... PARTIALLY IMPLEMENTED: the interface methods the test class
|
|
135202
|
+
* does not implement exist on a system and raise CX_SY_DYN_CALL_ILLEGAL_METHOD
|
|
135203
|
+
* when called. Emits a method of that shape under the name the implementation
|
|
135204
|
+
* would have had, so the call ends in that exception and not in a TypeError */
|
|
135205
|
+
buildPartiallyImplementedStubs(node, traversal) {
|
|
135206
|
+
const token = node.findFirstExpression(abaplint.Expressions.ClassName)?.getFirstToken();
|
|
135207
|
+
if (token === undefined) {
|
|
135208
|
+
return "";
|
|
135209
|
+
}
|
|
135210
|
+
const cdef = traversal.getClassDefinition(token);
|
|
135211
|
+
const scope = traversal.findCurrentScopeByToken(token);
|
|
135212
|
+
if (cdef === undefined || scope === undefined) {
|
|
135213
|
+
return "";
|
|
135214
|
+
}
|
|
135215
|
+
const partial = cdef.getImplementing().filter(i => i.partial === true);
|
|
135216
|
+
if (partial.length === 0) {
|
|
135217
|
+
return "";
|
|
135218
|
+
}
|
|
135219
|
+
// the methods the class implements itself, by the emitted name
|
|
135220
|
+
const implemented = new Set();
|
|
135221
|
+
for (const m of node.findAllStatements(abaplint.Statements.MethodImplementation)) {
|
|
135222
|
+
const name = m.findFirstExpression(abaplint.Expressions.MethodName)?.getFirstToken().getStr();
|
|
135223
|
+
if (name !== undefined) {
|
|
135224
|
+
implemented.add(traversal_1.Traversal.escapeNamespace(name.replace("~", "$").toLowerCase()));
|
|
135225
|
+
}
|
|
135226
|
+
}
|
|
135227
|
+
// an interface a superclass implements is inherited, with the real implementations,
|
|
135228
|
+
// a stub for one of its methods would override those
|
|
135229
|
+
const inherited = new Set();
|
|
135230
|
+
let sup = cdef.getSuperClass();
|
|
135231
|
+
while (sup !== undefined) {
|
|
135232
|
+
const sdef = traversal.findClassDefinition(sup, scope);
|
|
135233
|
+
for (const name of this.findIncludedInterfaces(sdef?.getImplementing().map(i => i.name) || [], scope, traversal)) {
|
|
135234
|
+
inherited.add(name);
|
|
135235
|
+
}
|
|
135236
|
+
sup = sdef?.getSuperClass();
|
|
135237
|
+
}
|
|
135238
|
+
let ret = "";
|
|
135239
|
+
for (const name of this.findIncludedInterfaces(partial.map(i => i.name), scope, traversal)) {
|
|
135240
|
+
if (inherited.has(name)) {
|
|
135241
|
+
continue;
|
|
135242
|
+
}
|
|
135243
|
+
const intf = traversal.findInterfaceDefinition(name, scope);
|
|
135244
|
+
if (intf === undefined) {
|
|
135245
|
+
continue;
|
|
135246
|
+
}
|
|
135247
|
+
const prefix = traversal_1.Traversal.escapeNamespace(intf.getName().toLowerCase()) + "$";
|
|
135248
|
+
for (const m of intf.getMethodDefinitions().getAll()) {
|
|
135249
|
+
const emitted = prefix + traversal_1.Traversal.escapeNamespace(m.getName().toLowerCase());
|
|
135250
|
+
if (implemented.has(emitted)) {
|
|
135251
|
+
continue;
|
|
135252
|
+
}
|
|
135253
|
+
implemented.add(emitted);
|
|
135254
|
+
ret += this.buildNotImplementedMethod(emitted, m, token.getStr().toLowerCase(), intf.getName(), token, traversal);
|
|
135255
|
+
}
|
|
135256
|
+
}
|
|
135257
|
+
return ret;
|
|
135258
|
+
}
|
|
135259
|
+
/** the interfaces, upper cased, with the interfaces they include, recursively */
|
|
135260
|
+
findIncludedInterfaces(names, scope, traversal) {
|
|
135261
|
+
const ret = [];
|
|
135262
|
+
const queue = [...names];
|
|
135263
|
+
while (queue.length > 0) {
|
|
135264
|
+
const name = queue.shift().toUpperCase();
|
|
135265
|
+
if (ret.includes(name)) {
|
|
135266
|
+
continue;
|
|
135267
|
+
}
|
|
135268
|
+
ret.push(name);
|
|
135269
|
+
const intf = traversal.findInterfaceDefinition(name, scope);
|
|
135270
|
+
queue.push(...(intf?.getImplementing().map(i => i.name) || []));
|
|
135271
|
+
}
|
|
135272
|
+
return ret;
|
|
135273
|
+
}
|
|
135274
|
+
/** the method a system generates for an interface method the test class leaves
|
|
135275
|
+
* out under PARTIALLY IMPLEMENTED: calling it raises CX_SY_DYN_CALL_ILLEGAL_METHOD
|
|
135276
|
+
* (ABAP keyword documentation, INTERFACES - PARTIALLY IMPLEMENTED), the class and
|
|
135277
|
+
* method named, instead of a JavaScript TypeError no CATCH sees */
|
|
135278
|
+
buildNotImplementedMethod(emitted, m, className, interfaceName, token, traversal) {
|
|
135279
|
+
const unique = m.getParameters().getAll().length > 0 ? "INPUT" : "";
|
|
135280
|
+
const exception = traversal.lookupClassOrInterface("'CX_SY_DYN_CALL_ILLEGAL_METHOD'", token, true);
|
|
135281
|
+
const classUpper = className.toUpperCase();
|
|
135282
|
+
const methodUpper = interfaceName.toUpperCase() + "~" + m.getName().toUpperCase();
|
|
135283
|
+
const notFound = `CX_SY_DYN_CALL_ILLEGAL_METHOD not found, ${classUpper}->${methodUpper} is not implemented`;
|
|
135284
|
+
const body = `if (${exception} === undefined) { throw new Error("${notFound}"); }\n` +
|
|
135285
|
+
`throw await new ${exception}().constructor_({` +
|
|
135286
|
+
`classname: new abap.types.String().set("${classUpper}"), ` +
|
|
135287
|
+
`methodname: new abap.types.String().set("${methodUpper}")});\n`;
|
|
135288
|
+
let ret = "";
|
|
135289
|
+
if (m.isStatic() === true) {
|
|
135290
|
+
// in ABAP static methods can be called with instance arrows, "->"
|
|
135291
|
+
ret += "async " + emitted + "(" + unique + ") {\n" +
|
|
135292
|
+
"return " + traversal_1.Traversal.escapeNamespace(className) + "." + emitted + "(" + unique + ");\n" +
|
|
135293
|
+
"}\n" + "static ";
|
|
135294
|
+
}
|
|
135295
|
+
ret += "async " + emitted + "(" + unique + ") {\n" + body + "}\n";
|
|
135296
|
+
return ret;
|
|
135297
|
+
}
|
|
135057
135298
|
hasConstructor(node) {
|
|
135058
135299
|
for (const m of node.findAllStatements(abaplint.Statements.MethodImplementation)) {
|
|
135059
135300
|
const name = m.findFirstExpression(abaplint.Expressions.MethodName)?.getFirstToken().getStr();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/transpiler-cli",
|
|
3
|
-
"version": "2.14.
|
|
3
|
+
"version": "2.14.12",
|
|
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.87",
|
|
31
|
+
"@abaplint/transpiler": "^2.14.12",
|
|
32
32
|
"@types/glob": "^9.0.0",
|
|
33
33
|
"@types/node": "^26.6.5",
|
|
34
34
|
"@types/progress": "^2.0.7",
|