flexy
Version:
A Flux library based on Channels and reducer functions
382 lines (323 loc) • 13 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', {
value: true
});
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; }; })();
exports.defineStore = defineStore;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function _defineProperty(obj, key, value) { return Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _immutable = require('immutable');
var _immutable2 = _interopRequireDefault(_immutable);
var _jsCsp = require('js-csp');
var _transducersJs = require('transducers.js');
function defineStore(_ref) {
var _ref$primaryKey = _ref.primaryKey;
var primaryKey = _ref$primaryKey === undefined ? 'id' : _ref$primaryKey;
var consumers = _ref.consumers;
var transformers = _ref.transformers;
var ctx = _objectWithoutProperties(_ref, ['primaryKey', 'consumers', 'transformers']);
return (function () {
var _class = function (initialData, ctx2) {
_classCallCheck(this, _class);
this.data = !initialData ? _immutable2['default'].Map() : Array.isArray(initialData) && primaryKey ? _immutable2['default'].fromJS(initialData.reduce(function (collection, obj) {
return Object.assign(collection, _defineProperty({}, obj[primaryKey], obj));
}, {})) : typeof initialData === 'object' ? _immutable2['default'].fromJS(initialData) : _immutable2['default'].Map();
this.context = _transducersJs.merge({}, ctx, ctx2);
this.reducers = _immutable2['default'].OrderedMap();
this.inCh = _jsCsp.chan();
this.outCh = _jsCsp.chan(_jsCsp.buffers.fixed(100), _transducersJs.compose(_transducersJs.dedupe()));
this.outMult = _jsCsp.operations.mult(this.outCh);
this.sources = _immutable2['default'].Set();
this.throughCh = _jsCsp.chan(_jsCsp.buffers.fixed(100));
this.throughMult = _jsCsp.operations.mult(this.throughCh);
};
_createClass(_class, [{
key: 'toJSON',
value: function toJSON() {
return JSON.stringify(this.data);
}
}, {
key: 'subscribeTo',
value: function subscribeTo(dispatcher) {
dispatcher.subscribe(this.handleAction, this);
return this;
}
}, {
key: 'unsubscribeFrom',
value: function unsubscribeFrom(dispatcher) {
dispatcher.unsubscribe(this.handleAction, this);
return this;
}
}, {
key: 'listen',
value: function listen(source) {
if (source.outMult && source.throughMult) {
source = source.throughMult;
} else if (source.outMult) {
source = source.outMult;
}
var ch = _jsCsp.chan();
var that = this;
_jsCsp.operations.mult.tap(source, ch);
_jsCsp.go(regeneratorRuntime.mark(function callee$3$0() {
var value;
return regeneratorRuntime.wrap(function callee$3$0$(context$4$0) {
while (1) switch (context$4$0.prev = context$4$0.next) {
case 0:
context$4$0.next = 2;
return _jsCsp.take(ch);
case 2:
value = context$4$0.sent;
case 3:
if (!(value !== _jsCsp.CLOSED)) {
context$4$0.next = 10;
break;
}
that.handleAction(value);
context$4$0.next = 7;
return _jsCsp.take(ch);
case 7:
value = context$4$0.sent;
context$4$0.next = 3;
break;
case 10:
case 'end':
return context$4$0.stop();
}
}, callee$3$0, this);
}));
return this;
}
}, {
key: 'trigger',
value: function trigger() {
// const oldData = this.data
var fnsToApply = this.reducers.takeWhile(function (v) {
return v > 0;
});
this.reducers = this.reducers.skipWhile(function (v) {
return v > 0;
}).filter(function (v) {
return v >= 0;
});
this.data = fnsToApply.reduce(function (value, val, fn) {
return fn(value);
}, this.data);
var dataToSend = this.reducers.reduce(function (value, val, fn) {
return fn(value);
}, this.data);
_jsCsp.putAsync(this.outCh, dataToSend);
}
}, {
key: 'getObservable',
value: function getObservable(transformer, onUndefined) {
transformer = transformer || function (a) {
return a;
};
var that = this;
return {
subscribe: function subscribe(onNext, onError, onCompleted) {
var initialData = transformer(that.reducers.filter(function (v) {
return v >= 0;
}).reduce(function (value, val, fn) {
return fn(value);
}, that.data));
if (initialData === undefined) {
typeof onUndefined === 'function' && onUndefined();
onNext(undefined);
} else {
onNext(initialData);
}
var tempCh = _jsCsp.chan();
_jsCsp.operations.mult.tap(that.outMult, tempCh);
var completed = false;
_jsCsp.go(regeneratorRuntime.mark(function callee$4$0() {
var value;
return regeneratorRuntime.wrap(function callee$4$0$(context$5$0) {
while (1) switch (context$5$0.prev = context$5$0.next) {
case 0:
context$5$0.prev = 0;
context$5$0.next = 3;
return _jsCsp.take(tempCh);
case 3:
value = context$5$0.sent;
case 4:
if (!(value !== _jsCsp.CLOSED)) {
context$5$0.next = 11;
break;
}
onNext(transformer(value));
context$5$0.next = 8;
return _jsCsp.take(tempCh);
case 8:
value = context$5$0.sent;
context$5$0.next = 4;
break;
case 11:
if (completed) {
onCompleted();
}
context$5$0.next = 17;
break;
case 14:
context$5$0.prev = 14;
context$5$0.t0 = context$5$0['catch'](0);
onError(context$5$0.t0);
case 17:
case 'end':
return context$5$0.stop();
}
}, callee$4$0, this, [[0, 14]]);
}));
return {
dispose: function dispose() {
_jsCsp.operations.mult.untap(that.outMult, tempCh);
tempCh.close();
}
};
}
};
}
}, {
key: 'subscribe',
value: function subscribe(onNext, onError, onCompleted) {
var tempCh = _jsCsp.chan();
_jsCsp.operations.mult.tap(this.outMult, tempCh);
var completed = false;
_jsCsp.go(regeneratorRuntime.mark(function callee$3$0() {
var value;
return regeneratorRuntime.wrap(function callee$3$0$(context$4$0) {
while (1) switch (context$4$0.prev = context$4$0.next) {
case 0:
context$4$0.prev = 0;
context$4$0.next = 3;
return _jsCsp.take(tempCh);
case 3:
value = context$4$0.sent;
case 4:
if (!(value !== _jsCsp.CLOSED)) {
context$4$0.next = 11;
break;
}
onNext(value);
context$4$0.next = 8;
return _jsCsp.take(tempCh);
case 8:
value = context$4$0.sent;
context$4$0.next = 4;
break;
case 11:
if (completed) {
onCompleted();
}
context$4$0.next = 17;
break;
case 14:
context$4$0.prev = 14;
context$4$0.t1 = context$4$0['catch'](0);
onError(context$4$0.t1);
case 17:
case 'end':
return context$4$0.stop();
}
}, callee$3$0, this, [[0, 14]]);
}));
return {
dispose: function dispose() {
_jsCsp.operations.mult.untap(this.outMult, tempCh);
tempCh.close();
}
};
}
}, {
key: 'tap',
value: function tap(channel) {
_jsCsp.operations.mult.tap(this.outMult, channel);
return this;
}
}, {
key: 'untap',
value: function untap(channel) {
_jsCsp.operations.mult.untap(this.outMult, channel);
return this;
}
}, {
key: 'handleAction',
value: function handleAction(action) {
var _this = this;
var that = this;
var name = action.name;
var payload = action.payload;
var promise = action.promise;
// in case of full consumer. We provide, (controls, action)
// controls is an object of three functions — apply, commit, and reject
// in case of sync operations, the consumer is expected to call apply with a reducer function and then immediately call commit
// in case of async ops, the consumer should call apply with a reducer function. Then if the async op is successful call commit,
// if the async operation fails, reject should be called. This will roll back the change.
if (consumers[name]) {
(function () {
var cached = null;
consumers[name].call(_this.context, { apply: function apply(fn) {
if (cached) {
that.reducers = that.reducers.set(cached, -1);
}
cached = fn;
that.reducers = that.reducers.set(fn, 0);
that.trigger();
},
commit: function commit() {
if (!cached) {
return false;
}
that.reducers = that.reducers.set(cached, 1);
that.trigger();
cached = null;
_jsCsp.putAsync(that.throughCh, action);
return true;
},
reject: function reject() {
if (!cached) {
return false;
}
that.reducers = that.reducers.set(cached, -1);
that.trigger();
cached = null;
_jsCsp.putAsync(that.throughCh, action);
return true;
}
}, { payload: payload, promise: promise });
})();
} else if (transformers[name]) {
(function () {
var cached = function cached(data) {
return transformers[name].call(_this.context, data, payload);
};
that.reducers = that.reducers.set(cached, 0);
if (promise) {
that.trigger();
promise.then(function () {
that.reducers = that.reducers.set(cached, 1);
that.trigger();
_jsCsp.putAsync(that.throughCh, action);
})['catch'](function (err) {
that.reducers = that.reducers.set(cached, -1);
that.trigger();
console.error(err);
_jsCsp.putAsync(that.throughCh, action);
});
} else {
that.reducers = that.reducers.set(cached, 1);
that.trigger();
_jsCsp.putAsync(that.throughCh, action);
}
})();
} else {
_jsCsp.putAsync(that.throughCh, action);
}
}
}]);
return _class;
})();
}