@cycle/core
Version:
The Cycle run() function meant to be used with RxJS v4
233 lines (225 loc) • 9.89 kB
JavaScript
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Cycle = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
;
var base_1 = require('@cycle/base');
var rx_adapter_1 = require('@cycle/rx-adapter');
/**
* A function that prepares the Cycle application to be executed. Takes a `main`
* function and prepares to circularly connects it to the given collection of
* driver functions. As an output, `Cycle()` returns an object with three
* properties: `sources`, `sinks` and `run`. Only when `run()` is called will
* the application actually execute. Refer to the documentation of `run()` for
* more details.
*
* **Example:**
* ```js
* const {sources, sinks, run} = Cycle(main, drivers);
* // ...
* const dispose = run(); // Executes the application
* // ...
* dispose();
* ```
*
* @param {Function} main a function that takes `sources` as input
* and outputs a collection of `sinks` Observables.
* @param {Object} drivers an object where keys are driver names and values
* are driver functions.
* @return {Object} an object with three properties: `sources`, `sinks` and
* `run`. `sources` is the collection of driver sources, `sinks` is the
* collection of driver sinks, these can be used for debugging or testing. `run`
* is the function that once called will execute the application.
* @function Cycle
*/
var Cycle = function Cycle(main, drivers) {
return base_1.default(main, drivers, { streamAdapter: rx_adapter_1.default });
};
/**
* Takes a `main` function and circularly connects it to the given collection
* of driver functions.
*
* **Example:**
* ```js
* const dispose = Cycle.run(main, drivers);
* // ...
* dispose();
* ```
*
* The `main` function expects a collection of "source" Observables (returned
* from drivers) as input, and should return a collection of "sink" Observables
* (to be given to drivers). A "collection of Observables" is a JavaScript
* object where keys match the driver names registered by the `drivers` object,
* and values are the Observables. Refer to the documentation of each driver to
* see more details on what types of sources it outputs and sinks it receives.
*
* @param {Function} main a function that takes `sources` as input
* and outputs a collection of `sinks` Observables.
* @param {Object} drivers an object where keys are driver names and values
* are driver functions.
* @return {Function} a dispose function, used to terminate the execution of the
* Cycle.js program, cleaning up resources used.
* @function run
*/
function run(main, drivers) {
var run = base_1.default(main, drivers, { streamAdapter: rx_adapter_1.default }).run;
return run();
}
exports.run = run;
Cycle.run = run;
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Cycle;
},{"@cycle/base":2,"@cycle/rx-adapter":3}],2:[function(require,module,exports){
;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
function logToConsoleError(err) {
var target = err.stack || err;
if (console && console.error) {
console.error(target);
} else if (console && console.log) {
console.log(target);
}
}
function makeSinkProxies(drivers, streamAdapter) {
var sinkProxies = {};
for (var name_1 in drivers) {
if (drivers.hasOwnProperty(name_1)) {
var holdSubject = streamAdapter.makeSubject();
var driverStreamAdapter = drivers[name_1].streamAdapter || streamAdapter;
var stream = driverStreamAdapter.adapt(holdSubject.stream, streamAdapter.streamSubscribe);
sinkProxies[name_1] = {
stream: stream,
observer: holdSubject.observer
};
}
}
return sinkProxies;
}
function callDrivers(drivers, sinkProxies, streamAdapter) {
var sources = {};
for (var name_2 in drivers) {
if (drivers.hasOwnProperty(name_2)) {
var driverOutput = drivers[name_2](sinkProxies[name_2].stream, streamAdapter, name_2);
var driverStreamAdapter = drivers[name_2].streamAdapter;
if (driverStreamAdapter && driverStreamAdapter.isValidStream(driverOutput)) {
sources[name_2] = streamAdapter.adapt(driverOutput, driverStreamAdapter.streamSubscribe);
} else {
sources[name_2] = driverOutput;
}
}
}
return sources;
}
function replicateMany(sinks, sinkProxies, streamAdapter) {
var results = Object.keys(sinks).filter(function (name) {
return !!sinkProxies[name];
}).map(function (name) {
return streamAdapter.streamSubscribe(sinks[name], {
next: function next(x) {
sinkProxies[name].observer.next(x);
},
error: function error(err) {
logToConsoleError(err);
sinkProxies[name].observer.error(err);
},
complete: function complete(x) {
sinkProxies[name].observer.complete(x);
}
});
});
var disposeFunctions = results.filter(function (dispose) {
return typeof dispose === 'function';
});
return function () {
disposeFunctions.forEach(function (dispose) {
return dispose();
});
};
}
function disposeSources(sources) {
for (var k in sources) {
if (sources.hasOwnProperty(k) && sources[k] && typeof sources[k].dispose === 'function') {
sources[k].dispose();
}
}
}
var isObjectEmpty = function isObjectEmpty(obj) {
return Object.keys(obj).length === 0;
};
function Cycle(main, drivers, options) {
if (typeof main !== "function") {
throw new Error("First argument given to Cycle must be the 'main' " + "function.");
}
if ((typeof drivers === 'undefined' ? 'undefined' : _typeof(drivers)) !== "object" || drivers === null) {
throw new Error("Second argument given to Cycle must be an object " + "with driver functions as properties.");
}
if (isObjectEmpty(drivers)) {
throw new Error("Second argument given to Cycle must be an object " + "with at least one driver function declared as a property.");
}
var streamAdapter = options.streamAdapter;
if (!streamAdapter || isObjectEmpty(streamAdapter)) {
throw new Error("Third argument given to Cycle must be an options object " + "with the streamAdapter key supplied with a valid stream adapter.");
}
var sinkProxies = makeSinkProxies(drivers, streamAdapter);
var sources = callDrivers(drivers, sinkProxies, streamAdapter);
var sinks = main(sources);
if (typeof window !== 'undefined') {
window.Cyclejs = { sinks: sinks };
}
var run = function run() {
var disposeReplication = replicateMany(sinks, sinkProxies, streamAdapter);
return function () {
disposeSources(sources);
disposeReplication();
};
};
return { sinks: sinks, sources: sources, run: run };
}
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = Cycle;
},{}],3:[function(require,module,exports){
;
var Rx = require('rx');
var RxJSAdapter = {
adapt: function (originStream, originStreamSubscribe) {
if (this.isValidStream(originStream)) {
return originStream;
}
return Rx.Observable.create(function (destinationObserver) {
var originObserver = {
next: function (x) { return destinationObserver.onNext(x); },
error: function (e) { return destinationObserver.onError(e); },
complete: function () { return destinationObserver.onCompleted(); },
};
var dispose = originStreamSubscribe(originStream, originObserver);
return function () {
if (typeof dispose === 'function') {
dispose.call(null);
}
};
});
},
remember: function (observable) {
return observable.shareReplay(1);
},
makeSubject: function () {
var stream = new Rx.Subject();
var observer = {
next: function (x) { stream.onNext(x); },
error: function (err) { stream.onError(err); },
complete: function (x) { stream.onCompleted(); }
};
return { stream: stream, observer: observer };
},
isValidStream: function (stream) {
return (typeof stream.subscribeOnNext === 'function' &&
typeof stream.onValue !== 'function');
},
streamSubscribe: function (stream, observer) {
var subscription = stream.subscribe(function (x) { return observer.next(x); }, function (e) { return observer.error(e); }, function (x) { return observer.complete(x); });
return function () {
subscription.dispose();
};
}
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.default = RxJSAdapter;
},{"rx":undefined}]},{},[1])(1)
});