UNPKG

9.68 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _getIterator2 = require('babel-runtime/core-js/get-iterator');
8
9var _getIterator3 = _interopRequireDefault(_getIterator2);
10
11var _promise = require('babel-runtime/core-js/promise');
12
13var _promise2 = _interopRequireDefault(_promise);
14
15var _typeof2 = require('babel-runtime/helpers/typeof');
16
17var _typeof3 = _interopRequireDefault(_typeof2);
18
19exports.default = dummyNoTreeShaking;
20
21var _racer = require('racer');
22
23var _racer2 = _interopRequireDefault(_racer);
24
25var _LocalDoc = require('racer/lib/Model/LocalDoc');
26
27var _LocalDoc2 = _interopRequireDefault(_LocalDoc);
28
29var _RemoteDoc = require('racer/lib/Model/RemoteDoc');
30
31var _RemoteDoc2 = _interopRequireDefault(_RemoteDoc);
32
33var _util = require('racer/lib/util');
34
35var _util2 = _interopRequireDefault(_util);
36
37var _Query = require('racer/lib/Model/Query');
38
39var _Query2 = _interopRequireDefault(_Query);
40
41var _doc = require('sharedb/lib/client/doc');
42
43var _doc2 = _interopRequireDefault(_doc);
44
45var _observerUtil = require('@nx-js/observer-util');
46
47var _batching = require('../batching');
48
49var _batching2 = _interopRequireDefault(_batching);
50
51var _semaphore = require('./semaphore');
52
53var _semaphore2 = _interopRequireDefault(_semaphore);
54
55function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
56
57var STORE = 'store';
58var $STORE = '$' + STORE;
59var DEFAULT_COLLECTION = '$components';
60
61var BATCH_SETTERS = ['_mutate', '_setEach', '_setDiff', '_setDiffDeep'];
62var WARNING_SETTERS = ['_set', '_setDiff', '_setNull', '_del'];
63
64// Export a dummy function to prevent tree shaking from getting rid of this module
65function dummyNoTreeShaking() {}
66
67// ----------------------------------------------
68// Monkey patches of ShareDB and Racer
69// ----------------------------------------------
70
71// Patch applying sharedb operations to prevent extra rerender from triggering
72var oldHandleOp = _doc2.default.prototype._handleOp;
73_doc2.default.prototype._handleOp = function () {
74 var _this = this,
75 _arguments = arguments;
76
77 var value = void 0;
78 _batching2.default.batch(function () {
79 value = oldHandleOp.apply(_this, _arguments);
80 });
81 return value;
82};
83
84// Patch racer setters to batch them from extra rerenders
85var _iteratorNormalCompletion = true;
86var _didIteratorError = false;
87var _iteratorError = undefined;
88
89try {
90 var _loop = function _loop() {
91 var methodName = _step.value;
92
93 var oldMethod = _racer2.default.Model.prototype[methodName];
94 _racer2.default.Model.prototype[methodName] = function () {
95 var _this2 = this,
96 _arguments2 = arguments;
97
98 var value = void 0;
99 _batching2.default.batch(function () {
100 value = oldMethod.apply(_this2, _arguments2);
101 });
102 return value;
103 };
104 };
105
106 for (var _iterator = (0, _getIterator3.default)(BATCH_SETTERS), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
107 _loop();
108 }
109
110 // Warn when trying to set the full document instead of doing setEach
111} catch (err) {
112 _didIteratorError = true;
113 _iteratorError = err;
114} finally {
115 try {
116 if (!_iteratorNormalCompletion && _iterator.return) {
117 _iterator.return();
118 }
119 } finally {
120 if (_didIteratorError) {
121 throw _iteratorError;
122 }
123 }
124}
125
126var _iteratorNormalCompletion2 = true;
127var _didIteratorError2 = false;
128var _iteratorError2 = undefined;
129
130try {
131 var _loop2 = function _loop2() {
132 var methodName = _step2.value;
133
134 var oldMethod = _racer2.default.Model.prototype[methodName];
135 _racer2.default.Model.prototype[methodName] = function (segments) {
136 if (segments.length === 2 && segments[0] === DEFAULT_COLLECTION && !_semaphore2.default.allowComponentSetter) {
137 throw new Error('You can\'t use \'' + methodName.replace(/^_/, '') + '\' on component\'s ' + ($STORE + ' root path. Use \'setEach\' instead.'));
138 }
139 return oldMethod.apply(this, arguments);
140 };
141 };
142
143 for (var _iterator2 = (0, _getIterator3.default)(WARNING_SETTERS), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
144 _loop2();
145 }
146
147 // Monkey patch racer's local documents to be observable
148} catch (err) {
149 _didIteratorError2 = true;
150 _iteratorError2 = err;
151} finally {
152 try {
153 if (!_iteratorNormalCompletion2 && _iterator2.return) {
154 _iterator2.return();
155 }
156 } finally {
157 if (_didIteratorError2) {
158 throw _iteratorError2;
159 }
160 }
161}
162
163var oldUpdateCollectionData = _LocalDoc2.default.prototype._updateCollectionData;
164_LocalDoc2.default.prototype._updateCollectionData = function () {
165 // Only objects and arrays can be made observable (both are typeof 'object')
166 if (this.data && (0, _typeof3.default)(this.data) === 'object') {
167 this.data = (0, _observerUtil.observable)(this.data);
168 }
169 if (!_semaphore2.default.ignoreCollectionObservableWarning && !(0, _observerUtil.isObservable)(this.collectionData) && this.collectionName !== '$connection') {
170 console.warn('[react-sharedb] Local collection "' + this.collectionName + '" is not initialized to be observable. ' + ('Run require("react-sharedb").initLocalCollection("' + this.collectionName + '") before using it anywhere. ') + ('You must also do it right after cleaning it up with model.silent().destroy("' + this.collectionName + '")'));
171 }
172 return oldUpdateCollectionData.apply(this, arguments);
173};
174
175// Monkey patch racer remote doc to make document observable when it's created locally
176var oldRemoteDocUpdateCollectionData = _RemoteDoc2.default.prototype._updateCollectionData;
177_RemoteDoc2.default.prototype._updateCollectionData = function () {
178 if (this.shareDoc.data) this.shareDoc.data = (0, _observerUtil.observable)(this.shareDoc.data);
179 return oldRemoteDocUpdateCollectionData.apply(this, arguments);
180};
181
182// Add additional `sync` variant of fetch, which will sync return data if it already exists in cache
183_racer2.default.Model.prototype.fetchSync = function () {
184 var _resolve;
185 var promise = new _promise2.default(function (resolve) {
186 _resolve = resolve;
187 });
188 this._forSubscribable(arguments, 'fetch', _resolve, promise);
189 return promise;
190};
191
192// Add additional `sync` variant of subscribe, which will sync return data if it already exists in cache
193_racer2.default.Model.prototype.subscribeSync = function () {
194 var _resolve;
195 var promise = new _promise2.default(function (resolve) {
196 _resolve = resolve;
197 });
198 this._forSubscribable(arguments, 'subscribe', _resolve, promise);
199 return promise;
200};
201
202// resolve is used for SYNC mode.
203// In this mode the subscribeSync function returns a promise
204// which is gonna be either:
205// - resolved, if we are already subscribed to all data (it's in racer model)
206// - pending, if at least one subscription needs to be executed
207_racer2.default.Model.prototype._forSubscribable = function (argumentsObject, method, resolve, promise) {
208 var args, cb;
209 if (!argumentsObject.length) {
210 // Use this model's scope if no arguments
211 args = [null];
212 } else if (typeof argumentsObject[0] === 'function') {
213 // Use this model's scope if the first argument is a callback
214 args = [null];
215 cb = argumentsObject[0];
216 } else if (Array.isArray(argumentsObject[0])) {
217 // Items can be passed in as an array
218 args = argumentsObject[0];
219 cb = argumentsObject[1];
220 } else {
221 // Or as multiple arguments
222 args = Array.prototype.slice.call(argumentsObject);
223 var last = args[args.length - 1];
224 if (typeof last === 'function') cb = args.pop();
225 }
226
227 // [SYNC MODE] For sync usage of subscribe
228 if (resolve) {
229 cb = function cb() {
230 promise.sync = true;
231 resolve();
232 };
233 }
234
235 var group = _util2.default.asyncGroup(this.wrapCallback(cb));
236 var finished = group();
237 var docMethod = method + 'Doc';
238
239 this.root.connection.startBulk();
240 for (var i = 0; i < args.length; i++) {
241 var item = args[i];
242 if (item instanceof _Query2.default) {
243 item[method](group());
244 } else {
245 var segments = this._dereference(this._splitPath(item));
246 if (segments.length === 2) {
247 // Do the appropriate method for a single document.
248 this[docMethod](segments[0], segments[1], group());
249 } else {
250 var message = 'Cannot ' + method + ' to path: ' + segments.join('.');
251 group()(new Error(message));
252 }
253 }
254 }
255 this.root.connection.endBulk();
256
257 // [SYNC MODE] Don't force async execution if we are in sync mode
258 if (resolve) return finished();
259
260 process.nextTick(finished);
261};
262
263// Monkey patch query subscribe to return data synchronously if it's in cache
264_Query2.default.prototype.subscribe = function (cb) {
265 cb = this.model.wrapCallback(cb);
266 this.model._context.subscribeQuery(this);
267
268 if (this.subscribeCount++) {
269 var query = this;
270 // Synchronously return data if it's already in cache
271 // process.nextTick(function() {
272 var data = query.model._get(query.segments);
273 if (data) {
274 cb();
275 } else {
276 query._pendingSubscribeCallbacks.push(cb);
277 }
278 // })
279 return this;
280 }
281
282 if (!this.created) this.create();
283
284 var options = this.options ? _util2.default.copy(this.options) : {};
285 options.results = this._getShareResults();
286
287 // When doing server-side rendering, we actually do a fetch the first time
288 // that subscribe is called, but keep track of the state as if subscribe
289 // were called for proper initialization in the client
290 if (this.model.root.fetchOnly) {
291 this._shareFetchedSubscribe(options, cb);
292 } else {
293 this._shareSubscribe(options, cb);
294 }
295
296 return this;
297};
298module.exports = exports['default'];
\No newline at end of file