UNPKG

5.5 kBJavaScriptView Raw
1'use strict';
2
3exports.__esModule = true;
4exports.UNDEFINED_INPUT_ERROR = exports.INVALID_BUFFER = exports.isEnd = exports.END = undefined;
5
6var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
7
8exports.emitter = emitter;
9exports.channel = channel;
10exports.eventChannel = eventChannel;
11exports.stdChannel = stdChannel;
12
13var _utils = require('./utils');
14
15var _buffers = require('./buffers');
16
17var _scheduler = require('./scheduler');
18
19var CHANNEL_END_TYPE = '@@redux-saga/CHANNEL_END';
20var END = exports.END = { type: CHANNEL_END_TYPE };
21var isEnd = exports.isEnd = function isEnd(a) {
22 return a && a.type === CHANNEL_END_TYPE;
23};
24
25function emitter() {
26 var subscribers = [];
27
28 function subscribe(sub) {
29 subscribers.push(sub);
30 return function () {
31 return (0, _utils.remove)(subscribers, sub);
32 };
33 }
34
35 function emit(item) {
36 var arr = subscribers.slice();
37 for (var i = 0, len = arr.length; i < len; i++) {
38 arr[i](item);
39 }
40 }
41
42 return {
43 subscribe: subscribe,
44 emit: emit
45 };
46}
47
48var INVALID_BUFFER = exports.INVALID_BUFFER = 'invalid buffer passed to channel factory function';
49var UNDEFINED_INPUT_ERROR = exports.UNDEFINED_INPUT_ERROR = 'Saga was provided with an undefined action';
50
51if (process.env.NODE_ENV !== 'production') {
52 exports.UNDEFINED_INPUT_ERROR = UNDEFINED_INPUT_ERROR += '\nHints:\n - check that your Action Creator returns a non-undefined value\n - if the Saga was started using runSaga, check that your subscribe source provides the action to its listeners\n ';
53}
54
55function channel() {
56 var buffer = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : _buffers.buffers.fixed();
57
58 var closed = false;
59 var takers = [];
60
61 (0, _utils.check)(buffer, _utils.is.buffer, INVALID_BUFFER);
62
63 function checkForbiddenStates() {
64 if (closed && takers.length) {
65 throw (0, _utils.internalErr)('Cannot have a closed channel with pending takers');
66 }
67 if (takers.length && !buffer.isEmpty()) {
68 throw (0, _utils.internalErr)('Cannot have pending takers with non empty buffer');
69 }
70 }
71
72 function put(input) {
73 checkForbiddenStates();
74 (0, _utils.check)(input, _utils.is.notUndef, UNDEFINED_INPUT_ERROR);
75 if (closed) {
76 return;
77 }
78 if (!takers.length) {
79 return buffer.put(input);
80 }
81 for (var i = 0; i < takers.length; i++) {
82 var cb = takers[i];
83 if (!cb[_utils.MATCH] || cb[_utils.MATCH](input)) {
84 takers.splice(i, 1);
85 return cb(input);
86 }
87 }
88 }
89
90 function take(cb) {
91 checkForbiddenStates();
92 (0, _utils.check)(cb, _utils.is.func, "channel.take's callback must be a function");
93
94 if (closed && buffer.isEmpty()) {
95 cb(END);
96 } else if (!buffer.isEmpty()) {
97 cb(buffer.take());
98 } else {
99 takers.push(cb);
100 cb.cancel = function () {
101 return (0, _utils.remove)(takers, cb);
102 };
103 }
104 }
105
106 function flush(cb) {
107 checkForbiddenStates(); // TODO: check if some new state should be forbidden now
108 (0, _utils.check)(cb, _utils.is.func, "channel.flush' callback must be a function");
109 if (closed && buffer.isEmpty()) {
110 cb(END);
111 return;
112 }
113 cb(buffer.flush());
114 }
115
116 function close() {
117 checkForbiddenStates();
118 if (!closed) {
119 closed = true;
120 if (takers.length) {
121 var arr = takers;
122 takers = [];
123 for (var i = 0, len = arr.length; i < len; i++) {
124 arr[i](END);
125 }
126 }
127 }
128 }
129
130 return {
131 take: take,
132 put: put,
133 flush: flush,
134 close: close,
135 get __takers__() {
136 return takers;
137 },
138 get __closed__() {
139 return closed;
140 }
141 };
142}
143
144function eventChannel(subscribe) {
145 var buffer = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : _buffers.buffers.none();
146 var matcher = arguments[2];
147
148 /**
149 should be if(typeof matcher !== undefined) instead?
150 see PR #273 for a background discussion
151 **/
152 if (arguments.length > 2) {
153 (0, _utils.check)(matcher, _utils.is.func, 'Invalid match function passed to eventChannel');
154 }
155
156 var chan = channel(buffer);
157 var close = function close() {
158 if (!chan.__closed__) {
159 if (unsubscribe) {
160 unsubscribe();
161 }
162 chan.close();
163 }
164 };
165 var unsubscribe = subscribe(function (input) {
166 if (isEnd(input)) {
167 close();
168 return;
169 }
170 if (matcher && !matcher(input)) {
171 return;
172 }
173 chan.put(input);
174 });
175 if (chan.__closed__) {
176 unsubscribe();
177 }
178
179 if (!_utils.is.func(unsubscribe)) {
180 throw new Error('in eventChannel: subscribe should return a function to unsubscribe');
181 }
182
183 return {
184 take: chan.take,
185 flush: chan.flush,
186 close: close
187 };
188}
189
190function stdChannel(subscribe) {
191 var chan = eventChannel(function (cb) {
192 return subscribe(function (input) {
193 if (input[_utils.SAGA_ACTION]) {
194 cb(input);
195 return;
196 }
197 (0, _scheduler.asap)(function () {
198 return cb(input);
199 });
200 });
201 });
202
203 return _extends({}, chan, {
204 take: function take(cb, matcher) {
205 if (arguments.length > 1) {
206 (0, _utils.check)(matcher, _utils.is.func, "channel.take's matcher argument must be a function");
207 cb[_utils.MATCH] = matcher;
208 }
209 chan.take(cb);
210 }
211 });
212}
\No newline at end of file