Guest User

Untitled

a guest
Nov 23rd, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.98 KB | None | 0 0
  1. type Validated<E, A> = ValidatedOk<E, A> | ValidatedError<E, A>
  2.  
  3. type ErrorOfValidated<V extends Validated<any, any>> = V['errorType']
  4. type ValueOfValidated<V extends Validated<any, any>> = V['valueType']
  5.  
  6. const Validated = {
  7.  
  8. ok<E, A>(a: A): ValidatedOk<E, A> {
  9. return new ValidatedOk<E, A>(a)
  10. },
  11.  
  12. error<E, A>(error: E): ValidatedError<E, A> {
  13. return new ValidatedError<E, A>([error])
  14. },
  15.  
  16. combine<O extends { [k: string]: Validated<any, any> }>(o: O): Validated<ErrorOfValidated<O[keyof O]>, { [K in keyof O]: ValueOfValidated<O[K]> }> {
  17.  
  18. const errors: any[] = []
  19. const values: { [K in keyof O]?: any } = {}
  20. Object.keys(o).forEach(key => {
  21. const validated = o[key]
  22. if (validated.kind === ValidatedOk.kind) {
  23. values[key] = validated.value
  24. } else if (validated.kind === ValidatedError.kind) {
  25. validated.errors.forEach((e: any) => {
  26. errors.push(e)
  27. })
  28. } else {
  29. const exhaustive: never = validated
  30. throw exhaustive
  31. }
  32. })
  33.  
  34. if (errors.length > 0) {
  35. return new ValidatedError(errors)
  36. } else {
  37. return new ValidatedOk(values as any)
  38. }
  39. }
  40. }
  41.  
  42. class ValidatedOk<E, A> {
  43. static readonly kind = 'ok'
  44. readonly kind = ValidatedOk.kind
  45.  
  46. readonly valueType: A = null as A
  47. readonly errorType: E = null as E
  48.  
  49. constructor(readonly value: A) { }
  50.  
  51. map<B>(fn: (a: A) => B): Validated<E, B> {
  52. return new ValidatedOk<E, B>(fn(this.value))
  53. }
  54.  
  55. fold<B>(ok: (v: ValidatedOk<E, A>) => B, error: (v: ValidatedError<E, A>) => B): B {
  56. return ok(this)
  57. }
  58. }
  59.  
  60. class ValidatedError<E, A> {
  61. static readonly kind = 'error'
  62. readonly kind = ValidatedError.kind
  63.  
  64. readonly valueType: A = null as A
  65. readonly errorType: E = null as E
  66.  
  67. constructor(readonly errors: E[]) { }
  68.  
  69. map<B>(fn: (a: A) => B): Validated<E, B> {
  70. return new ValidatedError<E, B>(this.errors)
  71. }
  72.  
  73. fold<B>(ok: (v: ValidatedOk<E, A>) => B, error: (v: ValidatedError<E, A>) => B): B {
  74. return error(this)
  75. }
  76.  
  77. coerceValue<B>(): ValidatedError<E, B> {
  78. return new ValidatedError<E, B>(this.errors)
  79. }
  80. }
  81.  
  82. class ValidationRule<E, A, B> {
  83.  
  84. readonly sourceType: A = null as A
  85. readonly targetType: B = null as B
  86. readonly errorType: E = null as E
  87.  
  88. constructor(readonly rule: (a: A) => Validated<E, B>) { }
  89.  
  90. followedBy<C>(rule: (b: B) => Validated<E, C>): ValidationRule<E, A, C> {
  91. const composedRule = (a: A) => this.rule(a).fold(
  92. ok => rule(ok.value),
  93. err => err.coerceValue<C>()
  94. )
  95. return new ValidationRule(composedRule)
  96. }
  97.  
  98. static fromPredicate<E, A>(predicate: (a: A) => boolean, error: E): ValidationRule<E, A, A> {
  99. return new ValidationRule<E, A, A>((a: A) =>
  100. predicate(a) ? new ValidatedOk<E, A>(a) : new ValidatedError<E, A>([error])
  101. )
  102. }
  103.  
  104. static combine<O extends { [k: string]: ValidationRule<any, any, any> }>(o: O): ValidationRule<ErrorOfValidationRule<O[keyof O]>, {[K in keyof O]: SourceOfValidationRule<O[K]> }, {[K in keyof O]: TargetOfValidationRule<O[K]> }> {
  105.  
  106. const rule = a => {
  107. const validatedsToCombine: { [K in keyof O]?: Validated<any, any> } = {}
  108. Object.keys(o).forEach(key => {
  109. validatedsToCombine[key] = o[key].rule(a[key])
  110. })
  111. return Validated.combine(validatedsToCombine)
  112. }
  113. return new ValidationRule(rule)
  114. }
  115. }
  116.  
  117. type SourceOfValidationRule<V extends ValidationRule<any, any, any>> = V['sourceType']
  118. type TargetOfValidationRule<V extends ValidationRule<any, any, any>> = V['targetType']
  119. type ErrorOfValidationRule<V extends ValidationRule<any, any, any>> = V['errorType']
  120.  
  121. const isBiggerThanTwo = new ValidationRule<string, number, string>(n =>
  122. n > 2
  123. ? Validated.ok('Big ' + n)
  124. : Validated.error('not.bigger.than.two')
  125. )
  126.  
  127. const isFalse = ValidationRule.fromPredicate(b => b === false, 'not.false')
  128.  
  129. const rules = {
  130. n: isBiggerThanTwo,
  131. b: isFalse
  132. }
  133.  
  134. const rulesV = ValidationRule.combine(rules)
  135. console.log(rulesV.rule({ n: 4, b: true }))
  136. console.log(rulesV.rule({ n: 4, b: false }))
  137. console.log(rulesV.rule({ n: 1, b: true }))
Add Comment
Please, Sign In to add comment