@abaplint/cli 2.120.25 → 2.120.27
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 +398 -33
- package/package.json +2 -2
package/build/cli.js
CHANGED
|
@@ -29103,6 +29103,51 @@ exports.BasicTypes = BasicTypes;
|
|
|
29103
29103
|
|
|
29104
29104
|
/***/ },
|
|
29105
29105
|
|
|
29106
|
+
/***/ "../core/build/src/abap/5_syntax/expressions/_check_database_fields.js"
|
|
29107
|
+
/*!*****************************************************************************!*\
|
|
29108
|
+
!*** ../core/build/src/abap/5_syntax/expressions/_check_database_fields.js ***!
|
|
29109
|
+
\*****************************************************************************/
|
|
29110
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
29111
|
+
|
|
29112
|
+
"use strict";
|
|
29113
|
+
|
|
29114
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
29115
|
+
exports.checkDatabaseFields = checkDatabaseFields;
|
|
29116
|
+
const basic_1 = __webpack_require__(/*! ../../types/basic */ "../core/build/src/abap/types/basic/index.js");
|
|
29117
|
+
const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
|
|
29118
|
+
function checkDatabaseFields(fields, dbSources, input, token) {
|
|
29119
|
+
if (dbSources.length > 1) {
|
|
29120
|
+
return;
|
|
29121
|
+
}
|
|
29122
|
+
const first = dbSources[0];
|
|
29123
|
+
if (first === undefined) {
|
|
29124
|
+
// then its voided
|
|
29125
|
+
return;
|
|
29126
|
+
}
|
|
29127
|
+
const type = first.parseType(input.scope.getRegistry());
|
|
29128
|
+
if (type instanceof basic_1.VoidType || type instanceof basic_1.UnknownType) {
|
|
29129
|
+
return;
|
|
29130
|
+
}
|
|
29131
|
+
if (!(type instanceof basic_1.StructureType)) {
|
|
29132
|
+
const message = "checkFields, expected structure, " + type.constructor.name;
|
|
29133
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
|
|
29134
|
+
return;
|
|
29135
|
+
}
|
|
29136
|
+
for (const field of fields) {
|
|
29137
|
+
if (field === "*") {
|
|
29138
|
+
continue;
|
|
29139
|
+
}
|
|
29140
|
+
if (/^\w+$/.test(field) && type.getComponentByName(field) === undefined) {
|
|
29141
|
+
const message = `checkFields, field ${field} not found`;
|
|
29142
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, token, message));
|
|
29143
|
+
return;
|
|
29144
|
+
}
|
|
29145
|
+
}
|
|
29146
|
+
}
|
|
29147
|
+
//# sourceMappingURL=_check_database_fields.js.map
|
|
29148
|
+
|
|
29149
|
+
/***/ },
|
|
29150
|
+
|
|
29106
29151
|
/***/ "../core/build/src/abap/5_syntax/expressions/_check_offset_length.js"
|
|
29107
29152
|
/*!***************************************************************************!*\
|
|
29108
29153
|
!*** ../core/build/src/abap/5_syntax/expressions/_check_offset_length.js ***!
|
|
@@ -33752,6 +33797,7 @@ const dynamic_1 = __webpack_require__(/*! ./dynamic */ "../core/build/src/abap/5
|
|
|
33752
33797
|
const _reference_1 = __webpack_require__(/*! ../_reference */ "../core/build/src/abap/5_syntax/_reference.js");
|
|
33753
33798
|
const _syntax_input_1 = __webpack_require__(/*! ../_syntax_input */ "../core/build/src/abap/5_syntax/_syntax_input.js");
|
|
33754
33799
|
const version_1 = __webpack_require__(/*! ../../../version */ "../core/build/src/version.js");
|
|
33800
|
+
const _check_database_fields_1 = __webpack_require__(/*! ./_check_database_fields */ "../core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
|
|
33755
33801
|
const isSimple = /^\w+$/;
|
|
33756
33802
|
class Select {
|
|
33757
33803
|
static runSyntax(node, input, skipImplicitInto = false, selectLoop = false) {
|
|
@@ -33776,7 +33822,7 @@ class Select {
|
|
|
33776
33822
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
33777
33823
|
return;
|
|
33778
33824
|
}
|
|
33779
|
-
|
|
33825
|
+
(0, _check_database_fields_1.checkDatabaseFields)(fields.map(field => field.code), dbSources, input, node.getFirstToken());
|
|
33780
33826
|
const intoExpression = this.handleInto(node, input, fields, dbSources);
|
|
33781
33827
|
const fae = node.findDirectExpression(Expressions.SQLForAllEntries);
|
|
33782
33828
|
if (fae) {
|
|
@@ -34003,35 +34049,6 @@ class Select {
|
|
|
34003
34049
|
}
|
|
34004
34050
|
return undefined;
|
|
34005
34051
|
}
|
|
34006
|
-
static checkFields(fields, dbSources, input, node) {
|
|
34007
|
-
if (dbSources.length > 1) {
|
|
34008
|
-
return;
|
|
34009
|
-
}
|
|
34010
|
-
const first = dbSources[0];
|
|
34011
|
-
if (first === undefined) {
|
|
34012
|
-
// then its voided
|
|
34013
|
-
return;
|
|
34014
|
-
}
|
|
34015
|
-
const type = first.parseType(input.scope.getRegistry());
|
|
34016
|
-
if (type instanceof basic_1.VoidType || type instanceof basic_1.UnknownType) {
|
|
34017
|
-
return;
|
|
34018
|
-
}
|
|
34019
|
-
if (!(type instanceof basic_1.StructureType)) {
|
|
34020
|
-
const message = "checkFields, expected structure, " + type.constructor.name;
|
|
34021
|
-
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
34022
|
-
return;
|
|
34023
|
-
}
|
|
34024
|
-
for (const field of fields) {
|
|
34025
|
-
if (field.code === "*") {
|
|
34026
|
-
continue;
|
|
34027
|
-
}
|
|
34028
|
-
if (isSimple.test(field.code) && type.getComponentByName(field.code) === undefined) {
|
|
34029
|
-
const message = `checkFields, field ${field.code} not found`;
|
|
34030
|
-
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, node.getFirstToken(), message));
|
|
34031
|
-
return;
|
|
34032
|
-
}
|
|
34033
|
-
}
|
|
34034
|
-
}
|
|
34035
34052
|
static countResultType(scope) {
|
|
34036
34053
|
if ((0, version_1.releaseAtLeast)(scope.getRelease(), version_1.Release.v750)
|
|
34037
34054
|
|| scope.getOpenABAP()
|
|
@@ -39384,6 +39401,7 @@ const Expressions = __importStar(__webpack_require__(/*! ../../2_statements/expr
|
|
|
39384
39401
|
const source_1 = __webpack_require__(/*! ../expressions/source */ "../core/build/src/abap/5_syntax/expressions/source.js");
|
|
39385
39402
|
const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/build/src/abap/5_syntax/expressions/dynamic.js");
|
|
39386
39403
|
const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "../core/build/src/abap/5_syntax/expressions/database_table.js");
|
|
39404
|
+
const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "../core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
|
|
39387
39405
|
class DeleteDatabase {
|
|
39388
39406
|
runSyntax(node, input) {
|
|
39389
39407
|
for (const s of node.findAllExpressions(Expressions.Source)) {
|
|
@@ -39397,7 +39415,14 @@ class DeleteDatabase {
|
|
|
39397
39415
|
}
|
|
39398
39416
|
const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
|
|
39399
39417
|
if (dbtab !== undefined) {
|
|
39400
|
-
database_table_1.DatabaseTable.runSyntax(dbtab, input);
|
|
39418
|
+
const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
|
|
39419
|
+
const fields = node.findAllExpressions(Expressions.SQLCompare)
|
|
39420
|
+
.map(compare => { var _a; return (_a = compare.findDirectExpression(Expressions.SQLFieldName)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase(); })
|
|
39421
|
+
.filter(field => field !== undefined);
|
|
39422
|
+
for (const orderBy of node.findAllExpressions(Expressions.SQLOrderBy)) {
|
|
39423
|
+
fields.push(...orderBy.findAllExpressions(Expressions.SQLFieldName).map(field => field.concatTokens().toUpperCase()));
|
|
39424
|
+
}
|
|
39425
|
+
(0, _check_database_fields_1.checkDatabaseFields)(fields, [dbSource], input, node.getFirstToken());
|
|
39401
39426
|
}
|
|
39402
39427
|
}
|
|
39403
39428
|
}
|
|
@@ -46342,11 +46367,19 @@ const _typed_identifier_1 = __webpack_require__(/*! ../../types/_typed_identifie
|
|
|
46342
46367
|
const identifier_1 = __webpack_require__(/*! ../../1_lexer/tokens/identifier */ "../core/build/src/abap/1_lexer/tokens/identifier.js");
|
|
46343
46368
|
const database_table_1 = __webpack_require__(/*! ../expressions/database_table */ "../core/build/src/abap/5_syntax/expressions/database_table.js");
|
|
46344
46369
|
const dynamic_1 = __webpack_require__(/*! ../expressions/dynamic */ "../core/build/src/abap/5_syntax/expressions/dynamic.js");
|
|
46370
|
+
const _check_database_fields_1 = __webpack_require__(/*! ../expressions/_check_database_fields */ "../core/build/src/abap/5_syntax/expressions/_check_database_fields.js");
|
|
46345
46371
|
class UpdateDatabase {
|
|
46346
46372
|
runSyntax(node, input) {
|
|
46347
46373
|
const dbtab = node.findFirstExpression(Expressions.DatabaseTable);
|
|
46348
46374
|
if (dbtab !== undefined) {
|
|
46349
|
-
database_table_1.DatabaseTable.runSyntax(dbtab, input);
|
|
46375
|
+
const dbSource = database_table_1.DatabaseTable.runSyntax(dbtab, input);
|
|
46376
|
+
const fields = node.findAllExpressions(Expressions.SQLFieldAndValue)
|
|
46377
|
+
.flatMap(fieldAndValue => fieldAndValue.findDirectExpressions(Expressions.SQLFieldName))
|
|
46378
|
+
.map(field => field.concatTokens().toUpperCase());
|
|
46379
|
+
fields.push(...node.findAllExpressions(Expressions.SQLCompare)
|
|
46380
|
+
.map(compare => { var _a; return (_a = compare.findDirectExpression(Expressions.SQLFieldName)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase(); })
|
|
46381
|
+
.filter(field => field !== undefined));
|
|
46382
|
+
(0, _check_database_fields_1.checkDatabaseFields)(fields, [dbSource], input, node.getFirstToken());
|
|
46350
46383
|
}
|
|
46351
46384
|
const tableName = node.findDirectExpression(Expressions.DatabaseTable);
|
|
46352
46385
|
const tokenName = tableName === null || tableName === void 0 ? void 0 : tableName.getFirstToken();
|
|
@@ -62474,6 +62507,7 @@ const _abstract_object_1 = __webpack_require__(/*! ./_abstract_object */ "../cor
|
|
|
62474
62507
|
const ddic_1 = __webpack_require__(/*! ../ddic */ "../core/build/src/ddic.js");
|
|
62475
62508
|
const Types = __importStar(__webpack_require__(/*! ../abap/types/basic */ "../core/build/src/abap/types/basic/index.js"));
|
|
62476
62509
|
const xml_utils_1 = __webpack_require__(/*! ../xml_utils */ "../core/build/src/xml_utils.js");
|
|
62510
|
+
const domain_1 = __webpack_require__(/*! ./domain */ "../core/build/src/objects/domain.js");
|
|
62477
62511
|
class DataElement extends _abstract_object_1.AbstractObject {
|
|
62478
62512
|
constructor() {
|
|
62479
62513
|
super(...arguments);
|
|
@@ -62504,6 +62538,22 @@ class DataElement extends _abstract_object_1.AbstractObject {
|
|
|
62504
62538
|
this.parse();
|
|
62505
62539
|
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.domname;
|
|
62506
62540
|
}
|
|
62541
|
+
/** parseType() cannot distinguish DEC, CURR, and QUAN because they all become PackedType.
|
|
62542
|
+
* Return the original DDIC datatype instead, resolving domain-backed data elements when possible. */
|
|
62543
|
+
getDataType(reg) {
|
|
62544
|
+
var _a, _b;
|
|
62545
|
+
this.parse();
|
|
62546
|
+
if ((_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.datatype) {
|
|
62547
|
+
return this.parsedXML.datatype;
|
|
62548
|
+
}
|
|
62549
|
+
if (reg && ((_b = this.parsedXML) === null || _b === void 0 ? void 0 : _b.refkind) === "D" && this.parsedXML.domname) {
|
|
62550
|
+
const domain = reg.getObject("DOMA", this.parsedXML.domname);
|
|
62551
|
+
if (domain instanceof domain_1.Domain) {
|
|
62552
|
+
return domain.getDataType();
|
|
62553
|
+
}
|
|
62554
|
+
}
|
|
62555
|
+
return undefined;
|
|
62556
|
+
}
|
|
62507
62557
|
getTexts() {
|
|
62508
62558
|
var _a;
|
|
62509
62559
|
this.parse();
|
|
@@ -62787,6 +62837,11 @@ class Domain extends _abstract_object_1.AbstractObject {
|
|
|
62787
62837
|
var _a;
|
|
62788
62838
|
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.conversionExit;
|
|
62789
62839
|
}
|
|
62840
|
+
getDataType() {
|
|
62841
|
+
var _a;
|
|
62842
|
+
this.parse();
|
|
62843
|
+
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.datatype;
|
|
62844
|
+
}
|
|
62790
62845
|
getAllowedNaming() {
|
|
62791
62846
|
return {
|
|
62792
62847
|
maxLength: 30,
|
|
@@ -69718,7 +69773,7 @@ class Registry {
|
|
|
69718
69773
|
}
|
|
69719
69774
|
static abaplintVersion() {
|
|
69720
69775
|
// magic, see build script "version.js"
|
|
69721
|
-
return "2.120.
|
|
69776
|
+
return "2.120.27";
|
|
69722
69777
|
}
|
|
69723
69778
|
getDDICReferences() {
|
|
69724
69779
|
return this.ddicReferences;
|
|
@@ -72382,6 +72437,315 @@ exports.CDSAssociationName = CDSAssociationName;
|
|
|
72382
72437
|
|
|
72383
72438
|
/***/ },
|
|
72384
72439
|
|
|
72440
|
+
/***/ "../core/build/src/rules/cds_check_syntax.js"
|
|
72441
|
+
/*!***************************************************!*\
|
|
72442
|
+
!*** ../core/build/src/rules/cds_check_syntax.js ***!
|
|
72443
|
+
\***************************************************/
|
|
72444
|
+
(__unused_webpack_module, exports, __webpack_require__) {
|
|
72445
|
+
|
|
72446
|
+
"use strict";
|
|
72447
|
+
|
|
72448
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
72449
|
+
exports.CDSCheckSyntax = exports.CDSCheckSyntaxConf = void 0;
|
|
72450
|
+
const nodes_1 = __webpack_require__(/*! ../abap/nodes */ "../core/build/src/abap/nodes/index.js");
|
|
72451
|
+
const basic_1 = __webpack_require__(/*! ../abap/types/basic */ "../core/build/src/abap/types/basic/index.js");
|
|
72452
|
+
const expressions_1 = __webpack_require__(/*! ../cds/expressions */ "../core/build/src/cds/expressions/index.js");
|
|
72453
|
+
const ddic_1 = __webpack_require__(/*! ../ddic */ "../core/build/src/ddic.js");
|
|
72454
|
+
const issue_1 = __webpack_require__(/*! ../issue */ "../core/build/src/issue.js");
|
|
72455
|
+
const objects_1 = __webpack_require__(/*! ../objects */ "../core/build/src/objects/index.js");
|
|
72456
|
+
const _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ "../core/build/src/rules/_basic_rule_config.js");
|
|
72457
|
+
const _irule_1 = __webpack_require__(/*! ./_irule */ "../core/build/src/rules/_irule.js");
|
|
72458
|
+
class CDSCheckSyntaxConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
72459
|
+
}
|
|
72460
|
+
exports.CDSCheckSyntaxConf = CDSCheckSyntaxConf;
|
|
72461
|
+
const KNOWN_QUAN_DATA_ELEMENTS = ["MENGE_D"];
|
|
72462
|
+
const KNOWN_CURR_DATA_ELEMENTS = ["BWERT", "DZWERT"];
|
|
72463
|
+
class CDSCheckSyntax {
|
|
72464
|
+
constructor() {
|
|
72465
|
+
this.conf = new CDSCheckSyntaxConf();
|
|
72466
|
+
}
|
|
72467
|
+
getMetadata() {
|
|
72468
|
+
return {
|
|
72469
|
+
key: "cds_check_syntax",
|
|
72470
|
+
title: "CDS Check Syntax",
|
|
72471
|
+
shortDescription: "Checks CDS source, field, type, and semantic annotation references",
|
|
72472
|
+
extendedInformation: `Performs semantic checks which require other DDIC objects to be available.
|
|
72473
|
+
|
|
72474
|
+
Missing objects are only reported when their names match the configured errorNamespace.`,
|
|
72475
|
+
tags: [_irule_1.RuleTag.Syntax],
|
|
72476
|
+
};
|
|
72477
|
+
}
|
|
72478
|
+
getConfig() {
|
|
72479
|
+
return this.conf;
|
|
72480
|
+
}
|
|
72481
|
+
setConfig(conf) {
|
|
72482
|
+
this.conf = conf;
|
|
72483
|
+
}
|
|
72484
|
+
initialize(reg) {
|
|
72485
|
+
this.reg = reg;
|
|
72486
|
+
return this;
|
|
72487
|
+
}
|
|
72488
|
+
run(object) {
|
|
72489
|
+
if (!(object instanceof objects_1.DataDefinition)) {
|
|
72490
|
+
return [];
|
|
72491
|
+
}
|
|
72492
|
+
const tree = object.getTree();
|
|
72493
|
+
const file = object.findSourceFile();
|
|
72494
|
+
if (tree === undefined || file === undefined) {
|
|
72495
|
+
return [];
|
|
72496
|
+
}
|
|
72497
|
+
const issues = [];
|
|
72498
|
+
const ddic = new ddic_1.DDIC(this.reg);
|
|
72499
|
+
const sources = this.findSources(tree, ddic, issues, file);
|
|
72500
|
+
this.checkRelations(tree, ddic, issues, file);
|
|
72501
|
+
this.checkTypes(tree, ddic, issues, file);
|
|
72502
|
+
this.checkRootProjection(tree, ddic, issues, file);
|
|
72503
|
+
this.checkFieldAnnotations(tree, ddic, issues, file);
|
|
72504
|
+
this.checkFields(tree, sources, object, issues, file);
|
|
72505
|
+
return issues;
|
|
72506
|
+
}
|
|
72507
|
+
findSources(tree, ddic, issues, file) {
|
|
72508
|
+
var _a;
|
|
72509
|
+
const sources = [];
|
|
72510
|
+
for (const node of tree.findAllExpressionsRecursive(expressions_1.CDSSource)) {
|
|
72511
|
+
const prefixed = node.findDirectExpression(expressions_1.CDSPrefixedName);
|
|
72512
|
+
const entityNode = prefixed === null || prefixed === void 0 ? void 0 : prefixed.findDirectExpression(expressions_1.CDSName);
|
|
72513
|
+
if (entityNode === undefined) {
|
|
72514
|
+
continue;
|
|
72515
|
+
}
|
|
72516
|
+
const entity = this.name(entityNode);
|
|
72517
|
+
const asName = (_a = node.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
|
|
72518
|
+
const bareAlias = node.findDirectExpression(expressions_1.CDSName);
|
|
72519
|
+
const alias = asName === undefined ? bareAlias : asName;
|
|
72520
|
+
const lookup = ddic.lookupTableOrView(entity);
|
|
72521
|
+
if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(entity)) {
|
|
72522
|
+
issues.push(issue_1.Issue.atToken(file, entityNode.getFirstToken(), `CDS source "${entity}" not found`, this.getMetadata().key, this.conf.severity));
|
|
72523
|
+
}
|
|
72524
|
+
if (lookup.type instanceof basic_1.StructureType || lookup.type instanceof basic_1.UnknownType || lookup.type instanceof basic_1.VoidType) {
|
|
72525
|
+
const names = [entity.toUpperCase()];
|
|
72526
|
+
if (alias) {
|
|
72527
|
+
names.push(this.name(alias).toUpperCase());
|
|
72528
|
+
}
|
|
72529
|
+
sources.push({ entity, names, type: lookup.type });
|
|
72530
|
+
}
|
|
72531
|
+
}
|
|
72532
|
+
return sources;
|
|
72533
|
+
}
|
|
72534
|
+
checkRelations(tree, ddic, issues, file) {
|
|
72535
|
+
for (const relation of tree.findAllExpressionsRecursive(expressions_1.CDSRelation)) {
|
|
72536
|
+
const directTokens = relation.getDirectTokens();
|
|
72537
|
+
if (directTokens.length === 0) {
|
|
72538
|
+
continue;
|
|
72539
|
+
}
|
|
72540
|
+
const entity = directTokens.map(t => t.getStr()).join("");
|
|
72541
|
+
const lookup = ddic.lookupTableOrView(entity);
|
|
72542
|
+
if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(entity)) {
|
|
72543
|
+
issues.push(issue_1.Issue.atToken(file, directTokens[0], `CDS source "${entity}" not found`, this.getMetadata().key, this.conf.severity));
|
|
72544
|
+
}
|
|
72545
|
+
}
|
|
72546
|
+
}
|
|
72547
|
+
checkTypes(tree, ddic, issues, file) {
|
|
72548
|
+
for (const typeNode of tree.findAllExpressionsRecursive(expressions_1.CDSType)) {
|
|
72549
|
+
const typeName = typeNode.findDirectExpressions(expressions_1.CDSName).map(n => this.name(n)).join(".");
|
|
72550
|
+
if (typeName === "" || typeName.toUpperCase().startsWith("ABAP.")) {
|
|
72551
|
+
continue;
|
|
72552
|
+
}
|
|
72553
|
+
const lookup = ddic.lookup(typeName);
|
|
72554
|
+
if (lookup.type instanceof basic_1.UnknownType && lookup.object === undefined && this.reg.inErrorNamespace(typeName)) {
|
|
72555
|
+
issues.push(issue_1.Issue.atToken(file, typeNode.getFirstToken(), `CDS type "${typeName}" not found`, this.getMetadata().key, this.conf.severity));
|
|
72556
|
+
}
|
|
72557
|
+
}
|
|
72558
|
+
}
|
|
72559
|
+
checkRootProjection(tree, ddic, issues, file) {
|
|
72560
|
+
var _a;
|
|
72561
|
+
const projection = tree.findFirstExpression(expressions_1.CDSDefineProjection);
|
|
72562
|
+
const rootToken = projection === null || projection === void 0 ? void 0 : projection.findDirectTokenByText("ROOT");
|
|
72563
|
+
if (projection === undefined || rootToken === undefined) {
|
|
72564
|
+
return;
|
|
72565
|
+
}
|
|
72566
|
+
const names = projection.findDirectExpressions(expressions_1.CDSName);
|
|
72567
|
+
const projectedEntityNode = names[1];
|
|
72568
|
+
if (projectedEntityNode === undefined) {
|
|
72569
|
+
return;
|
|
72570
|
+
}
|
|
72571
|
+
const projectedEntityName = this.name(projectedEntityNode);
|
|
72572
|
+
const projectedEntity = ddic.lookupTableOrView(projectedEntityName).object;
|
|
72573
|
+
if (projectedEntity instanceof objects_1.DataDefinition
|
|
72574
|
+
&& ((_a = projectedEntity.getTree()) === null || _a === void 0 ? void 0 : _a.findDirectTokenByText("ROOT")) === undefined) {
|
|
72575
|
+
const message = `ROOT keyword not valid since ${projectedEntityName} is not a root property`;
|
|
72576
|
+
issues.push(issue_1.Issue.atToken(file, rootToken, message, this.getMetadata().key, this.conf.severity));
|
|
72577
|
+
}
|
|
72578
|
+
}
|
|
72579
|
+
checkFieldAnnotations(tree, ddic, issues, file) {
|
|
72580
|
+
const definition = tree.findFirstExpression(expressions_1.CDSDefineAbstract);
|
|
72581
|
+
if (definition === undefined) {
|
|
72582
|
+
return;
|
|
72583
|
+
}
|
|
72584
|
+
let definitionNameSeen = false;
|
|
72585
|
+
let fieldName;
|
|
72586
|
+
let annotations = [];
|
|
72587
|
+
const fields = [];
|
|
72588
|
+
for (const child of definition.getChildren()) {
|
|
72589
|
+
if (child instanceof nodes_1.TokenNode) {
|
|
72590
|
+
if (child.get().getStr() === ";") {
|
|
72591
|
+
fieldName = undefined;
|
|
72592
|
+
annotations = [];
|
|
72593
|
+
}
|
|
72594
|
+
continue;
|
|
72595
|
+
}
|
|
72596
|
+
else if (child.get() instanceof expressions_1.CDSAnnotation) {
|
|
72597
|
+
annotations.push(child);
|
|
72598
|
+
}
|
|
72599
|
+
else if (child.get() instanceof expressions_1.CDSName) {
|
|
72600
|
+
if (definitionNameSeen === false) {
|
|
72601
|
+
definitionNameSeen = true;
|
|
72602
|
+
annotations = [];
|
|
72603
|
+
}
|
|
72604
|
+
else {
|
|
72605
|
+
fieldName = child;
|
|
72606
|
+
}
|
|
72607
|
+
}
|
|
72608
|
+
else if (child.get() instanceof expressions_1.CDSType && fieldName !== undefined) {
|
|
72609
|
+
const semanticType = this.determineSemanticType(child, ddic);
|
|
72610
|
+
const normalizedAnnotations = annotations.map(a => a.concatTokens().replace(/\s/g, ""));
|
|
72611
|
+
fields.push({ name: this.name(fieldName), node: fieldName, annotations: normalizedAnnotations, semanticType });
|
|
72612
|
+
fieldName = undefined;
|
|
72613
|
+
annotations = [];
|
|
72614
|
+
}
|
|
72615
|
+
}
|
|
72616
|
+
const reportedCompanionFields = new Set();
|
|
72617
|
+
for (const field of fields) {
|
|
72618
|
+
if (field.semanticType === undefined) {
|
|
72619
|
+
continue;
|
|
72620
|
+
}
|
|
72621
|
+
const quantity = field.semanticType === "QUAN";
|
|
72622
|
+
const referenceAnnotation = quantity ? "@Semantics.quantity.unitOfMeasure" : "@Semantics.amount.currencyCode";
|
|
72623
|
+
const companionAnnotation = quantity ? "@Semantics.unitOfMeasure: true" : "@Semantics.currencyCode: true";
|
|
72624
|
+
const reference = this.findSemanticReference(field.annotations, field.semanticType);
|
|
72625
|
+
if (reference === undefined) {
|
|
72626
|
+
const kind = quantity ? "quantity" : "amount";
|
|
72627
|
+
const message = `CDS ${kind} field "${field.name}" requires ${referenceAnnotation}`;
|
|
72628
|
+
issues.push(issue_1.Issue.atToken(file, field.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72629
|
+
continue;
|
|
72630
|
+
}
|
|
72631
|
+
const companion = fields.find(f => f.name.toUpperCase() === reference.toUpperCase());
|
|
72632
|
+
if (companion === undefined) {
|
|
72633
|
+
const kind = quantity ? "unit" : "currency";
|
|
72634
|
+
const message = `CDS field "${field.name}" references missing ${kind} field "${reference}"`;
|
|
72635
|
+
issues.push(issue_1.Issue.atToken(file, field.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72636
|
+
continue;
|
|
72637
|
+
}
|
|
72638
|
+
const companionKey = field.semanticType + ":" + companion.name.toUpperCase();
|
|
72639
|
+
if (reportedCompanionFields.has(companionKey) === false
|
|
72640
|
+
&& this.hasCompanionAnnotation(companion.annotations, field.semanticType) === false) {
|
|
72641
|
+
const message = `CDS field "${companion.name}" requires ${companionAnnotation}`;
|
|
72642
|
+
issues.push(issue_1.Issue.atToken(file, companion.node.getFirstToken(), message, this.getMetadata().key, this.conf.severity));
|
|
72643
|
+
reportedCompanionFields.add(companionKey);
|
|
72644
|
+
}
|
|
72645
|
+
}
|
|
72646
|
+
}
|
|
72647
|
+
determineSemanticType(typeNode, ddic) {
|
|
72648
|
+
var _a;
|
|
72649
|
+
const typeName = typeNode.findDirectExpressions(expressions_1.CDSName).map(n => this.name(n)).join(".");
|
|
72650
|
+
const upper = typeName.toUpperCase();
|
|
72651
|
+
if (upper === "ABAP.QUAN" || KNOWN_QUAN_DATA_ELEMENTS.includes(upper)) {
|
|
72652
|
+
return "QUAN";
|
|
72653
|
+
}
|
|
72654
|
+
else if (upper === "ABAP.CURR" || KNOWN_CURR_DATA_ELEMENTS.includes(upper)) {
|
|
72655
|
+
return "CURR";
|
|
72656
|
+
}
|
|
72657
|
+
const object = ddic.lookup(typeName).object;
|
|
72658
|
+
if (object instanceof objects_1.DataElement) {
|
|
72659
|
+
const dataType = (_a = object.getDataType(this.reg)) === null || _a === void 0 ? void 0 : _a.toUpperCase();
|
|
72660
|
+
if (dataType === "QUAN" || dataType === "CURR") {
|
|
72661
|
+
return dataType;
|
|
72662
|
+
}
|
|
72663
|
+
}
|
|
72664
|
+
return undefined;
|
|
72665
|
+
}
|
|
72666
|
+
findSemanticReference(annotations, type) {
|
|
72667
|
+
const expression = type === "QUAN"
|
|
72668
|
+
? /(?:SEMANTICS\.QUANTITY|SEMANTICS:\{QUANTITY:\{)\.?UNITOFMEASURE:'([^']+)'/i
|
|
72669
|
+
: /(?:SEMANTICS\.AMOUNT|SEMANTICS:\{AMOUNT:\{)\.?CURRENCYCODE:'([^']+)'/i;
|
|
72670
|
+
for (const annotation of annotations) {
|
|
72671
|
+
const match = annotation.match(expression);
|
|
72672
|
+
if (match) {
|
|
72673
|
+
return match[1];
|
|
72674
|
+
}
|
|
72675
|
+
}
|
|
72676
|
+
return undefined;
|
|
72677
|
+
}
|
|
72678
|
+
hasCompanionAnnotation(annotations, type) {
|
|
72679
|
+
if (type === "QUAN") {
|
|
72680
|
+
return annotations.some(a => a.toUpperCase().includes("@SEMANTICS.UNITOFMEASURE:TRUE")
|
|
72681
|
+
|| a.toUpperCase().includes("@SEMANTICS:{UNITOFMEASURE:TRUE"));
|
|
72682
|
+
}
|
|
72683
|
+
else {
|
|
72684
|
+
return annotations.some(a => a.toUpperCase().includes("@SEMANTICS.CURRENCYCODE:TRUE")
|
|
72685
|
+
|| a.toUpperCase().includes("@SEMANTICS:{CURRENCYCODE:TRUE"));
|
|
72686
|
+
}
|
|
72687
|
+
}
|
|
72688
|
+
checkFields(tree, sources, object, issues, file) {
|
|
72689
|
+
var _a;
|
|
72690
|
+
const associationNames = new Set();
|
|
72691
|
+
for (const association of ((_a = object.getParsedData()) === null || _a === void 0 ? void 0 : _a.associations) || []) {
|
|
72692
|
+
associationNames.add(association.name.toUpperCase());
|
|
72693
|
+
if (association.as) {
|
|
72694
|
+
associationNames.add(association.as.toUpperCase());
|
|
72695
|
+
}
|
|
72696
|
+
}
|
|
72697
|
+
for (const element of tree.findAllExpressionsRecursive(expressions_1.CDSElement)) {
|
|
72698
|
+
const prefixed = element.findDirectExpression(expressions_1.CDSPrefixedName);
|
|
72699
|
+
if (prefixed === undefined) {
|
|
72700
|
+
continue;
|
|
72701
|
+
}
|
|
72702
|
+
const names = prefixed.findDirectExpressions(expressions_1.CDSName);
|
|
72703
|
+
if (names.length === 0) {
|
|
72704
|
+
continue;
|
|
72705
|
+
}
|
|
72706
|
+
const first = this.name(names[0]);
|
|
72707
|
+
if (first === "*" || first.startsWith("$") || first.startsWith("#") || associationNames.has(first.toUpperCase())) {
|
|
72708
|
+
continue;
|
|
72709
|
+
}
|
|
72710
|
+
if (names.length > 1) {
|
|
72711
|
+
const matchingSources = sources.filter(s => s.names.includes(first.toUpperCase()));
|
|
72712
|
+
if (matchingSources.length !== 1) {
|
|
72713
|
+
continue;
|
|
72714
|
+
}
|
|
72715
|
+
const source = matchingSources[0];
|
|
72716
|
+
const sourceType = source.type;
|
|
72717
|
+
if (!(sourceType instanceof basic_1.StructureType)) {
|
|
72718
|
+
continue;
|
|
72719
|
+
}
|
|
72720
|
+
const field = this.name(names[1]);
|
|
72721
|
+
if (field !== "*" && sourceType.getComponentByName(field) === undefined) {
|
|
72722
|
+
issues.push(issue_1.Issue.atToken(file, names[1].getFirstToken(), `CDS field "${field}" not found in "${source.entity}"`, this.getMetadata().key, this.conf.severity));
|
|
72723
|
+
}
|
|
72724
|
+
continue;
|
|
72725
|
+
}
|
|
72726
|
+
// Do not guess across joins or when a dependency is absent.
|
|
72727
|
+
if (sources.length !== 1) {
|
|
72728
|
+
continue;
|
|
72729
|
+
}
|
|
72730
|
+
const source = sources[0];
|
|
72731
|
+
const sourceType = source.type;
|
|
72732
|
+
if (!(sourceType instanceof basic_1.StructureType)) {
|
|
72733
|
+
continue;
|
|
72734
|
+
}
|
|
72735
|
+
if (sourceType.getComponentByName(first) === undefined) {
|
|
72736
|
+
issues.push(issue_1.Issue.atToken(file, names[0].getFirstToken(), `CDS field "${first}" not found in "${source.entity}"`, this.getMetadata().key, this.conf.severity));
|
|
72737
|
+
}
|
|
72738
|
+
}
|
|
72739
|
+
}
|
|
72740
|
+
name(node) {
|
|
72741
|
+
return node.concatTokens().replace(/ /g, "");
|
|
72742
|
+
}
|
|
72743
|
+
}
|
|
72744
|
+
exports.CDSCheckSyntax = CDSCheckSyntax;
|
|
72745
|
+
//# sourceMappingURL=cds_check_syntax.js.map
|
|
72746
|
+
|
|
72747
|
+
/***/ },
|
|
72748
|
+
|
|
72385
72749
|
/***/ "../core/build/src/rules/cds_comment_style.js"
|
|
72386
72750
|
/*!****************************************************!*\
|
|
72387
72751
|
!*** ../core/build/src/rules/cds_comment_style.js ***!
|
|
@@ -83476,6 +83840,7 @@ __exportStar(__webpack_require__(/*! ./begin_single_include */ "../core/build/sr
|
|
|
83476
83840
|
__exportStar(__webpack_require__(/*! ./call_transaction_authority_check */ "../core/build/src/rules/call_transaction_authority_check.js"), exports);
|
|
83477
83841
|
__exportStar(__webpack_require__(/*! ./catch_and_raise */ "../core/build/src/rules/catch_and_raise.js"), exports);
|
|
83478
83842
|
__exportStar(__webpack_require__(/*! ./cds_association_name */ "../core/build/src/rules/cds_association_name.js"), exports);
|
|
83843
|
+
__exportStar(__webpack_require__(/*! ./cds_check_syntax */ "../core/build/src/rules/cds_check_syntax.js"), exports);
|
|
83479
83844
|
__exportStar(__webpack_require__(/*! ./cds_comment_style */ "../core/build/src/rules/cds_comment_style.js"), exports);
|
|
83480
83845
|
__exportStar(__webpack_require__(/*! ./cds_field_order */ "../core/build/src/rules/cds_field_order.js"), exports);
|
|
83481
83846
|
__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.27",
|
|
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.27",
|
|
43
43
|
"@types/chai": "^4.3.20",
|
|
44
44
|
"@types/minimist": "^1.2.5",
|
|
45
45
|
"@types/mocha": "^10.0.10",
|