import type { ArrayNonEmpty } from '@rimbu/common'; import { Reducer, type StreamSource } from '@rimbu/stream'; import { isEmptyStreamSourceInstance } from '@rimbu/stream/custom'; import { GraphBuilder, GraphEmpty, GraphNonEmpty } from '@rimbu/graph/custom'; import type { GraphBase, GraphElement, WithGraphValues, } from '../../common/index.mjs'; export interface GraphTypesContextImpl extends GraphBase.Types { readonly context: GraphContext; } export class GraphContext< UN, TT extends string, Dir extends boolean, Tp extends GraphTypesContextImpl = GraphTypesContextImpl, > implements GraphBase.Context { readonly _fixedType!: any; readonly _empty: WithGraphValues['normal']; constructor( readonly isDirected: Dir, readonly typeTag: TT, readonly linkMapContext: WithGraphValues['linkMapContext'], readonly linkConnectionsContext: WithGraphValues< Tp, UN, any >['linkConnectionsContext'] ) { this._empty = Object.freeze(new GraphEmpty(isDirected, this)) as any; } isNonEmptyInstance( source: any ): source is WithGraphValues['nonEmpty'] { return source instanceof GraphNonEmpty; } readonly empty = (): any => { return this._empty; }; readonly from: any = ( ...sources: ArrayNonEmpty>> ): any => { let builder = this.builder(); let i = -1; const length = sources.length; while (++i < length) { const source = sources[i]; if (isEmptyStreamSourceInstance(source)) continue; if ( builder.isEmpty && this.isNonEmptyInstance(source) && source.context === this ) { if (i === length - 1) return source; builder = source.toBuilder(); continue; } builder.addGraphElements(source); } return builder.build(); }; // prettier-ignore readonly of = (...values: ArrayNonEmpty>): any => { return this.from(values).assumeNonEmpty(); }; readonly builder = (): any => { return new GraphBuilder(this.isDirected, this); }; reducer = (source?: StreamSource>): any => { return Reducer.create( () => undefined === source ? this.builder() : this.from(source).toBuilder(), (builder, entry) => { builder.addGraphElement(entry); return builder; }, (builder) => builder.build() ); }; createBuilder( source?: WithGraphValues['nonEmpty'] ): WithGraphValues['builder'] { return new GraphBuilder(this.isDirected, this, source) as any; } createNonEmpty( linkMap: WithGraphValues['linkMapNonEmpty'], connectionSize: number ): WithGraphValues['nonEmpty'] { return new GraphNonEmpty( this.isDirected, this, linkMap, connectionSize ) as any; } }