All files / src/rules sequential_blank.ts

100% Statements 74/74
100% Branches 14/14
100% Functions 8/8
100% Lines 74/74

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 741x 1x 1x 1x 1x 1x 1x 1x 20648x 20648x 20648x 20648x 20648x 20648x 1x 10325x 10325x 10325x 1828x 1828x 10325x 10325x 10325x 30807x 30807x 30807x 30807x 30807x 30807x 30807x 10325x 10325x 5x 5x 10325x 10325x 9811x 9811x 10325x 10325x 241x 241x 10325x 10325x 263x 263x 263x 263x 263x 263x 1776x 281x 1776x 1495x 1495x 1776x 1776x 5x 5x 2x 2x 5x 5x 5x 5x 5x 5x 5x 5x 1776x 263x 263x 263x 10325x
import {Issue} from "../issue";
import {Position} from "../position";
import {ABAPRule} from "./_abap_rule";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRuleMetadata, RuleTag} from "./_irule";
import {EditHelper} from "../edit_helper";
import {ABAPFile} from "../abap/abap_file";
 
export class SequentialBlankConf extends BasicRuleConfig {
  /** An equal or higher number of sequential blank lines will trigger a violation.
   * Example: if lines = 3, a maximum of 2 is allowed.
   */
  public lines: number = 4;
}
 
export class SequentialBlank extends ABAPRule {
 
  public static isBlankOrWhitespace(line: string): boolean {
    return /^\s*$/.test(line);
  }
  private conf = new SequentialBlankConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "sequential_blank",
      title: "Sequential blank lines",
      shortDescription: `Checks that code does not contain more than the configured number of blank lines in a row.`,
      tags: [RuleTag.Whitespace, RuleTag.Quickfix, RuleTag.SingleFile],
    };
  }
 
  private getMessage(): string {
    return "Remove sequential blank lines";
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: SequentialBlankConf) {
    this.conf = conf;
  }
 
  public runParsed(file: ABAPFile) {
    const issues: Issue[] = [];
 
    const rows = file.getRawRows();
    let blanks = 0;
 
    for (let i = 0; i < rows.length; i++) {
      if (SequentialBlank.isBlankOrWhitespace(rows[i])) {
        blanks++;
      } else {
        blanks = 0;
      }
 
      if (blanks === this.conf.lines) {
        let blankCounter = 1;
        while(i + blankCounter < rows.length && SequentialBlank.isBlankOrWhitespace(rows[i + blankCounter])){
          ++blankCounter;
        }
        const reportPos = new Position(i + 1, 1);
        // fix has to start at end of previous row for it to properly delete the first row
        const startPos = new Position(i, rows[i].length + 1);
        const endPos = new Position(i + blankCounter, rows[i + blankCounter - 1].length + 1);
        const fix = EditHelper.deleteRange(file, startPos, endPos);
        const issue = Issue.atPosition(file, reportPos, this.getMessage(), this.getMetadata().key, this.conf.severity, fix);
        issues.push(issue);
      }
    }
 
    return issues;
  }
}