import { AnyExpressionFunctionDefinition } from '../expression_functions/types' ; import { ExpressionAstExpression , ExpressionAstFunction } from './types' ; import { buildExpressionFunction , ExpressionAstFunctionBuilder , InferFunctionDefinition , } from './build_function' ; import { format } from './format' ; import { parse } from './parse' ; example param val return export function isExpressionAstBuilder ( val ) { return val ?. type === 'expression_builder' ; } internal export function isExpressionAst ( val ) { return val ?. type === 'expression' ; } export interface ExpressionAstExpressionBuilder { /**
     * Used to identify expression builder objects.
     */ type : 'expression_builder' ; /**
     * Array of each of the `buildExpressionFunction()` instances
     * in this expression. Use this to remove or reorder functions
     * in the expression.
     */ functions : ExpressionAstFunctionBuilder [ ] ; param fnName return findFunction : < FnDef extends AnyExpressionFunctionDefinition = AnyExpressionFunctionDefinition > ( fnName : InferFunctionDefinition < FnDef > [ 'name' ] ) => Array < ExpressionAstFunctionBuilder < FnDef > > | [ ] ; return toAst : ( ) => ExpressionAstExpression ; return toString : ( ) => string ; } const generateExpressionAst = ( fns ) : ExpressionAstExpression => ( { type : 'expression' , chain : fns . map ( ( fn ) => fn . toAst ( ) ) , } ) ; param initialState return export function buildExpression ( initialState ? ) { const chainToFunctionBuilder = ( chain ) : ExpressionAstFunctionBuilder [ ] => chain . map ( ( fn ) => buildExpressionFunction ( fn . function , fn . arguments ) ) ; const extractFunctionsFromState = ( state ) : ExpressionAstFunctionBuilder [ ] => { if ( typeof state === 'string' ) { return chainToFunctionBuilder ( parse ( state , 'expression' ) . chain ) ; } else if ( ! Array . isArray ( state ) ) { return chainToFunctionBuilder ( state . chain ) ; } return state ; } ; const fns = initialState ? extractFunctionsFromState ( initialState ) : [ ] ; return { type : 'expression_builder' , functions : fns , findFunction < FnDef extends AnyExpressionFunctionDefinition > ( fnName ) { const foundFns = [ ] ; return fns . reduce ( ( found , currFn ) => { Object . values ( currFn . arguments ) . forEach ( ( values ) => { values . forEach ( ( value ) => { if ( isExpressionAstBuilder ( value ) ) { found = found . concat ( value . findFunction ( fnName ) ) ; } } ) ; } ) ; if ( currFn . name === fnName ) { found . push ( currFn as ExpressionAstFunctionBuilder < FnDef > ) ; } return found ; } , foundFns ) ; } , toAst ( ) { if ( fns . length < 1 ) { throw new Error ( 'Functions have not been added to the expression builder' ) ; } return generateExpressionAst ( fns ) ; } , toString ( ) { if ( fns . length < 1 ) { throw new Error ( 'Functions have not been added to the expression builder' ) ; } return format ( generateExpressionAst ( fns ) , 'expression' ) ; } , } ; }