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