import { toArray } from "@adpt/utils" ; import { isFunction } from "lodash" ; import { Handle , isHandle } from "../handle" ; import { Dependency , DeployHelpers , IsDeployedFunc , Relation , RelationExt , Waiting , } from "./deploy_types" ; import { depName , nDepends , relationIsReadyStatus , toRelation , } from "./relation_utils" ; export const waiting = ( status , related ? ) : Waiting => { const ret = { done : false , status } ; if ( related ) { const hands = [ ] ; const waits = [ ] ; for ( const r of related ) { if ( isHandle ( r ) ) hands . push ( r ) ; else waits . push ( r ) ; } if ( hands . length > 0 ) ret . toDeploy = hands ; if ( waits . length > 0 ) ret . related = waits ; } return ret ; } ; export const True = ( ) : Relation => ( { description : "True" , ready : ( ) => true , } ) ; export const False = ( ) : Relation => ( { description : "False" , ready : ( ) => waiting ( "False is never ready" ) , } ) ; export const Identity = ( a0 ) : Relation => ( { description : "" , ready : ( args ) => relationIsReadyStatus ( args [ 0 ] ) , relatesTo : [ a0 ] , } ) ; export const Not = ( a0 ) : Relation => ( { description : "Not" , ready : ( args ) => { const stat = relationIsReadyStatus ( args [ 0 ] ) ; if ( stat !== true ) return true ; return waiting ( "Not ready because child Relation is ready" ) ; } , relatesTo : [ a0 ] , } ) ; export const And = ( ... relatesTo ) : Relation => relatesTo . length === 0 ? True ( ) : relatesTo . length === 1 ? relatesTo [ 0 ] : { description : "And" , ready : ( rList ) => { const status = relationIsReadyStatus ( rList ) ; if ( status === true ) return true ; const notReady = toArray ( status ) ; return waiting ( `Waiting for ${ nDepends ( notReady . length ) }` , notReady ) ; } , relatesTo , } ; export const Or = ( ... relatesTo ) : Relation => relatesTo . length === 0 ? True ( ) : relatesTo . length === 1 ? relatesTo [ 0 ] : { description : "Or" , ready : ( rList ) => { const status = relationIsReadyStatus ( rList ) ; if ( status === true ) return true ; const notReady = toArray ( status ) ; if ( notReady . length < rList . length ) return true ; return waiting ( `Waiting for any of ${ nDepends ( notReady . length ) }` , notReady ) ; } , relatesTo , } ; export const Edge = ( a0 , a1 , isDeployed ) : RelationExt => ( { get description ( ) { return this . toString ! ( ) ; } , ready : ( ) => { if ( isDeployed ( a1 ) ) return true ; return waiting ( `Waiting for dependency ${ depName ( a1 ) }` ) ; } , inverse : ( ) => Edge ( a1 , a0 , isDeployed ) , toString : ( indent = "" ) => `${ indent }Edge( ${ depName ( a0 ) }, ${ depName ( a1 ) } )` , toDependencies : ( ) => [ a1 ] , } ) ; export type BoolVal = boolean | ( ( ) => boolean ) ; export const Value = ( v , description = "Value" ) : Relation => ( { description , ready : ( ) => { if ( isFunction ( v ) ? v ( ) : v ) return true ; return waiting ( `Waiting for ${ description }` ) ; } , toString : ( indent = "" ) : string => { return `${ indent }${ description }(${ typeof v === "boolean" ? v : "<function>" })` ; } } ) ; export function AllOf ( h , deps ) { return { description : "all of" , relatesTo : deps . map ( ( d ) => toRelation ( h , d ) ) , ready : ( rels ) => relationIsReadyStatus ( And ( ... rels ) ) , } ; } export function Only ( h , dep ) { return { description : "only" , relatesTo : [ toRelation ( h , dep ) ] , ready : ( rels ) => relationIsReadyStatus ( rels [ 0 ] ) , } ; } export function AnyOf ( h , deps ) { return { description : "any of" , relatesTo : deps . map ( ( d ) => toRelation ( h , d ) ) , ready : ( rels ) => relationIsReadyStatus ( Or ( ... rels ) ) , } ; } export function None ( ) { return { description : "none" , ready : ( ) => true , } ; }