<commit_before>import {
  InvalidFormatError,
} from "../errors";
import {
  IBaseValidatorDefinition,
  IValidationError,
  IValidator,
} from "../interfaces";

export interface IFormatValidatorDefinition extends IBaseValidatorDefinition {
  format: string;
}

export class FormatValidator implements IValidator<string, IFormatValidatorDefinition> {
  private static rDateTime: RegExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
  private static rEmail: RegExp = /^.+@.+\..+$/;
  private static rUri: RegExp = /^[0-9a-zA-Z]+:\/\/.+$/;

  constructor(public definition: IFormatValidatorDefinition) {
    this.definition.type = "format";
    const {format} = this.definition;
    switch (format) {
      case "date-time":
      case "email":
      case "hostname":
      case "uri":
      case "password-0Aa":
        return;
      default:
        throw new InvalidFormatError(`the format is not found`);
    }
  }

  public validate(input: string): IValidationError<string, IFormatValidatorDefinition> {
    const {format} = this.definition;
    const invalid = {
      definition: this.definition,
      input,
    };
    switch (format) {

      case "date-time": {
        if (FormatValidator.rDateTime.test(input)) {
          return;
        }
        break;
      }
      case "email": {
        if (FormatValidator.rEmail.test(input)) {
          return;
        }
        break;
      }
      case "hostname": {
        // stolen from https://golang.org/src/net/dnsclient.go
        const len = input.length;
        if (len === 0) {
          break;
        }
        if (len > 255) {
          break;
        }
        let last: string;
        let partlen: number = 0;
        for (let i = 0; i < len; i++) {
          const c = input.charAt(i);
          switch (true) {
            default:
              return invalid;
            case "a" <= c && c <= "z" || "A" <= c && c <= "Z" || c === "_":
              partlen++;
              break;
            case "0" <= c && c <= "9":
              partlen++;
              break;
            case c === "-":
              if (last === ".") {
                return invalid;
              }
              partlen++;
              break;
            case c === ".":
              if (last === "." || last === "-") {
                return invalid;
              }
              if (partlen > 63 || partlen === 0) {
                return invalid;
              }
              partlen = 0;
              break;
          }
          last = c;
        }
        if (last === "-" || partlen > 63) {
          break;
        }
        return;
      }
      case "uri": {
        if (FormatValidator.rUri.test(input)) {
          return;
        }
        break;
      }
      case "password-0Aa": {
        let large = false;
        let small = false;
        let num = false;
        for (let i = 0; i < input.length; i++) {
          const c = input.charAt(i);
          switch (true) {
            case "0" <= c && c <= "9":
              num = true;
              continue;
            case "A" <= c && c <= "Z":
              large = true;
              continue;
            case "a" <= c && c <= "z":
              small = true;
              continue;
            case "!" <= c && c <= "~":
              continue;
            default:
              return invalid;
          }
        }
        if (large && small && num) {
          return;
        }
        return invalid;
      }

    }
    return invalid;
  }
}<commit_msg>Separate large block into function<commit_after>import {
  InvalidFormatError,
} from "../errors";
import {
  IBaseValidatorDefinition,
  IValidationError,
  IValidator,
} from "../interfaces";

export interface IFormatValidatorDefinition extends IBaseValidatorDefinition {
  format: string;
}

export class FormatValidator implements IValidator<string, IFormatValidatorDefinition> {
  private static rDateTime: RegExp = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
  private static rEmail: RegExp = /^.+@.+\..+$/;
  private static rUri: RegExp = /^[0-9a-zA-Z]+:\/\/.+$/;

  constructor(public definition: IFormatValidatorDefinition) {
    this.definition.type = "format";
    const {format} = this.definition;
    switch (format) {
      case "date-time":
      case "email":
      case "hostname":
      case "uri":
      case "password-<PASSWORD>":
        return;
      default:
        throw new InvalidFormatError(`the format is not found`);
    }
  }

  public validate(input: string): IValidationError<string, IFormatValidatorDefinition> {
    const {format} = this.definition;
    switch (format) {
      case "date-time": {
        if (FormatValidator.rDateTime.test(input)) {
          return;
        }
        break;
      }
      case "email": {
        if (FormatValidator.rEmail.test(input)) {
          return;
        }
        break;
      }
      case "hostname": {
        if (this.isHostName(input)) {
          return;
        }
        break;
      }
      case "uri": {
        if (FormatValidator.rUri.test(input)) {
          return;
        }
        break;
      }
      case "password-<PASSWORD>": {
        if (this.isPassword0Aa(input)) {
          return;
        }
        break;
      }

    }
    return {
      definition: this.definition,
      input,
    };
  }

  // stolen from https://golang.org/src/net/dnsclient.go
  private isHostName(s: string): boolean {
    const len = s.length;
    if (len === 0) {
      return false;
    }
    if (len > 255) {
      return false;
    }
    let last: string = ".";
    let ok: boolean = false;
    let partlen: number = 0;
    for (let i = 0; i < len; i++) {
      const c = s.charAt(i);
      switch (true) {
        default:
          return false;
        case "a" <= c && c <= "z" || "A" <= c && c <= "Z" || c === "_":
          ok = true;
          partlen++;
          break;
        case "0" <= c && c <= "9":
          partlen++;
          break;
        case c === "-":
          if (last === ".") {
            return false;
          }
          partlen++;
          break;
        case c === ".":
          if (last === "." || last === "-") {
            return false;
          }
          if (partlen > 63 || partlen === 0) {
            return false;
          }
          partlen = 0;
          break;
      }
      last = c;
    }
    if (last === "-" || partlen > 63) {
      return false;
    }
    return ok;
  }

  private isPassword0Aa(s: string): boolean {
    let large = false;
    let small = false;
    let num = false;
    for (let i = 0; i < s.length; i++) {
      const c = s.charAt(i);
      switch (true) {
        case "0" <= c && c <= "9":
          num = true;
          continue;
        case "A" <= c && c <= "Z":
          large = true;
          continue;
        case "a" <= c && c <= "z":
          small = true;
          continue;
        case "!" <= c && c <= "~":
          continue;
        default:
          return false;
      }
    }
    return large && small && num;
  }
}
{'fraction_non_alphanumeric': 0.148, 'fraction_numerical': 0.007714285714285714, 'mean_word_length': 1.447902097902098, 'pattern_counts': {'":': 36, '<': 41, '<?xml version=': 0, '>': 15, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2098599', 'n_tokens_mistral': 2143, 'n_tokens_neox': 2084, 'n_words': 528}