@abaplint/core 2.102.15 → 2.102.16
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 +9 -3
- package/build/src/abap/2_statements/expressions/index.js +3 -2
- package/build/src/abap/2_statements/expressions/transporting_fields.js +14 -0
- package/build/src/abap/2_statements/statements/read_table.js +2 -2
- package/build/src/abap/5_syntax/expressions/message_source.js +10 -4
- package/build/src/abap/5_syntax/statements/include_type.js +6 -2
- package/build/src/abap/5_syntax/statements/raise.js +8 -2
- package/build/src/abap/5_syntax/statements/read_table.js +23 -14
- package/build/src/msag_references.js +3 -0
- package/build/src/objects/message_class.js +2 -0
- package/build/src/registry.js +1 -1
- package/build/src/rules/message_exists.js +107 -43
- package/build/src/rules/parser_missing_space.js +23 -3
- package/package.json +1 -1
package/build/abaplint.d.ts
CHANGED
|
@@ -2015,7 +2015,6 @@ declare namespace Expressions {
|
|
|
2015
2015
|
ComponentCondSub,
|
|
2016
2016
|
ComponentCond,
|
|
2017
2017
|
ComponentName,
|
|
2018
|
-
SQLFields,
|
|
2019
2018
|
ConcatenatedConstant,
|
|
2020
2019
|
CondBody,
|
|
2021
2020
|
CondSub,
|
|
@@ -2139,8 +2138,8 @@ declare namespace Expressions {
|
|
|
2139
2138
|
Source,
|
|
2140
2139
|
SQLAggregation,
|
|
2141
2140
|
SQLAliasField,
|
|
2142
|
-
SQLArithmetics,
|
|
2143
2141
|
SQLArithmeticOperator,
|
|
2142
|
+
SQLArithmetics,
|
|
2144
2143
|
SQLAsName,
|
|
2145
2144
|
SQLCase,
|
|
2146
2145
|
SQLCDSParameters,
|
|
@@ -2153,6 +2152,7 @@ declare namespace Expressions {
|
|
|
2153
2152
|
SQLFieldList,
|
|
2154
2153
|
SQLFieldName,
|
|
2155
2154
|
SQLField,
|
|
2155
|
+
SQLFields,
|
|
2156
2156
|
SQLForAllEntries,
|
|
2157
2157
|
SQLFromSource,
|
|
2158
2158
|
SQLFrom,
|
|
@@ -2185,6 +2185,7 @@ declare namespace Expressions {
|
|
|
2185
2185
|
TextElementString,
|
|
2186
2186
|
TextElement,
|
|
2187
2187
|
Throw,
|
|
2188
|
+
TransportingFields,
|
|
2188
2189
|
TypeNameOrInfer,
|
|
2189
2190
|
TypeName,
|
|
2190
2191
|
TypeParam,
|
|
@@ -3706,7 +3707,8 @@ declare interface IStructure {
|
|
|
3706
3707
|
declare interface IStructureComponent {
|
|
3707
3708
|
name: string;
|
|
3708
3709
|
type: AbstractType;
|
|
3709
|
-
|
|
3710
|
+
asInclude?: boolean;
|
|
3711
|
+
suffix?: string;
|
|
3710
3712
|
}
|
|
3711
3713
|
|
|
3712
3714
|
declare interface IStructureRunnable {
|
|
@@ -6326,6 +6328,10 @@ declare class Translate implements IStatement {
|
|
|
6326
6328
|
getMatcher(): IStatementRunnable;
|
|
6327
6329
|
}
|
|
6328
6330
|
|
|
6331
|
+
declare class TransportingFields extends Expression {
|
|
6332
|
+
getRunnable(): IStatementRunnable;
|
|
6333
|
+
}
|
|
6334
|
+
|
|
6329
6335
|
declare class TruncateDataset implements IStatement {
|
|
6330
6336
|
getMatcher(): IStatementRunnable;
|
|
6331
6337
|
}
|
|
@@ -43,7 +43,6 @@ __exportStar(require("./component_compare"), exports);
|
|
|
43
43
|
__exportStar(require("./component_cond_sub"), exports);
|
|
44
44
|
__exportStar(require("./component_cond"), exports);
|
|
45
45
|
__exportStar(require("./component_name"), exports);
|
|
46
|
-
__exportStar(require("./sql_fields"), exports);
|
|
47
46
|
__exportStar(require("./concatenated_constant"), exports);
|
|
48
47
|
__exportStar(require("./cond_body"), exports);
|
|
49
48
|
__exportStar(require("./cond_sub"), exports);
|
|
@@ -168,8 +167,8 @@ __exportStar(require("./source_field"), exports);
|
|
|
168
167
|
__exportStar(require("./source"), exports);
|
|
169
168
|
__exportStar(require("./sql_aggregation"), exports);
|
|
170
169
|
__exportStar(require("./sql_alias_field"), exports);
|
|
171
|
-
__exportStar(require("./sql_arithmetics"), exports);
|
|
172
170
|
__exportStar(require("./sql_arithmetic_operator"), exports);
|
|
171
|
+
__exportStar(require("./sql_arithmetics"), exports);
|
|
173
172
|
__exportStar(require("./sql_as_name"), exports);
|
|
174
173
|
__exportStar(require("./sql_case"), exports);
|
|
175
174
|
__exportStar(require("./sql_cds_parameters"), exports);
|
|
@@ -182,6 +181,7 @@ __exportStar(require("./sql_field_list_loop"), exports);
|
|
|
182
181
|
__exportStar(require("./sql_field_list"), exports);
|
|
183
182
|
__exportStar(require("./sql_field_name"), exports);
|
|
184
183
|
__exportStar(require("./sql_field"), exports);
|
|
184
|
+
__exportStar(require("./sql_fields"), exports);
|
|
185
185
|
__exportStar(require("./sql_for_all_entries"), exports);
|
|
186
186
|
__exportStar(require("./sql_from_source"), exports);
|
|
187
187
|
__exportStar(require("./sql_from"), exports);
|
|
@@ -214,6 +214,7 @@ __exportStar(require("./text_element_key"), exports);
|
|
|
214
214
|
__exportStar(require("./text_element_string"), exports);
|
|
215
215
|
__exportStar(require("./text_element"), exports);
|
|
216
216
|
__exportStar(require("./throw"), exports);
|
|
217
|
+
__exportStar(require("./transporting_fields"), exports);
|
|
217
218
|
__exportStar(require("./type_name_or_infer"), exports);
|
|
218
219
|
__exportStar(require("./type_name"), exports);
|
|
219
220
|
__exportStar(require("./type_param"), exports);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TransportingFields = void 0;
|
|
4
|
+
const combi_1 = require("../combi");
|
|
5
|
+
const dynamic_1 = require("./dynamic");
|
|
6
|
+
const field_sub_1 = require("./field_sub");
|
|
7
|
+
class TransportingFields extends combi_1.Expression {
|
|
8
|
+
getRunnable() {
|
|
9
|
+
const fields = (0, combi_1.plus)((0, combi_1.alt)((0, combi_1.seq)("INTO", (0, combi_1.failStar)()), field_sub_1.FieldSub));
|
|
10
|
+
return (0, combi_1.altPrio)(dynamic_1.Dynamic, fields);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
exports.TransportingFields = TransportingFields;
|
|
14
|
+
//# sourceMappingURL=transporting_fields.js.map
|
|
@@ -4,6 +4,7 @@ exports.ReadTable = void 0;
|
|
|
4
4
|
const combi_1 = require("../combi");
|
|
5
5
|
const expressions_1 = require("../expressions");
|
|
6
6
|
const version_1 = require("../../../version");
|
|
7
|
+
const transporting_fields_1 = require("../expressions/transporting_fields");
|
|
7
8
|
class ReadTable {
|
|
8
9
|
getMatcher() {
|
|
9
10
|
const comparing = (0, combi_1.seq)("COMPARING", (0, combi_1.alt)((0, combi_1.plus)(expressions_1.FieldSub), expressions_1.Dynamic));
|
|
@@ -12,8 +13,7 @@ class ReadTable {
|
|
|
12
13
|
const key = (0, combi_1.seq)((0, combi_1.altPrio)("WITH KEY", "WITH TABLE KEY"), (0, combi_1.alt)(expressions_1.ComponentCompareSimple, components, (0, combi_1.seq)((0, combi_1.optPrio)("="), expressions_1.Source)));
|
|
13
14
|
const using = (0, combi_1.seq)("USING KEY", (0, combi_1.alt)(expressions_1.Field, expressions_1.Dynamic));
|
|
14
15
|
const from = (0, combi_1.seq)("FROM", expressions_1.Source);
|
|
15
|
-
const
|
|
16
|
-
const perm = (0, combi_1.per)((0, combi_1.alt)(index, key, from), expressions_1.ReadTableTarget, using, comparing, "CASTING", "TRANSPORTING ALL FIELDS", (0, combi_1.seq)("TRANSPORTING", (0, combi_1.altPrio)(expressions_1.Dynamic, fields)), "BINARY SEARCH");
|
|
16
|
+
const perm = (0, combi_1.per)((0, combi_1.alt)(index, key, from), expressions_1.ReadTableTarget, using, comparing, "CASTING", "TRANSPORTING ALL FIELDS", (0, combi_1.seq)("TRANSPORTING", transporting_fields_1.TransportingFields), "BINARY SEARCH");
|
|
17
17
|
return (0, combi_1.seq)("READ TABLE", (0, combi_1.alt)(expressions_1.SimpleSource2, (0, combi_1.ver)(version_1.Version.v740sp02, expressions_1.Source)), (0, combi_1.opt)(perm));
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -5,22 +5,28 @@ const Expressions = require("../../2_statements/expressions");
|
|
|
5
5
|
const source_1 = require("./source");
|
|
6
6
|
class MessageSource {
|
|
7
7
|
runSyntax(node, scope, filename) {
|
|
8
|
-
var _a, _b, _c, _d;
|
|
8
|
+
var _a, _b, _c, _d, _e;
|
|
9
9
|
for (const f of node.findDirectExpressions(Expressions.Source)) {
|
|
10
10
|
new source_1.Source().runSyntax(f, scope, filename);
|
|
11
11
|
}
|
|
12
12
|
if (node.getFirstToken().getStr().toUpperCase() === "ID") {
|
|
13
13
|
const id = (_a = node.findExpressionAfterToken("ID")) === null || _a === void 0 ? void 0 : _a.concatTokens();
|
|
14
|
-
|
|
14
|
+
let number = (_b = node.findDirectExpression(Expressions.MessageNumber)) === null || _b === void 0 ? void 0 : _b.concatTokens();
|
|
15
|
+
if (number === undefined) {
|
|
16
|
+
const num = (_c = node.findExpressionAfterToken("NUMBER")) === null || _c === void 0 ? void 0 : _c.concatTokens();
|
|
17
|
+
if (num === null || num === void 0 ? void 0 : num.startsWith("'")) {
|
|
18
|
+
number = num.substring(1, num.length - 1).toUpperCase();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
15
21
|
if ((id === null || id === void 0 ? void 0 : id.startsWith("'")) && number) {
|
|
16
22
|
const messageClass = id.substring(1, id.length - 1).toUpperCase();
|
|
17
23
|
scope.getMSAGReferences().addUsing(filename, node.getFirstToken(), messageClass, number);
|
|
18
24
|
}
|
|
19
25
|
}
|
|
20
26
|
else {
|
|
21
|
-
const typeAndNumber = (
|
|
27
|
+
const typeAndNumber = (_d = node.findDirectExpression(Expressions.MessageTypeAndNumber)) === null || _d === void 0 ? void 0 : _d.concatTokens();
|
|
22
28
|
const messageNumber = typeAndNumber === null || typeAndNumber === void 0 ? void 0 : typeAndNumber.substring(1);
|
|
23
|
-
const messageClass = (
|
|
29
|
+
const messageClass = (_e = node.findDirectExpression(Expressions.MessageClass)) === null || _e === void 0 ? void 0 : _e.concatTokens().toUpperCase();
|
|
24
30
|
if (messageNumber && messageClass) {
|
|
25
31
|
scope.getMSAGReferences().addUsing(filename, node.getFirstToken(), messageClass, messageNumber);
|
|
26
32
|
}
|
|
@@ -17,14 +17,18 @@ class IncludeType {
|
|
|
17
17
|
let ityp = new basic_types_1.BasicTypes(filename, scope).parseType(iname);
|
|
18
18
|
const as = (_a = node.findExpressionAfterToken("AS")) === null || _a === void 0 ? void 0 : _a.concatTokens();
|
|
19
19
|
if (as && ityp instanceof basic_1.StructureType) {
|
|
20
|
-
ityp = new basic_1.StructureType(ityp.getComponents().concat([{
|
|
20
|
+
ityp = new basic_1.StructureType(ityp.getComponents().concat([{
|
|
21
|
+
name: as,
|
|
22
|
+
type: ityp,
|
|
23
|
+
asInclude: true,
|
|
24
|
+
}]));
|
|
21
25
|
}
|
|
22
26
|
const suffix = (_b = node.findExpressionAfterToken("SUFFIX")) === null || _b === void 0 ? void 0 : _b.concatTokens();
|
|
23
27
|
if (suffix && ityp instanceof basic_1.StructureType) {
|
|
24
28
|
const components = [];
|
|
25
29
|
for (const c of ityp.getComponents()) {
|
|
26
30
|
if (c.name === as) {
|
|
27
|
-
components.push(Object.assign(Object.assign({}, c), {
|
|
31
|
+
components.push(Object.assign(Object.assign({}, c), { suffix: suffix, asInclude: c.asInclude }));
|
|
28
32
|
continue;
|
|
29
33
|
}
|
|
30
34
|
components.push({
|
|
@@ -13,7 +13,7 @@ const method_parameters_1 = require("../expressions/method_parameters");
|
|
|
13
13
|
class Raise {
|
|
14
14
|
runSyntax(node, scope, filename) {
|
|
15
15
|
// todo
|
|
16
|
-
var _a, _b, _c, _d, _e;
|
|
16
|
+
var _a, _b, _c, _d, _e, _f;
|
|
17
17
|
const helper = new _object_oriented_1.ObjectOriented(scope);
|
|
18
18
|
let method;
|
|
19
19
|
const classTok = (_a = node.findDirectExpression(Expressions.ClassName)) === null || _a === void 0 ? void 0 : _a.getFirstToken();
|
|
@@ -72,7 +72,13 @@ class Raise {
|
|
|
72
72
|
new message_source_1.MessageSource().runSyntax(s, scope, filename);
|
|
73
73
|
}
|
|
74
74
|
const id = (_d = node.findExpressionAfterToken("ID")) === null || _d === void 0 ? void 0 : _d.concatTokens();
|
|
75
|
-
|
|
75
|
+
let number = (_e = node.findDirectExpression(Expressions.MessageNumber)) === null || _e === void 0 ? void 0 : _e.concatTokens();
|
|
76
|
+
if (number === undefined) {
|
|
77
|
+
const num = (_f = node.findExpressionAfterToken("NUMBER")) === null || _f === void 0 ? void 0 : _f.concatTokens();
|
|
78
|
+
if (num === null || num === void 0 ? void 0 : num.startsWith("'")) {
|
|
79
|
+
number = num.substring(1, num.length - 1).toUpperCase();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
76
82
|
if ((id === null || id === void 0 ? void 0 : id.startsWith("'")) && number) {
|
|
77
83
|
const messageClass = id.substring(1, id.length - 1).toUpperCase();
|
|
78
84
|
scope.getMSAGReferences().addUsing(filename, node.getFirstToken(), messageClass, number);
|
|
@@ -58,29 +58,19 @@ class ReadTable {
|
|
|
58
58
|
rowType = new basic_1.DataReference(rowType);
|
|
59
59
|
}
|
|
60
60
|
const inline = target.findFirstExpression(Expressions.InlineData);
|
|
61
|
+
const fst = target.findDirectExpression(Expressions.FSTarget);
|
|
62
|
+
const t = target.findFirstExpression(Expressions.Target);
|
|
61
63
|
if (inline) {
|
|
62
64
|
new inline_data_1.InlineData().runSyntax(inline, scope, filename, rowType);
|
|
63
|
-
return;
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
if (fst) {
|
|
66
|
+
else if (fst) {
|
|
67
67
|
new fstarget_1.FSTarget().runSyntax(fst, scope, filename, rowType);
|
|
68
|
-
return;
|
|
69
68
|
}
|
|
70
|
-
|
|
71
|
-
const inlinefs = target.findFirstExpression(Expressions.InlineFS);
|
|
72
|
-
if (inlinefs) {
|
|
73
|
-
new InlineFS().runSyntax(inlinefs, scope, filename, sourceType);
|
|
74
|
-
return;
|
|
75
|
-
}
|
|
76
|
-
*/
|
|
77
|
-
const t = target.findFirstExpression(Expressions.Target);
|
|
78
|
-
if (t) {
|
|
69
|
+
else if (t) {
|
|
79
70
|
const targetType = new target_1.Target().runSyntax(t, scope, filename);
|
|
80
71
|
if (new _type_utils_1.TypeUtils(scope).isAssignable(rowType, targetType) === false) {
|
|
81
72
|
throw new Error("Incompatible types");
|
|
82
73
|
}
|
|
83
|
-
return;
|
|
84
74
|
}
|
|
85
75
|
}
|
|
86
76
|
if (target === undefined && concat.includes(" TRANSPORTING NO FIELDS ") === false) {
|
|
@@ -89,6 +79,25 @@ class ReadTable {
|
|
|
89
79
|
throw new Error("READ TABLE, define INTO or TRANSPORTING NO FIELDS");
|
|
90
80
|
}
|
|
91
81
|
}
|
|
82
|
+
const transporting = node.findDirectExpression(Expressions.TransportingFields);
|
|
83
|
+
if (transporting
|
|
84
|
+
&& !(rowType instanceof basic_1.VoidType)
|
|
85
|
+
&& !(rowType instanceof basic_1.UnknownType)
|
|
86
|
+
&& !(rowType instanceof basic_1.AnyType)) {
|
|
87
|
+
if (!(rowType instanceof basic_1.StructureType)) {
|
|
88
|
+
throw new Error("READ TABLE, source not structured");
|
|
89
|
+
}
|
|
90
|
+
for (const t of (transporting === null || transporting === void 0 ? void 0 : transporting.findDirectExpressions(Expressions.FieldSub)) || []) {
|
|
91
|
+
const field = t.concatTokens();
|
|
92
|
+
if (field.includes("-")) {
|
|
93
|
+
// todo
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (rowType.getComponentByName(field) === undefined) {
|
|
97
|
+
throw new Error("READ TABLE, field " + field + " not found in source");
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
92
101
|
}
|
|
93
102
|
}
|
|
94
103
|
exports.ReadTable = ReadTable;
|
|
@@ -13,6 +13,7 @@ class MessageClass extends _abstract_object_1.AbstractObject {
|
|
|
13
13
|
return "MSAG";
|
|
14
14
|
}
|
|
15
15
|
getDescription() {
|
|
16
|
+
this.parseXML();
|
|
16
17
|
// todo
|
|
17
18
|
return undefined;
|
|
18
19
|
}
|
|
@@ -32,6 +33,7 @@ class MessageClass extends _abstract_object_1.AbstractObject {
|
|
|
32
33
|
return msg ? msg : [];
|
|
33
34
|
}
|
|
34
35
|
getByNumber(num) {
|
|
36
|
+
this.parseXML();
|
|
35
37
|
// todo, optimize performance,
|
|
36
38
|
for (const message of this.getMessages()) {
|
|
37
39
|
if (message.getNumber() === num) {
|
package/build/src/registry.js
CHANGED
|
@@ -2,17 +2,23 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.MessageExistsRule = exports.MessageExistsConf = void 0;
|
|
4
4
|
const Expressions = require("../abap/2_statements/expressions");
|
|
5
|
+
const Statements = require("../abap/2_statements/statements");
|
|
5
6
|
const issue_1 = require("../issue");
|
|
6
|
-
const _abap_rule_1 = require("./_abap_rule");
|
|
7
7
|
const _basic_rule_config_1 = require("./_basic_rule_config");
|
|
8
8
|
const ddic_1 = require("../ddic");
|
|
9
9
|
const _irule_1 = require("./_irule");
|
|
10
|
+
const nodes_1 = require("../abap/nodes");
|
|
11
|
+
const _abap_object_1 = require("../objects/_abap_object");
|
|
12
|
+
const syntax_1 = require("../abap/5_syntax/syntax");
|
|
10
13
|
class MessageExistsConf extends _basic_rule_config_1.BasicRuleConfig {
|
|
14
|
+
constructor() {
|
|
15
|
+
super(...arguments);
|
|
16
|
+
this.checkPlaceholders = true;
|
|
17
|
+
}
|
|
11
18
|
}
|
|
12
19
|
exports.MessageExistsConf = MessageExistsConf;
|
|
13
|
-
class MessageExistsRule
|
|
20
|
+
class MessageExistsRule {
|
|
14
21
|
constructor() {
|
|
15
|
-
super(...arguments);
|
|
16
22
|
this.conf = new MessageExistsConf();
|
|
17
23
|
}
|
|
18
24
|
getMetadata() {
|
|
@@ -29,58 +35,116 @@ class MessageExistsRule extends _abap_rule_1.ABAPRule {
|
|
|
29
35
|
setConfig(conf) {
|
|
30
36
|
this.conf = conf;
|
|
31
37
|
}
|
|
32
|
-
|
|
38
|
+
initialize(reg) {
|
|
39
|
+
this.msagReferences = reg.getMSAGReferences();
|
|
40
|
+
this.reg = reg;
|
|
41
|
+
// the SyntaxLogic builds the references
|
|
42
|
+
for (const obj of reg.getObjects()) {
|
|
43
|
+
if (obj instanceof _abap_object_1.ABAPObject) {
|
|
44
|
+
new syntax_1.SyntaxLogic(reg, obj).run();
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
run(obj) {
|
|
33
50
|
const issues = [];
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
51
|
+
if (obj instanceof _abap_object_1.ABAPObject) {
|
|
52
|
+
for (const file of obj.getABAPFiles()) {
|
|
53
|
+
const struc = file.getStructure();
|
|
54
|
+
if (struc === undefined) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
issues.push(...this.checkReportStatement(file));
|
|
58
|
+
issues.push(...this.checkSource(file));
|
|
59
|
+
}
|
|
37
60
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
return issues;
|
|
62
|
+
}
|
|
63
|
+
////////////////////////////////
|
|
64
|
+
checkReportStatement(file) {
|
|
65
|
+
const issues = [];
|
|
66
|
+
for (const statement of file.getStatements()) {
|
|
67
|
+
if (!(statement.get() instanceof Statements.Report)) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const expression = statement.findFirstExpression(Expressions.MessageClass);
|
|
71
|
+
if (expression) {
|
|
72
|
+
const issue = this.checkClass(expression, file);
|
|
73
|
+
if (issue) {
|
|
47
74
|
issues.push(issue);
|
|
48
75
|
}
|
|
49
76
|
}
|
|
50
77
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
return issues;
|
|
79
|
+
}
|
|
80
|
+
checkClass(node, file) {
|
|
81
|
+
const token = node.getFirstToken();
|
|
82
|
+
const name = token.getStr();
|
|
83
|
+
if (this.reg.getObject("MSAG", name) === undefined
|
|
84
|
+
&& new ddic_1.DDIC(this.reg).inErrorNamespace(name) === true) {
|
|
85
|
+
const message = "Message class \"" + name + "\" not found";
|
|
86
|
+
return issue_1.Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity);
|
|
87
|
+
}
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
checkSource(file) {
|
|
91
|
+
const issues = [];
|
|
92
|
+
const references = this.msagReferences.listByFilename(file.getFilename());
|
|
93
|
+
for (const statement of file.getStatements()) {
|
|
94
|
+
if (statement.get() instanceof Statements.Raise || statement.get() instanceof Statements.Message) {
|
|
95
|
+
for (const ref of references) {
|
|
96
|
+
// always max one message reference per statement? chained statements?
|
|
97
|
+
if (ref.token.getStart().isBetween(statement.getStart(), statement.getEnd())) {
|
|
98
|
+
const msag = this.reg.getObject("MSAG", ref.messageClass);
|
|
99
|
+
if (msag === undefined) {
|
|
100
|
+
if (new ddic_1.DDIC(this.reg).inErrorNamespace(ref.messageClass) === true) {
|
|
101
|
+
const message = "Message class \"" + ref.token.getStr() + "\" not found";
|
|
102
|
+
issues.push(issue_1.Issue.atToken(file, ref.token, message, this.getMetadata().key, this.conf.severity));
|
|
103
|
+
}
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
const text = msag.getByNumber(ref.number);
|
|
107
|
+
if (text === undefined) {
|
|
108
|
+
const message = "Message number \"" + ref.number + "\" not found in class \"" + ref.messageClass + "\"";
|
|
109
|
+
issues.push(issue_1.Issue.atToken(file, ref.token, message, this.getMetadata().key, this.conf.severity));
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
if (this.getConfig().checkPlaceholders === true) {
|
|
113
|
+
const count = this.countWith(statement);
|
|
114
|
+
const textCount = text.getPlaceholderCount();
|
|
115
|
+
if (count !== textCount) {
|
|
116
|
+
const message = `Message ${ref.number}, expected ${textCount} WITH parameters`;
|
|
117
|
+
issues.push(issue_1.Issue.atToken(file, ref.token, message, this.getMetadata().key, this.conf.severity));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
66
120
|
}
|
|
67
|
-
continue;
|
|
68
121
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return issues;
|
|
125
|
+
}
|
|
126
|
+
countWith(statement) {
|
|
127
|
+
const raiseWith = statement.findDirectExpression(Expressions.RaiseWith);
|
|
128
|
+
if (raiseWith) {
|
|
129
|
+
return raiseWith.getChildren().length - 1;
|
|
130
|
+
}
|
|
131
|
+
let count = 0;
|
|
132
|
+
let afterWith = false;
|
|
133
|
+
for (const expression of statement.getChildren()) {
|
|
134
|
+
if (expression instanceof nodes_1.TokenNode && expression.concatTokens().toUpperCase() === "WITH") {
|
|
135
|
+
afterWith = true;
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (afterWith === true) {
|
|
139
|
+
if (expression instanceof nodes_1.ExpressionNode) {
|
|
140
|
+
count++;
|
|
72
141
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (msag.getByNumber(num) === undefined) {
|
|
76
|
-
const message = "Message number \"" + num + "\" not found in class \"" + name + "\"";
|
|
77
|
-
const issue = issue_1.Issue.atToken(file, numberToken, message, this.getMetadata().key, this.conf.severity);
|
|
78
|
-
issues.push(issue);
|
|
142
|
+
else {
|
|
143
|
+
break;
|
|
79
144
|
}
|
|
80
145
|
}
|
|
81
146
|
}
|
|
82
|
-
|
|
83
|
-
return issues;
|
|
147
|
+
return count;
|
|
84
148
|
}
|
|
85
149
|
}
|
|
86
150
|
exports.MessageExistsRule = MessageExistsRule;
|
|
@@ -49,15 +49,21 @@ This rule makes sure the spaces are consistently required across the language.`,
|
|
|
49
49
|
return issues;
|
|
50
50
|
}
|
|
51
51
|
missingSpace(statement) {
|
|
52
|
-
const found = statement.findAllExpressionsMulti([
|
|
53
|
-
Expressions.
|
|
54
|
-
Expressions.
|
|
52
|
+
const found = statement.findAllExpressionsMulti([
|
|
53
|
+
Expressions.CondSub, Expressions.SQLCond, Expressions.ValueBodyLine,
|
|
54
|
+
Expressions.NewObject, Expressions.Cond, Expressions.ComponentCond,
|
|
55
|
+
Expressions.Source,
|
|
56
|
+
Expressions.ComponentCondSub, Expressions.MethodCallParam
|
|
57
|
+
], true);
|
|
55
58
|
let pos = undefined;
|
|
56
59
|
for (const f of found) {
|
|
57
60
|
const type = f.get();
|
|
58
61
|
if (type instanceof Expressions.Cond) {
|
|
59
62
|
pos = this.checkCond(f);
|
|
60
63
|
}
|
|
64
|
+
else if (type instanceof Expressions.Source) {
|
|
65
|
+
pos = this.checkSource(f);
|
|
66
|
+
}
|
|
61
67
|
else if (type instanceof Expressions.CondSub) {
|
|
62
68
|
pos = this.checkCondSub(f);
|
|
63
69
|
}
|
|
@@ -210,6 +216,20 @@ This rule makes sure the spaces are consistently required across the language.`,
|
|
|
210
216
|
}
|
|
211
217
|
return undefined;
|
|
212
218
|
}
|
|
219
|
+
checkSource(cond) {
|
|
220
|
+
const children = cond.getAllTokens();
|
|
221
|
+
if (children.length < 2) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
const nextLast = children[children.length - 2];
|
|
225
|
+
const last = children[children.length - 1];
|
|
226
|
+
if (nextLast.getStr().startsWith("'")
|
|
227
|
+
&& nextLast.getRow() === last.getRow()
|
|
228
|
+
&& nextLast.getEnd().getCol() === last.getStart().getCol()) {
|
|
229
|
+
return last.getEnd();
|
|
230
|
+
}
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
213
233
|
checkMethodCallParam(call) {
|
|
214
234
|
const children = call.getChildren();
|
|
215
235
|
{
|