import { Arr, Obj, Optional } from '@ephox/katamari'; import * as fc from 'fast-check'; export interface WeightedItem { useDepth?: boolean; weight: number; } export interface AccWeightItem { accWeight: number; } export interface WeightedList { readonly list: (T & AccWeightItem)[]; readonly total: number; } const weighted = (list: (T & AccWeightItem)[], total: number): WeightedList => ({ list, total }); const choose = (candidates: T[]): WeightedList => { const result = Arr.foldl(candidates, (rest, d) => { const newTotal = rest.total + d.weight; const merged: T & AccWeightItem = { ...d, accWeight: Math.fround(newTotal) }; return { total: newTotal, list: rest.list.concat([ merged ]) }; }, { list: [] as Array, total: 0 }); return weighted(result.list, result.total); }; const gChoose = (weighted: WeightedList): fc.Arbitrary> => fc.float({ min: 0, max: Math.fround(weighted.total), noDefaultInfinity: true, noNaN: true }).map((w): Optional => { const raw = Arr.find(weighted.list, (d) => w <= d.accWeight ); const keys = raw.map(Obj.keys).getOr([]); return keys.length === [ 'weight', 'accWeight' ].length ? Optional.none() : raw; }); const generator = (candidates: T[]): fc.Arbitrary> => { const list = choose(candidates); return gChoose(list); }; export { generator };