import { Arr, Merger, Obj } from '@ephox/katamari'; import * as fc from 'fast-check'; import * as WeightedChoice from './WeightedChoice'; type WeightedItem = WeightedChoice.WeightedItem; interface ChanceItem { readonly chance: number; } interface Detail { readonly components: Record; } export interface CompositeDetail extends Detail { readonly recursionDepth?: number; } export interface StructureDetail extends Detail {} type Component = T & { readonly component?: string; }; export type Construct = (component: string, depth: number) => fc.Arbitrary; const skipChild = '_'; const toComponents = (detail: Detail): Component[] => Obj.mapToArray(detail.components, (v, k) => // If there is no component, then the choice will be None. k !== skipChild ? Merger.deepMerge(v, { component: k }) : v ); const none = (): fc.Arbitrary => fc.constant([]); const composite = (rawDepth: number | undefined, detail: CompositeDetail, construct: Construct): fc.Arbitrary => { const components = toComponents(detail); const depth = rawDepth ?? detail.recursionDepth; if (depth === 0) { return none(); } else { const genComponent = (choice: Component, depth: number | undefined) => { const newDepth = choice.useDepth === true ? depth - 1 : depth; return fc.array(construct(choice.component, newDepth), { minLength: 1, maxLength: 5 }); }; const repeat = WeightedChoice.generator(components).chain((choice) => choice.fold( none, (c) => genComponent(c, depth) ) ); const flatten = (xs: T[][]): T[] => Arr.flatten(xs); return fc.array(repeat, { minLength: 1, maxLength: 5 }).map(flatten); } }; const structure = (rawDepth: number | undefined, detail: StructureDetail, construct: Construct): fc.Arbitrary => { const components = toComponents(detail); return fc.float({ min: 0, max: 1 }).chain((random) => { // TODO: Allow the order to be mixed up? const children = Arr.foldl, fc.Arbitrary[]>( components, (b, component) => random <= component.chance ? b.concat([ construct(component.component, rawDepth) ]) : b, [] ); return fc.tuple(...children); }); }; export { none, composite, structure };