All files / tr8-script/validators validator.ts

0% Statements 0/32
100% Branches 0/0
0% Functions 0/4
0% Lines 0/29

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                                                                                                                                                                                                 
import { autoInjectable } from "tsyringe";
 
import { Tr8AST } from "../domain/ast.js";
import { Breakdown } from "../domain/breakdown.js";
import { LedgerEvent } from "../domain/ledger-event.js";
import { AllocationPolicyRule } from "./rules/allocation-policy-rule.js";
import { NoEmptySourceAndDestinationInTxRule } from "./rules/no-empty-source-and-destination-rule.js";
import { NoFixedAmountAllocationPolicyInRelativeRefValueRule } from "./rules/no-fixed-amount-allocation-policy-in-relative-ref-value-rule.js";
import { NoLimitAndKeepWithOverdraftConstraintRule } from "./rules/no-limit-and-keep-with-overdraft-constraint-rule.js";
import { RelativeRefValueBookSameAsSourceBooksRule } from "./rules/relative-ref-value-book-same-as-source-books-rule.js";
import { RemainingAllocationPolicyRule } from "./rules/remaining-allocation-policy-rule.js";
import { SingleBookSourceDestForRequestRule } from "./rules/single-book-source-dest-for-request-rule.js";
import { SingleBookSourcePerTxForNotifRule } from "./rules/single-book-source-per-tx-for-notif-rule.js";
import { SourceConstraintsAllocationPolicyInNotifRule } from "./rules/source-constraints-allocation-policy-in-notif-rule.js";
import { UnboundedOverdraftRule } from "./rules/unbounded-overdraft-rule.js";
 
// TODO:
// keep and overdraft cannot be used together
// -> ref: https://team-gotrade.slack.com/archives/D03G88S1U95/p1696487876949449
// split abs amount > limit amount
// -> ref: https://team-gotrade.slack.com/archives/D03G88S1U95/p1696409428218059
 
interface ValidationResult {
  isValid: boolean;
  errors: string[];
}
 
interface SemanticValidationRule {
  validate(ast: Tr8AST): ValidationResult;
}
 
interface LogicalValidationRule {
  validate(ledgerEvent: LedgerEvent): ValidationResult;
}
 
@autoInjectable()
class Validator {
  #semanticRules: SemanticValidationRule[] = [];
  #logicalRules: LogicalValidationRule[] = [];
 
  constructor(
    private readonly breakdown: Breakdown,
    readonly NoEmptySourceAndDestinationInTxRule: NoEmptySourceAndDestinationInTxRule,
    readonly NoFixedAmountAllocationPolicyInRelativeRefValueRule: NoFixedAmountAllocationPolicyInRelativeRefValueRule,
    readonly NoLimitAndKeepWithOverdraftConstraintRule: NoLimitAndKeepWithOverdraftConstraintRule,
    readonly RemainingAllocationPolicyRule: RemainingAllocationPolicyRule,
    readonly RelativeRefValueBookSameAsSourceBooksRule: RelativeRefValueBookSameAsSourceBooksRule,
    readonly SingleBookSourceDestForRequestRule: SingleBookSourceDestForRequestRule,
    readonly SingleBookSourcePerTxForNotifRule: SingleBookSourcePerTxForNotifRule,
    readonly SourceConstraintsAllocationPolicyInNotifRule: SourceConstraintsAllocationPolicyInNotifRule,
    readonly UnboundedOverdraftRule: UnboundedOverdraftRule,
    readonly AllocationPolicyRule: AllocationPolicyRule,
  ) {
    this.#semanticRules = [
      NoEmptySourceAndDestinationInTxRule,
      NoFixedAmountAllocationPolicyInRelativeRefValueRule,
      NoLimitAndKeepWithOverdraftConstraintRule,
      RemainingAllocationPolicyRule,
      RelativeRefValueBookSameAsSourceBooksRule,
      SingleBookSourceDestForRequestRule,
      SingleBookSourcePerTxForNotifRule,
      SourceConstraintsAllocationPolicyInNotifRule,
      UnboundedOverdraftRule,
    ];
 
    this.#logicalRules = [AllocationPolicyRule];
  }
 
  validate(ast: Tr8AST): ValidationResult {
    let isValid = true;
    const errors: string[] = [];
 
    this.#semanticRules.forEach((rule) => {
      const result = rule.validate(ast);
      isValid &&= result.isValid;
      errors.push(...result.errors);
    });
 
    const ledgerEvents = this.breakdown.breakdown(ast);
    for (const event of ledgerEvents) {
      this.#logicalRules.forEach((rule) => {
        const result = rule.validate(event);
        isValid &&= result.isValid;
        errors.push(...result.errors);
      });
    }
 
    return {
      isValid,
      errors,
    };
  }
}
 
export { Validator };
export type { ValidationResult, SemanticValidationRule, LogicalValidationRule };