import humanId from 'human-id' ; import produce from 'immer' ; import { sanitizeActor , sanitizeScenario , sanitizeFeature , } from './sanitizeUtilities' ; import { Database , Actor , FlattenedDatabase , Scenario , Step } from './types' ; const uuid = ( ) => humanId ( ) ; /**
 * Flattens the database into a series of arrays, instead
 * of keyed objects.
 *
 * Also sanitizes various names by camelcasing them
 */ export const flattenDatabase = ( database ) : FlattenedDatabase => { return { features : Object . values ( database . features ) . map ( ( feature ) => { return { ... sanitizeFeature ( feature ) , actors : Object . values ( feature . actors ) . map ( sanitizeActor ) , scenarios : Object . values ( feature . scenarios ) . map ( sanitizeScenario ) , } ; } ) , } ; } ; export interface StepDescriptor { env : string ; in : Step [ ] ; out : Step [ ] ; } export type ActorWithStep = Actor & { from : StepDescriptor [ ] ; to : StepDescriptor [ ] ; } ; export const getActorsWithSteps = ( actors , steps ) : ActorWithStep [ ] => { return actors . map ( ( env ) => { return { ... env , from : actors . map ( ( fromEnv ) => { return { env : fromEnv . name , in : steps . filter ( ( step ) => { return step . to === env . id && step . from === fromEnv . id ; } ) , out : steps . filter ( ( step ) => { return step . from === env . id && step . to === fromEnv . id ; } ) , } ; } ) . filter ( ( fromEnv ) => { return fromEnv . in . length > 0 || fromEnv . out . length > 0 ; } ) , to : actors . map ( ( toEnv ) => { return { env : toEnv . name , in : steps . filter ( ( step ) => { return step . from === env . id && step . to === toEnv . id ; } ) , out : steps . filter ( ( step ) => { return step . to === env . id && step . from === toEnv . id ; } ) , } ; } ) . filter ( ( fromEnv ) => { return fromEnv . in . length > 0 || fromEnv . out . length > 0 ; } ) , } ; } ) ; } ; /** Scenarios */ export const addScenario = ( database , featureId ) : Database => { return produce ( database , ( draft ) => { const feature = draft . features [ featureId ] ; const id = uuid ( ) ; feature . scenarios [ id ] = { id , description : 'Description' , name : 'New Scenario' , order : Object . keys ( feature . scenarios ) . length , steps : [ ] , } ; } ) ; } ; export const addFeature = ( database ) => { return produce ( database , ( draft ) => { const id = uuid ( ) ; draft . features [ id ] = { id , actors : { } , description : 'Description' , eventPayloads : '' , name : 'New Feature' , scenarios : { } , } ; } ) ; } ; export const updateScenarioName = ( database , featureId , scenarioId , name ) : Database => { return produce ( database , ( draft ) => { draft . features [ featureId ] . scenarios [ scenarioId ] . name = name ; } ) ; } ; export const updateScenarioDescription = ( database , featureId , scenarioId , description ) : Database => { return produce ( database , ( draft ) => { draft . features [ featureId ] . scenarios [ scenarioId ] . description = description ; } ) ; } ; export const deleteScenario = ( database , featureId , scenarioId ) : Database => produce ( database , ( draft ) => { delete draft . features [ featureId ] . scenarios [ scenarioId ] ; } ) ; export const duplicateScenario = ( database , featureId , scenarioId ) : Database => produce ( database , ( draft ) => { const newId = uuid ( ) ; draft . features [ featureId ] . scenarios [ newId ] = { ... draft . features [ featureId ] . scenarios [ scenarioId ] , id : newId , } ; } ) ; export const DEFAULT_EVENT_NAME = 'EVENT' ; /** Steps */ export const addStep = ( { database , fromEnvId , index , scenarioId , featureId , toEnvId , } ) : Database => produce ( database , ( draft ) => { draft . features [ featureId ] . scenarios [ scenarioId ] . steps . splice ( index , 0 , { event : DEFAULT_EVENT_NAME , id : uuid ( ) , from : fromEnvId , to : toEnvId , } ) ; } ) ; export const updateStepEventName = ( database , featureId , scenarioId , stepIndex , name ) : Database => produce ( database , ( draft ) => { draft . features [ featureId ] . scenarios [ scenarioId ] . steps [ stepIndex ] . event = name ; } ) ; export const deleteStep = ( database , featureId , scenarioId , stepIndex ) : Database => { return produce ( database , ( draft ) => { draft . features [ featureId ] . scenarios [ scenarioId ] . steps . splice ( stepIndex , 1 ) ; } ) ; } ; /** Actor */ export const addActor = ( database , featureId ) => { return produce ( database , ( draft ) => { const newId = uuid ( ) ; draft . features [ featureId ] . actors [ newId ] = { id : newId , name : 'New Actor' , } ; } ) ; } ; export const updateActorName = ( database , featureId , scenarioId , envId , name ) => { return produce ( database , ( draft ) => { draft . features [ featureId ] . scenarios [ scenarioId ] ; draft . features [ featureId ] . actors [ envId ] . name = name ; } ) ; } ; export const deleteActor = ( database , featureId , envId ) => { Object . values ( database . features [ featureId ] . scenarios ) . forEach ( ( feature ) => { feature . steps . forEach ( ( step ) => { if ( step . from === envId || step . to === envId ) { throw new Error ( 'This actor cannot be deleted because steps depend on it.' ) ; } } ) ; } ) ; return produce ( database , ( draft ) => { delete draft . features [ featureId ] . actors [ envId ] ; } ) ; } ; export const getStepsFromScenarios = ( scenarios ) : Step [ ] => { return scenarios . reduce ( ( accum , scenario ) => { return accum . concat ( scenario . steps . reduce ( ( stepAccum , step ) => { return stepAccum . concat ( step ) ; } , [ ] as Step [ ] ) ) ; } , [ ] as Step [ ] ) ; } ; export const updateFeatureEventPayload = ( database , featureId , eventPayloads ) => { return produce ( database , ( draft ) => { draft . features [ featureId ] . eventPayloads = eventPayloads ; } ) ; } ; export const updateFeatureName = ( database , featureId , name ) => { return produce ( database , ( draft ) => { draft . features [ featureId ] . name = name ; } ) ; } ; export const updateFeatureDescription = ( database , featureId , description ) => { return produce ( database , ( draft ) => { draft . features [ featureId ] . description = description ; } ) ; } ; export const updateFeatureEventPayloadWithFunc = ( database , featureId , func ) => { return produce ( database , ( draft ) => { draft . features [ featureId ] . eventPayloads = func ( draft . features [ featureId ] . eventPayloads ) ; } ) ; } ;