UNPKG

@abaplint/core

Version:
221 lines • 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.XMLConsistency = exports.XMLConsistencyConf = void 0; const issue_1 = require("../issue"); const _irule_1 = require("./_irule"); const Objects = require("../objects"); const _abap_object_1 = require("../objects/_abap_object"); const _basic_rule_config_1 = require("./_basic_rule_config"); const fast_xml_parser_1 = require("fast-xml-parser"); const severity_1 = require("../severity"); class XMLConsistencyConf extends _basic_rule_config_1.BasicRuleConfig { constructor() { super(...arguments); /** Problem severity for text and translation length checks */ this.textAndTranslationLengthSeverity = severity_1.Severity.Error; } } exports.XMLConsistencyConf = XMLConsistencyConf; class XMLConsistency { constructor() { this.conf = new XMLConsistencyConf(); } getMetadata() { return { key: "xml_consistency", title: "XML consistency", shortDescription: `Checks the consistency of main XML files`, extendedInformation: `Checks: * XML is well-formed and parseable * Naming for CLAS and INTF objects * Texts and translations do not exceed maximum allowed length.`, tags: [_irule_1.RuleTag.Naming, _irule_1.RuleTag.Syntax], }; } getConfig() { return this.conf; } setConfig(conf) { this.conf = conf; } initialize(_reg) { return this; } run(obj) { const issues = []; const file = obj.getXMLFile(); if (file === undefined) { return issues; } const xml = obj.getXML(); if (xml) { const res = fast_xml_parser_1.XMLValidator.validate(xml); if (res !== true) { issues.push(issue_1.Issue.atRow(file, 1, "XML parser error: " + res.err.msg, this.getMetadata().key, this.conf.severity)); } } // todo, have some XML validation in each object? if (obj instanceof Objects.Class) { issues.push(...this.runClass(obj, file)); } else if (obj instanceof Objects.Interface) { issues.push(...this.runInterface(obj, file)); } else if (obj instanceof Objects.DataElement) { issues.push(...this.runDataElement(obj, file)); } else if (obj instanceof Objects.Domain) { issues.push(...this.runDomain(obj, file)); } else if (obj instanceof Objects.Transaction) { issues.push(...this.runTransaction(obj, file)); } else if (obj instanceof Objects.MessageClass) { issues.push(...this.runMessageClass(obj, file)); } if (obj instanceof _abap_object_1.ABAPObject) { issues.push(...this.runTextPool(obj, file)); } return issues; } runClass(obj, file) { var _a; const issues = []; const name = obj.getNameFromXML(); if (name === undefined) { issues.push(issue_1.Issue.atRow(file, 1, "Name undefined in XML", this.getMetadata().key, this.conf.severity)); } else if (obj.getDescription() && obj.getDescription().length > 60) { issues.push(issue_1.Issue.atRow(file, 1, "Description too long", this.getMetadata().key, this.conf.severity)); } else if (name !== obj.getName().toUpperCase()) { issues.push(issue_1.Issue.atRow(file, 1, "Name in XML does not match object", this.getMetadata().key, this.conf.severity)); } else if (((_a = obj.getMainABAPFile()) === null || _a === void 0 ? void 0 : _a.getStructure()) !== undefined && obj.getClassDefinition() === undefined) { issues.push(issue_1.Issue.atRow(file, 1, "Class matching XML name not found in ABAP file", this.getMetadata().key, this.conf.severity)); } return issues; } runTextPool(obj, file) { const issues = []; const push = (issue) => { if (issue) { issues.push(issue); } }; for (const [key, el] of Object.entries(obj.getTextElements())) { push(this.checkTextLength(file, `ENTRY[${key}]`, el.entry, el.maxLength)); } for (const translation of obj.getTextElementsTranslations()) { for (const [key, el] of Object.entries(translation.textElements)) { push(this.checkTextLength(file, `ENTRY[${key}]`, el.entry, el.maxLength, translation.language)); } } return issues; } runInterface(obj, file) { var _a; const issues = []; const name = obj.getNameFromXML(); if (name === undefined) { issues.push(issue_1.Issue.atRow(file, 1, "Name undefined in XML", this.getMetadata().key, this.conf.severity)); } else if (obj.getDescription() && obj.getDescription().length > 60) { issues.push(issue_1.Issue.atRow(file, 1, "Description too long", this.getMetadata().key, this.conf.severity)); } else if (name !== obj.getName().toUpperCase()) { issues.push(issue_1.Issue.atRow(file, 1, "Name in XML does not match object", this.getMetadata().key, this.conf.severity)); } else if (obj.getDefinition() !== undefined && ((_a = obj.getDefinition()) === null || _a === void 0 ? void 0 : _a.getName().toUpperCase()) !== name.toUpperCase()) { issues.push(issue_1.Issue.atRow(file, 1, "Interface matching XML name not found in ABAP file", this.getMetadata().key, this.conf.severity)); } return issues; } checkTextLength(file, fieldName, text, maxLength, lang) { if (text === undefined || maxLength === undefined) { return undefined; } const max = typeof maxLength === "number" ? maxLength : parseInt(maxLength, 10); if (text.length > max) { const prefix = lang ? `[${lang}] ` : ""; return issue_1.Issue.atRow(file, 1, `${prefix}${fieldName} "${text}" exceeds maximum length of ${max} characters (actual: ${text.length})`, this.getMetadata().key, this.conf.textAndTranslationLengthSeverity); } return undefined; } runDataElement(obj, file) { var _a; const issues = []; const texts = obj.getTexts(); const maxLengths = obj.getTextMaxLengths(); for (const issue of [ this.checkTextLength(file, "DDTEXT", obj.getDescription(), 60), this.checkTextLength(file, "SCRTEXT_S", texts === null || texts === void 0 ? void 0 : texts.short, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.short), this.checkTextLength(file, "SCRTEXT_M", texts === null || texts === void 0 ? void 0 : texts.medium, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.medium), this.checkTextLength(file, "SCRTEXT_L", texts === null || texts === void 0 ? void 0 : texts.long, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.long), this.checkTextLength(file, "REPTEXT", texts === null || texts === void 0 ? void 0 : texts.heading, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.heading), ]) { if (issue) { issues.push(issue); } } for (const translation of (_a = obj.getTextsTranslations()) !== null && _a !== void 0 ? _a : []) { const lang = translation.language; for (const issue of [ this.checkTextLength(file, "DDTEXT", translation.description, 60, lang), this.checkTextLength(file, "SCRTEXT_S", translation.short, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.short, lang), this.checkTextLength(file, "SCRTEXT_M", translation.medium, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.medium, lang), this.checkTextLength(file, "SCRTEXT_L", translation.long, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.long, lang), this.checkTextLength(file, "REPTEXT", translation.heading, maxLengths === null || maxLengths === void 0 ? void 0 : maxLengths.heading, lang), ]) { if (issue) { issues.push(issue); } } } return issues; } runDomain(obj, file) { var _a, _b; const maxTextLength = 60; const issues = []; const push = (issue) => { if (issue) { issues.push(issue); } }; push(this.checkTextLength(file, "DDTEXT", obj.getDescription(), maxTextLength)); for (const fixedValue of (_a = obj.getFixedValues()) !== null && _a !== void 0 ? _a : []) { push(this.checkTextLength(file, "DDTEXT", fixedValue.description, maxTextLength, fixedValue.language)); } for (const translationFixedValue of (_b = obj.getFixedValuesTranslations()) !== null && _b !== void 0 ? _b : []) { push(this.checkTextLength(file, "DDTEXT", translationFixedValue.description, maxTextLength, translationFixedValue.language)); } return issues; } runTransaction(obj, file) { var _a; const maxTextLength = 36; const issues = []; const push = (issue) => { if (issue) { issues.push(issue); } }; push(this.checkTextLength(file, "TTEXT", obj.getDescription(), maxTextLength)); for (const translation of (_a = obj.getTextsTranslations()) !== null && _a !== void 0 ? _a : []) { push(this.checkTextLength(file, "TTEXT", translation.description, maxTextLength, translation.language)); } return issues; } runMessageClass(obj, file) { var _a; const maxTextLength = 73; const issues = []; const push = (issue) => { if (issue) { issues.push(issue); } }; for (const msg of obj.getMessages()) { push(this.checkTextLength(file, `TEXT[${msg.getNumber()}]`, msg.getMessage(), maxTextLength)); } for (const translation of (_a = obj.getTextsTranslations()) !== null && _a !== void 0 ? _a : []) { push(this.checkTextLength(file, `TEXT[${translation.number}]`, translation.text, maxTextLength, translation.language)); } return issues; } } exports.XMLConsistency = XMLConsistency; //# sourceMappingURL=xml_consistency.js.map