import { Stream } from 'xstream'; export declare type Component = (sources: So, ...rest: Array) => Si; export declare type FirstArg) => any> = T extends (r: infer R, ...args: Array) => any ? R : any; export declare type IsolateableSource = { isolateSource(source: IsolateableSource, scope: any): IsolateableSource; isolateSink(sink: A, scope: any): B; }; export declare type Sources = { [name: string]: IsolateableSource; }; export declare type WildcardScope = { ['*']?: string; }; export declare type ScopesPerChannel = { [K in keyof So]: any; }; export declare type Scopes = (Partial> & WildcardScope) | string; /** * `isolate` takes a small component as input, and returns a big component. * A "small" component is a component that operates in a deeper scope. * A "big" component is a component that operates on a scope that * includes/wraps/nests the small component's scope. This is specially true for * isolation contexts such as onionify. * * Notice that we type BigSo/BigSi as any. This is unfortunate, since ideally * these would be generics in `isolate`. TypeScript's inference isn't strong * enough yet for us to automatically provide the typings that would make * `isolate` return a big component. However, we still keep these aliases here * in case TypeScript's inference becomes better, then we know how to proceed * to provide proper types. */ export declare type OuterSo = { [K in keyof ISo]: ISo[K] extends IsolateableSource ? FirstArg : ISo[K]; }; export declare type OuterSi = { [K in keyof ISo & keyof ISi]: ISo[K] extends IsolateableSource ? (ReturnType extends Stream ? Stream : (ReturnType extends Stream ? Stream : unknown)) : ISi[K]; } & { [K in Exclude]: ISi[K]; }; /** * Takes a `component` function and a `scope`, and returns an isolated version * of the `component` function. * * When the isolated component is invoked, each source provided to it is * isolated to the given `scope` using `source.isolateSource(source, scope)`, * if possible. Likewise, the sinks returned from the isolated component are * isolated to the given `scope` using `source.isolateSink(sink, scope)`. * * The `scope` can be a string or an object. If it is anything else than those * two types, it will be converted to a string. If `scope` is an object, it * represents "scopes per channel", allowing you to specify a different scope * for each key of sources/sinks. For instance * * ```js * const childSinks = isolate(Child, {DOM: 'foo', HTTP: 'bar'})(sources); * ``` * * You can also use a wildcard `'*'` to use as a default for source/sinks * channels that did not receive a specific scope: * * ```js * // Uses 'bar' as the isolation scope for HTTP and other channels * const childSinks = isolate(Child, {DOM: 'foo', '*': 'bar'})(sources); * ``` * * If a channel's value is null, then that channel's sources and sinks won't be * isolated. If the wildcard is null and some channels are unspecified, those * channels won't be isolated. If you don't have a wildcard and some channels * are unspecified, then `isolate` will generate a random scope. * * ```js * // Does not isolate HTTP requests * const childSinks = isolate(Child, {DOM: 'foo', HTTP: null})(sources); * ``` * * If the `scope` argument is not provided at all, a new scope will be * automatically created. This means that while **`isolate(component, scope)` is * pure** (referentially transparent), **`isolate(component)` is impure** (not * referentially transparent). Two calls to `isolate(Foo, bar)` will generate * the same component. But, two calls to `isolate(Foo)` will generate two * distinct components. * * ```js * // Uses some arbitrary string as the isolation scope for HTTP and other channels * const childSinks = isolate(Child, {DOM: 'foo'})(sources); * ``` * * Note that both `isolateSource()` and `isolateSink()` are static members of * `source`. The reason for this is that drivers produce `source` while the * application produces `sink`, and it's the driver's responsibility to * implement `isolateSource()` and `isolateSink()`. * * _Note for Typescript users:_ `isolate` is not currently type-transparent and * will explicitly convert generic type arguments to `any`. To preserve types in * your components, you can use a type assertion: * * ```ts * // if Child is typed `Component` * const isolatedChild = isolate( Child ) as Component; * ``` * * @param {Function} component a function that takes `sources` as input * and outputs a collection of `sinks`. * @param {String} scope an optional string that is used to isolate each * `sources` and `sinks` when the returned scoped component is invoked. * @return {Function} the scoped component function that, as the original * `component` function, takes `sources` and returns `sinks`. * @function isolate */ declare function isolate(component: Component, scope?: any): Component, OuterSi>; export default isolate; export declare function toIsolated(scope?: any): (c: Component) => Component, OuterSi>;