All files / src/rules check_text_elements.ts

98.05% Statements 101/103
96.66% Branches 29/30
100% Functions 6/6
98.05% Lines 101/103

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 1041x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 11763x 11763x 11763x 11763x 11763x 11763x 35101x 35101x 35101x 35101x 35101x 35101x 11763x 11763x 11241x 11241x 11763x 11763x 239x 239x 11763x 11763x 253x 253x 253x 253x 11763x 11763x 328x 71x 71x 257x 257x 257x 328x 264x 264x 12x 12x 252x 252x 252x 252x 252x 252x 252x 264x 13x 13x 13x 13x 13x 13x 13x     13x 252x 264x 13x 13x 6x 6x 6x 1x 1x 1x 13x 7x 7x 7x 7x 7x 7x 4x 4x 7x 2x 2x 7x 5x 2x 2x 7x 13x 252x 257x 257x 257x 11763x 11763x  
import {IRule} from "./_irule";
import {Issue} from "../issue";
import {BasicRuleConfig} from "./_basic_rule_config";
import * as Expressions from "../abap/2_statements/expressions";
import {ABAPObject, ITextElements} from "../objects/_abap_object";
import {IObject} from "../objects/_iobject";
import {IRegistry} from "../_iregistry";
import {IncludeGraph} from "../utils/include_graph";
 
export class CheckTextElementsConf extends BasicRuleConfig {
}
 
export class CheckTextElements implements IRule {
  private reg: IRegistry;
  private conf = new CheckTextElementsConf();
  private graph: IncludeGraph;
 
  public getMetadata() {
    return {
      key: "check_text_elements",
      title: "Check text elements",
      shortDescription: `Check text elements exists or matches code`,
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: CheckTextElementsConf) {
    this.conf = conf;
  }
 
  public initialize(reg: IRegistry) {
    this.reg = reg;
    this.graph = new IncludeGraph(this.reg);
    return this;
  }
 
  public run(obj: IObject): Issue[] {
    if (!(obj instanceof ABAPObject)) {
      return [];
    }
 
    const output: Issue[] = [];
 
    for (const file of obj.getABAPFiles()) {
      const stru = file.getStructure();
      if (stru === undefined) {
        continue;
      }
 
      let texts: ITextElements;
      let mainName: string | undefined = undefined;
 
      const expressions = stru.findAllExpressionsMulti([Expressions.TextElement, Expressions.TextElementString]);
 
      // optimize: no need to find main and texts if there are no expressions to check
      if (expressions.length > 0) {
        const mains = this.graph.listMainForInclude(file.getFilename());
        if (mains.length === 1) {
// todo, this only checks the first main
          mainName = mains[0];
          const main1 = this.reg.findObjectForFile(this.reg.getFileByName(mains[0])!)! as ABAPObject;
          texts = main1.getTextSymbols();
        } else {
          texts = obj.getTextSymbols();
        }
      }
 
      for (const e of expressions) {
        const mainNameSuffix = mainName !== undefined && mainName.toLowerCase() !== file.getFilename().toLowerCase() ? ", " + mainName : "";
        if (e.get() instanceof Expressions.TextElement) {
          const token = e.findFirstExpression(Expressions.TextElementKey)!.getFirstToken();
          const key = token.getStr().toUpperCase();
          if (texts![key] === undefined) {
            const message = `Text element "${key}" not found` + mainNameSuffix;
            output.push(Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity));
          }
        } else {
          // its a Expressions.TextElementString
          const token = e.findFirstExpression(Expressions.TextElementKey)!.getFirstToken();
          const code = e.getFirstToken().getStr();
          const key = token.getStr().toUpperCase();
          let found = texts![key]?.entry;
          if (found !== undefined && code.startsWith("'")) {
            found = found.replace(/'/g, "''");
          }
          if (found === undefined) {
            const message = `Text element "${key}" not found` + mainNameSuffix;
            output.push(Issue.atToken(file, token, message, this.getMetadata().key, this.conf.severity));
          } else if (code !== "'" + found + "'"
              && code !== "`" + found + "`") {
            output.push(Issue.atToken(file, token, "Text does not match text element", this.getMetadata().key, this.conf.severity));
          }
        }
      }
    }
 
    return output;
  }
 
}