freddi301/flow-validator

View on GitHub
src/async/AsyncVType.js

Summary

Maintainability
D
2 days
Test Coverage
// @flow

import { ValidationError } from "../sync/ValidationError";
import { AsyncType } from "./AsyncType";
import { asyncVintersection } from "./asyncVintersection";
import { asyncVunion } from "./asyncVunion";
import { asyncVoptional } from "./asyncVoptional";

export class AsyncVType<T> extends AsyncType<T> {
  validate: (value: mixed) => Promise<T>;
  constructor(name: string, validate: (value: mixed) => Promise<T>) {
    super(name, validate);
    this.validate = validate;
  }
  Vrefine(
    refinement: (v: T, error: (e: string) => ValidationError) => Promise<T>
  ): AsyncVRefinedType<T> {
    const rf = new AsyncVRefinedType(this, async v => {
      const vResolved = await v;
      return refinement(
        await this.parse(v),
        (err: string) =>
          new ValidationError({
            expected: rf,
            got: vResolved,
            description: err
          })
      );
    });
    return rf;
  }
  Vand<T2>(t2: AsyncVType<T2>): AsyncVIntersectionType<T, T2> {
    return asyncVintersection(this, t2);
  }
  Vor<T2>(t2: AsyncVType<T2>): AsyncVUnionType<T, T2> {
    return asyncVunion(this, t2);
  }
  Voptional(): AsyncVOptionalType<T> {
    return asyncVoptional(this);
  }
}

export class AsyncVOptionalType<T> extends AsyncVType<?T> {
  innerType: AsyncVType<T>;
  constructor(t: AsyncVType<T>, validate: (value: mixed) => Promise<?T>) {
    super("optional", validate);
    this.innerType = t;
  }
}

export class AsyncVUnionType<A, B> extends AsyncVType<A | B> {
  typeA: AsyncVType<A>;
  typeB: AsyncVType<B>;
  constructor(
    a: AsyncVType<A>,
    b: AsyncVType<B>,
    validate: (value: mixed) => Promise<A | B>
  ) {
    super("union", validate);
    this.typeA = a;
    this.typeB = b;
  }
}

export class AsyncVIntersectionType<A, B> extends AsyncVType<A & B> {
  typeA: AsyncVType<A>;
  typeB: AsyncVType<B>;
  constructor(
    a: AsyncVType<A>,
    b: AsyncVType<B>,
    validate: (value: mixed) => Promise<A & B>
  ) {
    super("intersection", validate);
    this.typeA = a;
    this.typeB = b;
  }
}

export class AsyncVRefinedType<T> extends AsyncVType<T> {
  base: AsyncVType<T>;
  constructor(base: AsyncVType<T>, f: (v: mixed) => Promise<T>) {
    super("refined", f);
    this.base = base;
  }
  revalidate(): AsyncVType<T> {
    return new AsyncVType("revalidated", async v =>
      this.base.validate(await this.validate(v))
    );
  }
}