@abaplint/core 2.120.43 → 2.120.45
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/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/5_syntax/expressions/value_body.js +32 -0
- package/build/src/abap/types/method_parameters.js +17 -3
- package/build/src/objects/behavior_definition.js +47 -0
- package/build/src/objects/lock_object.js +19 -1
- package/build/src/objects/table.js +20 -4
- package/build/src/registry.js +1 -1
- package/build/src/rules/line_break_style.js +12 -3
- package/build/src/rules/xml_consistency.js +31 -3
- 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,6 +5644,14 @@ 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;
|
|
@@ -7938,6 +7966,8 @@ declare class Table extends AbstractObject {
|
|
|
7938
7966
|
listKeys(reg: IRegistry): string[];
|
|
7939
7967
|
parseType(reg: IRegistry): AbstractType;
|
|
7940
7968
|
getTableCategory(): TableCategory | undefined;
|
|
7969
|
+
getDeliveryClass(): string | undefined;
|
|
7970
|
+
getSizeCategory(): string | undefined;
|
|
7941
7971
|
getEnhancementCategory(): EnhancementCategory;
|
|
7942
7972
|
private keyFieldsNotFirst;
|
|
7943
7973
|
private parseXML;
|
|
@@ -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
|
}
|
|
@@ -131,6 +131,19 @@ class ValueBody {
|
|
|
131
131
|
const message = "VALUE, source type CharacterType not compatible with StringType";
|
|
132
132
|
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
|
|
133
133
|
}
|
|
134
|
+
else if (this.insertsUsingTableKey(targetType)) {
|
|
135
|
+
// only STANDARD tables append the rows, and thus allow padding of shorter c and x values
|
|
136
|
+
const row = this.characterOrHexLength(rowType);
|
|
137
|
+
const source = this.characterOrHexLength(sourceType);
|
|
138
|
+
if (row !== undefined
|
|
139
|
+
&& source !== undefined
|
|
140
|
+
&& row.abap === source.abap
|
|
141
|
+
&& row.length !== source.length) {
|
|
142
|
+
const message = `VALUE, source type ${source.abap} LENGTH ${source.length} not compatible ` +
|
|
143
|
+
`with row type ${row.abap} LENGTH ${row.length}`;
|
|
144
|
+
input.issues.push((0, _syntax_input_1.syntaxIssue)(input, s.getFirstToken(), message));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
134
147
|
}
|
|
135
148
|
}
|
|
136
149
|
if (letScoped === true) {
|
|
@@ -144,6 +157,25 @@ class ValueBody {
|
|
|
144
157
|
}
|
|
145
158
|
return targetType ? targetType : type;
|
|
146
159
|
}
|
|
160
|
+
/** SORTED and HASHED tables insert the constructed rows using the table key, which
|
|
161
|
+
* requires the rows to be compatible with the row type. STANDARD tables only append
|
|
162
|
+
* the rows, so shorter c and x values are padded on the right instead. */
|
|
163
|
+
static insertsUsingTableKey(targetType) {
|
|
164
|
+
if (!(targetType instanceof basic_1.TableType)) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
const accessType = targetType.getAccessType();
|
|
168
|
+
return accessType === basic_1.TableAccessType.sorted || accessType === basic_1.TableAccessType.hashed;
|
|
169
|
+
}
|
|
170
|
+
static characterOrHexLength(type) {
|
|
171
|
+
if (type instanceof basic_1.CharacterType) {
|
|
172
|
+
return { abap: "c", length: type.getLength() };
|
|
173
|
+
}
|
|
174
|
+
else if (type instanceof basic_1.HexType) {
|
|
175
|
+
return { abap: "x", length: type.getLength() };
|
|
176
|
+
}
|
|
177
|
+
return undefined;
|
|
178
|
+
}
|
|
147
179
|
}
|
|
148
180
|
exports.ValueBody = ValueBody;
|
|
149
181
|
//# sourceMappingURL=value_body.js.map
|
|
@@ -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 ")
|
|
@@ -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
|
|
@@ -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
|
}
|
|
@@ -310,6 +310,20 @@ class Table extends _abstract_object_1.AbstractObject {
|
|
|
310
310
|
}
|
|
311
311
|
return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.tableCategory;
|
|
312
312
|
}
|
|
313
|
+
getDeliveryClass() {
|
|
314
|
+
var _a;
|
|
315
|
+
if (this.parsedData === undefined) {
|
|
316
|
+
this.parseXML();
|
|
317
|
+
}
|
|
318
|
+
return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.deliveryClass;
|
|
319
|
+
}
|
|
320
|
+
getSizeCategory() {
|
|
321
|
+
var _a;
|
|
322
|
+
if (this.parsedData === undefined) {
|
|
323
|
+
this.parseXML();
|
|
324
|
+
}
|
|
325
|
+
return (_a = this.parsedData) === null || _a === void 0 ? void 0 : _a.sizeCategory;
|
|
326
|
+
}
|
|
313
327
|
getEnhancementCategory() {
|
|
314
328
|
var _a;
|
|
315
329
|
if (this.parsedData === undefined) {
|
|
@@ -337,7 +351,7 @@ class Table extends _abstract_object_1.AbstractObject {
|
|
|
337
351
|
return false;
|
|
338
352
|
}
|
|
339
353
|
parseXML() {
|
|
340
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
|
|
354
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12;
|
|
341
355
|
const parsed = super.parseRaw2();
|
|
342
356
|
if (parsed === undefined) {
|
|
343
357
|
return;
|
|
@@ -357,8 +371,10 @@ class Table extends _abstract_object_1.AbstractObject {
|
|
|
357
371
|
this.parsedData.tableCategory = (_m = (_l = (_k = (_j = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _j === void 0 ? void 0 : _j["asx:abap"]) === null || _k === void 0 ? void 0 : _k["asx:values"]) === null || _l === void 0 ? void 0 : _l.DD02V) === null || _m === void 0 ? void 0 : _m.TABCLASS;
|
|
358
372
|
this.parsedData.description = (_r = (_q = (_p = (_o = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _o === void 0 ? void 0 : _o["asx:abap"]) === null || _p === void 0 ? void 0 : _p["asx:values"]) === null || _q === void 0 ? void 0 : _q.DD02V) === null || _r === void 0 ? void 0 : _r.DDTEXT;
|
|
359
373
|
this.parsedData.dataClass = (_v = (_u = (_t = (_s = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _s === void 0 ? void 0 : _s["asx:abap"]) === null || _t === void 0 ? void 0 : _t["asx:values"]) === null || _u === void 0 ? void 0 : _u.DD09L) === null || _v === void 0 ? void 0 : _v.TABART;
|
|
374
|
+
this.parsedData.deliveryClass = (_z = (_y = (_x = (_w = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _w === void 0 ? void 0 : _w["asx:abap"]) === null || _x === void 0 ? void 0 : _x["asx:values"]) === null || _y === void 0 ? void 0 : _y.DD02V) === null || _z === void 0 ? void 0 : _z.CONTFLAG;
|
|
375
|
+
this.parsedData.sizeCategory = (_3 = (_2 = (_1 = (_0 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _0 === void 0 ? void 0 : _0["asx:abap"]) === null || _1 === void 0 ? void 0 : _1["asx:values"]) === null || _2 === void 0 ? void 0 : _2.DD09L) === null || _3 === void 0 ? void 0 : _3.TABKAT;
|
|
360
376
|
// fields
|
|
361
|
-
const fields = (
|
|
377
|
+
const fields = (_6 = (_5 = (_4 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _4 === void 0 ? void 0 : _4["asx:abap"]) === null || _5 === void 0 ? void 0 : _5["asx:values"]) === null || _6 === void 0 ? void 0 : _6.DD03P_TABLE;
|
|
362
378
|
for (const field of (0, xml_utils_1.xmlToArray)(fields === null || fields === void 0 ? void 0 : fields.DD03P)) {
|
|
363
379
|
if (typeof (field === null || field === void 0 ? void 0 : field.FIELDNAME) !== "string") {
|
|
364
380
|
continue;
|
|
@@ -382,13 +398,13 @@ class Table extends _abstract_object_1.AbstractObject {
|
|
|
382
398
|
});
|
|
383
399
|
}
|
|
384
400
|
// secondary indexes
|
|
385
|
-
const indexes = (
|
|
401
|
+
const indexes = (_9 = (_8 = (_7 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _7 === void 0 ? void 0 : _7["asx:abap"]) === null || _8 === void 0 ? void 0 : _8["asx:values"]) === null || _9 === void 0 ? void 0 : _9.DD12V;
|
|
386
402
|
;
|
|
387
403
|
this.parsedData.secondaryIndexes = [];
|
|
388
404
|
for (const index of (0, xml_utils_1.xmlToArray)(indexes === null || indexes === void 0 ? void 0 : indexes.DD12V)) {
|
|
389
405
|
const indexName = index.INDEXNAME;
|
|
390
406
|
const indexFields = [];
|
|
391
|
-
const indexFieldsXml = (
|
|
407
|
+
const indexFieldsXml = (_12 = (_11 = (_10 = parsed === null || parsed === void 0 ? void 0 : parsed.abapGit) === null || _10 === void 0 ? void 0 : _10["asx:abap"]) === null || _11 === void 0 ? void 0 : _11["asx:values"]) === null || _12 === void 0 ? void 0 : _12.DD17V;
|
|
392
408
|
for (const indexField of (0, xml_utils_1.xmlToArray)(indexFieldsXml === null || indexFieldsXml === void 0 ? void 0 : indexFieldsXml.DD17V)) {
|
|
393
409
|
if (indexField.INDEXNAME === indexName) {
|
|
394
410
|
// assumption: fields are listed by POSITION in the xml
|
package/build/src/registry.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.LineBreakStyle = exports.LineBreakStyleConf = void 0;
|
|
|
4
4
|
const issue_1 = require("../issue");
|
|
5
5
|
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
6
6
|
const _irule_1 = require("./_irule");
|
|
7
|
+
const objects_1 = require("../objects");
|
|
7
8
|
class LineBreakStyleConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
8
9
|
}
|
|
9
10
|
exports.LineBreakStyleConf = LineBreakStyleConf;
|
|
@@ -14,10 +15,11 @@ class LineBreakStyle {
|
|
|
14
15
|
getMetadata() {
|
|
15
16
|
return {
|
|
16
17
|
key: "line_break_style",
|
|
17
|
-
title: "Makes sure line breaks are consistent
|
|
18
|
-
shortDescription: `Enforces LF as newlines in ABAP files
|
|
18
|
+
title: "Makes sure line breaks are consistent",
|
|
19
|
+
shortDescription: `Enforces LF as newlines in ABAP and XML files
|
|
19
20
|
|
|
20
21
|
abapGit does not work with CRLF`,
|
|
22
|
+
extendedInformation: `SMIM and W3MI files are not checked.`,
|
|
21
23
|
tags: [_irule_1.RuleTag.Whitespace, _irule_1.RuleTag.SingleFile],
|
|
22
24
|
};
|
|
23
25
|
}
|
|
@@ -32,8 +34,15 @@ abapGit does not work with CRLF`,
|
|
|
32
34
|
}
|
|
33
35
|
run(obj) {
|
|
34
36
|
const output = [];
|
|
37
|
+
if (obj instanceof objects_1.MIMEObject || obj instanceof objects_1.WebMIME) {
|
|
38
|
+
return output;
|
|
39
|
+
}
|
|
35
40
|
for (const file of obj.getFiles()) {
|
|
36
|
-
|
|
41
|
+
const filename = file.getFilename();
|
|
42
|
+
if (filename.endsWith(".abap") || filename.endsWith(".xml")) {
|
|
43
|
+
if (filename.endsWith(".xslt.source.xml")) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
37
46
|
const rows = file.getRawRows();
|
|
38
47
|
for (let i = 0; i < rows.length; i++) {
|
|
39
48
|
if (rows[i].endsWith("\r") === true) {
|
|
@@ -64,6 +64,8 @@ class XMLConsistency {
|
|
|
64
64
|
* XML is well-formed and parseable
|
|
65
65
|
* Naming for CLAS and INTF objects
|
|
66
66
|
* QUAN fields in TABL objects have reference table and field values
|
|
67
|
+
* Transparent TABL objects have delivery class and size category set
|
|
68
|
+
* Lock parameter names in ENQU objects are max 16 characters
|
|
67
69
|
* Texts and translations do not exceed maximum allowed length.`,
|
|
68
70
|
tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax],
|
|
69
71
|
};
|
|
@@ -121,6 +123,9 @@ class XMLConsistency {
|
|
|
121
123
|
else if (obj instanceof Objects.Table) {
|
|
122
124
|
issues.push(...this.runTable(obj, file));
|
|
123
125
|
}
|
|
126
|
+
else if (obj instanceof Objects.LockObject) {
|
|
127
|
+
issues.push(...this.runLockObject(obj, file));
|
|
128
|
+
}
|
|
124
129
|
if (obj instanceof _abap_object_1.ABAPObject) {
|
|
125
130
|
issues.push(...this.runTextPool(obj, file));
|
|
126
131
|
}
|
|
@@ -304,16 +309,39 @@ class XMLConsistency {
|
|
|
304
309
|
}
|
|
305
310
|
return issues;
|
|
306
311
|
}
|
|
312
|
+
runLockObject(obj, file) {
|
|
313
|
+
var _a;
|
|
314
|
+
const maxParameterLength = 16;
|
|
315
|
+
const issues = [];
|
|
316
|
+
for (const parameter of (_a = obj.getParameters()) !== null && _a !== void 0 ? _a : []) {
|
|
317
|
+
if (parameter.VIEWFIELD.length > maxParameterLength) {
|
|
318
|
+
const message = `Lock parameter ${parameter.VIEWFIELD} exceeds maximum length of ` +
|
|
319
|
+
`${maxParameterLength} characters (actual: ${parameter.VIEWFIELD.length})`;
|
|
320
|
+
issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return issues;
|
|
324
|
+
}
|
|
307
325
|
runTable(obj, file) {
|
|
308
|
-
var _a, _b;
|
|
309
|
-
var
|
|
326
|
+
var _a, _b, _c, _d;
|
|
327
|
+
var _e;
|
|
310
328
|
const issues = [];
|
|
311
|
-
for (const field of (
|
|
329
|
+
for (const field of (_e = obj.getFields()) !== null && _e !== void 0 ? _e : []) {
|
|
312
330
|
if (field.DATATYPE === "QUAN" && (!((_a = field.REFTABLE) === null || _a === void 0 ? void 0 : _a.trim()) || !((_b = field.REFFIELD) === null || _b === void 0 ? void 0 : _b.trim()))) {
|
|
313
331
|
const message = `QUAN field ${field.FIELDNAME} must have REFTABLE and REFFIELD set`;
|
|
314
332
|
issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
|
|
315
333
|
}
|
|
316
334
|
}
|
|
335
|
+
if (obj.getTableCategory() === Objects.TableCategory.Transparent) {
|
|
336
|
+
if (!((_c = obj.getDeliveryClass()) === null || _c === void 0 ? void 0 : _c.trim())) {
|
|
337
|
+
const message = `Transparent table must have delivery class(CONTFLAG in DD02V) set`;
|
|
338
|
+
issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
|
|
339
|
+
}
|
|
340
|
+
if (!((_d = obj.getSizeCategory()) === null || _d === void 0 ? void 0 : _d.trim())) {
|
|
341
|
+
const message = `Transparent table must have size category(TABKAT in DD09L) set`;
|
|
342
|
+
issues.push(issue_1.Issue.atRow(file, 1, message, this.getMetadata().key, this.conf.severity));
|
|
343
|
+
}
|
|
344
|
+
}
|
|
317
345
|
return issues;
|
|
318
346
|
}
|
|
319
347
|
}
|