import { concat , each , filter , find , first , flatMap , fromPairs , get , isArray , isEmpty , keys , map , mapValues , negate , reduce , toPairs , values , zip } from 'lodash/fp' ; import flatten , { unflatten } from 'flat' ; interface StoryVariant < T > { props : T ; story : any ; title : string ; } type CartesianData < T > = { [ P in keyof T ] : Array < T [ P ] > | any ; } ; const titles = { renderCheckSignsIfExists : ( { exists = '✓' , missing = 'x' , existsFn = ( v ) => v , sep = ' | ' } = { } ) => ( props ) => toPairs ( props ) . map ( ( [ k , v ] ) => ( existsFn ( v ) ? `${ exists } ${ k }` : `${ missing } ${ k }` ) ) . join ( sep ) , renderPropNames : ( { sep = ' | ' } = { } ) => ( props ) => keys ( props ) . join ( sep ) , renderProps : ( { eqSep = '=' , sep = ' ' } = { } ) => ( props ) => toPairs ( props ) . map ( ( [ k , v ] ) => `${ k }${ eqSep }${ JSON . stringify ( v ) }` ) . join ( sep ) } ; const renderWithLegend = ( legend ) => ( f ) => ( props ) => f ( unflatten ( mapValues ( ( p ) => legend [ p != null ? p . toString ( ) : 'null' ] || p , flatten ( props ) ) ) ) ; const renderWithLegendFlat = ( legend ) => ( f ) => ( props ) => f ( mapValues ( ( p ) => legend [ p != null ? p . toString ( ) : 'null' ] || p , props ) ) ; const xproduct = ( vals ) => reduce ( ( a , b ) => flatMap ( x => map ( y => concat ( x , [ y ] ) ) ( b ) ) ( a ) ) ( [ [ ] ] ) ( vals ) ; const compile = < Props > ( data ) => find ( v => isChoice ( v ) , values ( data ) ) ? data : mapValues ( v => ( isArray ( v ) ? choice ( ... v ) : v ) , data ) ; const isChoice = ( v ) => isArray ( v ) && v . length === 2 && first ( v ) === '$choice$' ; const choice = ( ... choices ) => [ '$choice$' , choices ] ; const nodeValue = ( node ) => get ( '1' , node ) ; const defaultApply = < T > ( stories , variants ) : void => { each ( cand => stories . add ( cand . title , ( ) => cand . story ) , variants ) ; } ; const alwaysValid = ( ) => true ; const cartesian = ( stories ) => ( { add : < Props > ( seed , renderStory , opts ) => { const { valid , renderTitle , apply } = { apply : defaultApply as ( stories : any , variants : Array < StoryVariant < Props > > ) => void , renderTitle : ( props ) => JSON . stringify ( props ) , valid : alwaysValid , ... opts } ; const data = flatten ( seed ( ) , { safe : true } ) ; const compiledData = compile ( data ) ; const fields = keys ( compiledData ) ; const rows = map ( p => unflatten ( fromPairs ( zip ( fields , p ) ) ) as Props , xproduct ( map ( v => ( isChoice ( v ) ? nodeValue ( v ) : [ v ] ) , values < CartesianData < Props > > ( compiledData ) ) ) ) ; const variants = map ( props => ( { props , story : renderStory ( props ) , title : renderTitle ( props ) } ) , filter ( valid , filter ( negate ( isEmpty ) , rows ) ) ) ; apply ( stories , variants ) ; } } ) ; export { choice , renderWithLegend , renderWithLegendFlat , xproduct , titles } ; export default cartesian ;