ixfx
Version:
Bundle of ixfx libraries
1,414 lines (1,413 loc) • 89 kB
TypeScript
import { a as ChangeRecord, t as PathDataChange } from "./pathed-7exI3RzP.js";
import { r as RecursivePartial } from "./ts-utility-01VlmgFR.js";
import { n as IsEqualContext, t as IsEqual } from "./is-equal-BE9SbPVX.js";
import { i as Interval, l as RankFunction, o as Primitive, u as RankOptions } from "./types-1oz6G7XR.js";
import { A as IQueueMutableWithEvents } from "./index-CvH8hp8B.js";
import { $ as InterpolateOptions } from "./index-D7rg4bcN2.js";
import { v as Processors } from "./index-C0VvOavs.js";
//#region ../packages/rx/src/ops/types.d.ts
type SyncOptions = {
/**
* How to handle when a source completes.
* * 'allow' means we continue synchronising with remaining alive sources. Use 'finalValue' option to control what data is returned for completed sources
* * 'break' means we stop the stream, because synchronisation across all sources is no longer possible.
*
* Default: 'break'.
*/
onSourceDone: `allow` | `break`;
/**
* Maximum time to wait for synchronisation to happen.
* If interval is exceeded, stream closes.
* Default: 2s
*/
maximumWait: Interval;
/**
* If we continue synchronisation when a source is done (via `onSourceDone:'allow'`),
* what source should be returned for a completed source?
* * 'undefined': _undefined_
* * 'last': the last received value, or _undefined_
*
* Default: 'undefined'
*/
finalValue: `undefined` | `last`;
};
/**
* Switcher options.
*
* match (default: 'first')
* * 'first': Outputs to first case where predicate is _true_
* * 'all': Outputs to all cases where predicate is _true_
*/
type SwitcherOptions = {
match: `first` | `all`;
};
/**
* Transform options
*/
type TransformOpts = InitStreamOptions & {
traceInput: boolean;
traceOutput: boolean;
};
type ChunkOptions = InitStreamOptions & {
/**
* If _true_ (default) remaining results are yielded
* if source closes. If _false_, only chunks that meet
* `elapsed` or `quantity` are emitted.
*/
returnRemainder: boolean;
/**
* Amount of time to gather results for a chunk.
* 'elapsed' and 'quantity' is ORed. Meaning a chunk will the minimum of
* 'elapsed' and 'quantity'
*/
elapsed: Interval;
/**
* Number of items to gather for a chunk.
* 'elapsed' and 'quantity' is ORed. Meaning a chunk will the minimum of
* 'elapsed' and 'quantity'
*/
quantity: number;
};
type DebounceOptions = InitStreamOptions & {
/**
* Minimum time between events. Default 50ms
*/
elapsed: Interval;
};
type FilterPredicate<In> = (value: In) => boolean;
type ThrottleOptions = InitStreamOptions & {
elapsed: Interval;
};
type SplitOptions = {
quantity: number;
};
type FieldOptions<TSource, TValue> = InitStreamOptions & {
/**
* If `field` is missing on a value, it is query from this object instead.
* If this also is missing, `fallbackFieldValue` is attempted.
*/
fallbackObject: TSource;
/**
* If `field` is missing on a value and `fallbackObject` (if specified),
* this value is used in its place.
* If not set, no value is emitted when the field is missing.
*/
fallbackFieldValue: TValue;
};
type SingleFromArrayOptions<V> = {
/**
* Function to select a single value from array
* @param value
* @returns
*/
predicate: (value: V) => boolean;
/**
* `default`: leave array in same order (default option)
* `random`: shuffles array before further processing
* function: function that sorts values
*/
order: `default` | `random` | ((a: V, b: V) => number);
/**
* Selects an index from array. 0 being first, 1 being second.
* Reverse indexing also works: -1 being last, -2 being second last...
*
* If index exceeds length of array, _undefined_ is returned
*/
at: number;
};
type OpAsAnnotation = {
annotate: true;
};
type OpMathOptions = Partial<InitStreamOptions> & {
annotate?: boolean;
/**
* If _true_ (default) operations that return _undefined_ do not emit a value.
* If _false_, _undefined_ is potentially emitted
*/
skipUndefined?: boolean;
/**
* If _true_ (default) operations only emit a value if it has changed.
* In the case of `max()`, for example, a stream of '1, 2, 3, 2, 1' would emit '1, 2, 3'.
* If _false_ was used, same input would emit '1, 2, 3, 3, 3'
*/
skipIdentical?: boolean;
};
//#endregion
//#region ../packages/rx/src/sinks/dom.d.ts
type SetHtmlOptionsQuery = {
query: string;
};
type SetHtmlOptionsElement = {
el: HTMLElement;
};
type SetHtmlOptions = (SetHtmlOptionsQuery | SetHtmlOptionsElement) & {
/**
* If _true_ .innerHTML is used
* If _false_ (default) .textContent is used
*/
asHtml?: boolean;
};
/**
* Values from `input` are set to the textContent/innerHTML of an element.
* ```js
* const rxSource = Rx.From.string('hello');
* const rxSet = Rx.Sinks.setHtmlText(rxSource, { query: })
* ```
* @param rxOrSource
* @param optionsOrElementOrQuery
*/
declare const setHtmlText: (rxOrSource: ReactiveOrSource<any>, optionsOrElementOrQuery: SetHtmlOptions | string | HTMLElement) => Unsubscriber;
//#endregion
//#region ../packages/rx/src/ops/math.d.ts
declare function max(input: ReactiveOrSource<any>, options: OpMathOptions): Reactive<number>;
declare function max(input: ReactiveOrSource<any>, options: OpAsAnnotation & OpMathOptions): Reactive<{
value: number;
max: number;
}>;
declare function min(input: ReactiveOrSource<any>, options: OpMathOptions): Reactive<number>;
declare function min(input: ReactiveOrSource<any>, options: OpAsAnnotation & OpMathOptions): Reactive<{
value: number;
min: number;
}>;
declare function average(input: ReactiveOrSource<any>, options: OpMathOptions): Reactive<number>;
declare function average(input: ReactiveOrSource<any>, options: OpAsAnnotation & OpMathOptions): Reactive<{
value: number;
average: number;
}>;
declare function sum(input: ReactiveOrSource<any>, options: OpMathOptions): Reactive<number>;
declare function sum(input: ReactiveOrSource<any>, options: OpAsAnnotation & OpMathOptions): Reactive<{
value: number;
sum: number;
}>;
type TallyOptions = OpMathOptions & {
countArrayItems: boolean;
};
declare function tally(input: ReactiveOrSource<any>, options: Partial<TallyOptions>): Reactive<number>;
declare function tally<TIn>(input: ReactiveOrSource<TIn>, options: OpAsAnnotation & Partial<TallyOptions>): Reactive<{
value: TIn;
tally: number;
}>;
declare function rank<TIn>(input: ReactiveOrSource<any>, rank: RankFunction<TIn>, options: Partial<RankOptions & OpMathOptions>): Reactive<TIn>;
declare function rank<TIn>(input: ReactiveOrSource<any>, rank: RankFunction<TIn>, options: OpAsAnnotation & Partial<RankOptions & OpMathOptions>): Reactive<{
value: TIn;
rank: TIn;
}>;
//#endregion
//#region ../packages/rx/src/types.d.ts
type CombineLatestOptions = {
/**
* If _true_, disposes all the merged sources when the merged reactive closes.
* Default: _true_.
*/
disposeSources: boolean;
/**
* How to handle when a source ends.
* * 'allow': continue combined stream, last value for done stream will kept
* * 'break': stop combined stream
*
* Default: 'break'
*/
onSourceDone: `allow` | `break`;
/**
* If _true_ (default), emits a value when initialised.
*/
emitInitial: boolean;
};
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
declare const symbol: unique symbol;
type SignalKinds = `done` | `warn`;
type Passed<V> = {
value: V | undefined;
signal?: SignalKinds;
context?: string;
};
type PassedSignal = Passed<any> & {
value: undefined;
signal: SignalKinds;
context: string;
};
type PassedValue<V> = Passed<V> & {
value: V;
};
type UpstreamOptions<In> = {
lazy: Lazy;
/**
* If _true_ (default), we dispose the underlying stream if the upstream closes. This happens after onStop() is called.
*/
disposeIfSourceDone: boolean;
onValue: (v: In) => void;
/**
* Called just before we subscribe to source
* @returns
*/
onStart: () => void;
/**
* Called after we unsubscribe from source
* @returns
*/
onStop: () => void;
debugLabel: string;
onDispose: (reason: string) => void;
};
type UpstreamInitialOptions<In> = UpstreamOptions<In> & {
initialValue: In;
};
/**
* Wrapped Reactive for object-oriented access
*/
type Wrapped<TIn> = {
enacts: {
setHtmlText: (options: SetHtmlOptions) => () => void;
};
source: Reactive<TIn>;
/**
* Annotate values with output from the `annotation` function.
* Returned values will be in the form `{ value:TIn, annotation:TAnnotation }`
* @param transformer
* @returns
*/
annotate: <TAnnotation>(transformer: (value: TIn) => TAnnotation) => Wrapped<{
value: TIn;
annotation: TAnnotation;
}>;
annotateWithOp: <TOut>(op: ReactiveOp<TIn, TOut>) => Wrapped<{
value: TIn;
annotation: TOut;
}>;
/**
* Accumulate a chunk of values, emitted as an array
* @param options
* @returns
*/
chunk: (options: Partial<ChunkOptions>) => Wrapped<TIn[]>;
debounce: (options: Partial<DebounceOptions>) => Wrapped<TIn>;
/**
* Pluck and emit a single field from values
* @param fieldName
* @param options
* @returns
*/
field: <TSource, TFieldType>(fieldName: keyof TIn, options: Partial<FieldOptions<TSource, TFieldType>>) => Wrapped<TFieldType>;
/**
* Throws away values that don't match `predicate`
* @param predicate
* @param options
* @returns
*/
filter: (predicate: FilterPredicate<TIn>, options: Partial<InitStreamOptions>) => Wrapped<TIn>;
combineLatestToArray: <const T extends readonly ReactiveOrSource<any>[]>(sources: T, options: Partial<CombineLatestOptions>) => Wrapped<RxValueTypes<T>>;
combineLatestToObject: <const T extends Record<string, ReactiveOrSource<any>>>(sources: T, options: {
name: string;
} & Partial<CombineLatestOptions>) => Wrapped<RxValueTypeObject<T>>;
min: (options?: Partial<OpMathOptions>) => Wrapped<number>;
max: (options?: Partial<OpMathOptions>) => Wrapped<number>;
average: (options?: Partial<OpMathOptions>) => Wrapped<number>;
sum: (options?: Partial<OpMathOptions>) => Wrapped<number>;
tally: (options?: Partial<TallyOptions>) => Wrapped<number>;
/**
* Converts one source stream into two, with values being emitted by both
* @param options
* @returns
*/
split: (options?: Partial<SplitOptions>) => Wrapped<TIn>[];
/**
* Emits values when this stream and any additional streams produce a value. The resulting stream is
* thus an array of values, each source at a given index.
* Waits to output a value until each stream has produced a value. Thus, the pace is determined by
* the slowest stream.
* @returns
*/
syncToArray: <const T extends readonly ReactiveOrSource<any>[]>(reactiveSources: T, options?: Partial<SyncOptions>) => Wrapped<[TIn, ...RxValueTypes<T>]>;
syncToObject: <const T extends Record<string, ReactiveOrSource<any>>>(reactiveSources: T, options?: {
name?: string;
} & Partial<SyncOptions>) => Wrapped<RxValueTypeObject<T>>;
/**
* Creates new streams for each case, sending values to the stream if they match the filter predicate
* @param cases
* @param options
* @returns
*/
switcher: <TRec extends Record<string, FilterPredicate<TIn>>, TLabel extends keyof TRec>(cases: TRec, options: Partial<SwitcherOptions>) => Record<TLabel, Wrapped<TIn>>;
/**
* Creates new streams for each case
* @param labels
* @returns
*/
splitLabelled: <K extends keyof TIn>(...labels: K[]) => Record<K, Wrapped<TIn>>;
/**
* Taps the stream, passing values to one or more 'processor' functions.
* This processing essentially happens in parallel, not affecting the main stream.
*
* ```js
* // Stream of pointermove events with {x:0,y:0} as default
* const move = Rx.From.event(document.body, `pointermove`, {x:0,y:0});
* // Wrap it for fluent access
* const ptr = Rx.wrap(move)
* .tapProcess(
* // Create a string representation
* v => `${v.x},${v.y}`
* // Set to DOM
* v => {
* document.getElementById(`coords`).innerText = v;
* }
* )
* .onValue(value => {
* // 'value' will be original PointerEvent, since .tapProcess happened in parallel,
* // not affecting stream
* });
* ```
* @param processors One-five processing functions
* @returns
*/
tapProcess: <T2, T3, T4, T5, T6>(...processors: Processors<TIn, T2, T3, T4, T5, T6>) => Wrapped<TIn>;
tapStream: (divergedStream: ReactiveWritable<TIn>) => Wrapped<TIn>;
tapOps: <TOut>(source: ReactiveOrSource<TIn>, ...ops: ReactiveOp<TIn, TOut>[]) => Wrapped<TIn>;
/**
* Transforms all values
* @param transformer
* @param options
* @returns
*/
transform: <TOut>(transformer: (value: TIn) => TOut, options?: Partial<TransformOpts>) => Wrapped<TOut>;
/**
* Only allow values through if a minimum of time has elapsed. Throws away values.
* Ie. converts a fast stream into a slower one.
* @param options
* @returns
*/
throttle: (options: Partial<ThrottleOptions>) => Wrapped<TIn>;
/**
* Emits a value if `source` does not emit a value after `interval`
* has elapsed. This can be useful to reset a reactive to some
* 'zero' state if nothing is going on.
*
* If `source` emits faster than the `interval`, it won't get triggered.
*
* Default for 'timeout': 1000s.
*
* ```js
* // Emit 'hello' if 'source' doesn't emit a value after 1 minute
* const r = Rx.timeoutValue(source, { value: 'hello', interval: { mins: 1 } });
* ```
*
* Can also emit results from a function or generator
* ```js
* // Emits a random number if 'source' doesn't emit a value after 500ms
* const r = Rx.timeoutValue(source, { fn: Math.random, interval: 500 });
* ```
*
* If `immediate` option is _true_ (default), the timer starts from stream initialisation.
* Otherwise it won't start until it observes the first value from `source`.
* @param options
*/
timeoutValue: <TTriggerValue>(options: TimeoutValueOptions<TTriggerValue>) => Wrapped<TIn | TTriggerValue>;
/**
* 'Pings' reactive (if it supports it) if a value is not received within a given interval.
* Behaviour can be stopped using an abort signal.
* @param options
* @returns
*/
timeoutPing: (options: TimeoutPingOptions) => Wrapped<TIn>;
/**
* Copies values from source into an array, throwing
* an error if expected number of items is not reached
* @param options
* @returns
*/
toArrayOrThrow: (options: Partial<ToArrayOptions<TIn>>) => Promise<TIn[]>;
/**
* Copies values from source into an array.
* @param options
* @returns
*/
toArray: (options: Partial<ToArrayOptions<TIn>>) => Promise<(TIn | undefined)[]>;
/**
* Listen for values
* @param callback
* @returns
*/
onValue: (callback: (value: TIn) => void) => void;
};
type ToArrayOptions<V> = {
/**
* Maximim time to wait for `limit` to be reached. 10s by default.
*/
maximumWait: Interval;
/**
* Number of items to read
*/
limit: number;
/**
* Behaviour if threshold is not reached.
* partial: return partial results
* throw: throw an error
* fill: fill remaining array slots with `fillValue`
*/
underThreshold: `partial` | `throw` | `fill`;
/**
* Value to fill empty slots with if `underThreshold = 'fill'`.
*/
fillValue: V;
};
/**
* Laziness
* * start: only begins on first subscriber. Keeps running even when there are no subscribers
* * very: only begins on first subscriber. Stops looping if there are no subscribers
* * never: begins calling function when initalised and doesn't stop until Reactive is disposed
*/
type Lazy = `initial` | `never` | `very`;
type InitLazyStreamOptions = Partial<InitStreamOptions> & {
lazy?: Lazy;
debugLabel?: string;
onStart: () => void;
onStop: () => void;
};
type InitLazyStreamInitedOptions<T> = InitLazyStreamOptions & {
initialValue: T;
};
type ReactiveOrSource<V> = Wrapped<V> | Reactive<V> | IterableIterator<V> | AsyncIterableIterator<V> | Generator<V> | AsyncGenerator<V> | V[] | (() => V);
/**
* A Reactive
*/
type Reactive<V> = {
/**
* Subscribes to a reactive. Receives
* data as well as signals. Use `onValue` if you
* just care about values.
*
* Return result unsubscribes.
*
* ```js
* const unsub = someReactive.on(msg => {
* // Do something with msg.value
* });
*
* unsub(); // Unsubscribe
* ```
* @param handler
*/
on(handler: (value: Passed<V>) => void): Unsubscriber;
/**
* Subscribes to a reactive's values.
* Returns a function that unsubscribes.
* @param handler
*/
onValue(handler: (value: V) => void): Unsubscriber;
/**
* Disposes the reactive, providing a reason for debug tracing
* @param reason
*/
dispose(reason: string): void;
/**
* Returns _true_ if Reactive is disposed
*/
isDisposed(): boolean;
/**
* Optional 'set' to write a value. Use {@link ReactiveWritable} if you want this non-optional
* @param value
*/
set?(value: V): void;
};
/**
* A reactive that can be 'pinged' to produce a value.
*
* Use {@link isPingable} to check if a reactive is pingable.
*
* Pingable reactives are returned from
* * interpolate
* * computeWithPrevious
* * valueToPing
*/
type ReactivePingable<V> = Reactive<V> & {
ping(): void;
};
type Unsubscriber = () => void;
type ReactiveNonInitial<V> = Reactive<V> & {
last(): V | undefined;
};
/**
* A stream that can be written to
*/
type ReactiveWritable<TIn, TOut = TIn> = Reactive<TOut> & {
/**
* Sets a value
* @param value Value to write
*/
set(value: TIn): void;
};
type ReactiveInitial<V> = Reactive<V> & {
last(): V;
};
type ReactiveFinite = {
isDone(): boolean;
};
type ReactiveArray<V> = ReactiveWritable<V[]> & {
push(value: V): void;
deleteAt(index: number): void;
deleteWhere(filter: (value: V) => boolean): number;
setAt(index: number, value: V): void;
insertAt(index: number, value: V): void;
onArray(handler: (changes: Passed<ChangeRecord<number>[]>) => void): () => void;
};
type ObjectFieldHandler = {
value: any;
fieldName: string;
pattern: string;
};
type ReactiveDiff<V> = Reactive<V> & ReactiveWritable<V> & {
/**
* Notifies when the value of `fieldName` is changed.
*
* Use the returned function to unsubscribe.
* @param fieldName
* @param handler
*/
onField(fieldName: string, handler: (result: ObjectFieldHandler) => void): () => void;
/**
* Notifies of which field(s) were changed.
* If you just care about the whole, changed data use the `value` event.
*
* Use the returned function to unsubscribe.
* @param changes
*/
onDiff(changes: (changes: PathDataChange<any>[]) => void): () => void;
/**
* Updates the reactive with some partial key-value pairs.
* Keys omitted are left the same as the current value.
* @param changedPart
* @returns Returns new value
*/
update(changedPart: RecursivePartial<V>): V;
/**
* Updates a particular field by its path
* @param field
* @param value
*/
updateField(field: string, value: any): void;
};
/**
* A reactive stream which can be read and written to
*/
type ReactiveStream<V> = Reactive<V> & ReactiveWritable<V> & {
/**
* Removes all the subscribers from this stream.
*/
removeAllSubscribers(): void;
/**
* Dispatches a signal
* @param signal
* @param context
*/
signal(signal: SignalKinds, context?: string): void;
};
type ReactiveInitialStream<V> = ReactiveStream<V> & ReactiveInitial<V>;
type PipeSet<In, Out> = [Reactive<In>, ...(Reactive<any> & ReactiveWritable<any>)[]];
type InitStreamOptions = {
/**
* Optional label to associate with this stream. Useful for debugging.
*/
debugLabel: string;
/**
* Called when there is a subscriber after there were no subscribers.
* Useful for 'startup' types of things that we want to run only when someone is actually listening.
*
* During the lifeycle of a stream, this could be called multiple times. Eg if all subscribers are removed
* next time someone subscribes it will get called again.
* @returns
*/
onFirstSubscribe: () => void;
/**
* Called when there are no longer any subscribers. Useful for shutting down
* activities now that no-one is listening.
*
* During the lifecycle of a stream, this could be called multiple times.
* @returns
*/
onNoSubscribers: () => void;
/**
* Called whenever the stream disposes. Useful for cleaning up.
* @param reason
* @returns
*/
onDispose: (reason: string) => void;
};
/**
* WithValue stream options
*/
type WithValueOptions<V> = Partial<InitStreamOptions> & {
/**
* Initial value
*/
initial: V;
/**
* Laziness
*/
lazy?: Lazy;
};
type ResolveOptions = {
/**
* How many times to return value or call function.
* If _infinite_ is set to true, this value is ignored
*/
loops: number;
/**
* If _true_ loops forever
*/
infinite: boolean;
/**
* Delay before value
*/
interval: Interval;
lazy: Lazy;
};
type ReactiveOpInit<TIn, TOut, TOpts> = (options: Partial<TOpts>) => ReactiveOp<TIn, TOut>;
type ReactiveOp<TIn, TOut> = (source: ReactiveOrSource<TIn>) => Reactive<TOut>;
type ReactiveOpLinks<In, Out> = [ReactiveOrSource<In>, ...ReactiveOp<any, any>[], ReactiveOp<any, Out>];
type RxValueTypes<T extends readonly ReactiveOrSource<any>[]> = { [K in keyof T]: T[K] extends Reactive<infer V> ? V | undefined : T[K] extends Wrapped<infer V> ? V | undefined : T[K] extends Generator<infer V> ? V | undefined : T[K] extends AsyncGenerator<infer V> ? V | undefined : T[K] extends IterableIterator<infer V> ? V | undefined : T[K] extends AsyncIterableIterator<infer V> ? V | undefined : T[K] extends (infer V)[] ? V | undefined : never };
type RxValueTypeObject<T extends Record<string, ReactiveOrSource<any>>> = { [K in keyof T]: T[K] extends Reactive<infer V> ? V : T[K] extends Wrapped<infer V> ? V : T[K] extends Generator<infer V> ? V : T[K] extends AsyncGenerator<infer V> ? V : T[K] extends IterableIterator<infer V> ? V : T[K] extends AsyncIterableIterator<infer V> ? V : T[K] extends (infer V)[] ? V : never };
type RxValueTypeObjectOrUndefined<T extends Record<string, ReactiveOrSource<any>>> = { [K in keyof T]: T[K] extends Reactive<infer V> ? V | undefined : T[K] extends Wrapped<infer V> ? V | undefined : T[K] extends Generator<infer V> ? V | undefined : T[K] extends AsyncGenerator<infer V> ? V | undefined : T[K] extends IterableIterator<infer V> ? V | undefined : T[K] extends AsyncIterableIterator<infer V> ? V | undefined : T[K] extends (infer V)[] ? V | undefined : never };
type RxValueTypeRx<T extends Record<string, ReactiveOrSource<any>>> = { [K in keyof T]: T[K] extends Reactive<infer V> ? Reactive<V> : T[K] extends Wrapped<infer V> ? Reactive<V> : T[K] extends Generator<infer V> ? Reactive<V> : T[K] extends AsyncGenerator<infer V> ? Reactive<V> : T[K] extends IterableIterator<infer V> ? Reactive<V> : T[K] extends AsyncIterableIterator<infer V> ? Reactive<V> : T[K] extends (infer V)[] ? Reactive<V> : never };
type PrimitiveValueTypeObject<T extends Record<string, Primitive>> = { [K in keyof T]: T[K] extends number ? number | undefined : T[K] extends string ? string | undefined : T[K] extends boolean ? boolean | undefined : T[K] extends bigint ? bigint | undefined : never };
//#endregion
//#region ../packages/rx/src/from/types.d.ts
type TriggerValue<TTriggerValue> = {
value: TTriggerValue;
};
/**
* Options for the 'count' source.
*/
type CountOptions = {
/**
* Determines when counting starts
* @defaultValue 'initial'
*/
lazy: Lazy;
/**
* Amount to increment by
* @defaultValue 1
*/
amount: number;
/**
* Where to begin counting
* @defaultValue 0
*/
offset: number;
/**
* How long to wait before incrementing.
* @defaultValue 1 second
*/
interval: Interval;
/**
* Abort signal to trigger the source to close.
*/
signal: AbortSignal;
};
/**
* Function which returns a result. Or promised result.
*
* `abort` value is a callback to exit out of looped execution.
*/
type FunctionFunction<T> = ((abort: (reason: string) => void) => T) | ((abort: (reason: string) => void) => Promise<T>);
type ArrayOptions = {
/**
* Interval between each item being read. Default: 5ms.
*/
interval: Interval;
lazy: Lazy;
/**
* Behaviour when reactive stops, for example due to having no subscribers
* * continue: iteration continues through array where it left off
* * reset: iteration begins from start of array
*/
whenStopped: `continue` | `reset`;
debugLifecycle: boolean;
signal: AbortSignal;
};
/**
* Function which returns a result. Or promised result.
* Takes a `value` as first parameter, and callback to signal an abort as the second.
*/
type PingedFunctionFunction<T, TSource> = ((value: TSource, abort: (reason: string) => void) => T) | ((value: TSource, abort: (reason: string) => void) => Promise<T>);
/**
* Trigger that calls a `fn`.
* If `fn` returns _undefined_, it means the trigger is complete
*/
type TriggerFunction<TTriggerValue> = {
fn: () => TTriggerValue;
};
type TriggerGenerator<TTriggerValue> = {
gen: IterableIterator<TTriggerValue>;
};
/**
* A trigger can be a value, a function or generator. Value triggers never complete.
*
* A trigger function is considered complete if it returns undefined.
* A trigger generator is considered complete if it returns done.
*
*/
type Trigger<TTriggerValue> = TriggerValue<TTriggerValue> | TriggerFunction<TTriggerValue> | TriggerGenerator<TTriggerValue>;
type TimeoutPingOptions = Interval & {
/**
* If abort signals, it will disable
*/
abort?: AbortSignal;
};
type TimeoutValueOptions<TTriggerValue> = Trigger<TTriggerValue> & {
/**
* Whether to repeatedly trigger even if upstream source doesn't emit values.
* When _false_ (default) it will emit a max of one value after a source value if `interval` is reached.
* When _true_, it will continue emitting values at `interval`.
* Default: false
*/
repeat?: boolean;
/**
* Interval before emitting trigger value
* Default: 1s
*/
interval: Interval;
/**
* If _true_ (default) start the timeout
* immediately, even before the first value.
* If _false_, it won't timeout until the first
* upstream value happens.
*/
immediate?: boolean;
};
/**
* Options when creating a reactive object.
*/
type ObjectOptions<V extends Record<string, unknown>> = {
/**
* _false_ by default.
* If _true_, inherited fields are included. This is necessary for event args, for example.
*/
deepEntries: boolean;
/**
* Uses JSON.stringify() by default.
* Fn that returns _true_ if two values are equal, given a certain path.
*/
eq: IsEqualContext<V>;
};
type ValueToPingOptions<TUpstream> = {
/**
* If set, this function acts as a threshold gate.
* If the function returns _true_ the upstream value will trigger a ping
* Otherwise the value won't trigger a ping.
*
* By default all values trigger a ping.
* @param value
* @returns
*/
gate: (value: TUpstream) => boolean;
/**
* Laziness
* * start: only begins on first subscriber. Keeps running even when there are no subscribers
* * very: only begins on first subscriber. Stops looping if there are no subscribers
* * never: begins calling function when initalised and doesn't stop until Reactive is disposed
*/
lazy: Lazy;
/**
* If specified, signal is checked to prevent function execution.
* Also used for aborting a looped fromFunction.
*/
signal: AbortSignal;
};
type PingedFunctionOptions = {
/**
* If _true_, stream closes if function throws an error.
* If _false_, errors are emitted as signals, but stream is not closed.
* Default: _true_
*/
closeOnError: boolean;
/**
* Laziness
* * start: only begins on first subscriber. Keeps running even when there are no subscribers
* * very: only begins on first subscriber. Stops looping if there are no subscribers
* * never: begins calling function when initalised and doesn't stop until Reactive is disposed
*/
lazy: Lazy;
/**
* If specified, a time before invoking function.
* If `repeat` is used, this is in addition to `interval` time.
*/
predelay: Interval;
/***
* If specified, signal is checked to prevent function execution.
* Also used for aborting a looped fromFunction.
*/
signal: AbortSignal;
};
/**
* Options when creating a reactive object.
*/
type ArrayObjectOptions<V> = {
/**
* Uses JSON.stringify() by default.
* Fn that returns _true_ if two values are equal, given a certain path.
*/
eq: IsEqual<V>;
};
type FunctionOptions = Partial<InitLazyStreamOptions> & {
/**
* If _true_, stream closes if function throws an error.
* If _false_, errors are emitted as signals, but stream is not closed.
* Default: _true_
*/
closeOnError: boolean;
/**
* Laziness
* * start: only begins on first subscriber. Keeps running even when there are no subscribers
* * very: only begins on first subscriber. Stops looping if there are no subscribers
* * never: begins calling function when initalised and doesn't stop until Reactive is disposed
*/
lazy: Lazy;
/**
* If _true_, no automatic calling of function will happen, it will only
* be executed if the reactive gets a ping
* When this is set, 'interval' is ignored. 'maximumRepeats' and 'predelay' still apply.
* Default: _false_
*/
manual: boolean;
/**
* If specified, sets an upper limit of how many times we loop
* (if this is also enabled)
*/
maximumRepeats: number;
/**
* If specified, function is called repeatedly with this delay
*/
interval: Interval;
/**
* If specified, a time before invoking function.
* If `repeat` is used, this is in addition to `interval` time.
*/
predelay: Interval;
/***
* If specified, signal is checked to prevent function execution.
* Also used for aborting a looped fromFunction.
*/
signal: AbortSignal;
};
type GeneratorOptions = {
traceLifecycle: boolean;
/**
* Wait between reading from generator
* Default: 5ms
*/
readInterval: Interval;
/**
* Timeout when waiting for a value
* Default: `{ mins: 5 }`
*/
readTimeout: Interval;
/**
* If _true_, only accesses the generator if there is a subscriber.
* Default: true
*/
lazy: Lazy;
signal: AbortSignal;
/**
* Behaviour when reactive stops, for example due to having no subscribers
* * continue: iteration continues through array where it left off
* * reset: iteration begins from start of array
*/
whenStopped: `continue` | `reset`;
};
type EventSourceOptions = {
/**
* If true, behaves like Source.object where event
* properties are compared and source only
* emits where there is a change.
*
* Default: _false_
*/
diff?: boolean;
lazy?: Lazy;
/**
* If true, log messages are emitted
* when event handlers are added/removed
*/
debugLifecycle?: boolean;
/**
* If true, log messages are emitted
* when the source event fires
*/
debugFiring?: boolean;
};
type EventSourceTriggerOptions = EventSourceOptions & {
/**
* If _true_ sends an initial trigger when starting
* Default: false
*/
fireInitial: boolean;
};
type EventPluckedFieldOptions<T> = {
lazy?: Lazy;
initialValue: T;
};
type EventPluckedFieldOptions2<TDomSource, TValueDestination> = {
lazy?: Lazy;
initialValue: TValueDestination;
domToValue: (value: TDomSource | undefined) => TValueDestination | undefined;
valueToDom: (value: TValueDestination) => TDomSource;
};
type DerivedFunction<TOutput> = (...args: unknown[]) => TOutput;
type DerivedOptions<TResult, T> = {
ignoreIdentical: boolean;
eq: (a: TResult, b: TResult) => boolean;
} & CombineLatestOptions & UpstreamOptions<T>;
//#endregion
//#region ../packages/rx/src/ops/annotate.d.ts
/**
* Annotates values from `source`. Output values will be
* in the form `{ value: TIn, annotation: TAnnotation }`.
* Where `TIn` is the type of the input, and `TAnnotation` is
* the return type of the annotator function.
*
* Example calculating area from width & height:
* ```js
* const data = Rx.From.array(
* { w: 1, h: 3 }, { w: 1, h: 1 }, { w: 2, h: 2 }
* );
* const annotated = Rx.Ops.annotate(data, v => {
* return { area: v.w * v.h }
* });
* const data = await Rx.toArray(annotated);
* // Data = [ { value: { w:1, h:3 }, annotation: { area:3 } } ...]
* ```
*
* If you would rather annotate and have values merge with the input,
* use `transform`:
* ```js
* const data = Rx.From.array(
* { w: 1, h: 3 }, { w: 1, h: 1 }, { w: 2, h: 2 }
* );
* const withArea = Rx.Ops.transform(data, v => {
* return { ...v, area: v.w * v.h }
* });
* const data = await Rx.toArray(withArea);
* // Data = [ { w:1, h:3, area:3 }, ...]
* ```
*/
declare function annotate<In, TAnnotation>(input: ReactiveOrSource<In>, annotator: (value: In) => TAnnotation, options?: Partial<TransformOpts>): Reactive<{
value: In;
annotation: TAnnotation;
}>;
/**
* Annotates the input stream using {@link ReactiveOp} as the source of annotations.
* The output values will have the shape of `{ value: TIn, annotation: TAnnotation }`.
* Meaning that the original value is stored under `.value`, and the annotation under `.annotation`.
*
* ```js
* const data = Rx.From.array([ 1, 2, 3 ]);
* const annotated = Rx.Ops.annotateWithOp(data, Rx.Ops.sum());
* const data = await annotated.toArray(annotated);
* // Data = [ { value: 1, annotation: 1 }, { value: 2, annotation: 3 }, { value: 3, annotation: 6 } ]
* ```
* @param annotatorOp Operator to generate annotations
* @param input Input stream
* @returns
*/
declare function annotateWithOp<In, TAnnotation>(input: ReactiveOrSource<In>, annotatorOp: ReactiveOp<In, TAnnotation>): Reactive<{
value: In;
annotation: TAnnotation;
}>;
//#endregion
//#region ../packages/rx/src/ops/chunk.d.ts
/**
* Queue from `source`, emitting when thresholds are reached.
* The resulting Reactive produces arrays.
*
* Can use a combination of elapsed time or number of data items.
*
* By default options are OR'ed together.
*
* ```js
* // Emit data in chunks of 5 items
* chunk(source, { quantity: 5 });
* // Emit a chunk of data every second
* chunk(source, { elapsed: 1000 });
* ```
* @param source
* @param options
* @returns
*/
declare function chunk<V>(source: ReactiveOrSource<V>, options?: Partial<ChunkOptions>): Reactive<V[]>;
//#endregion
//#region ../packages/rx/src/ops/clone-from-fields.d.ts
/**
* Create a new object from input, based on cloning fields rather than a destructured copy.
* This is useful for event args.
* @param source
* @returns
*/
declare const cloneFromFields: <In>(source: ReactiveOrSource<In>) => Reactive<In>;
//#endregion
//#region ../packages/rx/src/ops/combine-latest-to-array.d.ts
/**
* Monitors input reactive values, storing values as they happen to an array.
* Whenever a new value is emitted, the whole array is sent out, containing current
* values from each source, or _undefined_ if not yet emitted.
*
* See {@link combineLatestToObject} to combine streams by name into an object, rather than array.
*
* ```
* const sources = [
* Rx.fromFunction(Math.random, { loop: true, interval: 100 }),
* Rx.fromFunction(Math.random, { loop: true, interval: 200 })
* ];
* const r = Rx.combineLatestToArray(sources);
* r.onValue(value => {
* // Value will be an array of last value from each source:
* // [number,number]
* });
* ```
*
* The tempo of this stream will be set by the fastest source stream.
* See {@link syncToArray} to have pace determined by slowest source, and only
* send when each source has produce a new value compared to last time.
*
* Set `onSourceDone` to choose behaviour if a source stops. By default it
* is 'break', meaning the whole merged stream stops.
*
* Note: unlike RxJS's `combineLatest`, does not wait for each source to emit once
* before emitting first value.
* @param reactiveSources Sources to merge
* @param options Options for merging
* @returns
*/
declare function combineLatestToArray<const T extends readonly ReactiveOrSource<any>[]>(reactiveSources: T, options?: Partial<CombineLatestOptions>): Reactive<RxValueTypes<T>>;
//#endregion
//#region ../packages/rx/src/ops/combine-latest-to-object.d.ts
type CombineLatestToObject<T extends Record<string, ReactiveOrSource<any>>> = {
hasSource: (field: string) => boolean;
replaceSource: (field: Extract<keyof T, string>, source: ReactiveOrSource<any>) => void;
/**
* Reactive sources being combined
*/
sources: RxValueTypeRx<T>;
/**
* Updates writable sources with values.
* @param data
* @returns Keys and values set to writable source(s)
*/
setWith: (data: Partial<RxValueTypeObject<T>>) => Partial<RxValueTypeObject<T>>;
} & ReactiveDiff<RxValueTypeObject<T>> & ReactiveInitial<RxValueTypeObject<T>>;
/**
* Monitors input reactive values, storing values as they happen to an object.
* Whenever a new value is emitted, the whole object is sent out, containing current
* values from each source (or _undefined_ if not yet emitted)
*
* See {@link combineLatestToArray} to combine streams by name into an array instead.
*
* ```
* const sources = {
* fast: Rx.fromFunction(Math.random, { loop: true, interval: 100 }),
* slow: Rx.fromFunction(Math.random, { loop: true, interval: 200 })
* ];
* const r = Rx.combineLatestToObject(sources);
* r.onValue(value => {
* // 'value' will be an object containing the labelled latest
* // values from each source.
* // { fast: number, slow: number }
* });
* ```
*
* The tempo of this stream will be set by the fastest source stream.
* See {@link syncToObject} to have pace determined by slowest source, and only
* send when each source has produce a new value compared to last time.
*
* This source ends if all source streams end.
* @param reactiveSources Sources to merge
* @param options Options for merging
* @returns
*/
declare function combineLatestToObject<const T extends Record<string, ReactiveOrSource<any>>>(reactiveSources: T, options?: Partial<CombineLatestOptions>): CombineLatestToObject<T>;
//#endregion
//#region ../packages/rx/src/ops/compute-with-previous.d.ts
/**
* When there is a value from `input`, or the reactive is pinged,
* this reactive emits the result of `fn`.
*
* `fn` is provided the previous value as well as the most recent value.
*
* If no previous value is available, the current value is emitted and `fn` is not called.
* @param input
* @param fn
* @returns
*/
declare function computeWithPrevious<TIn>(input: ReactiveOrSource<TIn>, fn: (previous: TIn, current: TIn) => TIn): ReactivePingable<TIn>;
//#endregion
//#region ../packages/rx/src/ops/debounce.d.ts
declare function debounce<V>(options: Partial<DebounceOptions>): ReactiveOp<V, V>;
//#endregion
//#region ../packages/rx/src/ops/elapsed.d.ts
/**
* Emits time in milliseconds since last message.
* If it is the first value, 0 is used.
* @param input
* @returns
*/
declare const elapsed: <In>(input: ReactiveOrSource<In>) => Reactive<number>;
//#endregion
//#region ../packages/rx/src/ops/field.d.ts
/**
* From a source value, yields a field from it. Only works
* if stream values are objects.
*
* If a source value doesn't have that field, it is skipped.
*
* @returns
*/
declare function field<TIn extends object, TFieldType>(fieldSource: ReactiveOrSource<TIn>, fieldName: keyof TIn, options?: Partial<FieldOptions<TIn, TFieldType>>): Reactive<TFieldType>;
//#endregion
//#region ../packages/rx/src/ops/filter.d.ts
/**
* Passes all values where `predicate` function returns _true_.
*/
declare function filter<In>(input: ReactiveOrSource<In>, predicate: FilterPredicate<In>, options: Partial<InitStreamOptions>): Reactive<In>;
/**
* Drops all values where `predicate` function returns _true_.
*/
declare function drop<In>(input: ReactiveOrSource<In>, predicate: FilterPredicate<In>, options: Partial<InitStreamOptions>): Reactive<In>;
//#endregion
//#region ../packages/rx/src/ops/interpolate.d.ts
type OpInterpolateOptions = InterpolateOptions & {
amount: number;
/**
* Percentage of value that we consider 'done'.
* Since interpolation can never converge to target exactly, this allows us to snap to completion.
* Default: 0.99, meaning if value gets to within 99%, return the target.
*/
snapAt: number;
};
/**
* Interpolates to the source value.
*
* Outputs one value for every input value. Thus, to interpolation
* over time, it's necessary to get the source to emit values at the desired rate.
*
* Options can specify an easing name or custom transform of easing progress.
* @param input
* @param options
* @returns
*/
declare function interpolate(input: ReactiveOrSource<number>, options?: Partial<OpInterpolateOptions>): ReactivePingable<number>;
//#endregion
//#region ../packages/rx/src/ops/pipe.d.ts
/**
* Pipes the output of one stream into another, in order.
* The stream returned is a new stream which captures the final output.
*
* If any stream in the pipe closes the whole pipe is closed.
* @param streams
* @returns
*/
declare const pipe: <TInput, TOutput>(...streams: PipeSet<TInput, TOutput>) => Reactive<TOutput>;
//#endregion
//#region ../packages/rx/src/ops/single-from-array.d.ts
/**
* For a stream that emits arrays of values, this op will select a single value.
*
* Can select based on:
* * predicate: a function that returns _true_ for a value
* * at: selection based on array index (can be combined with random ordering to select a random value)
*
* ```js
* // If source is Reactive<Array<number>>, picks the first even number
* singleFromArray(source, {
* predicate: v => v % 2 === 0
* });
*
* // Selects a random value from source
* singleFromArray(source, {
* order: `random`,
* at: 0
* });
* ```
*
* If neither `predicate` or `at` options are given, exception is thrown.
* @param source Source to read from
* @param options Options for selection
* @returns
*/
declare function singleFromArray<V>(source: ReactiveOrSource<V[]>, options?: Partial<SingleFromArrayOptions<V>>): Reactive<V>;
//#endregion
//#region ../packages/rx/src/ops/split.d.ts
/**
* Creates a set of streams each of which receives data from `source`.
* By default these are lazy and dispose if the upstream source closes.
*
* See also {@link splitLabelled} to split into named streams.
* @param rxOrSource
* @param options
* @returns
*/
declare const split: <T>(rxOrSource: ReactiveOrSource<T>, options?: Partial<SplitOptions>) => ReactiveStream<T>[];
/**
* Splits `source` into several duplicated streams.
* Returns an object with keys according to `labels`.
* Each value is a stream which echos the values from `source`.
* ```js
* const { a, b, c} = splitLabelled(source, `a`, `b`, `c`);
* // a, b, c are Reactive types
* ```
*
* See also {@link split} to get an unlabelled split
* @param rxOrSource
* @param labels
* @returns
*/
declare const splitLabelled: <T, K extends PropertyKey>(rxOrSource: ReactiveOrSource<T>, labels: K[]) => Record<K, Reactive<T>>;
//#endregion
//#region ../packages/rx/src/ops/switcher.d.ts
/**
* Switcher generates several output streams, labelled according to the values of `cases`.
* Values from `source` are fed to the output streams if their associated predicate function returns _true_.
*
* In this way, we can split one input stream into several output streams, each potentially getting a different
* subset of the input.
*
* With `options`, you can specify whether to send to multiple outputs if several match, or just the first (default behaviour).
*
* The below example shows setting up a switcher and consuming the output streams.
* @example
* ```js
* // Initialise a reactive number, starting at 0
* const switcherSource = Reactive.number(0);
* // Set up the switcher
* const x = Reactive.switcher(switcherSource, {
* even: v => v % 2 === 0,
* odd: v => v % 2 !== 0
* });
* // Listen for outputs from each of the resulting streams
* x.even.on(msg => {
* log(`even: ${msg.value}`);
* });
* x.odd.on(msg => {
* log(`odd: ${msg.value}`);
* })
* // Set new values to the number source, counting upwards
* // ...this will in turn trigger the outputs above
* setInterval(() => {
* switcherSource.set(switcherSource.last() + 1);
* }, 1000);
* ```
*
* If `source` closes, all the output streams will be closed as well.
* @param reactiveOrSource
* @param cases
* @param options
* @returns
*/
declare const switcher: <TValue, TRec extends Record<string, FilterPredicate<TValue>>, TLabel extends keyof TRec>(reactiveOrSource: ReactiveOrSource<TValue>, cases: TRec, options?: Partial<SwitcherOptions>) => Record<TLabel, Reactive<TValue>>;
//#endregion
//#region ../packages/rx/src/ops/sync-to-array.d.ts
/**
* Waits for all sources to produce a value, sending the combined results as an array.
* After sending, it waits again for each source to send at least one value.
*
* Use {@link syncToObject} to output objects based on labelled sources rather than an array of values.
*
* Pace will be set by the slowest source. Alternatively, use {@link combineLatestToArray} where the rate is determined by fastest source.
*
* Only complete results are sent. For example if source A & B finish and source C is still producing values,
* synchronisation is not possible because A & B stopped producing values. Thus the stream will self-terminate
* after `maximumWait` (2 seconds). The newer values from C are lost.
*/
declare function syncToArray<const T extends readonly ReactiveOrSource<any>[]>(reactiveSources: T, options?: Partial<SyncOptions>): Reactive<RxValueTypes<T>>;
//#endregion
//#region ../packages/rx/src/ops/sync-to-object.d.ts
declare function syncToObject<const T extends Record<string, ReactiveOrSource<any>>>(reactiveSources: T, options?: Partial<SyncOptions>): Reactive<RxValueTypeObject<T>>;
//#endregion
//#region ../packages/rx/src/ops/tap.d.ts
/**
* 'Taps' the values from 'input', passing them to the 'process' function.
* Return stream is the input stream, unaffected by what 'process' does.
* @param input Input stream
* @param processors List of processors
* @returns
*/
declare function tapProcess<In, T2, T3, T4, T5, T6>(input: ReactiveOrSource<In>, ...processors: Processors<In, T2, T3, T4, T5, T6>): Reactive<In>;
/**
* 'Taps' the values from 'input', passing them to 'diverged'
* Returns the original input stream, unaffected by what 'diverged' does.
* @param input Input stream
* @param diverged Stream to write to
* @returns
*/
declare function tapStream<In>(input: ReactiveOrSource<In>, diverged: ReactiveWritable<In>): Reactive<In>;
/**
* Create a parallel 'tap' of processing
* @param input Input stream
* @param ops Series of ops to process data
* @returns
*/
declare const tapOps: <TIn, TOut>(input: ReactiveOrSource<TIn>, ...ops: ReactiveOp<TIn, TOut>[]) => Reactive<TOut>;
//#endregion
//#region ../packages/rx/src/ops/throttle.d.ts
/**
* Only allow a value through if a minimum amount of time has elapsed.
* since the last value. This effectively slows down a source to a given number
* of values/ms. Values emitted by the source which are too fast are discarded.
*
* Throttle will fire on the first value received.
*
* In more detail:
* Every time throttle passes a value, it records the time it allowed something through. For every
* value received, it checks the elapsed time against this timestamp, throwing away values if
* the period hasn't elapsed.
*
* With this logic, a fury of values of the source might be discarded if they fall within the elapsed time
* window. But then if there is not a new value for a while, the actual duration between values can be longer
* than expected. This is in contrast to {@link debounce}, which will emit the last value received after a duration,
* even if the source stops sending.
* @param options
* @returns
*/
declare function throttle<V>(throttleSource: ReactiveOrSource<V>, options?: Partial<ThrottleOptions>): Reactive<V>;
//#endregion
//#region ../packages/rx/src/ops/timeout-value.d.ts
/**
* Emits a value if `source` does not emit a value after `interval`
* has elapsed. This can be useful to reset a reactive to some
* 'zero' state if nothing is going on.
*
* If `source` emits faster than the `interval`, it won't get triggered.
*
* Default for 'timeout': 1000s.
*
* ```js
* // Emit 'hello' if 'source' doesn't emit a value after 1 minute
* const r = Rx.timeoutValue(source, { value: 'hello', interval: { mins: 1 } });
* ```
*
* Can also emit results from a function or generator
* ```js
* // Emits a random number if 'source' doesn't emit a value after 500ms
* const r = Rx.timeoutValue(source, { fn: Math.random, interval: 500 });
* ```
*
* If `immediate` option is _true_ (default), the timer starts from stream initialisation.
* Otherwise it won't start until it observes the first value from `source`.
* @param source
* @param options
*/
declare function timeoutValue<TSource, TTriggerValue>(source: ReactiveOrSource<TSource>, options: TimeoutValueOptions<TTriggerValue>): Reactive<TSource | TTriggerValue>;
//#endregion
//#region ../packages/rx/src/ops/timeout-ping.d.ts
/**
* Pings a reactive if no value is emitted at after `interval`.
* Returns `source`.
*
* ```js
* // Ping `source` if no value is emitted after one minute
* const r = Rx.timeoutPing(source, { mins: 1 });
* ```
*
* Behavior can be stopped using an abort signal.
* @see {@link ReactivePingable}
* @param source
* @param options
*/
declare function timeoutPing<TSource>(source: ReactiveOrSource<TSource>, options: TimeoutPi