@abaplint/core 2.120.42 → 2.120.44
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/abaplint.d.ts +30 -0
- package/build/src/abap/2_statements/statements/write.js +1 -1
- package/build/src/abap/4_file_information/abap_file_information_parser.js +16 -0
- package/build/src/abap/5_syntax/_current_scope.js +12 -0
- package/build/src/abap/5_syntax/basic_types.js +28 -16
- package/build/src/abap/types/method_parameters.js +17 -3
- package/build/src/cds/cds_determine_types.js +4 -2
- package/build/src/objects/behavior_definition.js +47 -0
- package/build/src/objects/data_definition.js +12 -12
- package/build/src/objects/lock_object.js +19 -1
- package/build/src/registry.js +1 -1
- package/build/src/rules/xml_consistency.js +20 -1
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -558,12 +558,22 @@ declare namespace BasicTypes {
|
|
|
558
558
|
export { BasicTypes }
|
|
559
559
|
|
|
560
560
|
declare class BehaviorDefinition extends AbstractObject {
|
|
561
|
+
private parsedData;
|
|
561
562
|
getType(): string;
|
|
562
563
|
getAllowedNaming(): {
|
|
563
564
|
maxLength: number;
|
|
564
565
|
allowNamespace: boolean;
|
|
565
566
|
};
|
|
566
567
|
getDescription(): string | undefined;
|
|
568
|
+
setDirty(): void;
|
|
569
|
+
findSourceFile(): IFile | undefined;
|
|
570
|
+
listEntities(): readonly {
|
|
571
|
+
name: string;
|
|
572
|
+
alias: string | undefined;
|
|
573
|
+
}[];
|
|
574
|
+
/** finds the entity name for a given alias, undefined if the alias is not defined */
|
|
575
|
+
findEntityNameByAlias(alias: string): string | undefined;
|
|
576
|
+
private parseSource;
|
|
567
577
|
}
|
|
568
578
|
|
|
569
579
|
declare class BehaviorDefinitionName extends Expression {
|
|
@@ -1626,6 +1636,8 @@ export declare class CurrentScope {
|
|
|
1626
1636
|
addSQLConversion(fieldName: string, message: string, token: Token): void;
|
|
1627
1637
|
findFunctionModule(name: string | undefined): FunctionModuleDefinition | undefined;
|
|
1628
1638
|
findObjectDefinition(name: string | undefined): IClassDefinition | IInterfaceDefinition | undefined;
|
|
1639
|
+
/** the BDEF from "FOR BEHAVIOR OF" of the enclosing global class, undefined if not a behavior pool */
|
|
1640
|
+
findBehaviorDefinition(): BehaviorDefinition | undefined;
|
|
1629
1641
|
isBadiDef(name: string): boolean;
|
|
1630
1642
|
existsObject(name: string | undefined): {
|
|
1631
1643
|
id: Identifier | undefined;
|
|
@@ -3888,6 +3900,8 @@ declare interface InfoClassDefinition extends InfoInterfaceDefinition {
|
|
|
3888
3900
|
duration: Duration | undefined;
|
|
3889
3901
|
riskLevel: RiskLevel | undefined;
|
|
3890
3902
|
isSharedMemory: boolean;
|
|
3903
|
+
/** name of the BDEF from "FOR BEHAVIOR OF", undefined if not a behavior pool */
|
|
3904
|
+
behaviorDefinitionName: string | undefined;
|
|
3891
3905
|
}
|
|
3892
3906
|
|
|
3893
3907
|
declare interface InfoClassImplementation {
|
|
@@ -4599,6 +4613,11 @@ declare class LockObject extends AbstractObject {
|
|
|
4599
4613
|
getAllowedNaming(): IAllowedNaming;
|
|
4600
4614
|
setDirty(): void;
|
|
4601
4615
|
getPrimaryTable(): string | undefined;
|
|
4616
|
+
getParameters(): {
|
|
4617
|
+
VIEWFIELD: string;
|
|
4618
|
+
TABNAME?: string;
|
|
4619
|
+
FIELDNAME?: string;
|
|
4620
|
+
}[] | undefined;
|
|
4602
4621
|
parseType(reg: IRegistry): AbstractType;
|
|
4603
4622
|
parse(): {
|
|
4604
4623
|
updated: boolean;
|
|
@@ -5324,6 +5343,7 @@ declare namespace Objects {
|
|
|
5324
5343
|
AuthorizationObjectExtension,
|
|
5325
5344
|
AuthorizationObject,
|
|
5326
5345
|
BADIDefinition,
|
|
5346
|
+
ParsedBehaviorDefinition,
|
|
5327
5347
|
BehaviorDefinition,
|
|
5328
5348
|
BRFPlusSystemApplication,
|
|
5329
5349
|
BSPApplication,
|
|
@@ -5624,13 +5644,23 @@ declare class ParenRightW extends Token {
|
|
|
5624
5644
|
static railroad(): string;
|
|
5625
5645
|
}
|
|
5626
5646
|
|
|
5647
|
+
declare type ParsedBehaviorDefinition = {
|
|
5648
|
+
/** entities defined in the behavior definition, alias is undefined if not specified */
|
|
5649
|
+
entities: {
|
|
5650
|
+
name: string;
|
|
5651
|
+
alias: string | undefined;
|
|
5652
|
+
}[];
|
|
5653
|
+
};
|
|
5654
|
+
|
|
5627
5655
|
declare type ParsedDataDefinition = {
|
|
5628
5656
|
sqlViewName: string | undefined;
|
|
5629
5657
|
definitionName: string | undefined;
|
|
5630
5658
|
description: string | undefined;
|
|
5659
|
+
/** name is the name of the element, nameInSource the name in the prefixed source, if aliased via "as" */
|
|
5631
5660
|
fields: {
|
|
5632
5661
|
key: boolean;
|
|
5633
5662
|
name: string;
|
|
5663
|
+
nameInSource?: string;
|
|
5634
5664
|
prefix: string;
|
|
5635
5665
|
annotations: string[];
|
|
5636
5666
|
}[];
|
|
@@ -13,7 +13,7 @@ class Write {
|
|
|
13
13
|
const to = (0, combi_1.seq)("TO", expressions_1.Target);
|
|
14
14
|
const options = (0, combi_1.per)(mask, to, (0, combi_1.seq)("EXPONENT", expressions_1.Source), "NO-GROUPING", "NO-ZERO", "CENTERED", (0, combi_1.seq)("INPUT", (0, combi_1.opt)(onOff)), "NO-GAP", "LEFT-JUSTIFIED", as, (0, combi_1.seq)("FRAMES", onOff), (0, combi_1.seq)("HOTSPOT", (0, combi_1.opt)(onOff)), "RIGHT-JUSTIFIED", (0, combi_1.seq)("TIME ZONE", expressions_1.Source), (0, combi_1.seq)("UNDER", expressions_1.Source), (0, combi_1.seq)("STYLE", expressions_1.Source), (0, combi_1.seq)("ROUND", expressions_1.Source), (0, combi_1.seq)("QUICKINFO", expressions_1.Source), "ENVIRONMENT TIME FORMAT", dateFormat, (0, combi_1.seq)("UNIT", expressions_1.Source), (0, combi_1.seq)("INTENSIFIED", (0, combi_1.opt)(onOff)), (0, combi_1.seq)("INDEX", expressions_1.Source), (0, combi_1.seq)("DECIMALS", expressions_1.Source), (0, combi_1.seq)("INVERSE", (0, combi_1.opt)(onOff)), expressions_1.Color, (0, combi_1.seq)("CURRENCY", expressions_1.Source), "RESET", "NO-SIGN");
|
|
15
15
|
// Need to refactor all this sometime,
|
|
16
|
-
const ret = (0, combi_1.seq)("WRITE", (0, combi_1.alt)((0, combi_1.seq)("AT /", (0, combi_1.opt)(expressions_1.Source), (0, combi_1.opt)(
|
|
16
|
+
const ret = (0, combi_1.seq)("WRITE", (0, combi_1.alt)((0, combi_1.seq)("AT /", (0, combi_1.opt)(expressions_1.Source), (0, combi_1.opt)(options)), (0, combi_1.seq)((0, combi_1.opt)(expressions_1.WriteOffsetLength), (0, combi_1.alt)(expressions_1.Source, expressions_1.Dynamic, "/"), (0, combi_1.opt)(options))));
|
|
17
17
|
return (0, combi_1.verNotLang)(version_1.LanguageVersion.Cloud, ret);
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -37,6 +37,7 @@ exports.ABAPFileInformationParser = void 0;
|
|
|
37
37
|
const Structures = __importStar(require("../3_structures/structures"));
|
|
38
38
|
const Expressions = __importStar(require("../2_statements/expressions"));
|
|
39
39
|
const Statements = __importStar(require("../2_statements/statements"));
|
|
40
|
+
const nodes_1 = require("../nodes");
|
|
40
41
|
const _identifier_1 = require("./_identifier");
|
|
41
42
|
const Tokens = __importStar(require("../1_lexer/tokens"));
|
|
42
43
|
const visibility_1 = require("./visibility");
|
|
@@ -176,6 +177,7 @@ class ABAPFileInformationParser {
|
|
|
176
177
|
riskLevel,
|
|
177
178
|
isAbstract: (cdef === null || cdef === void 0 ? void 0 : cdef.findDirectTokenByText("ABSTRACT")) !== undefined,
|
|
178
179
|
isSharedMemory: concat.includes(" SHARED MEMORY ENABLED"),
|
|
180
|
+
behaviorDefinitionName: this.findBehaviorDefinitionName(cdef),
|
|
179
181
|
isFinal: found.findFirstExpression(Expressions.ClassFinal) !== undefined,
|
|
180
182
|
aliases,
|
|
181
183
|
attributes,
|
|
@@ -185,6 +187,20 @@ class ABAPFileInformationParser {
|
|
|
185
187
|
return classes;
|
|
186
188
|
}
|
|
187
189
|
///////////////////
|
|
190
|
+
/** "FOR BEHAVIOR OF" and "FOR EVENTS OF" both use the BehaviorDefinitionName expression,
|
|
191
|
+
* so look at the token two positions before the expression to tell them apart */
|
|
192
|
+
findBehaviorDefinitionName(cdef) {
|
|
193
|
+
const children = (cdef === null || cdef === void 0 ? void 0 : cdef.getChildren()) || [];
|
|
194
|
+
for (let i = 2; i < children.length; i++) {
|
|
195
|
+
const child = children[i];
|
|
196
|
+
if (child instanceof nodes_1.ExpressionNode
|
|
197
|
+
&& child.get() instanceof Expressions.BehaviorDefinitionName
|
|
198
|
+
&& children[i - 2].concatTokens().toUpperCase() === "BEHAVIOR") {
|
|
199
|
+
return child.concatTokens();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return undefined;
|
|
203
|
+
}
|
|
188
204
|
getImplementing(input) {
|
|
189
205
|
const ret = [];
|
|
190
206
|
for (const node of input.findAllStatements(Statements.InterfaceDef)) {
|
|
@@ -232,6 +232,18 @@ class CurrentScope {
|
|
|
232
232
|
}
|
|
233
233
|
return undefined;
|
|
234
234
|
}
|
|
235
|
+
/** the BDEF from "FOR BEHAVIOR OF" of the enclosing global class, undefined if not a behavior pool */
|
|
236
|
+
findBehaviorDefinition() {
|
|
237
|
+
var _a;
|
|
238
|
+
if (this.parentObj.getType() !== "CLAS") {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
const name = (_a = this.parentObj.getClassDefinition()) === null || _a === void 0 ? void 0 : _a.behaviorDefinitionName;
|
|
242
|
+
if (name === undefined) {
|
|
243
|
+
return undefined;
|
|
244
|
+
}
|
|
245
|
+
return this.reg.getObject("BDEF", name);
|
|
246
|
+
}
|
|
235
247
|
isBadiDef(name) {
|
|
236
248
|
const upper = name.toUpperCase();
|
|
237
249
|
for (const enhs of this.reg.getObjectsByType("ENHS")) {
|
|
@@ -345,7 +345,7 @@ class BasicTypes {
|
|
|
345
345
|
return undefined;
|
|
346
346
|
}
|
|
347
347
|
parseTable(node, name) {
|
|
348
|
-
var _a, _b, _c
|
|
348
|
+
var _a, _b, _c;
|
|
349
349
|
const typename = node.findFirstExpression(Expressions.TypeName) || node.findFirstExpression(Expressions.EntityAssociation);
|
|
350
350
|
const text = (_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();
|
|
351
351
|
if (text === undefined) {
|
|
@@ -482,25 +482,31 @@ class BasicTypes {
|
|
|
482
482
|
return new Types.TableType(structure, options);
|
|
483
483
|
}
|
|
484
484
|
else if (typename && this.isRAPTableFor(text)) {
|
|
485
|
-
|
|
486
|
-
const ddlsName = this.getRAPBaseEntityName(name);
|
|
487
|
-
const type = (_d = this.input.scope.getDDIC().lookupDDLS(ddlsName)) === null || _d === void 0 ? void 0 : _d.type;
|
|
488
|
-
if (type) {
|
|
489
|
-
return new Types.TableType(basic_1.VoidType.get("RAP-TODO"), options);
|
|
490
|
-
}
|
|
491
|
-
else if (this.isRAPDerivedEntityName(name)) {
|
|
492
|
-
return Types.VoidType.get(name);
|
|
493
|
-
}
|
|
494
|
-
else if (this.input.scope.getDDIC().inErrorNamespace(ddlsName)) {
|
|
495
|
-
return new Types.UnknownType(`DDLS ${ddlsName} not found`);
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
498
|
-
return Types.VoidType.get(name);
|
|
499
|
-
}
|
|
485
|
+
return this.rapTableFor(typename.concatTokens(), options);
|
|
500
486
|
}
|
|
501
487
|
// fallback to old style syntax, OCCURS etc
|
|
502
488
|
return this.parseType(node, name);
|
|
503
489
|
}
|
|
490
|
+
/** type of a RAP derived table type, ie the "TABLE FOR LOCK zentity" part of a type */
|
|
491
|
+
rapTableFor(entityName, options) {
|
|
492
|
+
var _a;
|
|
493
|
+
const ddlsName = this.resolveRAPAlias(this.getRAPBaseEntityName(entityName));
|
|
494
|
+
if ((_a = this.input.scope.getDDIC().lookupDDLS(ddlsName)) === null || _a === void 0 ? void 0 : _a.type) {
|
|
495
|
+
return new Types.TableType(basic_1.VoidType.get("RAP-TODO"), options !== null && options !== void 0 ? options : {
|
|
496
|
+
withHeader: false,
|
|
497
|
+
keyType: Types.TableKeyType.user,
|
|
498
|
+
primaryKey: { name: "primary_key", type: basic_1.TableAccessType.standard, isUnique: false, keyFields: [] },
|
|
499
|
+
secondary: [],
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
else if (this.isRAPDerivedEntityName(entityName)) {
|
|
503
|
+
return Types.VoidType.get(entityName);
|
|
504
|
+
}
|
|
505
|
+
else if (this.input.scope.getDDIC().inErrorNamespace(ddlsName)) {
|
|
506
|
+
return new Types.UnknownType(`DDLS ${ddlsName} not found`);
|
|
507
|
+
}
|
|
508
|
+
return Types.VoidType.get(entityName);
|
|
509
|
+
}
|
|
504
510
|
parseType(node, qualifiedName) {
|
|
505
511
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
506
512
|
const typeName = node.findFirstExpression(Expressions.TypeName);
|
|
@@ -694,6 +700,12 @@ class BasicTypes {
|
|
|
694
700
|
const splitAt = Math.min(...candidates);
|
|
695
701
|
return name.substring(0, splitAt);
|
|
696
702
|
}
|
|
703
|
+
/** inside a behavior pool the entities are referenced via the aliases defined in the BDEF */
|
|
704
|
+
resolveRAPAlias(name) {
|
|
705
|
+
var _a;
|
|
706
|
+
var _b;
|
|
707
|
+
return (_b = (_a = this.input.scope.findBehaviorDefinition()) === null || _a === void 0 ? void 0 : _a.findEntityNameByAlias(name)) !== null && _b !== void 0 ? _b : name;
|
|
708
|
+
}
|
|
697
709
|
isRAPDerivedEntityName(name) {
|
|
698
710
|
return name.includes("\\") || name.includes("~");
|
|
699
711
|
}
|
|
@@ -41,6 +41,7 @@ const _typed_identifier_1 = require("./_typed_identifier");
|
|
|
41
41
|
const basic_1 = require("./basic");
|
|
42
42
|
const method_def_returning_1 = require("../5_syntax/expressions/method_def_returning");
|
|
43
43
|
const method_param_1 = require("../5_syntax/expressions/method_param");
|
|
44
|
+
const basic_types_1 = require("../5_syntax/basic_types");
|
|
44
45
|
const _object_oriented_1 = require("../5_syntax/_object_oriented");
|
|
45
46
|
const _reference_1 = require("../5_syntax/_reference");
|
|
46
47
|
const identifier_1 = require("../1_lexer/tokens/identifier");
|
|
@@ -228,24 +229,37 @@ class MethodParameters {
|
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
workaroundRAP(node, input, parentName) {
|
|
232
|
+
var _a;
|
|
231
233
|
const resultName = node.findExpressionAfterToken("RESULT");
|
|
232
234
|
const concat = node.concatTokens().toUpperCase();
|
|
233
235
|
const isRap = node.findExpressionAfterToken("IMPORTING")
|
|
234
236
|
|| (concat.includes(" IMPORTING REQUEST ") ? node.findExpressionAfterToken("REQUEST") : undefined);
|
|
235
237
|
if (isRap) {
|
|
238
|
+
// "FOR LOCK" handlers have a well defined signature, so the types can be derived
|
|
239
|
+
const lockEntity = concat.includes(" FOR LOCK ")
|
|
240
|
+
? (_a = node.findExpressionAfterToken("LOCK")) === null || _a === void 0 ? void 0 : _a.concatTokens()
|
|
241
|
+
: undefined;
|
|
236
242
|
for (const foo of node.findDirectExpressions(Expressions.MethodParamName)) {
|
|
237
243
|
if (foo === resultName) {
|
|
238
244
|
continue;
|
|
239
245
|
}
|
|
240
|
-
|
|
246
|
+
const type = lockEntity === undefined
|
|
247
|
+
? basic_1.VoidType.get("RapMethodParameter")
|
|
248
|
+
: new basic_types_1.BasicTypes(input).rapTableFor(lockEntity);
|
|
249
|
+
this.importing.push(new _typed_identifier_1.TypedIdentifier(foo.getFirstToken(), input.filename, type, ["importing" /* IdentifierMeta.MethodImporting */]));
|
|
250
|
+
}
|
|
251
|
+
if (lockEntity !== undefined) {
|
|
252
|
+
// note: "mapped" is not part of the signature for "FOR LOCK"
|
|
253
|
+
const token = isRap.getFirstToken();
|
|
254
|
+
this.exporting.push(new _typed_identifier_1.TypedIdentifier(new identifier_1.Identifier(token.getStart(), "failed"), input.filename, basic_1.VoidType.get(`RESPONSE FOR FAILED EARLY ${lockEntity}`), ["exporting" /* IdentifierMeta.MethodExporting */]));
|
|
255
|
+
this.exporting.push(new _typed_identifier_1.TypedIdentifier(new identifier_1.Identifier(token.getStart(), "reported"), input.filename, basic_1.VoidType.get(`RESPONSE FOR REPORTED EARLY ${lockEntity}`), ["exporting" /* IdentifierMeta.MethodExporting */]));
|
|
241
256
|
}
|
|
242
|
-
if (concat.includes(" FOR VALIDATE ")
|
|
257
|
+
else if (concat.includes(" FOR VALIDATE ")
|
|
243
258
|
|| concat.includes(" FOR BEHAVIOR ")
|
|
244
259
|
|| concat.includes(" FOR DETERMINE ")
|
|
245
260
|
|| concat.includes(" FOR FEATURES ")
|
|
246
261
|
|| concat.includes(" FOR INSTANCE FEATURES ")
|
|
247
262
|
|| concat.includes(" FOR GLOBAL AUTHORIZATION ")
|
|
248
|
-
|| concat.includes(" FOR LOCK ")
|
|
249
263
|
|| concat.includes(" FOR PRECHECK ")
|
|
250
264
|
|| concat.includes(" FOR NUMBERING ")
|
|
251
265
|
|| concat.includes(" FOR READ ")
|
|
@@ -5,6 +5,7 @@ const basic_1 = require("../abap/types/basic");
|
|
|
5
5
|
const ddic_1 = require("../ddic");
|
|
6
6
|
class CDSDetermineTypes {
|
|
7
7
|
parseType(reg, parsedData, ddlsName) {
|
|
8
|
+
var _a;
|
|
8
9
|
const ddic = new ddic_1.DDIC(reg);
|
|
9
10
|
if ((parsedData === null || parsedData === void 0 ? void 0 : parsedData.fields.length) === 0) {
|
|
10
11
|
return basic_1.VoidType.get("DDLS:todo");
|
|
@@ -41,10 +42,11 @@ class CDSDetermineTypes {
|
|
|
41
42
|
});
|
|
42
43
|
continue;
|
|
43
44
|
}
|
|
45
|
+
const nameInSource = (_a = f.nameInSource) !== null && _a !== void 0 ? _a : f.name;
|
|
44
46
|
const lookup = ddic.lookupTableOrView(source.name);
|
|
45
47
|
if (lookup.type) {
|
|
46
48
|
if (lookup.type instanceof basic_1.StructureType) {
|
|
47
|
-
const type = lookup.type.getComponentByName(
|
|
49
|
+
const type = lookup.type.getComponentByName(nameInSource);
|
|
48
50
|
if (type) {
|
|
49
51
|
components.push({
|
|
50
52
|
name: f.name,
|
|
@@ -54,7 +56,7 @@ class CDSDetermineTypes {
|
|
|
54
56
|
else {
|
|
55
57
|
components.push({
|
|
56
58
|
name: f.name,
|
|
57
|
-
type: new basic_1.UnknownType(
|
|
59
|
+
type: new basic_1.UnknownType(nameInSource + " not found in " + source.name + ", CDSDetermineTypes"),
|
|
58
60
|
});
|
|
59
61
|
}
|
|
60
62
|
}
|
|
@@ -3,6 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.BehaviorDefinition = void 0;
|
|
4
4
|
const _abstract_object_1 = require("./_abstract_object");
|
|
5
5
|
class BehaviorDefinition extends _abstract_object_1.AbstractObject {
|
|
6
|
+
constructor() {
|
|
7
|
+
super(...arguments);
|
|
8
|
+
this.parsedData = undefined;
|
|
9
|
+
}
|
|
6
10
|
getType() {
|
|
7
11
|
return "BDEF";
|
|
8
12
|
}
|
|
@@ -16,6 +20,49 @@ class BehaviorDefinition extends _abstract_object_1.AbstractObject {
|
|
|
16
20
|
// todo
|
|
17
21
|
return undefined;
|
|
18
22
|
}
|
|
23
|
+
setDirty() {
|
|
24
|
+
this.parsedData = undefined;
|
|
25
|
+
super.setDirty();
|
|
26
|
+
}
|
|
27
|
+
findSourceFile() {
|
|
28
|
+
return this.getFiles().find(f => f.getFilename().endsWith(".asbdef"));
|
|
29
|
+
}
|
|
30
|
+
listEntities() {
|
|
31
|
+
return this.parseSource().entities;
|
|
32
|
+
}
|
|
33
|
+
/** finds the entity name for a given alias, undefined if the alias is not defined */
|
|
34
|
+
findEntityNameByAlias(alias) {
|
|
35
|
+
var _a;
|
|
36
|
+
const upper = alias.toUpperCase();
|
|
37
|
+
for (const entity of this.listEntities()) {
|
|
38
|
+
if (((_a = entity.alias) === null || _a === void 0 ? void 0 : _a.toUpperCase()) === upper) {
|
|
39
|
+
return entity.name;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
/////////////////////////
|
|
45
|
+
parseSource() {
|
|
46
|
+
var _a;
|
|
47
|
+
if (this.parsedData !== undefined) {
|
|
48
|
+
return this.parsedData;
|
|
49
|
+
}
|
|
50
|
+
this.parsedData = { entities: [] };
|
|
51
|
+
const raw = (_a = this.findSourceFile()) === null || _a === void 0 ? void 0 : _a.getRaw();
|
|
52
|
+
if (raw === undefined) {
|
|
53
|
+
return this.parsedData;
|
|
54
|
+
}
|
|
55
|
+
// BDEF uses "//" for line comments
|
|
56
|
+
const stripped = raw.replace(/\/\/.*$/gm, "");
|
|
57
|
+
// eg. "define behavior for ZI_Booking alias Booking", also "define abstract behavior for ..."
|
|
58
|
+
const regex = /\bdefine\s+(?:\w+\s+)*?behavior\s+for\s+([\w/]+)(?:\s+alias\s+(\w+))?/gi;
|
|
59
|
+
let match = regex.exec(stripped);
|
|
60
|
+
while (match !== null) {
|
|
61
|
+
this.parsedData.entities.push({ name: match[1], alias: match[2] });
|
|
62
|
+
match = regex.exec(stripped);
|
|
63
|
+
}
|
|
64
|
+
return this.parsedData;
|
|
65
|
+
}
|
|
19
66
|
}
|
|
20
67
|
exports.BehaviorDefinition = BehaviorDefinition;
|
|
21
68
|
//# sourceMappingURL=behavior_definition.js.map
|
|
@@ -138,19 +138,18 @@ class DataDefinition extends _abstract_object_1.AbstractObject {
|
|
|
138
138
|
}
|
|
139
139
|
for (const e of (expr === null || expr === void 0 ? void 0 : expr.findDirectExpressions(expressions_1.CDSElement)) || []) {
|
|
140
140
|
let prefix = "";
|
|
141
|
+
let nameInSource = undefined;
|
|
141
142
|
let found = (_a = e.findDirectExpression(expressions_1.CDSAs)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(expressions_1.CDSName);
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}
|
|
153
|
-
}
|
|
143
|
+
const list = (_b = e.findDirectExpression(expressions_1.CDSPrefixedName)) === null || _b === void 0 ? void 0 : _b.findAllExpressions(expressions_1.CDSName);
|
|
144
|
+
if (list !== undefined) {
|
|
145
|
+
const redirected = list.length > 1 && e.concatTokens().toUpperCase().includes(" REDIRECTED TO ");
|
|
146
|
+
if (list.length > 1 && redirected === false) {
|
|
147
|
+
// "prefix.field" is looked up as "field" in "prefix", also when aliased via "as"
|
|
148
|
+
prefix = list[0].concatTokens();
|
|
149
|
+
nameInSource = list[list.length - 1].concatTokens();
|
|
150
|
+
}
|
|
151
|
+
if (found === undefined) {
|
|
152
|
+
found = redirected === true ? list[0] : list[list.length - 1];
|
|
154
153
|
}
|
|
155
154
|
}
|
|
156
155
|
if (found === undefined) {
|
|
@@ -172,6 +171,7 @@ class DataDefinition extends _abstract_object_1.AbstractObject {
|
|
|
172
171
|
}
|
|
173
172
|
this.parsedData.fields.push({
|
|
174
173
|
name: name,
|
|
174
|
+
nameInSource: nameInSource,
|
|
175
175
|
annotations: annotations,
|
|
176
176
|
prefix: prefix,
|
|
177
177
|
key: e.findDirectTokenByText("KEY") !== undefined,
|
|
@@ -4,6 +4,7 @@ exports.LockObject = void 0;
|
|
|
4
4
|
const basic_1 = require("../abap/types/basic");
|
|
5
5
|
const ddic_1 = require("../ddic");
|
|
6
6
|
const _abstract_object_1 = require("./_abstract_object");
|
|
7
|
+
const xml_utils_1 = require("../xml_utils");
|
|
7
8
|
class LockObject extends _abstract_object_1.AbstractObject {
|
|
8
9
|
getType() {
|
|
9
10
|
return "ENQU";
|
|
@@ -24,6 +25,11 @@ class LockObject extends _abstract_object_1.AbstractObject {
|
|
|
24
25
|
this.parse();
|
|
25
26
|
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.primaryTable;
|
|
26
27
|
}
|
|
28
|
+
getParameters() {
|
|
29
|
+
var _a;
|
|
30
|
+
this.parse();
|
|
31
|
+
return (_a = this.parsedXML) === null || _a === void 0 ? void 0 : _a.parameters;
|
|
32
|
+
}
|
|
27
33
|
parseType(reg) {
|
|
28
34
|
var _a;
|
|
29
35
|
this.parse();
|
|
@@ -48,7 +54,7 @@ class LockObject extends _abstract_object_1.AbstractObject {
|
|
|
48
54
|
}
|
|
49
55
|
}
|
|
50
56
|
parse() {
|
|
51
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
57
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
52
58
|
if (this.parsedXML) {
|
|
53
59
|
return { updated: false, runtime: 0 };
|
|
54
60
|
}
|
|
@@ -62,6 +68,18 @@ class LockObject extends _abstract_object_1.AbstractObject {
|
|
|
62
68
|
}
|
|
63
69
|
this.parsedXML.primaryTable = (_f = (_e = (_d = (_c = parsed.abapGit) === null || _c === void 0 ? void 0 : _c["asx:abap"]) === null || _d === void 0 ? void 0 : _d["asx:values"]) === null || _e === void 0 ? void 0 : _e.DD25V) === null || _f === void 0 ? void 0 : _f.ROOTTAB;
|
|
64
70
|
this.parsedXML.description = (_k = (_j = (_h = (_g = parsed.abapGit) === null || _g === void 0 ? void 0 : _g["asx:abap"]) === null || _h === void 0 ? void 0 : _h["asx:values"]) === null || _j === void 0 ? void 0 : _j.DD25V) === null || _k === void 0 ? void 0 : _k.DDTEXT;
|
|
71
|
+
this.parsedXML.parameters = [];
|
|
72
|
+
const parameters = (_o = (_m = (_l = parsed.abapGit) === null || _l === void 0 ? void 0 : _l["asx:abap"]) === null || _m === void 0 ? void 0 : _m["asx:values"]) === null || _o === void 0 ? void 0 : _o.DD27P_TABLE;
|
|
73
|
+
for (const parameter of (0, xml_utils_1.xmlToArray)(parameters === null || parameters === void 0 ? void 0 : parameters.DD27P)) {
|
|
74
|
+
if (typeof (parameter === null || parameter === void 0 ? void 0 : parameter.VIEWFIELD) !== "string") {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
this.parsedXML.parameters.push({
|
|
78
|
+
VIEWFIELD: parameter.VIEWFIELD,
|
|
79
|
+
TABNAME: parameter.TABNAME,
|
|
80
|
+
FIELDNAME: parameter.FIELDNAME,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
65
83
|
const end = Date.now();
|
|
66
84
|
return { updated: true, runtime: end - start };
|
|
67
85
|
}
|
package/build/src/registry.js
CHANGED
|
@@ -46,6 +46,8 @@ class XMLConsistencyConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
|
46
46
|
super(...arguments);
|
|
47
47
|
/** Problem severity for text and translation length checks */
|
|
48
48
|
this.textAndTranslationLengthSeverity = severity_1.Severity.Error;
|
|
49
|
+
/** Problem severity for data element(DTEL) field checks */
|
|
50
|
+
this.dataElementSeverity = severity_1.Severity.Error;
|
|
49
51
|
}
|
|
50
52
|
}
|
|
51
53
|
exports.XMLConsistencyConf = XMLConsistencyConf;
|
|
@@ -62,6 +64,7 @@ class XMLConsistency {
|
|
|
62
64
|
* XML is well-formed and parseable
|
|
63
65
|
* Naming for CLAS and INTF objects
|
|
64
66
|
* QUAN fields in TABL objects have reference table and field values
|
|
67
|
+
* Lock parameter names in ENQU objects are max 16 characters
|
|
65
68
|
* Texts and translations do not exceed maximum allowed length.`,
|
|
66
69
|
tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
|
|
67
70
|
};
|
|
@@ -119,6 +122,9 @@ class XMLConsistency {
|
|
|
119
122
|
else if (obj instanceof Objects.Table) {
|
|
120
123
|
issues.push(...this.runTable(obj, file));
|
|
121
124
|
}
|
|
125
|
+
else if (obj instanceof Objects.LockObject) {
|
|
126
|
+
issues.push(...this.runLockObject(obj, file));
|
|
127
|
+
}
|
|
122
128
|
if (obj instanceof _abap_object_1.ABAPObject) {
|
|
123
129
|
issues.push(...this.runTextPool(obj, file));
|
|
124
130
|
}
|
|
@@ -254,7 +260,7 @@ class XMLConsistency {
|
|
|
254
260
|
}
|
|
255
261
|
checkRequiredField(file, fieldName, value) {
|
|
256
262
|
if (value === undefined || value === "") {
|
|
257
|
-
return issue_1.Issue.atRow(file, 1, `Missing required field ${fieldName} in DD04V`, this.getMetadata().key, this.conf.
|
|
263
|
+
return issue_1.Issue.atRow(file, 1, `Missing required field ${fieldName} in DD04V`, this.getMetadata().key, this.conf.dataElementSeverity);
|
|
258
264
|
}
|
|
259
265
|
return undefined;
|
|
260
266
|
}
|
|
@@ -302,6 +308,19 @@ class XMLConsistency {
|
|
|
302
308
|
}
|
|
303
309
|
return issues;
|
|
304
310
|
}
|
|
311
|
+
runLockObject(obj, file) {
|
|
312
|
+
var _a;
|
|
313
|
+
const maxParameterLength = 16;
|
|
314
|
+
const issues = [];
|
|
315
|
+
for (const parameter of (_a = obj.getParameters()) !== null && _a !== void 0 ? _a : []) {
|
|
316
|
+
if (parameter.VIEWFIELD.length > maxParameterLength) {
|
|
317
|
+
const message = `Lock parameter ${parameter.VIEWFIELD} exceeds maximum length of ` +
|
|
318
|
+
`${maxParameterLength} characters (actual: ${parameter.VIEWFIELD.length})`;
|
|
319
|
+
issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return issues;
|
|
323
|
+
}
|
|
305
324
|
runTable(obj, file) {
|
|
306
325
|
var _a, _b;
|
|
307
326
|
var _c;
|