All files / src/rules msag_consistency.ts

84.67% Statements 105/124
80% Branches 20/25
100% Functions 8/8
84.67% Lines 105/124

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 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 1241x 1x 1x 1x 1x 1x 1x 1x 23019x 23019x 23019x 23019x 1x 11513x 11513x 11513x 11513x 34369x 34369x 34369x 34369x 34369x 34369x 34369x 34369x 11513x 11513x 1x 1x 11513x 11513x 11014x 11014x 11513x 11513x 235x 235x 11513x 11513x 242x 242x 11513x 11513x 312x 312x 312x 302x 302x 10x 10x 10x 312x 8x 8x 1x 1x 1x 1x 1x 8x 8x           8x 8x 1x 1x 1x 1x 1x 8x 8x 8x 1x 1x 1x 1x 8x 7x 7x 8x 8x 8x 8x           8x 8x                   8x 8x 8x 1x 1x 1x 1x 1x 1x 8x 10x 312x 2x 2x 2x 2x 2x 10x 10x 10x 11513x
import {Issue} from "../issue";
import {BasicRuleConfig} from "./_basic_rule_config";
import {IRegistry} from "../_iregistry";
import {MessageClass} from "../objects";
import {IRule, IRuleMetadata} from "./_irule";
import {IObject} from "../objects/_iobject";
import {Position} from "../position";
 
export class MSAGConsistencyConf extends BasicRuleConfig {
  /** parameters must be numbered */
  public numericParameters = true;
}
 
export class MSAGConsistency implements IRule {
  private conf = new MSAGConsistencyConf();
 
  public getMetadata(): IRuleMetadata {
    return {
      key: "msag_consistency",
      title: "MSAG consistency check",
      shortDescription: `Checks the validity of messages in message classes`,
      extendedInformation: `Message numbers must be 3 digits, message text must not be empty,\n` +
        `message text must not exceed 73 characters, no message number duplicates`,
    };
  }
 
  private getDescription(reason: string): string {
    return "Message class invalid: " + reason;
  }
 
  public getConfig() {
    return this.conf;
  }
 
  public setConfig(conf: MSAGConsistencyConf) {
    this.conf = conf;
  }
 
  public initialize(_reg: IRegistry) {
    return this;
  }
 
  public run(obj: IObject): Issue[] {
    const issues: Issue[] = [];
 
    if (!(obj instanceof MessageClass)) {
      return [];
    }
 
    const numbers = new Set<string>();
 
    for (const message of obj.getMessages()) {
// todo, get the right positions in xml file, and report the issue there
      if (!message.getNumber().match(/\d\d\d/)) {
        const text = this.getDescription("Message number must be 3 digits: message " + message.getNumber());
        const position = new Position(1, 1);
        const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
        issues.push(issue);
      }
 
      if (message.getMessage() === "") {
        const text = "Message text empty: message " + message.getNumber();
        const position = new Position(1, 1);
        const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
        issues.push(issue);
      }
 
      if (message.getMessage().length > 73) {
        const text = `Message text too long (max 73 characters): message ${message.getNumber()}`;
        const position = new Position(1, 1);
        const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
        issues.push(issue);
      }
 
      const num = message.getNumber();
      if (numbers.has(num)) {
        const text = "Duplicate message number " + num;
        const position = new Position(1, 1);
        const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
        issues.push(issue);
      } else {
        numbers.add(num);
      }
 
      if (this.getConfig().numericParameters === true) {
        const placeholderCount = message.getPlaceholderCount();
        if (placeholderCount > 4) {
          const text = `More than 4 placeholders in message ${message.getNumber()}` ;
          const position = new Position(1, 1);
          const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
          issues.push(issue);
        }
 
        for (let i = 1; i <= placeholderCount; i++) {
          const placeholder = "&" + i;
          if (message.getMessage().includes(placeholder) === false) {
            const text = `Expected placeholder ${placeholder} in message ${message.getNumber()}` ;
            const position = new Position(1, 1);
            const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
            issues.push(issue);
            break;
          }
        }
      }
 
      if (message.getMessageClass() !== obj.getName()) {
        const text = `Message class "${message.getMessageClass()}" does not match filename "${
          obj.getName()}" for message ${message.getNumber()}`;
        const position = new Position(1, 1);
        const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
        issues.push(issue);
      }
    }
 
    if (obj.getParsed()?.topName !== obj.getName()) {
      const text = `Message class name "${obj.getParsed()?.topName}" does not match filename "${obj.getName()}"`;
      const position = new Position(1, 1);
      const issue = Issue.atPosition(obj.getFiles()[0], position, text, this.getMetadata().key, this.conf.severity);
      issues.push(issue);
    }
 
    return issues;
  }
}