@abaplint/cli 2.120.26 → 2.120.28
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 +430 -20
- 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);
|
|
@@ -29137,7 +29137,7 @@ function checkDatabaseFields(fields, dbSources, input, token) {
|
|
|
29137
29137
|
if (field === "*") {
|
|
29138
29138
|
continue;
|
|
29139
29139
|
}
|
|
29140
|
-
if (
|
|
29140
|
+
if (/^[A-Z_]\w*$/i.test(field) && type.getComponentByName(field) === undefined) {
|
|
29141
29141
|
const message = `checkFields, field ${field} not found`;
|
|
29142
29142
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
|
|
29143
29143
|
return;
|
|
@@ -33823,7 +33823,7 @@ class Select {
|
|
|
33823
33823
|
return;
|
|
33824
33824
|
}
|
|
33825
33825
|
(0, _check_database_fields_1.checkDatabaseFields)(fields.map(field => field.code), dbSources, input, node.getFirstToken());
|
|
33826
|
-
const intoExpression = this.handleInto(node, input, fields, dbSources);
|
|
33826
|
+
const intoExpression = this.handleInto(node, input, fields, dbSources, from);
|
|
33827
33827
|
const fae = node.findDirectExpression(Expressions.SQLForAllEntries);
|
|
33828
33828
|
if (fae) {
|
|
33829
33829
|
input.scope.push(_scope_type_1.ScopeType.OpenSQL, "SELECT", token.getStart(), input.filename);
|
|
@@ -33984,12 +33984,12 @@ class Select {
|
|
|
33984
33984
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
33985
33985
|
}
|
|
33986
33986
|
}
|
|
33987
|
-
static handleInto(node, input, fields, dbSources) {
|
|
33987
|
+
static handleInto(node, input, fields, dbSources, from) {
|
|
33988
33988
|
const intoTable = node.findDirectExpression(Expressions.SQLIntoTable);
|
|
33989
33989
|
if (intoTable) {
|
|
33990
33990
|
const inline = intoTable.findFirstExpression(Expressions.InlineData);
|
|
33991
33991
|
if (inline) {
|
|
33992
|
-
inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope));
|
|
33992
|
+
inline_data_1.InlineData.runSyntax(inline, input, this.buildTableType(fields, dbSources, input.scope, from));
|
|
33993
33993
|
}
|
|
33994
33994
|
return intoTable;
|
|
33995
33995
|
}
|
|
@@ -34137,11 +34137,36 @@ class Select {
|
|
|
34137
34137
|
return basic_1.VoidType.get("SELECT_todo13");
|
|
34138
34138
|
}
|
|
34139
34139
|
}
|
|
34140
|
-
static buildTableType(fields, dbSources, scope) {
|
|
34141
|
-
|
|
34140
|
+
static buildTableType(fields, dbSources, scope, from) {
|
|
34141
|
+
var _a;
|
|
34142
|
+
const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
|
|
34143
|
+
if (dbSources.length > 1) {
|
|
34144
|
+
const sourceInfos = this.buildDatabaseSourceInfos(from, dbSources);
|
|
34145
|
+
if (fields.length === 1 && fields[0].code === "*") {
|
|
34146
|
+
const components = [];
|
|
34147
|
+
for (const info of sourceInfos) {
|
|
34148
|
+
const type = (_a = info.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
|
|
34149
|
+
if (!(type instanceof basic_1.StructureType)) {
|
|
34150
|
+
return basic_1.VoidType.get("SELECT_todo3");
|
|
34151
|
+
}
|
|
34152
|
+
components.push({ name: info.alias || info.name, type });
|
|
34153
|
+
}
|
|
34154
|
+
return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
|
|
34155
|
+
}
|
|
34156
|
+
const components = [];
|
|
34157
|
+
for (const field of fields) {
|
|
34158
|
+
const type = this.findFieldType(field.code, sourceInfos, scope);
|
|
34159
|
+
if (type === undefined) {
|
|
34160
|
+
return basic_1.VoidType.get("SELECT_todo3");
|
|
34161
|
+
}
|
|
34162
|
+
const name = field.as || field.code.split("~").pop();
|
|
34163
|
+
components.push({ name, type });
|
|
34164
|
+
}
|
|
34165
|
+
return new basic_1.TableType(new basic_1.StructureType(components), tableOptions, undefined);
|
|
34166
|
+
}
|
|
34167
|
+
else if (dbSources.length !== 1) {
|
|
34142
34168
|
return basic_1.VoidType.get("SELECT_todo3");
|
|
34143
34169
|
}
|
|
34144
|
-
const tableOptions = { withHeader: false, keyType: basic_1.TableKeyType.empty };
|
|
34145
34170
|
if (dbSources[0] === undefined) {
|
|
34146
34171
|
// then its a voided table
|
|
34147
34172
|
return new basic_1.TableType(basic_1.VoidType.get("SELECT_todo4"), tableOptions, undefined);
|
|
@@ -34167,6 +34192,39 @@ class Select {
|
|
|
34167
34192
|
}
|
|
34168
34193
|
return basic_1.VoidType.get("SELECT_todo7");
|
|
34169
34194
|
}
|
|
34195
|
+
static buildDatabaseSourceInfos(from, dbSources) {
|
|
34196
|
+
const fromSources = from.findAllExpressions(Expressions.SQLFromSource);
|
|
34197
|
+
return dbSources.map((source, index) => {
|
|
34198
|
+
var _a, _b;
|
|
34199
|
+
const fromSource = fromSources[index];
|
|
34200
|
+
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()) || "";
|
|
34201
|
+
const alias = ((_b = fromSource === null || fromSource === void 0 ? void 0 : fromSource.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase()) || "";
|
|
34202
|
+
return { source, name, alias };
|
|
34203
|
+
});
|
|
34204
|
+
}
|
|
34205
|
+
static findFieldType(code, sourceInfos, scope) {
|
|
34206
|
+
var _a;
|
|
34207
|
+
const separator = code.indexOf("~");
|
|
34208
|
+
const qualifier = separator >= 0 ? code.substring(0, separator) : undefined;
|
|
34209
|
+
const fieldName = separator >= 0 ? code.substring(separator + 1) : code;
|
|
34210
|
+
const candidates = qualifier === undefined
|
|
34211
|
+
? sourceInfos
|
|
34212
|
+
: sourceInfos.filter(info => info.alias === qualifier || info.name === qualifier);
|
|
34213
|
+
for (const candidate of candidates) {
|
|
34214
|
+
let type = (_a = candidate.source) === null || _a === void 0 ? void 0 : _a.parseType(scope.getRegistry());
|
|
34215
|
+
for (const component of fieldName.split("-")) {
|
|
34216
|
+
if (!(type instanceof basic_1.StructureType)) {
|
|
34217
|
+
type = undefined;
|
|
34218
|
+
break;
|
|
34219
|
+
}
|
|
34220
|
+
type = type.getComponentByName(component);
|
|
34221
|
+
}
|
|
34222
|
+
if (type) {
|
|
34223
|
+
return type;
|
|
34224
|
+
}
|
|
34225
|
+
}
|
|
34226
|
+
return undefined;
|
|
34227
|
+
}
|
|
34170
34228
|
static findFields(node, input) {
|
|
34171
34229
|
var _a, _b;
|
|
34172
34230
|
let expr = undefined;
|
|
@@ -34180,7 +34238,7 @@ class Select {
|
|
|
34180
34238
|
let code = field.concatTokens().toUpperCase();
|
|
34181
34239
|
const as = ((_b = field.findDirectExpression(Expressions.SQLAsName)) === null || _b === void 0 ? void 0 : _b.concatTokens()) || "";
|
|
34182
34240
|
if (as !== "") {
|
|
34183
|
-
code = code.replace(" AS " + as, "");
|
|
34241
|
+
code = code.replace(" AS " + as.toUpperCase(), "");
|
|
34184
34242
|
}
|
|
34185
34243
|
ret.push({ code, as, expression: field });
|
|
34186
34244
|
}
|
|
@@ -35936,6 +35994,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35936
35994
|
})();
|
|
35937
35995
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
35938
35996
|
exports.ValueBody = void 0;
|
|
35997
|
+
const nodes_1 = __webpack_require__(/*! ../../nodes */ "../core/build/src/abap/nodes/index.js");
|
|
35939
35998
|
const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expressions */ "../core/build/src/abap/2_statements/expressions/index.js"));
|
|
35940
35999
|
const for_1 = __webpack_require__(/*! ./for */ "../core/build/src/abap/5_syntax/expressions/for.js");
|
|
35941
36000
|
const source_1 = __webpack_require__(/*! ./source */ "../core/build/src/abap/5_syntax/expressions/source.js");
|
|
@@ -35945,7 +36004,7 @@ const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/
|
|
|
35945
36004
|
const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
|
|
35946
36005
|
class ValueBody {
|
|
35947
36006
|
static runSyntax(node, input, targetType) {
|
|
35948
|
-
var _a, _b;
|
|
36007
|
+
var _a, _b, _c;
|
|
35949
36008
|
if (node === undefined) {
|
|
35950
36009
|
return targetType;
|
|
35951
36010
|
}
|
|
@@ -35962,26 +36021,45 @@ class ValueBody {
|
|
|
35962
36021
|
}
|
|
35963
36022
|
}
|
|
35964
36023
|
const fields = new Set();
|
|
35965
|
-
|
|
35966
|
-
|
|
35967
|
-
if (
|
|
35968
|
-
|
|
35969
|
-
|
|
36024
|
+
const hasTableLines = node.findDirectExpression(Expressions.ValueBodyLine) !== undefined;
|
|
36025
|
+
for (const child of node.getChildren()) {
|
|
36026
|
+
if (!(child instanceof nodes_1.ExpressionNode)) {
|
|
36027
|
+
continue;
|
|
36028
|
+
}
|
|
36029
|
+
else if (child.get() instanceof Expressions.FieldAssignment) {
|
|
36030
|
+
const fieldname = (_a = child.findDirectExpression(Expressions.FieldSub)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
36031
|
+
if (fieldname && hasTableLines === false && fields.has(fieldname)) {
|
|
36032
|
+
const message = "Duplicate field assignment";
|
|
36033
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, child.getFirstToken(), message));
|
|
36034
|
+
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
36035
|
+
}
|
|
35970
36036
|
if (fieldname) {
|
|
35971
|
-
|
|
36037
|
+
fields.add(fieldname);
|
|
36038
|
+
}
|
|
36039
|
+
}
|
|
36040
|
+
else if (child.get() instanceof Expressions.ValueBodyLine) {
|
|
36041
|
+
const rowFields = new Set(fields);
|
|
36042
|
+
for (const assignment of child.findDirectExpressions(Expressions.FieldAssignment)) {
|
|
36043
|
+
const fieldname = (_b = assignment.findDirectExpression(Expressions.FieldSub)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();
|
|
36044
|
+
if (fieldname && rowFields.has(fieldname)) {
|
|
35972
36045
|
const message = "Duplicate field assignment";
|
|
35973
|
-
input.issues.push((0, _syntax_input_1.syntaxIssue)(input,
|
|
36046
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, assignment.getFirstToken(), message));
|
|
35974
36047
|
return basic_1.VoidType.get(_syntax_input_1.CheckSyntaxKey);
|
|
35975
36048
|
}
|
|
35976
|
-
|
|
36049
|
+
if (fieldname) {
|
|
36050
|
+
rowFields.add(fieldname);
|
|
36051
|
+
}
|
|
35977
36052
|
}
|
|
35978
36053
|
}
|
|
35979
36054
|
}
|
|
36055
|
+
for (const s of node.findDirectExpressions(Expressions.FieldAssignment)) {
|
|
36056
|
+
field_assignment_1.FieldAssignment.runSyntax(s, input, targetType);
|
|
36057
|
+
}
|
|
35980
36058
|
let type = undefined; // todo, this is only correct if there is a single source in the body
|
|
35981
36059
|
for (const s of node.findDirectExpressions(Expressions.Source)) {
|
|
35982
36060
|
type = source_1.Source.runSyntax(s, input, type);
|
|
35983
36061
|
}
|
|
35984
|
-
for (const s of ((
|
|
36062
|
+
for (const s of ((_c = node.findDirectExpression(Expressions.ValueBase)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.Source)) || []) {
|
|
35985
36063
|
type = source_1.Source.runSyntax(s, input, type);
|
|
35986
36064
|
}
|
|
35987
36065
|
for (const foo of node.findDirectExpressions(Expressions.ValueBodyLine)) {
|
|
@@ -62507,6 +62585,7 @@ const _abstract_object_1 = __webpack_require__(/*! ./_abstract_object */ "../cor
|
|
|
62507
62585
|
const ddic_1 = __webpack_require__(/*! ../ddic */ "../core/build/src/ddic.js");
|
|
62508
62586
|
const Types = __importStar(__webpack_require__(/*! ../abap/types/basic */ "../core/build/src/abap/types/basic/index.js"));
|
|
62509
62587
|
const xml_utils_1 = __webpack_require__(/*! ../xml_utils */ "../core/build/src/xml_utils.js");
|
|
62588
|
+
const domain_1 = __webpack_require__(/*! ./domain */ "../core/build/src/objects/domain.js");
|
|
62510
62589
|
class DataElement extends _abstract_object_1.AbstractObject {
|
|
62511
62590
|
constructor() {
|
|
62512
62591
|
super(...arguments);
|
|
@@ -62537,6 +62616,22 @@ class DataElement extends _abstract_object_1.AbstractObject {
|
|
|
62537
62616
|
this.parse();
|
|
62538
62617
|
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.domname;
|
|
62539
62618
|
}
|
|
62619
|
+
/** parseType() cannot distinguish DEC, CURR, and QUAN because they all become PackedType.
|
|
62620
|
+
* Return the original DDIC datatype instead, resolving domain-backed data elements when possible. */
|
|
62621
|
+
getDataType(reg) {
|
|
62622
|
+
var _a, _b;
|
|
62623
|
+
this.parse();
|
|
62624
|
+
if ((_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.datatype) {
|
|
62625
|
+
return this.parsedXML.datatype;
|
|
62626
|
+
}
|
|
62627
|
+
if (reg && ((_b = this.parsedXML) === null || _b === void 0 ? void 0 : _b.refkind) === "D" && this.parsedXML.domname) {
|
|
62628
|
+
const domain = reg.getObject("DOMA", this.parsedXML.domname);
|
|
62629
|
+
if (domain instanceof domain_1.Domain) {
|
|
62630
|
+
return domain.getDataType();
|
|
62631
|
+
}
|
|
62632
|
+
}
|
|
62633
|
+
return undefined;
|
|
62634
|
+
}
|
|
62540
62635
|
getTexts() {
|
|
62541
62636
|
var _a;
|
|
62542
62637
|
this.parse();
|
|
@@ -62820,6 +62915,11 @@ class Domain extends _abstract_object_1.AbstractObject {
|
|
|
62820
62915
|
var _a;
|
|
62821
62916
|
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.conversionExit;
|
|
62822
62917
|
}
|
|
62918
|
+
getDataType() {
|
|
62919
|
+
var _a;
|
|
62920
|
+
this.parse();
|
|
62921
|
+
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.datatype;
|
|
62922
|
+
}
|
|
62823
62923
|
getAllowedNaming() {
|
|
62824
62924
|
return {
|
|
62825
62925
|
maxLength: 30,
|
|
@@ -69751,7 +69851,7 @@ class Registry {
|
|
|
69751
69851
|
}
|
|
69752
69852
|
static abaplintVersion() {
|
|
69753
69853
|
// magic, see build script "version.js"
|
|
69754
|
-
return "2.120.
|
|
69854
|
+
return "2.120.28";
|
|
69755
69855
|
}
|
|
69756
69856
|
getDDICReferences() {
|
|
69757
69857
|
return this.ddicReferences;
|
|
@@ -72415,6 +72515,315 @@ exports.CDSAssociationName = CDSAssociationName;
|
|
|
72415
72515
|
|
|
72416
72516
|
/***/ },
|
|
72417
72517
|
|
|
72518
|
+
/***/ "../core/build/src/rules/cds_check_syntax.js"
|
|
72519
|
+
/*!***************************************************!*\
|
|
72520
|
+
!*** ../core/build/src/rules/cds_check_syntax.js ***!
|
|
72521
|
+
\***************************************************/
|
|
72522
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
72523
|
+
|
|
72524
|
+
"use strict";
|
|
72525
|
+
|
|
72526
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
72527
|
+
exports.CDSCheckSyntax = exports.CDSCheckSyntaxConf = void 0;
|
|
72528
|
+
const nodes_1 = __webpack_require__(/*! ../abap/nodes */ "../core/build/src/abap/nodes/index.js");
|
|
72529
|
+
const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "../core/build/src/abap/types/basic/index.js");
|
|
72530
|
+
const expressions_1 = __webpack_require__(/*! ../cds/expressions */ "../core/build/src/cds/expressions/index.js");
|
|
72531
|
+
const ddic_1 = __webpack_require__(/*! ../ddic */ "../core/build/src/ddic.js");
|
|
72532
|
+
const issue_1 = __webpack_require__(/*! ../issue */ "../core/build/src/issue.js");
|
|
72533
|
+
const objects_1 = __webpack_require__(/*! ../objects */ "../core/build/src/objects/index.js");
|
|
72534
|
+
const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "../core/build/src/rules/_basic_rule_config.js");
|
|
72535
|
+
const _irule_1 = __webpack_require__(/*! ./_irule */ "../core/build/src/rules/_irule.js");
|
|
72536
|
+
class CDSCheckSyntaxConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
72537
|
+
}
|
|
72538
|
+
exports.CDSCheckSyntaxConf = CDSCheckSyntaxConf;
|
|
72539
|
+
const KNOWN_QUAN_DATA_ELEMENTS = ["MENGE_D"];
|
|
72540
|
+
const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
|
|
72541
|
+
class CDSCheckSyntax {
|
|
72542
|
+
constructor() {
|
|
72543
|
+
this.conf = new CDSCheckSyntaxConf();
|
|
72544
|
+
}
|
|
72545
|
+
getMetadata() {
|
|
72546
|
+
return {
|
|
72547
|
+
key: "cds_check_syntax",
|
|
72548
|
+
title: "CDS Check Syntax",
|
|
72549
|
+
shortDescription: "Checks CDS source, field, type, and semantic annotation references",
|
|
72550
|
+
extendedInformation: `Performs semantic checks which require other DDIC objects to be available.
|
|
72551
|
+
|
|
72552
|
+
Missing objects are only reported when their names match the configured errorNamespace.`,
|
|
72553
|
+
tags: [_irule_1.RuleTag.Syntax],
|
|
72554
|
+
};
|
|
72555
|
+
}
|
|
72556
|
+
getConfig() {
|
|
72557
|
+
return this.conf;
|
|
72558
|
+
}
|
|
72559
|
+
setConfig(conf) {
|
|
72560
|
+
this.conf = conf;
|
|
72561
|
+
}
|
|
72562
|
+
initialize(reg) {
|
|
72563
|
+
this.reg = reg;
|
|
72564
|
+
return this;
|
|
72565
|
+
}
|
|
72566
|
+
run(object) {
|
|
72567
|
+
if (!(object instanceof objects_1.DataDefinition)) {
|
|
72568
|
+
return [];
|
|
72569
|
+
}
|
|
72570
|
+
const tree = object.getTree();
|
|
72571
|
+
const file = object.findSourceFile();
|
|
72572
|
+
if (tree === undefined || file === undefined) {
|
|
72573
|
+
return [];
|
|
72574
|
+
}
|
|
72575
|
+
const issues = [];
|
|
72576
|
+
const ddic = new ddic_1.DDIC(this.reg);
|
|
72577
|
+
const sources = this.findSources(tree, ddic, issues, file);
|
|
72578
|
+
this.checkRelations(tree, ddic, issues, file);
|
|
72579
|
+
this.checkTypes(tree, ddic, issues, file);
|
|
72580
|
+
this.checkRootProjection(tree, ddic, issues, file);
|
|
72581
|
+
this.checkFieldAnnotations(tree, ddic, issues, file);
|
|
72582
|
+
this.checkFields(tree, sources, object, issues, file);
|
|
72583
|
+
return issues;
|
|
72584
|
+
}
|
|
72585
|
+
findSources(tree, ddic, issues, file) {
|
|
72586
|
+
var _a;
|
|
72587
|
+
const sources = [];
|
|
72588
|
+
for (const node of tree.findAllExpressionsRecursive(expressions_1.CDSSource)) {
|
|
72589
|
+
const prefixed = node.findDirectExpression(expressions_1.CDSPrefixedName);
|
|
72590
|
+
const entityNode = prefixed === null || prefixed === void 0 ? void 0 : prefixed.findDirectExpression(expressions_1.CDSName);
|
|
72591
|
+
if (entityNode === undefined) {
|
|
72592
|
+
continue;
|
|
72593
|
+
}
|
|
72594
|
+
const entity = this.name(entityNode);
|
|
72595
|
+
const asName = (_a = node.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
|
|
72596
|
+
const bareAlias = node.findDirectExpression(expressions_1.CDSName);
|
|
72597
|
+
const alias = asName === undefined ? bareAlias : asName;
|
|
72598
|
+
const lookup = ddic.lookupTableOrView(entity);
|
|
72599
|
+
if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(entity)) {
|
|
72600
|
+
issues.push(issue_1.Issue.atToken(file, entityNode.getFirstToken(), `CDS source "${entity}" not found`, this.getMetadata().key, this.conf.severity));
|
|
72601
|
+
}
|
|
72602
|
+
if (lookup.type instanceof basic_1.StructureType || lookup.type instanceof basic_1.UnknownType || lookup.type instanceof basic_1.VoidType) {
|
|
72603
|
+
const names = [entity.toUpperCase()];
|
|
72604
|
+
if (alias) {
|
|
72605
|
+
names.push(this.name(alias).toUpperCase());
|
|
72606
|
+
}
|
|
72607
|
+
sources.push({ entity, names, type: lookup.type });
|
|
72608
|
+
}
|
|
72609
|
+
}
|
|
72610
|
+
return sources;
|
|
72611
|
+
}
|
|
72612
|
+
checkRelations(tree, ddic, issues, file) {
|
|
72613
|
+
for (const relation of tree.findAllExpressionsRecursive(expressions_1.CDSRelation)) {
|
|
72614
|
+
const directTokens = relation.getDirectTokens();
|
|
72615
|
+
if (directTokens.length === 0) {
|
|
72616
|
+
continue;
|
|
72617
|
+
}
|
|
72618
|
+
const entity = directTokens.map(t => t.getStr()).join("");
|
|
72619
|
+
const lookup = ddic.lookupTableOrView(entity);
|
|
72620
|
+
if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(entity)) {
|
|
72621
|
+
issues.push(issue_1.Issue.atToken(file, directTokens[0], `CDS source "${entity}" not found`, this.getMetadata().key, this.conf.severity));
|
|
72622
|
+
}
|
|
72623
|
+
}
|
|
72624
|
+
}
|
|
72625
|
+
checkTypes(tree, ddic, issues, file) {
|
|
72626
|
+
for (const typeNode of tree.findAllExpressionsRecursive(expressions_1.CDSType)) {
|
|
72627
|
+
const typeName = typeNode.findDirectExpressions(expressions_1.CDSName).map(n => this.name(n)).join(".");
|
|
72628
|
+
if (typeName === "" || typeName.toUpperCase().startsWith("ABAP.")) {
|
|
72629
|
+
continue;
|
|
72630
|
+
}
|
|
72631
|
+
const lookup = ddic.lookup(typeName);
|
|
72632
|
+
if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(typeName)) {
|
|
72633
|
+
issues.push(issue_1.Issue.atToken(file, typeNode.getFirstToken(), `CDS type "${typeName}" not found`, this.getMetadata().key, this.conf.severity));
|
|
72634
|
+
}
|
|
72635
|
+
}
|
|
72636
|
+
}
|
|
72637
|
+
checkRootProjection(tree, ddic, issues, file) {
|
|
72638
|
+
var _a;
|
|
72639
|
+
const projection = tree.findFirstExpression(expressions_1.CDSDefineProjection);
|
|
72640
|
+
const rootToken = projection === null || projection === void 0 ? void 0 : projection.findDirectTokenByText("ROOT");
|
|
72641
|
+
if (projection === undefined || rootToken === undefined) {
|
|
72642
|
+
return;
|
|
72643
|
+
}
|
|
72644
|
+
const names = projection.findDirectExpressions(expressions_1.CDSName);
|
|
72645
|
+
const projectedEntityNode = names[1];
|
|
72646
|
+
if (projectedEntityNode === undefined) {
|
|
72647
|
+
return;
|
|
72648
|
+
}
|
|
72649
|
+
const projectedEntityName = this.name(projectedEntityNode);
|
|
72650
|
+
const projectedEntity = ddic.lookupTableOrView(projectedEntityName).object;
|
|
72651
|
+
if (projectedEntity instanceof objects_1.DataDefinition
|
|
72652
|
+
&& ((_a = projectedEntity.getTree()) === null || _a === void 0 ? void 0 : _a.findDirectTokenByText("ROOT")) === undefined) {
|
|
72653
|
+
const message = `ROOT keyword not valid since ${projectedEntityName} is not a root property`;
|
|
72654
|
+
issues.push(issue_1.Issue.atToken(file, rootToken, message, this.getMetadata().key, this.conf.severity));
|
|
72655
|
+
}
|
|
72656
|
+
}
|
|
72657
|
+
checkFieldAnnotations(tree, ddic, issues, file) {
|
|
72658
|
+
const definition = tree.findFirstExpression(expressions_1.CDSDefineAbstract);
|
|
72659
|
+
if (definition === undefined) {
|
|
72660
|
+
return;
|
|
72661
|
+
}
|
|
72662
|
+
let definitionNameSeen = false;
|
|
72663
|
+
let fieldName;
|
|
72664
|
+
let annotations = [];
|
|
72665
|
+
const fields = [];
|
|
72666
|
+
for (const child of definition.getChildren()) {
|
|
72667
|
+
if (child instanceof nodes_1.TokenNode) {
|
|
72668
|
+
if (child.get().getStr() === ";") {
|
|
72669
|
+
fieldName = undefined;
|
|
72670
|
+
annotations = [];
|
|
72671
|
+
}
|
|
72672
|
+
continue;
|
|
72673
|
+
}
|
|
72674
|
+
else if (child.get() instanceof expressions_1.CDSAnnotation) {
|
|
72675
|
+
annotations.push(child);
|
|
72676
|
+
}
|
|
72677
|
+
else if (child.get() instanceof expressions_1.CDSName) {
|
|
72678
|
+
if (definitionNameSeen === false) {
|
|
72679
|
+
definitionNameSeen = true;
|
|
72680
|
+
annotations = [];
|
|
72681
|
+
}
|
|
72682
|
+
else {
|
|
72683
|
+
fieldName = child;
|
|
72684
|
+
}
|
|
72685
|
+
}
|
|
72686
|
+
else if (child.get() instanceof expressions_1.CDSType && fieldName !== undefined) {
|
|
72687
|
+
const semanticType = this.determineSemanticType(child, ddic);
|
|
72688
|
+
const normalizedAnnotations = annotations.map(a => a.concatTokens().replace(/\s/g, ""));
|
|
72689
|
+
fields.push({ name: this.name(fieldName), node: fieldName, annotations: normalizedAnnotations, semanticType });
|
|
72690
|
+
fieldName = undefined;
|
|
72691
|
+
annotations = [];
|
|
72692
|
+
}
|
|
72693
|
+
}
|
|
72694
|
+
const reportedCompanionFields = new Set();
|
|
72695
|
+
for (const field of fields) {
|
|
72696
|
+
if (field.semanticType === undefined) {
|
|
72697
|
+
continue;
|
|
72698
|
+
}
|
|
72699
|
+
const quantity = field.semanticType === "QUAN";
|
|
72700
|
+
const referenceAnnotation = quantity ? "@Semantics.quantity.unitOfMeasure" : "@Semantics.amount.currencyCode";
|
|
72701
|
+
const companionAnnotation = quantity ? "@Semantics.unitOfMeasure: true" : "@Semantics.currencyCode: true";
|
|
72702
|
+
const reference = this.findSemanticReference(field.annotations, field.semanticType);
|
|
72703
|
+
if (reference === undefined) {
|
|
72704
|
+
const kind = quantity ? "quantity" : "amount";
|
|
72705
|
+
const message = `CDS ${kind} field "${field.name}" requires ${referenceAnnotation}`;
|
|
72706
|
+
issues.push(issue_1.Issue.atToken(file, field.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72707
|
+
continue;
|
|
72708
|
+
}
|
|
72709
|
+
const companion = fields.find(f => f.name.toUpperCase() === reference.toUpperCase());
|
|
72710
|
+
if (companion === undefined) {
|
|
72711
|
+
const kind = quantity ? "unit" : "currency";
|
|
72712
|
+
const message = `CDS field "${field.name}" references missing ${kind} field "${reference}"`;
|
|
72713
|
+
issues.push(issue_1.Issue.atToken(file, field.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72714
|
+
continue;
|
|
72715
|
+
}
|
|
72716
|
+
const companionKey = field.semanticType + ":" + companion.name.toUpperCase();
|
|
72717
|
+
if (reportedCompanionFields.has(companionKey) === false
|
|
72718
|
+
&& this.hasCompanionAnnotation(companion.annotations, field.semanticType) === false) {
|
|
72719
|
+
const message = `CDS field "${companion.name}" requires ${companionAnnotation}`;
|
|
72720
|
+
issues.push(issue_1.Issue.atToken(file, companion.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72721
|
+
reportedCompanionFields.add(companionKey);
|
|
72722
|
+
}
|
|
72723
|
+
}
|
|
72724
|
+
}
|
|
72725
|
+
determineSemanticType(typeNode, ddic) {
|
|
72726
|
+
var _a;
|
|
72727
|
+
const typeName = typeNode.findDirectExpressions(expressions_1.CDSName).map(n => this.name(n)).join(".");
|
|
72728
|
+
const upper = typeName.toUpperCase();
|
|
72729
|
+
if (upper === "ABAP.QUAN" || KNOWN_QUAN_DATA_ELEMENTS.includes(upper)) {
|
|
72730
|
+
return "QUAN";
|
|
72731
|
+
}
|
|
72732
|
+
else if (upper === "ABAP.CURR" || KNOWN_CURR_DATA_ELEMENTS.includes(upper)) {
|
|
72733
|
+
return "CURR";
|
|
72734
|
+
}
|
|
72735
|
+
const object = ddic.lookup(typeName).object;
|
|
72736
|
+
if (object instanceof objects_1.DataElement) {
|
|
72737
|
+
const dataType = (_a = object.getDataType(this.reg)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
72738
|
+
if (dataType === "QUAN" || dataType === "CURR") {
|
|
72739
|
+
return dataType;
|
|
72740
|
+
}
|
|
72741
|
+
}
|
|
72742
|
+
return undefined;
|
|
72743
|
+
}
|
|
72744
|
+
findSemanticReference(annotations, type) {
|
|
72745
|
+
const expression = type === "QUAN"
|
|
72746
|
+
? /(?:SEMANTICS\.QUANTITY|SEMANTICS:\{QUANTITY:\{)\.?UNITOFMEASURE:'([^']+)'/i
|
|
72747
|
+
: /(?:SEMANTICS\.AMOUNT|SEMANTICS:\{AMOUNT:\{)\.?CURRENCYCODE:'([^']+)'/i;
|
|
72748
|
+
for (const annotation of annotations) {
|
|
72749
|
+
const match = annotation.match(expression);
|
|
72750
|
+
if (match) {
|
|
72751
|
+
return match[1];
|
|
72752
|
+
}
|
|
72753
|
+
}
|
|
72754
|
+
return undefined;
|
|
72755
|
+
}
|
|
72756
|
+
hasCompanionAnnotation(annotations, type) {
|
|
72757
|
+
if (type === "QUAN") {
|
|
72758
|
+
return annotations.some(a => a.toUpperCase().includes("@SEMANTICS.UNITOFMEASURE:TRUE")
|
|
72759
|
+
|| a.toUpperCase().includes("@SEMANTICS:{UNITOFMEASURE:TRUE"));
|
|
72760
|
+
}
|
|
72761
|
+
else {
|
|
72762
|
+
return annotations.some(a => a.toUpperCase().includes("@SEMANTICS.CURRENCYCODE:TRUE")
|
|
72763
|
+
|| a.toUpperCase().includes("@SEMANTICS:{CURRENCYCODE:TRUE"));
|
|
72764
|
+
}
|
|
72765
|
+
}
|
|
72766
|
+
checkFields(tree, sources, object, issues, file) {
|
|
72767
|
+
var _a;
|
|
72768
|
+
const associationNames = new Set();
|
|
72769
|
+
for (const association of ((_a = object.getParsedData()) === null || _a === void 0 ? void 0 : _a.associations) || []) {
|
|
72770
|
+
associationNames.add(association.name.toUpperCase());
|
|
72771
|
+
if (association.as) {
|
|
72772
|
+
associationNames.add(association.as.toUpperCase());
|
|
72773
|
+
}
|
|
72774
|
+
}
|
|
72775
|
+
for (const element of tree.findAllExpressionsRecursive(expressions_1.CDSElement)) {
|
|
72776
|
+
const prefixed = element.findDirectExpression(expressions_1.CDSPrefixedName);
|
|
72777
|
+
if (prefixed === undefined) {
|
|
72778
|
+
continue;
|
|
72779
|
+
}
|
|
72780
|
+
const names = prefixed.findDirectExpressions(expressions_1.CDSName);
|
|
72781
|
+
if (names.length === 0) {
|
|
72782
|
+
continue;
|
|
72783
|
+
}
|
|
72784
|
+
const first = this.name(names[0]);
|
|
72785
|
+
if (first === "*" || first.startsWith("$") || first.startsWith("#") || associationNames.has(first.toUpperCase())) {
|
|
72786
|
+
continue;
|
|
72787
|
+
}
|
|
72788
|
+
if (names.length > 1) {
|
|
72789
|
+
const matchingSources = sources.filter(s => s.names.includes(first.toUpperCase()));
|
|
72790
|
+
if (matchingSources.length !== 1) {
|
|
72791
|
+
continue;
|
|
72792
|
+
}
|
|
72793
|
+
const source = matchingSources[0];
|
|
72794
|
+
const sourceType = source.type;
|
|
72795
|
+
if (!(sourceType instanceof basic_1.StructureType)) {
|
|
72796
|
+
continue;
|
|
72797
|
+
}
|
|
72798
|
+
const field = this.name(names[1]);
|
|
72799
|
+
if (field !== "*" && sourceType.getComponentByName(field) === undefined) {
|
|
72800
|
+
issues.push(issue_1.Issue.atToken(file, names[1].getFirstToken(), `CDS field "${field}" not found in "${source.entity}"`, this.getMetadata().key, this.conf.severity));
|
|
72801
|
+
}
|
|
72802
|
+
continue;
|
|
72803
|
+
}
|
|
72804
|
+
// Do not guess across joins or when a dependency is absent.
|
|
72805
|
+
if (sources.length !== 1) {
|
|
72806
|
+
continue;
|
|
72807
|
+
}
|
|
72808
|
+
const source = sources[0];
|
|
72809
|
+
const sourceType = source.type;
|
|
72810
|
+
if (!(sourceType instanceof basic_1.StructureType)) {
|
|
72811
|
+
continue;
|
|
72812
|
+
}
|
|
72813
|
+
if (sourceType.getComponentByName(first) === undefined) {
|
|
72814
|
+
issues.push(issue_1.Issue.atToken(file, names[0].getFirstToken(), `CDS field "${first}" not found in "${source.entity}"`, this.getMetadata().key, this.conf.severity));
|
|
72815
|
+
}
|
|
72816
|
+
}
|
|
72817
|
+
}
|
|
72818
|
+
name(node) {
|
|
72819
|
+
return node.concatTokens().replace(/ /g, "");
|
|
72820
|
+
}
|
|
72821
|
+
}
|
|
72822
|
+
exports.CDSCheckSyntax = CDSCheckSyntax;
|
|
72823
|
+
//# sourceMappingURL=cds_check_syntax.js.map
|
|
72824
|
+
|
|
72825
|
+
/***/ },
|
|
72826
|
+
|
|
72418
72827
|
/***/ "../core/build/src/rules/cds_comment_style.js"
|
|
72419
72828
|
/*!****************************************************!*\
|
|
72420
72829
|
!*** ../core/build/src/rules/cds_comment_style.js ***!
|
|
@@ -83509,6 +83918,7 @@ __exportStar(__webpack_require__(/*! ./begin_single_include */ "../core/build/sr
|
|
|
83509
83918
|
__exportStar(__webpack_require__(/*! ./call_transaction_authority_check */ "../core/build/src/rules/call_transaction_authority_check.js"), exports);
|
|
83510
83919
|
__exportStar(__webpack_require__(/*! ./catch_and_raise */ "../core/build/src/rules/catch_and_raise.js"), exports);
|
|
83511
83920
|
__exportStar(__webpack_require__(/*! ./cds_association_name */ "../core/build/src/rules/cds_association_name.js"), exports);
|
|
83921
|
+
__exportStar(__webpack_require__(/*! ./cds_check_syntax */ "../core/build/src/rules/cds_check_syntax.js"), exports);
|
|
83512
83922
|
__exportStar(__webpack_require__(/*! ./cds_comment_style */ "../core/build/src/rules/cds_comment_style.js"), exports);
|
|
83513
83923
|
__exportStar(__webpack_require__(/*! ./cds_field_order */ "../core/build/src/rules/cds_field_order.js"), exports);
|
|
83514
83924
|
__exportStar(__webpack_require__(/*! ./cds_legacy_view */ "../core/build/src/rules/cds_legacy_view.js"), exports);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/cli",
|
|
3
|
-
"version": "2.120.
|
|
3
|
+
"version": "2.120.28",
|
|
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.28",
|
|
43
43
|
"@types/chai": "^4.3.20",
|
|
44
44
|
"@types/minimist": "^1.2.5",
|
|
45
45
|
"@types/mocha": "^10.0.10",
|