mmlpx
Version:
mobx model layer paradigm
110 lines • 4.51 kB
JavaScript
import * as tslib_1 from "tslib";
/**
* @author Kuitos
* @homepage https://github.com/kuitos/
* @since 2018-06-26 17:06
*/
import { action, observable, ObservableMap, runInAction } from 'mobx';
import Injector from '../core/dependency-inject/Injector';
import { isMap } from '../utils/types';
var reactiveInjectorSymbol = Symbol('reactiveInjector');
function getLRUCacheSymbol(container) {
return Object.getOwnPropertySymbols(container).find(function (symbol) {
return isMap(container[symbol]);
});
}
function makeLRUCacheReactive(container, cacheSymbol) {
var originalDump = container.dump,
originalSet = container.set;
var originalMap = container[cacheSymbol];
var observableMap = originalMap instanceof ObservableMap ? originalMap : new ObservableMap();
// hijack the map assignment to replace it by a ObservableMap
// @see https://github.com/isaacs/node-lru-cache/blob/master/index.js#L201
Object.defineProperty(container, cacheSymbol, {
set: function () {
// should clear the map rather than reassign it to a new one, what will lose the reactive observation
runInAction(function () {
return observableMap.clear();
});
},
get: function () {
return observableMap;
}
});
// wrap observable map setting into action
container.set = function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
var result = false;
runInAction(function () {
return result = originalSet.apply(container, args);
});
return result;
};
container.dump = function () {
// :dark magic: access container map size thus snapshot will reactive with ObservableMap when its setting(via getSnapshot invocation)
// tslint:disable-next-line
container[cacheSymbol].size;
return originalDump.apply(container);
};
}
var ReactiveContainer = /** @class */function () {
function ReactiveContainer() {
this.container = new Map();
}
ReactiveContainer.prototype.set = function (key, value) {
try {
this.container.set(key, value);
return true;
} catch (e) {
/* istanbul ignore next */
console.error(e);
/* istanbul ignore next */
return false;
}
};
ReactiveContainer.prototype.get = function (key) {
return this.container.get(key);
};
ReactiveContainer.prototype.dump = function () {
return Array.from(this.container.entries()).map(function (entry) {
return { k: entry[0], v: entry[1] };
});
};
ReactiveContainer.prototype.load = function (cacheEntries) {
var _this = this;
this.container.clear();
cacheEntries.forEach(function (entry) {
_this.container.set(entry.k, entry.v);
});
};
tslib_1.__decorate([observable, tslib_1.__metadata("design:type", Object)], ReactiveContainer.prototype, "container", void 0);
tslib_1.__decorate([action, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [String, Object]), tslib_1.__metadata("design:returntype", void 0)], ReactiveContainer.prototype, "set", null);
tslib_1.__decorate([action, tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object]), tslib_1.__metadata("design:returntype", void 0)], ReactiveContainer.prototype, "load", null);
return ReactiveContainer;
}();
export default function genReactiveInjector(prevInjector) {
if (prevInjector[reactiveInjectorSymbol]) {
return prevInjector;
}
var newInjector = prevInjector;
/*
* if the injector has an LRUCache based container, we can hijack it and made the underlying map to be a reactive map,
* and keep the lru features
* otherwise we need to construct a simple-ObservableMap-based reactive container
*/
var container = prevInjector._getContainer();
var cacheSymbol = getLRUCacheSymbol(container);
if (cacheSymbol) {
makeLRUCacheReactive(container, cacheSymbol);
} else {
var reactiveContainer = new ReactiveContainer();
newInjector = Injector.newInstance(reactiveContainer);
}
var snapshot = prevInjector.dump();
newInjector.load(snapshot);
newInjector[reactiveInjectorSymbol] = true;
return newInjector;
}