@abaplint/cli 2.120.27 → 2.120.29
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/cli.js +294 -41
- package/package.json +2 -2
package/build/cli.js
CHANGED
|
@@ -9079,7 +9079,7 @@ const sql_field_1 = __webpack_require__(/*! ./sql_field */ "../core/build/src/ab
|
|
|
9079
9079
|
const sql_grouping_sets_1 = __webpack_require__(/*! ./sql_grouping_sets */ "../core/build/src/abap/2_statements/expressions/sql_grouping_sets.js");
|
|
9080
9080
|
class SQLGroupBy extends combi_1.Expression {
|
|
9081
9081
|
getRunnable() {
|
|
9082
|
-
const fieldName = (0, combi_1.alt)(sql_field_name_1.SQLFieldName, dynamic_1.Dynamic);
|
|
9082
|
+
const fieldName = (0, combi_1.seq)((0, combi_1.stopBefore)("ORDER", "BY"), (0, combi_1.alt)(sql_field_name_1.SQLFieldName, dynamic_1.Dynamic));
|
|
9083
9083
|
const expr = (0, combi_1.ver)(version_1.Release.v740sp02, sql_field_1.SQLField, { also: combi_1.AlsoIn.OpenABAP });
|
|
9084
9084
|
const newGroup = (0, combi_1.ver)(version_1.Release.v740sp02, (0, combi_1.seq)("GROUP BY", expr, (0, combi_1.altPrio)((0, combi_1.plus)((0, combi_1.seq)(",", expr)), (0, combi_1.optPrio)((0, combi_1.plus)(fieldName)))), { also: combi_1.AlsoIn.OpenABAP });
|
|
9085
9085
|
const old = (0, combi_1.seq)((0, combi_1.plus)((0, combi_1.seq)(fieldName, ",")), fieldName);
|
|
@@ -26676,6 +26676,31 @@ class ObjectOriented {
|
|
|
26676
26676
|
}
|
|
26677
26677
|
return ret;
|
|
26678
26678
|
}
|
|
26679
|
+
// does the supplied class have friendship with "friendName"?
|
|
26680
|
+
// note that interfaces of the friend, and subclasses of the friend also have friendship
|
|
26681
|
+
hasFriendship(cd, friendName) {
|
|
26682
|
+
var _a;
|
|
26683
|
+
const friends = cd.getFriends().map(f => f.toUpperCase());
|
|
26684
|
+
const isFriend = (name) => friends.includes(name.toUpperCase()) || this.scope.isLocalFriend(cd.getName(), name);
|
|
26685
|
+
if (isFriend(friendName)) {
|
|
26686
|
+
return true;
|
|
26687
|
+
}
|
|
26688
|
+
const friendDefinition = this.scope.findClassDefinition(friendName);
|
|
26689
|
+
if (friendDefinition === undefined) {
|
|
26690
|
+
return false;
|
|
26691
|
+
}
|
|
26692
|
+
if (this.findInterfaces(friendDefinition).some(i => friends.includes(i.name.toUpperCase()))) {
|
|
26693
|
+
return true;
|
|
26694
|
+
}
|
|
26695
|
+
let sup = friendDefinition.getSuperClass();
|
|
26696
|
+
while (sup !== undefined) {
|
|
26697
|
+
if (isFriend(sup)) {
|
|
26698
|
+
return true;
|
|
26699
|
+
}
|
|
26700
|
+
sup = (_a = this.scope.findClassDefinition(sup)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
|
|
26701
|
+
}
|
|
26702
|
+
return false;
|
|
26703
|
+
}
|
|
26679
26704
|
searchEvent(def, name) {
|
|
26680
26705
|
if (def === undefined || name === undefined) {
|
|
26681
26706
|
return undefined;
|
|
@@ -27865,6 +27890,9 @@ class TypeUtils {
|
|
|
27865
27890
|
console.dir(source);
|
|
27866
27891
|
console.dir(target);
|
|
27867
27892
|
*/
|
|
27893
|
+
if (source instanceof basic_1.UTCLongType || target instanceof basic_1.UTCLongType) {
|
|
27894
|
+
return this.isUTCLongAssignable(source, target);
|
|
27895
|
+
}
|
|
27868
27896
|
if (target instanceof basic_1.TableType) {
|
|
27869
27897
|
if (target.isWithHeader()) {
|
|
27870
27898
|
return this.isAssignable(source, target.getRowType());
|
|
@@ -28016,6 +28044,33 @@ class TypeUtils {
|
|
|
28016
28044
|
}
|
|
28017
28045
|
return true;
|
|
28018
28046
|
}
|
|
28047
|
+
// utclong can only be converted to and from character like types
|
|
28048
|
+
isUTCLongAssignable(source, target) {
|
|
28049
|
+
if (this.isGenericOrVoid(source) || this.isGenericOrVoid(target)) {
|
|
28050
|
+
return true;
|
|
28051
|
+
}
|
|
28052
|
+
else if (source instanceof basic_1.UTCLongType && target instanceof basic_1.UTCLongType) {
|
|
28053
|
+
return true;
|
|
28054
|
+
}
|
|
28055
|
+
else if (source instanceof basic_1.UTCLongType) {
|
|
28056
|
+
return this.isTextLike(target);
|
|
28057
|
+
}
|
|
28058
|
+
return this.isTextLike(source);
|
|
28059
|
+
}
|
|
28060
|
+
isGenericOrVoid(type) {
|
|
28061
|
+
return type instanceof basic_1.VoidType
|
|
28062
|
+
|| type instanceof basic_1.AnyType
|
|
28063
|
+
|| type instanceof basic_1.DataType
|
|
28064
|
+
|| type instanceof basic_1.UnknownType;
|
|
28065
|
+
}
|
|
28066
|
+
isTextLike(type) {
|
|
28067
|
+
return type instanceof basic_1.CharacterType
|
|
28068
|
+
|| type instanceof basic_1.StringType
|
|
28069
|
+
|| type instanceof basic_1.CLikeType
|
|
28070
|
+
|| type instanceof basic_1.CSequenceType
|
|
28071
|
+
|| type instanceof cgeneric_type_1.CGenericType
|
|
28072
|
+
|| type instanceof basic_1.SimpleType;
|
|
28073
|
+
}
|
|
28019
28074
|
}
|
|
28020
28075
|
exports.TypeUtils = TypeUtils;
|
|
28021
28076
|
//# sourceMappingURL=_type_utils.js.map
|
|
@@ -29137,7 +29192,7 @@ function checkDatabaseFields(fields, dbSources, input, token) {
|
|
|
29137
29192
|
if (field === "*") {
|
|
29138
29193
|
continue;
|
|
29139
29194
|
}
|
|
29140
|
-
if (
|
|
29195
|
+
if (/^[A-Z_]\w*$/i.test(field) && type.getComponentByName(field) === undefined) {
|
|
29141
29196
|
const message = `checkFields, field ${field} not found`;
|
|
29142
29197
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
|
|
29143
29198
|
return;
|
|
@@ -32311,6 +32366,8 @@ const _reference_1 = __webpack_require__(/*! ../_reference */ "../core/build/src
|
|
|
32311
32366
|
const component_name_1 = __webpack_require__(/*! ./component_name */ "../core/build/src/abap/5_syntax/expressions/component_name.js");
|
|
32312
32367
|
const attribute_name_1 = __webpack_require__(/*! ./attribute_name */ "../core/build/src/abap/5_syntax/expressions/attribute_name.js");
|
|
32313
32368
|
const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
|
|
32369
|
+
const visibility_1 = __webpack_require__(/*! ../../4_file_information/visibility */ "../core/build/src/abap/4_file_information/visibility.js");
|
|
32370
|
+
const class_definition_1 = __webpack_require__(/*! ../../types/class_definition */ "../core/build/src/abap/types/class_definition.js");
|
|
32314
32371
|
class MethodCallChain {
|
|
32315
32372
|
static runSyntax(node, input, targetType) {
|
|
32316
32373
|
var _a, _b;
|
|
@@ -32359,6 +32416,12 @@ class MethodCallChain {
|
|
|
32359
32416
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, methodToken, message));
|
|
32360
32417
|
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
32361
32418
|
}
|
|
32419
|
+
const notVisible = method ? this.checkVisibility(method, def, foundDef, input) : undefined;
|
|
32420
|
+
if (notVisible !== undefined) {
|
|
32421
|
+
const message = `Method "${methodName}" is ${notVisible} and cannot be accessed`;
|
|
32422
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, methodToken, message));
|
|
32423
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
32424
|
+
}
|
|
32362
32425
|
const voidedName = context instanceof basic_1.VoidType ? context.getVoided() : undefined;
|
|
32363
32426
|
const extra = helper.methodReferenceExtras(foundDef, className || voidedName);
|
|
32364
32427
|
input.scope.addReference(methodToken, method, _reference_1.ReferenceType.MethodReference, input.filename, extra);
|
|
@@ -32401,6 +32464,47 @@ class MethodCallChain {
|
|
|
32401
32464
|
return context;
|
|
32402
32465
|
}
|
|
32403
32466
|
//////////////////////////////////////
|
|
32467
|
+
// returns the visibility as text if the method cannot be accessed from the current scope
|
|
32468
|
+
static checkVisibility(method, def, foundDef, input) {
|
|
32469
|
+
var _a, _b, _c;
|
|
32470
|
+
const visibility = method.getVisibility();
|
|
32471
|
+
if (visibility === visibility_1.Visibility.Public || foundDef === undefined) {
|
|
32472
|
+
return undefined;
|
|
32473
|
+
}
|
|
32474
|
+
else if (!(foundDef instanceof class_definition_1.ClassDefinition)) {
|
|
32475
|
+
// interface members are always public
|
|
32476
|
+
return undefined;
|
|
32477
|
+
}
|
|
32478
|
+
const name = foundDef.getName().toUpperCase();
|
|
32479
|
+
const enclosing = (_a = input.scope.getEnclosingClassName()) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
32480
|
+
if (enclosing === undefined || enclosing === name) {
|
|
32481
|
+
return undefined;
|
|
32482
|
+
}
|
|
32483
|
+
// friendship with the class used at the call site also gives access to inherited members
|
|
32484
|
+
const helper = new _object_oriented_1.ObjectOriented(input.scope);
|
|
32485
|
+
const visited = [];
|
|
32486
|
+
let current = def instanceof class_definition_1.ClassDefinition ? def : foundDef;
|
|
32487
|
+
while (current !== undefined && visited.includes(current.getName().toUpperCase()) === false) {
|
|
32488
|
+
visited.push(current.getName().toUpperCase());
|
|
32489
|
+
if (helper.hasFriendship(current, enclosing)) {
|
|
32490
|
+
return undefined;
|
|
32491
|
+
}
|
|
32492
|
+
const sup = current.getSuperClass();
|
|
32493
|
+
current = sup === undefined ? undefined : input.scope.findClassDefinition(sup);
|
|
32494
|
+
}
|
|
32495
|
+
if (visibility === visibility_1.Visibility.Protected) {
|
|
32496
|
+
// subclasses can access protected members
|
|
32497
|
+
let sup = (_b = input.scope.findClassDefinition(enclosing)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
|
|
32498
|
+
while (sup !== undefined) {
|
|
32499
|
+
if (sup.toUpperCase() === name) {
|
|
32500
|
+
return undefined;
|
|
32501
|
+
}
|
|
32502
|
+
sup = (_c = input.scope.findClassDefinition(sup)) === null || _c === void 0 ? void 0 : _c.getSuperClass();
|
|
32503
|
+
}
|
|
32504
|
+
return "protected";
|
|
32505
|
+
}
|
|
32506
|
+
return "private";
|
|
32507
|
+
}
|
|
32404
32508
|
static findTop(first, input, targetType) {
|
|
32405
32509
|
var _a;
|
|
32406
32510
|
if (first.get() instanceof Expressions.ClassName) {
|
|
@@ -33823,7 +33927,7 @@ class Select {
|
|
|
33823
33927
|
return;
|
|
33824
33928
|
}
|
|
33825
33929
|
(0, _check_database_fields_1.checkDatabaseFields)(fields.map(field => field.code), dbSources, input, node.getFirstToken());
|
|
33826
|
-
const intoExpression = this.handleInto(node, input, fields, dbSources);
|
|
33930
|
+
const intoExpression = this.handleInto(node, input, fields, dbSources, from);
|
|
33827
33931
|
const fae = node.findDirectExpression(Expressions.SQLForAllEntries);
|
|
33828
33932
|
if (fae) {
|
|
33829
33933
|
input.scope.push(_scope_type_1.ScopeType.OpenSQL, "SELECT", token.getStart(), input.filename);
|
|
@@ -33984,12 +34088,12 @@ class Select {
|
|
|
33984
34088
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
33985
34089
|
}
|
|
33986
34090
|
}
|
|
33987
|
-
static handleInto(node, input, fields, dbSources) {
|
|
34091
|
+
static handleInto(node, input, fields, dbSources, from) {
|
|
33988
34092
|
const intoTable = node.findDirectExpression(Expressions.SQLIntoTable);
|
|
33989
34093
|
if (intoTable) {
|
|
33990
34094
|
const inline = intoTable.findFirstExpression(Expressions.InlineData);
|
|
33991
34095
|
if (inline) {
|
|
33992
|
-
inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope));
|
|
34096
|
+
inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope, from));
|
|
33993
34097
|
}
|
|
33994
34098
|
return intoTable;
|
|
33995
34099
|
}
|
|
@@ -34137,11 +34241,36 @@ class Select {
|
|
|
34137
34241
|
return basic_1.VoidType.get("SELECT_todo13");
|
|
34138
34242
|
}
|
|
34139
34243
|
}
|
|
34140
|
-
static buildTableType(fields, dbSources, scope) {
|
|
34141
|
-
|
|
34244
|
+
static buildTableType(fields, dbSources, scope, from) {
|
|
34245
|
+
var _a;
|
|
34246
|
+
const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
|
|
34247
|
+
if (dbSources.length > 1) {
|
|
34248
|
+
const sourceInfos = this.buildDatabaseSourceInfos(from, dbSources);
|
|
34249
|
+
if (fields.length === 1 && fields[0].code === "*") {
|
|
34250
|
+
const components = [];
|
|
34251
|
+
for (const info of sourceInfos) {
|
|
34252
|
+
const type = (_a = info.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
|
|
34253
|
+
if (!(type instanceof basic_1.StructureType)) {
|
|
34254
|
+
return basic_1.VoidType.get("SELECT_todo3");
|
|
34255
|
+
}
|
|
34256
|
+
components.push({ name: info.alias || info.name, type });
|
|
34257
|
+
}
|
|
34258
|
+
return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
|
|
34259
|
+
}
|
|
34260
|
+
const components = [];
|
|
34261
|
+
for (const field of fields) {
|
|
34262
|
+
const type = this.findFieldType(field.code, sourceInfos, scope);
|
|
34263
|
+
if (type === undefined) {
|
|
34264
|
+
return basic_1.VoidType.get("SELECT_todo3");
|
|
34265
|
+
}
|
|
34266
|
+
const name = field.as || field.code.split("~").pop();
|
|
34267
|
+
components.push({ name, type });
|
|
34268
|
+
}
|
|
34269
|
+
return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
|
|
34270
|
+
}
|
|
34271
|
+
else if (dbSources.length !== 1) {
|
|
34142
34272
|
return basic_1.VoidType.get("SELECT_todo3");
|
|
34143
34273
|
}
|
|
34144
|
-
const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
|
|
34145
34274
|
if (dbSources[0] === undefined) {
|
|
34146
34275
|
// then its a voided table
|
|
34147
34276
|
return new basic_1.TableType(basic_1.VoidType.get("SELECT_todo4"), tableOptions, undefined);
|
|
@@ -34167,6 +34296,39 @@ class Select {
|
|
|
34167
34296
|
}
|
|
34168
34297
|
return basic_1.VoidType.get("SELECT_todo7");
|
|
34169
34298
|
}
|
|
34299
|
+
static buildDatabaseSourceInfos(from, dbSources) {
|
|
34300
|
+
const fromSources = from.findAllExpressions(Expressions.SQLFromSource);
|
|
34301
|
+
return dbSources.map((source, index) => {
|
|
34302
|
+
var _a, _b;
|
|
34303
|
+
const fromSource = fromSources[index];
|
|
34304
|
+
const name = ((_a = fromSource === null || fromSource === void 0 ? void 0 : fromSource.findFirstExpression(Expressions.DatabaseTable)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStr().replace(/^\*/, "").toUpperCase()) || "";
|
|
34305
|
+
const alias = ((_b = fromSource === null || fromSource === void 0 ? void 0 : fromSource.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase()) || "";
|
|
34306
|
+
return { source, name, alias };
|
|
34307
|
+
});
|
|
34308
|
+
}
|
|
34309
|
+
static findFieldType(code, sourceInfos, scope) {
|
|
34310
|
+
var _a;
|
|
34311
|
+
const separator = code.indexOf("~");
|
|
34312
|
+
const qualifier = separator >= 0 ? code.substring(0, separator) : undefined;
|
|
34313
|
+
const fieldName = separator >= 0 ? code.substring(separator + 1) : code;
|
|
34314
|
+
const candidates = qualifier === undefined
|
|
34315
|
+
? sourceInfos
|
|
34316
|
+
: sourceInfos.filter(info => info.alias === qualifier || info.name === qualifier);
|
|
34317
|
+
for (const candidate of candidates) {
|
|
34318
|
+
let type = (_a = candidate.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
|
|
34319
|
+
for (const component of fieldName.split("-")) {
|
|
34320
|
+
if (!(type instanceof basic_1.StructureType)) {
|
|
34321
|
+
type = undefined;
|
|
34322
|
+
break;
|
|
34323
|
+
}
|
|
34324
|
+
type = type.getComponentByName(component);
|
|
34325
|
+
}
|
|
34326
|
+
if (type) {
|
|
34327
|
+
return type;
|
|
34328
|
+
}
|
|
34329
|
+
}
|
|
34330
|
+
return undefined;
|
|
34331
|
+
}
|
|
34170
34332
|
static findFields(node, input) {
|
|
34171
34333
|
var _a, _b;
|
|
34172
34334
|
let expr = undefined;
|
|
@@ -34180,7 +34342,7 @@ class Select {
|
|
|
34180
34342
|
let code = field.concatTokens().toUpperCase();
|
|
34181
34343
|
const as = ((_b = field.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens()) || "";
|
|
34182
34344
|
if (as !== "") {
|
|
34183
|
-
code = code.replace(" AS " + as, "");
|
|
34345
|
+
code = code.replace(" AS " + as.toUpperCase(), "");
|
|
34184
34346
|
}
|
|
34185
34347
|
ret.push({ code, as, expression: field });
|
|
34186
34348
|
}
|
|
@@ -35011,6 +35173,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/
|
|
|
35011
35173
|
const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
|
|
35012
35174
|
const sql_set_op_group_1 = __webpack_require__(/*! ./sql_set_op_group */ "../core/build/src/abap/5_syntax/expressions/sql_set_op_group.js");
|
|
35013
35175
|
const sql_source_1 = __webpack_require__(/*! ./sql_source */ "../core/build/src/abap/5_syntax/expressions/sql_source.js");
|
|
35176
|
+
const RANGE_COMPONENTS = ["SIGN", "OPTION", "LOW", "HIGH"];
|
|
35014
35177
|
class SQLIn {
|
|
35015
35178
|
static runSyntax(node, input) {
|
|
35016
35179
|
const setop = node.findDirectExpression(Expressions.SQLSetOpGroup);
|
|
@@ -35030,6 +35193,12 @@ class SQLIn {
|
|
|
35030
35193
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
35031
35194
|
return;
|
|
35032
35195
|
}
|
|
35196
|
+
if (intype instanceof basic_1.TableType && this.isRangeRow(intype.getRowType()) === false) {
|
|
35197
|
+
const name = insource.concatTokens().replace(/^@/, "").replace(/\[\]$/, "");
|
|
35198
|
+
const message = `row structure of ${name} is not correct`;
|
|
35199
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
35200
|
+
return;
|
|
35201
|
+
}
|
|
35033
35202
|
}
|
|
35034
35203
|
return;
|
|
35035
35204
|
}
|
|
@@ -35040,6 +35209,16 @@ class SQLIn {
|
|
|
35040
35209
|
sql_source_1.SQLSource.runSyntax(s, input);
|
|
35041
35210
|
}
|
|
35042
35211
|
}
|
|
35212
|
+
// "IN itab" expects a ranges table, ie. the row must have SIGN, OPTION, LOW and HIGH
|
|
35213
|
+
static isRangeRow(rowType) {
|
|
35214
|
+
if (rowType instanceof basic_1.VoidType || rowType instanceof basic_1.UnknownType || rowType instanceof basic_1.AnyType) {
|
|
35215
|
+
return true;
|
|
35216
|
+
}
|
|
35217
|
+
else if (!(rowType instanceof basic_1.StructureType)) {
|
|
35218
|
+
return false;
|
|
35219
|
+
}
|
|
35220
|
+
return RANGE_COMPONENTS.every(c => rowType.getComponentByName(c) !== undefined);
|
|
35221
|
+
}
|
|
35043
35222
|
}
|
|
35044
35223
|
exports.SQLIn = SQLIn;
|
|
35045
35224
|
//# sourceMappingURL=sql_in.js.map
|
|
@@ -35936,6 +36115,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35936
36115
|
})();
|
|
35937
36116
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
35938
36117
|
exports.ValueBody = void 0;
|
|
36118
|
+
const nodes_1 = __webpack_require__(/*! ../../nodes */ "../core/build/src/abap/nodes/index.js");
|
|
35939
36119
|
const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expressions */ "../core/build/src/abap/2_statements/expressions/index.js"));
|
|
35940
36120
|
const for_1 = __webpack_require__(/*! ./for */ "../core/build/src/abap/5_syntax/expressions/for.js");
|
|
35941
36121
|
const source_1 = __webpack_require__(/*! ./source */ "../core/build/src/abap/5_syntax/expressions/source.js");
|
|
@@ -35945,7 +36125,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/
|
|
|
35945
36125
|
const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
|
|
35946
36126
|
class ValueBody {
|
|
35947
36127
|
static runSyntax(node, input, targetType) {
|
|
35948
|
-
var _a, _b;
|
|
36128
|
+
var _a, _b, _c;
|
|
35949
36129
|
if (node === undefined) {
|
|
35950
36130
|
return targetType;
|
|
35951
36131
|
}
|
|
@@ -35962,26 +36142,45 @@ class ValueBody {
|
|
|
35962
36142
|
}
|
|
35963
36143
|
}
|
|
35964
36144
|
const fields = new Set();
|
|
35965
|
-
|
|
35966
|
-
|
|
35967
|
-
if (
|
|
35968
|
-
|
|
35969
|
-
|
|
36145
|
+
const hasTableLines = node.findDirectExpression(Expressions.ValueBodyLine) !== undefined;
|
|
36146
|
+
for (const child of node.getChildren()) {
|
|
36147
|
+
if (!(child instanceof nodes_1.ExpressionNode)) {
|
|
36148
|
+
continue;
|
|
36149
|
+
}
|
|
36150
|
+
else if (child.get() instanceof Expressions.FieldAssignment) {
|
|
36151
|
+
const fieldname = (_a = child.findDirectExpression(Expressions.FieldSub)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
36152
|
+
if (fieldname && hasTableLines === false && fields.has(fieldname)) {
|
|
36153
|
+
const message = "Duplicate field assignment";
|
|
36154
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, child.getFirstToken(), message));
|
|
36155
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
36156
|
+
}
|
|
35970
36157
|
if (fieldname) {
|
|
35971
|
-
|
|
36158
|
+
fields.add(fieldname);
|
|
36159
|
+
}
|
|
36160
|
+
}
|
|
36161
|
+
else if (child.get() instanceof Expressions.ValueBodyLine) {
|
|
36162
|
+
const rowFields = new Set(fields);
|
|
36163
|
+
for (const assignment of child.findDirectExpressions(Expressions.FieldAssignment)) {
|
|
36164
|
+
const fieldname = (_b = assignment.findDirectExpression(Expressions.FieldSub)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
|
|
36165
|
+
if (fieldname && rowFields.has(fieldname)) {
|
|
35972
36166
|
const message = "Duplicate field assignment";
|
|
35973
|
-
input.issues.push((0, _syntax_input_1.syntaxIssue)(input,
|
|
36167
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, assignment.getFirstToken(), message));
|
|
35974
36168
|
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
35975
36169
|
}
|
|
35976
|
-
|
|
36170
|
+
if (fieldname) {
|
|
36171
|
+
rowFields.add(fieldname);
|
|
36172
|
+
}
|
|
35977
36173
|
}
|
|
35978
36174
|
}
|
|
35979
36175
|
}
|
|
36176
|
+
for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
|
|
36177
|
+
field_assignment_1.FieldAssignment.runSyntax(s, input, targetType);
|
|
36178
|
+
}
|
|
35980
36179
|
let type = undefined; // todo, this is only correct if there is a single source in the body
|
|
35981
36180
|
for (const s of node.findDirectExpressions(Expressions.Source)) {
|
|
35982
36181
|
type = source_1.Source.runSyntax(s, input, type);
|
|
35983
36182
|
}
|
|
35984
|
-
for (const s of ((
|
|
36183
|
+
for (const s of ((_c = node.findDirectExpression(Expressions.ValueBase)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.Source)) || []) {
|
|
35985
36184
|
type = source_1.Source.runSyntax(s, input, type);
|
|
35986
36185
|
}
|
|
35987
36186
|
for (const foo of node.findDirectExpressions(Expressions.ValueBodyLine)) {
|
|
@@ -39098,7 +39297,7 @@ class CreateObject {
|
|
|
39098
39297
|
this.validateParameters(cdef, node, input);
|
|
39099
39298
|
}
|
|
39100
39299
|
static checkInstantiationAllowed(cdef, input) {
|
|
39101
|
-
var _a, _b
|
|
39300
|
+
var _a, _b;
|
|
39102
39301
|
const createVis = cdef.getCreateVisibility();
|
|
39103
39302
|
if (createVis === visibility_1.Visibility.Public) {
|
|
39104
39303
|
return undefined;
|
|
@@ -39111,34 +39310,17 @@ class CreateObject {
|
|
|
39111
39310
|
if (enclosingClass.toUpperCase() === cdef.getName().toUpperCase()) {
|
|
39112
39311
|
return undefined;
|
|
39113
39312
|
}
|
|
39114
|
-
if (
|
|
39115
|
-
input.scope.isLocalFriend(cdef.getName(), enclosingClass)) {
|
|
39313
|
+
if (new _object_oriented_1.ObjectOriented(input.scope).hasFriendship(cdef, enclosingClass)) {
|
|
39116
39314
|
return undefined;
|
|
39117
39315
|
}
|
|
39118
|
-
const enclosingDefinition = input.scope.findClassDefinition(enclosingClass);
|
|
39119
|
-
if (enclosingDefinition !== undefined) {
|
|
39120
|
-
const implementedInterfaces = new _object_oriented_1.ObjectOriented(input.scope).findInterfaces(enclosingDefinition);
|
|
39121
|
-
if (cdef.getFriends().some(friend => implementedInterfaces.some(implemented => implemented.name.toUpperCase() === friend.toUpperCase()))) {
|
|
39122
|
-
return undefined;
|
|
39123
|
-
}
|
|
39124
|
-
}
|
|
39125
|
-
// subclasses of friends also have friendship
|
|
39126
|
-
let enclosingSup = enclosingDefinition === null || enclosingDefinition === void 0 ? void 0 : enclosingDefinition.getSuperClass();
|
|
39127
|
-
while (enclosingSup !== undefined) {
|
|
39128
|
-
if (cdef.getFriends().some(f => f.toUpperCase() === enclosingSup.toUpperCase()) ||
|
|
39129
|
-
input.scope.isLocalFriend(cdef.getName(), enclosingSup)) {
|
|
39130
|
-
return undefined;
|
|
39131
|
-
}
|
|
39132
|
-
enclosingSup = (_a = input.scope.findClassDefinition(enclosingSup)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
|
|
39133
|
-
}
|
|
39134
39316
|
if (createVis === visibility_1.Visibility.Protected) {
|
|
39135
39317
|
// subclasses are also allowed
|
|
39136
|
-
let sup = (
|
|
39318
|
+
let sup = (_a = input.scope.findClassDefinition(enclosingClass)) === null || _a === void 0 ? void 0 : _a.getSuperClass();
|
|
39137
39319
|
while (sup !== undefined) {
|
|
39138
39320
|
if (sup.toUpperCase() === cdef.getName().toUpperCase()) {
|
|
39139
39321
|
return undefined;
|
|
39140
39322
|
}
|
|
39141
|
-
sup = (
|
|
39323
|
+
sup = (_b = input.scope.findClassDefinition(sup)) === null || _b === void 0 ? void 0 : _b.getSuperClass();
|
|
39142
39324
|
}
|
|
39143
39325
|
}
|
|
39144
39326
|
return cdef.getName() + " cannot be instantiated, class is defined as " +
|
|
@@ -39402,6 +39584,7 @@ const source_1 = __webpack_require__(/*! ../expressions/source */ "../core/build
|
|
|
39402
39584
|
const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/build/src/abap/5_syntax/expressions/dynamic.js");
|
|
39403
39585
|
const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "../core/build/src/abap/5_syntax/expressions/database_table.js");
|
|
39404
39586
|
const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "../core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
|
|
39587
|
+
const sql_in_1 = __webpack_require__(/*! ../expressions/sql_in */ "../core/build/src/abap/5_syntax/expressions/sql_in.js");
|
|
39405
39588
|
class DeleteDatabase {
|
|
39406
39589
|
runSyntax(node, input) {
|
|
39407
39590
|
for (const s of node.findAllExpressions(Expressions.Source)) {
|
|
@@ -39413,6 +39596,12 @@ class DeleteDatabase {
|
|
|
39413
39596
|
for (const d of node.findAllExpressions(Expressions.Dynamic)) {
|
|
39414
39597
|
dynamic_1.Dynamic.runSyntax(d, input);
|
|
39415
39598
|
}
|
|
39599
|
+
for (const compare of node.findAllExpressions(Expressions.SQLCompare)) {
|
|
39600
|
+
const sqlin = compare.findDirectExpression(Expressions.SQLIn);
|
|
39601
|
+
if (sqlin !== undefined) {
|
|
39602
|
+
sql_in_1.SQLIn.runSyntax(sqlin, input);
|
|
39603
|
+
}
|
|
39604
|
+
}
|
|
39416
39605
|
const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
|
|
39417
39606
|
if (dbtab !== undefined) {
|
|
39418
39607
|
const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
|
|
@@ -69773,7 +69962,7 @@ class Registry {
|
|
|
69773
69962
|
}
|
|
69774
69963
|
static abaplintVersion() {
|
|
69775
69964
|
// magic, see build script "version.js"
|
|
69776
|
-
return "2.120.
|
|
69965
|
+
return "2.120.29";
|
|
69777
69966
|
}
|
|
69778
69967
|
getDDICReferences() {
|
|
69779
69968
|
return this.ddicReferences;
|
|
@@ -72460,6 +72649,11 @@ class CDSCheckSyntaxConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
|
72460
72649
|
exports.CDSCheckSyntaxConf = CDSCheckSyntaxConf;
|
|
72461
72650
|
const KNOWN_QUAN_DATA_ELEMENTS = ["MENGE_D"];
|
|
72462
72651
|
const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
|
|
72652
|
+
// Reserved names, cannot be used as element names, see DDIC table TRESE
|
|
72653
|
+
const RESERVED_ELEMENT_NAMES = ["BEGIN", "NUMBER", "POSITION"];
|
|
72654
|
+
const MAX_LABEL_LENGTH = 40;
|
|
72655
|
+
// Annotations which are not supported in CDS view entities
|
|
72656
|
+
const VIEW_ENTITY_FORBIDDEN_ANNOTATIONS = ["Semantics.unitOfMeasure"];
|
|
72463
72657
|
class CDSCheckSyntax {
|
|
72464
72658
|
constructor() {
|
|
72465
72659
|
this.conf = new CDSCheckSyntaxConf();
|
|
@@ -72501,6 +72695,9 @@ Missing objects are only reported when their names match the configured errorNam
|
|
|
72501
72695
|
this.checkTypes(tree, ddic, issues, file);
|
|
72502
72696
|
this.checkRootProjection(tree, ddic, issues, file);
|
|
72503
72697
|
this.checkFieldAnnotations(tree, ddic, issues, file);
|
|
72698
|
+
this.checkLabels(tree, issues, file);
|
|
72699
|
+
this.checkViewEntityAnnotations(tree, issues, file);
|
|
72700
|
+
this.checkReservedNames(tree, issues, file);
|
|
72504
72701
|
this.checkFields(tree, sources, object, issues, file);
|
|
72505
72702
|
return issues;
|
|
72506
72703
|
}
|
|
@@ -72685,6 +72882,62 @@ Missing objects are only reported when their names match the configured errorNam
|
|
|
72685
72882
|
|| a.toUpperCase().includes("@SEMANTICS:{CURRENCYCODE:TRUE"));
|
|
72686
72883
|
}
|
|
72687
72884
|
}
|
|
72885
|
+
checkLabels(tree, issues, file) {
|
|
72886
|
+
for (const annotation of tree.findAllExpressionsRecursive(expressions_1.CDSAnnotation)) {
|
|
72887
|
+
const concatenated = annotation.concatTokens();
|
|
72888
|
+
if (/@\s*<?\s*EndUserText/i.test(concatenated) === false) {
|
|
72889
|
+
continue;
|
|
72890
|
+
}
|
|
72891
|
+
const expression = /label\s*:\s*'((?:[^']|'')*)'/gi;
|
|
72892
|
+
let match = expression.exec(concatenated);
|
|
72893
|
+
while (match !== null) {
|
|
72894
|
+
const label = match[1].replace(/''/g, "'");
|
|
72895
|
+
if (label.length > MAX_LABEL_LENGTH) {
|
|
72896
|
+
const message = `CDS label is ${label.length} characters, maximum is ${MAX_LABEL_LENGTH}`;
|
|
72897
|
+
issues.push(issue_1.Issue.atToken(file, annotation.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72898
|
+
}
|
|
72899
|
+
match = expression.exec(concatenated);
|
|
72900
|
+
}
|
|
72901
|
+
}
|
|
72902
|
+
}
|
|
72903
|
+
checkViewEntityAnnotations(tree, issues, file) {
|
|
72904
|
+
const view = tree.findFirstExpression(expressions_1.CDSDefineView);
|
|
72905
|
+
if (view === undefined || view.findDirectTokenByText("ENTITY") === undefined) {
|
|
72906
|
+
return;
|
|
72907
|
+
}
|
|
72908
|
+
for (const annotation of tree.findAllExpressionsRecursive(expressions_1.CDSAnnotation)) {
|
|
72909
|
+
const normalized = annotation.concatTokens().replace(/\s/g, "").toUpperCase().replace(/^@</, "@");
|
|
72910
|
+
for (const forbidden of VIEW_ENTITY_FORBIDDEN_ANNOTATIONS) {
|
|
72911
|
+
const upper = forbidden.toUpperCase();
|
|
72912
|
+
if (normalized.startsWith("@" + upper) === false
|
|
72913
|
+
&& normalized.startsWith("@" + upper.replace(".", ":{")) === false) {
|
|
72914
|
+
continue;
|
|
72915
|
+
}
|
|
72916
|
+
const message = `Annotation ${forbidden} is not allowed in view entities`;
|
|
72917
|
+
issues.push(issue_1.Issue.atToken(file, annotation.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72918
|
+
}
|
|
72919
|
+
}
|
|
72920
|
+
}
|
|
72921
|
+
checkReservedNames(tree, issues, file) {
|
|
72922
|
+
var _a, _b;
|
|
72923
|
+
for (const element of tree.findAllExpressionsRecursive(expressions_1.CDSElement)) {
|
|
72924
|
+
if (element.findDirectTokenByText("INCLUDE") !== undefined) {
|
|
72925
|
+
continue;
|
|
72926
|
+
}
|
|
72927
|
+
let nameNode = (_a = element.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
|
|
72928
|
+
if (nameNode === undefined) {
|
|
72929
|
+
const names = ((_b = element.findDirectExpression(expressions_1.CDSPrefixedName)) === null || _b === void 0 ? void 0 : _b.findDirectExpressions(expressions_1.CDSName)) || [];
|
|
72930
|
+
nameNode = names[names.length - 1];
|
|
72931
|
+
}
|
|
72932
|
+
if (nameNode === undefined) {
|
|
72933
|
+
continue;
|
|
72934
|
+
}
|
|
72935
|
+
const name = this.name(nameNode);
|
|
72936
|
+
if (RESERVED_ELEMENT_NAMES.includes(name.toUpperCase())) {
|
|
72937
|
+
issues.push(issue_1.Issue.atToken(file, nameNode.getFirstToken(), `CDS element name "${name}" is reserved`, this.getMetadata().key, this.conf.severity));
|
|
72938
|
+
}
|
|
72939
|
+
}
|
|
72940
|
+
}
|
|
72688
72941
|
checkFields(tree, sources, object, issues, file) {
|
|
72689
72942
|
var _a;
|
|
72690
72943
|
const associationNames = new Set();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/cli",
|
|
3
|
-
"version": "2.120.
|
|
3
|
+
"version": "2.120.29",
|
|
4
4
|
"description": "abaplint - Command Line Interface",
|
|
5
5
|
"funding": "https://github.com/sponsors/larshp",
|
|
6
6
|
"bin": {
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"homepage": "https://abaplint.org",
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@abaplint/core": "^2.120.
|
|
42
|
+
"@abaplint/core": "^2.120.29",
|
|
43
43
|
"@types/chai": "^4.3.20",
|
|
44
44
|
"@types/minimist": "^1.2.5",
|
|
45
45
|
"@types/mocha": "^10.0.10",
|