@abaplint/cli 2.93.27 → 2.93.29
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 +7 -7
- package/package.json +4 -4
package/build/cli.js
CHANGED
|
@@ -1842,7 +1842,7 @@ eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\n
|
|
|
1842
1842
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
1843
1843
|
|
|
1844
1844
|
"use strict";
|
|
1845
|
-
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.ReduceNext = void 0;\r\nconst combi_1 = __webpack_require__(/*! ../combi */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/combi.js\");\r\nconst _1 = __webpack_require__(/*! . */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst tokens_1 = __webpack_require__(/*! ../../1_lexer/tokens */ \"./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/index.js\");\r\nconst version_1 = __webpack_require__(/*! ../../../version */ \"./node_modules/@abaplint/core/build/src/version.js\");\r\nclass ReduceNext extends combi_1.Expression {\r\n getRunnable() {\r\n const calcAssign = (0, combi_1.ver)(version_1.Version.v754, (0, combi_1.alt)((0, combi_1.seq)((0, combi_1.tok)(tokens_1.WPlus), \"=\"), (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WDash), \"=\"), \"/=\", \"*=\", \"&&=\"));\r\n const fields = (0, combi_1.seq)(_1.
|
|
1845
|
+
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.ReduceNext = void 0;\r\nconst combi_1 = __webpack_require__(/*! ../combi */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/combi.js\");\r\nconst _1 = __webpack_require__(/*! . */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst tokens_1 = __webpack_require__(/*! ../../1_lexer/tokens */ \"./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/index.js\");\r\nconst version_1 = __webpack_require__(/*! ../../../version */ \"./node_modules/@abaplint/core/build/src/version.js\");\r\nclass ReduceNext extends combi_1.Expression {\r\n getRunnable() {\r\n const calcAssign = (0, combi_1.ver)(version_1.Version.v754, (0, combi_1.alt)((0, combi_1.seq)((0, combi_1.tok)(tokens_1.WPlus), \"=\"), (0, combi_1.seq)((0, combi_1.tok)(tokens_1.WDash), \"=\"), \"/=\", \"*=\", \"&&=\"));\r\n const fields = (0, combi_1.seq)(_1.SimpleFieldChain, (0, combi_1.altPrio)(\"=\", calcAssign), _1.Source);\r\n return (0, combi_1.seq)(\"NEXT\", (0, combi_1.plus)(fields));\r\n }\r\n}\r\nexports.ReduceNext = ReduceNext;\r\n//# sourceMappingURL=reduce_next.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/reduce_next.js?");
|
|
1846
1846
|
|
|
1847
1847
|
/***/ }),
|
|
1848
1848
|
|
|
@@ -6660,7 +6660,7 @@ eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\n
|
|
|
6660
6660
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
6661
6661
|
|
|
6662
6662
|
"use strict";
|
|
6663
|
-
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.BasicTypes = void 0;\r\n/* eslint-disable default-case */\r\nconst _typed_identifier_1 = __webpack_require__(/*! ../types/_typed_identifier */ \"./node_modules/@abaplint/core/build/src/abap/types/_typed_identifier.js\");\r\nconst Expressions = __webpack_require__(/*! ../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst Statements = __webpack_require__(/*! ../2_statements/statements */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js\");\r\nconst Types = __webpack_require__(/*! ../types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst _scope_type_1 = __webpack_require__(/*! ./_scope_type */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_scope_type.js\");\r\nconst _object_oriented_1 = __webpack_require__(/*! ./_object_oriented */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_object_oriented.js\");\r\nconst class_constant_1 = __webpack_require__(/*! ../types/class_constant */ \"./node_modules/@abaplint/core/build/src/abap/types/class_constant.js\");\r\nconst identifier_1 = __webpack_require__(/*! ../1_lexer/tokens/identifier */ \"./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/identifier.js\");\r\nconst _reference_1 = __webpack_require__(/*! ./_reference */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js\");\r\nconst basic_1 = __webpack_require__(/*! ../types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst field_chain_1 = __webpack_require__(/*! ./expressions/field_chain */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/field_chain.js\");\r\nconst types_1 = __webpack_require__(/*! ../types */ \"./node_modules/@abaplint/core/build/src/abap/types/index.js\");\r\nconst expressions_1 = __webpack_require__(/*! ../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst _builtin_1 = __webpack_require__(/*! ./_builtin */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js\");\r\nconst position_1 = __webpack_require__(/*! ../../position */ \"./node_modules/@abaplint/core/build/src/position.js\");\r\nclass BasicTypes {\r\n constructor(filename, scope) {\r\n this.filename = filename;\r\n this.scope = scope;\r\n }\r\n lookupQualifiedName(name) {\r\n var _a;\r\n // argh, todo, rewrite this entire method\r\n if (name === undefined) {\r\n return undefined;\r\n }\r\n const found = this.scope.findType(name);\r\n if (found) {\r\n return found;\r\n }\r\n if (name.includes(\"=>\")) {\r\n const split = name.split(\"=>\");\r\n const ooName = split[0];\r\n const typeName = split[1];\r\n const oo = this.scope.findObjectDefinition(ooName);\r\n if (oo) {\r\n const f = oo.getTypeDefinitions().getByName(typeName);\r\n if (f) {\r\n return f;\r\n }\r\n }\r\n }\r\n else if (name.includes(\"-\")) {\r\n const split = name.split(\"-\");\r\n const typeName = split[0];\r\n const fieldName = split[1];\r\n const type = this.scope.findType(typeName);\r\n if (type) {\r\n const stru = type.getType();\r\n if (stru instanceof basic_1.StructureType) {\r\n const f = stru.getComponentByName(fieldName);\r\n if (f) {\r\n return new _typed_identifier_1.TypedIdentifier(type.getToken(), type.getFilename(), f);\r\n }\r\n }\r\n }\r\n }\r\n const lookup = this.scope.getDDIC().lookupNoVoid(name);\r\n const id = (_a = lookup === null || lookup === void 0 ? void 0 : lookup.object) === null || _a === void 0 ? void 0 : _a.getIdentifier();\r\n if (id && (lookup === null || lookup === void 0 ? void 0 : lookup.type)) {\r\n return new _typed_identifier_1.TypedIdentifier(id.getToken(), id.getFilename(), lookup.type);\r\n }\r\n const builtin = this.scope.getDDIC().lookupBuiltinType(name);\r\n if (builtin) {\r\n return new _typed_identifier_1.TypedIdentifier(new identifier_1.Identifier(new position_1.Position(1, 1), name), _builtin_1.BuiltIn.filename, builtin);\r\n }\r\n const type = this.scope.findTypePoolType(name);\r\n if (type) {\r\n return type;\r\n }\r\n return undefined;\r\n }\r\n resolveLikeName(node, headerLogic = true) {\r\n var _a;\r\n if (node === undefined) {\r\n return undefined;\r\n }\r\n let chain = node.findFirstExpression(Expressions.FieldChain);\r\n if (chain === undefined) {\r\n chain = node.findFirstExpression(Expressions.TypeName);\r\n }\r\n if (chain === undefined) {\r\n chain = node.findFirstExpression(Expressions.FieldSub);\r\n }\r\n if (chain === undefined) {\r\n chain = node.findFirstExpression(Expressions.SimpleFieldChain);\r\n }\r\n if (chain === undefined) {\r\n throw new Error(\"resolveLikeName, chain undefined\");\r\n }\r\n const fullName = chain.concatTokens();\r\n const children = [...chain.getChildren()];\r\n if (children.length === 0) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + fullName + \"\\\", resolveLikeName1\");\r\n }\r\n let type = undefined;\r\n if (children[1] && (children[1].getFirstToken().getStr() === \"=>\" || children[1].getFirstToken().getStr() === \"->\")) {\r\n type = new field_chain_1.FieldChain().runSyntax(chain, this.scope, this.filename, _reference_1.ReferenceType.TypeReference);\r\n }\r\n else {\r\n const name = children.shift().getFirstToken().getStr();\r\n let found = this.scope.findVariable(name);\r\n type = found === null || found === void 0 ? void 0 : found.getType();\r\n if (found === undefined) {\r\n found = this.scope.findExtraLikeType(name);\r\n type = found === null || found === void 0 ? void 0 : found.getType();\r\n }\r\n if (found) {\r\n this.scope.addReference(chain === null || chain === void 0 ? void 0 : chain.getFirstToken(), found, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n if (type === undefined) {\r\n type = (_a = this.scope.getDDIC().lookupNoVoid(name)) === null || _a === void 0 ? void 0 : _a.type;\r\n }\r\n if (type === undefined && this.scope.isOO() === false && this.scope.getDDIC().inErrorNamespace(name) === false) {\r\n this.scope.addReference(chain.getChildren()[0].getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n return new Types.VoidType(name);\r\n }\r\n while (children.length > 0) {\r\n const child = children.shift();\r\n if (child.getFirstToken().getStr() === \"-\") {\r\n if (type instanceof Types.VoidType) {\r\n return type;\r\n }\r\n }\r\n else if (child.concatTokens() === \"[]\") {\r\n if (type instanceof Types.TableType) {\r\n type = new basic_1.TableType(type.getRowType(), { withHeader: false });\r\n }\r\n }\r\n else { // field name\r\n let sub = undefined;\r\n if (type instanceof Types.TableType) {\r\n type = type.getRowType();\r\n }\r\n if (type instanceof Types.StructureType) {\r\n sub = type.getComponentByName(child.getFirstToken().getStr());\r\n }\r\n if (sub === undefined) {\r\n return new Types.UnknownType(\"Type error, field not part of structure \" + fullName);\r\n }\r\n type = sub;\r\n }\r\n }\r\n if (type instanceof Types.VoidType) {\r\n return type;\r\n }\r\n else if (type instanceof basic_1.TableType\r\n && type.isWithHeader()\r\n && headerLogic === true) {\r\n type = type.getRowType();\r\n }\r\n else if (type instanceof Types.TableType\r\n && type.isWithHeader() === true\r\n && type.getRowType() instanceof Types.VoidType) {\r\n return type.getRowType();\r\n }\r\n }\r\n if (!type) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + fullName + \"\\\", resolveLikeName2\");\r\n }\r\n return type;\r\n }\r\n resolveTypeName(typeName, length, decimals, qualifiedName) {\r\n var _a;\r\n if (typeName === undefined) {\r\n return undefined;\r\n }\r\n let chain = this.resolveTypeChain(typeName);\r\n if (chain) {\r\n if (chain instanceof basic_1.CharacterType && qualifiedName) {\r\n chain = chain.cloneType(qualifiedName);\r\n }\r\n return chain;\r\n }\r\n const chainText = typeName.concatTokens().toUpperCase();\r\n const f = this.scope.getDDIC().lookupBuiltinType(chainText, length, decimals, qualifiedName);\r\n if (f !== undefined) {\r\n return f;\r\n }\r\n const typ = this.scope.findType(chainText);\r\n if (typ) {\r\n const token = typeName.getFirstToken();\r\n if (chainText.includes(\"~\")) {\r\n const name = chainText.split(\"~\")[0];\r\n const idef = this.scope.findInterfaceDefinition(name);\r\n if (idef) {\r\n this.scope.addReference(token, idef, _reference_1.ReferenceType.ObjectOrientedReference, this.filename, { ooType: \"INTF\", ooName: name });\r\n }\r\n }\r\n this.scope.addReference(token, typ, _reference_1.ReferenceType.TypeReference, this.filename);\r\n return typ.getType();\r\n }\r\n const type = (_a = this.scope.findTypePoolType(chainText)) === null || _a === void 0 ? void 0 : _a.getType();\r\n if (type) {\r\n // this.scope.addReference(typeName.getFirstToken(), type, ReferenceType.TypeReference, this.filename);\r\n return type;\r\n }\r\n const ddic = this.scope.getDDIC().lookup(chainText);\r\n if (ddic) {\r\n this.scope.getDDICReferences().addUsing(this.scope.getParentObj(), { object: ddic.object, token: typeName.getFirstToken(), filename: this.filename });\r\n if (ddic.type instanceof _typed_identifier_1.TypedIdentifier) {\r\n this.scope.addReference(typeName.getFirstToken(), ddic.type, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n else if (ddic.type instanceof basic_1.VoidType) {\r\n this.scope.addReference(typeName.getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n }\r\n return ddic.type;\r\n }\r\n return undefined;\r\n }\r\n simpleType(node, qualifiedNamePrefix) {\r\n let nameExpr = node.findFirstExpression(Expressions.NamespaceSimpleName);\r\n if (nameExpr === undefined) {\r\n nameExpr = node.findFirstExpression(Expressions.DefinitionName);\r\n }\r\n if (nameExpr === undefined) {\r\n return undefined;\r\n }\r\n let name = nameExpr.getFirstToken();\r\n if (nameExpr.countTokens() > 1) { // workaround for names with dashes\r\n name = new identifier_1.Identifier(name.getStart(), nameExpr.concatTokens());\r\n }\r\n let qualifiedName = undefined;\r\n if (node.get() instanceof Statements.Type) {\r\n if (this.scope.isTypePool() === true) {\r\n qualifiedName = name.getStr();\r\n }\r\n else {\r\n qualifiedName = (qualifiedNamePrefix || \"\") + name.getStr();\r\n if (this.scope.getType() === _scope_type_1.ScopeType.ClassDefinition\r\n || this.scope.getType() === _scope_type_1.ScopeType.Interface) {\r\n qualifiedName = this.scope.getName() + \"=>\" + qualifiedName;\r\n }\r\n }\r\n }\r\n else if (qualifiedNamePrefix) {\r\n qualifiedName = qualifiedNamePrefix + qualifiedName;\r\n }\r\n const found = this.parseType(node, qualifiedName);\r\n if (found) {\r\n return new _typed_identifier_1.TypedIdentifier(name, this.filename, found);\r\n }\r\n return undefined;\r\n }\r\n parseTable(node, name) {\r\n var _a;\r\n const typename = node.findFirstExpression(Expressions.TypeName);\r\n const text = (_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();\r\n if (text === undefined) {\r\n return undefined;\r\n }\r\n let type = undefined;\r\n if (text.includes(\" STANDARD TABLE \")) {\r\n type = basic_1.TableAccessType.standard;\r\n }\r\n else if (text.includes(\" SORTED TABLE \")) {\r\n type = basic_1.TableAccessType.sorted;\r\n }\r\n else if (text.includes(\" HASHED TABLE \")) {\r\n type = basic_1.TableAccessType.hashed;\r\n }\r\n const keyFields = [];\r\n if (type) {\r\n const keys = node.findFirstExpression(expressions_1.TypeTableKey);\r\n for (const k of (keys === null || keys === void 0 ? void 0 : keys.findDirectExpressions(expressions_1.FieldSub)) || []) {\r\n keyFields.push(k.concatTokens().toUpperCase());\r\n }\r\n }\r\n const options = {\r\n withHeader: text.includes(\" WITH HEADER LINE\"),\r\n type: type,\r\n isUnique: text.includes(\" WITH UNIQUE\"),\r\n keyFields: keyFields,\r\n };\r\n let found = undefined;\r\n if (text.startsWith(\"TYPE TABLE OF REF TO \")\r\n || text.startsWith(\"TYPE STANDARD TABLE OF REF TO \")\r\n || text.startsWith(\"TYPE SORTED TABLE OF REF TO \")\r\n || text.startsWith(\"TYPE HASHED TABLE OF REF TO \")) {\r\n found = this.resolveTypeRef(typename);\r\n if (found) {\r\n return new Types.TableType(found, options, name);\r\n }\r\n }\r\n else if (text.startsWith(\"TYPE TABLE OF \")\r\n || text.startsWith(\"TYPE STANDARD TABLE OF \")\r\n || text.startsWith(\"TYPE SORTED TABLE OF \")\r\n || text.startsWith(\"TYPE HASHED TABLE OF \")) {\r\n found = this.resolveTypeName(typename);\r\n if (found) {\r\n return new Types.TableType(found, options, name);\r\n }\r\n }\r\n else if (text.startsWith(\"LIKE TABLE OF \")\r\n || text.startsWith(\"LIKE STANDARD TABLE OF \")\r\n || text.startsWith(\"LIKE SORTED TABLE OF \")\r\n || text.startsWith(\"LIKE HASHED TABLE OF \")) {\r\n found = this.resolveLikeName(node);\r\n if (found) {\r\n return new Types.TableType(found, options, name);\r\n }\r\n }\r\n else if (text === \"TYPE STANDARD TABLE\"\r\n || text === \"TYPE SORTED TABLE\"\r\n || text === \"TYPE HASHED TABLE\"\r\n || text === \"TYPE INDEX TABLE\"\r\n || text === \"TYPE ANY TABLE\") {\r\n return new Types.TableType(new Types.AnyType(), options);\r\n }\r\n else if (text.startsWith(\"TYPE RANGE OF \")) {\r\n const sub = node.findFirstExpression(Expressions.TypeName);\r\n found = this.resolveTypeName(sub);\r\n if (found === undefined) {\r\n return new Types.UnknownType(\"TYPE RANGE OF, could not resolve type\");\r\n }\r\n const structure = new Types.StructureType([\r\n { name: \"sign\", type: new Types.CharacterType(1) },\r\n { name: \"option\", type: new Types.CharacterType(2) },\r\n { name: \"low\", type: found },\r\n { name: \"high\", type: found },\r\n ]);\r\n return new Types.TableType(structure, options, name);\r\n }\r\n else if (text.startsWith(\"LIKE RANGE OF \")) {\r\n const sub = node.findFirstExpression(Expressions.SimpleFieldChain);\r\n found = this.resolveLikeName(sub);\r\n if (found === undefined) {\r\n return new Types.UnknownType(\"LIKE RANGE OF, could not resolve type\");\r\n }\r\n const structure = new Types.StructureType([\r\n { name: \"sign\", type: new Types.CharacterType(1) },\r\n { name: \"option\", type: new Types.CharacterType(2) },\r\n { name: \"low\", type: found },\r\n { name: \"high\", type: found },\r\n ], name);\r\n return new Types.TableType(structure, options);\r\n }\r\n // fallback to old style syntax, OCCURS etc\r\n return this.parseType(node, name);\r\n }\r\n parseType(node, qualifiedName) {\r\n var _a, _b, _c, _d, _e, _f;\r\n const typeName = node.findFirstExpression(Expressions.TypeName);\r\n let text = (_a = node.findFirstExpression(Expressions.Type)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();\r\n if (text === undefined) {\r\n text = (_b = node.findFirstExpression(Expressions.TypeParam)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();\r\n }\r\n if (text === undefined) {\r\n text = (_c = node.findFirstExpression(Expressions.TypeTable)) === null || _c === void 0 ? void 0 : _c.concatTokens().toUpperCase();\r\n if ((text === null || text === void 0 ? void 0 : text.startsWith(\"TYPE\")) === false && (text === null || text === void 0 ? void 0 : text.startsWith(\"LIKE\")) === false) {\r\n text = \"TYPE\";\r\n }\r\n }\r\n if (text === undefined) {\r\n text = (_d = node.findFirstExpression(Expressions.FormParamType)) === null || _d === void 0 ? void 0 : _d.concatTokens().toUpperCase();\r\n }\r\n if (text === undefined) {\r\n text = \"TYPE\";\r\n }\r\n let found = undefined;\r\n if (text.startsWith(\"LIKE LINE OF \")) {\r\n const name = (_e = node.findFirstExpression(Expressions.FieldChain)) === null || _e === void 0 ? void 0 : _e.concatTokens();\r\n let e = node.findFirstExpression(Expressions.Type);\r\n if (e === undefined) {\r\n e = node.findFirstExpression(Expressions.FormParamType);\r\n }\r\n const type = this.resolveLikeName(e, false);\r\n if (type === undefined) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + name + \"\\\", parseType\");\r\n }\r\n else if (type instanceof Types.TableType) {\r\n return type.getRowType();\r\n }\r\n else if (type instanceof Types.VoidType) {\r\n return type;\r\n }\r\n else {\r\n return new Types.UnknownType(\"Type error, not a table type \" + name);\r\n }\r\n }\r\n else if (text.startsWith(\"LIKE REF TO \")) {\r\n const name = (_f = node.findFirstExpression(Expressions.FieldChain)) === null || _f === void 0 ? void 0 : _f.concatTokens();\r\n const type = this.resolveLikeName(node.findFirstExpression(Expressions.Type), false);\r\n if (type === undefined) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + name + \"\\\", parseType\");\r\n }\r\n return new Types.DataReference(type, name);\r\n }\r\n else if (text === \"TYPE STANDARD TABLE\"\r\n || text === \"TYPE SORTED TABLE\"\r\n || text === \"TYPE HASHED TABLE\"\r\n || text === \"TYPE INDEX TABLE\"\r\n || text === \"TYPE ANY TABLE\") {\r\n return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes(\"WITH HEADER LINE\") });\r\n }\r\n else if (text.startsWith(\"LIKE \")) {\r\n let sub = node.findFirstExpression(Expressions.Type);\r\n if (sub === undefined) {\r\n sub = node.findFirstExpression(Expressions.FormParamType);\r\n }\r\n if (sub === undefined) {\r\n sub = node.findFirstExpression(Expressions.TypeParam);\r\n }\r\n if (sub === undefined) {\r\n sub = node.findFirstExpression(Expressions.FieldChain);\r\n }\r\n found = this.resolveLikeName(sub);\r\n if (found && this.isOccurs(node)) {\r\n found = new Types.TableType(found, { withHeader: text.includes(\"WITH HEADER LINE\") }, qualifiedName);\r\n }\r\n }\r\n else if (text.startsWith(\"TYPE LINE OF \")) {\r\n const sub = node.findFirstExpression(Expressions.TypeName);\r\n found = this.resolveTypeName(sub);\r\n if (found instanceof _typed_identifier_1.TypedIdentifier) {\r\n found = found.getType();\r\n }\r\n if (found instanceof Types.TableType) {\r\n return found.getRowType();\r\n }\r\n else if (found instanceof Types.VoidType) {\r\n return found;\r\n }\r\n else if (found instanceof Types.UnknownType) {\r\n return new Types.UnknownType(\"TYPE LINE OF, unknown type, \" + found.getError());\r\n }\r\n else {\r\n return new Types.UnknownType(\"TYPE LINE OF, unexpected type, \" + (found === null || found === void 0 ? void 0 : found.constructor.name));\r\n }\r\n }\r\n else if (text.startsWith(\"TYPE REF TO \")) {\r\n found = this.resolveTypeRef(typeName);\r\n }\r\n else if (text.startsWith(\"TYPE\")) {\r\n found = this.resolveTypeName(typeName, this.findLength(node), this.findDecimals(node), qualifiedName);\r\n const concat = node.concatTokens().toUpperCase();\r\n if (found && this.isOccurs(node)) {\r\n found = new Types.TableType(found, { withHeader: concat.includes(\" WITH HEADER LINE\") }, qualifiedName);\r\n }\r\n else if (found && concat.includes(\" WITH HEADER LINE\")) {\r\n if (found instanceof Types.VoidType) {\r\n found = new Types.TableType(found, { withHeader: true });\r\n }\r\n else if (!(found instanceof Types.TableType)) {\r\n throw new Error(\"WITH HEADER LINE can only be used with internal table\");\r\n }\r\n else {\r\n found = new Types.TableType(found.getRowType(), { withHeader: true });\r\n }\r\n }\r\n if (found === undefined && typeName === undefined) {\r\n let length = 1;\r\n const len = node.findDirectExpression(Expressions.ConstantFieldLength);\r\n if (len) {\r\n const int = len.findDirectExpression(Expressions.Integer);\r\n if (int) {\r\n length = parseInt(int.concatTokens(), 10);\r\n }\r\n }\r\n found = new Types.CharacterType(length, qualifiedName); // fallback\r\n if (this.isOccurs(node)) {\r\n found = new Types.TableType(found, { withHeader: concat.includes(\" WITH HEADER LINE\") }, qualifiedName);\r\n }\r\n }\r\n }\r\n return found;\r\n }\r\n /////////////////////\r\n isOccurs(node) {\r\n var _a;\r\n if (node.findDirectTokenByText(\"OCCURS\")) {\r\n return true;\r\n }\r\n else if ((_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.findDirectTokenByText(\"OCCURS\")) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n // todo, rewrite this method\r\n resolveTypeChain(expr) {\r\n var _a;\r\n const chainText = expr.concatTokens().toUpperCase();\r\n if (chainText.includes(\"=>\") === false && chainText.includes(\"-\") === false) {\r\n return undefined;\r\n }\r\n let className;\r\n let rest = chainText;\r\n if (chainText.includes(\"=>\")) {\r\n const split = chainText.split(\"=>\");\r\n className = split[0];\r\n rest = split[1];\r\n }\r\n const subs = rest.split(\"-\");\r\n let foundType = undefined;\r\n if (className) {\r\n const split = chainText.split(\"=>\");\r\n const className = split[0];\r\n // the prefix might be itself\r\n if ((this.scope.getType() === _scope_type_1.ScopeType.Interface\r\n || this.scope.getType() === _scope_type_1.ScopeType.ClassDefinition)\r\n && this.scope.getName().toUpperCase() === className.toUpperCase()) {\r\n const foundId = this.scope.findType(subs[0]);\r\n foundType = foundId === null || foundId === void 0 ? void 0 : foundId.getType();\r\n if (foundType === undefined) {\r\n return new Types.UnknownType(\"Could not resolve type \" + chainText);\r\n }\r\n this.scope.addReference(expr.getTokens()[2], foundId, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n else {\r\n // lookup in local and global scope\r\n const obj = this.scope.findObjectDefinition(className);\r\n if (obj === undefined && this.scope.getDDIC().inErrorNamespace(className) === false) {\r\n this.scope.addReference(expr.getFirstToken(), undefined, _reference_1.ReferenceType.ObjectOrientedVoidReference, this.filename, { ooName: className.toUpperCase() });\r\n return new Types.VoidType(className);\r\n }\r\n else if (obj === undefined) {\r\n return new Types.UnknownType(\"Could not resolve top \" + className + \", resolveTypeChain\");\r\n }\r\n const type = obj instanceof types_1.ClassDefinition ? \"CLAS\" : \"INTF\";\r\n this.scope.addReference(expr.getFirstToken(), obj, _reference_1.ReferenceType.ObjectOrientedReference, this.filename, { ooType: type, ooName: className });\r\n const byName = new _object_oriented_1.ObjectOriented(this.scope).searchTypeName(obj, subs[0]);\r\n foundType = byName === null || byName === void 0 ? void 0 : byName.getType();\r\n if (byName === undefined || foundType === undefined) {\r\n return new Types.UnknownType(subs[0] + \" not found in class or interface\");\r\n }\r\n this.scope.addReference(expr.getTokens()[2], byName, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n }\r\n else {\r\n const found = this.scope.findType(subs[0]);\r\n foundType = found === null || found === void 0 ? void 0 : found.getType();\r\n if (foundType === undefined) {\r\n const typePoolType = (_a = this.scope.findTypePoolType(subs[0])) === null || _a === void 0 ? void 0 : _a.getType();\r\n if (typePoolType) {\r\n // this.scope.addReference(typeName.getFirstToken(), typePoolType, ReferenceType.TypeReference, this.filename);\r\n foundType = typePoolType;\r\n }\r\n if (foundType === undefined) {\r\n const f = this.scope.getDDIC().lookupTableOrView(subs[0]);\r\n this.scope.getDDICReferences().addUsing(this.scope.getParentObj(), { object: f.object, filename: this.filename, token: expr.getFirstToken() });\r\n if (f.type instanceof _typed_identifier_1.TypedIdentifier) {\r\n foundType = f.type.getType();\r\n }\r\n else {\r\n foundType = f.type;\r\n }\r\n }\r\n }\r\n else {\r\n this.scope.addReference(expr.getFirstToken(), found, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n if (foundType === undefined && this.scope.getDDIC().inErrorNamespace(subs[0]) === false) {\r\n this.scope.addReference(expr.getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n return new Types.VoidType(subs[0]);\r\n }\r\n else if (foundType instanceof Types.VoidType) {\r\n this.scope.addReference(expr.getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n return foundType;\r\n }\r\n else if (foundType === undefined) {\r\n return new Types.UnknownType(\"Unknown type \" + subs[0]);\r\n }\r\n }\r\n subs.shift();\r\n while (subs.length > 0) {\r\n if (foundType instanceof Types.UnknownType\r\n || foundType instanceof Types.VoidType) {\r\n return foundType;\r\n }\r\n else if (!(foundType instanceof Types.StructureType)) {\r\n return new Types.UnknownType(\"Not a structured type\");\r\n }\r\n foundType = foundType.getComponentByName(subs[0]);\r\n subs.shift();\r\n }\r\n return foundType;\r\n }\r\n resolveConstantValue(expr) {\r\n var _a, _b;\r\n if (!(expr.get() instanceof Expressions.SimpleFieldChain)) {\r\n throw new Error(\"resolveConstantValue\");\r\n }\r\n const firstNode = expr.getFirstChild();\r\n const firstToken = firstNode.getFirstToken();\r\n const firstName = firstToken.getStr();\r\n if (firstNode.get() instanceof Expressions.Field) {\r\n const found = this.scope.findVariable(firstName);\r\n const val = found === null || found === void 0 ? void 0 : found.getValue();\r\n if (typeof val === \"string\") {\r\n this.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.filename);\r\n return val;\r\n }\r\n return undefined;\r\n }\r\n else if (firstNode.get() instanceof Expressions.ClassName\r\n && firstName.toLowerCase() === this.scope.getName().toLowerCase()\r\n && (this.scope.getType() === _scope_type_1.ScopeType.Interface\r\n || this.scope.getType() === _scope_type_1.ScopeType.ClassDefinition)) {\r\n const children = expr.getChildren();\r\n const token = (_a = children[2]) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n const found = this.scope.findVariable(token.getStr());\r\n const val = found === null || found === void 0 ? void 0 : found.getValue();\r\n if (typeof val === \"string\") {\r\n this.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.filename);\r\n return val;\r\n }\r\n return undefined;\r\n }\r\n else if (firstNode.get() instanceof Expressions.ClassName) {\r\n const obj = this.scope.findObjectDefinition(firstName);\r\n if (obj === undefined) {\r\n if (this.scope.existsObject(firstName).found === true) {\r\n return undefined;\r\n }\r\n else if (this.scope.getDDIC().inErrorNamespace(firstName) === true) {\r\n throw new Error(\"resolveConstantValue, not found: \" + firstName);\r\n }\r\n else {\r\n this.scope.addReference(firstNode.getFirstToken(), undefined, _reference_1.ReferenceType.ObjectOrientedVoidReference, this.filename, { ooName: firstName.toUpperCase() });\r\n return undefined;\r\n }\r\n }\r\n const children = expr.getChildren();\r\n const token = (_b = children[2]) === null || _b === void 0 ? void 0 : _b.getFirstToken();\r\n const attr = token.getStr();\r\n const c = new _object_oriented_1.ObjectOriented(this.scope).searchConstantName(obj, attr);\r\n if (c instanceof class_constant_1.ClassConstant) {\r\n this.scope.addReference(token, c, _reference_1.ReferenceType.DataReadReference, this.filename);\r\n const val = c.getValue();\r\n if (typeof val === \"string\") {\r\n return val;\r\n }\r\n else if (typeof val === \"object\" && children[4]) {\r\n const name = children[4].getFirstToken().getStr();\r\n if (val[name] !== undefined) {\r\n return val[name];\r\n }\r\n }\r\n return undefined;\r\n }\r\n throw new Error(\"resolveConstantValue, constant not found \" + attr);\r\n }\r\n else {\r\n throw new Error(\"resolveConstantValue, unexpected structure\");\r\n }\r\n }\r\n resolveTypeRef(chain) {\r\n var _a;\r\n if (chain === undefined) {\r\n return undefined;\r\n }\r\n const name = chain.getFirstToken().getStr();\r\n if (chain.getAllTokens().length === 1) {\r\n if (name.toUpperCase() === \"OBJECT\") {\r\n return new Types.GenericObjectReferenceType();\r\n }\r\n const search = this.scope.existsObject(name);\r\n if (search.found === true && search.id) {\r\n this.scope.addReference(chain.getFirstToken(), search.id, _reference_1.ReferenceType.ObjectOrientedReference, this.filename, { ooType: search.ooType, ooName: name });\r\n return new Types.ObjectReferenceType(search.id, name);\r\n }\r\n }\r\n const found = this.resolveTypeName(chain);\r\n if (found && !(found instanceof Types.UnknownType) && !(found instanceof Types.VoidType)) {\r\n return new Types.DataReference(found);\r\n }\r\n else if (chain.concatTokens().toUpperCase() === \"DATA\") {\r\n return new Types.DataReference(new Types.AnyType());\r\n }\r\n if (this.scope.isBadiDef(name) === true) {\r\n return new Types.VoidType(name);\r\n }\r\n if (((_a = this.scope.getDDIC()) === null || _a === void 0 ? void 0 : _a.inErrorNamespace(name)) === false) {\r\n // this.scope.addReference(chain.getFirstToken(), undefined, ReferenceType.VoidType, this.filename);\r\n return new Types.VoidType(name);\r\n }\r\n return new Types.UnknownType(\"REF, unable to resolve \" + name);\r\n }\r\n findValue(node) {\r\n const val = node.findFirstExpression(Expressions.Value);\r\n if (val === undefined) {\r\n throw new Error(\"VALUE missing in expression\");\r\n }\r\n if (val.concatTokens().toUpperCase() === \"VALUE IS INITIAL\") {\r\n return undefined;\r\n }\r\n const constant = val.findFirstExpression(Expressions.Constant);\r\n if (constant) {\r\n return constant.concatTokens();\r\n }\r\n const chain = val.findFirstExpression(Expressions.SimpleFieldChain);\r\n if (chain) {\r\n return this.resolveConstantValue(chain);\r\n }\r\n throw new Error(\"findValue, unexpected\");\r\n }\r\n findDecimals(node) {\r\n var _a, _b;\r\n const dec = (_b = (_a = node.findDirectExpression(Expressions.Decimals)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Integer)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (dec) {\r\n return parseInt(dec, 10);\r\n }\r\n return undefined;\r\n }\r\n findLength(node) {\r\n const val = node.findFirstExpression(Expressions.Length);\r\n const flen = node.findFirstExpression(Expressions.ConstantFieldLength);\r\n if (val && flen) {\r\n throw new Error(\"Only specify length once\");\r\n }\r\n if (flen) {\r\n const cintExpr = flen.findFirstExpression(Expressions.Integer);\r\n if (cintExpr) {\r\n return this.parseInt(cintExpr.concatTokens());\r\n }\r\n const cchain = flen.findFirstExpression(Expressions.SimpleFieldChain);\r\n if (cchain) {\r\n const val = this.resolveConstantValue(cchain);\r\n return this.parseInt(val);\r\n }\r\n }\r\n if (val === undefined) {\r\n return 1;\r\n }\r\n const intExpr = val.findFirstExpression(Expressions.Integer);\r\n if (intExpr) {\r\n return this.parseInt(intExpr.concatTokens());\r\n }\r\n const strExpr = val.findFirstExpression(Expressions.ConstantString);\r\n if (strExpr) {\r\n return this.parseInt(strExpr.concatTokens());\r\n }\r\n const chain = val.findFirstExpression(Expressions.SimpleFieldChain);\r\n if (chain) {\r\n const val = this.resolveConstantValue(chain);\r\n return this.parseInt(val);\r\n }\r\n throw new Error(\"Unexpected, findLength\");\r\n }\r\n parseInt(text) {\r\n if (text === undefined) {\r\n return undefined;\r\n }\r\n if (text.startsWith(\"'\")) {\r\n text = text.split(\"'\")[1];\r\n }\r\n else if (text.startsWith(\"`\")) {\r\n text = text.split(\"`\")[1];\r\n }\r\n return parseInt(text, 10);\r\n }\r\n}\r\nexports.BasicTypes = BasicTypes;\r\n//# sourceMappingURL=basic_types.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/abap/5_syntax/basic_types.js?");
|
|
6663
|
+
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.BasicTypes = void 0;\r\n/* eslint-disable default-case */\r\nconst _typed_identifier_1 = __webpack_require__(/*! ../types/_typed_identifier */ \"./node_modules/@abaplint/core/build/src/abap/types/_typed_identifier.js\");\r\nconst Expressions = __webpack_require__(/*! ../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst Statements = __webpack_require__(/*! ../2_statements/statements */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js\");\r\nconst Types = __webpack_require__(/*! ../types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst _scope_type_1 = __webpack_require__(/*! ./_scope_type */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_scope_type.js\");\r\nconst _object_oriented_1 = __webpack_require__(/*! ./_object_oriented */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_object_oriented.js\");\r\nconst class_constant_1 = __webpack_require__(/*! ../types/class_constant */ \"./node_modules/@abaplint/core/build/src/abap/types/class_constant.js\");\r\nconst identifier_1 = __webpack_require__(/*! ../1_lexer/tokens/identifier */ \"./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/identifier.js\");\r\nconst _reference_1 = __webpack_require__(/*! ./_reference */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js\");\r\nconst basic_1 = __webpack_require__(/*! ../types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst field_chain_1 = __webpack_require__(/*! ./expressions/field_chain */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/field_chain.js\");\r\nconst types_1 = __webpack_require__(/*! ../types */ \"./node_modules/@abaplint/core/build/src/abap/types/index.js\");\r\nconst expressions_1 = __webpack_require__(/*! ../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst _builtin_1 = __webpack_require__(/*! ./_builtin */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js\");\r\nconst position_1 = __webpack_require__(/*! ../../position */ \"./node_modules/@abaplint/core/build/src/position.js\");\r\nclass BasicTypes {\r\n constructor(filename, scope) {\r\n this.filename = filename;\r\n this.scope = scope;\r\n }\r\n lookupQualifiedName(name) {\r\n var _a;\r\n // argh, todo, rewrite this entire method, more argh\r\n if (name === undefined) {\r\n return undefined;\r\n }\r\n const found = this.scope.findType(name);\r\n if (found) {\r\n return found;\r\n }\r\n if (name.includes(\"=>\")) {\r\n const split = name.split(\"=>\");\r\n const ooName = split[0];\r\n const typeName = split[1];\r\n const oo = this.scope.findObjectDefinition(ooName);\r\n if (oo) {\r\n if (typeName.includes(\"-\")) {\r\n const split = typeName.split(\"-\");\r\n const subTypeName = split[0];\r\n const fieldName = split[1];\r\n const stru = oo.getTypeDefinitions().getByName(subTypeName);\r\n const struType = stru === null || stru === void 0 ? void 0 : stru.getType();\r\n if (stru && struType instanceof basic_1.StructureType) {\r\n const f = struType.getComponentByName(fieldName);\r\n if (f) {\r\n return new _typed_identifier_1.TypedIdentifier(stru.getToken(), stru.getFilename(), f);\r\n }\r\n }\r\n }\r\n else {\r\n const f = oo.getTypeDefinitions().getByName(typeName);\r\n if (f) {\r\n return f;\r\n }\r\n }\r\n }\r\n }\r\n else if (name.includes(\"-\")) {\r\n const split = name.split(\"-\");\r\n const typeName = split[0];\r\n const fieldName = split[1];\r\n const type = this.scope.findType(typeName);\r\n if (type) {\r\n const stru = type.getType();\r\n if (stru instanceof basic_1.StructureType) {\r\n const f = stru.getComponentByName(fieldName);\r\n if (f) {\r\n return new _typed_identifier_1.TypedIdentifier(type.getToken(), type.getFilename(), f);\r\n }\r\n }\r\n }\r\n }\r\n const lookup = this.scope.getDDIC().lookupNoVoid(name);\r\n const id = (_a = lookup === null || lookup === void 0 ? void 0 : lookup.object) === null || _a === void 0 ? void 0 : _a.getIdentifier();\r\n if (id && (lookup === null || lookup === void 0 ? void 0 : lookup.type)) {\r\n return new _typed_identifier_1.TypedIdentifier(id.getToken(), id.getFilename(), lookup.type);\r\n }\r\n const builtin = this.scope.getDDIC().lookupBuiltinType(name);\r\n if (builtin) {\r\n return new _typed_identifier_1.TypedIdentifier(new identifier_1.Identifier(new position_1.Position(1, 1), name), _builtin_1.BuiltIn.filename, builtin);\r\n }\r\n const type = this.scope.findTypePoolType(name);\r\n if (type) {\r\n return type;\r\n }\r\n return undefined;\r\n }\r\n resolveLikeName(node, headerLogic = true) {\r\n var _a;\r\n if (node === undefined) {\r\n return undefined;\r\n }\r\n let chain = node.findFirstExpression(Expressions.FieldChain);\r\n if (chain === undefined) {\r\n chain = node.findFirstExpression(Expressions.TypeName);\r\n }\r\n if (chain === undefined) {\r\n chain = node.findFirstExpression(Expressions.FieldSub);\r\n }\r\n if (chain === undefined) {\r\n chain = node.findFirstExpression(Expressions.SimpleFieldChain);\r\n }\r\n if (chain === undefined) {\r\n throw new Error(\"resolveLikeName, chain undefined\");\r\n }\r\n const fullName = chain.concatTokens();\r\n const children = [...chain.getChildren()];\r\n if (children.length === 0) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + fullName + \"\\\", resolveLikeName1\");\r\n }\r\n let type = undefined;\r\n if (children[1] && (children[1].getFirstToken().getStr() === \"=>\" || children[1].getFirstToken().getStr() === \"->\")) {\r\n type = new field_chain_1.FieldChain().runSyntax(chain, this.scope, this.filename, _reference_1.ReferenceType.TypeReference);\r\n }\r\n else {\r\n const name = children.shift().getFirstToken().getStr();\r\n let found = this.scope.findVariable(name);\r\n type = found === null || found === void 0 ? void 0 : found.getType();\r\n if (found === undefined) {\r\n found = this.scope.findExtraLikeType(name);\r\n type = found === null || found === void 0 ? void 0 : found.getType();\r\n }\r\n if (found) {\r\n this.scope.addReference(chain === null || chain === void 0 ? void 0 : chain.getFirstToken(), found, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n if (type === undefined) {\r\n type = (_a = this.scope.getDDIC().lookupNoVoid(name)) === null || _a === void 0 ? void 0 : _a.type;\r\n }\r\n if (type === undefined && this.scope.isOO() === false && this.scope.getDDIC().inErrorNamespace(name) === false) {\r\n this.scope.addReference(chain.getChildren()[0].getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n return new Types.VoidType(name);\r\n }\r\n while (children.length > 0) {\r\n const child = children.shift();\r\n if (child.getFirstToken().getStr() === \"-\") {\r\n if (type instanceof Types.VoidType) {\r\n return type;\r\n }\r\n }\r\n else if (child.concatTokens() === \"[]\") {\r\n if (type instanceof Types.TableType) {\r\n type = new basic_1.TableType(type.getRowType(), { withHeader: false });\r\n }\r\n }\r\n else { // field name\r\n let sub = undefined;\r\n if (type instanceof Types.TableType) {\r\n type = type.getRowType();\r\n }\r\n if (type instanceof Types.StructureType) {\r\n sub = type.getComponentByName(child.getFirstToken().getStr());\r\n }\r\n if (sub === undefined) {\r\n return new Types.UnknownType(\"Type error, field not part of structure \" + fullName);\r\n }\r\n type = sub;\r\n }\r\n }\r\n if (type instanceof Types.VoidType) {\r\n return type;\r\n }\r\n else if (type instanceof basic_1.TableType\r\n && type.isWithHeader()\r\n && headerLogic === true) {\r\n type = type.getRowType();\r\n }\r\n else if (type instanceof Types.TableType\r\n && type.isWithHeader() === true\r\n && type.getRowType() instanceof Types.VoidType) {\r\n return type.getRowType();\r\n }\r\n }\r\n if (!type) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + fullName + \"\\\", resolveLikeName2\");\r\n }\r\n return type;\r\n }\r\n resolveTypeName(typeName, length, decimals, qualifiedName) {\r\n var _a;\r\n if (typeName === undefined) {\r\n return undefined;\r\n }\r\n let chain = this.resolveTypeChain(typeName);\r\n if (chain) {\r\n if (chain instanceof basic_1.CharacterType && qualifiedName) {\r\n chain = chain.cloneType(qualifiedName);\r\n }\r\n return chain;\r\n }\r\n const chainText = typeName.concatTokens().toUpperCase();\r\n const f = this.scope.getDDIC().lookupBuiltinType(chainText, length, decimals, qualifiedName);\r\n if (f !== undefined) {\r\n return f;\r\n }\r\n const typ = this.scope.findType(chainText);\r\n if (typ) {\r\n const token = typeName.getFirstToken();\r\n if (chainText.includes(\"~\")) {\r\n const name = chainText.split(\"~\")[0];\r\n const idef = this.scope.findInterfaceDefinition(name);\r\n if (idef) {\r\n this.scope.addReference(token, idef, _reference_1.ReferenceType.ObjectOrientedReference, this.filename, { ooType: \"INTF\", ooName: name });\r\n }\r\n }\r\n this.scope.addReference(token, typ, _reference_1.ReferenceType.TypeReference, this.filename);\r\n return typ.getType();\r\n }\r\n const type = (_a = this.scope.findTypePoolType(chainText)) === null || _a === void 0 ? void 0 : _a.getType();\r\n if (type) {\r\n // this.scope.addReference(typeName.getFirstToken(), type, ReferenceType.TypeReference, this.filename);\r\n return type;\r\n }\r\n const ddic = this.scope.getDDIC().lookup(chainText);\r\n if (ddic) {\r\n this.scope.getDDICReferences().addUsing(this.scope.getParentObj(), { object: ddic.object, token: typeName.getFirstToken(), filename: this.filename });\r\n if (ddic.type instanceof _typed_identifier_1.TypedIdentifier) {\r\n this.scope.addReference(typeName.getFirstToken(), ddic.type, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n else if (ddic.type instanceof basic_1.VoidType) {\r\n this.scope.addReference(typeName.getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n }\r\n return ddic.type;\r\n }\r\n return undefined;\r\n }\r\n simpleType(node, qualifiedNamePrefix) {\r\n let nameExpr = node.findFirstExpression(Expressions.NamespaceSimpleName);\r\n if (nameExpr === undefined) {\r\n nameExpr = node.findFirstExpression(Expressions.DefinitionName);\r\n }\r\n if (nameExpr === undefined) {\r\n return undefined;\r\n }\r\n let name = nameExpr.getFirstToken();\r\n if (nameExpr.countTokens() > 1) { // workaround for names with dashes\r\n name = new identifier_1.Identifier(name.getStart(), nameExpr.concatTokens());\r\n }\r\n let qualifiedName = undefined;\r\n if (node.get() instanceof Statements.Type) {\r\n if (this.scope.isTypePool() === true) {\r\n qualifiedName = name.getStr();\r\n }\r\n else {\r\n qualifiedName = (qualifiedNamePrefix || \"\") + name.getStr();\r\n if (this.scope.getType() === _scope_type_1.ScopeType.ClassDefinition\r\n || this.scope.getType() === _scope_type_1.ScopeType.Interface) {\r\n qualifiedName = this.scope.getName() + \"=>\" + qualifiedName;\r\n }\r\n }\r\n }\r\n else if (qualifiedNamePrefix) {\r\n qualifiedName = qualifiedNamePrefix + qualifiedName;\r\n }\r\n const found = this.parseType(node, qualifiedName);\r\n if (found) {\r\n return new _typed_identifier_1.TypedIdentifier(name, this.filename, found);\r\n }\r\n return undefined;\r\n }\r\n parseTable(node, name) {\r\n var _a;\r\n const typename = node.findFirstExpression(Expressions.TypeName);\r\n const text = (_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();\r\n if (text === undefined) {\r\n return undefined;\r\n }\r\n let type = undefined;\r\n if (text.includes(\" STANDARD TABLE \")) {\r\n type = basic_1.TableAccessType.standard;\r\n }\r\n else if (text.includes(\" SORTED TABLE \")) {\r\n type = basic_1.TableAccessType.sorted;\r\n }\r\n else if (text.includes(\" HASHED TABLE \")) {\r\n type = basic_1.TableAccessType.hashed;\r\n }\r\n const keyFields = [];\r\n if (type) {\r\n const keys = node.findFirstExpression(expressions_1.TypeTableKey);\r\n for (const k of (keys === null || keys === void 0 ? void 0 : keys.findDirectExpressions(expressions_1.FieldSub)) || []) {\r\n keyFields.push(k.concatTokens().toUpperCase());\r\n }\r\n }\r\n const options = {\r\n withHeader: text.includes(\" WITH HEADER LINE\"),\r\n type: type,\r\n isUnique: text.includes(\" WITH UNIQUE\"),\r\n keyFields: keyFields,\r\n };\r\n let found = undefined;\r\n if (text.startsWith(\"TYPE TABLE OF REF TO \")\r\n || text.startsWith(\"TYPE STANDARD TABLE OF REF TO \")\r\n || text.startsWith(\"TYPE SORTED TABLE OF REF TO \")\r\n || text.startsWith(\"TYPE HASHED TABLE OF REF TO \")) {\r\n found = this.resolveTypeRef(typename);\r\n if (found) {\r\n return new Types.TableType(found, options, name);\r\n }\r\n }\r\n else if (text.startsWith(\"TYPE TABLE OF \")\r\n || text.startsWith(\"TYPE STANDARD TABLE OF \")\r\n || text.startsWith(\"TYPE SORTED TABLE OF \")\r\n || text.startsWith(\"TYPE HASHED TABLE OF \")) {\r\n found = this.resolveTypeName(typename);\r\n if (found) {\r\n return new Types.TableType(found, options, name);\r\n }\r\n }\r\n else if (text.startsWith(\"LIKE TABLE OF \")\r\n || text.startsWith(\"LIKE STANDARD TABLE OF \")\r\n || text.startsWith(\"LIKE SORTED TABLE OF \")\r\n || text.startsWith(\"LIKE HASHED TABLE OF \")) {\r\n found = this.resolveLikeName(node);\r\n if (found) {\r\n return new Types.TableType(found, options, name);\r\n }\r\n }\r\n else if (text === \"TYPE STANDARD TABLE\"\r\n || text === \"TYPE SORTED TABLE\"\r\n || text === \"TYPE HASHED TABLE\"\r\n || text === \"TYPE INDEX TABLE\"\r\n || text === \"TYPE ANY TABLE\") {\r\n return new Types.TableType(new Types.AnyType(), options);\r\n }\r\n else if (text.startsWith(\"TYPE RANGE OF \")) {\r\n const sub = node.findFirstExpression(Expressions.TypeName);\r\n found = this.resolveTypeName(sub);\r\n if (found === undefined) {\r\n return new Types.UnknownType(\"TYPE RANGE OF, could not resolve type\");\r\n }\r\n const structure = new Types.StructureType([\r\n { name: \"sign\", type: new Types.CharacterType(1) },\r\n { name: \"option\", type: new Types.CharacterType(2) },\r\n { name: \"low\", type: found },\r\n { name: \"high\", type: found },\r\n ]);\r\n return new Types.TableType(structure, options, name);\r\n }\r\n else if (text.startsWith(\"LIKE RANGE OF \")) {\r\n const sub = node.findFirstExpression(Expressions.SimpleFieldChain);\r\n found = this.resolveLikeName(sub);\r\n if (found === undefined) {\r\n return new Types.UnknownType(\"LIKE RANGE OF, could not resolve type\");\r\n }\r\n const structure = new Types.StructureType([\r\n { name: \"sign\", type: new Types.CharacterType(1) },\r\n { name: \"option\", type: new Types.CharacterType(2) },\r\n { name: \"low\", type: found },\r\n { name: \"high\", type: found },\r\n ], name);\r\n return new Types.TableType(structure, options);\r\n }\r\n // fallback to old style syntax, OCCURS etc\r\n return this.parseType(node, name);\r\n }\r\n parseType(node, qualifiedName) {\r\n var _a, _b, _c, _d, _e, _f;\r\n const typeName = node.findFirstExpression(Expressions.TypeName);\r\n let text = (_a = node.findFirstExpression(Expressions.Type)) === null || _a === void 0 ? void 0 : _a.concatTokens().toUpperCase();\r\n if (text === undefined) {\r\n text = (_b = node.findFirstExpression(Expressions.TypeParam)) === null || _b === void 0 ? void 0 : _b.concatTokens().toUpperCase();\r\n }\r\n if (text === undefined) {\r\n text = (_c = node.findFirstExpression(Expressions.TypeTable)) === null || _c === void 0 ? void 0 : _c.concatTokens().toUpperCase();\r\n if ((text === null || text === void 0 ? void 0 : text.startsWith(\"TYPE\")) === false && (text === null || text === void 0 ? void 0 : text.startsWith(\"LIKE\")) === false) {\r\n text = \"TYPE\";\r\n }\r\n }\r\n if (text === undefined) {\r\n text = (_d = node.findFirstExpression(Expressions.FormParamType)) === null || _d === void 0 ? void 0 : _d.concatTokens().toUpperCase();\r\n }\r\n if (text === undefined) {\r\n text = \"TYPE\";\r\n }\r\n let found = undefined;\r\n if (text.startsWith(\"LIKE LINE OF \")) {\r\n const name = (_e = node.findFirstExpression(Expressions.FieldChain)) === null || _e === void 0 ? void 0 : _e.concatTokens();\r\n let e = node.findFirstExpression(Expressions.Type);\r\n if (e === undefined) {\r\n e = node.findFirstExpression(Expressions.FormParamType);\r\n }\r\n const type = this.resolveLikeName(e, false);\r\n if (type === undefined) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + name + \"\\\", parseType\");\r\n }\r\n else if (type instanceof Types.TableType) {\r\n return type.getRowType();\r\n }\r\n else if (type instanceof Types.VoidType) {\r\n return type;\r\n }\r\n else {\r\n return new Types.UnknownType(\"Type error, not a table type \" + name);\r\n }\r\n }\r\n else if (text.startsWith(\"LIKE REF TO \")) {\r\n const name = (_f = node.findFirstExpression(Expressions.FieldChain)) === null || _f === void 0 ? void 0 : _f.concatTokens();\r\n const type = this.resolveLikeName(node.findFirstExpression(Expressions.Type), false);\r\n if (type === undefined) {\r\n return new Types.UnknownType(\"Type error, could not resolve \\\"\" + name + \"\\\", parseType\");\r\n }\r\n return new Types.DataReference(type, name);\r\n }\r\n else if (text === \"TYPE STANDARD TABLE\"\r\n || text === \"TYPE SORTED TABLE\"\r\n || text === \"TYPE HASHED TABLE\"\r\n || text === \"TYPE INDEX TABLE\"\r\n || text === \"TYPE ANY TABLE\") {\r\n return new Types.TableType(new Types.AnyType(), { withHeader: node.concatTokens().toUpperCase().includes(\"WITH HEADER LINE\") });\r\n }\r\n else if (text.startsWith(\"LIKE \")) {\r\n let sub = node.findFirstExpression(Expressions.Type);\r\n if (sub === undefined) {\r\n sub = node.findFirstExpression(Expressions.FormParamType);\r\n }\r\n if (sub === undefined) {\r\n sub = node.findFirstExpression(Expressions.TypeParam);\r\n }\r\n if (sub === undefined) {\r\n sub = node.findFirstExpression(Expressions.FieldChain);\r\n }\r\n found = this.resolveLikeName(sub);\r\n if (found && this.isOccurs(node)) {\r\n found = new Types.TableType(found, { withHeader: text.includes(\"WITH HEADER LINE\") }, qualifiedName);\r\n }\r\n }\r\n else if (text.startsWith(\"TYPE LINE OF \")) {\r\n const sub = node.findFirstExpression(Expressions.TypeName);\r\n found = this.resolveTypeName(sub);\r\n if (found instanceof _typed_identifier_1.TypedIdentifier) {\r\n found = found.getType();\r\n }\r\n if (found instanceof Types.TableType) {\r\n return found.getRowType();\r\n }\r\n else if (found instanceof Types.VoidType) {\r\n return found;\r\n }\r\n else if (found instanceof Types.UnknownType) {\r\n return new Types.UnknownType(\"TYPE LINE OF, unknown type, \" + found.getError());\r\n }\r\n else {\r\n return new Types.UnknownType(\"TYPE LINE OF, unexpected type, \" + (found === null || found === void 0 ? void 0 : found.constructor.name));\r\n }\r\n }\r\n else if (text.startsWith(\"TYPE REF TO \")) {\r\n found = this.resolveTypeRef(typeName);\r\n }\r\n else if (text.startsWith(\"TYPE\")) {\r\n found = this.resolveTypeName(typeName, this.findLength(node), this.findDecimals(node), qualifiedName);\r\n const concat = node.concatTokens().toUpperCase();\r\n if (found && this.isOccurs(node)) {\r\n found = new Types.TableType(found, { withHeader: concat.includes(\" WITH HEADER LINE\") }, qualifiedName);\r\n }\r\n else if (found && concat.includes(\" WITH HEADER LINE\")) {\r\n if (found instanceof Types.VoidType) {\r\n found = new Types.TableType(found, { withHeader: true });\r\n }\r\n else if (!(found instanceof Types.TableType)) {\r\n throw new Error(\"WITH HEADER LINE can only be used with internal table\");\r\n }\r\n else {\r\n found = new Types.TableType(found.getRowType(), { withHeader: true });\r\n }\r\n }\r\n if (found === undefined && typeName === undefined) {\r\n let length = 1;\r\n const len = node.findDirectExpression(Expressions.ConstantFieldLength);\r\n if (len) {\r\n const int = len.findDirectExpression(Expressions.Integer);\r\n if (int) {\r\n length = parseInt(int.concatTokens(), 10);\r\n }\r\n }\r\n found = new Types.CharacterType(length, qualifiedName); // fallback\r\n if (this.isOccurs(node)) {\r\n found = new Types.TableType(found, { withHeader: concat.includes(\" WITH HEADER LINE\") }, qualifiedName);\r\n }\r\n }\r\n }\r\n return found;\r\n }\r\n /////////////////////\r\n isOccurs(node) {\r\n var _a;\r\n if (node.findDirectTokenByText(\"OCCURS\")) {\r\n return true;\r\n }\r\n else if ((_a = node.findFirstExpression(Expressions.TypeTable)) === null || _a === void 0 ? void 0 : _a.findDirectTokenByText(\"OCCURS\")) {\r\n return true;\r\n }\r\n return false;\r\n }\r\n // todo, rewrite this method\r\n resolveTypeChain(expr) {\r\n var _a;\r\n const chainText = expr.concatTokens().toUpperCase();\r\n if (chainText.includes(\"=>\") === false && chainText.includes(\"-\") === false) {\r\n return undefined;\r\n }\r\n let className;\r\n let rest = chainText;\r\n if (chainText.includes(\"=>\")) {\r\n const split = chainText.split(\"=>\");\r\n className = split[0];\r\n rest = split[1];\r\n }\r\n const subs = rest.split(\"-\");\r\n let foundType = undefined;\r\n if (className) {\r\n const split = chainText.split(\"=>\");\r\n const className = split[0];\r\n // the prefix might be itself\r\n if ((this.scope.getType() === _scope_type_1.ScopeType.Interface\r\n || this.scope.getType() === _scope_type_1.ScopeType.ClassDefinition)\r\n && this.scope.getName().toUpperCase() === className.toUpperCase()) {\r\n const foundId = this.scope.findType(subs[0]);\r\n foundType = foundId === null || foundId === void 0 ? void 0 : foundId.getType();\r\n if (foundType === undefined) {\r\n return new Types.UnknownType(\"Could not resolve type \" + chainText);\r\n }\r\n this.scope.addReference(expr.getTokens()[2], foundId, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n else {\r\n // lookup in local and global scope\r\n const obj = this.scope.findObjectDefinition(className);\r\n if (obj === undefined && this.scope.getDDIC().inErrorNamespace(className) === false) {\r\n this.scope.addReference(expr.getFirstToken(), undefined, _reference_1.ReferenceType.ObjectOrientedVoidReference, this.filename, { ooName: className.toUpperCase() });\r\n return new Types.VoidType(className);\r\n }\r\n else if (obj === undefined) {\r\n return new Types.UnknownType(\"Could not resolve top \" + className + \", resolveTypeChain\");\r\n }\r\n const type = obj instanceof types_1.ClassDefinition ? \"CLAS\" : \"INTF\";\r\n this.scope.addReference(expr.getFirstToken(), obj, _reference_1.ReferenceType.ObjectOrientedReference, this.filename, { ooType: type, ooName: className });\r\n const byName = new _object_oriented_1.ObjectOriented(this.scope).searchTypeName(obj, subs[0]);\r\n foundType = byName === null || byName === void 0 ? void 0 : byName.getType();\r\n if (byName === undefined || foundType === undefined) {\r\n return new Types.UnknownType(subs[0] + \" not found in class or interface\");\r\n }\r\n this.scope.addReference(expr.getTokens()[2], byName, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n }\r\n else {\r\n const found = this.scope.findType(subs[0]);\r\n foundType = found === null || found === void 0 ? void 0 : found.getType();\r\n if (foundType === undefined) {\r\n const typePoolType = (_a = this.scope.findTypePoolType(subs[0])) === null || _a === void 0 ? void 0 : _a.getType();\r\n if (typePoolType) {\r\n // this.scope.addReference(typeName.getFirstToken(), typePoolType, ReferenceType.TypeReference, this.filename);\r\n foundType = typePoolType;\r\n }\r\n if (foundType === undefined) {\r\n const f = this.scope.getDDIC().lookupTableOrView(subs[0]);\r\n this.scope.getDDICReferences().addUsing(this.scope.getParentObj(), { object: f.object, filename: this.filename, token: expr.getFirstToken() });\r\n if (f.type instanceof _typed_identifier_1.TypedIdentifier) {\r\n foundType = f.type.getType();\r\n }\r\n else {\r\n foundType = f.type;\r\n }\r\n }\r\n }\r\n else {\r\n this.scope.addReference(expr.getFirstToken(), found, _reference_1.ReferenceType.TypeReference, this.filename);\r\n }\r\n if (foundType === undefined && this.scope.getDDIC().inErrorNamespace(subs[0]) === false) {\r\n this.scope.addReference(expr.getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n return new Types.VoidType(subs[0]);\r\n }\r\n else if (foundType instanceof Types.VoidType) {\r\n this.scope.addReference(expr.getFirstToken(), undefined, _reference_1.ReferenceType.VoidType, this.filename);\r\n return foundType;\r\n }\r\n else if (foundType === undefined) {\r\n return new Types.UnknownType(\"Unknown type \" + subs[0]);\r\n }\r\n }\r\n subs.shift();\r\n while (subs.length > 0) {\r\n if (foundType instanceof Types.UnknownType\r\n || foundType instanceof Types.VoidType) {\r\n return foundType;\r\n }\r\n else if (!(foundType instanceof Types.StructureType)) {\r\n return new Types.UnknownType(\"Not a structured type\");\r\n }\r\n foundType = foundType.getComponentByName(subs[0]);\r\n subs.shift();\r\n }\r\n return foundType;\r\n }\r\n resolveConstantValue(expr) {\r\n var _a, _b;\r\n if (!(expr.get() instanceof Expressions.SimpleFieldChain)) {\r\n throw new Error(\"resolveConstantValue\");\r\n }\r\n const firstNode = expr.getFirstChild();\r\n const firstToken = firstNode.getFirstToken();\r\n const firstName = firstToken.getStr();\r\n if (firstNode.get() instanceof Expressions.Field) {\r\n const found = this.scope.findVariable(firstName);\r\n const val = found === null || found === void 0 ? void 0 : found.getValue();\r\n if (typeof val === \"string\") {\r\n this.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.filename);\r\n return val;\r\n }\r\n return undefined;\r\n }\r\n else if (firstNode.get() instanceof Expressions.ClassName\r\n && firstName.toLowerCase() === this.scope.getName().toLowerCase()\r\n && (this.scope.getType() === _scope_type_1.ScopeType.Interface\r\n || this.scope.getType() === _scope_type_1.ScopeType.ClassDefinition)) {\r\n const children = expr.getChildren();\r\n const token = (_a = children[2]) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n const found = this.scope.findVariable(token.getStr());\r\n const val = found === null || found === void 0 ? void 0 : found.getValue();\r\n if (typeof val === \"string\") {\r\n this.scope.addReference(firstToken, found, _reference_1.ReferenceType.DataReadReference, this.filename);\r\n return val;\r\n }\r\n return undefined;\r\n }\r\n else if (firstNode.get() instanceof Expressions.ClassName) {\r\n const obj = this.scope.findObjectDefinition(firstName);\r\n if (obj === undefined) {\r\n if (this.scope.existsObject(firstName).found === true) {\r\n return undefined;\r\n }\r\n else if (this.scope.getDDIC().inErrorNamespace(firstName) === true) {\r\n throw new Error(\"resolveConstantValue, not found: \" + firstName);\r\n }\r\n else {\r\n this.scope.addReference(firstNode.getFirstToken(), undefined, _reference_1.ReferenceType.ObjectOrientedVoidReference, this.filename, { ooName: firstName.toUpperCase() });\r\n return undefined;\r\n }\r\n }\r\n const children = expr.getChildren();\r\n const token = (_b = children[2]) === null || _b === void 0 ? void 0 : _b.getFirstToken();\r\n const attr = token.getStr();\r\n const c = new _object_oriented_1.ObjectOriented(this.scope).searchConstantName(obj, attr);\r\n if (c instanceof class_constant_1.ClassConstant) {\r\n this.scope.addReference(token, c, _reference_1.ReferenceType.DataReadReference, this.filename);\r\n const val = c.getValue();\r\n if (typeof val === \"string\") {\r\n return val;\r\n }\r\n else if (typeof val === \"object\" && children[4]) {\r\n const name = children[4].getFirstToken().getStr();\r\n if (val[name] !== undefined) {\r\n return val[name];\r\n }\r\n }\r\n return undefined;\r\n }\r\n throw new Error(\"resolveConstantValue, constant not found \" + attr);\r\n }\r\n else {\r\n throw new Error(\"resolveConstantValue, unexpected structure\");\r\n }\r\n }\r\n resolveTypeRef(chain) {\r\n var _a;\r\n if (chain === undefined) {\r\n return undefined;\r\n }\r\n const name = chain.getFirstToken().getStr();\r\n if (chain.getAllTokens().length === 1) {\r\n if (name.toUpperCase() === \"OBJECT\") {\r\n return new Types.GenericObjectReferenceType();\r\n }\r\n const search = this.scope.existsObject(name);\r\n if (search.found === true && search.id) {\r\n this.scope.addReference(chain.getFirstToken(), search.id, _reference_1.ReferenceType.ObjectOrientedReference, this.filename, { ooType: search.ooType, ooName: name });\r\n return new Types.ObjectReferenceType(search.id, name);\r\n }\r\n }\r\n const found = this.resolveTypeName(chain);\r\n if (found && !(found instanceof Types.UnknownType) && !(found instanceof Types.VoidType)) {\r\n return new Types.DataReference(found);\r\n }\r\n else if (chain.concatTokens().toUpperCase() === \"DATA\") {\r\n return new Types.DataReference(new Types.AnyType());\r\n }\r\n if (this.scope.isBadiDef(name) === true) {\r\n return new Types.VoidType(name);\r\n }\r\n if (((_a = this.scope.getDDIC()) === null || _a === void 0 ? void 0 : _a.inErrorNamespace(name)) === false) {\r\n // this.scope.addReference(chain.getFirstToken(), undefined, ReferenceType.VoidType, this.filename);\r\n return new Types.VoidType(name);\r\n }\r\n return new Types.UnknownType(\"REF, unable to resolve \" + name);\r\n }\r\n findValue(node) {\r\n const val = node.findFirstExpression(Expressions.Value);\r\n if (val === undefined) {\r\n throw new Error(\"VALUE missing in expression\");\r\n }\r\n if (val.concatTokens().toUpperCase() === \"VALUE IS INITIAL\") {\r\n return undefined;\r\n }\r\n const constant = val.findFirstExpression(Expressions.Constant);\r\n if (constant) {\r\n return constant.concatTokens();\r\n }\r\n const chain = val.findFirstExpression(Expressions.SimpleFieldChain);\r\n if (chain) {\r\n return this.resolveConstantValue(chain);\r\n }\r\n throw new Error(\"findValue, unexpected\");\r\n }\r\n findDecimals(node) {\r\n var _a, _b;\r\n const dec = (_b = (_a = node.findDirectExpression(Expressions.Decimals)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Integer)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (dec) {\r\n return parseInt(dec, 10);\r\n }\r\n return undefined;\r\n }\r\n findLength(node) {\r\n const val = node.findFirstExpression(Expressions.Length);\r\n const flen = node.findFirstExpression(Expressions.ConstantFieldLength);\r\n if (val && flen) {\r\n throw new Error(\"Only specify length once\");\r\n }\r\n if (flen) {\r\n const cintExpr = flen.findFirstExpression(Expressions.Integer);\r\n if (cintExpr) {\r\n return this.parseInt(cintExpr.concatTokens());\r\n }\r\n const cchain = flen.findFirstExpression(Expressions.SimpleFieldChain);\r\n if (cchain) {\r\n const val = this.resolveConstantValue(cchain);\r\n return this.parseInt(val);\r\n }\r\n }\r\n if (val === undefined) {\r\n return 1;\r\n }\r\n const intExpr = val.findFirstExpression(Expressions.Integer);\r\n if (intExpr) {\r\n return this.parseInt(intExpr.concatTokens());\r\n }\r\n const strExpr = val.findFirstExpression(Expressions.ConstantString);\r\n if (strExpr) {\r\n return this.parseInt(strExpr.concatTokens());\r\n }\r\n const chain = val.findFirstExpression(Expressions.SimpleFieldChain);\r\n if (chain) {\r\n const val = this.resolveConstantValue(chain);\r\n return this.parseInt(val);\r\n }\r\n throw new Error(\"Unexpected, findLength\");\r\n }\r\n parseInt(text) {\r\n if (text === undefined) {\r\n return undefined;\r\n }\r\n if (text.startsWith(\"'\")) {\r\n text = text.split(\"'\")[1];\r\n }\r\n else if (text.startsWith(\"`\")) {\r\n text = text.split(\"`\")[1];\r\n }\r\n return parseInt(text, 10);\r\n }\r\n}\r\nexports.BasicTypes = BasicTypes;\r\n//# sourceMappingURL=basic_types.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/abap/5_syntax/basic_types.js?");
|
|
6664
6664
|
|
|
6665
6665
|
/***/ }),
|
|
6666
6666
|
|
|
@@ -7144,7 +7144,7 @@ eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\n
|
|
|
7144
7144
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
7145
7145
|
|
|
7146
7146
|
"use strict";
|
|
7147
|
-
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.ReduceBody = void 0;\r\nconst Expressions = __webpack_require__(/*! ../../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst for_1 = __webpack_require__(/*! ./for */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/for.js\");\r\nconst source_1 = __webpack_require__(/*! ./source */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js\");\r\nconst inline_field_definition_1 = __webpack_require__(/*! ./inline_field_definition */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/inline_field_definition.js\");\r\nconst unknown_type_1 = __webpack_require__(/*! ../../types/basic/unknown_type */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/unknown_type.js\");\r\nconst reduce_next_1 = __webpack_require__(/*! ./reduce_next */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/reduce_next.js\");\r\nconst let_1 = __webpack_require__(/*! ./let */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/let.js\");\r\nclass ReduceBody {\r\n runSyntax(node, scope, filename) {\r\n if (node === undefined) {\r\n return;\r\n }\r\n let scoped = false;\r\n const letNode = node.findDirectExpression(Expressions.Let);\r\n if (letNode) {\r\n scoped = new let_1.Let().runSyntax(letNode, scope, filename);\r\n }\r\n let first = undefined;\r\n for (const i of node.findDirectExpressions(Expressions.InlineFieldDefinition)) {\r\n const found = new inline_field_definition_1.InlineFieldDefinition().runSyntax(i, scope, filename);\r\n if (found && first === undefined) {\r\n first = found;\r\n }\r\n }\r\n let forScopes = 0;\r\n for (const forNode of node.findDirectExpressions(Expressions.For) || []) {\r\n const scoped = new for_1.For().runSyntax(forNode, scope, filename);\r\n if (scoped === true) {\r\n forScopes++;\r\n }\r\n }\r\n for (const s of node.findDirectExpressions(Expressions.Source)) {\r\n new source_1.Source().runSyntax(s, scope, filename);\r\n }\r\n for (const s of node.findDirectExpressions(Expressions.ReduceNext)) {\r\n new reduce_next_1.ReduceNext().runSyntax(s, scope, filename);\r\n }\r\n if (scoped === true) {\r\n scope.pop(node.getLastToken().getEnd());\r\n }\r\n for (let i = 0; i < forScopes; i++) {\r\n scope.pop(node.getLastToken().getEnd());\r\n }\r\n if (first) {\r\n return first;\r\n }\r\n else {\r\n return new unknown_type_1.UnknownType(\"todo, ReduceBody\");\r\n }\r\n }\r\n}\r\nexports.ReduceBody = ReduceBody;\r\n//# sourceMappingURL=reduce_body.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/reduce_body.js?");
|
|
7147
|
+
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.ReduceBody = void 0;\r\nconst Expressions = __webpack_require__(/*! ../../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst for_1 = __webpack_require__(/*! ./for */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/for.js\");\r\nconst source_1 = __webpack_require__(/*! ./source */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js\");\r\nconst inline_field_definition_1 = __webpack_require__(/*! ./inline_field_definition */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/inline_field_definition.js\");\r\nconst unknown_type_1 = __webpack_require__(/*! ../../types/basic/unknown_type */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/unknown_type.js\");\r\nconst reduce_next_1 = __webpack_require__(/*! ./reduce_next */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/reduce_next.js\");\r\nconst let_1 = __webpack_require__(/*! ./let */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/let.js\");\r\nconst _scope_type_1 = __webpack_require__(/*! ../_scope_type */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_scope_type.js\");\r\nclass ReduceBody {\r\n runSyntax(node, scope, filename) {\r\n if (node === undefined) {\r\n return;\r\n }\r\n let scoped = false;\r\n const letNode = node.findDirectExpression(Expressions.Let);\r\n if (letNode) {\r\n scoped = new let_1.Let().runSyntax(letNode, scope, filename);\r\n }\r\n let first = undefined;\r\n for (const i of node.findDirectExpressions(Expressions.InlineFieldDefinition)) {\r\n if (scoped === false) {\r\n scope.push(_scope_type_1.ScopeType.Let, \"LET\", node.getFirstToken().getStart(), filename);\r\n scoped = true;\r\n }\r\n const found = new inline_field_definition_1.InlineFieldDefinition().runSyntax(i, scope, filename);\r\n if (found && first === undefined) {\r\n first = found;\r\n }\r\n }\r\n let forScopes = 0;\r\n for (const forNode of node.findDirectExpressions(Expressions.For) || []) {\r\n const scoped = new for_1.For().runSyntax(forNode, scope, filename);\r\n if (scoped === true) {\r\n forScopes++;\r\n }\r\n }\r\n for (const s of node.findDirectExpressions(Expressions.Source)) {\r\n new source_1.Source().runSyntax(s, scope, filename);\r\n }\r\n for (const s of node.findDirectExpressions(Expressions.ReduceNext)) {\r\n new reduce_next_1.ReduceNext().runSyntax(s, scope, filename);\r\n }\r\n if (scoped === true) {\r\n scope.pop(node.getLastToken().getEnd());\r\n }\r\n for (let i = 0; i < forScopes; i++) {\r\n scope.pop(node.getLastToken().getEnd());\r\n }\r\n if (first) {\r\n return first;\r\n }\r\n else {\r\n return new unknown_type_1.UnknownType(\"todo, ReduceBody\");\r\n }\r\n }\r\n}\r\nexports.ReduceBody = ReduceBody;\r\n//# sourceMappingURL=reduce_body.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/reduce_body.js?");
|
|
7148
7148
|
|
|
7149
7149
|
/***/ }),
|
|
7150
7150
|
|
|
@@ -7694,7 +7694,7 @@ eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\n
|
|
|
7694
7694
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
7695
7695
|
|
|
7696
7696
|
"use strict";
|
|
7697
|
-
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.Describe = void 0;\r\nconst Expressions = __webpack_require__(/*! ../../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst inline_data_1 = __webpack_require__(/*! ../expressions/inline_data */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/inline_data.js\");\r\nconst basic_1 = __webpack_require__(/*! ../../types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst target_1 = __webpack_require__(/*! ../expressions/target */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/target.js\");\r\nconst source_1 = __webpack_require__(/*! ../expressions/source */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js\");\r\nconst field_chain_1 = __webpack_require__(/*! ../expressions/field_chain */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/field_chain.js\");\r\nconst _reference_1 = __webpack_require__(/*! ../_reference */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js\");\r\nclass Describe {\r\n runSyntax(node, scope, filename) {\r\n for (const s of node.findAllExpressions(Expressions.Source)) {\r\n new source_1.Source().runSyntax(s, scope, filename);\r\n }\r\n for (const s of node.findAllExpressions(Expressions.FieldChain)) {\r\n new field_chain_1.FieldChain().runSyntax(s, scope, filename, _reference_1.ReferenceType.DataReadReference);\r\n }\r\n const linesTarget = node.findExpressionAfterToken(\"LINES\");\r\n if ((linesTarget === null || linesTarget === void 0 ? void 0 : linesTarget.get()) instanceof Expressions.Target) {\r\n const inline = linesTarget === null || linesTarget === void 0 ? void 0 : linesTarget.findDirectExpression(Expressions.InlineData);\r\n if (inline) {\r\n new inline_data_1.InlineData().runSyntax(inline, scope, filename, new basic_1.IntegerType());\r\n }\r\n else {\r\n new target_1.Target().runSyntax(linesTarget, scope, filename);\r\n }\r\n }\r\n const typeTarget = node.findExpressionAfterToken(\"TYPE\");\r\n if ((typeTarget === null || typeTarget === void 0 ? void 0 : typeTarget.get()) instanceof Expressions.Target) {\r\n const inline = typeTarget === null || typeTarget === void 0 ? void 0 : typeTarget.findDirectExpression(Expressions.InlineData);\r\n if (inline) {\r\n new inline_data_1.InlineData().runSyntax(inline, scope, filename, new basic_1.CharacterType(1));\r\n }\r\n else {\r\n new target_1.Target().runSyntax(typeTarget, scope, filename);\r\n }\r\n }\r\n const lengthTarget = node.findExpressionAfterToken(\"LENGTH\");\r\n if ((lengthTarget === null || lengthTarget === void 0 ? void 0 : lengthTarget.get()) instanceof Expressions.Target) {\r\n const inline = lengthTarget === null || lengthTarget === void 0 ? void 0 : lengthTarget.findDirectExpression(Expressions.InlineData);\r\n if (inline) {\r\n new inline_data_1.InlineData().runSyntax(inline, scope, filename, new basic_1.IntegerType());\r\n }\r\n else {\r\n new target_1.Target().runSyntax(lengthTarget, scope, filename);\r\n }\r\n }\r\n }\r\n}\r\nexports.Describe = Describe;\r\n//# sourceMappingURL=describe.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/abap/5_syntax/statements/describe.js?");
|
|
7697
|
+
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.Describe = void 0;\r\nconst Expressions = __webpack_require__(/*! ../../2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst inline_data_1 = __webpack_require__(/*! ../expressions/inline_data */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/inline_data.js\");\r\nconst basic_1 = __webpack_require__(/*! ../../types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst target_1 = __webpack_require__(/*! ../expressions/target */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/target.js\");\r\nconst source_1 = __webpack_require__(/*! ../expressions/source */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/source.js\");\r\nconst field_chain_1 = __webpack_require__(/*! ../expressions/field_chain */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/expressions/field_chain.js\");\r\nconst _reference_1 = __webpack_require__(/*! ../_reference */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js\");\r\nclass Describe {\r\n runSyntax(node, scope, filename) {\r\n for (const s of node.findAllExpressions(Expressions.Source)) {\r\n new source_1.Source().runSyntax(s, scope, filename);\r\n }\r\n for (const s of node.findAllExpressions(Expressions.FieldChain)) {\r\n new field_chain_1.FieldChain().runSyntax(s, scope, filename, _reference_1.ReferenceType.DataReadReference);\r\n }\r\n const linesTarget = node.findExpressionAfterToken(\"LINES\");\r\n if ((linesTarget === null || linesTarget === void 0 ? void 0 : linesTarget.get()) instanceof Expressions.Target) {\r\n const inline = linesTarget === null || linesTarget === void 0 ? void 0 : linesTarget.findDirectExpression(Expressions.InlineData);\r\n if (inline) {\r\n new inline_data_1.InlineData().runSyntax(inline, scope, filename, new basic_1.IntegerType());\r\n }\r\n else {\r\n new target_1.Target().runSyntax(linesTarget, scope, filename);\r\n }\r\n }\r\n const typeTarget = node.findExpressionAfterToken(\"TYPE\");\r\n if ((typeTarget === null || typeTarget === void 0 ? void 0 : typeTarget.get()) instanceof Expressions.Target) {\r\n const inline = typeTarget === null || typeTarget === void 0 ? void 0 : typeTarget.findDirectExpression(Expressions.InlineData);\r\n if (inline) {\r\n new inline_data_1.InlineData().runSyntax(inline, scope, filename, new basic_1.CharacterType(1));\r\n }\r\n else {\r\n new target_1.Target().runSyntax(typeTarget, scope, filename);\r\n }\r\n }\r\n const lengthTarget = node.findExpressionAfterToken(\"LENGTH\");\r\n if ((lengthTarget === null || lengthTarget === void 0 ? void 0 : lengthTarget.get()) instanceof Expressions.Target) {\r\n const inline = lengthTarget === null || lengthTarget === void 0 ? void 0 : lengthTarget.findDirectExpression(Expressions.InlineData);\r\n if (inline) {\r\n new inline_data_1.InlineData().runSyntax(inline, scope, filename, new basic_1.IntegerType());\r\n }\r\n else {\r\n new target_1.Target().runSyntax(lengthTarget, scope, filename);\r\n }\r\n }\r\n const componentsTarget = node.findExpressionAfterToken(\"COMPONENTS\");\r\n if ((componentsTarget === null || componentsTarget === void 0 ? void 0 : componentsTarget.get()) instanceof Expressions.Target) {\r\n const inline = componentsTarget === null || componentsTarget === void 0 ? void 0 : componentsTarget.findDirectExpression(Expressions.InlineData);\r\n if (inline) {\r\n new inline_data_1.InlineData().runSyntax(inline, scope, filename, new basic_1.IntegerType());\r\n }\r\n else {\r\n new target_1.Target().runSyntax(componentsTarget, scope, filename);\r\n }\r\n }\r\n }\r\n}\r\nexports.Describe = Describe;\r\n//# sourceMappingURL=describe.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/abap/5_syntax/statements/describe.js?");
|
|
7698
7698
|
|
|
7699
7699
|
/***/ }),
|
|
7700
7700
|
|
|
@@ -11467,7 +11467,7 @@ eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\n
|
|
|
11467
11467
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
11468
11468
|
|
|
11469
11469
|
"use strict";
|
|
11470
|
-
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Registry = void 0;\nconst config_1 = __webpack_require__(/*! ./config */ \"./node_modules/@abaplint/core/build/src/config.js\");\nconst artifacts_objects_1 = __webpack_require__(/*! ./artifacts_objects */ \"./node_modules/@abaplint/core/build/src/artifacts_objects.js\");\nconst find_global_definitions_1 = __webpack_require__(/*! ./abap/5_syntax/global_definitions/find_global_definitions */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/global_definitions/find_global_definitions.js\");\nconst excludeHelper_1 = __webpack_require__(/*! ./utils/excludeHelper */ \"./node_modules/@abaplint/core/build/src/utils/excludeHelper.js\");\nconst ddic_references_1 = __webpack_require__(/*! ./ddic_references */ \"./node_modules/@abaplint/core/build/src/ddic_references.js\");\nconst rules_runner_1 = __webpack_require__(/*! ./rules_runner */ \"./node_modules/@abaplint/core/build/src/rules_runner.js\");\n// todo, this should really be an instance in case there are multiple Registry'ies\nclass ParsingPerformance {\n static clear() {\n this.results = [];\n this.lexing = 0;\n this.statements = 0;\n this.structure = 0;\n }\n static push(obj, result) {\n if (result.runtimeExtra) {\n this.lexing += result.runtimeExtra.lexing;\n this.statements += result.runtimeExtra.statements;\n this.structure += result.runtimeExtra.structure;\n }\n if (result.runtime < 100) {\n return;\n }\n if (this.results === undefined) {\n this.results = [];\n }\n let extra = \"\";\n if (result.runtimeExtra) {\n extra = `\\t(lexing: ${result.runtimeExtra.lexing}ms, statements: ${result.runtimeExtra.statements}ms, structure: ${result.runtimeExtra.structure}ms)`;\n }\n this.results.push({\n runtime: result.runtime,\n extra,\n name: obj.getType() + \" \" + obj.getName(),\n });\n }\n static output() {\n const MAX = 10;\n this.results.sort((a, b) => { return b.runtime - a.runtime; });\n for (let i = 0; i < MAX; i++) {\n const row = this.results[i];\n if (row === undefined) {\n break;\n }\n process.stderr.write(`\\t${row.runtime}ms\\t${row.name} ${row.extra}\\n`);\n }\n process.stderr.write(`\\tTotal lexing: ${this.lexing}ms\\n`);\n process.stderr.write(`\\tTotal statements: ${this.statements}ms\\n`);\n process.stderr.write(`\\tTotal structure: ${this.structure}ms\\n`);\n }\n}\n///////////////////////////////////////////////////////////////////////////////////////////////\nclass Registry {\n constructor(conf) {\n this.objects = {};\n this.objectsByType = {};\n this.dependencies = {};\n this.conf = conf ? conf : config_1.Config.getDefault();\n this.references = new ddic_references_1.DDICReferences();\n }\n static abaplintVersion() {\n // magic, see build script \"version.sh\"\n return \"2.93.27\";\n }\n getDDICReferences() {\n return this.references;\n }\n *getObjects() {\n for (const name in this.objects) {\n for (const type in this.objects[name]) {\n yield this.objects[name][type];\n }\n }\n }\n *getObjectsByType(type) {\n for (const name in this.objectsByType[type] || []) {\n yield this.objectsByType[type][name];\n }\n }\n *getFiles() {\n for (const obj of this.getObjects()) {\n for (const file of obj.getFiles()) {\n yield file;\n }\n }\n }\n getFirstObject() {\n for (const name in this.objects) {\n for (const type in this.objects[name]) {\n return this.objects[name][type];\n }\n }\n return undefined;\n }\n getObjectCount(skipDependencies = true) {\n let res = 0;\n for (const o of this.getObjects()) {\n if (skipDependencies === true && this.isDependency(o)) {\n continue;\n }\n res = res + 1;\n }\n return res;\n }\n getFileByName(filename) {\n const upper = filename.toUpperCase();\n for (const o of this.getObjects()) {\n for (const f of o.getFiles()) {\n if (f.getFilename().toUpperCase() === upper) {\n return f;\n }\n }\n }\n return undefined;\n }\n getObject(type, name) {\n if (type === undefined || name === undefined) {\n return undefined;\n }\n const searchName = name.toUpperCase();\n if (this.objects[searchName]) {\n return this.objects[searchName][type];\n }\n return undefined;\n }\n getConfig() {\n return this.conf;\n }\n // assumption: Config is immutable, and can only be changed via this method\n setConfig(conf) {\n for (const obj of this.getObjects()) {\n obj.setDirty();\n }\n this.conf = conf;\n return this;\n }\n inErrorNamespace(name) {\n // todo: performance? cache regexp?\n const reg = new RegExp(this.getConfig().getSyntaxSetttings().errorNamespace, \"i\");\n return reg.test(name);\n }\n addFile(file) {\n return this.addFiles([file]);\n }\n updateFile(file) {\n const obj = this.find(file.getObjectName(), file.getObjectType());\n obj.updateFile(file);\n return this;\n }\n removeFile(file) {\n const obj = this.find(file.getObjectName(), file.getObjectType());\n obj.removeFile(file);\n if (obj.getFiles().length === 0) {\n this.references.clear(obj);\n this.removeObject(obj);\n }\n return this;\n }\n _addFiles(files, dependency) {\n var _a;\n const globalExclude = ((_a = this.conf.getGlobal().exclude) !== null && _a !== void 0 ? _a : [])\n .map(pattern => new RegExp(pattern, \"i\"));\n for (const f of files) {\n const filename = f.getFilename();\n const isNotAbapgitFile = filename.split(\".\").length <= 2;\n if (isNotAbapgitFile || excludeHelper_1.ExcludeHelper.isExcluded(filename, globalExclude)) {\n continue;\n }\n let found = this.findOrCreate(f.getObjectName(), f.getObjectType());\n if (dependency === false && found && this.isDependency(found)) {\n this.removeDependency(found);\n found = this.findOrCreate(f.getObjectName(), f.getObjectType());\n }\n found.addFile(f);\n }\n return this;\n }\n addFiles(files) {\n this._addFiles(files, false);\n return this;\n }\n addDependencies(files) {\n for (const f of files) {\n this.addDependency(f);\n }\n return this;\n }\n addDependency(file) {\n var _a;\n const type = (_a = file.getObjectType()) === null || _a === void 0 ? void 0 : _a.toUpperCase();\n if (type === undefined) {\n return this;\n }\n const name = file.getObjectName().toUpperCase();\n if (this.dependencies[type] === undefined) {\n this.dependencies[type] = {};\n }\n this.dependencies[type][name] = true;\n this._addFiles([file], true);\n return this;\n }\n removeDependency(obj) {\n var _a;\n (_a = this.dependencies[obj.getType()]) === null || _a === void 0 ? true : delete _a[obj.getName()];\n this.removeObject(obj);\n }\n isDependency(obj) {\n var _a;\n return ((_a = this.dependencies[obj.getType()]) === null || _a === void 0 ? void 0 : _a[obj.getName()]) === true;\n }\n isFileDependency(filename) {\n var _a, _b;\n const f = this.getFileByName(filename);\n if (f === undefined) {\n return false;\n }\n const type = (_a = f.getObjectType()) === null || _a === void 0 ? void 0 : _a.toUpperCase();\n if (type === undefined) {\n return false;\n }\n const name = f.getObjectName().toUpperCase();\n return ((_b = this.dependencies[type]) === null || _b === void 0 ? void 0 : _b[name]) === true;\n }\n // assumption: the file is already in the registry\n findObjectForFile(file) {\n const filename = file.getFilename();\n for (const obj of this.getObjects()) {\n for (const ofile of obj.getFiles()) {\n if (ofile.getFilename() === filename) {\n return obj;\n }\n }\n }\n return undefined;\n }\n // todo, this will be changed to async sometime\n findIssues(input) {\n if (this.isDirty() === true) {\n this.parse();\n }\n return new rules_runner_1.RulesRunner(this).runRules(this.getObjects(), input);\n }\n // todo, this will be changed to async sometime\n findIssuesObject(iobj) {\n if (this.isDirty() === true) {\n this.parse();\n }\n return new rules_runner_1.RulesRunner(this).runRules([iobj]);\n }\n // todo, this will be changed to async sometime\n parse() {\n if (this.isDirty() === false) {\n return this;\n }\n ParsingPerformance.clear();\n for (const o of this.getObjects()) {\n this.parsePrivate(o);\n }\n new find_global_definitions_1.FindGlobalDefinitions(this).run();\n return this;\n }\n async parseAsync(input) {\n var _a, _b;\n if (this.isDirty() === false) {\n return this;\n }\n ParsingPerformance.clear();\n (_a = input === null || input === void 0 ? void 0 : input.progress) === null || _a === void 0 ? void 0 : _a.set(this.getObjectCount(false), \"Lexing and parsing\");\n for (const o of this.getObjects()) {\n await ((_b = input === null || input === void 0 ? void 0 : input.progress) === null || _b === void 0 ? void 0 : _b.tick(\"Lexing and parsing(\" + this.conf.getVersion() + \") - \" + o.getType() + \" \" + o.getName()));\n this.parsePrivate(o);\n }\n if ((input === null || input === void 0 ? void 0 : input.outputPerformance) === true) {\n ParsingPerformance.output();\n }\n new find_global_definitions_1.FindGlobalDefinitions(this).run(input === null || input === void 0 ? void 0 : input.progress);\n return this;\n }\n //////////////////////////////////////////\n // todo, refactor, this is a mess, see where-used, a lot of the code should be in this method instead\n parsePrivate(input) {\n const config = this.getConfig();\n const result = input.parse(config.getVersion(), config.getSyntaxSetttings().globalMacros, this);\n ParsingPerformance.push(input, result);\n }\n isDirty() {\n for (const o of this.getObjects()) {\n const dirty = o.isDirty();\n if (dirty === true) {\n return true;\n }\n }\n return false;\n }\n findOrCreate(name, type) {\n try {\n return this.find(name, type);\n }\n catch (_a) {\n const newName = name.toUpperCase();\n const newType = type ? type : \"UNKNOWN\";\n const add = artifacts_objects_1.ArtifactsObjects.newObject(newName, newType);\n if (this.objects[newName] === undefined) {\n this.objects[newName] = {};\n }\n this.objects[newName][newType] = add;\n if (this.objectsByType[newType] === undefined) {\n this.objectsByType[newType] = {};\n }\n this.objectsByType[newType][newName] = add;\n return add;\n }\n }\n removeObject(remove) {\n if (remove === undefined) {\n return;\n }\n if (this.objects[remove.getName()][remove.getType()] === undefined) {\n throw new Error(\"removeObject: object not found\");\n }\n if (Object.keys(this.objects[remove.getName()]).length === 1) {\n delete this.objects[remove.getName()];\n }\n else {\n delete this.objects[remove.getName()][remove.getType()];\n }\n if (Object.keys(this.objectsByType[remove.getType()]).length === 1) {\n delete this.objectsByType[remove.getType()];\n }\n else {\n delete this.objectsByType[remove.getType()][remove.getName()];\n }\n }\n find(name, type) {\n const searchType = type ? type : \"UNKNOWN\";\n const searchName = name.toUpperCase();\n if (this.objects[searchName] !== undefined\n && this.objects[searchName][searchType]) {\n return this.objects[searchName][searchType];\n }\n throw new Error(\"find: object not found, \" + type + \" \" + name);\n }\n}\nexports.Registry = Registry;\n//# sourceMappingURL=registry.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/registry.js?");
|
|
11470
|
+
eval("\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\nexports.Registry = void 0;\nconst config_1 = __webpack_require__(/*! ./config */ \"./node_modules/@abaplint/core/build/src/config.js\");\nconst artifacts_objects_1 = __webpack_require__(/*! ./artifacts_objects */ \"./node_modules/@abaplint/core/build/src/artifacts_objects.js\");\nconst find_global_definitions_1 = __webpack_require__(/*! ./abap/5_syntax/global_definitions/find_global_definitions */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/global_definitions/find_global_definitions.js\");\nconst excludeHelper_1 = __webpack_require__(/*! ./utils/excludeHelper */ \"./node_modules/@abaplint/core/build/src/utils/excludeHelper.js\");\nconst ddic_references_1 = __webpack_require__(/*! ./ddic_references */ \"./node_modules/@abaplint/core/build/src/ddic_references.js\");\nconst rules_runner_1 = __webpack_require__(/*! ./rules_runner */ \"./node_modules/@abaplint/core/build/src/rules_runner.js\");\n// todo, this should really be an instance in case there are multiple Registry'ies\nclass ParsingPerformance {\n static clear() {\n this.results = [];\n this.lexing = 0;\n this.statements = 0;\n this.structure = 0;\n }\n static push(obj, result) {\n if (result.runtimeExtra) {\n this.lexing += result.runtimeExtra.lexing;\n this.statements += result.runtimeExtra.statements;\n this.structure += result.runtimeExtra.structure;\n }\n if (result.runtime < 100) {\n return;\n }\n if (this.results === undefined) {\n this.results = [];\n }\n let extra = \"\";\n if (result.runtimeExtra) {\n extra = `\\t(lexing: ${result.runtimeExtra.lexing}ms, statements: ${result.runtimeExtra.statements}ms, structure: ${result.runtimeExtra.structure}ms)`;\n }\n this.results.push({\n runtime: result.runtime,\n extra,\n name: obj.getType() + \" \" + obj.getName(),\n });\n }\n static output() {\n const MAX = 10;\n this.results.sort((a, b) => { return b.runtime - a.runtime; });\n for (let i = 0; i < MAX; i++) {\n const row = this.results[i];\n if (row === undefined) {\n break;\n }\n process.stderr.write(`\\t${row.runtime}ms\\t${row.name} ${row.extra}\\n`);\n }\n process.stderr.write(`\\tTotal lexing: ${this.lexing}ms\\n`);\n process.stderr.write(`\\tTotal statements: ${this.statements}ms\\n`);\n process.stderr.write(`\\tTotal structure: ${this.structure}ms\\n`);\n }\n}\n///////////////////////////////////////////////////////////////////////////////////////////////\nclass Registry {\n constructor(conf) {\n this.objects = {};\n this.objectsByType = {};\n this.dependencies = {};\n this.conf = conf ? conf : config_1.Config.getDefault();\n this.references = new ddic_references_1.DDICReferences();\n }\n static abaplintVersion() {\n // magic, see build script \"version.sh\"\n return \"2.93.29\";\n }\n getDDICReferences() {\n return this.references;\n }\n *getObjects() {\n for (const name in this.objects) {\n for (const type in this.objects[name]) {\n yield this.objects[name][type];\n }\n }\n }\n *getObjectsByType(type) {\n for (const name in this.objectsByType[type] || []) {\n yield this.objectsByType[type][name];\n }\n }\n *getFiles() {\n for (const obj of this.getObjects()) {\n for (const file of obj.getFiles()) {\n yield file;\n }\n }\n }\n getFirstObject() {\n for (const name in this.objects) {\n for (const type in this.objects[name]) {\n return this.objects[name][type];\n }\n }\n return undefined;\n }\n getObjectCount(skipDependencies = true) {\n let res = 0;\n for (const o of this.getObjects()) {\n if (skipDependencies === true && this.isDependency(o)) {\n continue;\n }\n res = res + 1;\n }\n return res;\n }\n getFileByName(filename) {\n const upper = filename.toUpperCase();\n for (const o of this.getObjects()) {\n for (const f of o.getFiles()) {\n if (f.getFilename().toUpperCase() === upper) {\n return f;\n }\n }\n }\n return undefined;\n }\n getObject(type, name) {\n if (type === undefined || name === undefined) {\n return undefined;\n }\n const searchName = name.toUpperCase();\n if (this.objects[searchName]) {\n return this.objects[searchName][type];\n }\n return undefined;\n }\n getConfig() {\n return this.conf;\n }\n // assumption: Config is immutable, and can only be changed via this method\n setConfig(conf) {\n for (const obj of this.getObjects()) {\n obj.setDirty();\n }\n this.conf = conf;\n return this;\n }\n inErrorNamespace(name) {\n // todo: performance? cache regexp?\n const reg = new RegExp(this.getConfig().getSyntaxSetttings().errorNamespace, \"i\");\n return reg.test(name);\n }\n addFile(file) {\n return this.addFiles([file]);\n }\n updateFile(file) {\n const obj = this.find(file.getObjectName(), file.getObjectType());\n obj.updateFile(file);\n return this;\n }\n removeFile(file) {\n const obj = this.find(file.getObjectName(), file.getObjectType());\n obj.removeFile(file);\n if (obj.getFiles().length === 0) {\n this.references.clear(obj);\n this.removeObject(obj);\n }\n return this;\n }\n _addFiles(files, dependency) {\n var _a;\n const globalExclude = ((_a = this.conf.getGlobal().exclude) !== null && _a !== void 0 ? _a : [])\n .map(pattern => new RegExp(pattern, \"i\"));\n for (const f of files) {\n const filename = f.getFilename();\n const isNotAbapgitFile = filename.split(\".\").length <= 2;\n if (isNotAbapgitFile || excludeHelper_1.ExcludeHelper.isExcluded(filename, globalExclude)) {\n continue;\n }\n let found = this.findOrCreate(f.getObjectName(), f.getObjectType());\n if (dependency === false && found && this.isDependency(found)) {\n this.removeDependency(found);\n found = this.findOrCreate(f.getObjectName(), f.getObjectType());\n }\n found.addFile(f);\n }\n return this;\n }\n addFiles(files) {\n this._addFiles(files, false);\n return this;\n }\n addDependencies(files) {\n for (const f of files) {\n this.addDependency(f);\n }\n return this;\n }\n addDependency(file) {\n var _a;\n const type = (_a = file.getObjectType()) === null || _a === void 0 ? void 0 : _a.toUpperCase();\n if (type === undefined) {\n return this;\n }\n const name = file.getObjectName().toUpperCase();\n if (this.dependencies[type] === undefined) {\n this.dependencies[type] = {};\n }\n this.dependencies[type][name] = true;\n this._addFiles([file], true);\n return this;\n }\n removeDependency(obj) {\n var _a;\n (_a = this.dependencies[obj.getType()]) === null || _a === void 0 ? true : delete _a[obj.getName()];\n this.removeObject(obj);\n }\n isDependency(obj) {\n var _a;\n return ((_a = this.dependencies[obj.getType()]) === null || _a === void 0 ? void 0 : _a[obj.getName()]) === true;\n }\n isFileDependency(filename) {\n var _a, _b;\n const f = this.getFileByName(filename);\n if (f === undefined) {\n return false;\n }\n const type = (_a = f.getObjectType()) === null || _a === void 0 ? void 0 : _a.toUpperCase();\n if (type === undefined) {\n return false;\n }\n const name = f.getObjectName().toUpperCase();\n return ((_b = this.dependencies[type]) === null || _b === void 0 ? void 0 : _b[name]) === true;\n }\n // assumption: the file is already in the registry\n findObjectForFile(file) {\n const filename = file.getFilename();\n for (const obj of this.getObjects()) {\n for (const ofile of obj.getFiles()) {\n if (ofile.getFilename() === filename) {\n return obj;\n }\n }\n }\n return undefined;\n }\n // todo, this will be changed to async sometime\n findIssues(input) {\n if (this.isDirty() === true) {\n this.parse();\n }\n return new rules_runner_1.RulesRunner(this).runRules(this.getObjects(), input);\n }\n // todo, this will be changed to async sometime\n findIssuesObject(iobj) {\n if (this.isDirty() === true) {\n this.parse();\n }\n return new rules_runner_1.RulesRunner(this).runRules([iobj]);\n }\n // todo, this will be changed to async sometime\n parse() {\n if (this.isDirty() === false) {\n return this;\n }\n ParsingPerformance.clear();\n for (const o of this.getObjects()) {\n this.parsePrivate(o);\n }\n new find_global_definitions_1.FindGlobalDefinitions(this).run();\n return this;\n }\n async parseAsync(input) {\n var _a, _b;\n if (this.isDirty() === false) {\n return this;\n }\n ParsingPerformance.clear();\n (_a = input === null || input === void 0 ? void 0 : input.progress) === null || _a === void 0 ? void 0 : _a.set(this.getObjectCount(false), \"Lexing and parsing\");\n for (const o of this.getObjects()) {\n await ((_b = input === null || input === void 0 ? void 0 : input.progress) === null || _b === void 0 ? void 0 : _b.tick(\"Lexing and parsing(\" + this.conf.getVersion() + \") - \" + o.getType() + \" \" + o.getName()));\n this.parsePrivate(o);\n }\n if ((input === null || input === void 0 ? void 0 : input.outputPerformance) === true) {\n ParsingPerformance.output();\n }\n new find_global_definitions_1.FindGlobalDefinitions(this).run(input === null || input === void 0 ? void 0 : input.progress);\n return this;\n }\n //////////////////////////////////////////\n // todo, refactor, this is a mess, see where-used, a lot of the code should be in this method instead\n parsePrivate(input) {\n const config = this.getConfig();\n const result = input.parse(config.getVersion(), config.getSyntaxSetttings().globalMacros, this);\n ParsingPerformance.push(input, result);\n }\n isDirty() {\n for (const o of this.getObjects()) {\n const dirty = o.isDirty();\n if (dirty === true) {\n return true;\n }\n }\n return false;\n }\n findOrCreate(name, type) {\n try {\n return this.find(name, type);\n }\n catch (_a) {\n const newName = name.toUpperCase();\n const newType = type ? type : \"UNKNOWN\";\n const add = artifacts_objects_1.ArtifactsObjects.newObject(newName, newType);\n if (this.objects[newName] === undefined) {\n this.objects[newName] = {};\n }\n this.objects[newName][newType] = add;\n if (this.objectsByType[newType] === undefined) {\n this.objectsByType[newType] = {};\n }\n this.objectsByType[newType][newName] = add;\n return add;\n }\n }\n removeObject(remove) {\n if (remove === undefined) {\n return;\n }\n if (this.objects[remove.getName()][remove.getType()] === undefined) {\n throw new Error(\"removeObject: object not found\");\n }\n if (Object.keys(this.objects[remove.getName()]).length === 1) {\n delete this.objects[remove.getName()];\n }\n else {\n delete this.objects[remove.getName()][remove.getType()];\n }\n if (Object.keys(this.objectsByType[remove.getType()]).length === 1) {\n delete this.objectsByType[remove.getType()];\n }\n else {\n delete this.objectsByType[remove.getType()][remove.getName()];\n }\n }\n find(name, type) {\n const searchType = type ? type : \"UNKNOWN\";\n const searchName = name.toUpperCase();\n if (this.objects[searchName] !== undefined\n && this.objects[searchName][searchType]) {\n return this.objects[searchName][searchType];\n }\n throw new Error(\"find: object not found, \" + type + \" \" + name);\n }\n}\nexports.Registry = Registry;\n//# sourceMappingURL=registry.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/registry.js?");
|
|
11471
11471
|
|
|
11472
11472
|
/***/ }),
|
|
11473
11473
|
|
|
@@ -11533,7 +11533,7 @@ eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\n
|
|
|
11533
11533
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
11534
11534
|
|
|
11535
11535
|
"use strict";
|
|
11536
|
-
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.Abapdoc = exports.AbapdocConf = void 0;\r\nconst _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ \"./node_modules/@abaplint/core/build/src/rules/_abap_rule.js\");\r\nconst _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ \"./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js\");\r\nconst issue_1 = __webpack_require__(/*! ../issue */ \"./node_modules/@abaplint/core/build/src/issue.js\");\r\nconst visibility_1 = __webpack_require__(/*! ../abap/4_file_information/visibility */ \"./node_modules/@abaplint/core/build/src/abap/4_file_information/visibility.js\");\r\nconst _irule_1 = __webpack_require__(/*! ./_irule */ \"./node_modules/@abaplint/core/build/src/rules/_irule.js\");\r\nclass AbapdocConf extends _basic_rule_config_1.BasicRuleConfig {\r\n constructor() {\r\n super(...arguments);\r\n /** Check local classes and interfaces for abapdoc. */\r\n this.checkLocal = false;\r\n }\r\n}\r\nexports.AbapdocConf = AbapdocConf;\r\nclass Abapdoc extends _abap_rule_1.ABAPRule {\r\n constructor() {\r\n super(...arguments);\r\n this.conf = new AbapdocConf();\r\n }\r\n getMetadata() {\r\n return {\r\n key: \"abapdoc\",\r\n title: \"Check abapdoc\",\r\n shortDescription: `Various checks regarding abapdoc.\r\nBase rule checks for existence of abapdoc for public class methods and all interface methods.`,\r\n tags: [_irule_1.RuleTag.SingleFile],\r\n };\r\n }\r\n getConfig() {\r\n return this.conf;\r\n }\r\n setConfig(conf) {\r\n this.conf = conf;\r\n }\r\n runParsed(file) {\r\n const issues = [];\r\n const rows = file.getRawRows();\r\n let methods = [];\r\n for (const classDef of file.getInfo().listClassDefinitions()) {\r\n if (this.conf.checkLocal === false && classDef.isLocal === true) {\r\n continue;\r\n }\r\n methods = methods.concat(classDef.methods.filter(m => m.visibility === visibility_1.Visibility.Public));\r\n }\r\n for (const interfaceDef of file.getInfo().listInterfaceDefinitions()) {\r\n if (this.conf.checkLocal === false && interfaceDef.isLocal === true) {\r\n continue;\r\n }\r\n methods = methods.concat(interfaceDef.methods);\r\n }\r\n for (const method of methods) {\r\n if (method.isRedefinition === true) {\r\n continue;\r\n }\r\n const previousRow = method.identifier.getStart().getRow() - 2;\r\n if (!(rows[previousRow].trim().substring(0, 2) === \"\\\"!\")) {\r\n const message = \"Missing ABAP Doc for method \" + method.identifier.getToken().getStr();\r\n const issue = issue_1.Issue.atIdentifier(method.identifier, message, this.getMetadata().key, this.conf.severity);\r\n issues.push(issue);\r\n }\r\n }\r\n return issues;\r\n }\r\n}\r\nexports.Abapdoc = Abapdoc;\r\n//# sourceMappingURL=abapdoc.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/rules/abapdoc.js?");
|
|
11536
|
+
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.Abapdoc = exports.AbapdocConf = void 0;\r\nconst _abap_rule_1 = __webpack_require__(/*! ./_abap_rule */ \"./node_modules/@abaplint/core/build/src/rules/_abap_rule.js\");\r\nconst _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ \"./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js\");\r\nconst issue_1 = __webpack_require__(/*! ../issue */ \"./node_modules/@abaplint/core/build/src/issue.js\");\r\nconst visibility_1 = __webpack_require__(/*! ../abap/4_file_information/visibility */ \"./node_modules/@abaplint/core/build/src/abap/4_file_information/visibility.js\");\r\nconst _irule_1 = __webpack_require__(/*! ./_irule */ \"./node_modules/@abaplint/core/build/src/rules/_irule.js\");\r\nclass AbapdocConf extends _basic_rule_config_1.BasicRuleConfig {\r\n constructor() {\r\n super(...arguments);\r\n /** Check local classes and interfaces for abapdoc. */\r\n this.checkLocal = false;\r\n this.classDefinition = false;\r\n this.interfaceDefinition = false;\r\n }\r\n}\r\nexports.AbapdocConf = AbapdocConf;\r\nclass Abapdoc extends _abap_rule_1.ABAPRule {\r\n constructor() {\r\n super(...arguments);\r\n this.conf = new AbapdocConf();\r\n }\r\n getMetadata() {\r\n return {\r\n key: \"abapdoc\",\r\n title: \"Check abapdoc\",\r\n shortDescription: `Various checks regarding abapdoc.\r\nBase rule checks for existence of abapdoc for public class methods and all interface methods.\r\n\r\nPlus class and interface definitions.`,\r\n tags: [_irule_1.RuleTag.SingleFile],\r\n };\r\n }\r\n getConfig() {\r\n return this.conf;\r\n }\r\n setConfig(conf) {\r\n this.conf = conf;\r\n }\r\n runParsed(file) {\r\n var _a, _b;\r\n const issues = [];\r\n const rows = file.getRawRows();\r\n let methods = [];\r\n for (const classDef of file.getInfo().listClassDefinitions()) {\r\n if (this.conf.checkLocal === false && classDef.isLocal === true) {\r\n continue;\r\n }\r\n methods = methods.concat(classDef.methods.filter(m => m.visibility === visibility_1.Visibility.Public));\r\n if (this.getConfig().classDefinition === true) {\r\n const previousRow = classDef.identifier.getStart().getRow() - 2;\r\n if (((_a = rows[previousRow]) === null || _a === void 0 ? void 0 : _a.trim().substring(0, 2)) !== \"\\\"!\") {\r\n const message = \"Missing ABAP Doc for class \" + classDef.identifier.getToken().getStr();\r\n const issue = issue_1.Issue.atIdentifier(classDef.identifier, message, this.getMetadata().key, this.conf.severity);\r\n issues.push(issue);\r\n }\r\n }\r\n }\r\n for (const interfaceDef of file.getInfo().listInterfaceDefinitions()) {\r\n if (this.conf.checkLocal === false && interfaceDef.isLocal === true) {\r\n continue;\r\n }\r\n methods = methods.concat(interfaceDef.methods);\r\n if (this.getConfig().interfaceDefinition === true) {\r\n const previousRow = interfaceDef.identifier.getStart().getRow() - 2;\r\n if (((_b = rows[previousRow]) === null || _b === void 0 ? void 0 : _b.trim().substring(0, 2)) !== \"\\\"!\") {\r\n const message = \"Missing ABAP Doc for interface \" + interfaceDef.identifier.getToken().getStr();\r\n const issue = issue_1.Issue.atIdentifier(interfaceDef.identifier, message, this.getMetadata().key, this.conf.severity);\r\n issues.push(issue);\r\n }\r\n }\r\n }\r\n for (const method of methods) {\r\n if (method.isRedefinition === true) {\r\n continue;\r\n }\r\n const previousRow = method.identifier.getStart().getRow() - 2;\r\n if (!(rows[previousRow].trim().substring(0, 2) === \"\\\"!\")) {\r\n const message = \"Missing ABAP Doc for method \" + method.identifier.getToken().getStr();\r\n const issue = issue_1.Issue.atIdentifier(method.identifier, message, this.getMetadata().key, this.conf.severity);\r\n issues.push(issue);\r\n }\r\n }\r\n return issues;\r\n }\r\n}\r\nexports.Abapdoc = Abapdoc;\r\n//# sourceMappingURL=abapdoc.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/rules/abapdoc.js?");
|
|
11537
11537
|
|
|
11538
11538
|
/***/ }),
|
|
11539
11539
|
|
|
@@ -11940,7 +11940,7 @@ eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\n
|
|
|
11940
11940
|
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
|
|
11941
11941
|
|
|
11942
11942
|
"use strict";
|
|
11943
|
-
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.Downport = exports.DownportConf = void 0;\r\n/* eslint-disable max-len */\r\nconst Statements = __webpack_require__(/*! ../abap/2_statements/statements */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js\");\r\nconst Expressions = __webpack_require__(/*! ../abap/2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst Structures = __webpack_require__(/*! ../abap/3_structures/structures */ \"./node_modules/@abaplint/core/build/src/abap/3_structures/structures/index.js\");\r\nconst _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ \"./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js\");\r\nconst issue_1 = __webpack_require__(/*! ../issue */ \"./node_modules/@abaplint/core/build/src/issue.js\");\r\nconst _irule_1 = __webpack_require__(/*! ./_irule */ \"./node_modules/@abaplint/core/build/src/rules/_irule.js\");\r\nconst _statement_1 = __webpack_require__(/*! ../abap/2_statements/statements/_statement */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/statements/_statement.js\");\r\nconst nodes_1 = __webpack_require__(/*! ../abap/nodes */ \"./node_modules/@abaplint/core/build/src/abap/nodes/index.js\");\r\nconst edit_helper_1 = __webpack_require__(/*! ../edit_helper */ \"./node_modules/@abaplint/core/build/src/edit_helper.js\");\r\nconst position_1 = __webpack_require__(/*! ../position */ \"./node_modules/@abaplint/core/build/src/position.js\");\r\nconst _abap_object_1 = __webpack_require__(/*! ../objects/_abap_object */ \"./node_modules/@abaplint/core/build/src/objects/_abap_object.js\");\r\nconst version_1 = __webpack_require__(/*! ../version */ \"./node_modules/@abaplint/core/build/src/version.js\");\r\nconst registry_1 = __webpack_require__(/*! ../registry */ \"./node_modules/@abaplint/core/build/src/registry.js\");\r\nconst syntax_1 = __webpack_require__(/*! ../abap/5_syntax/syntax */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/syntax.js\");\r\nconst _reference_1 = __webpack_require__(/*! ../abap/5_syntax/_reference */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js\");\r\nconst _typed_identifier_1 = __webpack_require__(/*! ../abap/types/_typed_identifier */ \"./node_modules/@abaplint/core/build/src/abap/types/_typed_identifier.js\");\r\nconst basic_1 = __webpack_require__(/*! ../abap/types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst config_1 = __webpack_require__(/*! ../config */ \"./node_modules/@abaplint/core/build/src/config.js\");\r\nconst tokens_1 = __webpack_require__(/*! ../abap/1_lexer/tokens */ \"./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/index.js\");\r\nconst include_graph_1 = __webpack_require__(/*! ../utils/include_graph */ \"./node_modules/@abaplint/core/build/src/utils/include_graph.js\");\r\nconst objects_1 = __webpack_require__(/*! ../objects */ \"./node_modules/@abaplint/core/build/src/objects/index.js\");\r\nconst _builtin_1 = __webpack_require__(/*! ../abap/5_syntax/_builtin */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js\");\r\n// todo: refactor each sub-rule to new classes?\r\n// todo: add configuration\r\nclass DownportConf extends _basic_rule_config_1.BasicRuleConfig {\r\n}\r\nexports.DownportConf = DownportConf;\r\nclass Downport {\r\n constructor() {\r\n this.conf = new DownportConf();\r\n }\r\n getMetadata() {\r\n return {\r\n key: \"downport\",\r\n title: \"Downport statement\",\r\n shortDescription: `Experimental downport functionality`,\r\n extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with\r\na higher level language version. If successful, various rules are applied to downport the statement.\r\nTarget downport version is always v702, thus rule is only enabled if target version is v702.\r\n\r\nCurrent rules:\r\n* NEW transformed to CREATE OBJECT, opposite of https://rules.abaplint.org/use_new/\r\n* DATA() definitions are outlined, opposite of https://rules.abaplint.org/prefer_inline/\r\n* FIELD-SYMBOL() definitions are outlined\r\n* CONV is outlined\r\n* COND is outlined\r\n* REDUCE is outlined\r\n* SWITCH is outlined\r\n* APPEND expression is outlined\r\n* INSERT expression is outlined\r\n* EMPTY KEY is changed to DEFAULT KEY, opposite of DEFAULT KEY in https://rules.abaplint.org/avoid_use/\r\n* CAST changed to ?=\r\n* LOOP AT method_call( ) is outlined\r\n* VALUE # with structure fields\r\n* VALUE # with internal table lines\r\n* Table Expressions are outlined\r\n* SELECT INTO @DATA definitions are outlined\r\n* Some occurrences of string template formatting option ALPHA changed to function module call\r\n* SELECT/INSERT/MODIFY/DELETE/UPDATE \",\" in field list removed, \"@\" in source/targets removed\r\n* PARTIALLY IMPLEMENTED removed, it can be quick fixed via rule implement_methods\r\n* RAISE EXCEPTION ... MESSAGE\r\n* Moving with +=, -=, /=, *=, &&= is expanded\r\n* line_exists and line_index is downported to READ TABLE\r\n* ENUMs, but does not nessesarily give the correct type and value\r\n* MESSAGE with non simple source\r\n\r\nOnly one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,\r\n tags: [_irule_1.RuleTag.Experimental, _irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],\r\n };\r\n }\r\n getConfig() {\r\n return this.conf;\r\n }\r\n setConfig(conf) {\r\n this.conf = conf;\r\n }\r\n initialize(reg) {\r\n this.lowReg = reg;\r\n const version = this.lowReg.getConfig().getVersion();\r\n if (version === version_1.Version.v702 || version === version_1.Version.OpenABAP) {\r\n this.initHighReg();\r\n }\r\n return this;\r\n }\r\n listMainForInclude(filename) {\r\n if (filename === undefined) {\r\n return [];\r\n }\r\n // only initialize this.graph if needed\r\n if (this.graph === undefined) {\r\n this.graph = new include_graph_1.IncludeGraph(this.lowReg);\r\n }\r\n return this.graph.listMainForInclude(filename);\r\n }\r\n run(lowObj) {\r\n var _a;\r\n const ret = [];\r\n this.counter = 1;\r\n const version = this.lowReg.getConfig().getVersion();\r\n if (version !== version_1.Version.v702 && version !== version_1.Version.OpenABAP) {\r\n return ret;\r\n }\r\n else if (!(lowObj instanceof _abap_object_1.ABAPObject)) {\r\n return ret;\r\n }\r\n const highObj = this.highReg.getObject(lowObj.getType(), lowObj.getName());\r\n if (highObj === undefined || !(highObj instanceof _abap_object_1.ABAPObject)) {\r\n return ret;\r\n }\r\n let highSyntaxObj = highObj;\r\n // for includes do the syntax check via a main program\r\n if (lowObj instanceof objects_1.Program && lowObj.isInclude()) {\r\n const mains = this.listMainForInclude((_a = lowObj.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getFilename());\r\n if (mains.length <= 0) {\r\n return [];\r\n }\r\n const f = this.highReg.getFileByName(mains[0]);\r\n if (f === undefined) {\r\n return [];\r\n }\r\n highSyntaxObj = this.highReg.findObjectForFile(f);\r\n }\r\n for (const lowFile of lowObj.getABAPFiles()) {\r\n let highSyntax = undefined;\r\n const highFile = highObj.getABAPFileByName(lowFile.getFilename());\r\n if (highFile === undefined) {\r\n continue;\r\n }\r\n const lowStatements = lowFile.getStatements();\r\n const highStatements = highFile.getStatements();\r\n if (lowStatements.length !== highStatements.length) {\r\n // after applying a fix, there might be more statements in lowFile\r\n // should highReg be initialized again?\r\n /*\r\n const message = \"Internal Error: Statement lengths does not match\";\r\n ret.push(Issue.atStatement(lowFile, lowStatements[0], message, this.getMetadata().key));\r\n */\r\n // hmm, add some way to disable lazyUnknown() in statement_parser.ts\r\n continue;\r\n }\r\n for (let i = 0; i < lowStatements.length; i++) {\r\n const low = lowStatements[i];\r\n const high = highStatements[i];\r\n if ((low.get() instanceof _statement_1.Unknown && !(high.get() instanceof _statement_1.Unknown))\r\n || high.findFirstExpression(Expressions.InlineData)) {\r\n if (highSyntax === undefined) {\r\n highSyntax = new syntax_1.SyntaxLogic(this.highReg, highSyntaxObj).run();\r\n }\r\n const issue = this.checkStatement(low, high, lowFile, highSyntax, highFile);\r\n if (issue) {\r\n ret.push(issue);\r\n }\r\n }\r\n }\r\n }\r\n return ret;\r\n }\r\n ////////////////////\r\n /** clones the orginal repository into highReg, and parses it with higher language version */\r\n initHighReg() {\r\n // use default configuration, ie. default target version\r\n const highConfig = config_1.Config.getDefault().get();\r\n const lowConfig = this.lowReg.getConfig().get();\r\n highConfig.syntax.errorNamespace = lowConfig.syntax.errorNamespace;\r\n highConfig.syntax.globalConstants = lowConfig.syntax.globalConstants;\r\n highConfig.syntax.globalMacros = lowConfig.syntax.globalMacros;\r\n this.highReg = new registry_1.Registry();\r\n for (const o of this.lowReg.getObjects()) {\r\n for (const f of o.getFiles()) {\r\n if (this.lowReg.isDependency(o) === true) {\r\n this.highReg.addDependency(f);\r\n }\r\n else {\r\n this.highReg.addFile(f);\r\n }\r\n }\r\n }\r\n this.highReg.parse();\r\n }\r\n /** applies one rule at a time, multiple iterations are required to transform complex statements */\r\n checkStatement(low, high, lowFile, highSyntax, highFile) {\r\n if (low.getFirstToken().getStart() instanceof position_1.VirtualPosition) {\r\n return undefined;\r\n }\r\n let found = this.downportEnum(low, high, lowFile, highSyntax, highFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.partiallyImplemented(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.raiseException(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.emptyKey(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.stringTemplateAlpha(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.moveWithOperator(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.moveWithSimpleValue(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.assignWithTable(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportRefSimple(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportCorrespondingSimple(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportRef(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportLoopGroup(high, lowFile, highSyntax, highFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.callFunctionParameterSimple(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.moveWithTableTarget(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportSelectInline(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportSQLExtras(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineLoopInput(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineLoopTarget(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n let skipValue = false;\r\n let skipReduce = false;\r\n const valueBody = high.findFirstExpression(Expressions.ValueBody);\r\n const reduceBody = high.findFirstExpression(Expressions.ReduceBody);\r\n if (valueBody && reduceBody) {\r\n const valueToken = valueBody.getFirstToken();\r\n const reduceToken = reduceBody.getFirstToken();\r\n if (valueToken.getStart().isBefore(reduceToken.getStart())) {\r\n skipReduce = true;\r\n }\r\n else {\r\n skipValue = true;\r\n }\r\n }\r\n if (skipValue !== true) {\r\n found = this.outlineValue(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n }\r\n if (skipReduce !== true) {\r\n found = this.outlineReduce(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n }\r\n found = this.outlineSwitch(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineCast(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineConv(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineCond(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineCatchSimple(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineDataSimple(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineData(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineFS(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.newToCreateObject(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceXsdBool(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceLineFunctions(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.getReference(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceContains(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceMethodConditional(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceTableExpression(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceAppendExpression(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceInsertExpression(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportMessage(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n return undefined;\r\n }\r\n //////////////////////////////////////////\r\n downportSQLExtras(low, high, lowFile, _highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Select)\r\n && !(high.get() instanceof Statements.SelectLoop)\r\n && !(high.get() instanceof Statements.UpdateDatabase)\r\n && !(high.get() instanceof Statements.ModifyDatabase)\r\n && !(high.get() instanceof Statements.DeleteDatabase)\r\n && !(high.get() instanceof Statements.InsertDatabase)) {\r\n return undefined;\r\n }\r\n let fix = undefined;\r\n const addFix = (token) => {\r\n const add = edit_helper_1.EditHelper.deleteToken(lowFile, token);\r\n if (fix === undefined) {\r\n fix = add;\r\n }\r\n else {\r\n fix = edit_helper_1.EditHelper.merge(fix, add);\r\n }\r\n };\r\n const candidates = [high.findAllExpressionsRecursive(Expressions.SQLTarget),\r\n high.findAllExpressionsRecursive(Expressions.SQLSource),\r\n high.findAllExpressionsRecursive(Expressions.SQLSourceSimple)].flat();\r\n for (const c of candidates.reverse()) {\r\n if (c.getFirstToken() instanceof tokens_1.WAt\r\n || c.getFirstToken() instanceof tokens_1.At) {\r\n addFix(c.getFirstToken());\r\n }\r\n }\r\n for (const fieldList of high.findAllExpressionsMulti([Expressions.SQLFieldList, Expressions.SQLFieldListLoop], true)) {\r\n for (const token of fieldList.getDirectTokens()) {\r\n if (token.getStr() === \",\") {\r\n addFix(token);\r\n }\r\n }\r\n }\r\n if (fix !== undefined) {\r\n return issue_1.Issue.atToken(lowFile, low.getFirstToken(), \"SQL, remove @ and ,\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n for (const c of high.findAllExpressionsRecursive(Expressions.SQLIn)) {\r\n const children = c.getChildren();\r\n const first = children[1];\r\n if (!(first.get() instanceof tokens_1.WParenLeftW)) {\r\n continue;\r\n }\r\n const last = children[children.length - 1];\r\n if (last.get() instanceof tokens_1.WParenRightW || last.get() instanceof tokens_1.WParenRight) {\r\n const firstEnd = first.getFirstToken().getEnd();\r\n const endDelete = new position_1.Position(firstEnd.getRow(), firstEnd.getCol() + 1);\r\n const fix1 = edit_helper_1.EditHelper.deleteRange(lowFile, firstEnd, endDelete);\r\n const lastStart = last.getFirstToken().getStart();\r\n const startDelete = new position_1.Position(lastStart.getRow(), lastStart.getCol() - 1);\r\n const fix2 = edit_helper_1.EditHelper.deleteRange(lowFile, startDelete, lastStart);\r\n fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, low.getFirstToken(), \"SQL, remove spaces\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n downportSelectInline(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Select) && !(high.get() instanceof Statements.SelectLoop)) {\r\n return undefined;\r\n }\r\n // as first step outline the @DATA, note that void types are okay, as long the field names are specified\r\n let found = this.downportSelectSingleInline(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportSelectTableInline(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n return undefined;\r\n }\r\n downportSelectSingleInline(low, high, lowFile, _highSyntax) {\r\n var _a, _b, _c, _d;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const targets = ((_a = high.findFirstExpression(Expressions.SQLIntoStructure)) === null || _a === void 0 ? void 0 : _a.findDirectExpressions(Expressions.SQLTarget)) || [];\r\n if (targets.length !== 1) {\r\n return undefined;\r\n }\r\n const inlineData = targets[0].findFirstExpression(Expressions.InlineData);\r\n if (inlineData === undefined) {\r\n return undefined;\r\n }\r\n const sqlFrom = high.findAllExpressions(Expressions.SQLFromSource);\r\n if (sqlFrom.length !== 1) {\r\n return undefined;\r\n }\r\n const tableName = (_b = sqlFrom[0].findDirectExpression(Expressions.DatabaseTable)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (tableName === undefined) {\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let fieldList = high.findFirstExpression(Expressions.SQLFieldList);\r\n if (fieldList === undefined) {\r\n fieldList = high.findFirstExpression(Expressions.SQLFieldListLoop);\r\n }\r\n if (fieldList === undefined) {\r\n return undefined;\r\n }\r\n let fieldDefinition = \"\";\r\n const fields = fieldList.findAllExpressions(Expressions.SQLFieldName);\r\n const name = ((_c = inlineData.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"error\";\r\n if (fields.length === 1) {\r\n fieldDefinition = `DATA ${name} TYPE ${tableName}-${fields[0].concatTokens()}.`;\r\n }\r\n else if (fieldList.concatTokens() === \"*\") {\r\n fieldDefinition = `DATA ${name} TYPE ${tableName}.`;\r\n }\r\n else if (fieldList.concatTokens().toUpperCase() === \"COUNT( * )\") {\r\n fieldDefinition = `DATA ${name} TYPE i.`;\r\n }\r\n else if (fieldList.getChildren().length === 1 && fieldList.getChildren()[0].get() instanceof Expressions.SQLAggregation) {\r\n const c = fieldList.getChildren()[0];\r\n if (c instanceof nodes_1.ExpressionNode) {\r\n const concat = (_d = c.findFirstExpression(Expressions.SQLArithmetics)) === null || _d === void 0 ? void 0 : _d.concatTokens();\r\n fieldDefinition = `DATA ${name} TYPE ${tableName}-${concat}.`;\r\n }\r\n }\r\n else {\r\n for (const f of fields) {\r\n const fieldName = f.concatTokens();\r\n fieldDefinition += indentation + \" \" + fieldName + \" TYPE \" + tableName + \"-\" + fieldName + \",\\n\";\r\n }\r\n fieldDefinition = `DATA: BEGIN OF ${name},\r\n${fieldDefinition}${indentation} END OF ${name}.`;\r\n }\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `${fieldDefinition}\r\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, inlineData.getFirstToken(), \"Outline SELECT @DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportSelectTableInline(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const targets = ((_a = high.findFirstExpression(Expressions.SQLIntoTable)) === null || _a === void 0 ? void 0 : _a.findDirectExpressions(Expressions.SQLTarget)) || [];\r\n if (targets.length !== 1) {\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const inlineData = targets[0].findFirstExpression(Expressions.InlineData);\r\n if (inlineData === undefined) {\r\n return undefined;\r\n }\r\n const sqlFrom = high.findAllExpressions(Expressions.SQLFromSource);\r\n if (sqlFrom.length === 0) {\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Error outlining, sqlFrom not found\", this.getMetadata().key, this.conf.severity);\r\n }\r\n let tableName = (_b = sqlFrom[0].findDirectExpression(Expressions.DatabaseTable)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (tableName === undefined) {\r\n return undefined;\r\n }\r\n const fieldList = high.findFirstExpression(Expressions.SQLFieldList);\r\n if (fieldList === undefined) {\r\n return undefined;\r\n }\r\n let fieldDefinitions = \"\";\r\n for (const f of fieldList.findAllExpressions(Expressions.SQLFieldName)) {\r\n let fieldName = f.concatTokens();\r\n if (fieldName.includes(\"~\")) {\r\n const split = fieldName.split(\"~\");\r\n tableName = split[0];\r\n fieldName = split[1];\r\n }\r\n fieldDefinitions += indentation + \" \" + fieldName + \" TYPE \" + tableName + \"-\" + fieldName + \",\\n\";\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const name = ((_c = inlineData.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"error\";\r\n let fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `TYPES: BEGIN OF ${uniqueName},\r\n${fieldDefinitions}${indentation} END OF ${uniqueName}.\r\n${indentation}DATA ${name} TYPE STANDARD TABLE OF ${uniqueName} WITH DEFAULT KEY.\r\n${indentation}`);\r\n if (fieldDefinitions === \"\") {\r\n fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `DATA ${name} TYPE STANDARD TABLE OF ${tableName} WITH DEFAULT KEY.\r\n${indentation}`);\r\n }\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, inlineData.getFirstToken(), \"Outline SELECT @DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportMessage(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.Message)) {\r\n return undefined;\r\n }\r\n const foundWith = high.findExpressionAfterToken(\"WITH\");\r\n if (foundWith === undefined) {\r\n return undefined;\r\n }\r\n const likeSource = high.findExpressionAfterToken(\"LIKE\");\r\n for (const s of high.findAllExpressions(Expressions.Source)) {\r\n if (s === likeSource) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n const code = `DATA(${uniqueName}) = ${s.concatTokens()}.\\n${indentation}`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, s.getFirstToken().getStart(), s.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Refactor MESSAGE WITH source\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n replaceAppendExpression(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.Append)) {\r\n return undefined;\r\n }\r\n const children = high.getChildren();\r\n if (children[1].get() instanceof Expressions.Source) {\r\n const source = children[1];\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${target === null || target === void 0 ? void 0 : target.concatTokens()}.\r\n${indentation}${uniqueName} = ${source.concatTokens()}.\\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, source.getFirstToken().getStart(), source.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline APPEND source expression\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n replaceInsertExpression(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.InsertInternal)) {\r\n return undefined;\r\n }\r\n const children = high.getChildren();\r\n if (children[1].get() instanceof Expressions.Source) {\r\n const source = children[1];\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${target === null || target === void 0 ? void 0 : target.concatTokens()}.\r\n${indentation}${uniqueName} = ${source.concatTokens()}.\\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, source.getFirstToken().getStart(), source.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline INSERT source expression\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n replaceTableExpression(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const fieldChain of high.findAllExpressionsRecursive(Expressions.FieldChain)) {\r\n const tableExpression = fieldChain.findDirectExpression(Expressions.TableExpression);\r\n if (tableExpression === undefined) {\r\n continue;\r\n }\r\n const concat = high.concatTokens().toUpperCase();\r\n if (concat.includes(\" LINE_EXISTS( \") || concat.includes(\" LINE_INDEX( \")) {\r\n // note: line_exists() must be replaced before handling table expressions\r\n continue;\r\n }\r\n let pre = \"\";\r\n let startToken = undefined;\r\n for (const child of fieldChain.getChildren()) {\r\n if (startToken === undefined) {\r\n startToken = child.getFirstToken();\r\n }\r\n else if (child === tableExpression) {\r\n break;\r\n }\r\n pre += child.concatTokens();\r\n }\r\n if (startToken === undefined) {\r\n continue;\r\n }\r\n const condition = this.tableCondition(tableExpression);\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n // note that the tabix restore should be done before throwing the exception\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.\r\n${indentation}DATA ${tabixBackup} LIKE sy-tabix.\r\n${indentation}${tabixBackup} = sy-tabix.\r\n${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.\r\n${indentation}sy-tabix = ${tabixBackup}.\r\n${indentation}IF sy-subrc <> 0.\r\n${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.\r\n${indentation}ENDIF.\r\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, startToken.getStart(), tableExpression.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline table expression\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n tableCondition(tableExpression) {\r\n let condition = \"\";\r\n let keyName = \"\";\r\n for (const c of tableExpression.getChildren() || []) {\r\n if (c.getFirstToken().getStr() === \"[\" || c.getFirstToken().getStr() === \"]\") {\r\n continue;\r\n }\r\n else if (c.get() instanceof Expressions.ComponentChainSimple && condition === \"\") {\r\n if (keyName === \"\") {\r\n condition = \"WITH KEY \";\r\n }\r\n else {\r\n condition = \"WITH TABLE KEY \" + keyName + \" COMPONENTS \";\r\n }\r\n }\r\n else if (c.get() instanceof Expressions.Source && condition === \"\") {\r\n condition = \"INDEX \";\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.getFirstToken().getStr().toUpperCase() === \"KEY\") {\r\n continue;\r\n }\r\n else if (c.get() instanceof Expressions.SimpleName) {\r\n keyName = c.concatTokens();\r\n continue;\r\n }\r\n condition += c.concatTokens() + \" \";\r\n }\r\n return condition;\r\n }\r\n outlineCatchSimple(node, lowFile) {\r\n // outlines \"CATCH cx_bcs INTO DATA(lx_bcs_excep).\", note that this does not need to look at types\r\n var _a, _b;\r\n if (!(node.get() instanceof Statements.Catch)) {\r\n return undefined;\r\n }\r\n const target = node.findFirstExpression(Expressions.Target);\r\n if (!(((_a = target === null || target === void 0 ? void 0 : target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.InlineData)) {\r\n return undefined;\r\n }\r\n const classNames = node.findDirectExpressions(Expressions.ClassName);\r\n if (classNames.length !== 1) {\r\n return undefined;\r\n }\r\n const className = classNames[0].concatTokens();\r\n const targetName = (_b = target.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const code = ` DATA ${targetName} TYPE REF TO ${className}.\r\n${indentation}CATCH ${className} INTO ${targetName}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), code);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n outlineDataSimple(node, lowFile) {\r\n // outlines \"DATA(ls_msg) = temp1.\", note that this does not need to look at types\r\n var _a, _b, _c;\r\n if (!(node.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const target = node.findFirstExpression(Expressions.Target);\r\n if (!(((_a = target === null || target === void 0 ? void 0 : target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.InlineData)) {\r\n return undefined;\r\n }\r\n let type = \"\";\r\n const source = node.findFirstExpression(Expressions.Source);\r\n if (source === undefined) {\r\n return undefined;\r\n }\r\n else if (source.getChildren().length !== 1) {\r\n return undefined;\r\n }\r\n else if (!(((_b = source.getFirstChild()) === null || _b === void 0 ? void 0 : _b.get()) instanceof Expressions.FieldChain)) {\r\n return undefined;\r\n }\r\n else if (source.findFirstExpression(Expressions.FieldOffset)) {\r\n return undefined;\r\n }\r\n else if (source.findFirstExpression(Expressions.FieldLength)) {\r\n return undefined;\r\n }\r\n else if (source.findFirstExpression(Expressions.TableExpression)) {\r\n const chain = source.findDirectExpression(Expressions.FieldChain);\r\n if (chain !== undefined\r\n && chain.getChildren().length === 2\r\n && chain.getChildren()[0].get() instanceof Expressions.SourceField\r\n && chain.getChildren()[1].get() instanceof Expressions.TableExpression) {\r\n type = \"LINE OF \" + chain.getChildren()[0].concatTokens();\r\n }\r\n else {\r\n return undefined;\r\n }\r\n }\r\n else {\r\n type = source.concatTokens();\r\n }\r\n const targetName = (_c = target.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = node.getFirstToken();\r\n const lastToken = node.getLastToken();\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${targetName} LIKE ${type}.\\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), lastToken.getEnd(), `${targetName} = ${source.concatTokens()}.`);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n partiallyImplemented(node, lowFile) {\r\n if (node.get() instanceof Statements.InterfaceDef) {\r\n const partially = node.findDirectTokenByText(\"PARTIALLY\");\r\n if (partially === undefined) {\r\n return undefined;\r\n }\r\n const implemented = node.findDirectTokenByText(\"IMPLEMENTED\");\r\n if (implemented === undefined) {\r\n return undefined;\r\n }\r\n const fix = edit_helper_1.EditHelper.deleteRange(lowFile, partially.getStart(), implemented.getEnd());\r\n return issue_1.Issue.atToken(lowFile, partially, \"Downport PARTIALLY IMPLEMENTED\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n raiseException(node, lowFile, highSyntax) {\r\n /*\r\n Note: IF_T100_DYN_MSG does not exist in 702, so this rule is mostly relevant for the transpiler\r\n \r\n DATA foo LIKE if_t100_message=>t100key.\r\n foo-msgid = 'ZHVAM'.\r\n foo-msgno = '001'.\r\n foo-attr1 = 'IF_T100_DYN_MSG~MSGV1'.\r\n foo-attr2 = 'IF_T100_DYN_MSG~MSGV2'.\r\n foo-attr3 = 'IF_T100_DYN_MSG~MSGV3'.\r\n foo-attr4 = 'IF_T100_DYN_MSG~MSGV4'.\r\n DATA bar TYPE REF TO zcl_hvam_exception.\r\n CREATE OBJECT bar EXPORTING textid = foo.\r\n bar->if_t100_dyn_msg~msgty = 'E'.\r\n bar->if_t100_dyn_msg~msgv1 = 'abc'.\r\n bar->if_t100_dyn_msg~msgv2 = 'abc'.\r\n bar->if_t100_dyn_msg~msgv3 = 'abc'.\r\n bar->if_t100_dyn_msg~msgv4 = 'abc'.\r\n RAISE EXCEPTION bar.\r\n */\r\n var _a, _b, _c;\r\n if (!(node.get() instanceof Statements.Raise)) {\r\n return undefined;\r\n }\r\n let id = undefined;\r\n let number = undefined;\r\n let startToken = node.findDirectTokenByText(\"ID\");\r\n if (startToken) {\r\n const sources = node.findDirectExpressions(Expressions.Source);\r\n id = sources[0].concatTokens();\r\n const numberExpression = node.findExpressionAfterToken(\"NUMBER\");\r\n if (numberExpression === undefined) {\r\n throw \"downport raiseException, could not find number\";\r\n }\r\n number = numberExpression.concatTokens();\r\n if (numberExpression.get() instanceof Expressions.MessageNumber) {\r\n number = \"'\" + number + \"'\";\r\n }\r\n }\r\n else {\r\n const s = node.findDirectExpression(Expressions.MessageSource);\r\n if (s === undefined) {\r\n return undefined;\r\n }\r\n id = \"'\" + ((_a = s.findDirectExpression(Expressions.MessageClass)) === null || _a === void 0 ? void 0 : _a.concatTokens()) + \"'\";\r\n number = \"'\" + ((_b = s.findDirectExpression(Expressions.MessageTypeAndNumber)) === null || _b === void 0 ? void 0 : _b.concatTokens().substring(1)) + \"'\";\r\n startToken = node.getFirstToken();\r\n }\r\n const className = ((_c = node.findDirectExpression(Expressions.ClassName)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"ERROR\";\r\n const uniqueName1 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const uniqueName2 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const abap = `DATA ${uniqueName1} LIKE if_t100_message=>t100key.\r\n${indentation}${uniqueName1}-msgid = ${id === null || id === void 0 ? void 0 : id.toUpperCase()}.\r\n${indentation}${uniqueName1}-msgno = ${number}.\r\n${indentation}DATA ${uniqueName2} TYPE REF TO ${className}.\r\n${indentation}CREATE OBJECT ${uniqueName2} EXPORTING textid = ${uniqueName1}.\r\n${indentation}RAISE EXCEPTION ${uniqueName2}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), abap);\r\n return issue_1.Issue.atToken(lowFile, startToken, \"Downport RAISE MESSAGE\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n emptyKey(low, node, lowFile) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (let i of node.findAllExpressions(Expressions.TypeTable)) {\r\n const key = i.findDirectExpression(Expressions.TypeTableKey);\r\n if (key === undefined) {\r\n continue;\r\n }\r\n i = key;\r\n const concat = i.concatTokens();\r\n if (concat.toUpperCase().includes(\"WITH EMPTY KEY\") === false) {\r\n continue;\r\n }\r\n const token = i.findDirectTokenByText(\"EMPTY\");\r\n if (token === undefined) {\r\n continue;\r\n }\r\n const fix = edit_helper_1.EditHelper.replaceToken(lowFile, token, \"DEFAULT\");\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport EMPTY KEY\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n callFunctionParameterSimple(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.CallFunction)) {\r\n return undefined;\r\n }\r\n let found = undefined;\r\n for (const p of high.findAllExpressions(Expressions.FunctionExportingParameter)) {\r\n found = p.findDirectExpression(Expressions.Source);\r\n if (found && (found.findDirectExpression(Expressions.FieldChain)\r\n || found.findDirectExpression(Expressions.Constant)\r\n || found.findDirectExpression(Expressions.TextElement))) {\r\n // its actually simple, ok\r\n found = undefined;\r\n }\r\n else if (found !== undefined) {\r\n break;\r\n }\r\n }\r\n if (found === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const code = `DATA(${uniqueName}) = ${found.concatTokens()}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, found.getFirstToken().getStart(), found.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, call function parameter\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportCorrespondingSimple(high, lowFile) {\r\n var _a;\r\n if (!(high.get() instanceof Statements.Move)\r\n || high.getChildren().length !== 4\r\n || high.getChildren()[2].getFirstToken().getStr().toUpperCase() !== \"CORRESPONDING\") {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n console.dir(\"sdf1\");\r\n return undefined;\r\n }\r\n const sourceRef = (_a = high.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.findFirstExpression(Expressions.CorrespondingBody);\r\n if (sourceRef === undefined || sourceRef.getChildren().length !== 1) {\r\n return;\r\n }\r\n const code = `MOVE-CORRESPONDING ${sourceRef.concatTokens()} TO ${target.concatTokens()}`;\r\n const start = high.getFirstToken().getStart();\r\n const end = high.getLastToken().getStart();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, simple CORRESPONDING move\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportRefSimple(high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(high.get() instanceof Statements.Move)\r\n || high.getChildren().length !== 4\r\n || high.getChildren()[2].getFirstToken().getStr().toUpperCase() !== \"REF\") {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const sourceRef = (_a = high.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Source);\r\n if (sourceRef === undefined\r\n || sourceRef.getChildren().length !== 1) {\r\n return undefined;\r\n }\r\n let code = \"\";\r\n if (sourceRef.findFirstExpression(Expressions.TableExpression)) {\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n code = `ASSIGN ${sourceRef.concatTokens()} TO FIELD-SYMBOL(<${uniqueName}>).\r\nGET REFERENCE OF <${uniqueName}> INTO ${target.concatTokens()}`;\r\n }\r\n else {\r\n code = `GET REFERENCE OF ${sourceRef.concatTokens()} INTO ${target.concatTokens()}`;\r\n }\r\n const start = high.getFirstToken().getStart();\r\n const end = high.getLastToken().getStart();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, simple REF move\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportLoopGroup(high, lowFile, highSyntax, highFile) {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;\r\n if (!(high.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n const group = high.findDirectExpression(Expressions.LoopGroupBy);\r\n if (group === undefined) {\r\n return undefined;\r\n }\r\n const groupTargetName = ((_a = group.findFirstExpression(Expressions.TargetField)) === null || _a === void 0 ? void 0 : _a.concatTokens())\r\n || ((_b = group.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _b === void 0 ? void 0 : _b.concatTokens().replace(\"<\", \"_\").replace(\">\", \"_\"))\r\n || \"nameNotFound\";\r\n const loopSourceName = ((_c = high.findFirstExpression(Expressions.SimpleSource2)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"nameNotFound\";\r\n const loopTargetName = ((_d = high.findFirstExpression(Expressions.TargetField)) === null || _d === void 0 ? void 0 : _d.concatTokens())\r\n || ((_e = high.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _e === void 0 ? void 0 : _e.concatTokens())\r\n || \"nameNotFound\";\r\n const groupTarget = ((_f = group.findDirectExpression(Expressions.LoopGroupByTarget)) === null || _f === void 0 ? void 0 : _f.concatTokens()) || \"\";\r\n const isReference = (_g = high.findFirstExpression(Expressions.LoopTarget)) === null || _g === void 0 ? void 0 : _g.concatTokens().toUpperCase().startsWith(\"REFERENCE INTO \");\r\n let loopSourceRowType = \"typeNotFound\";\r\n const spag = highSyntax.spaghetti.lookupPosition(high.getFirstToken().getStart(), lowFile.getFilename());\r\n if (spag !== undefined) {\r\n const found = spag.findVariable(loopSourceName);\r\n const tt = found === null || found === void 0 ? void 0 : found.getType();\r\n if (tt instanceof basic_1.TableType) {\r\n loopSourceRowType = tt.getRowType().getQualifiedName() || \"typeNotFound\";\r\n }\r\n }\r\n let code = `TYPES: BEGIN OF ${groupTargetName}type,\\n`;\r\n let condition = \"\";\r\n let groupCountName = undefined;\r\n let groupIndexName = undefined;\r\n for (const c of group.findAllExpressions(Expressions.LoopGroupByComponent)) {\r\n const name = c.findFirstExpression(Expressions.ComponentName);\r\n let type = ((_h = c.findFirstExpression(Expressions.Source)) === null || _h === void 0 ? void 0 : _h.concatTokens()) || \"todo\";\r\n if ((_j = c.concatTokens()) === null || _j === void 0 ? void 0 : _j.toUpperCase().endsWith(\" = GROUP SIZE\")) {\r\n type = \"i\";\r\n groupCountName = name === null || name === void 0 ? void 0 : name.concatTokens();\r\n }\r\n else if ((_k = c.concatTokens()) === null || _k === void 0 ? void 0 : _k.toUpperCase().endsWith(\" = GROUP INDEX\")) {\r\n type = \"i\";\r\n groupIndexName = name === null || name === void 0 ? void 0 : name.concatTokens();\r\n }\r\n else {\r\n condition += c.concatTokens();\r\n type = type.replace(loopTargetName, loopSourceRowType);\r\n type = type.replace(\"->\", \"-\");\r\n }\r\n code += ` ${name === null || name === void 0 ? void 0 : name.concatTokens()} TYPE ${type},\\n`;\r\n }\r\n const s = group.findDirectExpression(Expressions.Source);\r\n let singleName = \"\";\r\n if (s) {\r\n let type = s.concatTokens();\r\n type = type.replace(loopTargetName, loopSourceRowType);\r\n type = type.replace(\"->\", \"-\");\r\n singleName = s.concatTokens().split(\"-\")[1];\r\n code += ` ${singleName} TYPE ${type},\\n`;\r\n condition = singleName + \" = \" + s.concatTokens();\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const uniqueFS = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const uniqueNameIndex = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n code += ` items LIKE ${loopSourceName},\r\n END OF ${groupTargetName}type.\r\nDATA ${groupTargetName}tab TYPE STANDARD TABLE OF ${groupTargetName}type WITH DEFAULT KEY.\r\nDATA ${uniqueName} LIKE LINE OF ${groupTargetName}tab.\r\nLOOP AT ${loopSourceName} ${(_l = high.findFirstExpression(Expressions.LoopTarget)) === null || _l === void 0 ? void 0 : _l.concatTokens()}.\\n`;\r\n if (groupIndexName !== undefined) {\r\n code += `DATA(${uniqueNameIndex}) = sy-tabix.\\n`;\r\n }\r\n code += `READ TABLE ${groupTargetName}tab ASSIGNING FIELD-SYMBOL(<${uniqueFS}>) WITH KEY ${condition}.\r\nIF sy-subrc = 0.\\n`;\r\n if (groupCountName !== undefined) {\r\n code += ` <${uniqueFS}>-${groupCountName} = <${uniqueFS}>-${groupCountName} + 1.\\n`;\r\n }\r\n code += ` INSERT ${loopTargetName}${isReference ? \"->*\" : \"\"} INTO TABLE <${uniqueFS}>-items.\r\nELSE.\\n`;\r\n code += ` CLEAR ${uniqueName}.\\n`;\r\n for (const c of group.findAllExpressions(Expressions.LoopGroupByComponent)) {\r\n const concat = c.concatTokens();\r\n if (concat.endsWith(\" GROUP INDEX\")) {\r\n code += ` ${uniqueName}-${groupIndexName} = ${uniqueNameIndex}.\\n`;\r\n }\r\n else {\r\n code += ` ${uniqueName}-${concat.replace(\"GROUP SIZE\", \"1\")}.\\n`;\r\n }\r\n }\r\n if (singleName !== \"\") {\r\n code += ` ${uniqueName}-${singleName} = ${loopTargetName}-${singleName}.\\n`;\r\n }\r\n code += ` INSERT ${loopTargetName}${isReference ? \"->*\" : \"\"} INTO TABLE ${uniqueName}-items.\\n`;\r\n code += ` INSERT ${uniqueName} INTO TABLE ${groupTargetName}tab.\\n`;\r\n code += `ENDIF.\r\nENDLOOP.\r\nLOOP AT ${groupTargetName}tab ${groupTarget}.`;\r\n let fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), code);\r\n for (const l of ((_m = highFile.getStructure()) === null || _m === void 0 ? void 0 : _m.findAllStructures(Structures.Loop)) || []) {\r\n // make sure to find the correct/current loop statement\r\n if (l.findDirectStatement(Statements.Loop) !== high) {\r\n continue;\r\n }\r\n for (const loop of l.findAllStatements(Statements.Loop)) {\r\n if ((_o = loop.concatTokens()) === null || _o === void 0 ? void 0 : _o.toUpperCase().startsWith(\"LOOP AT GROUP \")) {\r\n const subLoopSource = loop.findFirstExpression(Expressions.SimpleSource2);\r\n if (subLoopSource === undefined) {\r\n continue;\r\n }\r\n const subLoopSourceName = (subLoopSource === null || subLoopSource === void 0 ? void 0 : subLoopSource.concatTokens()) || \"nameNotFound\";\r\n const subCode = `LOOP AT ${subLoopSourceName}${isReference ? \"->\" : \"-\"}items`;\r\n const subFix = edit_helper_1.EditHelper.replaceRange(lowFile, loop.getFirstToken().getStart(), subLoopSource.getLastToken().getEnd(), subCode);\r\n fix = edit_helper_1.EditHelper.merge(subFix, fix);\r\n }\r\n }\r\n }\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, LOOP GROUP\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportRef(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n let found = undefined;\r\n for (const s of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n if (s.getFirstToken().getStr().toUpperCase() === \"REF\"\r\n && s.findDirectExpression(Expressions.TypeNameOrInfer)) {\r\n found = s;\r\n }\r\n }\r\n if (found === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const code = `DATA(${uniqueName}) = ${found.concatTokens()}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, found.getFirstToken().getStart(), found.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, REF\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n assignWithTable(low, high, lowFile) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Assign)) {\r\n return undefined;\r\n }\r\n else if (high.getChildren().length !== 5) {\r\n return undefined;\r\n }\r\n const fieldChain = (_b = (_a = high.findDirectExpression(Expressions.AssignSource)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.findDirectExpression(Expressions.FieldChain);\r\n if ((fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren().length) !== 2) {\r\n return undefined;\r\n }\r\n const tableExpression = fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren()[1];\r\n if (!(tableExpression.get() instanceof Expressions.TableExpression)\r\n || !(tableExpression instanceof nodes_1.ExpressionNode)) {\r\n return undefined;\r\n }\r\n let condition = \"\";\r\n if (tableExpression.getChildren().length === 3) {\r\n const index = tableExpression.findDirectExpression(Expressions.Source);\r\n if (index === undefined) {\r\n return undefined;\r\n }\r\n condition = `INDEX ${index.concatTokens()}`;\r\n }\r\n else {\r\n let concat = tableExpression.concatTokens();\r\n concat = concat.substring(2);\r\n concat = concat.substring(0, concat.length - 2);\r\n condition = `WITH KEY ${concat}`;\r\n }\r\n const fsTarget = high.findDirectExpression(Expressions.FSTarget);\r\n const code = `READ TABLE ${fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren()[0].concatTokens()} ${condition} ASSIGNING ${fsTarget === null || fsTarget === void 0 ? void 0 : fsTarget.concatTokens()}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, ASSIGN table expr\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n moveWithSimpleValue(low, high, lowFile) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Move)\r\n || high.getChildren().length !== 4) {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const source = high.findDirectExpression(Expressions.Source);\r\n if (source === undefined) {\r\n return undefined;\r\n }\r\n const field = target.findDirectExpression(Expressions.TargetField);\r\n if (field === undefined) {\r\n return;\r\n }\r\n const valueBody = source.findDirectExpression(Expressions.ValueBody);\r\n if (valueBody === undefined) {\r\n return;\r\n }\r\n const fieldAssignments = valueBody.findDirectExpressions(Expressions.FieldAssignment);\r\n if (fieldAssignments.length === 0) {\r\n return;\r\n }\r\n else if (fieldAssignments.length !== valueBody.getChildren().length) {\r\n return;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let code = `CLEAR ${target.concatTokens()}.\\n`;\r\n for (const fieldAssignment of fieldAssignments) {\r\n code += indentation + target.concatTokens() + \"-\" + fieldAssignment.concatTokens() + `.\\n`;\r\n }\r\n code = code.trimEnd();\r\n const start = high.getFirstToken().getStart();\r\n const end = high.getLastToken().getEnd();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, simple move\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n // note, downporting ENUM does not give the correct types, but it will work in most cases?\r\n downportEnum(_low, high, lowFile, _highSyntax, highFile) {\r\n var _a, _b, _c, _d, _e;\r\n if (!(high.get() instanceof Statements.TypeEnumBegin)) {\r\n return undefined;\r\n }\r\n const enumStructure = (_a = highFile.getStructure()) === null || _a === void 0 ? void 0 : _a.findFirstStructure(Structures.TypeEnum);\r\n if (enumStructure === undefined) {\r\n return undefined;\r\n }\r\n if (enumStructure.getFirstStatement() !== high) {\r\n return undefined;\r\n }\r\n const enumName = (_b = high.findExpressionAfterToken(\"ENUM\")) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const structureName = (_c = high.findExpressionAfterToken(\"STRUCTURE\")) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n // all ENUMS are char like?\r\n let code = `TYPES ${enumName} TYPE string.\r\nCONSTANTS: BEGIN OF ${structureName},\\n`;\r\n let count = 1;\r\n for (const e of enumStructure.findDirectStatements(Statements.TypeEnum).concat(enumStructure.findDirectStatements(Statements.Type))) {\r\n const name = (_d = e.findFirstExpression(Expressions.NamespaceSimpleName)) === null || _d === void 0 ? void 0 : _d.concatTokens();\r\n let value = (_e = e.findFirstExpression(Expressions.Value)) === null || _e === void 0 ? void 0 : _e.concatTokens();\r\n if (value === undefined) {\r\n value = \"VALUE '\" + count++ + \"'\";\r\n }\r\n code += ` ${name} TYPE ${enumName} ${value},\\n`;\r\n }\r\n code += ` END OF ${structureName}.`;\r\n const start = enumStructure.getFirstToken().getStart();\r\n const end = enumStructure.getLastToken().getEnd();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport ENUM\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n moveWithTableTarget(low, high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const tableExpression = target.findDirectExpression(Expressions.TableExpression);\r\n if (tableExpression === undefined) {\r\n return undefined;\r\n }\r\n const index = tableExpression.findDirectExpression(Expressions.Source);\r\n if (index === undefined) {\r\n return undefined;\r\n }\r\n let uniqueName = this.uniqueName(low.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n uniqueName = `<${uniqueName}>`;\r\n const tName = target.concatTokens().split(\"[\")[0];\r\n const condition = this.tableCondition(tableExpression);\r\n const tabixBackup = this.uniqueName(low.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n // restore tabix before exeption\r\n const code = `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${tName}.\r\n${indentation}DATA ${tabixBackup} LIKE sy-tabix.\r\n${indentation}${tabixBackup} = sy-tabix.\r\n${indentation}READ TABLE ${tName} ${condition}ASSIGNING ${uniqueName}.\r\n${indentation}sy-tabix = ${tabixBackup}.\r\n${indentation}IF sy-subrc <> 0.\r\n${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.\r\n${indentation}ENDIF.\r\n${indentation}${uniqueName}`;\r\n const start = target.getFirstToken().getStart();\r\n const end = (_a = tableExpression.findDirectTokenByText(\"]\")) === null || _a === void 0 ? void 0 : _a.getEnd();\r\n if (end === undefined) {\r\n return undefined;\r\n }\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, move with table target\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n moveWithOperator(low, high, lowFile) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const children = high.getChildren();\r\n const secondChild = children[1];\r\n if (secondChild === undefined) {\r\n return undefined;\r\n }\r\n const op = secondChild.getFirstToken();\r\n let operator = \"\";\r\n switch (op.getStr()) {\r\n case \"+\":\r\n operator = \" + \";\r\n break;\r\n case \"-\":\r\n operator = \" - \";\r\n break;\r\n case \"/=\":\r\n operator = \" / \";\r\n break;\r\n case \"*=\":\r\n operator = \" * \";\r\n break;\r\n case \"&&=\":\r\n operator = \" && \";\r\n break;\r\n default:\r\n return undefined;\r\n }\r\n const target = (_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n if (target === undefined) {\r\n return;\r\n }\r\n const sourceStart = (_c = (_b = high.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.getFirstChild()) === null || _c === void 0 ? void 0 : _c.getFirstToken().getStart();\r\n if (sourceStart === undefined) {\r\n return;\r\n }\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, op.getStart(), sourceStart, \"= \" + target + operator);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Expand operator\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n // must be very simple string templates, like \"|{ ls_line-no ALPHA = IN }|\"\r\n stringTemplateAlpha(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const topSource = high.findDirectExpression(Expressions.Source);\r\n if (topSource === undefined || topSource.getChildren().length !== 1) {\r\n return undefined;\r\n }\r\n let top = true;\r\n let child = topSource.getFirstChild();\r\n if (!(child.get() instanceof Expressions.StringTemplate)) {\r\n child = child.findFirstExpression(Expressions.StringTemplate);\r\n top = false;\r\n }\r\n if (child === undefined || !(child.get() instanceof Expressions.StringTemplate)) {\r\n return undefined;\r\n }\r\n const templateTokens = child.getChildren();\r\n if (templateTokens.length !== 3\r\n || templateTokens[0].getFirstToken().getStr() !== \"|{\"\r\n || templateTokens[2].getFirstToken().getStr() !== \"}|\") {\r\n return undefined;\r\n }\r\n const templateSource = child.findDirectExpression(Expressions.StringTemplateSource);\r\n const formatting = (_a = templateSource === null || templateSource === void 0 ? void 0 : templateSource.findDirectExpression(Expressions.StringTemplateFormatting)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n let functionName = \"\";\r\n switch (formatting) {\r\n case \"ALPHA = IN\":\r\n functionName = \"CONVERSION_EXIT_ALPHA_INPUT\";\r\n break;\r\n case \"ALPHA = OUT\":\r\n functionName = \"CONVERSION_EXIT_ALPHA_OUTPUT\";\r\n break;\r\n default:\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const source = (_b = templateSource === null || templateSource === void 0 ? void 0 : templateSource.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const topTarget = (_c = high.findDirectExpression(Expressions.Target)) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n if (top === false) {\r\n const code = `DATA ${uniqueName} TYPE string.\r\n${indentation}CALL FUNCTION '${functionName}'\r\n${indentation} EXPORTING\r\n${indentation} input = ${source}\r\n${indentation} IMPORTING\r\n${indentation} output = ${uniqueName}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, child.getFirstToken().getStart(), child.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport ALPHA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n else {\r\n const code = `CALL FUNCTION '${functionName}'\r\n${indentation} EXPORTING\r\n${indentation} input = ${source}\r\n${indentation} IMPORTING\r\n${indentation} output = ${topTarget}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport ALPHA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n outlineLoopInput(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n else if (high.findDirectExpression(Expressions.SimpleSource2)) {\r\n return undefined;\r\n }\r\n // the first Source must be outlined\r\n const s = high.findDirectExpression(Expressions.Source);\r\n if (s === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const code = `DATA(${uniqueName}) = ${s.concatTokens()}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, s.getFirstToken().getStart(), s.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline LOOP input\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n outlineLoopTarget(node, lowFile, _highSyntax) {\r\n var _a, _b, _c, _d, _e, _f, _g;\r\n // also allows outlining of voided types\r\n if (!(node.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n const sourceName = (_a = node.findDirectExpression(Expressions.SimpleSource2)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n if (sourceName === undefined) {\r\n return undefined;\r\n }\r\n const concat = node.concatTokens().toUpperCase();\r\n if (concat.includes(\" REFERENCE INTO \")\r\n || concat.includes(\" GROUP BY \")\r\n || concat.startsWith(\"LOOP AT GROUP \")) {\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const dataTarget = (_c = (_b = node.findDirectExpression(Expressions.LoopTarget)) === null || _b === void 0 ? void 0 : _b.findDirectExpression(Expressions.Target)) === null || _c === void 0 ? void 0 : _c.findDirectExpression(Expressions.InlineData);\r\n if (dataTarget) {\r\n const targetName = ((_d = dataTarget.findDirectExpression(Expressions.TargetField)) === null || _d === void 0 ? void 0 : _d.concatTokens()) || \"DOWNPORT_ERROR\";\r\n const code = `DATA ${targetName} LIKE LINE OF ${sourceName}.\\n${indentation}`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, dataTarget.getFirstToken().getStart(), dataTarget.getLastToken().getEnd(), targetName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline LOOP data target\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n const fsTarget = (_f = (_e = node.findDirectExpression(Expressions.LoopTarget)) === null || _e === void 0 ? void 0 : _e.findDirectExpression(Expressions.FSTarget)) === null || _f === void 0 ? void 0 : _f.findDirectExpression(Expressions.InlineFS);\r\n if (fsTarget) {\r\n const targetName = ((_g = fsTarget.findDirectExpression(Expressions.TargetFieldSymbol)) === null || _g === void 0 ? void 0 : _g.concatTokens()) || \"DOWNPORT_ERROR\";\r\n const code = `FIELD-SYMBOLS ${targetName} LIKE LINE OF ${sourceName}.\\n${indentation}`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, fsTarget.getFirstToken().getStart(), fsTarget.getLastToken().getEnd(), targetName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline LOOP fs target\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineFor(forLoop, indentation, lowFile, highSyntax) {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;\r\n let body = \"\";\r\n let end = \"\";\r\n const loopSource = (_a = forLoop.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n let loopTargetField = (_b = forLoop.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const of = (_c = forLoop.findExpressionAfterToken(\"OF\")) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n if (of !== undefined) {\r\n loopTargetField = of;\r\n }\r\n if (((_e = (_d = forLoop.findDirectExpression(Expressions.InlineLoopDefinition)) === null || _d === void 0 ? void 0 : _d.getFirstChild()) === null || _e === void 0 ? void 0 : _e.get()) instanceof Expressions.TargetFieldSymbol) {\r\n loopTargetField = undefined;\r\n }\r\n let cond = ((_f = forLoop.findDirectExpression(Expressions.ComponentCond)) === null || _f === void 0 ? void 0 : _f.concatTokens()) || \"\";\r\n if (cond !== \"\") {\r\n cond = \" WHERE \" + cond;\r\n }\r\n const loop = forLoop.findDirectExpression(Expressions.InlineLoopDefinition);\r\n const indexInto = (_g = loop === null || loop === void 0 ? void 0 : loop.findExpressionAfterToken(\"INTO\")) === null || _g === void 0 ? void 0 : _g.concatTokens();\r\n if (forLoop.findDirectTokenByText(\"UNTIL\")\r\n || forLoop.findDirectTokenByText(\"WHILE\")) {\r\n const fieldDef = forLoop.findDirectExpression(Expressions.InlineFieldDefinition);\r\n const field = (_h = fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.findFirstExpression(Expressions.Field)) === null || _h === void 0 ? void 0 : _h.concatTokens();\r\n const indexBackup = this.uniqueName(forLoop.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n body += indentation + \"DATA \" + field + \" TYPE i.\\n\";\r\n const second = fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.getChildren()[2];\r\n if ((second === null || second === void 0 ? void 0 : second.get()) instanceof Expressions.Source) {\r\n body += indentation + field + \" = \" + second.concatTokens() + \".\\n\";\r\n }\r\n const not = forLoop.findDirectTokenByText(\"UNTIL\") ? \" NOT\" : \"\";\r\n const cond = forLoop.findFirstExpression(Expressions.Cond);\r\n body += indentation + `DATA ${indexBackup} LIKE sy-index.\\n`;\r\n body += indentation + `${indexBackup} = sy-index.\\n`;\r\n body += indentation + `WHILE${not} ${cond === null || cond === void 0 ? void 0 : cond.concatTokens()}.\\n`;\r\n body += indentation + ` sy-index = ${indexBackup}.\\n`;\r\n const then = forLoop.findExpressionAfterToken(\"THEN\");\r\n if (then) {\r\n end += ` ${field} = ${then.concatTokens()}.\\n`;\r\n }\r\n else {\r\n end += ` ${field} = ${field} + 1.\\n`;\r\n }\r\n end += indentation + \"ENDWHILE\";\r\n }\r\n else if (loopTargetField !== undefined) {\r\n let from = (_j = forLoop.findExpressionAfterToken(\"FROM\")) === null || _j === void 0 ? void 0 : _j.concatTokens();\r\n from = from ? \" FROM \" + from : \"\";\r\n let to = (_k = forLoop.findExpressionAfterToken(\"TO\")) === null || _k === void 0 ? void 0 : _k.concatTokens();\r\n to = to ? \" TO \" + to : \"\";\r\n let gby = \"\";\r\n for (const lg of forLoop.findDirectExpressions(Expressions.LoopGroupByComponent)) {\r\n if (gby !== \"\") {\r\n gby += \" \";\r\n }\r\n gby += lg.concatTokens();\r\n }\r\n if (gby !== \"\") {\r\n gby = \" GROUP BY ( \" + gby + \" )\";\r\n }\r\n const groups = forLoop.findExpressionAfterToken(\"GROUPS\");\r\n if (groups) {\r\n gby += \" INTO DATA(\" + groups.concatTokens() + \")\";\r\n }\r\n let inGroup = \"\";\r\n if (forLoop.concatTokens().toUpperCase().includes(\" IN GROUP \")) {\r\n inGroup = \"-items\";\r\n }\r\n // todo, also backup sy-index / sy-tabix here?\r\n body += indentation + `LOOP AT ${loopSource}${inGroup} INTO DATA(${loopTargetField})${from}${to}${cond}${gby}.\\n`;\r\n if (indexInto) {\r\n body += indentation + \" DATA(\" + indexInto + \") = sy-tabix.\\n\";\r\n }\r\n end = \"ENDLOOP\";\r\n }\r\n else if (loopTargetField === undefined) {\r\n // todo, also backup sy-index / sy-tabix here?\r\n const loopTargetFieldSymbol = (_l = forLoop.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _l === void 0 ? void 0 : _l.concatTokens();\r\n body += indentation + `LOOP AT ${loopSource} ASSIGNING FIELD-SYMBOL(${loopTargetFieldSymbol})${cond}.\\n`;\r\n if (indexInto) {\r\n body += indentation + \" DATA(\" + indexInto + \") = sy-tabix.\\n\";\r\n }\r\n end = \"ENDLOOP\";\r\n }\r\n const l = forLoop.findDirectExpression(Expressions.Let);\r\n if (l) {\r\n body += this.outlineLet(l, indentation, highSyntax, lowFile);\r\n }\r\n return { body, end };\r\n }\r\n outlineSwitch(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c, _d;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n const firstToken = i.getFirstToken();\r\n if (firstToken.getStr().toUpperCase() !== \"SWITCH\") {\r\n continue;\r\n }\r\n let type = this.findType(i, lowFile, highSyntax);\r\n if (type === undefined) {\r\n if (high.get() instanceof Statements.Move\r\n && high.findDirectExpression(Expressions.Source) === i\r\n && ((_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.TargetField)) !== undefined) {\r\n type = \"LIKE \" + ((_b = high.findDirectExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());\r\n }\r\n if (type === undefined) {\r\n continue;\r\n }\r\n }\r\n else {\r\n type = \"TYPE \" + type;\r\n }\r\n const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let body = \"\";\r\n let name = \"\";\r\n const switchBody = i.findDirectExpression(Expressions.SwitchBody);\r\n if (switchBody === undefined) {\r\n continue;\r\n }\r\n for (const l of ((_c = switchBody === null || switchBody === void 0 ? void 0 : switchBody.findDirectExpression(Expressions.Let)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.InlineFieldDefinition)) || []) {\r\n name = l.getFirstToken().getStr();\r\n body += indentation + `DATA(${name}) = ${(_d = switchBody.findFirstExpression(Expressions.Source)) === null || _d === void 0 ? void 0 : _d.concatTokens()}.\\n`;\r\n }\r\n body += `DATA ${uniqueName} ${type}.\\n`;\r\n let firstSource = false;\r\n let inWhen = false;\r\n for (const c of switchBody.getChildren()) {\r\n if (c.get() instanceof Expressions.Source && firstSource === false) {\r\n body += indentation + `CASE ${c.concatTokens()}.`;\r\n firstSource = true;\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"THEN\") {\r\n inWhen = true;\r\n body += \".\\n\";\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"WHEN\") {\r\n inWhen = false;\r\n body += `\\n${indentation} WHEN `;\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"OR\") {\r\n body += ` OR `;\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"ELSE\") {\r\n inWhen = true;\r\n body += `\\n${indentation} WHEN OTHERS.\\n`;\r\n }\r\n else if (inWhen === false) {\r\n body += c.concatTokens();\r\n }\r\n else {\r\n body += indentation + \" \" + uniqueName + \" = \" + c.concatTokens() + \".\";\r\n }\r\n }\r\n body += \"\\n\" + indentation + \"ENDCASE.\\n\" + indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), body);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, firstToken, \"Downport SWITCH\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineReduce(low, high, lowFile, highSyntax) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n const firstToken = i.getFirstToken();\r\n if (firstToken.getStr().toUpperCase() !== \"REDUCE\") {\r\n continue;\r\n }\r\n const type = this.findType(i, lowFile, highSyntax);\r\n if (type === undefined) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let body = \"\";\r\n let name = \"\";\r\n const reduceBody = i.findDirectExpression(Expressions.ReduceBody);\r\n if (reduceBody === undefined) {\r\n continue;\r\n }\r\n const letNode = reduceBody.findDirectExpression(Expressions.Let);\r\n if (letNode) {\r\n body += this.outlineLet(letNode, indentation, highSyntax, lowFile);\r\n }\r\n let firstName = \"\";\r\n for (const init of reduceBody.findDirectExpressions(Expressions.InlineFieldDefinition)) {\r\n name = init.getFirstToken().getStr();\r\n if (firstName === \"\") {\r\n firstName = name;\r\n }\r\n const s = (_a = init.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n const t = (_b = init.findFirstExpression(Expressions.TypeName)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (s) {\r\n body += indentation + `DATA(${name}) = ${s}.\\n`;\r\n }\r\n else {\r\n body += indentation + `DATA ${name} TYPE ${t}.\\n`;\r\n }\r\n }\r\n let end = \"\";\r\n for (const forLoop of (reduceBody === null || reduceBody === void 0 ? void 0 : reduceBody.findDirectExpressions(Expressions.For)) || []) {\r\n const outlineFor = this.outlineFor(forLoop, indentation, lowFile, highSyntax);\r\n body += outlineFor.body;\r\n end = outlineFor.end + `.\\n` + end;\r\n }\r\n const next = reduceBody.findDirectExpression(Expressions.ReduceNext);\r\n if (next === undefined) {\r\n continue;\r\n }\r\n for (const n of next.getChildren()) {\r\n const concat = n.concatTokens();\r\n if (concat.toUpperCase() === \"NEXT\") {\r\n continue;\r\n }\r\n else if (n.get() instanceof Expressions.Field) {\r\n body += indentation + \" \" + concat + \" \";\r\n }\r\n else if (n.get() instanceof Expressions.Source) {\r\n body += \" \" + concat + \".\\n\";\r\n }\r\n else {\r\n body += concat;\r\n }\r\n }\r\n body += indentation + end;\r\n body += indentation + `${uniqueName} = ${firstName}.\\n`;\r\n const abap = `DATA ${uniqueName} TYPE ${type}.\\n` +\r\n body +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, firstToken, \"Downport REDUCE\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineValue(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const allSources = high.findAllExpressionsRecursive(Expressions.Source);\r\n for (const s of allSources) {\r\n const firstToken = s.getFirstToken();\r\n if (firstToken.getStr().toUpperCase() !== \"VALUE\") {\r\n continue;\r\n }\r\n let type = this.findType(s, lowFile, highSyntax);\r\n if (type === undefined) {\r\n if (high.get() instanceof Statements.Move && high.findDirectExpression(Expressions.Source) === s) {\r\n type = \"LIKE \" + ((_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.concatTokens());\r\n }\r\n if (type === undefined) {\r\n continue;\r\n }\r\n }\r\n else {\r\n type = \"TYPE \" + type;\r\n }\r\n const valueBody = s.findDirectExpression(Expressions.ValueBody);\r\n const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n let indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let body = \"\";\r\n const base = valueBody === null || valueBody === void 0 ? void 0 : valueBody.findExpressionAfterToken(\"BASE\");\r\n if (base) {\r\n body += indentation + uniqueName + \" = \" + base.concatTokens() + \".\\n\";\r\n }\r\n let end = \"\";\r\n let structureName = uniqueName;\r\n let added = false;\r\n let data = \"\";\r\n let previous = undefined;\r\n for (const a of (valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren()) || []) {\r\n if (a.get() instanceof Expressions.FieldAssignment) {\r\n if (added === false) {\r\n body += data;\r\n added = true;\r\n }\r\n body += indentation + structureName + \"-\" + a.concatTokens() + \".\\n\";\r\n }\r\n else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.For) {\r\n const outlineFor = this.outlineFor(a, indentation, lowFile, highSyntax);\r\n body += outlineFor.body;\r\n end = outlineFor.end + `.\\n` + end;\r\n indentation += \" \";\r\n }\r\n else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.Source) {\r\n // special handling for superflous value expression\r\n if ((valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren().length) === 1) {\r\n body += indentation + uniqueName + \" = \" + a.concatTokens() + `.\\n`;\r\n }\r\n }\r\n else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.Let) {\r\n body += this.outlineLet(a, indentation, highSyntax, lowFile);\r\n }\r\n if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.ValueBodyLine) {\r\n let skip = false;\r\n for (const b of (a === null || a === void 0 ? void 0 : a.getChildren()) || []) {\r\n if (b.concatTokens() === \"(\" && added === false) {\r\n structureName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n data = indentation + `DATA ${structureName} LIKE LINE OF ${uniqueName}.\\n`;\r\n }\r\n if (b.get() instanceof Expressions.FieldAssignment) {\r\n if (added === false) {\r\n body += data;\r\n added = true;\r\n }\r\n body += indentation + structureName + \"-\" + b.concatTokens() + \".\\n\";\r\n }\r\n else if (b.get() instanceof Expressions.Source) {\r\n body += indentation + \"APPEND \" + b.concatTokens() + ` TO ${uniqueName}.\\n`;\r\n skip = true;\r\n }\r\n else if (b.get() instanceof Expressions.ValueBodyLines) {\r\n body += indentation + \"APPEND \" + b.concatTokens() + ` TO ${uniqueName}.\\n`;\r\n skip = true;\r\n }\r\n else if (b.concatTokens() === \")\") {\r\n if (added === false && (previous === null || previous === void 0 ? void 0 : previous.concatTokens()) === \"(\") {\r\n body += data;\r\n added = true;\r\n }\r\n if (skip === false) {\r\n body += indentation + `APPEND ${structureName} TO ${uniqueName}.\\n`;\r\n }\r\n }\r\n previous = b;\r\n }\r\n }\r\n }\r\n if (body === \"\" && ((_b = valueBody === null || valueBody === void 0 ? void 0 : valueBody.getLastChild()) === null || _b === void 0 ? void 0 : _b.getFirstToken().getStr().toUpperCase()) === \"OPTIONAL\") {\r\n const fieldChain = valueBody.findFirstExpression(Expressions.FieldChain);\r\n const rowName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n let tableExpression = undefined;\r\n let tabName = \"\";\r\n let after = \"\";\r\n for (const c of (fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren()) || []) {\r\n if (c.get() instanceof Expressions.TableExpression && c instanceof nodes_1.ExpressionNode) {\r\n tableExpression = c;\r\n }\r\n else if (tableExpression === undefined) {\r\n tabName += c.concatTokens();\r\n }\r\n else {\r\n after += c.concatTokens();\r\n }\r\n }\r\n let condition = \"\";\r\n if ((tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.getChildren().length) === 3) {\r\n condition = \"INDEX \" + ((_c = tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.findDirectExpression(Expressions.Source)) === null || _c === void 0 ? void 0 : _c.concatTokens());\r\n }\r\n else {\r\n condition = \"WITH KEY \" + (tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.concatTokens().replace(\"[ \", \"\").replace(\" ]\", \"\"));\r\n }\r\n body +=\r\n indentation + `READ TABLE ${tabName} INTO DATA(${rowName}) ${condition}.\\n` +\r\n indentation + `IF sy-subrc = 0.\\n` +\r\n indentation + ` ${uniqueName} = ${rowName}${after}.\\n` +\r\n indentation + `ENDIF.\\n`;\r\n }\r\n if (end !== \"\") {\r\n indentation = indentation.substring(2);\r\n body += indentation + end;\r\n }\r\n const abap = `DATA ${uniqueName} ${type}.\\n` +\r\n indentation + `CLEAR ${uniqueName}.\\n` + // might be called inside a loop\r\n body +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), s.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, firstToken, \"Downport VALUE\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineLet(node, indentation, highSyntax, lowFile) {\r\n var _a;\r\n let ret = \"\";\r\n for (const f of node.findDirectExpressions(Expressions.InlineFieldDefinition)) {\r\n const c = f.getFirstChild();\r\n if (c === undefined) {\r\n continue;\r\n }\r\n const name = c.concatTokens().toLowerCase();\r\n const spag = highSyntax.spaghetti.lookupPosition(c.getFirstToken().getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n continue;\r\n }\r\n const found = spag.findVariable(name);\r\n if (found === undefined) {\r\n const source = f.findFirstExpression(Expressions.Source);\r\n if (source) {\r\n ret += indentation + \"DATA(\" + name + `) = ${source.concatTokens()}.\\n`;\r\n }\r\n continue;\r\n }\r\n const type = found.getType().getQualifiedName() ? (_a = found.getType().getQualifiedName()) === null || _a === void 0 ? void 0 : _a.toLowerCase() : found.getType().toABAP();\r\n ret += indentation + \"DATA \" + name + ` TYPE ${type}.\\n`;\r\n const source = f.findFirstExpression(Expressions.Source);\r\n if (source) {\r\n ret += indentation + name + ` = ${source.concatTokens()}.\\n`;\r\n }\r\n }\r\n return ret;\r\n }\r\n findType(i, lowFile, highSyntax, ref = false) {\r\n var _a;\r\n const expr = i.findDirectExpression(Expressions.TypeNameOrInfer);\r\n if (expr === undefined) {\r\n return undefined;\r\n }\r\n const firstToken = expr.getFirstToken();\r\n const concat = expr.concatTokens().toLowerCase();\r\n if (concat !== \"#\") {\r\n return ref ? \"REF TO \" + concat : concat;\r\n }\r\n const spag = highSyntax.spaghetti.lookupPosition(firstToken.getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n return undefined;\r\n }\r\n let inferred = undefined;\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType === _reference_1.ReferenceType.InferredType\r\n && r.resolved\r\n && r.position.getStart().equals(firstToken.getStart())\r\n && r.resolved instanceof _typed_identifier_1.TypedIdentifier) {\r\n inferred = r.resolved;\r\n break;\r\n }\r\n }\r\n if (inferred === undefined) {\r\n return undefined;\r\n }\r\n if (inferred.getType() instanceof basic_1.ObjectReferenceType) {\r\n return inferred.getType().toABAP();\r\n }\r\n else {\r\n return (_a = inferred.getType().getQualifiedName()) === null || _a === void 0 ? void 0 : _a.toLowerCase();\r\n }\r\n }\r\n outlineFS(low, high, lowFile, highSyntax) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)\r\n || (high.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.InlineFS)) {\r\n const nameToken = (_a = i.findDirectExpression(Expressions.TargetFieldSymbol)) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n if (nameToken === undefined) {\r\n continue;\r\n }\r\n const name = nameToken.getStr();\r\n let type = \"\";\r\n if (high.concatTokens().toUpperCase().startsWith(\"APPEND INITIAL LINE TO \")) {\r\n type = \"LIKE LINE OF \" + ((_b = high.findFirstExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());\r\n }\r\n else {\r\n const spag = highSyntax.spaghetti.lookupPosition(nameToken.getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n continue;\r\n }\r\n const found = spag.findVariable(name);\r\n if (found === undefined) {\r\n continue;\r\n }\r\n else if (found.getType() instanceof basic_1.VoidType) {\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Error outlining voided type\", this.getMetadata().key, this.conf.severity);\r\n }\r\n type = \"TYPE \";\r\n type += found.getType().getQualifiedName() ? found.getType().getQualifiedName().toLowerCase() : found.getType().toABAP();\r\n }\r\n const code = `FIELD-SYMBOLS ${name} ${type}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Outline FIELD-SYMBOL\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineData(node, lowFile, highSyntax) {\r\n // hmm, no guard here, as DATA(SDF) is valid in 702\r\n var _a, _b;\r\n for (const i of node.findAllExpressionsRecursive(Expressions.InlineData)) {\r\n const nameToken = (_a = i.findDirectExpression(Expressions.TargetField)) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n if (nameToken === undefined) {\r\n continue;\r\n }\r\n const name = nameToken.getStr();\r\n const spag = highSyntax.spaghetti.lookupPosition(nameToken.getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n continue;\r\n }\r\n const found = spag.findVariable(name);\r\n if (found === undefined) {\r\n continue;\r\n }\r\n else if (found.getType() instanceof basic_1.VoidType && found.getType().getQualifiedName() === undefined) {\r\n continue;\r\n }\r\n let type = found.getType().getQualifiedName() ? (_b = found.getType().getQualifiedName()) === null || _b === void 0 ? void 0 : _b.toLowerCase() : found.getType().toABAP();\r\n if (found.getType() instanceof basic_1.ObjectReferenceType) {\r\n type = found.getType().toABAP();\r\n }\r\n const code = `DATA ${name} TYPE ${type}.\\n` +\r\n \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Outline DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineCond(low, high, lowFile, highSyntax) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n if (i.getFirstToken().getStr().toUpperCase() !== \"COND\") {\r\n continue;\r\n }\r\n const body = i.findDirectExpression(Expressions.CondBody);\r\n if (body === undefined) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n let type = this.findType(i, lowFile, highSyntax);\r\n if (type === undefined) {\r\n if (high.get() instanceof Statements.Move\r\n && high.findDirectExpression(Expressions.Source) === i\r\n && ((_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.TargetField)) !== undefined) {\r\n type = \"LIKE \" + ((_b = high.findDirectExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());\r\n }\r\n if (type === undefined) {\r\n continue;\r\n }\r\n }\r\n else {\r\n type = \"TYPE \" + type;\r\n }\r\n const indent = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const bodyCode = this.buildCondBody(body, uniqueName, indent, lowFile, highSyntax);\r\n const abap = `DATA ${uniqueName} ${type}.\\n` + bodyCode;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport COND\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n buildCondBody(body, uniqueName, indent, lowFile, highSyntax) {\r\n let code = \"\";\r\n let first = true;\r\n let addElse = true;\r\n for (const c of body.getChildren()) {\r\n if (c instanceof nodes_1.TokenNode) {\r\n switch (c.getFirstToken().getStr().toUpperCase()) {\r\n case \"WHEN\":\r\n if (first === true) {\r\n code += indent + \"IF \";\r\n first = false;\r\n }\r\n else {\r\n code += indent + \"ELSEIF \";\r\n }\r\n break;\r\n case \"THEN\":\r\n code += \".\\n\";\r\n break;\r\n case \"ELSE\":\r\n code += indent + \"ELSE.\\n\";\r\n addElse = false;\r\n break;\r\n default:\r\n throw \"buildCondBody, unexpected token\";\r\n }\r\n }\r\n else if (c.get() instanceof Expressions.Cond) {\r\n code += c.concatTokens();\r\n }\r\n else if (c.get() instanceof Expressions.Let) {\r\n code += this.outlineLet(c, indent, highSyntax, lowFile);\r\n }\r\n else if (c.get() instanceof Expressions.Source) {\r\n code += indent + \" \" + uniqueName + \" = \" + c.concatTokens() + \".\\n\";\r\n }\r\n else {\r\n throw \"buildCondBody, unexpected expression, \" + c.get().constructor.name;\r\n }\r\n }\r\n if (addElse) {\r\n // COND might be called inside a loop\r\n code += indent + \"ELSE.\\n\";\r\n code += indent + ` CLEAR ${uniqueName}.\\n`;\r\n }\r\n code += indent + \"ENDIF.\\n\";\r\n code += indent;\r\n return code;\r\n }\r\n outlineConv(low, high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n if (i.getFirstToken().getStr().toUpperCase() !== \"CONV\") {\r\n continue;\r\n }\r\n const end = i.findDirectTokenByText(\")\");\r\n if (end === undefined) {\r\n continue;\r\n }\r\n const body = (_a = i.findDirectExpression(Expressions.ConvBody)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n if (body === undefined) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const type = this.findType(i, lowFile, highSyntax);\r\n const indent = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const abap = `DATA ${uniqueName} TYPE ${type}.\\n` +\r\n indent + `${uniqueName} = ${body}.\\n` +\r\n indent;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), end.getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport CONV\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n // \"CAST\" to \"?=\"\r\n outlineCast(low, high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Cast)) {\r\n const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const type = this.findType(i, lowFile, highSyntax, true);\r\n const body = (_a = i.findDirectExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n const abap = `DATA ${uniqueName} TYPE ${type}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1) +\r\n `${uniqueName} ?= ${body}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport CAST\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n uniqueName(position, filename, highSyntax) {\r\n const spag = highSyntax.spaghetti.lookupPosition(position, filename);\r\n if (spag === undefined) {\r\n const name = \"temprr\" + this.counter;\r\n this.counter++;\r\n return name;\r\n }\r\n while (true) {\r\n const name = \"temp\" + this.counter;\r\n const found = spag.findVariable(name);\r\n this.counter++;\r\n if (found === undefined) {\r\n return name;\r\n }\r\n }\r\n }\r\n replaceXsdBool(node, lowFile, highSyntax) {\r\n const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType === _reference_1.ReferenceType.BuiltinMethodReference\r\n && r.position.getName().toUpperCase() === \"XSDBOOL\") {\r\n const token = r.position.getToken();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, token.getStart(), token.getEnd(), \"boolc\");\r\n return issue_1.Issue.atToken(lowFile, token, \"Use BOOLC\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n findMethodCallExpression(node, token) {\r\n var _a;\r\n for (const m of node.findAllExpressions(Expressions.MethodCall)) {\r\n if ((_a = m.findDirectExpression(Expressions.MethodName)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStart().equals(token.getStart())) {\r\n return m;\r\n }\r\n }\r\n return undefined;\r\n }\r\n replaceMethodConditional(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const c of high.findAllExpressionsRecursive(Expressions.Compare)) {\r\n const chain = c.findDirectExpression(Expressions.MethodCallChain);\r\n if (chain === undefined) {\r\n continue;\r\n }\r\n let predicate = false;\r\n const spag = highSyntax.spaghetti.lookupPosition(high.getFirstToken().getStart(), lowFile.getFilename());\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType === _reference_1.ReferenceType.BuiltinMethodReference &&\r\n new _builtin_1.BuiltIn().isPredicate(chain.getFirstToken().getStr().toUpperCase())) {\r\n predicate = true;\r\n break;\r\n }\r\n }\r\n const end = chain.getLastToken().getEnd();\r\n let fix = edit_helper_1.EditHelper.insertAt(lowFile, end, \" IS NOT INITIAL\");\r\n if (predicate === true) {\r\n fix = edit_helper_1.EditHelper.insertAt(lowFile, end, \" ) = abap_true\");\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, chain.getFirstToken().getStart(), \"boolc( \");\r\n fix = edit_helper_1.EditHelper.merge(fix, fix1);\r\n }\r\n return issue_1.Issue.atToken(lowFile, chain.getFirstToken(), \"Downport method conditional\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n getReference(node, lowFile, _highSyntax) {\r\n var _a, _b, _c;\r\n if (!(node.get() instanceof Statements.GetReference)) {\r\n return undefined;\r\n }\r\n const inline = (_a = node.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.InlineData);\r\n if (inline === undefined) {\r\n return undefined;\r\n }\r\n const targetName = (_b = inline.findDirectExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const sourceName = (_c = node.findDirectExpression(Expressions.Source)) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n if (targetName === undefined || sourceName === undefined) {\r\n return undefined;\r\n }\r\n const code = `DATA ${targetName} LIKE REF TO ${sourceName}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inline.getFirstToken().getStart(), inline.getLastToken().getEnd(), targetName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, inline.getFirstToken(), \"Downport, outline DATA ref\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n replaceContains(node, lowFile, highSyntax) {\r\n const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());\r\n // only downport if its an single method call condition\r\n let found = false;\r\n for (const c of node.findAllExpressionsRecursive(Expressions.Compare)) {\r\n found = c.findDirectExpression(Expressions.MethodCallChain) !== undefined;\r\n if (found === true) {\r\n break;\r\n }\r\n }\r\n if (found === false) {\r\n return undefined;\r\n }\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType !== _reference_1.ReferenceType.BuiltinMethodReference) {\r\n continue;\r\n }\r\n const func = r.position.getName().toUpperCase();\r\n if (func === \"CONTAINS\") {\r\n const token = r.position.getToken();\r\n const expression = this.findMethodCallExpression(node, token);\r\n if (expression === undefined) {\r\n continue;\r\n }\r\n const sList = expression.findAllExpressions(Expressions.Source).map(e => e.concatTokens());\r\n if (sList.length !== 2) {\r\n continue;\r\n }\r\n const code = sList[0] + \" CS \" + sList[1];\r\n const start = expression.getFirstToken().getStart();\r\n const end = expression.getLastToken().getEnd();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, token, \"Downport contains()\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n replaceLineFunctions(node, lowFile, highSyntax) {\r\n var _a, _b;\r\n const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType !== _reference_1.ReferenceType.BuiltinMethodReference) {\r\n continue;\r\n }\r\n const func = r.position.getName().toUpperCase();\r\n if (func === \"LINE_EXISTS\" || func === \"LINE_INDEX\") {\r\n const token = r.position.getToken();\r\n const expression = this.findMethodCallExpression(node, token);\r\n if (expression === undefined) {\r\n continue;\r\n }\r\n let condition = \"\";\r\n for (const c of ((_a = expression === null || expression === void 0 ? void 0 : expression.findFirstExpression(Expressions.TableExpression)) === null || _a === void 0 ? void 0 : _a.getChildren()) || []) {\r\n if (c.getFirstToken().getStr() === \"[\" || c.getFirstToken().getStr() === \"]\") {\r\n continue;\r\n }\r\n else if (c.get() instanceof Expressions.ComponentChainSimple && condition === \"\") {\r\n condition = \"WITH KEY \";\r\n }\r\n else if (c.get() instanceof Expressions.Source && condition === \"\") {\r\n condition = \"INDEX \";\r\n }\r\n condition += c.concatTokens() + \" \";\r\n }\r\n const tableName = (_b = expression.findFirstExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens().split(\"[\")[0];\r\n const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const sy = func === \"LINE_EXISTS\" ? \"sy-subrc\" : \"sy-tabix\";\r\n const code = `DATA ${uniqueName} LIKE sy-subrc.\\n` +\r\n indentation + `READ TABLE ${tableName} ${condition}TRANSPORTING NO FIELDS.\\n` +\r\n indentation + uniqueName + ` = ${sy}.\\n` +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const start = expression.getFirstToken().getStart();\r\n const end = expression.getLastToken().getEnd();\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, uniqueName + (func === \"LINE_EXISTS\" ? \" = 0\" : \"\"));\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, token, \"Use BOOLC\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n newToCreateObject(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const source = high.findDirectExpression(Expressions.Source);\r\n let fix = undefined;\r\n if (high.get() instanceof Statements.Move\r\n && source\r\n && source.getFirstToken().getStr().toUpperCase() === \"NEW\") {\r\n const target = high.findDirectExpression(Expressions.Target);\r\n const found = source === null || source === void 0 ? void 0 : source.findFirstExpression(Expressions.NewObject);\r\n // must be at top level of the source for quickfix to work(todo: handle more scenarios)\r\n if (target\r\n && found\r\n && source.concatTokens() === found.concatTokens()\r\n && target.findDirectExpression(Expressions.InlineData) === undefined) {\r\n const abap = this.newParameters(found, target.concatTokens(), highSyntax, lowFile);\r\n if (abap !== undefined) {\r\n fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), abap);\r\n }\r\n }\r\n }\r\n if (fix === undefined && high.findAllExpressions(Expressions.NewObject)) {\r\n const found = high.findFirstExpression(Expressions.NewObject);\r\n if (found === undefined) {\r\n return undefined;\r\n }\r\n const name = this.uniqueName(found.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const abap = this.newParameters(found, name, highSyntax, lowFile);\r\n if (abap === undefined) {\r\n return undefined;\r\n }\r\n const type = this.findType(found, lowFile, highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const data = `DATA ${name} TYPE REF TO ${type}.\\n` +\r\n indentation + abap + \"\\n\" +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), data);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, found.getFirstToken().getStart(), found.getLastToken().getEnd(), name);\r\n fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n }\r\n if (fix) {\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Use CREATE OBJECT instead of NEW\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n else {\r\n return undefined;\r\n }\r\n }\r\n newParameters(found, name, highSyntax, lowFile) {\r\n var _a, _b, _c;\r\n const typeToken = (_a = found.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n let extra = (typeToken === null || typeToken === void 0 ? void 0 : typeToken.getStr()) === \"#\" ? \"\" : \" TYPE \" + (typeToken === null || typeToken === void 0 ? void 0 : typeToken.getStr());\r\n const parameters = found.findFirstExpression(Expressions.ParameterListS);\r\n if (parameters) {\r\n extra = parameters ? extra + \" EXPORTING \" + parameters.concatTokens() : extra;\r\n }\r\n else if (typeToken) {\r\n const source = (_b = found.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (source) {\r\n // find the default parameter name for the constructor\r\n const spag = highSyntax.spaghetti.lookupPosition(typeToken === null || typeToken === void 0 ? void 0 : typeToken.getStart(), lowFile.getFilename());\r\n let cdef = undefined;\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if ((r.referenceType === _reference_1.ReferenceType.InferredType\r\n || r.referenceType === _reference_1.ReferenceType.ObjectOrientedReference)\r\n && r.resolved && r.position.getStart().equals(typeToken.getStart())) {\r\n cdef = r.resolved;\r\n }\r\n }\r\n if (cdef && cdef.getMethodDefinitions === undefined) {\r\n return undefined; // something wrong\r\n }\r\n const importing = (_c = cdef === null || cdef === void 0 ? void 0 : cdef.getMethodDefinitions().getByName(\"CONSTRUCTOR\")) === null || _c === void 0 ? void 0 : _c.getParameters().getDefaultImporting();\r\n if (importing) {\r\n extra += \" EXPORTING \" + importing + \" = \" + source;\r\n }\r\n else if (spag === undefined) {\r\n extra += \" SpagUndefined\";\r\n }\r\n else if (cdef === undefined) {\r\n extra += \" ClassDefinitionNotFound\";\r\n }\r\n else {\r\n extra += \" SomeError\";\r\n }\r\n }\r\n }\r\n const abap = `CREATE OBJECT ${name}${extra}.`;\r\n return abap;\r\n }\r\n}\r\nexports.Downport = Downport;\r\n//# sourceMappingURL=downport.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/rules/downport.js?");
|
|
11943
|
+
eval("\r\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\r\nexports.Downport = exports.DownportConf = void 0;\r\n/* eslint-disable max-len */\r\nconst Statements = __webpack_require__(/*! ../abap/2_statements/statements */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/statements/index.js\");\r\nconst Expressions = __webpack_require__(/*! ../abap/2_statements/expressions */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/expressions/index.js\");\r\nconst Structures = __webpack_require__(/*! ../abap/3_structures/structures */ \"./node_modules/@abaplint/core/build/src/abap/3_structures/structures/index.js\");\r\nconst _basic_rule_config_1 = __webpack_require__(/*! ./_basic_rule_config */ \"./node_modules/@abaplint/core/build/src/rules/_basic_rule_config.js\");\r\nconst issue_1 = __webpack_require__(/*! ../issue */ \"./node_modules/@abaplint/core/build/src/issue.js\");\r\nconst _irule_1 = __webpack_require__(/*! ./_irule */ \"./node_modules/@abaplint/core/build/src/rules/_irule.js\");\r\nconst _statement_1 = __webpack_require__(/*! ../abap/2_statements/statements/_statement */ \"./node_modules/@abaplint/core/build/src/abap/2_statements/statements/_statement.js\");\r\nconst nodes_1 = __webpack_require__(/*! ../abap/nodes */ \"./node_modules/@abaplint/core/build/src/abap/nodes/index.js\");\r\nconst edit_helper_1 = __webpack_require__(/*! ../edit_helper */ \"./node_modules/@abaplint/core/build/src/edit_helper.js\");\r\nconst position_1 = __webpack_require__(/*! ../position */ \"./node_modules/@abaplint/core/build/src/position.js\");\r\nconst _abap_object_1 = __webpack_require__(/*! ../objects/_abap_object */ \"./node_modules/@abaplint/core/build/src/objects/_abap_object.js\");\r\nconst version_1 = __webpack_require__(/*! ../version */ \"./node_modules/@abaplint/core/build/src/version.js\");\r\nconst registry_1 = __webpack_require__(/*! ../registry */ \"./node_modules/@abaplint/core/build/src/registry.js\");\r\nconst syntax_1 = __webpack_require__(/*! ../abap/5_syntax/syntax */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/syntax.js\");\r\nconst _reference_1 = __webpack_require__(/*! ../abap/5_syntax/_reference */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_reference.js\");\r\nconst _typed_identifier_1 = __webpack_require__(/*! ../abap/types/_typed_identifier */ \"./node_modules/@abaplint/core/build/src/abap/types/_typed_identifier.js\");\r\nconst basic_1 = __webpack_require__(/*! ../abap/types/basic */ \"./node_modules/@abaplint/core/build/src/abap/types/basic/index.js\");\r\nconst config_1 = __webpack_require__(/*! ../config */ \"./node_modules/@abaplint/core/build/src/config.js\");\r\nconst tokens_1 = __webpack_require__(/*! ../abap/1_lexer/tokens */ \"./node_modules/@abaplint/core/build/src/abap/1_lexer/tokens/index.js\");\r\nconst include_graph_1 = __webpack_require__(/*! ../utils/include_graph */ \"./node_modules/@abaplint/core/build/src/utils/include_graph.js\");\r\nconst objects_1 = __webpack_require__(/*! ../objects */ \"./node_modules/@abaplint/core/build/src/objects/index.js\");\r\nconst _builtin_1 = __webpack_require__(/*! ../abap/5_syntax/_builtin */ \"./node_modules/@abaplint/core/build/src/abap/5_syntax/_builtin.js\");\r\n// todo: refactor each sub-rule to new classes?\r\n// todo: add configuration\r\nclass DownportConf extends _basic_rule_config_1.BasicRuleConfig {\r\n}\r\nexports.DownportConf = DownportConf;\r\nclass Downport {\r\n constructor() {\r\n this.conf = new DownportConf();\r\n }\r\n getMetadata() {\r\n return {\r\n key: \"downport\",\r\n title: \"Downport statement\",\r\n shortDescription: `Experimental downport functionality`,\r\n extendedInformation: `Much like the 'commented_code' rule this rule loops through unknown statements and tries parsing with\r\na higher level language version. If successful, various rules are applied to downport the statement.\r\nTarget downport version is always v702, thus rule is only enabled if target version is v702.\r\n\r\nCurrent rules:\r\n* NEW transformed to CREATE OBJECT, opposite of https://rules.abaplint.org/use_new/\r\n* DATA() definitions are outlined, opposite of https://rules.abaplint.org/prefer_inline/\r\n* FIELD-SYMBOL() definitions are outlined\r\n* CONV is outlined\r\n* COND is outlined\r\n* REDUCE is outlined\r\n* SWITCH is outlined\r\n* APPEND expression is outlined\r\n* INSERT expression is outlined\r\n* EMPTY KEY is changed to DEFAULT KEY, opposite of DEFAULT KEY in https://rules.abaplint.org/avoid_use/\r\n* CAST changed to ?=\r\n* LOOP AT method_call( ) is outlined\r\n* VALUE # with structure fields\r\n* VALUE # with internal table lines\r\n* Table Expressions are outlined\r\n* SELECT INTO @DATA definitions are outlined\r\n* Some occurrences of string template formatting option ALPHA changed to function module call\r\n* SELECT/INSERT/MODIFY/DELETE/UPDATE \",\" in field list removed, \"@\" in source/targets removed\r\n* PARTIALLY IMPLEMENTED removed, it can be quick fixed via rule implement_methods\r\n* RAISE EXCEPTION ... MESSAGE\r\n* Moving with +=, -=, /=, *=, &&= is expanded\r\n* line_exists and line_index is downported to READ TABLE\r\n* ENUMs, but does not nessesarily give the correct type and value\r\n* MESSAGE with non simple source\r\n\r\nOnly one transformation is applied to a statement at a time, so multiple steps might be required to do the full downport.`,\r\n tags: [_irule_1.RuleTag.Experimental, _irule_1.RuleTag.Downport, _irule_1.RuleTag.Quickfix],\r\n };\r\n }\r\n getConfig() {\r\n return this.conf;\r\n }\r\n setConfig(conf) {\r\n this.conf = conf;\r\n }\r\n initialize(reg) {\r\n this.lowReg = reg;\r\n const version = this.lowReg.getConfig().getVersion();\r\n if (version === version_1.Version.v702 || version === version_1.Version.OpenABAP) {\r\n this.initHighReg();\r\n }\r\n return this;\r\n }\r\n listMainForInclude(filename) {\r\n if (filename === undefined) {\r\n return [];\r\n }\r\n // only initialize this.graph if needed\r\n if (this.graph === undefined) {\r\n this.graph = new include_graph_1.IncludeGraph(this.lowReg);\r\n }\r\n return this.graph.listMainForInclude(filename);\r\n }\r\n run(lowObj) {\r\n var _a;\r\n const ret = [];\r\n this.counter = 1;\r\n const version = this.lowReg.getConfig().getVersion();\r\n if (version !== version_1.Version.v702 && version !== version_1.Version.OpenABAP) {\r\n return ret;\r\n }\r\n else if (!(lowObj instanceof _abap_object_1.ABAPObject)) {\r\n return ret;\r\n }\r\n const highObj = this.highReg.getObject(lowObj.getType(), lowObj.getName());\r\n if (highObj === undefined || !(highObj instanceof _abap_object_1.ABAPObject)) {\r\n return ret;\r\n }\r\n let highSyntaxObj = highObj;\r\n // for includes do the syntax check via a main program\r\n if (lowObj instanceof objects_1.Program && lowObj.isInclude()) {\r\n const mains = this.listMainForInclude((_a = lowObj.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getFilename());\r\n if (mains.length <= 0) {\r\n return [];\r\n }\r\n const f = this.highReg.getFileByName(mains[0]);\r\n if (f === undefined) {\r\n return [];\r\n }\r\n highSyntaxObj = this.highReg.findObjectForFile(f);\r\n }\r\n for (const lowFile of lowObj.getABAPFiles()) {\r\n let highSyntax = undefined;\r\n const highFile = highObj.getABAPFileByName(lowFile.getFilename());\r\n if (highFile === undefined) {\r\n continue;\r\n }\r\n const lowStatements = lowFile.getStatements();\r\n const highStatements = highFile.getStatements();\r\n if (lowStatements.length !== highStatements.length) {\r\n // after applying a fix, there might be more statements in lowFile\r\n // should highReg be initialized again?\r\n /*\r\n const message = \"Internal Error: Statement lengths does not match\";\r\n ret.push(Issue.atStatement(lowFile, lowStatements[0], message, this.getMetadata().key));\r\n */\r\n // hmm, add some way to disable lazyUnknown() in statement_parser.ts\r\n continue;\r\n }\r\n for (let i = 0; i < lowStatements.length; i++) {\r\n const low = lowStatements[i];\r\n const high = highStatements[i];\r\n if ((low.get() instanceof _statement_1.Unknown && !(high.get() instanceof _statement_1.Unknown))\r\n || high.findFirstExpression(Expressions.InlineData)) {\r\n if (highSyntax === undefined) {\r\n highSyntax = new syntax_1.SyntaxLogic(this.highReg, highSyntaxObj).run();\r\n }\r\n const issue = this.checkStatement(low, high, lowFile, highSyntax, highFile);\r\n if (issue) {\r\n ret.push(issue);\r\n }\r\n }\r\n }\r\n }\r\n return ret;\r\n }\r\n ////////////////////\r\n /** clones the orginal repository into highReg, and parses it with higher language version */\r\n initHighReg() {\r\n // use default configuration, ie. default target version\r\n const highConfig = config_1.Config.getDefault().get();\r\n const lowConfig = this.lowReg.getConfig().get();\r\n highConfig.syntax.errorNamespace = lowConfig.syntax.errorNamespace;\r\n highConfig.syntax.globalConstants = lowConfig.syntax.globalConstants;\r\n highConfig.syntax.globalMacros = lowConfig.syntax.globalMacros;\r\n this.highReg = new registry_1.Registry();\r\n for (const o of this.lowReg.getObjects()) {\r\n for (const f of o.getFiles()) {\r\n if (this.lowReg.isDependency(o) === true) {\r\n this.highReg.addDependency(f);\r\n }\r\n else {\r\n this.highReg.addFile(f);\r\n }\r\n }\r\n }\r\n this.highReg.parse();\r\n }\r\n /** applies one rule at a time, multiple iterations are required to transform complex statements */\r\n checkStatement(low, high, lowFile, highSyntax, highFile) {\r\n if (low.getFirstToken().getStart() instanceof position_1.VirtualPosition) {\r\n return undefined;\r\n }\r\n let found = this.downportEnum(low, high, lowFile, highSyntax, highFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.partiallyImplemented(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.raiseException(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.emptyKey(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.stringTemplateAlpha(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.moveWithOperator(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.moveWithSimpleValue(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.assignWithTable(low, high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportRefSimple(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportCorrespondingSimple(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportRef(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportLoopGroup(high, lowFile, highSyntax, highFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.callFunctionParameterSimple(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.moveWithTableTarget(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportSelectInline(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportSQLExtras(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineLoopInput(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineLoopTarget(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n let skipValue = false;\r\n let skipReduce = false;\r\n const valueBody = high.findFirstExpression(Expressions.ValueBody);\r\n const reduceBody = high.findFirstExpression(Expressions.ReduceBody);\r\n if (valueBody && reduceBody) {\r\n const valueToken = valueBody.getFirstToken();\r\n const reduceToken = reduceBody.getFirstToken();\r\n if (valueToken.getStart().isBefore(reduceToken.getStart())) {\r\n skipReduce = true;\r\n }\r\n else {\r\n skipValue = true;\r\n }\r\n }\r\n if (skipValue !== true) {\r\n found = this.outlineValue(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n }\r\n if (skipReduce !== true) {\r\n found = this.outlineReduce(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n }\r\n found = this.outlineSwitch(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineCast(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineConv(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineCond(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineCatchSimple(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineDataSimple(high, lowFile);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineData(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.outlineFS(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.newToCreateObject(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceXsdBool(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceLineFunctions(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.getReference(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceContains(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceMethodConditional(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceTableExpression(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceAppendExpression(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.replaceInsertExpression(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportMessage(high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n return undefined;\r\n }\r\n //////////////////////////////////////////\r\n downportSQLExtras(low, high, lowFile, _highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Select)\r\n && !(high.get() instanceof Statements.SelectLoop)\r\n && !(high.get() instanceof Statements.UpdateDatabase)\r\n && !(high.get() instanceof Statements.ModifyDatabase)\r\n && !(high.get() instanceof Statements.DeleteDatabase)\r\n && !(high.get() instanceof Statements.InsertDatabase)) {\r\n return undefined;\r\n }\r\n let fix = undefined;\r\n const addFix = (token) => {\r\n const add = edit_helper_1.EditHelper.deleteToken(lowFile, token);\r\n if (fix === undefined) {\r\n fix = add;\r\n }\r\n else {\r\n fix = edit_helper_1.EditHelper.merge(fix, add);\r\n }\r\n };\r\n const candidates = [high.findAllExpressionsRecursive(Expressions.SQLTarget),\r\n high.findAllExpressionsRecursive(Expressions.SQLSource),\r\n high.findAllExpressionsRecursive(Expressions.SQLSourceSimple)].flat();\r\n for (const c of candidates.reverse()) {\r\n if (c.getFirstToken() instanceof tokens_1.WAt\r\n || c.getFirstToken() instanceof tokens_1.At) {\r\n addFix(c.getFirstToken());\r\n }\r\n }\r\n for (const fieldList of high.findAllExpressionsMulti([Expressions.SQLFieldList, Expressions.SQLFieldListLoop], true)) {\r\n for (const token of fieldList.getDirectTokens()) {\r\n if (token.getStr() === \",\") {\r\n addFix(token);\r\n }\r\n }\r\n }\r\n if (fix !== undefined) {\r\n return issue_1.Issue.atToken(lowFile, low.getFirstToken(), \"SQL, remove @ and ,\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n for (const c of high.findAllExpressionsRecursive(Expressions.SQLIn)) {\r\n const children = c.getChildren();\r\n const first = children[1];\r\n if (!(first.get() instanceof tokens_1.WParenLeftW)) {\r\n continue;\r\n }\r\n const last = children[children.length - 1];\r\n if (last.get() instanceof tokens_1.WParenRightW || last.get() instanceof tokens_1.WParenRight) {\r\n const firstEnd = first.getFirstToken().getEnd();\r\n const endDelete = new position_1.Position(firstEnd.getRow(), firstEnd.getCol() + 1);\r\n const fix1 = edit_helper_1.EditHelper.deleteRange(lowFile, firstEnd, endDelete);\r\n const lastStart = last.getFirstToken().getStart();\r\n const startDelete = new position_1.Position(lastStart.getRow(), lastStart.getCol() - 1);\r\n const fix2 = edit_helper_1.EditHelper.deleteRange(lowFile, startDelete, lastStart);\r\n fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, low.getFirstToken(), \"SQL, remove spaces\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n downportSelectInline(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Select) && !(high.get() instanceof Statements.SelectLoop)) {\r\n return undefined;\r\n }\r\n // as first step outline the @DATA, note that void types are okay, as long the field names are specified\r\n let found = this.downportSelectSingleInline(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n found = this.downportSelectTableInline(low, high, lowFile, highSyntax);\r\n if (found) {\r\n return found;\r\n }\r\n return undefined;\r\n }\r\n downportSelectSingleInline(low, high, lowFile, _highSyntax) {\r\n var _a, _b, _c, _d;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const targets = ((_a = high.findFirstExpression(Expressions.SQLIntoStructure)) === null || _a === void 0 ? void 0 : _a.findDirectExpressions(Expressions.SQLTarget)) || [];\r\n if (targets.length !== 1) {\r\n return undefined;\r\n }\r\n const inlineData = targets[0].findFirstExpression(Expressions.InlineData);\r\n if (inlineData === undefined) {\r\n return undefined;\r\n }\r\n const sqlFrom = high.findAllExpressions(Expressions.SQLFromSource);\r\n if (sqlFrom.length !== 1) {\r\n return undefined;\r\n }\r\n const tableName = (_b = sqlFrom[0].findDirectExpression(Expressions.DatabaseTable)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (tableName === undefined) {\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let fieldList = high.findFirstExpression(Expressions.SQLFieldList);\r\n if (fieldList === undefined) {\r\n fieldList = high.findFirstExpression(Expressions.SQLFieldListLoop);\r\n }\r\n if (fieldList === undefined) {\r\n return undefined;\r\n }\r\n let fieldDefinition = \"\";\r\n const fields = fieldList.findAllExpressions(Expressions.SQLFieldName);\r\n const name = ((_c = inlineData.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"error\";\r\n if (fields.length === 1) {\r\n fieldDefinition = `DATA ${name} TYPE ${tableName}-${fields[0].concatTokens()}.`;\r\n }\r\n else if (fieldList.concatTokens() === \"*\") {\r\n fieldDefinition = `DATA ${name} TYPE ${tableName}.`;\r\n }\r\n else if (fieldList.concatTokens().toUpperCase() === \"COUNT( * )\") {\r\n fieldDefinition = `DATA ${name} TYPE i.`;\r\n }\r\n else if (fieldList.getChildren().length === 1 && fieldList.getChildren()[0].get() instanceof Expressions.SQLAggregation) {\r\n const c = fieldList.getChildren()[0];\r\n if (c instanceof nodes_1.ExpressionNode) {\r\n const concat = (_d = c.findFirstExpression(Expressions.SQLArithmetics)) === null || _d === void 0 ? void 0 : _d.concatTokens();\r\n fieldDefinition = `DATA ${name} TYPE ${tableName}-${concat}.`;\r\n }\r\n }\r\n else {\r\n for (const f of fields) {\r\n const fieldName = f.concatTokens();\r\n fieldDefinition += indentation + \" \" + fieldName + \" TYPE \" + tableName + \"-\" + fieldName + \",\\n\";\r\n }\r\n fieldDefinition = `DATA: BEGIN OF ${name},\r\n${fieldDefinition}${indentation} END OF ${name}.`;\r\n }\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `${fieldDefinition}\r\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, inlineData.getFirstToken(), \"Outline SELECT @DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportSelectTableInline(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const targets = ((_a = high.findFirstExpression(Expressions.SQLIntoTable)) === null || _a === void 0 ? void 0 : _a.findDirectExpressions(Expressions.SQLTarget)) || [];\r\n if (targets.length !== 1) {\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const inlineData = targets[0].findFirstExpression(Expressions.InlineData);\r\n if (inlineData === undefined) {\r\n return undefined;\r\n }\r\n const sqlFrom = high.findAllExpressions(Expressions.SQLFromSource);\r\n if (sqlFrom.length === 0) {\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Error outlining, sqlFrom not found\", this.getMetadata().key, this.conf.severity);\r\n }\r\n let tableName = (_b = sqlFrom[0].findDirectExpression(Expressions.DatabaseTable)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (tableName === undefined) {\r\n return undefined;\r\n }\r\n const fieldList = high.findFirstExpression(Expressions.SQLFieldList);\r\n if (fieldList === undefined) {\r\n return undefined;\r\n }\r\n let fieldDefinitions = \"\";\r\n for (const f of fieldList.findAllExpressions(Expressions.SQLFieldName)) {\r\n let fieldName = f.concatTokens();\r\n if (fieldName.includes(\"~\")) {\r\n const split = fieldName.split(\"~\");\r\n tableName = split[0];\r\n fieldName = split[1];\r\n }\r\n fieldDefinitions += indentation + \" \" + fieldName + \" TYPE \" + tableName + \"-\" + fieldName + \",\\n\";\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const name = ((_c = inlineData.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"error\";\r\n let fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `TYPES: BEGIN OF ${uniqueName},\r\n${fieldDefinitions}${indentation} END OF ${uniqueName}.\r\n${indentation}DATA ${name} TYPE STANDARD TABLE OF ${uniqueName} WITH DEFAULT KEY.\r\n${indentation}`);\r\n if (fieldDefinitions === \"\") {\r\n fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getStart(), `DATA ${name} TYPE STANDARD TABLE OF ${tableName} WITH DEFAULT KEY.\r\n${indentation}`);\r\n }\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inlineData.getFirstToken().getStart(), inlineData.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, inlineData.getFirstToken(), \"Outline SELECT @DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportMessage(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.Message)) {\r\n return undefined;\r\n }\r\n const foundWith = high.findExpressionAfterToken(\"WITH\");\r\n if (foundWith === undefined) {\r\n return undefined;\r\n }\r\n const likeSource = high.findExpressionAfterToken(\"LIKE\");\r\n for (const s of high.findAllExpressions(Expressions.Source)) {\r\n if (s === likeSource) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n const code = `DATA(${uniqueName}) = ${s.concatTokens()}.\\n${indentation}`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, s.getFirstToken().getStart(), s.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Refactor MESSAGE WITH source\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n replaceAppendExpression(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.Append)) {\r\n return undefined;\r\n }\r\n const children = high.getChildren();\r\n if (children[1].get() instanceof Expressions.Source) {\r\n const source = children[1];\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${target === null || target === void 0 ? void 0 : target.concatTokens()}.\r\n${indentation}${uniqueName} = ${source.concatTokens()}.\\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, source.getFirstToken().getStart(), source.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline APPEND source expression\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n replaceInsertExpression(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.InsertInternal)) {\r\n return undefined;\r\n }\r\n const children = high.getChildren();\r\n if (children[1].get() instanceof Expressions.Source) {\r\n const source = children[1];\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${target === null || target === void 0 ? void 0 : target.concatTokens()}.\r\n${indentation}${uniqueName} = ${source.concatTokens()}.\\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, source.getFirstToken().getStart(), source.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline INSERT source expression\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n replaceTableExpression(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const fieldChain of high.findAllExpressionsRecursive(Expressions.FieldChain)) {\r\n const tableExpression = fieldChain.findDirectExpression(Expressions.TableExpression);\r\n if (tableExpression === undefined) {\r\n continue;\r\n }\r\n const concat = high.concatTokens().toUpperCase();\r\n if (concat.includes(\" LINE_EXISTS( \") || concat.includes(\" LINE_INDEX( \")) {\r\n // note: line_exists() must be replaced before handling table expressions\r\n continue;\r\n }\r\n let pre = \"\";\r\n let startToken = undefined;\r\n for (const child of fieldChain.getChildren()) {\r\n if (startToken === undefined) {\r\n startToken = child.getFirstToken();\r\n }\r\n else if (child === tableExpression) {\r\n break;\r\n }\r\n pre += child.concatTokens();\r\n }\r\n if (startToken === undefined) {\r\n continue;\r\n }\r\n const condition = this.tableCondition(tableExpression);\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const tabixBackup = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = high.getFirstToken();\r\n // note that the tabix restore should be done before throwing the exception\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${uniqueName} LIKE LINE OF ${pre}.\r\n${indentation}DATA ${tabixBackup} LIKE sy-tabix.\r\n${indentation}${tabixBackup} = sy-tabix.\r\n${indentation}READ TABLE ${pre} ${condition}INTO ${uniqueName}.\r\n${indentation}sy-tabix = ${tabixBackup}.\r\n${indentation}IF sy-subrc <> 0.\r\n${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.\r\n${indentation}ENDIF.\r\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, startToken.getStart(), tableExpression.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline table expression\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n tableCondition(tableExpression) {\r\n let condition = \"\";\r\n let keyName = \"\";\r\n for (const c of tableExpression.getChildren() || []) {\r\n if (c.getFirstToken().getStr() === \"[\" || c.getFirstToken().getStr() === \"]\") {\r\n continue;\r\n }\r\n else if (c.get() instanceof Expressions.ComponentChainSimple && condition === \"\") {\r\n if (keyName === \"\") {\r\n condition = \"WITH KEY \";\r\n }\r\n else {\r\n condition = \"WITH TABLE KEY \" + keyName + \" COMPONENTS \";\r\n }\r\n }\r\n else if (c.get() instanceof Expressions.Source && condition === \"\") {\r\n condition = \"INDEX \";\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.getFirstToken().getStr().toUpperCase() === \"KEY\") {\r\n continue;\r\n }\r\n else if (c.get() instanceof Expressions.SimpleName) {\r\n keyName = c.concatTokens();\r\n continue;\r\n }\r\n condition += c.concatTokens() + \" \";\r\n }\r\n return condition;\r\n }\r\n outlineCatchSimple(node, lowFile) {\r\n // outlines \"CATCH cx_bcs INTO DATA(lx_bcs_excep).\", note that this does not need to look at types\r\n var _a, _b;\r\n if (!(node.get() instanceof Statements.Catch)) {\r\n return undefined;\r\n }\r\n const target = node.findFirstExpression(Expressions.Target);\r\n if (!(((_a = target === null || target === void 0 ? void 0 : target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.InlineData)) {\r\n return undefined;\r\n }\r\n const classNames = node.findDirectExpressions(Expressions.ClassName);\r\n if (classNames.length !== 1) {\r\n return undefined;\r\n }\r\n const className = classNames[0].concatTokens();\r\n const targetName = (_b = target.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const code = ` DATA ${targetName} TYPE REF TO ${className}.\r\n${indentation}CATCH ${className} INTO ${targetName}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), code);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n outlineDataSimple(node, lowFile) {\r\n // outlines \"DATA(ls_msg) = temp1.\", note that this does not need to look at types\r\n var _a, _b, _c;\r\n if (!(node.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const target = node.findFirstExpression(Expressions.Target);\r\n if (!(((_a = target === null || target === void 0 ? void 0 : target.getFirstChild()) === null || _a === void 0 ? void 0 : _a.get()) instanceof Expressions.InlineData)) {\r\n return undefined;\r\n }\r\n let type = \"\";\r\n const source = node.findFirstExpression(Expressions.Source);\r\n if (source === undefined) {\r\n return undefined;\r\n }\r\n else if (source.getChildren().length !== 1) {\r\n return undefined;\r\n }\r\n else if (!(((_b = source.getFirstChild()) === null || _b === void 0 ? void 0 : _b.get()) instanceof Expressions.FieldChain)) {\r\n return undefined;\r\n }\r\n else if (source.findFirstExpression(Expressions.FieldOffset)) {\r\n return undefined;\r\n }\r\n else if (source.findFirstExpression(Expressions.FieldLength)) {\r\n return undefined;\r\n }\r\n else if (source.findFirstExpression(Expressions.TableExpression)) {\r\n const chain = source.findDirectExpression(Expressions.FieldChain);\r\n if (chain !== undefined\r\n && chain.getChildren().length === 2\r\n && chain.getChildren()[0].get() instanceof Expressions.SourceField\r\n && chain.getChildren()[1].get() instanceof Expressions.TableExpression) {\r\n type = \"LINE OF \" + chain.getChildren()[0].concatTokens();\r\n }\r\n else {\r\n return undefined;\r\n }\r\n }\r\n else {\r\n type = source.concatTokens();\r\n }\r\n const targetName = (_c = target.findFirstExpression(Expressions.TargetField)) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const firstToken = node.getFirstToken();\r\n const lastToken = node.getLastToken();\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, firstToken.getStart(), `DATA ${targetName} LIKE ${type}.\\n${indentation}`);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), lastToken.getEnd(), `${targetName} = ${source.concatTokens()}.`);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n partiallyImplemented(node, lowFile) {\r\n if (node.get() instanceof Statements.InterfaceDef) {\r\n const partially = node.findDirectTokenByText(\"PARTIALLY\");\r\n if (partially === undefined) {\r\n return undefined;\r\n }\r\n const implemented = node.findDirectTokenByText(\"IMPLEMENTED\");\r\n if (implemented === undefined) {\r\n return undefined;\r\n }\r\n const fix = edit_helper_1.EditHelper.deleteRange(lowFile, partially.getStart(), implemented.getEnd());\r\n return issue_1.Issue.atToken(lowFile, partially, \"Downport PARTIALLY IMPLEMENTED\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n raiseException(node, lowFile, highSyntax) {\r\n /*\r\n Note: IF_T100_DYN_MSG does not exist in 702, so this rule is mostly relevant for the transpiler\r\n \r\n DATA foo LIKE if_t100_message=>t100key.\r\n foo-msgid = 'ZHVAM'.\r\n foo-msgno = '001'.\r\n foo-attr1 = 'IF_T100_DYN_MSG~MSGV1'.\r\n foo-attr2 = 'IF_T100_DYN_MSG~MSGV2'.\r\n foo-attr3 = 'IF_T100_DYN_MSG~MSGV3'.\r\n foo-attr4 = 'IF_T100_DYN_MSG~MSGV4'.\r\n DATA bar TYPE REF TO zcl_hvam_exception.\r\n CREATE OBJECT bar EXPORTING textid = foo.\r\n bar->if_t100_dyn_msg~msgty = 'E'.\r\n bar->if_t100_dyn_msg~msgv1 = 'abc'.\r\n bar->if_t100_dyn_msg~msgv2 = 'abc'.\r\n bar->if_t100_dyn_msg~msgv3 = 'abc'.\r\n bar->if_t100_dyn_msg~msgv4 = 'abc'.\r\n RAISE EXCEPTION bar.\r\n */\r\n var _a, _b, _c;\r\n if (!(node.get() instanceof Statements.Raise)) {\r\n return undefined;\r\n }\r\n let id = undefined;\r\n let number = undefined;\r\n let startToken = node.findDirectTokenByText(\"ID\");\r\n if (startToken) {\r\n const sources = node.findDirectExpressions(Expressions.Source);\r\n id = sources[0].concatTokens();\r\n const numberExpression = node.findExpressionAfterToken(\"NUMBER\");\r\n if (numberExpression === undefined) {\r\n throw \"downport raiseException, could not find number\";\r\n }\r\n number = numberExpression.concatTokens();\r\n if (numberExpression.get() instanceof Expressions.MessageNumber) {\r\n number = \"'\" + number + \"'\";\r\n }\r\n }\r\n else {\r\n const s = node.findDirectExpression(Expressions.MessageSource);\r\n if (s === undefined) {\r\n return undefined;\r\n }\r\n id = \"'\" + ((_a = s.findDirectExpression(Expressions.MessageClass)) === null || _a === void 0 ? void 0 : _a.concatTokens()) + \"'\";\r\n number = \"'\" + ((_b = s.findDirectExpression(Expressions.MessageTypeAndNumber)) === null || _b === void 0 ? void 0 : _b.concatTokens().substring(1)) + \"'\";\r\n startToken = node.getFirstToken();\r\n }\r\n const className = ((_c = node.findDirectExpression(Expressions.ClassName)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"ERROR\";\r\n const uniqueName1 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const uniqueName2 = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const abap = `DATA ${uniqueName1} LIKE if_t100_message=>t100key.\r\n${indentation}${uniqueName1}-msgid = ${id === null || id === void 0 ? void 0 : id.toUpperCase()}.\r\n${indentation}${uniqueName1}-msgno = ${number}.\r\n${indentation}DATA ${uniqueName2} TYPE REF TO ${className}.\r\n${indentation}CREATE OBJECT ${uniqueName2} EXPORTING textid = ${uniqueName1}.\r\n${indentation}RAISE EXCEPTION ${uniqueName2}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, node.getStart(), node.getEnd(), abap);\r\n return issue_1.Issue.atToken(lowFile, startToken, \"Downport RAISE MESSAGE\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n emptyKey(low, node, lowFile) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (let i of node.findAllExpressions(Expressions.TypeTable)) {\r\n const key = i.findDirectExpression(Expressions.TypeTableKey);\r\n if (key === undefined) {\r\n continue;\r\n }\r\n i = key;\r\n const concat = i.concatTokens();\r\n if (concat.toUpperCase().includes(\"WITH EMPTY KEY\") === false) {\r\n continue;\r\n }\r\n const token = i.findDirectTokenByText(\"EMPTY\");\r\n if (token === undefined) {\r\n continue;\r\n }\r\n const fix = edit_helper_1.EditHelper.replaceToken(lowFile, token, \"DEFAULT\");\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport EMPTY KEY\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n callFunctionParameterSimple(high, lowFile, highSyntax) {\r\n if (!(high.get() instanceof Statements.CallFunction)) {\r\n return undefined;\r\n }\r\n let found = undefined;\r\n for (const p of high.findAllExpressions(Expressions.FunctionExportingParameter)) {\r\n found = p.findDirectExpression(Expressions.Source);\r\n if (found && (found.findDirectExpression(Expressions.FieldChain)\r\n || found.findDirectExpression(Expressions.Constant)\r\n || found.findDirectExpression(Expressions.TextElement))) {\r\n // its actually simple, ok\r\n found = undefined;\r\n }\r\n else if (found !== undefined) {\r\n break;\r\n }\r\n }\r\n if (found === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const code = `DATA(${uniqueName}) = ${found.concatTokens()}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, found.getFirstToken().getStart(), found.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, call function parameter\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportCorrespondingSimple(high, lowFile) {\r\n var _a;\r\n if (!(high.get() instanceof Statements.Move)\r\n || high.getChildren().length !== 4\r\n || high.getChildren()[2].getFirstToken().getStr().toUpperCase() !== \"CORRESPONDING\") {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n console.dir(\"sdf1\");\r\n return undefined;\r\n }\r\n const sourceRef = (_a = high.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.findFirstExpression(Expressions.CorrespondingBody);\r\n if (sourceRef === undefined || sourceRef.getChildren().length !== 1) {\r\n return;\r\n }\r\n const code = `MOVE-CORRESPONDING ${sourceRef.concatTokens()} TO ${target.concatTokens()}`;\r\n const start = high.getFirstToken().getStart();\r\n const end = high.getLastToken().getStart();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, simple CORRESPONDING move\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportRefSimple(high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(high.get() instanceof Statements.Move)\r\n || high.getChildren().length !== 4\r\n || high.getChildren()[2].getFirstToken().getStr().toUpperCase() !== \"REF\") {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const sourceRef = (_a = high.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Source);\r\n if (sourceRef === undefined\r\n || sourceRef.getChildren().length !== 1) {\r\n return undefined;\r\n }\r\n let code = \"\";\r\n if (sourceRef.findFirstExpression(Expressions.TableExpression)) {\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n code = `ASSIGN ${sourceRef.concatTokens()} TO FIELD-SYMBOL(<${uniqueName}>).\r\nIF sy-subrc <> 0.\r\n RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.\r\nENDIF.\r\nGET REFERENCE OF <${uniqueName}> INTO ${target.concatTokens()}`;\r\n }\r\n else {\r\n code = `GET REFERENCE OF ${sourceRef.concatTokens()} INTO ${target.concatTokens()}`;\r\n }\r\n const start = high.getFirstToken().getStart();\r\n const end = high.getLastToken().getStart();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, simple REF move\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportLoopGroup(high, lowFile, highSyntax, highFile) {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;\r\n if (!(high.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n const group = high.findDirectExpression(Expressions.LoopGroupBy);\r\n if (group === undefined) {\r\n return undefined;\r\n }\r\n const groupTargetName = ((_a = group.findFirstExpression(Expressions.TargetField)) === null || _a === void 0 ? void 0 : _a.concatTokens())\r\n || ((_b = group.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _b === void 0 ? void 0 : _b.concatTokens().replace(\"<\", \"_\").replace(\">\", \"_\"))\r\n || \"nameNotFound\";\r\n const loopSourceName = ((_c = high.findFirstExpression(Expressions.SimpleSource2)) === null || _c === void 0 ? void 0 : _c.concatTokens()) || \"nameNotFound\";\r\n const loopTargetName = ((_d = high.findFirstExpression(Expressions.TargetField)) === null || _d === void 0 ? void 0 : _d.concatTokens())\r\n || ((_e = high.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _e === void 0 ? void 0 : _e.concatTokens())\r\n || \"nameNotFound\";\r\n const groupTarget = ((_f = group.findDirectExpression(Expressions.LoopGroupByTarget)) === null || _f === void 0 ? void 0 : _f.concatTokens()) || \"\";\r\n const isReference = (_g = high.findFirstExpression(Expressions.LoopTarget)) === null || _g === void 0 ? void 0 : _g.concatTokens().toUpperCase().startsWith(\"REFERENCE INTO \");\r\n let loopSourceRowType = \"typeNotFound\";\r\n const spag = highSyntax.spaghetti.lookupPosition(high.getFirstToken().getStart(), lowFile.getFilename());\r\n if (spag !== undefined) {\r\n const found = spag.findVariable(loopSourceName);\r\n const tt = found === null || found === void 0 ? void 0 : found.getType();\r\n if (tt instanceof basic_1.TableType) {\r\n loopSourceRowType = tt.getRowType().getQualifiedName() || \"typeNotFound\";\r\n }\r\n }\r\n let code = `TYPES: BEGIN OF ${groupTargetName}type,\\n`;\r\n let condition = \"\";\r\n let groupCountName = undefined;\r\n let groupIndexName = undefined;\r\n for (const c of group.findAllExpressions(Expressions.LoopGroupByComponent)) {\r\n const name = c.findFirstExpression(Expressions.ComponentName);\r\n let type = ((_h = c.findFirstExpression(Expressions.Source)) === null || _h === void 0 ? void 0 : _h.concatTokens()) || \"todo\";\r\n if ((_j = c.concatTokens()) === null || _j === void 0 ? void 0 : _j.toUpperCase().endsWith(\" = GROUP SIZE\")) {\r\n type = \"i\";\r\n groupCountName = name === null || name === void 0 ? void 0 : name.concatTokens();\r\n }\r\n else if ((_k = c.concatTokens()) === null || _k === void 0 ? void 0 : _k.toUpperCase().endsWith(\" = GROUP INDEX\")) {\r\n type = \"i\";\r\n groupIndexName = name === null || name === void 0 ? void 0 : name.concatTokens();\r\n }\r\n else {\r\n condition += c.concatTokens();\r\n type = type.replace(loopTargetName, loopSourceRowType);\r\n type = type.replace(\"->\", \"-\");\r\n }\r\n code += ` ${name === null || name === void 0 ? void 0 : name.concatTokens()} TYPE ${type},\\n`;\r\n }\r\n const s = group.findDirectExpression(Expressions.Source);\r\n let singleName = \"\";\r\n if (s) {\r\n let type = s.concatTokens();\r\n type = type.replace(loopTargetName, loopSourceRowType);\r\n type = type.replace(\"->\", \"-\");\r\n singleName = s.concatTokens().split(\"-\")[1];\r\n code += ` ${singleName} TYPE ${type},\\n`;\r\n condition = singleName + \" = \" + s.concatTokens();\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const uniqueFS = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const uniqueNameIndex = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n code += ` items LIKE ${loopSourceName},\r\n END OF ${groupTargetName}type.\r\nDATA ${groupTargetName}tab TYPE STANDARD TABLE OF ${groupTargetName}type WITH DEFAULT KEY.\r\nDATA ${uniqueName} LIKE LINE OF ${groupTargetName}tab.\r\nLOOP AT ${loopSourceName} ${(_l = high.findFirstExpression(Expressions.LoopTarget)) === null || _l === void 0 ? void 0 : _l.concatTokens()}.\\n`;\r\n if (groupIndexName !== undefined) {\r\n code += `DATA(${uniqueNameIndex}) = sy-tabix.\\n`;\r\n }\r\n code += `READ TABLE ${groupTargetName}tab ASSIGNING FIELD-SYMBOL(<${uniqueFS}>) WITH KEY ${condition}.\r\nIF sy-subrc = 0.\\n`;\r\n if (groupCountName !== undefined) {\r\n code += ` <${uniqueFS}>-${groupCountName} = <${uniqueFS}>-${groupCountName} + 1.\\n`;\r\n }\r\n code += ` INSERT ${loopTargetName}${isReference ? \"->*\" : \"\"} INTO TABLE <${uniqueFS}>-items.\r\nELSE.\\n`;\r\n code += ` CLEAR ${uniqueName}.\\n`;\r\n for (const c of group.findAllExpressions(Expressions.LoopGroupByComponent)) {\r\n const concat = c.concatTokens();\r\n if (concat.endsWith(\" GROUP INDEX\")) {\r\n code += ` ${uniqueName}-${groupIndexName} = ${uniqueNameIndex}.\\n`;\r\n }\r\n else {\r\n code += ` ${uniqueName}-${concat.replace(\"GROUP SIZE\", \"1\")}.\\n`;\r\n }\r\n }\r\n if (singleName !== \"\") {\r\n code += ` ${uniqueName}-${singleName} = ${loopTargetName}-${singleName}.\\n`;\r\n }\r\n code += ` INSERT ${loopTargetName}${isReference ? \"->*\" : \"\"} INTO TABLE ${uniqueName}-items.\\n`;\r\n code += ` INSERT ${uniqueName} INTO TABLE ${groupTargetName}tab.\\n`;\r\n code += `ENDIF.\r\nENDLOOP.\r\nLOOP AT ${groupTargetName}tab ${groupTarget}.`;\r\n let fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), code);\r\n for (const l of ((_m = highFile.getStructure()) === null || _m === void 0 ? void 0 : _m.findAllStructures(Structures.Loop)) || []) {\r\n // make sure to find the correct/current loop statement\r\n if (l.findDirectStatement(Statements.Loop) !== high) {\r\n continue;\r\n }\r\n for (const loop of l.findAllStatements(Statements.Loop)) {\r\n if ((_o = loop.concatTokens()) === null || _o === void 0 ? void 0 : _o.toUpperCase().startsWith(\"LOOP AT GROUP \")) {\r\n const subLoopSource = loop.findFirstExpression(Expressions.SimpleSource2);\r\n if (subLoopSource === undefined) {\r\n continue;\r\n }\r\n const subLoopSourceName = (subLoopSource === null || subLoopSource === void 0 ? void 0 : subLoopSource.concatTokens()) || \"nameNotFound\";\r\n const subCode = `LOOP AT ${subLoopSourceName}${isReference ? \"->\" : \"-\"}items`;\r\n const subFix = edit_helper_1.EditHelper.replaceRange(lowFile, loop.getFirstToken().getStart(), subLoopSource.getLastToken().getEnd(), subCode);\r\n fix = edit_helper_1.EditHelper.merge(subFix, fix);\r\n }\r\n }\r\n }\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, LOOP GROUP\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n downportRef(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n let found = undefined;\r\n for (const s of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n if (s.getFirstToken().getStr().toUpperCase() === \"REF\"\r\n && s.findDirectExpression(Expressions.TypeNameOrInfer)) {\r\n found = s;\r\n }\r\n }\r\n if (found === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const code = `DATA(${uniqueName}) = ${found.concatTokens()}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, found.getFirstToken().getStart(), found.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, REF\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n assignWithTable(low, high, lowFile) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Assign)) {\r\n return undefined;\r\n }\r\n else if (high.getChildren().length !== 5) {\r\n return undefined;\r\n }\r\n const fieldChain = (_b = (_a = high.findDirectExpression(Expressions.AssignSource)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.findDirectExpression(Expressions.FieldChain);\r\n if ((fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren().length) !== 2) {\r\n return undefined;\r\n }\r\n const tableExpression = fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren()[1];\r\n if (!(tableExpression.get() instanceof Expressions.TableExpression)\r\n || !(tableExpression instanceof nodes_1.ExpressionNode)) {\r\n return undefined;\r\n }\r\n let condition = \"\";\r\n if (tableExpression.getChildren().length === 3) {\r\n const index = tableExpression.findDirectExpression(Expressions.Source);\r\n if (index === undefined) {\r\n return undefined;\r\n }\r\n condition = `INDEX ${index.concatTokens()}`;\r\n }\r\n else {\r\n let concat = tableExpression.concatTokens();\r\n concat = concat.substring(2);\r\n concat = concat.substring(0, concat.length - 2);\r\n condition = `WITH KEY ${concat}`;\r\n }\r\n const fsTarget = high.findDirectExpression(Expressions.FSTarget);\r\n const code = `READ TABLE ${fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren()[0].concatTokens()} ${condition} ASSIGNING ${fsTarget === null || fsTarget === void 0 ? void 0 : fsTarget.concatTokens()}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, ASSIGN table expr\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n moveWithSimpleValue(low, high, lowFile) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Move)\r\n || high.getChildren().length !== 4) {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const source = high.findDirectExpression(Expressions.Source);\r\n if (source === undefined) {\r\n return undefined;\r\n }\r\n const field = target.findDirectExpression(Expressions.TargetField);\r\n if (field === undefined) {\r\n return;\r\n }\r\n const valueBody = source.findDirectExpression(Expressions.ValueBody);\r\n if (valueBody === undefined) {\r\n return;\r\n }\r\n const fieldAssignments = valueBody.findDirectExpressions(Expressions.FieldAssignment);\r\n if (fieldAssignments.length === 0) {\r\n return;\r\n }\r\n else if (fieldAssignments.length !== valueBody.getChildren().length) {\r\n return;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let code = `CLEAR ${target.concatTokens()}.\\n`;\r\n for (const fieldAssignment of fieldAssignments) {\r\n code += indentation + target.concatTokens() + \"-\" + fieldAssignment.concatTokens() + `.\\n`;\r\n }\r\n code = code.trimEnd();\r\n const start = high.getFirstToken().getStart();\r\n const end = high.getLastToken().getEnd();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, simple move\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n // note, downporting ENUM does not give the correct types, but it will work in most cases?\r\n downportEnum(_low, high, lowFile, _highSyntax, highFile) {\r\n var _a, _b, _c, _d, _e;\r\n if (!(high.get() instanceof Statements.TypeEnumBegin)) {\r\n return undefined;\r\n }\r\n const enumStructure = (_a = highFile.getStructure()) === null || _a === void 0 ? void 0 : _a.findFirstStructure(Structures.TypeEnum);\r\n if (enumStructure === undefined) {\r\n return undefined;\r\n }\r\n if (enumStructure.getFirstStatement() !== high) {\r\n return undefined;\r\n }\r\n const enumName = (_b = high.findExpressionAfterToken(\"ENUM\")) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const structureName = (_c = high.findExpressionAfterToken(\"STRUCTURE\")) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n // all ENUMS are char like?\r\n let code = `TYPES ${enumName} TYPE string.\r\nCONSTANTS: BEGIN OF ${structureName},\\n`;\r\n let count = 1;\r\n for (const e of enumStructure.findDirectStatements(Statements.TypeEnum).concat(enumStructure.findDirectStatements(Statements.Type))) {\r\n const name = (_d = e.findFirstExpression(Expressions.NamespaceSimpleName)) === null || _d === void 0 ? void 0 : _d.concatTokens();\r\n let value = (_e = e.findFirstExpression(Expressions.Value)) === null || _e === void 0 ? void 0 : _e.concatTokens();\r\n if (value === undefined) {\r\n value = \"VALUE '\" + count++ + \"'\";\r\n }\r\n code += ` ${name} TYPE ${enumName} ${value},\\n`;\r\n }\r\n code += ` END OF ${structureName}.`;\r\n const start = enumStructure.getFirstToken().getStart();\r\n const end = enumStructure.getLastToken().getEnd();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport ENUM\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n moveWithTableTarget(low, high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n if (!(high.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const target = high.findDirectExpression(Expressions.Target);\r\n if (target === undefined) {\r\n return undefined;\r\n }\r\n const tableExpression = target.findDirectExpression(Expressions.TableExpression);\r\n if (tableExpression === undefined) {\r\n return undefined;\r\n }\r\n const index = tableExpression.findDirectExpression(Expressions.Source);\r\n if (index === undefined) {\r\n return undefined;\r\n }\r\n let uniqueName = this.uniqueName(low.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n uniqueName = `<${uniqueName}>`;\r\n const tName = target.concatTokens().split(\"[\")[0];\r\n const condition = this.tableCondition(tableExpression);\r\n const tabixBackup = this.uniqueName(low.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n // restore tabix before exeption\r\n const code = `FIELD-SYMBOLS ${uniqueName} LIKE LINE OF ${tName}.\r\n${indentation}DATA ${tabixBackup} LIKE sy-tabix.\r\n${indentation}${tabixBackup} = sy-tabix.\r\n${indentation}READ TABLE ${tName} ${condition}ASSIGNING ${uniqueName}.\r\n${indentation}sy-tabix = ${tabixBackup}.\r\n${indentation}IF sy-subrc <> 0.\r\n${indentation} RAISE EXCEPTION TYPE cx_sy_itab_line_not_found.\r\n${indentation}ENDIF.\r\n${indentation}${uniqueName}`;\r\n const start = target.getFirstToken().getStart();\r\n const end = (_a = tableExpression.findDirectTokenByText(\"]\")) === null || _a === void 0 ? void 0 : _a.getEnd();\r\n if (end === undefined) {\r\n return undefined;\r\n }\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport, move with table target\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n moveWithOperator(low, high, lowFile) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const children = high.getChildren();\r\n const secondChild = children[1];\r\n if (secondChild === undefined) {\r\n return undefined;\r\n }\r\n const op = secondChild.getFirstToken();\r\n let operator = \"\";\r\n switch (op.getStr()) {\r\n case \"+\":\r\n operator = \" + \";\r\n break;\r\n case \"-\":\r\n operator = \" - \";\r\n break;\r\n case \"/=\":\r\n operator = \" / \";\r\n break;\r\n case \"*=\":\r\n operator = \" * \";\r\n break;\r\n case \"&&=\":\r\n operator = \" && \";\r\n break;\r\n default:\r\n return undefined;\r\n }\r\n const target = (_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n if (target === undefined) {\r\n return;\r\n }\r\n const sourceStart = (_c = (_b = high.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.getFirstChild()) === null || _c === void 0 ? void 0 : _c.getFirstToken().getStart();\r\n if (sourceStart === undefined) {\r\n return;\r\n }\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, op.getStart(), sourceStart, \"= \" + target + operator);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Expand operator\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n // must be very simple string templates, like \"|{ ls_line-no ALPHA = IN }|\"\r\n stringTemplateAlpha(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Move)) {\r\n return undefined;\r\n }\r\n const topSource = high.findDirectExpression(Expressions.Source);\r\n if (topSource === undefined || topSource.getChildren().length !== 1) {\r\n return undefined;\r\n }\r\n let top = true;\r\n let child = topSource.getFirstChild();\r\n if (!(child.get() instanceof Expressions.StringTemplate)) {\r\n child = child.findFirstExpression(Expressions.StringTemplate);\r\n top = false;\r\n }\r\n if (child === undefined || !(child.get() instanceof Expressions.StringTemplate)) {\r\n return undefined;\r\n }\r\n const templateTokens = child.getChildren();\r\n if (templateTokens.length !== 3\r\n || templateTokens[0].getFirstToken().getStr() !== \"|{\"\r\n || templateTokens[2].getFirstToken().getStr() !== \"}|\") {\r\n return undefined;\r\n }\r\n const templateSource = child.findDirectExpression(Expressions.StringTemplateSource);\r\n const formatting = (_a = templateSource === null || templateSource === void 0 ? void 0 : templateSource.findDirectExpression(Expressions.StringTemplateFormatting)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n let functionName = \"\";\r\n switch (formatting) {\r\n case \"ALPHA = IN\":\r\n functionName = \"CONVERSION_EXIT_ALPHA_INPUT\";\r\n break;\r\n case \"ALPHA = OUT\":\r\n functionName = \"CONVERSION_EXIT_ALPHA_OUTPUT\";\r\n break;\r\n default:\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const source = (_b = templateSource === null || templateSource === void 0 ? void 0 : templateSource.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const topTarget = (_c = high.findDirectExpression(Expressions.Target)) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n if (top === false) {\r\n const code = `DATA ${uniqueName} TYPE string.\r\n${indentation}CALL FUNCTION '${functionName}'\r\n${indentation} EXPORTING\r\n${indentation} input = ${source}\r\n${indentation} IMPORTING\r\n${indentation} output = ${uniqueName}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, child.getFirstToken().getStart(), child.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport ALPHA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n else {\r\n const code = `CALL FUNCTION '${functionName}'\r\n${indentation} EXPORTING\r\n${indentation} input = ${source}\r\n${indentation} IMPORTING\r\n${indentation} output = ${topTarget}.`;\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), code);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Downport ALPHA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n outlineLoopInput(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n else if (!(high.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n else if (high.findDirectExpression(Expressions.SimpleSource2)) {\r\n return undefined;\r\n }\r\n // the first Source must be outlined\r\n const s = high.findDirectExpression(Expressions.Source);\r\n if (s === undefined) {\r\n return undefined;\r\n }\r\n const uniqueName = this.uniqueName(high.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const code = `DATA(${uniqueName}) = ${s.concatTokens()}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, s.getFirstToken().getStart(), s.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Outline LOOP input\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n outlineLoopTarget(node, lowFile, _highSyntax) {\r\n var _a, _b, _c, _d, _e, _f, _g;\r\n // also allows outlining of voided types\r\n if (!(node.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n const sourceName = (_a = node.findDirectExpression(Expressions.SimpleSource2)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n if (sourceName === undefined) {\r\n return undefined;\r\n }\r\n const concat = node.concatTokens().toUpperCase();\r\n if (concat.includes(\" REFERENCE INTO \")\r\n || concat.includes(\" GROUP BY \")\r\n || concat.startsWith(\"LOOP AT GROUP \")) {\r\n return undefined;\r\n }\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const dataTarget = (_c = (_b = node.findDirectExpression(Expressions.LoopTarget)) === null || _b === void 0 ? void 0 : _b.findDirectExpression(Expressions.Target)) === null || _c === void 0 ? void 0 : _c.findDirectExpression(Expressions.InlineData);\r\n if (dataTarget) {\r\n const targetName = ((_d = dataTarget.findDirectExpression(Expressions.TargetField)) === null || _d === void 0 ? void 0 : _d.concatTokens()) || \"DOWNPORT_ERROR\";\r\n const code = `DATA ${targetName} LIKE LINE OF ${sourceName}.\\n${indentation}`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, dataTarget.getFirstToken().getStart(), dataTarget.getLastToken().getEnd(), targetName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline LOOP data target\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n const fsTarget = (_f = (_e = node.findDirectExpression(Expressions.LoopTarget)) === null || _e === void 0 ? void 0 : _e.findDirectExpression(Expressions.FSTarget)) === null || _f === void 0 ? void 0 : _f.findDirectExpression(Expressions.InlineFS);\r\n if (fsTarget) {\r\n const targetName = ((_g = fsTarget.findDirectExpression(Expressions.TargetFieldSymbol)) === null || _g === void 0 ? void 0 : _g.concatTokens()) || \"DOWNPORT_ERROR\";\r\n const code = `FIELD-SYMBOLS ${targetName} LIKE LINE OF ${sourceName}.\\n${indentation}`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, fsTarget.getFirstToken().getStart(), fsTarget.getLastToken().getEnd(), targetName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, node.getFirstToken(), \"Outline LOOP fs target\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineFor(forLoop, indentation, lowFile, highSyntax) {\r\n var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;\r\n let body = \"\";\r\n let end = \"\";\r\n const loopSource = (_a = forLoop.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n let loopTargetField = (_b = forLoop.findFirstExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const of = (_c = forLoop.findExpressionAfterToken(\"OF\")) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n if (of !== undefined) {\r\n loopTargetField = of;\r\n }\r\n if (((_e = (_d = forLoop.findDirectExpression(Expressions.InlineLoopDefinition)) === null || _d === void 0 ? void 0 : _d.getFirstChild()) === null || _e === void 0 ? void 0 : _e.get()) instanceof Expressions.TargetFieldSymbol) {\r\n loopTargetField = undefined;\r\n }\r\n let cond = ((_f = forLoop.findDirectExpression(Expressions.ComponentCond)) === null || _f === void 0 ? void 0 : _f.concatTokens()) || \"\";\r\n if (cond !== \"\") {\r\n cond = \" WHERE \" + cond;\r\n }\r\n const loop = forLoop.findDirectExpression(Expressions.InlineLoopDefinition);\r\n const indexInto = (_g = loop === null || loop === void 0 ? void 0 : loop.findExpressionAfterToken(\"INTO\")) === null || _g === void 0 ? void 0 : _g.concatTokens();\r\n if (forLoop.findDirectTokenByText(\"UNTIL\")\r\n || forLoop.findDirectTokenByText(\"WHILE\")) {\r\n const fieldDef = forLoop.findDirectExpression(Expressions.InlineFieldDefinition);\r\n const field = (_h = fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.findFirstExpression(Expressions.Field)) === null || _h === void 0 ? void 0 : _h.concatTokens();\r\n const indexBackup = this.uniqueName(forLoop.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n body += indentation + \"DATA \" + field + \" TYPE i.\\n\";\r\n const second = fieldDef === null || fieldDef === void 0 ? void 0 : fieldDef.getChildren()[2];\r\n if ((second === null || second === void 0 ? void 0 : second.get()) instanceof Expressions.Source) {\r\n body += indentation + field + \" = \" + second.concatTokens() + \".\\n\";\r\n }\r\n const not = forLoop.findDirectTokenByText(\"UNTIL\") ? \" NOT\" : \"\";\r\n const cond = forLoop.findFirstExpression(Expressions.Cond);\r\n body += indentation + `DATA ${indexBackup} LIKE sy-index.\\n`;\r\n body += indentation + `${indexBackup} = sy-index.\\n`;\r\n body += indentation + `WHILE${not} ${cond === null || cond === void 0 ? void 0 : cond.concatTokens()}.\\n`;\r\n body += indentation + ` sy-index = ${indexBackup}.\\n`;\r\n const then = forLoop.findExpressionAfterToken(\"THEN\");\r\n if (then) {\r\n end += ` ${field} = ${then.concatTokens()}.\\n`;\r\n }\r\n else {\r\n end += ` ${field} = ${field} + 1.\\n`;\r\n }\r\n end += indentation + \"ENDWHILE\";\r\n }\r\n else if (loopTargetField !== undefined) {\r\n let from = (_j = forLoop.findExpressionAfterToken(\"FROM\")) === null || _j === void 0 ? void 0 : _j.concatTokens();\r\n from = from ? \" FROM \" + from : \"\";\r\n let to = (_k = forLoop.findExpressionAfterToken(\"TO\")) === null || _k === void 0 ? void 0 : _k.concatTokens();\r\n to = to ? \" TO \" + to : \"\";\r\n let gby = \"\";\r\n for (const lg of forLoop.findDirectExpressions(Expressions.LoopGroupByComponent)) {\r\n if (gby !== \"\") {\r\n gby += \" \";\r\n }\r\n gby += lg.concatTokens();\r\n }\r\n if (gby !== \"\") {\r\n gby = \" GROUP BY ( \" + gby + \" )\";\r\n }\r\n const fc = forLoop.findDirectExpression(Expressions.FieldChain);\r\n if (fc) {\r\n gby = \" GROUP BY \" + fc.concatTokens();\r\n }\r\n if (forLoop.findDirectTokenByText(\"ASCENDING\")) {\r\n gby += \" ASCENDING\";\r\n }\r\n if (forLoop.findDirectTokenByText(\"DESCENDING\")) {\r\n gby += \" DESCENDING\";\r\n }\r\n const groups = forLoop.findExpressionAfterToken(\"GROUPS\");\r\n if (groups) {\r\n const concat = groups.concatTokens();\r\n if (concat.startsWith(\"<\")) {\r\n gby += \" ASSIGNING FIELD-SYMBOL(\" + concat + \")\";\r\n }\r\n else {\r\n gby += \" INTO DATA(\" + concat + \")\";\r\n }\r\n }\r\n let inGroup = \"\";\r\n if (forLoop.concatTokens().toUpperCase().includes(\" IN GROUP \")) {\r\n inGroup = \"-items\";\r\n }\r\n let into = \"INTO DATA\";\r\n if (loopTargetField.startsWith(\"<\")) {\r\n into = \"ASSIGNING FIELD-SYMBOL\";\r\n }\r\n // todo, also backup sy-index / sy-tabix here?\r\n body += indentation + `LOOP AT ${loopSource}${inGroup} ${into}(${loopTargetField})${from}${to}${cond}${gby}.\\n`;\r\n if (indexInto) {\r\n body += indentation + \" DATA(\" + indexInto + \") = sy-tabix.\\n\";\r\n }\r\n end = \"ENDLOOP\";\r\n }\r\n else if (loopTargetField === undefined) {\r\n // todo, also backup sy-index / sy-tabix here?\r\n const loopTargetFieldSymbol = (_l = forLoop.findFirstExpression(Expressions.TargetFieldSymbol)) === null || _l === void 0 ? void 0 : _l.concatTokens();\r\n body += indentation + `LOOP AT ${loopSource} ASSIGNING FIELD-SYMBOL(${loopTargetFieldSymbol})${cond}.\\n`;\r\n if (indexInto) {\r\n body += indentation + \" DATA(\" + indexInto + \") = sy-tabix.\\n\";\r\n }\r\n end = \"ENDLOOP\";\r\n }\r\n const l = forLoop.findDirectExpression(Expressions.Let);\r\n if (l) {\r\n body += this.outlineLet(l, indentation, highSyntax, lowFile);\r\n }\r\n return { body, end };\r\n }\r\n outlineSwitch(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c, _d;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n const firstToken = i.getFirstToken();\r\n if (firstToken.getStr().toUpperCase() !== \"SWITCH\") {\r\n continue;\r\n }\r\n let type = this.findType(i, lowFile, highSyntax);\r\n if (type === undefined) {\r\n if (high.get() instanceof Statements.Move\r\n && high.findDirectExpression(Expressions.Source) === i\r\n && ((_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.TargetField)) !== undefined) {\r\n type = \"LIKE \" + ((_b = high.findDirectExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());\r\n }\r\n if (type === undefined) {\r\n continue;\r\n }\r\n }\r\n else {\r\n type = \"TYPE \" + type;\r\n }\r\n const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let body = \"\";\r\n let name = \"\";\r\n const switchBody = i.findDirectExpression(Expressions.SwitchBody);\r\n if (switchBody === undefined) {\r\n continue;\r\n }\r\n for (const l of ((_c = switchBody === null || switchBody === void 0 ? void 0 : switchBody.findDirectExpression(Expressions.Let)) === null || _c === void 0 ? void 0 : _c.findDirectExpressions(Expressions.InlineFieldDefinition)) || []) {\r\n name = l.getFirstToken().getStr();\r\n body += indentation + `DATA(${name}) = ${(_d = switchBody.findFirstExpression(Expressions.Source)) === null || _d === void 0 ? void 0 : _d.concatTokens()}.\\n`;\r\n }\r\n body += `DATA ${uniqueName} ${type}.\\n`;\r\n let firstSource = false;\r\n let inWhen = false;\r\n for (const c of switchBody.getChildren()) {\r\n if (c.get() instanceof Expressions.Source && firstSource === false) {\r\n body += indentation + `CASE ${c.concatTokens()}.`;\r\n firstSource = true;\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"THEN\") {\r\n inWhen = true;\r\n body += \".\\n\";\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"WHEN\") {\r\n inWhen = false;\r\n body += `\\n${indentation} WHEN `;\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"OR\") {\r\n body += ` OR `;\r\n }\r\n else if (c instanceof nodes_1.TokenNode && c.concatTokens().toUpperCase() === \"ELSE\") {\r\n inWhen = true;\r\n body += `\\n${indentation} WHEN OTHERS.\\n`;\r\n }\r\n else if (inWhen === false) {\r\n body += c.concatTokens();\r\n }\r\n else {\r\n body += indentation + \" \" + uniqueName + \" = \" + c.concatTokens() + \".\";\r\n }\r\n }\r\n body += \"\\n\" + indentation + \"ENDCASE.\\n\" + indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), body);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, firstToken, \"Downport SWITCH\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineReduce(low, high, lowFile, highSyntax) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n const firstToken = i.getFirstToken();\r\n if (firstToken.getStr().toUpperCase() !== \"REDUCE\") {\r\n continue;\r\n }\r\n const type = this.findType(i, lowFile, highSyntax);\r\n if (type === undefined) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let body = \"\";\r\n let name = \"\";\r\n const reduceBody = i.findDirectExpression(Expressions.ReduceBody);\r\n if (reduceBody === undefined) {\r\n continue;\r\n }\r\n const letNode = reduceBody.findDirectExpression(Expressions.Let);\r\n if (letNode) {\r\n body += this.outlineLet(letNode, indentation, highSyntax, lowFile);\r\n }\r\n let firstName = \"\";\r\n for (const init of reduceBody.findDirectExpressions(Expressions.InlineFieldDefinition)) {\r\n name = init.getFirstToken().getStr();\r\n if (firstName === \"\") {\r\n firstName = name;\r\n }\r\n const s = (_a = init.findFirstExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n const t = (_b = init.findFirstExpression(Expressions.TypeName)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (s) {\r\n body += indentation + `DATA(${name}) = ${s}.\\n`;\r\n }\r\n else {\r\n body += indentation + `DATA ${name} TYPE ${t}.\\n`;\r\n }\r\n }\r\n let end = \"\";\r\n for (const forLoop of (reduceBody === null || reduceBody === void 0 ? void 0 : reduceBody.findDirectExpressions(Expressions.For)) || []) {\r\n const outlineFor = this.outlineFor(forLoop, indentation, lowFile, highSyntax);\r\n body += outlineFor.body;\r\n end = outlineFor.end + `.\\n` + end;\r\n }\r\n const next = reduceBody.findDirectExpression(Expressions.ReduceNext);\r\n if (next === undefined) {\r\n continue;\r\n }\r\n for (const n of next.getChildren()) {\r\n const concat = n.concatTokens();\r\n if (concat.toUpperCase() === \"NEXT\") {\r\n continue;\r\n }\r\n else if (n.get() instanceof Expressions.SimpleFieldChain) {\r\n body += indentation + \" \" + concat + \" \";\r\n }\r\n else if (n.get() instanceof Expressions.Source) {\r\n body += \" \" + concat + \".\\n\";\r\n }\r\n else {\r\n body += concat;\r\n }\r\n }\r\n body += indentation + end;\r\n body += indentation + `${uniqueName} = ${firstName}.\\n`;\r\n const abap = `DATA ${uniqueName} TYPE ${type}.\\n` +\r\n body +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, firstToken, \"Downport REDUCE\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineValue(low, high, lowFile, highSyntax) {\r\n var _a, _b, _c;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const allSources = high.findAllExpressionsRecursive(Expressions.Source);\r\n for (const s of allSources) {\r\n const firstToken = s.getFirstToken();\r\n if (firstToken.getStr().toUpperCase() !== \"VALUE\") {\r\n continue;\r\n }\r\n let type = this.findType(s, lowFile, highSyntax);\r\n if (type === undefined) {\r\n if (high.get() instanceof Statements.Move && high.findDirectExpression(Expressions.Source) === s) {\r\n type = \"LIKE \" + ((_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.concatTokens());\r\n }\r\n if (type === undefined) {\r\n continue;\r\n }\r\n }\r\n else {\r\n type = \"TYPE \" + type;\r\n }\r\n const valueBody = s.findDirectExpression(Expressions.ValueBody);\r\n const uniqueName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n let indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n let body = \"\";\r\n const base = valueBody === null || valueBody === void 0 ? void 0 : valueBody.findExpressionAfterToken(\"BASE\");\r\n if (base) {\r\n body += indentation + uniqueName + \" = \" + base.concatTokens() + \".\\n\";\r\n }\r\n let end = \"\";\r\n let structureName = uniqueName;\r\n let added = false;\r\n let data = \"\";\r\n let previous = undefined;\r\n for (const a of (valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren()) || []) {\r\n if (a.get() instanceof Expressions.FieldAssignment) {\r\n if (added === false) {\r\n body += data;\r\n added = true;\r\n }\r\n body += indentation + structureName + \"-\" + a.concatTokens() + \".\\n\";\r\n }\r\n else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.For) {\r\n const outlineFor = this.outlineFor(a, indentation, lowFile, highSyntax);\r\n body += outlineFor.body;\r\n end = outlineFor.end + `.\\n` + end;\r\n indentation += \" \";\r\n }\r\n else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.Source) {\r\n // special handling for superflous value expression\r\n if ((valueBody === null || valueBody === void 0 ? void 0 : valueBody.getChildren().length) === 1) {\r\n body += indentation + uniqueName + \" = \" + a.concatTokens() + `.\\n`;\r\n }\r\n }\r\n else if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.Let) {\r\n body += this.outlineLet(a, indentation, highSyntax, lowFile);\r\n }\r\n if (a instanceof nodes_1.ExpressionNode && a.get() instanceof Expressions.ValueBodyLine) {\r\n let skip = false;\r\n for (const b of (a === null || a === void 0 ? void 0 : a.getChildren()) || []) {\r\n if (b.concatTokens() === \"(\" && added === false) {\r\n structureName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n data = indentation + `DATA ${structureName} LIKE LINE OF ${uniqueName}.\\n`;\r\n }\r\n if (b.get() instanceof Expressions.FieldAssignment) {\r\n if (added === false) {\r\n body += data;\r\n added = true;\r\n }\r\n body += indentation + structureName + \"-\" + b.concatTokens() + \".\\n\";\r\n }\r\n else if (b.get() instanceof Expressions.Source) {\r\n body += indentation + \"APPEND \" + b.concatTokens() + ` TO ${uniqueName}.\\n`;\r\n skip = true;\r\n }\r\n else if (b.get() instanceof Expressions.ValueBodyLines) {\r\n body += indentation + \"APPEND \" + b.concatTokens() + ` TO ${uniqueName}.\\n`;\r\n skip = true;\r\n }\r\n else if (b.concatTokens() === \")\") {\r\n if (added === false && (previous === null || previous === void 0 ? void 0 : previous.concatTokens()) === \"(\") {\r\n body += data;\r\n added = true;\r\n }\r\n if (skip === false) {\r\n body += indentation + `APPEND ${structureName} TO ${uniqueName}.\\n`;\r\n }\r\n }\r\n previous = b;\r\n }\r\n }\r\n }\r\n if (body === \"\" && ((_b = valueBody === null || valueBody === void 0 ? void 0 : valueBody.getLastChild()) === null || _b === void 0 ? void 0 : _b.getFirstToken().getStr().toUpperCase()) === \"OPTIONAL\") {\r\n const fieldChain = valueBody.findFirstExpression(Expressions.FieldChain);\r\n const rowName = this.uniqueName(firstToken.getStart(), lowFile.getFilename(), highSyntax);\r\n let tableExpression = undefined;\r\n let tabName = \"\";\r\n let after = \"\";\r\n for (const c of (fieldChain === null || fieldChain === void 0 ? void 0 : fieldChain.getChildren()) || []) {\r\n if (c.get() instanceof Expressions.TableExpression && c instanceof nodes_1.ExpressionNode) {\r\n tableExpression = c;\r\n }\r\n else if (tableExpression === undefined) {\r\n tabName += c.concatTokens();\r\n }\r\n else {\r\n after += c.concatTokens();\r\n }\r\n }\r\n let condition = \"\";\r\n if ((tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.getChildren().length) === 3) {\r\n condition = \"INDEX \" + ((_c = tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.findDirectExpression(Expressions.Source)) === null || _c === void 0 ? void 0 : _c.concatTokens());\r\n }\r\n else {\r\n condition = \"WITH KEY \" + (tableExpression === null || tableExpression === void 0 ? void 0 : tableExpression.concatTokens().replace(\"[ \", \"\").replace(\" ]\", \"\"));\r\n }\r\n body +=\r\n indentation + `READ TABLE ${tabName} INTO DATA(${rowName}) ${condition}.\\n` +\r\n indentation + `IF sy-subrc = 0.\\n` +\r\n indentation + ` ${uniqueName} = ${rowName}${after}.\\n` +\r\n indentation + `ENDIF.\\n`;\r\n }\r\n if (end !== \"\") {\r\n indentation = indentation.substring(2);\r\n body += indentation + end;\r\n }\r\n const abap = `DATA ${uniqueName} ${type}.\\n` +\r\n indentation + `CLEAR ${uniqueName}.\\n` + // might be called inside a loop\r\n body +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, firstToken.getStart(), s.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, firstToken, \"Downport VALUE\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineLet(node, indentation, highSyntax, lowFile) {\r\n var _a;\r\n let ret = \"\";\r\n for (const f of node.findDirectExpressions(Expressions.InlineFieldDefinition)) {\r\n const c = f.getFirstChild();\r\n if (c === undefined) {\r\n continue;\r\n }\r\n const name = c.concatTokens().toLowerCase();\r\n const spag = highSyntax.spaghetti.lookupPosition(c.getFirstToken().getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n continue;\r\n }\r\n const found = spag.findVariable(name);\r\n if (found === undefined) {\r\n const source = f.findFirstExpression(Expressions.Source);\r\n if (source) {\r\n ret += indentation + \"DATA(\" + name + `) = ${source.concatTokens()}.\\n`;\r\n }\r\n continue;\r\n }\r\n const type = found.getType().getQualifiedName() ? (_a = found.getType().getQualifiedName()) === null || _a === void 0 ? void 0 : _a.toLowerCase() : found.getType().toABAP();\r\n ret += indentation + \"DATA \" + name + ` TYPE ${type}.\\n`;\r\n const source = f.findFirstExpression(Expressions.Source);\r\n if (source) {\r\n ret += indentation + name + ` = ${source.concatTokens()}.\\n`;\r\n }\r\n }\r\n return ret;\r\n }\r\n findType(i, lowFile, highSyntax, ref = false) {\r\n var _a;\r\n const expr = i.findDirectExpression(Expressions.TypeNameOrInfer);\r\n if (expr === undefined) {\r\n return undefined;\r\n }\r\n const firstToken = expr.getFirstToken();\r\n const concat = expr.concatTokens().toLowerCase();\r\n if (concat !== \"#\") {\r\n return ref ? \"REF TO \" + concat : concat;\r\n }\r\n const spag = highSyntax.spaghetti.lookupPosition(firstToken.getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n return undefined;\r\n }\r\n let inferred = undefined;\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType === _reference_1.ReferenceType.InferredType\r\n && r.resolved\r\n && r.position.getStart().equals(firstToken.getStart())\r\n && r.resolved instanceof _typed_identifier_1.TypedIdentifier) {\r\n inferred = r.resolved;\r\n break;\r\n }\r\n }\r\n if (inferred === undefined) {\r\n return undefined;\r\n }\r\n if (inferred.getType() instanceof basic_1.ObjectReferenceType) {\r\n return inferred.getType().toABAP();\r\n }\r\n else {\r\n return (_a = inferred.getType().getQualifiedName()) === null || _a === void 0 ? void 0 : _a.toLowerCase();\r\n }\r\n }\r\n outlineFS(low, high, lowFile, highSyntax) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)\r\n || (high.get() instanceof Statements.Loop)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.InlineFS)) {\r\n const nameToken = (_a = i.findDirectExpression(Expressions.TargetFieldSymbol)) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n if (nameToken === undefined) {\r\n continue;\r\n }\r\n const name = nameToken.getStr();\r\n let type = \"\";\r\n if (high.concatTokens().toUpperCase().startsWith(\"APPEND INITIAL LINE TO \")) {\r\n type = \"LIKE LINE OF \" + ((_b = high.findFirstExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());\r\n }\r\n else {\r\n const spag = highSyntax.spaghetti.lookupPosition(nameToken.getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n continue;\r\n }\r\n const found = spag.findVariable(name);\r\n if (found === undefined) {\r\n continue;\r\n }\r\n else if (found.getType() instanceof basic_1.VoidType) {\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Error outlining voided type\", this.getMetadata().key, this.conf.severity);\r\n }\r\n type = \"TYPE \";\r\n type += found.getType().getQualifiedName() ? found.getType().getQualifiedName().toLowerCase() : found.getType().toABAP();\r\n }\r\n const code = `FIELD-SYMBOLS ${name} ${type}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Outline FIELD-SYMBOL\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineData(node, lowFile, highSyntax) {\r\n // hmm, no guard here, as DATA(SDF) is valid in 702\r\n var _a, _b;\r\n for (const i of node.findAllExpressionsRecursive(Expressions.InlineData)) {\r\n const nameToken = (_a = i.findDirectExpression(Expressions.TargetField)) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n if (nameToken === undefined) {\r\n continue;\r\n }\r\n const name = nameToken.getStr();\r\n const spag = highSyntax.spaghetti.lookupPosition(nameToken.getStart(), lowFile.getFilename());\r\n if (spag === undefined) {\r\n continue;\r\n }\r\n const found = spag.findVariable(name);\r\n if (found === undefined) {\r\n continue;\r\n }\r\n else if (found.getType() instanceof basic_1.VoidType && found.getType().getQualifiedName() === undefined) {\r\n continue;\r\n }\r\n let type = found.getType().getQualifiedName() ? (_b = found.getType().getQualifiedName()) === null || _b === void 0 ? void 0 : _b.toLowerCase() : found.getType().toABAP();\r\n if (found.getType() instanceof basic_1.ObjectReferenceType) {\r\n type = found.getType().toABAP();\r\n }\r\n const code = `DATA ${name} TYPE ${type}.\\n` +\r\n \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), name);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Outline DATA\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n outlineCond(low, high, lowFile, highSyntax) {\r\n var _a, _b;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n if (i.getFirstToken().getStr().toUpperCase() !== \"COND\") {\r\n continue;\r\n }\r\n const body = i.findDirectExpression(Expressions.CondBody);\r\n if (body === undefined) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n let type = this.findType(i, lowFile, highSyntax);\r\n if (type === undefined) {\r\n if (high.get() instanceof Statements.Move\r\n && high.findDirectExpression(Expressions.Source) === i\r\n && ((_a = high.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.TargetField)) !== undefined) {\r\n type = \"LIKE \" + ((_b = high.findDirectExpression(Expressions.Target)) === null || _b === void 0 ? void 0 : _b.concatTokens());\r\n }\r\n if (type === undefined) {\r\n continue;\r\n }\r\n }\r\n else {\r\n type = \"TYPE \" + type;\r\n }\r\n const indent = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const bodyCode = this.buildCondBody(body, uniqueName, indent, lowFile, highSyntax);\r\n const abap = `DATA ${uniqueName} ${type}.\\n` + bodyCode;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport COND\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n buildCondBody(body, uniqueName, indent, lowFile, highSyntax) {\r\n let code = \"\";\r\n let first = true;\r\n let addElse = true;\r\n for (const c of body.getChildren()) {\r\n if (c instanceof nodes_1.TokenNode) {\r\n switch (c.getFirstToken().getStr().toUpperCase()) {\r\n case \"WHEN\":\r\n if (first === true) {\r\n code += indent + \"IF \";\r\n first = false;\r\n }\r\n else {\r\n code += indent + \"ELSEIF \";\r\n }\r\n break;\r\n case \"THEN\":\r\n code += \".\\n\";\r\n break;\r\n case \"ELSE\":\r\n code += indent + \"ELSE.\\n\";\r\n addElse = false;\r\n break;\r\n default:\r\n throw \"buildCondBody, unexpected token\";\r\n }\r\n }\r\n else if (c.get() instanceof Expressions.Cond) {\r\n code += c.concatTokens();\r\n }\r\n else if (c.get() instanceof Expressions.Let) {\r\n code += this.outlineLet(c, indent, highSyntax, lowFile);\r\n }\r\n else if (c.get() instanceof Expressions.Source) {\r\n code += indent + \" \" + uniqueName + \" = \" + c.concatTokens() + \".\\n\";\r\n }\r\n else {\r\n throw \"buildCondBody, unexpected expression, \" + c.get().constructor.name;\r\n }\r\n }\r\n if (addElse) {\r\n // COND might be called inside a loop\r\n code += indent + \"ELSE.\\n\";\r\n code += indent + ` CLEAR ${uniqueName}.\\n`;\r\n }\r\n code += indent + \"ENDIF.\\n\";\r\n code += indent;\r\n return code;\r\n }\r\n outlineConv(low, high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Source)) {\r\n if (i.getFirstToken().getStr().toUpperCase() !== \"CONV\") {\r\n continue;\r\n }\r\n const end = i.findDirectTokenByText(\")\");\r\n if (end === undefined) {\r\n continue;\r\n }\r\n const body = (_a = i.findDirectExpression(Expressions.ConvBody)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n if (body === undefined) {\r\n continue;\r\n }\r\n const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const type = this.findType(i, lowFile, highSyntax);\r\n const indent = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const abap = `DATA ${uniqueName} TYPE ${type}.\\n` +\r\n indent + `${uniqueName} = ${body}.\\n` +\r\n indent;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), end.getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport CONV\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n // \"CAST\" to \"?=\"\r\n outlineCast(low, high, lowFile, highSyntax) {\r\n var _a;\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const i of high.findAllExpressionsRecursive(Expressions.Cast)) {\r\n const uniqueName = this.uniqueName(i.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const type = this.findType(i, lowFile, highSyntax, true);\r\n const body = (_a = i.findDirectExpression(Expressions.Source)) === null || _a === void 0 ? void 0 : _a.concatTokens();\r\n const abap = `DATA ${uniqueName} TYPE ${type}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1) +\r\n `${uniqueName} ?= ${body}.\\n` +\r\n \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), abap);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, i.getFirstToken().getStart(), i.getLastToken().getEnd(), uniqueName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, i.getFirstToken(), \"Downport CAST\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n uniqueName(position, filename, highSyntax) {\r\n const spag = highSyntax.spaghetti.lookupPosition(position, filename);\r\n if (spag === undefined) {\r\n const name = \"temprr\" + this.counter;\r\n this.counter++;\r\n return name;\r\n }\r\n while (true) {\r\n const name = \"temp\" + this.counter;\r\n const found = spag.findVariable(name);\r\n this.counter++;\r\n if (found === undefined) {\r\n return name;\r\n }\r\n }\r\n }\r\n replaceXsdBool(node, lowFile, highSyntax) {\r\n const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType === _reference_1.ReferenceType.BuiltinMethodReference\r\n && r.position.getName().toUpperCase() === \"XSDBOOL\") {\r\n const token = r.position.getToken();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, token.getStart(), token.getEnd(), \"boolc\");\r\n return issue_1.Issue.atToken(lowFile, token, \"Use BOOLC\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n findMethodCallExpression(node, token) {\r\n var _a;\r\n for (const m of node.findAllExpressions(Expressions.MethodCall)) {\r\n if ((_a = m.findDirectExpression(Expressions.MethodName)) === null || _a === void 0 ? void 0 : _a.getFirstToken().getStart().equals(token.getStart())) {\r\n return m;\r\n }\r\n }\r\n return undefined;\r\n }\r\n replaceMethodConditional(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n for (const c of high.findAllExpressionsRecursive(Expressions.Compare)) {\r\n const chain = c.findDirectExpression(Expressions.MethodCallChain);\r\n if (chain === undefined) {\r\n continue;\r\n }\r\n let predicate = false;\r\n const spag = highSyntax.spaghetti.lookupPosition(high.getFirstToken().getStart(), lowFile.getFilename());\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType === _reference_1.ReferenceType.BuiltinMethodReference &&\r\n new _builtin_1.BuiltIn().isPredicate(chain.getFirstToken().getStr().toUpperCase())) {\r\n predicate = true;\r\n break;\r\n }\r\n }\r\n const end = chain.getLastToken().getEnd();\r\n let fix = edit_helper_1.EditHelper.insertAt(lowFile, end, \" IS NOT INITIAL\");\r\n if (predicate === true) {\r\n fix = edit_helper_1.EditHelper.insertAt(lowFile, end, \" ) = abap_true\");\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, chain.getFirstToken().getStart(), \"boolc( \");\r\n fix = edit_helper_1.EditHelper.merge(fix, fix1);\r\n }\r\n return issue_1.Issue.atToken(lowFile, chain.getFirstToken(), \"Downport method conditional\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n return undefined;\r\n }\r\n getReference(node, lowFile, _highSyntax) {\r\n var _a, _b, _c;\r\n if (!(node.get() instanceof Statements.GetReference)) {\r\n return undefined;\r\n }\r\n const inline = (_a = node.findDirectExpression(Expressions.Target)) === null || _a === void 0 ? void 0 : _a.findDirectExpression(Expressions.InlineData);\r\n if (inline === undefined) {\r\n return undefined;\r\n }\r\n const targetName = (_b = inline.findDirectExpression(Expressions.TargetField)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n const sourceName = (_c = node.findDirectExpression(Expressions.Source)) === null || _c === void 0 ? void 0 : _c.concatTokens();\r\n if (targetName === undefined || sourceName === undefined) {\r\n return undefined;\r\n }\r\n const code = `DATA ${targetName} LIKE REF TO ${sourceName}.\\n`;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, inline.getFirstToken().getStart(), inline.getLastToken().getEnd(), targetName);\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, inline.getFirstToken(), \"Downport, outline DATA ref\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n replaceContains(node, lowFile, highSyntax) {\r\n const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());\r\n // only downport if its an single method call condition\r\n let found = false;\r\n for (const c of node.findAllExpressionsRecursive(Expressions.Compare)) {\r\n found = c.findDirectExpression(Expressions.MethodCallChain) !== undefined;\r\n if (found === true) {\r\n break;\r\n }\r\n }\r\n if (found === false) {\r\n return undefined;\r\n }\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType !== _reference_1.ReferenceType.BuiltinMethodReference) {\r\n continue;\r\n }\r\n const func = r.position.getName().toUpperCase();\r\n if (func === \"CONTAINS\") {\r\n const token = r.position.getToken();\r\n const expression = this.findMethodCallExpression(node, token);\r\n if (expression === undefined) {\r\n continue;\r\n }\r\n const sList = expression.findAllExpressions(Expressions.Source).map(e => e.concatTokens());\r\n if (sList.length !== 2) {\r\n continue;\r\n }\r\n const code = sList[0] + \" CS \" + sList[1];\r\n const start = expression.getFirstToken().getStart();\r\n const end = expression.getLastToken().getEnd();\r\n const fix = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, code);\r\n return issue_1.Issue.atToken(lowFile, token, \"Downport contains()\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n replaceLineFunctions(node, lowFile, highSyntax) {\r\n var _a, _b;\r\n const spag = highSyntax.spaghetti.lookupPosition(node.getFirstToken().getStart(), lowFile.getFilename());\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if (r.referenceType !== _reference_1.ReferenceType.BuiltinMethodReference) {\r\n continue;\r\n }\r\n const func = r.position.getName().toUpperCase();\r\n if (func === \"LINE_EXISTS\" || func === \"LINE_INDEX\") {\r\n const token = r.position.getToken();\r\n const expression = this.findMethodCallExpression(node, token);\r\n if (expression === undefined) {\r\n continue;\r\n }\r\n let condition = \"\";\r\n for (const c of ((_a = expression === null || expression === void 0 ? void 0 : expression.findFirstExpression(Expressions.TableExpression)) === null || _a === void 0 ? void 0 : _a.getChildren()) || []) {\r\n if (c.getFirstToken().getStr() === \"[\" || c.getFirstToken().getStr() === \"]\") {\r\n continue;\r\n }\r\n else if (c.get() instanceof Expressions.ComponentChainSimple && condition === \"\") {\r\n condition = \"WITH KEY \";\r\n }\r\n else if (c.get() instanceof Expressions.Source && condition === \"\") {\r\n condition = \"INDEX \";\r\n }\r\n condition += c.concatTokens() + \" \";\r\n }\r\n const tableName = (_b = expression.findFirstExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens().split(\"[\")[0];\r\n const uniqueName = this.uniqueName(node.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const indentation = \" \".repeat(node.getFirstToken().getStart().getCol() - 1);\r\n const sy = func === \"LINE_EXISTS\" ? \"sy-subrc\" : \"sy-tabix\";\r\n const code = `DATA ${uniqueName} LIKE sy-subrc.\\n` +\r\n indentation + `READ TABLE ${tableName} ${condition}TRANSPORTING NO FIELDS.\\n` +\r\n indentation + uniqueName + ` = ${sy}.\\n` +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, node.getFirstToken().getStart(), code);\r\n const start = expression.getFirstToken().getStart();\r\n const end = expression.getLastToken().getEnd();\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, start, end, uniqueName + (func === \"LINE_EXISTS\" ? \" = 0\" : \"\"));\r\n const fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n return issue_1.Issue.atToken(lowFile, token, \"Use BOOLC\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n }\r\n return undefined;\r\n }\r\n newToCreateObject(low, high, lowFile, highSyntax) {\r\n if (!(low.get() instanceof _statement_1.Unknown)) {\r\n return undefined;\r\n }\r\n const source = high.findDirectExpression(Expressions.Source);\r\n let fix = undefined;\r\n if (high.get() instanceof Statements.Move\r\n && source\r\n && source.getFirstToken().getStr().toUpperCase() === \"NEW\") {\r\n const target = high.findDirectExpression(Expressions.Target);\r\n const found = source === null || source === void 0 ? void 0 : source.findFirstExpression(Expressions.NewObject);\r\n // must be at top level of the source for quickfix to work(todo: handle more scenarios)\r\n if (target\r\n && found\r\n && source.concatTokens() === found.concatTokens()\r\n && target.findDirectExpression(Expressions.InlineData) === undefined) {\r\n const abap = this.newParameters(found, target.concatTokens(), highSyntax, lowFile);\r\n if (abap !== undefined) {\r\n fix = edit_helper_1.EditHelper.replaceRange(lowFile, high.getFirstToken().getStart(), high.getLastToken().getEnd(), abap);\r\n }\r\n }\r\n }\r\n if (fix === undefined && high.findAllExpressions(Expressions.NewObject)) {\r\n const found = high.findFirstExpression(Expressions.NewObject);\r\n if (found === undefined) {\r\n return undefined;\r\n }\r\n const name = this.uniqueName(found.getFirstToken().getStart(), lowFile.getFilename(), highSyntax);\r\n const abap = this.newParameters(found, name, highSyntax, lowFile);\r\n if (abap === undefined) {\r\n return undefined;\r\n }\r\n const type = this.findType(found, lowFile, highSyntax);\r\n const indentation = \" \".repeat(high.getFirstToken().getStart().getCol() - 1);\r\n const data = `DATA ${name} TYPE REF TO ${type}.\\n` +\r\n indentation + abap + \"\\n\" +\r\n indentation;\r\n const fix1 = edit_helper_1.EditHelper.insertAt(lowFile, high.getFirstToken().getStart(), data);\r\n const fix2 = edit_helper_1.EditHelper.replaceRange(lowFile, found.getFirstToken().getStart(), found.getLastToken().getEnd(), name);\r\n fix = edit_helper_1.EditHelper.merge(fix2, fix1);\r\n }\r\n if (fix) {\r\n return issue_1.Issue.atToken(lowFile, high.getFirstToken(), \"Use CREATE OBJECT instead of NEW\", this.getMetadata().key, this.conf.severity, fix);\r\n }\r\n else {\r\n return undefined;\r\n }\r\n }\r\n newParameters(found, name, highSyntax, lowFile) {\r\n var _a, _b, _c;\r\n const typeToken = (_a = found.findDirectExpression(Expressions.TypeNameOrInfer)) === null || _a === void 0 ? void 0 : _a.getFirstToken();\r\n let extra = (typeToken === null || typeToken === void 0 ? void 0 : typeToken.getStr()) === \"#\" ? \"\" : \" TYPE \" + (typeToken === null || typeToken === void 0 ? void 0 : typeToken.getStr());\r\n const parameters = found.findFirstExpression(Expressions.ParameterListS);\r\n if (parameters) {\r\n extra = parameters ? extra + \" EXPORTING \" + parameters.concatTokens() : extra;\r\n }\r\n else if (typeToken) {\r\n const source = (_b = found.findDirectExpression(Expressions.Source)) === null || _b === void 0 ? void 0 : _b.concatTokens();\r\n if (source) {\r\n // find the default parameter name for the constructor\r\n const spag = highSyntax.spaghetti.lookupPosition(typeToken === null || typeToken === void 0 ? void 0 : typeToken.getStart(), lowFile.getFilename());\r\n let cdef = undefined;\r\n for (const r of (spag === null || spag === void 0 ? void 0 : spag.getData().references) || []) {\r\n if ((r.referenceType === _reference_1.ReferenceType.InferredType\r\n || r.referenceType === _reference_1.ReferenceType.ObjectOrientedReference)\r\n && r.resolved && r.position.getStart().equals(typeToken.getStart())) {\r\n cdef = r.resolved;\r\n }\r\n }\r\n if (cdef && cdef.getMethodDefinitions === undefined) {\r\n return undefined; // something wrong\r\n }\r\n const importing = (_c = cdef === null || cdef === void 0 ? void 0 : cdef.getMethodDefinitions().getByName(\"CONSTRUCTOR\")) === null || _c === void 0 ? void 0 : _c.getParameters().getDefaultImporting();\r\n if (importing) {\r\n extra += \" EXPORTING \" + importing + \" = \" + source;\r\n }\r\n else if (spag === undefined) {\r\n extra += \" SpagUndefined\";\r\n }\r\n else if (cdef === undefined) {\r\n extra += \" ClassDefinitionNotFound\";\r\n }\r\n else {\r\n extra += \" SomeError\";\r\n }\r\n }\r\n }\r\n const abap = `CREATE OBJECT ${name}${extra}.`;\r\n return abap;\r\n }\r\n}\r\nexports.Downport = Downport;\r\n//# sourceMappingURL=downport.js.map\n\n//# sourceURL=webpack://@abaplint/cli/./node_modules/@abaplint/core/build/src/rules/downport.js?");
|
|
11944
11944
|
|
|
11945
11945
|
/***/ }),
|
|
11946
11946
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abaplint/cli",
|
|
3
|
-
"version": "2.93.
|
|
3
|
+
"version": "2.93.29",
|
|
4
4
|
"description": "abaplint - Command Line Interface",
|
|
5
5
|
"bin": {
|
|
6
6
|
"abaplint": "./abaplint"
|
|
@@ -39,16 +39,16 @@
|
|
|
39
39
|
},
|
|
40
40
|
"homepage": "https://abaplint.org",
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@abaplint/core": "^2.93.
|
|
42
|
+
"@abaplint/core": "^2.93.29",
|
|
43
43
|
"@types/chai": "^4.3.3",
|
|
44
44
|
"@types/glob": "^7.2.0",
|
|
45
45
|
"@types/minimist": "^1.2.2",
|
|
46
46
|
"@types/mocha": "^9.1.1",
|
|
47
|
-
"@types/node": "^18.7.
|
|
47
|
+
"@types/node": "^18.7.20",
|
|
48
48
|
"@types/progress": "^2.0.5",
|
|
49
49
|
"chai": "^4.3.6",
|
|
50
50
|
"chalk": "^5.0.1",
|
|
51
|
-
"eslint": "^8.
|
|
51
|
+
"eslint": "^8.24.0",
|
|
52
52
|
"glob": "^7.2.3",
|
|
53
53
|
"json5": "^2.2.1",
|
|
54
54
|
"memfs": "^3.4.7",
|