UNPKG

ciril

Version:
1,527 lines (1,272 loc) 455 kB
(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){ (function (global){ 'use strict'; var _flowgraph = require('./core/flowgraph'); var _flowgraph2 = _interopRequireDefault(_flowgraph); var _flownode = require('./core/flownode'); var _flownode2 = _interopRequireDefault(_flownode); var _classes = require('./factory/classes'); var _classes2 = _interopRequireDefault(_classes); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } if (!global._babelPolyfill) { require('babel-polyfill'); } var Ciril = { // core/flownode.js FlowNode: _flownode2.default, Transformer: _flownode.Transformer, wrap: _flownode.wrap, // FlowGraph API // core/flowgraph.js FlowGraph: _flowgraph2.default, // fields for debugging _nodes: _flowgraph2.default.nodes, _bindings: _flowgraph2.default.bindings, _inputs: _flowgraph2.default.inputs, // public methods register: _flowgraph2.default.register.bind(_flowgraph2.default), isRegistered: _flowgraph2.default.isRegistered.bind(_flowgraph2.default), remove: _flowgraph2.default.remove.bind(_flowgraph2.default), removeAll: _flowgraph2.default.removeAll.bind(_flowgraph2.default), bind: _flowgraph2.default.bind.bind(_flowgraph2.default), bindAll: _flowgraph2.default.bindAll.bind(_flowgraph2.default), bindInputs: _flowgraph2.default.bindInputs.bind(_flowgraph2.default), bindAllInputs: _flowgraph2.default.bindAllInputs.bind(_flowgraph2.default), unbind: _flowgraph2.default.unbind.bind(_flowgraph2.default), unbindAll: _flowgraph2.default.unbindAll.bind(_flowgraph2.default), synchronize: _flowgraph2.default.synchronize.bind(_flowgraph2.default), synchronizeAll: _flowgraph2.default.synchronizeAll.bind(_flowgraph2.default), desynchronize: _flowgraph2.default.desynchronize.bind(_flowgraph2.default), desynchronizeAll: _flowgraph2.default.desynchronizeAll.bind(_flowgraph2.default), nodeFromUuid: _flowgraph2.default.nodeFromUuid.bind(_flowgraph2.default), getNodeState: _flowgraph2.default.getNodeState.bind(_flowgraph2.default), update: _flowgraph2.default.update.bind(_flowgraph2.default), updateAll: _flowgraph2.default.updateAll.bind(_flowgraph2.default), updateSync: _flowgraph2.default.updateSync.bind(_flowgraph2.default), updateAllSync: _flowgraph2.default.updateAllSync.bind(_flowgraph2.default), flush: _flowgraph2.default.flush.bind(_flowgraph2.default), clear: _flowgraph2.default.clear.bind(_flowgraph2.default), // Factory methods // factory/classes.js createClass: _classes2.default, createMixin: _classes.createMixin }; module.exports = Ciril; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./core/flowgraph":2,"./core/flownode":3,"./factory/classes":4,"babel-polyfill":5}],2:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); Object.defineProperty(exports, "__esModule", { value: true }); var _bluebird = require('bluebird'); var _bluebird2 = _interopRequireDefault(_bluebird); var _remove = require('lodash/array/remove'); var _remove2 = _interopRequireDefault(_remove); var _cloneDeep = require('lodash/lang/cloneDeep'); var _cloneDeep2 = _interopRequireDefault(_cloneDeep); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } // renaming var hasProp = require('lodash/object/has'); /** * Maintains bindings between various nodes, and * manages all node updates. The nodes themselves * are unaware of their bindings -- this information * is kept within the FlowGraph. * * The FlowGraph structure is meant for internal * use. The public API is exposed through the Ciril * object. */ var _FlowGraph = function () { function _FlowGraph() { _classCallCheck(this, _FlowGraph); // uuid --> node this.nodes = new Map([]); // uuid --> Set<uuid> this.bindings = new Map([]); // uuid --> [uuid] this.inputs = new Map([]); // Set<Promise> this.pending = new Set([]); } /** * Register the node with this FlowGraph. * @param node * the node * @return * true iff the node doesn't already * exist in the store. */ _createClass(_FlowGraph, [{ key: 'register', value: function register(node) { if (!hasProp(node, 'uuid')) throw new Error('register(node): node must ' + 'have a uuid.'); var uuid = node.uuid; if (this.nodes.has(uuid)) throw new Error('register(node): a node with ' + 'the given uuid is already registered, ' + 'try generating a new one.'); this.nodes.set(uuid, node); this.bindings.set(uuid, new Set([])); this.inputs.set(uuid, []); } /** * Remove the given nodes from the FlowGraph. * Connected edges are removed as well. * @param nodes * the nodes to remove */ }, { key: 'remove', value: function remove() { for (var _len = arguments.length, nodes = Array(_len), _key = 0; _key < _len; _key++) { nodes[_key] = arguments[_key]; } this.removeAll(nodes); } /** * Remove the given nodes from the FlowGraph. * Connected edges are removed as well. * @param nodes * the nodes to remove */ }, { key: 'removeAll', value: function removeAll(nodes) { var _this = this; nodes.forEach(function (node) { var uuid = node.uuid; _this.inputs.get(uuid).map(function (id) { return _this.nodeFromUuid(id); }).forEach(function (inp) { return _this.unbind(inp, _this); }); var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = _this.bindings.get(uuid)[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var id = _step.value; var dest = _this.nodeFromUuid(id); _this.unbind(node, dest); } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } node.onRemove(); _this.nodes.delete(uuid); }); } /** * Create a one-way data binding between * the source and each of the destinations. * @param source * the source node * @param destinations * the destination nodes * @return * true iff source and destinations * are registered */ }, { key: 'bind', value: function bind(source) { for (var _len2 = arguments.length, destinations = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) { destinations[_key2 - 1] = arguments[_key2]; } return this.bindAll(source, destinations); } /** * Create a one-way data binding between * the source and each of the destinations. * @param source * the source node * @param destinations * the destination nodes * @return true iff source and destinations * are registered */ }, { key: 'bindAll', value: function bindAll(source, destinations) { if (!this.isRegistered(source)) throw new Error('bindAll(...): source not registered.'); var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = destinations[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var node = _step2.value; if (!this.isRegistered(node)) throw new Error('bindAll(...): destination not registered.'); } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2.return) { _iterator2.return(); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } var _iteratorNormalCompletion3 = true; var _didIteratorError3 = false; var _iteratorError3 = undefined; try { for (var _iterator3 = destinations[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { var node = _step3.value; this.inputs.get(node.uuid).push(source.uuid); this.bindings.get(source.uuid).add(node.uuid); node.onBindInput(source); source.onBind(node); } } catch (err) { _didIteratorError3 = true; _iteratorError3 = err; } finally { try { if (!_iteratorNormalCompletion3 && _iterator3.return) { _iterator3.return(); } } finally { if (_didIteratorError3) { throw _iteratorError3; } } } return true; } /** * Bind the input nodes to the given node, in * the given order. * @param node * the output node * @param inputs * the input nodes */ }, { key: 'bindInputs', value: function bindInputs(node) { for (var _len3 = arguments.length, inputs = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) { inputs[_key3 - 1] = arguments[_key3]; } this.bindAllInputs(node, inputs); } /** * Bind the input nodes to the given node, in * the given order. * @param node * the output node * @param inputs * the input nodes */ }, { key: 'bindAllInputs', value: function bindAllInputs(node, inputs) { var _this2 = this; var uuid = node.uuid; var _inputs = this.inputs.get(uuid); if (_inputs.length > 0) { console.warn("bindAllInputs(...): Overwriting existing inputs"); _inputs.map(function (id) { return _this2.nodeFromUuid(id); }).forEach(function (inp) { return _this2.unbind(inp, node); }); } var _iteratorNormalCompletion4 = true; var _didIteratorError4 = false; var _iteratorError4 = undefined; try { for (var _iterator4 = inputs[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) { var inp = _step4.value; this.bind(inp, node); } } catch (err) { _didIteratorError4 = true; _iteratorError4 = err; } finally { try { if (!_iteratorNormalCompletion4 && _iterator4.return) { _iterator4.return(); } } finally { if (_didIteratorError4) { throw _iteratorError4; } } } } /** * Remove bindings between the source * and destinations. * @param source * the source node * @param destinations * the destination nodes * @return true iff source and destinations * are registered */ }, { key: 'unbind', value: function unbind(source) { for (var _len4 = arguments.length, destinations = Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) { destinations[_key4 - 1] = arguments[_key4]; } return this.unbindAll(source, destinations); } /** * Remove bindings between the source * and destinations. * @param source * the source node * @param destinations * the destination nodes * @return true iff source and destinations * are registered */ }, { key: 'unbindAll', value: function unbindAll(source, destinations) { if (!this.nodes.has(source.uuid)) return false; var _iteratorNormalCompletion5 = true; var _didIteratorError5 = false; var _iteratorError5 = undefined; try { for (var _iterator5 = destinations[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) { var node = _step5.value; if (!this.nodes.has(node.uuid)) { console.warn("unbindAll(...): Attempting to unbind unregistered node."); continue; } node.onUnbindInput(source); source.onUnbind(node); (0, _remove2.default)(this.inputs.get(node.uuid), function (id) { return id === source.uuid; }); this.bindings.get(source.uuid).delete(node.uuid); // remove direct reference to input state objects. node.state = (0, _cloneDeep2.default)(node.state); } } catch (err) { _didIteratorError5 = true; _iteratorError5 = err; } finally { try { if (!_iteratorNormalCompletion5 && _iterator5.return) { _iterator5.return(); } } finally { if (_didIteratorError5) { throw _iteratorError5; } } } return true; } /** * Create a cycle of bindings within nodes. * @param nodes * the nodes to synchronize */ }, { key: 'synchronize', value: function synchronize() { for (var _len5 = arguments.length, nodes = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { nodes[_key5] = arguments[_key5]; } this.synchronizeAll(nodes); } /** * Create a cycle of bindings within nodes. * @param nodes * a list of the nodes to synchronize */ }, { key: 'synchronizeAll', value: function synchronizeAll(nodes) { var _this3 = this; if (nodes.length <= 1) return false; nodes.reduce(function (p, c, i, a) { var next = (i + 1) % nodes.length; return _this3.bind(c, a[next]); }); } /** * Inverse of this.synchronize(...nodes). * @param nodes * the nodes to desynchronize */ }, { key: 'desynchronize', value: function desynchronize() { for (var _len6 = arguments.length, nodes = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { nodes[_key6] = arguments[_key6]; } this.desynchronizeAll(nodes); } /** * Inverse of this.synchronizeAll(nodes). * @param nodes * a list of the nodes to desynchronize */ }, { key: 'desynchronizeAll', value: function desynchronizeAll(nodes) { var _this4 = this; if (nodes.length <= 1) return; nodes.reduce(function (p, c, i, a) { _this4.unbind(p, c); return c; }, nodes[nodes.length - 1]); } /** * Get the node keyed by uuid. * @param uuid * the node's uuid * @return * the node keyed by uuid */ }, { key: 'nodeFromUuid', value: function nodeFromUuid(uuid) { return this.nodes.has(uuid) ? this.nodes.get(uuid) : null; } /** * Get the state of the node keyed * by uuid. * @param uuid * the node's uuid * @return * the node's state */ }, { key: 'getNodeState', value: function getNodeState(uuid) { return this.nodeFromUuid(uuid).getState(); } /** * Should be called when a node's data changes. * Recursively updates bound nodes asynchronously. * @param nodes * the nodes to update * @return * a Promise for the update */ }, { key: 'update', value: function update() { for (var _len7 = arguments.length, nodes = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { nodes[_key7] = arguments[_key7]; } return this.updateAll(nodes); } /** * Should be called when a node's data changes. * Recursively updates bound nodes asynchronously. * @param nodes * the nodes to update * @return * a Promise for the update */ }, { key: 'updateAll', value: function updateAll(nodes) { var _this5 = this; var p = _bluebird2.default.map(nodes, function (node) { var uuid = node.uuid; return new _bluebird2.default(function (resolve, reject) { resolve(_this5._terminalsFrom(uuid)); }).map(function (id) { return _this5._update(id); }).all(); }).all(); // TODO: test with inconsistent updates this.pending.add(p); return p.then(function (res) { return _this5.pending.delete(p); }); } /** * Synchronous version of update(node). * Assumes setState() implementations on * dependent nodes are synchronous. * @param nodes * the nodes to update */ }, { key: 'updateSync', value: function updateSync() { for (var _len8 = arguments.length, nodes = Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { nodes[_key8] = arguments[_key8]; } this.updateAllSync(nodes); } /** * Synchronous version of update(node). * Assumes setState() implementations on * dependent nodes are synchronous. * @param nodes * the nodes to update */ }, { key: 'updateAllSync', value: function updateAllSync(nodes) { var _this6 = this; nodes.forEach(function (node) { var uuid = node.uuid; _this6._terminalsFrom(uuid).forEach(function (id) { return _this6._updateSync(id); }); }); } /** * Removes all nodes and bindings. Completes * Pending updates first. * @param safe * if safe, pending updates will * be completed before FlowGraph is * cleared. * @return * a Promise for the clear, void if !safe */ }, { key: 'clear', value: function clear() { var _this7 = this; var safe = arguments.length <= 0 || arguments[0] === undefined ? true : arguments[0]; if (safe) { // Finish remaining updates. return this.flush().then(function (res) { return _this7._clear(); }).caught(function (e) { console.warn(e.stack); _this7._clear(); }); } else { this._clear(); } } /** * Return a promise for the completion of all pending * promises. * @return * a promise for the completion. */ }, { key: 'flush', value: function flush() { return _bluebird2.default.all(Array.from(this.pending)); } /** * Clear this FlowGraph. */ }, { key: '_clear', value: function _clear() { this.nodes.clear(); this.bindings.clear(); this.inputs.clear(); this.pending.clear(); } /** * Updates terminal node keyed by uuid, recursively * updating dirty nodes when necessary. * @param uuid * the terminal uuid * @return * a Promise for the update * @api private */ }, { key: '_update', value: function _update(uuid) { var _this8 = this; var node = this.nodeFromUuid(uuid); if (!node.isDirty()) return _bluebird2.default.resolve(false); node.markDirty(false); return _bluebird2.default.map(this.inputs.get(uuid).filter(function (uuid) { return _this8.nodeFromUuid(uuid).isDirty(); }), function (id) { return _this8._update(id); }).all() // then update node .then(function (res) { var inputs = _this8.inputs.get(uuid); var changed = inputs.length > 0 ? inputs.reduce(function (p, uuid, i, a) { return p || _this8.nodeFromUuid(uuid).changed; }) : false; if (changed) { var args = inputs.map(function (id) { return _this8.getNodeState(id); }); // supporting asynchronous setState() functions return _bluebird2.default.resolve(node.setState.apply(node, args)); } node.changed = false; return _bluebird2.default.resolve(false); }); } /** * Synchronous version of _updateSync(node). * Assumes setState() implementations on * dependent nodes are synchronous. * @param node * the node to update * @api private */ }, { key: '_updateSync', value: function _updateSync(uuid) { var _this9 = this; var node = this.nodeFromUuid(uuid); if (!node.isDirty()) return false; node.markDirty(false); var upstream = this.inputs.get(uuid).filter(function (id) { return _this9.nodeFromUuid(id).isDirty(); }).map(function (id) { return _this9._updateSync(id); }); var inputs = this.inputs.get(uuid); var changed = inputs.length > 0 ? inputs.reduce(function (p, uuid, i, a) { return p || _this9.nodeFromUuid(uuid).changed; }) : false; if (changed) { var args = inputs.map(function (id) { return _this9.getNodeState(id); }); return node.setState.apply(node, _toConsumableArray(args)); } node.changed = false; return false; } /** * Get terminal nodes from node keyed by uuid * @param uuid * the node uuid * @return * the terminal nodes * @api private */ }, { key: '_terminalsFrom', value: function _terminalsFrom(uuid) { var visited = new Set(); var stack = [uuid]; var terminals = []; // Depth-first search from uuid while (stack.length > 0) { var current = stack.pop(); var terminal = true; visited.add(current); var _iteratorNormalCompletion6 = true; var _didIteratorError6 = false; var _iteratorError6 = undefined; try { for (var _iterator6 = this.bindings.get(current)[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) { var child = _step6.value; if (!visited.has(child)) { terminal = false; stack.push(child); this.nodeFromUuid(child).markDirty(true); } } } catch (err) { _didIteratorError6 = true; _iteratorError6 = err; } finally { try { if (!_iteratorNormalCompletion6 && _iterator6.return) { _iterator6.return(); } } finally { if (_didIteratorError6) { throw _iteratorError6; } } } if (terminal) terminals.push(current); } return terminals; } }, { key: 'isRegistered', value: function isRegistered(node) { return this.nodes.has(node.uuid); } }]); return _FlowGraph; }(); var FlowGraph = new _FlowGraph(); exports.default = FlowGraph; },{"bluebird":7,"lodash/array/remove":196,"lodash/lang/cloneDeep":238,"lodash/object/has":246}],3:[function(require,module,exports){ 'use strict'; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Transformer = undefined; exports.wrap = wrap; exports.NodeConstructor = NodeConstructor; var _flowgraph = require('./flowgraph'); var _flowgraph2 = _interopRequireDefault(_flowgraph); var _uuid = require('uuid'); var _uuid2 = _interopRequireDefault(_uuid); var _isEqual = require('lodash/lang/isEqual'); var _isEqual2 = _interopRequireDefault(_isEqual); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function conservativeMerge(target) { for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { sources[_key - 1] = arguments[_key]; } sources.forEach(function (source) { Object.getOwnPropertyNames(source).forEach(function (name) { if (name === 'constructor' || target[name]) return; Object.defineProperty(target, name, Object.getOwnPropertyDescriptor(source, name)); }); }); } function createTransformer(fn) { return new Transformer(fn); } function createSimpleWrapper(obj) { var node = new FlowNode(obj); return node; } function createWrapper(obj) { if (!obj.hasOwnProperty('state')) return createSimpleWrapper(obj); var node = new FlowNode(null, false); // Add FlowNode fields conservativeMerge(obj, node, FlowNode.prototype); obj.register(); return obj; } /** * Wrap the given object or function or value in a FlowNode. * @param obj * the object, function, or value to wrap * @return * the wrapper FlowNode */ function wrap(obj) { if (obj instanceof FlowNode) return obj.register(); switch (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) { case 'function': return createTransformer(obj); case 'object': return createWrapper(obj); default: return createSimpleWrapper(obj); } } /** * Constructor for creating a FlowNode. Should be * called if creating a mixin class with FlowNode. */ function NodeConstructor() { var initialState = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0]; var register = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1]; Object.defineProperty(this, 'dirty', { writable: true, value: false }); Object.defineProperty(this, 'uuid', { value: _uuid2.default.v4() }); Object.defineProperty(this, 'state', { writable: true, value: initialState }); Object.defineProperty(this, 'changed', { writable: true, value: false }); if (register) _flowgraph2.default.register(this); } /** * A FlowNode stores some state and can have * input and output nodes. When extending this class, * the primary implementation details to consider * are how input data is handled in setState(), and * how object data is serialized in getState(). * * The core subclasses of FlowNode are Transformer * and DataNode. */ var FlowNode = function () { /** * On creation, a FlowNode registers itself * with the FlowGraph. */ function FlowNode() { var initialState = arguments.length <= 0 || arguments[0] === undefined ? null : arguments[0]; var register = arguments.length <= 1 || arguments[1] === undefined ? true : arguments[1]; _classCallCheck(this, FlowNode); NodeConstructor.call(this, initialState, register); } /** * Same as Ciril.register(this). */ _createClass(FlowNode, [{ key: 'register', value: function register() { _flowgraph2.default.register(this); return this; } /** * Same as Ciril.isRegistered(this). */ }, { key: 'isRegistered', value: function isRegistered() { return _flowgraph2.default.isRegistered(this); } /** * Bind this node to a transformer node. * @param fn * the transformer function * @return * the transformer node */ }, { key: 'transform', value: function transform(fn) { var transformer = new Transformer(fn); _flowgraph2.default.bind(this, transformer); return transformer; } }, { key: 'bind', /** * Same as Ciril.bind(this, ...destinations) * @param destinations * the destination nodes * @return * the last node in destinations */ value: function bind() { for (var _len2 = arguments.length, destinations = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { destinations[_key2] = arguments[_key2]; } return this.bindAll(destinations); } /** * Same as Ciril.bindAll(this, ...destinations) * @param destinations * the destination nodes * @return * the last node in destinations */ }, { key: 'bindAll', value: function bindAll(destinations) { var dests = destinations.map(function (e) { return _flowgraph2.default.isRegistered(e) ? e : wrap(e); }); _flowgraph2.default.bindAll(this, dests); return dests[dests.length - 1]; } /** * Same as Ciril.synchronize(this, ..nodes). * @param nodes * the nodes to synchronize with * @return * this node */ }, { key: 'synchronize', value: function synchronize() { for (var _len3 = arguments.length, nodes = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { nodes[_key3] = arguments[_key3]; } nodes.reduce(function (p, c, i, a) { return p.bind(c); }, this); return this; } /** * Same as Ciril.synchronize(this, ..nodes). * @param nodes * the nodes to synchronize with * @return * this node */ }, { key: 'synchronizeAll', value: function synchronizeAll(nodes) { nodes.reduce(function (p, c, i, a) { return p.bind(c); }, this); return this; } /** * Same as Ciril.unbind(this, ...destinations). * @param destinations * the destination nodes */ }, { key: 'unbind', value: function unbind() { for (var _len4 = arguments.length, destinations = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { destinations[_key4] = arguments[_key4]; } _flowgraph2.default.unbindAll(this, destinations); } /** * Same as Ciril.unbindAll(this, destinations). * @param destinations */ }, { key: 'unbindAll', value: function unbindAll(destinations) { _flowgraph2.default.unbindAll(this, destinations); } /** * Same as Ciril.update(this). */ }, { key: 'update', value: function update() { return _flowgraph2.default.update(this); } /** * Same as Ciril.updateSync(this). */ }, { key: 'updateSync', value: function updateSync() { _flowgraph2.default.updateSync(this); } /** * Ckecks whether this node has been * marked dirty, which is if its state * is out of date. * @return * true iff the node is dirty. */ }, { key: 'isDirty', value: function isDirty() { return this.dirty; } /** * Mark this node as dirty or clean. * Be careful using this method, as it * affects the update algorithm. It is * meant to be used by Ciril for * bookkeeping purposes. * @param dirty * true iff marking dirty */ }, { key: 'markDirty', value: function markDirty(dirty) { this.dirty = dirty; } /** * Same as cirl.bindInputs(this, ...inputs). * @param inputs * the input nodes * @return * this node */ }, { key: 'bindInputs', value: function bindInputs() { for (var _len5 = arguments.length, inputs = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { inputs[_key5] = arguments[_key5]; } _flowgraph2.default.bindAllInputs(this, inputs); return this; } /** * Same as Ciril.bindAllInputs(this, inputs). * @param inputs * the input nodes * @return * this node */ }, { key: 'bindAllInputs', value: function bindAllInputs(inputs) { _flowgraph2.default.bindAllInputs(this, inputs); return this; } /** * Same as Ciril.remove(this). */ }, { key: 'remove', value: function remove() { _flowgraph2.default.remove(this); } /** * Get this node's state. * @return * the node's state */ }, { key: 'getState', value: function getState() { return this.state; } /** * Set this node's state. * @param args * the input state objects * @return * true iff state changed */ }, { key: 'setState', value: function setState() { for (var _len6 = arguments.length, args = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { args[_key6] = arguments[_key6]; } if (!args.reduce(function (p, c, i, a) { return p && (0, _isEqual2.default)(a[0], a[i]); })) { console.warn('setState(...): Inconsistent state ' + 'detected, make sure transforms are correct.\n ' + ('inputs: ' + args)); } if (!(0, _isEqual2.default)(this.state, args[0])) { this.state = args[0]; this.changed = true; return true; } this.changed = false; return false; } /** * Called before node is removed. * Should be overriden. */ }, { key: 'onRemove', value: function onRemove() {} /** * Called before an input is unbound. * Should be overriden. */ }, { key: 'onUnbindInput', value: function onUnbindInput(input) {} /** * Called after an input is bound. * Should be overriden. */ }, { key: 'onBindInput', value: function onBindInput(input) {} /** * Called before an output is unbound. * Should be overriden. */ }, { key: 'onUnbind', value: function onUnbind(node) {} /** * Called after an output is bound. * Should be overriden. */ }, { key: 'onBind', value: function onBind(node) {} }]); return FlowNode; }(); /** * A Transformer represents a functional transform * from an input state to an output state. Its purpose * in the FlowGraph is to compute values from input * data. */ exports.default = FlowNode; var Transformer = exports.Transformer = function (_FlowNode) { _inherits(Transformer, _FlowNode); function Transformer(fn) { _classCallCheck(this, Transformer); var _this = _possibleConstructorReturn(this, Object.getPrototypeOf(Transformer).call(this)); _this.fn = fn; return _this; } /** * Compute new state based on input state. * @param args * the input state objects * @return * true iff state changed */ _createClass(Transformer, [{ key: 'setState', value: function setState() { for (var _len7 = arguments.length, args = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { args[_key7] = arguments[_key7]; } var state = this.fn.apply(this, args); if (!(0, _isEqual2.default)(this.state, state)) { this.state = state; this.changed = true; return true; } this.changed = false; return false; } }]); return Transformer; }(FlowNode); },{"./flowgraph":2,"lodash/lang/isEqual":241,"uuid":255}],4:[function(require,module,exports){ 'use strict'; 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; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createMixin = createMixin; exports.default = createClass; var _flownode = require('../core/flownode'); var _flownode2 = _interopRequireDefault(_flownode); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } var assign = require('object-assign'); function conservativeMerge(target, source) { Object.getOwnPropertyNames(source).forEach(function (name) { if (name !== "constructor" && !target[name]) Object.defineProperty(target, name, Object.getOwnPropertyDescriptor(source, name)); }); } /** * Helper method to mix source class into target class. Existing * properties are NOT overriden. * @param target {function} * @param source {function} */ function mixin(target) { var proto = target.prototype; for (var _len = arguments.length, sources = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { sources[_key - 1] = arguments[_key]; } sources.forEach(function (source) { source = source.prototype; conservativeMerge(proto, source); }); return target; } /** * Create a FlowNode mixin class from a constructor. * @param Constructor {function} * @return * A FlowNode mixin class */ function createMixin(Constructor) { if (typeof Constructor !== 'function') throw new Error('createMixin(...): argument ' + ('should be function, got ' + (typeof Constructor === 'undefined' ? 'undefined' : _typeof(Constructor)))); var getInitialState = Constructor.prototype.getInitialState; var initialState = typeof getInitialState === 'function' ? getInitialState.apply(this) : null; var register = Constructor.prototype.registerOnCreate || true; var Mixin = function (_Constructor) { _inherits(Mixin, _Constructor); function Mixin() { _classCallCheck(this, Mixin); return _possibleConstructorReturn(this, Object.getPrototypeOf(Mixin).apply(this, arguments)); } return Mixin; }(Constructor); ; mixin(Mixin, _flownode2.default); var proto = Mixin.prototype; // override constructor Mixin = function Mixin() { _flownode.NodeConstructor.call(this, initialState, register); Constructor.apply(this, arguments); }; // copy back prototype Mixin.prototype = proto; return Mixin; } /** * Create a FlowNode class from a specification. * @param spec {object} */ function createClass(spec) { if ((typeof spec === 'undefined' ? 'undefined' : _typeof(spec)) !== 'object') throw new Error('createClass(...): class ' + 'specification must be an object, ' + ('got ' + (typeof spec === 'undefined' ? 'undefined' : _typeof(spec)))); var NewClass = function (_FlowNode) { _inherits(NewClass, _FlowNode); function NewClass() { _classCallCheck(this, NewClass); return _possibleConstructorReturn(this, Object.getPrototypeOf(NewClass).apply(this, arguments)); } return NewClass; }(_flownode2.default); ; assign(NewClass.prototype, spec); return NewClass; } },{"../core/flownode":3,"object-assign":252}],5:[function(require,module,exports){ (function (global){ "use strict"; require("core-js/shim"); require("babel-regenerator-runtime"); if (global._babelPolyfill) { throw new Error("only one instance of babel-polyfill is allowed"); } global._babelPolyfill = true; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"babel-regenerator-runtime":6,"core-js/shim":194}],6:[function(require,module,exports){ (function (process,global){ /** * Copyright (c) 2014, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * https://raw.github.com/facebook/regenerator/master/LICENSE file. An * additional grant of patent rights can be found in the PATENTS file in * the same directory. */ !(function(global) { "use strict"; var hasOwn = Object.prototype.hasOwnProperty; var undefined; // More compressible than void 0. var iteratorSymbol = typeof Symbol === "function" && Symbol.iterator || "@@iterator"; var inModule = typeof module === "object"; var runtime = global.regeneratorRuntime; if (runtime) { if (inModule) { // If regeneratorRuntime is defined globally and we're in a module, // make the exports object identical to regeneratorRuntime. module.exports = runtime; } // Don't bother evaluating the rest of this file if the runtime was // already defined globally. return; } // Define the runtime globally (as expected by generated code) as either // module.exports (if we're in a module) or a new, empty object. runtime = global.regeneratorRuntime = inModule ? module.exports : {}; function wrap(innerFn, outerFn, self, tryLocsList) { // If outerFn provided, then outerFn.prototype instanceof Generator. var generator = Object.create((outerFn || Generator).prototype); var context = new Context(tryLocsList || []); // The ._invoke method unifies the implementations of the .next, // .throw, and .return methods. generator._invoke = makeInvokeMethod(innerFn, self, context); return generator; } runtime.wrap = wrap; // Try/catch helper to minimize deoptimizations. Returns a completi