All files / src/rules abapdoc.ts

86.53% Statements 90/104
91.66% Branches 22/24
100% Functions 7/7
86.53% Lines 90/104

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 18723x 18723x 18723x 18723x 18723x 18723x 1x 9362x 9362x 9362x 9362x 9362x 27948x 27948x 27948x 27948x 27948x 27948x 27948x 27948x 27948x 27948x 9362x 9362x 8970x 8970x 9362x 9362x 217x 217x 9362x 9362x 244x 244x 244x 244x 244x 244x 118x 67x 67x 51x 51x 118x               118x 244x 244x 49x 28x 28x 21x 21x 49x               49x 244x 244x 34x 1x 1x 33x 34x 24x 24x 24x 24x 34x 244x 244x 9362x 9362x 33x 33x 33x 1x 1x 1x 1x 32x 32x 9362x 9362x
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {Issue} from "../issue";
import {Visibility} from "../abap/4_file_information/visibility";
import {InfoMethodDefinition} from "../abap/4_file_information/_abap_file_information";
import {IRuleMetadata, RuleTag} from "./_irule";
import {ABAPFile} from "../abap/abap_file";
import {Position} from "../position";
 
export class AbapdocConf extends BasicRuleConfig {
  /** Check local classes and interfaces for abapdoc. */
  public checkLocal: boolean = false;
  public classDefinition: boolean = false;
  public interfaceDefinition: boolean = false;
}
 
export class Abapdoc extends ABAPRule {
 
  private conf = new AbapdocConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "abapdoc",
      title: "Check abapdoc",
      shortDescription: `Various checks regarding abapdoc.
Base rule checks for existence of abapdoc for public class methods and all interface methods.
 
Plus class and interface definitions.`,
      tags: [RuleTag.SingleFile],
    };
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: AbapdocConf): void {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
    const rows = file.getRawRows();
 
    let methods: InfoMethodDefinition[] = [];
 
    for (const classDef of file.getInfo().listClassDefinitions()) {
      if (this.conf.checkLocal === false && classDef.isLocal === true) {
        continue;
      }
      methods = methods.concat(classDef.methods.filter(m => m.visibility === Visibility.Public));
 
      if (this.getConfig().classDefinition === true) {
        const previousRow = classDef.identifier.getStart().getRow() - 2;
        if (rows[previousRow]?.trim().substring(0, 2) !== "\"!") {
          const message = "Missing ABAP Doc for class " + classDef.identifier.getToken().getStr();
          const issue = Issue.atIdentifier(classDef.identifier, message, this.getMetadata().key, this.conf.severity);
          issues.push(issue);
        }
      }
    }
 
    for (const interfaceDef of file.getInfo().listInterfaceDefinitions()) {
      if (this.conf.checkLocal === false && interfaceDef.isLocal === true) {
        continue;
      }
      methods = methods.concat(interfaceDef.methods);
 
      if (this.getConfig().interfaceDefinition === true) {
        const previousRow = interfaceDef.identifier.getStart().getRow() - 2;
        if (rows[previousRow]?.trim().substring(0, 2) !== "\"!") {
          const message = "Missing ABAP Doc for interface " + interfaceDef.identifier.getToken().getStr();
          const issue = Issue.atIdentifier(interfaceDef.identifier, message, this.getMetadata().key, this.conf.severity);
          issues.push(issue);
        }
      }
    }
 
    for (const method of methods) {
      if (method.isRedefinition === true) {
        continue;
      }
      const previousRowText = this.getPreviousRow(rows, method.identifier.getStart());
      if (!(previousRowText.substring(0, 2) === "\"!")) {
        const message = "Missing ABAP Doc for method " + method.identifier.getToken().getStr();
        const issue = Issue.atIdentifier(method.identifier, message, this.getMetadata().key, this.conf.severity);
        issues.push(issue);
      }
    }
    return issues;
  }
 
  private getPreviousRow(rows: readonly string[], pos: Position): string {
    const previousRow = pos.getRow() - 2;
    const text = rows[previousRow].trim().toUpperCase();
    if (text === "METHODS" || text === "CLASS-METHODS") {
      const previousRow = pos.getRow() - 3;
      const text = rows[previousRow].trim().toUpperCase();
      return text;
    }
    return text;
  }
 
}