UNPKG

6.6 kBPlain TextView Raw
1import {
2 CycleProgram,
3 DisposeFunction,
4 Drivers,
5 Sinks,
6 MatchingDrivers,
7 MatchingMain,
8 Engine,
9} from './types';
10import {
11 adaptSources,
12 callDrivers,
13 makeSinkProxies,
14 disposeSources,
15 disposeSinkProxies,
16 isObjectEmpty,
17 replicateMany,
18} from './internals';
19
20export {
21 FantasyObserver,
22 FantasySubscription,
23 FantasyObservable,
24 DevToolEnabledSource,
25 Sources,
26 Sinks,
27 SinkProxies,
28 Driver,
29 Drivers,
30 DisposeFunction,
31 MatchingDrivers,
32 MatchingMain,
33 Main,
34 CycleProgram,
35 Engine,
36 WidenStream,
37 GetValidInputs,
38} from './types';
39
40/**
41 * A function that prepares the Cycle application to be executed. Takes a `main`
42 * function and prepares to circularly connects it to the given collection of
43 * driver functions. As an output, `setup()` returns an object with three
44 * properties: `sources`, `sinks` and `run`. Only when `run()` is called will
45 * the application actually execute. Refer to the documentation of `run()` for
46 * more details.
47 *
48 * **Example:**
49 * ```js
50 * import {setup} from '@cycle/run';
51 * const {sources, sinks, run} = setup(main, drivers);
52 * // ...
53 * const dispose = run(); // Executes the application
54 * // ...
55 * dispose();
56 * ```
57 *
58 * @param {Function} main a function that takes `sources` as input and outputs
59 * `sinks`.
60 * @param {Object} drivers an object where keys are driver names and values
61 * are driver functions.
62 * @return {Object} an object with three properties: `sources`, `sinks` and
63 * `run`. `sources` is the collection of driver sources, `sinks` is the
64 * collection of driver sinks, these can be used for debugging or testing. `run`
65 * is the function that once called will execute the application.
66 * @function setup
67 */
68export function setup<
69 D extends MatchingDrivers<D, M>,
70 M extends MatchingMain<D, M>
71>(main: M, drivers: D): CycleProgram<D, M> {
72 if (typeof main !== `function`) {
73 throw new Error(
74 `First argument given to Cycle must be the 'main' ` + `function.`
75 );
76 }
77 if (typeof drivers !== `object` || drivers === null) {
78 throw new Error(
79 `Second argument given to Cycle must be an object ` +
80 `with driver functions as properties.`
81 );
82 }
83 if (isObjectEmpty(drivers)) {
84 throw new Error(
85 `Second argument given to Cycle must be an object ` +
86 `with at least one driver function declared as a property.`
87 );
88 }
89
90 const engine = setupReusable(drivers);
91 const sinks = main(engine.sources);
92 if (typeof window !== 'undefined') {
93 (window as any).Cyclejs = (window as any).Cyclejs || {};
94 (window as any).Cyclejs.sinks = sinks;
95 }
96 function _run(): DisposeFunction {
97 const disposeRun = engine.run(sinks);
98 return function dispose() {
99 disposeRun();
100 engine.dispose();
101 };
102 }
103 return {sinks, sources: engine.sources, run: _run};
104}
105
106/**
107 * A partially-applied variant of setup() which accepts only the drivers, and
108 * allows many `main` functions to execute and reuse this same set of drivers.
109 *
110 * Takes an object with driver functions as input, and outputs an object which
111 * contains the generated sources (from those drivers) and a `run` function
112 * (which in turn expects sinks as argument). This `run` function can be called
113 * multiple times with different arguments, and it will reuse the drivers that
114 * were passed to `setupReusable`.
115 *
116 * **Example:**
117 * ```js
118 * import {setupReusable} from '@cycle/run';
119 * const {sources, run, dispose} = setupReusable(drivers);
120 * // ...
121 * const sinks = main(sources);
122 * const disposeRun = run(sinks);
123 * // ...
124 * disposeRun();
125 * // ...
126 * dispose(); // ends the reusability of drivers
127 * ```
128 *
129 * @param {Object} drivers an object where keys are driver names and values
130 * are driver functions.
131 * @return {Object} an object with three properties: `sources`, `run` and
132 * `dispose`. `sources` is the collection of driver sources, `run` is the
133 * function that once called with 'sinks' as argument, will execute the
134 * application, tying together sources with sinks. `dispose` terminates the
135 * reusable resources used by the drivers. Note also that `run` returns a
136 * dispose function which terminates resources that are specific (not reusable)
137 * to that run.
138 * @function setupReusable
139 */
140export function setupReusable<D extends Drivers>(drivers: D): Engine<D> {
141 if (typeof drivers !== `object` || drivers === null) {
142 throw new Error(
143 `Argument given to setupReusable must be an object ` +
144 `with driver functions as properties.`
145 );
146 }
147 if (isObjectEmpty(drivers)) {
148 throw new Error(
149 `Argument given to setupReusable must be an object ` +
150 `with at least one driver function declared as a property.`
151 );
152 }
153
154 const sinkProxies = makeSinkProxies(drivers);
155 const rawSources = callDrivers(drivers, sinkProxies);
156 const sources = adaptSources(rawSources);
157 function _run<M extends MatchingMain<D, M>>(
158 sinks: Sinks<M>
159 ): DisposeFunction {
160 return replicateMany(sinks, sinkProxies as any);
161 }
162 function disposeEngine() {
163 disposeSources(sources);
164 disposeSinkProxies(sinkProxies);
165 }
166 return {sources, run: _run, dispose: disposeEngine};
167}
168
169/**
170 * Takes a `main` function and circularly connects it to the given collection
171 * of driver functions.
172 *
173 * **Example:**
174 * ```js
175 * import run from '@cycle/run';
176 * const dispose = run(main, drivers);
177 * // ...
178 * dispose();
179 * ```
180 *
181 * The `main` function expects a collection of "source" streams (returned from
182 * drivers) as input, and should return a collection of "sink" streams (to be
183 * given to drivers). A "collection of streams" is a JavaScript object where
184 * keys match the driver names registered by the `drivers` object, and values
185 * are the streams. Refer to the documentation of each driver to see more
186 * details on what types of sources it outputs and sinks it receives.
187 *
188 * @param {Function} main a function that takes `sources` as input and outputs
189 * `sinks`.
190 * @param {Object} drivers an object where keys are driver names and values
191 * are driver functions.
192 * @return {Function} a dispose function, used to terminate the execution of the
193 * Cycle.js program, cleaning up resources used.
194 * @function run
195 */
196export function run<
197 D extends MatchingDrivers<D, M>,
198 M extends MatchingMain<D, M>
199>(main: M, drivers: D): DisposeFunction {
200 const program = setup(main, drivers);
201 if (
202 typeof window !== 'undefined' &&
203 (window as any).CyclejsDevTool_startGraphSerializer
204 ) {
205 (window as any).CyclejsDevTool_startGraphSerializer(program.sinks);
206 }
207 return program.run();
208}
209
210export default run;